How to version .NET assemblies

May 9th, 2012 by Rabid Cow

Every .NET developer knows that we should version our assemblies.  Not only does it keep you, the developer, sane, but it also helps installers work properly.  File versioning is a fundamental task so it should be super easy, right?  Let’s try it: create a new C# application and we’re greeted with the familiar AssemblyInfo.cs that contains:


GeSHi Error: GeSHi could not find the language csharp (using path D:\hosting\2839554\html\blog\wp-content\plugins\codecolorer\lib\geshi\) (code 2)

It’s a brand new project so we naturally update the version information to indicate that it’s still in development:


GeSHi Error: GeSHi could not find the language csharp (using path D:\hosting\2839554\html\blog\wp-content\plugins\codecolorer\lib\geshi\) (code 2)

If we build this new project the compiler cheerfully informs us:

warning CS1607: Assembly generation — The version ’0.1.*’ specified for the ‘file version’ is not in the normal ‘major.minor.build.revision’ format

Under the covers

What’s actually happening here is a good old fashioned overflow.  By specifying “*” for the build number, the compiler uses the default format.  That format is a date stamp of the form YYMMDD.  The documentation for AssemblyFileVersion is not particularly helpful.  But if we follow the breadcrumbs we’ll discover that every .NET AssemblyFileVersion gets translated to a VERSIONINFO resource in the underlying Windows OS.  The MSDN documentation for the FILEVERSION portion of VERSIONINFO is more helpful:

Binary version number for the file. The version consists of two 32-bit integers, defined by four 16-bit integers. For example, “FILEVERSION 3,10,0,61″ is translated into two doublewords: 0x0003000a and 0x0000003d, in that order. Therefore, if version is defined by the DWORD values dw1 and dw2, they need to appear in the FILEVERSION statement as follows: HIWORD (dw1), LOWORD (dw1), HIWORD (dw2), LOWORD (dw2).

Or in other words, each component of a version must be less than 65,535.  That means January 1, 2007 translates to 70,101 which overflows the 16 bits assigned to each portion of the version.  The compiler is smart enough to detect the overflow, but the humans who wrote the compiler were not smart enough to give us a helpful error message.  Bad programmers, no cookie!

If it were easy, everyone would do it

So how can we fix this issue?  One solution is to remove the AssemblyFileVersion attribute and then specify the AssemblyVersion using wildcards.  This certainly eliminates the warning: omitting the AssemblyFileVersion causes the AssemblyVersion to be used for the Win32 VERSIONINFO resource.  The default format for the build portion of the AssemblyVersion is the number of days since January 1, 2000 and that will be less than 65,535 for quite a while.  The default format for the revision portion is the number of seconds that have elapsed since midnight of the current day divided by 2 so that will always be less than 65,535.  That sounds like a pretty easy solution….

Unfortunately, we’ve now introduced another problem: every time we rebuild this assembly its identity changes.  A new version number goes into the assembly manifest with each compilation.  For a stand alone application where everything is compiled in one solution using project references this may not be a problem.  However, for software that is intended to be consumed by another solution via binary references, the consumers will quickly become unhappy with us.  We’ve just forced them to pick one of the following terrible choices:

  • Update all binary references in all project files with each new build.  This is way too much work even if you automate it using NuGet.
  • Set SpecificVersion to False for each binary reference.  This is pretty easy, but then downstream consumers are not really sure what they’re getting at runtime.  They’ll get some version of the file from somewhere on the system.  There are rules for this sort of thing, but system administrators can override them with configuration files and who knows what an end user gets in a particular environment. (We’ll probably get a support call).
  • Manually remove the version information from every binary reference in every project file.  This option is not only time consuming, but it also results in partial assembly names.  Microsoft recommends against it.

What is our happy place?

The ideal solution to this problem would have all of the following features:

  • Specify AssemblyVersion independently of AssemblyFileVersion
  • Allow the build and revision portions of AssemblyFileVersion to increment automatically with each build
  • Build and revision portions of AssemblyFileVersion do not cause overflow warnings

Enter the MSBuild Community Tasks project.  It’s a collection of MSBuild tasks that solves some common problems and short comings of .NET compilation.  The Version task provides different options for setting the AssemblyVersion and AssemblyFileVersion attributes.  We can follow the Version task with an AssemblyInfo task to generate a code file with assembly directives. The Version task is designed to be used in one of two ways:

  1. Pass version information directly to the task. Only the output .cs file is modified by this form. The build number is still computed as an epoch date, but the start of the epoch is specified by the StartDate attribute. The revision number is still the number of seconds roughly divided by 2.

    GeSHi Error: GeSHi could not find the language xml (using path D:\hosting\2839554\html\blog\wp-content\plugins\codecolorer\lib\geshi\) (code 2)
  2. Pass version information via a text file which gets updated by the task.  The input text file and the output .cs file are both modified by this form.

    GeSHi Error: GeSHi could not find the language xml (using path D:\hosting\2839554\html\blog\wp-content\plugins\codecolorer\lib\geshi\) (code 2)

