Automatic XNB Serialisation in XNA 3.1

Automatic XNB Serialisation in XNA 3.1

With XNA 3.1 comes a very cool feature, that makes writing of own content types a lot easier. You don’t have to create your own ContentTypeWriter and ContentTypeReader anymore. If none of those classes is found for your type XNA writes them for you automatically by using reflection.

In order to work with external tools XML is a wonderful format to share the results and make them accessible in your code. There are lots of libraries for xml import and export you can include in your tool and if the xml file is not too long, you can even read or edit it manually with a simple text editor. That’s the reason why we use a lot of custom content types in Zeit². So the automatic serialisation is a welcome innovation for XNA and makes my live a lot easier.

You can find a pretty good introduction to the basic features and also some example code at Shawn Hargreaves Blog.

However there are still things I needed some time for to figure out, because they were not mentioned in the article above. So let me explain them to spare you the work [and to make me remember them the next time ;-) ].

Collections

You have the possibility to add collections to your type such as lists or arrays. Actually its no big deal to add a collection member to your type, but the tricky part is the format in the xml file. There are two different ways of separating collection entries. They can be space- or tag separated.

The separation method depends on the C# type you want to use. There are value-types and reference-types (pointer types should work like reference-types). Out of the value-types, the simple-types are space separated. These are predefined types such as int or float but also from XNA like Vector2 or Color.

The struct-types, enum-types and and all reference-types are separated with tags. The standard tag is <Item> but you can change the collection item name by adding the attribute [ContentSerializerAttribute(CollectionItemName = "CollectionItem")] to the managed type member.

For the example I used a space separated list with XNA Colors, the standard collection item name for the puppies and a customized one for the flees.

public class Dog
{
   public string name;
   public Color[] furColors;
   public Puppy[] puppies;
   [ContentSerializerAttribute(CollectionItemName = "FleeItem")]
   public List<Flee> flees;
}

public struct Puppy
{
   public string name;
}

public class Flee
{
   public int size;
}

<?xml version="1.0" encoding="utf-8"?>
<XnaContent>
 <Asset Type="GameLib.Dog[]">
   <Item>
     <name>Ace</name>
     <furColors>
       FFFFCCFF
       AAFFFF23
       1243FFFF
     </furColors>
     <puppies>
       <Item>
         <name>King</name>
       </Item>
       <Item>
         <name>Queen</name>
       </Item>
     </puppies>
     <flees>
       <FleeItem>
         <size>5</size>
       </FleeItem>
       <FleeItem>
         <size>28</size>
       </FleeItem>
     </flees>
   </Item>
 </Asset>
</XnaContent>

Optional Parameter

Another very useful thing is the optional attribute. By adding [ContentSerializerAttribute(Optional = true)] to a managed type member, you can skip it in the xml file if you don’t need it for an entry and use a standard value instead.

public class Flee
{
   [ContentSerializerAttribute(Optional = true)]
   public int size = 4;
}

So much for now, have fun with Automatic XNB Serialisation.

Cheers Volker

[ContentSerializerAttribute(CollectionItemName = "FleeItem")]