A while ago I wrote about how to extend IntermediateSerializer to support lists of shared resources. That is great for reading and writing XML files (either directly or using other code that calls into IntermediateSerializer, for instance the built-in XmlImporter), but will not affect how the data is serialized to binary .xnb format. If you want to take lists of shared resources all the way through into your game via ContentManager.Load, you must also customize the .xnb serialization behavior.
Custom .xnb serialization follows similar patterns to IntermediateSerializer, but uses a pair of ContentTypeWriter and ContentTypeReader classes instead of a single ContentTypeSerializer.
First, create a library project to hold this custom collection type:
class SharedResourceList<T> : List<T> { }
Plus this custom reader class, which will be invoked when you load the .xnb file:
public class SharedResourceListReader<T> : ContentTypeReader<SharedResourceList<T>> { protected override SharedResourceList<T> Read(ContentReader input, SharedResourceList<T> existingInstance) { if (existingInstance == null) existingInstance = new SharedResourceList<T>(); int count = input.ReadInt32(); for (int i = 0; i < count; i++) { input.ReadSharedResource((T item) => existingInstance.Add(item)); } return existingInstance; } }
If you are developing for Windows, this code should go in a Windows Game Library project, which can be referenced both from your game and also by the Content Pipeline build process.
If you are developing for Xbox or Windows Phone, you should still start by making a Windows Game Library project (which can be referenced by the Content Pipeline), and then use the cross platform project converter to create an Xbox 360 or Windows Phone copy of this library (which can be referenced by your main game).
Now we need to add some code to write the data into .xnb format. Because this only happens at build time, it goes in a separate assembly that will not ship as part of your final game. Create a new Content Pipeline Extension Library project, add the Windows version of the previously created library project to its references, then add this code:
[ContentTypeWriter] class SharedResourceListWriter<T> : ContentTypeWriter<SharedResourceList<T>> { protected override void Write(ContentWriter output, SharedResourceList<T> value) { output.Write(value.Count); foreach (T item in value) { output.WriteSharedResource(item); } } public override string GetRuntimeReader(TargetPlatform targetPlatform) { return typeof(SharedResourceListReader<T>).AssemblyQualifiedName; } }
Add this content pipeline extension to the references of your content project (not your main game references!) and you are good to go.