As some of you’ve might seen, I’ve been breaking my head over the following problem for the past few days:

How do I serialize the class like the following without creating a special ‘intermediate’ struct for each and ever classes

public class MyData
    {
        [ContentSerializer(SharedResource = true)]
        public Texture2D myTexture;
        public int myInt;
        public string[] myLines;
        public MyData() { } // for deserialization
        public MyData(int myInt, Texture2DProxy myTexture, string[] myLines)
        {
            this.myInt = myInt;
            this.myTexture = myTexture;
            this.myLines = myLines;
        }
    }

Even though I’ve marked the Texture2D as a shared resource, I still can’t serialize it using the IntermediateSerializer because a Texture2D always has a reference to a GraphicsDevice object, and the IS can’t serialize that.

Fortunately some helpfull people in #XNA on Efnet (ecosky and flashed, that’s you guys!) told me about proxyclasses, first I was confused and thought they wanted me to write a proxy for every class in my project, but soon they helped me understand that I should write a proxy class for Texture2D. I just had to write a proxy class that can be serialized and that will store the path to texture, so that it can reload itself when deserialized.

I quickly came up with the following class, very simple but it will suffice for now:

public class Texture2DProxy
    {
        public Texture2DProxy(string path)
        {
            LoadTexture(path);
        }

        public Texture2DProxy() { }

        private void LoadTexture(string path)
        {
            ContentManager content = GameServices.GetService<ContentManager>(); //My own class, see my code snippet, you can also reference a static CM here.
            texture = content.Load<Texture2D>(path);
            this.path = path;
        }

        [ContentSerializerIgnore()] //make this is not serialized
        private Texture2D texture;

        [ContentSerializerIgnore()]
        public Texture2D Texture
        {
            get
            {
                if (texture == null)
                {
                    LoadTexture(path);
                }
                return texture;
            }
        }

        [ContentSerializer()] //make sure this is, even-though it's a private field.
        private string path;
    }

Now we just need to replace Texture2D with Texture2DProxy everywhere, and update some code. In the end we can now serialize and deserialize the MyData class like this:

public void DoSerialize(MyData myData)
        {            
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            using (XmlWriter writer = XmlWriter.Create("example.xml", settings))
            {
                IntermediateSerializer.Serialize(writer, myData, null);
            }
        }

        public MyData DoLoad()
        {
            MyData tmp;
            XmlReaderSettings settings = new XmlReaderSettings();            
            using(XmlReader reader = XmlReader.Create("example.xml", settings))
            {
                tmp = IntermediateSerializer.Deserialize<MyData>(reader, null);
            }

            return tmp;
        }

Btw, serializing like this will generate the following XML file:

<?xml version="1.0" encoding="utf-8"?>
<XnaContent>
  <Asset Type="XNASerialization.MyData">
    <myTexture>#Resource1</myTexture>
    <myInt>42</myInt>
    <myLines>
      <Item>Two households, both alike in dignity,</Item>
      <Item>In fair Verona, where we lay our scene,</Item>
      <Item>From ancient grudge break to new mutiny,</Item>
      <Item>Where civil blood makes civil hands unclean.</Item>
    </myLines>
  </Asset>
  <Resources>
    <Resource ID="#Resource1" Type="XNASerialization.Texture2DProxy">
      <path>latern</path>
    </Resource>
  </Resources>
</XnaContent>

With this problem out of the way, I can now finally start working on a way to save and restore levels in Hollandia. Oh btw, you can ofcourse do the same trick with SoundEffects and Models or anything else for that matter.