New Content System - WhileFalseStudios/FNA GitHub Wiki

XNA's existing content system doesn't suit our needs very well. We like text-based assets, unprocessed binary assets and the ability to pack our data into singular archives. The XNB system is basically the opposite of that in most ways.

In light of this we have replaced XNA's content pipeline with our own virtual filesystem implementation.

Changes from XNA

At present the usage in code of this new content system is not too different. Game.Content is still used to access the asset manager. Content.Load<>() is still used to load an asset. However, by default you will find that calls to Load will return null even if the asset exists. This is because you must now manually tell the asset manager where to find your game data.

Setting up the Asset Manager

The most basic use of the Asset Manager requires specifying both a list of paths to search and a set of mounts to load the actual assets from. These are specified in two different ways.

Specifying search paths

Search paths are where the Asset Manager looks for the mounts you specify. This is not done in code, but by creating a file named DataSearchPaths.yaml alongside the FNA DLL. The contents of this file will generally look something like the following:

searchPaths:
- ../../Data/
- ./Data/

Each entry in the file specifies a file path relative to the FNA DLL to look for mount points in the next step. This was designed this way to make data loading easy when working in Visual Studio. Traditionally the game content would be copied to the output directory of the build, meaning this had to be done if assets changed but the binaries were not rebuilt. With our system, you can specify multiple directories game content can load from. The above file will search both the current directory and the root of the VS project (assuming the default bin/Debug / bin/Release output directory. This allows game content to be placed at the root without having to be copied to the output directory every time a change is made.

Specifying mount points

The second step to get your content loading to specify at least one mount point in code. Our test project does this in Game.Initialize() but it is possible to do so at any point after initialisation as well. An unlimited number of mount points can be specified provided each has a unique path.

Mount points can be specified like so:

int count = Content.MountDataPath("common");
count += Content.MountDataPath("game");

MountDataPath() has a set of rules it follows when looking for points to mount:

  • First, each path specified in DataSearchPaths.yaml is queried for a directory specified by the first method argument.
  • Second, each path is searched for a zip file named [argument1].pak.
  • Last, each path is searched for a bigfile table of contents file named [argument1].fat

The mount name can contain subdirectories (i.e. could be "path/to/mount/point"), and by default ALL existent mount points are mounted. It is possible to override this behaviour and only load the FIRST existent mount point by specifying the second method argument as true (it has a default value so you do not need to specify false if you want to mount them all). The return value of the method tells you how many valid mount points were mounted.

If no suitable mount point is found, there is no error but the return value will be 0.

It was decided that these should be specified in code to allow more complex behaviour when deciding what to mount. For example, to load DLC or to create a Source engine-like directory setup for modding. Fairly complex setups can be created with this system, far beyond what XNA allowed by default.

For an example of how this new system works, see the test project GitHub repository.