We could add these tasks to every project.  However, that could be quite a bit of work for an existing solution.  It’s also a definite maintenance issue when new projects are created.  (It sure would be nice if there was a GUI for editing a project’s MSBuild tasks, but apparently all we get is the XML editor.)  Plus the revision portion will vary from one assembly to another since the clock continues to tick throughout our compilation cycle.

Pulling it all together

A better solution is to execute the tasks once, generate a code file with the version data, and then consume that code file in all other projects.  This approach means we don’t need to modify every project file to include these custom build tasks.  Plus we get the exact same version in all of our assemblies.

For indie devs who perform builds in the Visual Studio IDE, a reasonable solution is to create a project that contains these tasks as well as the output code file.  Then add the output code file as a linked file in all other projects (Project -> Add Existing Item… -> Add As Link).  Finally we need to manually adjust the project dependencies (via Project -> Project Dependencies…) so every project depends on our versioning project.  This last step forces Visual Studio to build the versioning project before any others.  This is an ongoing maintenance issue, but it’s a small one with which we can probably live.

For folks who are a little more sophisticated and invoke MSBuild directly, I’m sure there’s a way to dynamically generate an MSBuild project that drives the versioning and then kicks off the actual compile.  Or something.  This is left as An Exercise For The Reader™.  (If you have a need to invoke MSBuild directly, you’re probably smart enough to figure out how to integrate this solution.)  The same goes for people who use a build server: there’s some documentation somewhere that should tell you how to do it.

The MSBuild Community Tasks provide a great solution to the assembly and file versioning problem.  It’s simple, light weight, and easy to consume.  It just took quite a bit of digging to get there.

New game!

March 7th, 2012 by Justin

Its official, we have started a new game.  Well, I suppose it would be more accurate to say that we have settled into working on our next game.  Since this is all done in our very limited spare time we have to be pretty picky about what we work on next.  The Bruce update is just about finished up and while that was going on we finally all congealed around an idea for our next title.  I am really excited about our new project and can’t WAIT to share it with you.  Ok, that’s not exactly true, I can wait…I would really just rather not.  I still need to write that next Bruce post so be sure to keep watching for that as well.

There is something to be said about starting a new project like this.  There is SOOOO much work ahead of us but it feels pretty good to be working on another project.  Starting out, building the underpinnings (really isn’t my cup of tea, I’d rather be working on the pretty graphics), churning through design details and rules, getting concept art and prototype engine work done.  It’s all very exciting and tempting to leap ahead to the fun stuff but you have to keep your focus and work smart.  With a small team, there are three main things that you have to keep on your mind at all times, focus on the project, keep scope within the confines of reality, and stay motivated.  If any of those things go off in a tail-spin, so do the others along with your progress and any hope of completing the game. (Queue dramatic music)

How do you stay motivated Justin?  Well I’ll tell you!  I’ve found that what works for one person is not necessarily what will work for the rest.  I tend to stay motivated by fun tasks (graphics, game-play) and getting new art from the awesome art team (cheers for Beck!).  In order to continue making progress I will spread out the things that I enjoy about making a game among the things that I don’t like,  that way I always have something to look forward to.  I am currently modeling all of our data into objects that will function as the basis for the entire game rule set.  This data foundation has got to be done correctly or everything will be at risk…and I don’t believe I could care any less about it.  It is a pain to work through this kind of thing for me but soon I’ll be able to get back to graphics and game-play.  Any way, I just thought I’d give an update.  If you have any questions about what we do just drop us a comment!

Thanks!

A Loading Screen in Unity3D Basic

February 4th, 2012 by Justin

One thing I see asked a lot is how to do loading screens in unity.  The best way obviously is to call unity’s Application.LoadLevelAsync method.  Of course those of you who only have Unity basic will not have access to that method since it is a Unity Pro feature.  One way around this is to have a static loading screen.  Let’s say you have a play button on your main menu and you want to go directly into a scene that has a bit of a load time.  Instead of calling Application.LoadLevel what you want to do is create a very light weight scene that you can load from the main menu.  Everything in this scene should be parented to a single game object, I’ll tell you why here in a bit.  Once you have that set up you can call Application.LoadLevel on your light weight Loading scene and it will load in almost instantly.  This scene will have a nice static “Loading…” image or text on it or maybe even a 3D model to make it look nice, just don’t make it too complex.

