Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
104 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

The Buildstamp

This isn't so much part of the engine as it is a simple project trick that could be more suited to a Sweet Snippet or something like it, but I'm going to put it in anyway because (a) Enginuity uses it, and (b) it's nifty.

When you're working with a project over a fairly long period of time, having gone through several builds, with various betas and test releases having been distributed amongst team members and the odd friend looking to test their particular hardware configuration.. it can be difficult to keep track of them all, to find out which 'version' of an in-development project you're dealing with. It becomes particularly important when it comes to networked games - you need to ensure that all your clients have the same build of the game, otherwise messages could get interpreted differently across platforms, protocols could mismatch.. you'd generally get what appear to be a load of bugs which are actually just due to not having updated the build properly.

So, the most obvious way to do this is to track the date and time of the build. You *could* just request that everyone right-click their executables and check that the creation date is the same across all machines, but that's hardly efficient - quite aside from the fact that you're relying on the local file having the same creation date as the build, and with things like version-control systems knocking around there's no guaranteeing that'll be the case. No, the best option is to compile the date and time into the executable itself; you get the added advantage, there, of being able to access it in code. So, when your networked games connect to each other, they can compare 'buildstamps' - if they're not the same, the connection is not made; the two times could even be tested to see which is older, and the developer in question given a message telling them to update their build.

A global variable does the trick.

const std::string buildStamp = "ProjectName " __TIMESTAMP__;

__TIMESTAMP__ is, according to MSDN, a universally defined ANSI C macro, so it should be safe to use. If you can't get it to work, you may need to resort to the more advanced method I describe in a minute. I've got my projects set up with that line in a file all on its own - 'buildstamp.cpp.' An 'extern const std::string buildStamp' in engine.h makes the buildstamp value available throughout the engine.

The only problem we've not mentioned is, ironically, with the efficiency of the compiler. Buildstamp.cpp will get built once, but then with no changes it won't get built again - irritatingly, the compiler doesn't pick up that because the value of __TIMESTAMP__ has changed, the resulting object code would be different, but oh well. Add a custom build step in MSVC, or a custom makefile rule, to delete the buildstamp.obj file after the executable is built. That will force the compiler to regenerate the buildstamp.cpp file whenever you want to link and produce a new executable.

For the more elite amongst you, you may want to use a more advanced technique - it's not something I really thought I needed, but it gives you increased flexibility and could potentially be useful in a situation where multiple developers are working on a project. Basically, rather than writing the buildstamp.cpp file yourself, you write a short program to generate it - with the obvious advantage that such a program would have access to any information you care to give it access to, including the name of the user currently logged onto the computer ('built by "fine.richard" at...'), or even a file to keep track of the number of times the generator program has been run (a build number). As before, you hook this program in as a custom build step, and voila - each build will have a freshly-generated buildstamp.cpp file, containing any information you want. I'd recommend that you write such a program to use a config file specific to the project - you can store the project name and current build number in there, while reusing the generator program across projects.

Conclusion

We've covered a chunk more today; hopefully that'll keep you all going for a bit while I finish up with article 6. :-) The interpolator and triggers come in particularly handy for polished GUI sequences I've found - menus sliding smoothly in and out - and the buildstamp, while not essential just yet, will come in very handy when we write the networking system.

Incidentally, I just ported the demo game - 'CY' - across to Mac OS X. The total time taken was about 4.5 hours, and most of that was spent accounting for differences between the compilers (like the fact that GCC has better adherence to standards than MSVC6, and thus didn't let me get away with much of my sloppy coding). There were only about 3 actual bugs that were exposed by the port, and one of them was simply that I'd not implemented user-level logging on Mac at that time (I have now, thanks to John McDowall - major kudos, man). Four and a half hours. Not bad, hmm? :-) The OSX port is an entrant into the uDevGame competition over at www.idevgames.com - Mac owners, go and help them out by playing the games and voting for your favourites! Judging by some of the entries last year - like the spectacular 'Kiki the Nanobot' - you won't be disappointed with the originality and sheer style of some of the entries.

I'm off for lunch. If you've got questions or comments, the discussion thread is a good place to start, otherwise I can be reached at rfine AT tbrf no-spam-monkeys DOT net. Next time, I think we'll be looking at the texturing system, but until then: have fun!


Contents
  Serialization
  Triggers & Interpolators
  The Buildstamp

  Source code
  Printable version
  Discuss this article

The Series
  Part I
  Part II
  Part III
  Part IV
  Part V