Skip to content
Andrew Castillo edited this page Oct 14, 2018 · 1 revision
public partial class ContentManager : IDisposable

This is the central class for content management. One is created on instantiation of the Game class.

Asset Loading

Assets are loaded using the ContentManager.Load<T>(string) method.

First, the manager checks that it has not ben disposed and that the asset name is a valid string. It fixes up file paths if everything is okay, and checks to see if the asset is already loaded (loaded assets are stored in a Dictionary<string, object> indexed by the fixed up asset name). If the asset is already loaded it simply returns the existing asset. If it is not loaded, ReadAsset<T>(string, Action<IDisposable>) is called. The asset is then added to the dictionary.

ReadAsset<T>() does some validity checks to make sure a graphics device service exists, before trying to open a stream from the asset name. Though the TitleContainer class, a stream is opened using File.OpenRead(). If the stream cannot be opened for whatever reason (usually because the name of the file is invalid), FNA tries to guess what the correct asset name would be. Assuming all goes well (throws if not) a check is done for the XNB header (3-byte X-N-B at the start of the file). If the header is found, the appropriate type reader is constructed from the header info. This is performed by GetContentReaderFromXnb().

GetContentReaderFromXnb() essentially does a bunch of magic to decompress the Lzx data inside the xnb and figure out what content reader should process back the decompressed binary data. Of note is that FNA loads the entire compressed data blob into memory at once with a MemoryStream rather than reading constantly during decompression for performance reasons. The decompressed stream is passed into a ContentReader constructor, which is returned back to ReadAsset().

If GetContentReaderFromXnb() cannot determine an appropriate content reader to use, it is assumed to be a 'raw asset' instead, which is processed using several other loading techniques depending on what the passed in asset type to ReadAsset<T>() was.

Disposable Recording

ContentManager has the concept of 'disposable recording'. This seems pretty simple, it just keeps track of assets as IDisposable in a list and uses it to free resources when an asset is unloaded. It seems to use this rather than the dictionary loadedAssets, although I'm not 100% on why this is. Maybe for performance with GC, or because assets are stored in the dictionary as object so this gives a way to manually free them in a strongly-typed way.