The next thing to do will be to get your game scene loaded in from this scene.  You will want to make a script whose sole purpose is to load in the game scene and when it’s done, destroy itself.  Since you made everything in the Loading scene a child of a single root game object, all you have to do now is attach the loader script to the single root object and it will destroy everything from the loading scene in one fell swoop.  Now, when you go to load in your Game scene you need to call Application.LoadLevelAdditive.  This will load everything in your game scene into your loading scene right alongside your loading scene root game object, that’s why you want to destroy everything you had in your loading screen so that all you have left is your Game scene contents.

So, to wrap it all up:

  1. The main menu loads the Loading scene
  2. The Loading scene loads the Game scene INTO the loading scene with LoadLevelAdditive
  3. When the Game scene has been loaded the Loading scene destroys itself and leaves the Game scene behind

Thanks for reading!

Bruce Postmortem Part 1

February 1st, 2012 by Justin

I figured I would do a postmortem on Bruce to let you guys know what went right, what went wrong and what we learned during the process. I think I’m going to split this up into several little posts because of time constraints and I’d rather give you something to read now and not wait until it is all finished before publishing. Today’s post will be the introduction and general overview of the game and how it came to be.

Let’s turn on the way back machine and head to the beginning of last year. I have been writing games for many years now and even finishing a couple here and there. It is incredibly difficult to write a game while working a 40+ hour a week job. Being able to stay focused and motivated is probably the hardest part of the whole business. The second hardest part is designing a game that can both be fun and be developed within the constraints of your time and budget, there were many failed attempts at this!

Bruce started life as a side scroller. It was a terrible idea but all things have to start somewhere. Baback and I got together and had lunch to discuss next steps and he convinced me (fairly easily) that doing a falling game would be much better for us. We went on to discuss implementation and look. Naturally there were a lot of grandiose dreams of what we could do with the game but then we came back down to the reality that was our time/budget. Moving forward was fairly easy. We would work late nights and toss updates back and forth. I found that getting new artwork was the best motivation for me because I just could not wait to see the new art in the game.

It took 4 months from start to finish to complete Bruce. The progress on the game was very fast and we were working some pretty crazy hours to get the game up running and polished. Check out the screens below. The next installment will be “The Right”, “The Wrong” or “What Was Learned”. I haven’t decided which yet but I am nearly 100% certain it will not be “The Conclusion”

Thanks for reading!

Oh, and if you have not played Bruce you most definitely should, there will be a quiz.

 

Singleton MonoBehavior in Unity3D

January 31st, 2012 by Justin

Hello everyone!

Since this is the first blog post I am going to start out with something really simple yet extremely useful.  As you are writing your games you will inevitably find yourself in a situation where you only want one instance of a game object to exist and want to allow many objects in your scene access to it.  I’m sure there are other ways to go about accomplishing this but I have chosen the MonoBehavior Singleton pattern to solve the problem.  It is simple and clean.

Below you will see the code for the MySingleton script.


GeSHi Error: GeSHi could not find the language csharp (using path D:\hosting\2839554\html\blog\wp-content\plugins\codecolorer\lib\geshi\) (code 2)

The trick here is in the Awake method.  Since Awake gets called when your game object gets loaded it will assign itself to the _instance backing field which is static.

If you attach this script to an empty game object you will be able gain access to it from anywhere in the system by simply invoking the static Instance property.
If the parent game object has been created this will return the one and only instance of MySingleton so that all of your objects can coordinate.


GeSHi Error: GeSHi could not find the language csharp (using path D:\hosting\2839554\html\blog\wp-content\plugins\codecolorer\lib\geshi\) (code 2)

You could also have the singleton class create the game object itself in the get of the property. If you choose to take this route you would not need to create a game object to attach the script too and you could remove the line in the Awake method that assigns the _instance field.


GeSHi Error: GeSHi could not find the language csharp (using path D:\hosting\2839554\html\blog\wp-content\plugins\codecolorer\lib\geshi\) (code 2)

As a side note, if you make your Awake method look like the following, the singleton object will not be destroyed between scene loads.  This allows for all instance information to be kept even after you move from one scene to another.

 


GeSHi Error: GeSHi could not find the language csharp (using path D:\hosting\2839554\html\blog\wp-content\plugins\codecolorer\lib\geshi\) (code 2)

Thanks for reading!  If you have any questions just let me know.