Embedding content as resources

Originally posted to Shawn Hargreaves Blog on MSDN, Tuesday, June 12, 2007

Reusable XNA components often contain content as well as code. For instance the bloom sample on the creators.xna.com site uses several custom effects, and the framerate component I described in my previous post needs a font to display the output.

If you are distributing a component in source form, people can just add the necessary content files to their project along with the component source code. If you distribute it as a game library project, adding that project to your game solution will even automatically copy the built content into the right output directory for you.

Things are less convenient if you want to distribute your component as a binary DLL, however. Not much fun for your users if you have to tell them "as well as adding this DLL to your project references, you also need to copy these three .xnb files to this particular directory where my component can find them".

The solution is to embed your content as resources directly inside the component DLL. This way you only need to distribute that one single file, which can include both code and content.

As a starting point, I'll assume you already have the framerate component from my previous post set up to build as a Game Library project. We need to add a second helper project to build the content, to make sure the content will be built before we try to embed it as a resource (there would be a circular dependency if the same project that was building the content was also trying to embed it).

Right-click on the solution node at the top of the Solution Explorer pane, choose Add / New Project / Windows Game Library, and enter "Content" as the project name. Delete the resulting Class1.cs file, because this helper project will only contain content, not code. To ensure the content is built first, right-click on the framerate component project, choose Project Dependencies, and check the entry for the content project.

Now you need to move the .spritefont file from the framerate component into the content project. You can do this by dragging in the Solution Explorer, which will make a copy, and then deleting the original file.

Build the content project, in order to create the output .xnb file.

Now create a resource file to embed the .xnb data. Right click on your framerate component project in the Solution Explorer, choose Add / New Item, and pick the "Resources File" template.

Double-click the resulting Resource1.resx to load it into the resource designer. From the toolbar at the top left of the designer, pull down the little arrow at the right of the Add Resource button and select Add Existing File. Browse into your Content/bin/x86/Debug directory, and select Font.xnb (if this doesn't show up, make sure the file selector filter is set to All Files).

Finally, you must tell the framerate component to load its content from the embedded resource rather than looking for an external file. Change this line:

    content = new ContentManager(game.Services);

to:

    content = new ResourceContentManager(game.Services, Resource1.ResourceManager);

And there you have it.

There is one major downside to embedding content as assembly resources, however. The entire assembly (including resource data) will be loaded into memory in one go, and the CLR does not provide any way to unload assemblies other than by unloading the entire AppDomain. This is no problem for components that just need a couple of small helper assets, but it probably wouldn't be a good idea to embed all your game levels and sounds in this way!

Blog index   -   Back to my homepage