Are you new? Read the FAQ and catch up on!
9k views

Why is XNA's XML Content Importer shit.

A friend of mine and I are working on a version of Air Race for xbox 360 (Xbox Live Indie Games). In the original version of the game, the different circuits are stored in XML format and I have a circuit editor created with Flash. Obviously, my intention was to reuse the original XML files and the circuit editor when needed. Just in case you're curious, this is how the original files looked like:

XML
  1. <mission name="Rabe" goldTime="43500" silverTime="55000">
  2.   <start x="15091" y="15399"/>
  3.   <objectives>
  4.     <objective x="15611" y="15398" type="normal"/>
  5.     <objective x="15931" y="15843" type="normal"/>
  6.     <objective x="16491" y="16072" type="vertical"/>
  7.     <objective x="21270" y="17025" type="normal"/>
  8.   </objectives>
  9. </mission>
  10.  

­

I quickly noticed that XNA has a Content Importer to automatically import data in XML format into the game, and we are trying to follow the "XNA-way" so I decided to use it. To learn how to do it, I read this article in msdn. At that point I discovered that I was not going to be able to use the exact same XML files because of some extra metadata required in them. Well I didn't like that but it's OK; If I wanted to use the exact same files I could create a custom Content Importer so I don't think that's XNA's fault.

Great, following the instructions, I created my custom datatype:

C#
  1. namespace DataTypes
  2. {
  3.     public class Mission
  4.     {
  5.         public struct Checkpoint
  6.         {
  7.             public Vector2 Position;
  8.             public String GateType;
  9.         }
  10.  
  11.         public string Name;
  12.  
  13.         /// <summary>
  14.         /// Time required to get the gold medal in this circuit
  15.         /// </summary>
  16.         public uint GoldTime;
  17.  
  18.         /// <summary>
  19.         /// Time required to get the silver medal in this circuit
  20.         /// </summary>
  21.         public uint SilverTime;
  22.  
  23.         /// <summary>
  24.         /// The start point for the plane
  25.         /// </summary>
  26.         public Vector2 StartPosition;
  27.  
  28.         /// <summary>
  29.         /// List of objectives of this circuit
  30.         /// </summary>
  31.         public Checkpoint[] Objectives;
  32.  
  33.     }
  34. }
  35.  

­

Then, I adapted the structure of the original XML files to what I thought correct. It was something like this:

XML
  1. <XnaContent>
  2.   <Asset Type="DataTypes.Mission" Name="Pruebas" GoldTime="43500" SilverTime="55000">
  3.     <StartPosition X="15091" Y="15399" />
  4.     <Objectives>
  5.       <Item GateType="normal">
  6.         <Position X="1609" Y="1499" Type="normal"></Position>
  7.       </Item>
  8.       <Item GateType="normal">
  9.         <Position X="1609" Y="1499" Type="normal"></Position>
  10.       </Item>
  11.     </Objectives>
  12.   </Asset>
  13. </XnaContent>
  14.  

­

Well, that was easy... Too easy, in fact, because it did not work: "XML element Name was not found". Apparently the importer can not understand that the Name attribute in the XML refers to the Name attribute in the C# class. I start to notice that this importer is not exactly great but, well, this is acceptable. I adapt again the XML file. This is my second attempt:

XML
  1. <XnaContent>
  2.   <Asset Type="DataTypes.Mission">
  3.     <Name>Pruebas</Name>
  4.     <SilverTime>123123</SilverTime>
  5.     <GoldTime>10000</GoldTime>
  6.     <StartPosition X="1500" Y="1500" />
  7.     <Objectives>
  8.       <Item>
  9.         <Position X="1600" Y="1500" />
  10.         <GateType>normal</GateType>
  11.       </Item>
  12.     </Objectives>
  13.   </Asset>
  14. </XnaContent>
  15.  

­

"XML element GoldTime not found". WTF! So it finds Name and SilverTime, but not GoldTime?? Why!? Ok, I calm down and I start to check carefully for typos. Nothing. Oh, wait... No, that can NOT be true. Although... Could it be possible that it expects GoldTime right after Name because that is the order I used to declare them in my Datatypes.Mission class?? Hoping to be wrong, I switch SilverTime and GoldTime:

XML
  1. <XnaContent>
  2.   <Asset Type="DataTypes.Mission">
  3.     <Name>Pruebas</Name>
  4.     <GoldTime>10000</GoldTime>
  5.     <SilverTime>123123</SilverTime>
  6.     <StartPosition X="1500" Y="1500" />
  7.     <Objectives>
  8.       <Item>
  9.         <Position X="1600" Y="1500" />
  10.         <GateType>normal</GateType>
  11.       </Item>
  12.     </Objectives>
  13.   </Asset>
  14. </XnaContent>
  15.  

­

"XML does not have enough entries in space-separated list.". I don't know WTF that means, but it seems that the order of the attributes IS actually important. I did some tests and confirmed it; the order of the elements in the XML needs to be the same as the one used to declare the attributes in the datatype class. Absurd. Completely.

Trying to be rigorous, I went to the official XML specification, where it states specifically that element attributes are unordered but says nothing about elements. Someone with a very weird way of thinking could argue that, as the specification says nothing, it is not wrong to take the order of the elements into account. But even in that case, it is absurd to take the order in which the attributes of a class are declared! I don't even know how to do that :S

Anyway, back to that weird error: "XML does not have enough entries in space-separated list.". I did not understand a thing so I directly googled the error, only to discover that XNA expects vectors like this: <SomeVector>666 666</SomeVector>. Mmmhh. I love how better is that! Why map XML attributes to C# attributes when we can write them all separated by spaces! Well, the final solution is this:

XML
  1. <XnaContent>
  2.   <Asset Type="DataTypes.Mission">
  3.     <Name>Pruebas</Name>
  4.     <GoldTime>10000</GoldTime>
  5.     <SilverTime>123123</SilverTime>
  6.     <StartPosition>1500 1500</StartPosition>
  7.     <Objectives>
  8.       <Item>
  9.         <Position>1609 1499</Position>
  10.         <GateType>normal</GateType>
  11.       </Item>
  12.       <Item>
  13.         <Position>2168 1496</Position>
  14.         <GateType>horizontal</GateType>
  15.       </Item>
  16.       <Item>
  17.         <Position>2268 1495</Position>
  18.         <GateType>normal</GateType>
  19.       </Item>
  20.     </Objectives>
  21.   </Asset>
  22. </XnaContent>
  23.  

­

As a conclusion, I admit that it may be too much to say that it is a shit (hey, it works!) but it can and should be improved. A lot.

Questions (and aggressive responses) to @miguelSantirso.

Tags: C# XML xna Content Importer

Embed: