Xna In 2015 In Which A Long Overdue Update Is Made
TL;DR
I’m updating a whole load of my libraries to the latest version of .Net framework.
A Long Overdue Update
Heist is not a standalone project, it is based on a huge collection of libraries - many of which I myself built and maintain. Chief amongst these are the open source Myre framework which I took over maintaining from a friend of mine several years ago and the closed source XNA framework released by Microsoft in 2004!
For the last couple of years Myre has been in a kind of Maintenance mode - changes have only been made to fix bugs or to add critical new features that I needed downstream. Obviously this has left some things to go a little bit rotten. Additionally XNA imposes some fairly annoying requirements on the user - I’ve never been successful in getting it to work with newer framework versions than .Net v4.0, and it refuses to build in anything other than x86 mode. On top of all this XNA is windows only and is long since abandoned by Microsoft.
Because of these problems I would really like to move away from XNA in the long term. Monogame is the obvious choice in the medium term, but longer term I’d like to move to something more powerful such as BGFX.
The most obvious usage of XNA throughout the codebase of all my libraries is Vector types. XNA defines types such as Vector2, Quaternion and Matrix and they’re used absolutely everywhere through all my game development libraries. To add some extra complexity to this problem the XNA vector types are not used in all of my libraries - non XNA libraries such as SupersonicSound (my open source FMOD C# wrapper) and HandyCollections (a set of useful collections) define their own vector types so that they don’t have to take a dependency on XNA.
This all means that by the time you get to the Heist you have:
- .Net v4.0 at best (Pretty ancient)
- x86 only (No 64 bit version, constrained memory use)
- Windows only (No love for Linux/Mac)
- 4 different (incompatible) vector types
Light At The (Start) Of The Tunnel
The latest version of .Net released recently. This version can be used all the way back to windows 7 and thanks to .Net Core is going to be on other platforms eventually (almost certainly before I put in the work to go cross-platform). This version adds a load of things to the standard library including Vector types! These are types I can happily use in all of my projects without taking an annoying dependency on XNA.
Step 1 - Myre
I’ve just finished updating Myre (it will be pushed up to Github and Nuget soon). There were a couple of kinks I would like to document for the future (largely for my own benefit).
Replace Project Files
Traditionally libraries for XNA projects were not just C# library projects, instead they were a special “XNA Library” project type. This is restrictive in various ways (e.g. cannot change the target framework version at all). Step one is to replace all your XNA library projects with standard C# class libraries. I achieved this by removing the old project, renaming the directory in explorer and then creating a new project with the same name and just duplicating the structure/file of the old project. Finally you need to add in references, for example to XNA.
You may now freely change target framework (as with any other class library). It’s likely still important to build for x86 as not doing so could cause runtime errors within XNA.
My Game Is Not A Library
The game itself is not an XNA library (obviously), instead it is an XNA game project. This can be replaced just like any other XNA project - simply create a C# class library then in the project properties change the “Output Type” to Windows Application and the “Startup Object” to your entry method (most likely Program.Main).
XNA projects expose a property in their project properties page which allows you to specify the framework version - Reach or HiDef. You will always want to use HiDef but it defaults to Reach. Unfortunately now that your game is not an XNA project there is no way to set it in project properties. Instead when you create your GraphicsDeviceManager (usually the first thing you do in your game constructor) you should set the GraphicsProfile proeprty to HiDef:
GraphicsDeviceManager graphics = new GraphicsDeviceManager(this) {
GraphicsProfile = GraphicsProfile.HiDef,
};
Content Is Complex
XNA has special “Content Projects” which build all of your Content when you build your game. These are not like any other project type and you must keep the content project. You will need to update references in your content project to any content pipeline extensions (which will have been replaced in the last step). XNA projects can have a special reference called a “content reference” which causes the referenced content project to be built, and then copied into the output directory - there is no such reference type for class libraries.
To take advantage of this behaviour simply create a new empty XNA library project (I call mine MyGame.ContentShim) and add the content reference to that. Now your game can add a normal reference to the content shim project and content will be built and copied correctly!
There is one final kink for using Content Pipeline Extensions (loading your own code into the content building process pipeline). Your content pipeline project is now a C# class library, targeting some arbitrary framework version of your choice (v4.6 in my case) but the content project is targeting v4.0 - this will cause runtime failures (content pipeline can’t find or use your alien code from the future). To fix this you need to edit the *.contentproj file. Find the line:
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
and replace it with:
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
Now your content pipeline will run on the framework of your choice!
Parting Note - How Does This Help Heist?
This is all an effort to reduce my dependency on XNA, with a view to eventually removing XNA altogether. This will allow me to use newer framework versions (better GC), go cross platform (linux and mac), take advantage of SIMD (CPU speedup) and create a 64 bit version of the game (less memory pressure).