XNA Content Pipeline Safe

Topics: Developer Forum, User Forum
Jun 2, 2009 at 12:13 AM

I'm making a game that uses Farseer Physics, and the XNA.Framework.Content. So far to get the physics engine and XNA content pipeline to work together, I've added quite a few [ContentSerializerIgnore] attribute tags around the XNA3 branch. I'm also keeping with the latest release of Farseer, and doing a daily update. My question is if the XNA3 branch could include tags to make it's objects intermediate serializer safe for everyone?

Coordinator
Jun 2, 2009 at 1:21 AM

If we included the ContentSerializerIgnore attribute, we would have dependence on the XNA framework. But because it is an attribute (simply just a class that inherits from Attribute) we might be able to include it.

At the same time, it would be great if there were support for standard serialization (not using the content pipeline). Would you be willing to contribute this to the project?

Jun 2, 2009 at 4:54 AM

Standard serialization would be cool! However, I haven't gone too far into using it.

So far, I've only made adjustments to Geom.cs, Body.cs, and GenericLis.cs. I've added:

#if(XNA)

[ContentSerializerIgnore]

#endif

For all delegates, and under #if (XNA) using Microsoft.XNA.Framework.Content;. I've Written Readers and Writers using the Microsoft.XNA.Framework.Content. So, it I do not think it will break the standard library.

I'd be more than happy to contribute to the project. Putting attribute tags for the content pipeline probably won't take too long, as there's only about 8 of them.  If you like, I could also put in XNA readers and writers (I just got done coding mine). I'm not too sure, but for standard xml serialization, the [XmlIgnoreAttribute] tag will cause the standard serializers to ignore the specific attribute. It will compile with the [ContentSerializerIgnore] attribute below it, so I think should work with both tags.

Before I started hacking at the farseerphysics.dll, I created custom, separate classes, which contained the same values as the body and geom, but it's harder to maintain. This would make it way easier! :)

Jun 2, 2009 at 9:57 AM

I've also gone a small part of the way with Intermediate Serializer stuff. Rather than editing the engine code, I created classes for PhysicsSimulatorContent, BodyContent and GeomContent. It was only really a proof of concept idea, and it was pretty messy with the Geom's storing a Body ID to look up the actual Body at runtime. I ended up scrapping the idea of serializing the whole Sim. How would you get your game objects' references assigned to the correct Geom.Tag anyway? Now I think I will have something like this for my physics object's content classes:

PhysicsObjectContent

   |- List<LinkContent>

   |- List<PhysicsElementContent>

      |- BodyContent,

      |- List<GeomContent>

 

Where LinkContent is a class with all the information for creating Joints and Springs (LinkType, elementId1, elementId2, anchorPoint1,  anchorPoint2 etc).

I don't see any reason why these content classes wouldn't be usable with both XmlSerializer and IntermediateSerializer.

 

 

Coordinator
Jun 2, 2009 at 1:16 PM

@daswampy: Great. If you could download the latest source code checkin, add the attributes and send it as a patch in our patch section (found under source control) it would be much appreciated.

Standard .net serialization is just adding [Serializable] to the classes that can be serialized. If some properties/fields does not need to be serialized, put a NonSerialized attribute above them to make the serializer ignore it. (Remember, binary serializers even serializes private fields). The XML serializer uses the XmlIgnoreAttribute (It only serializes public fields and properties) to mark it as non serialized.

Working with the XML serializer is the easiest in our case because we don't need to serialize all the private fields and properties. Everything needed is public (i think). To get the binary serializer to work correctly too, might be easier by implementing the ISerializable interface and tell it to only serialize the relevant data.

An example on how that is done, can be found here.

Jun 2, 2009 at 10:46 PM

Hmm, so it looks like there are many ways to serialize the data.

  • Standard .net serialization, System.Runtime.Serialization
    • [NonSerialized]
    • Not supported on Xbox
    • Updated in .net 3.5
    • Fastest
  • XML serialization, System.Xml
    • [XmlIgnore]
    • Hasn't changed since .net 1.1
    • Supported on Xbox, PC, will work for standard class, silverlight.
  • XNA serialization, Microsoft.XNA.Framework.Content
    • [ContentSerializerIgnore]
    • Supported on Xbox, PC, dependent on XNA framework (always changing)
    • For writers, requires a second .dll

So, which one will the patch be for?

The best way to test that it works, is to write a serializer for it, so which ever way, there should be a sample in the AdvancedSamples.

Coordinator
Jun 2, 2009 at 10:52 PM

I was not aware that binary serialization is not supported on Xbox. I guess we have to go with XML serialization only then.
But, that also makes it a lot easier :)

All public properties that should not be serialized should be attributed in the following manner:

#if(XNA)
[ContentSerializerIgnore]
#endif
[XmlIgnore]
public void Method(Type arguments)
{
}

That should do it. It would be great if you could create a test to see if it works. To smack two flies with one hit, it would be awesome if you made a simple sample for inclusion in AdvancedSamples. Just a simple "Load simulation", "Start Simulation", "Save Simulation" demo. All the tools are there to create such a sample.

Jun 2, 2009 at 10:53 PM

@roonda

I keep all geoms and bodies encapsulated in a physics object. The physics object is kept inside an array. The array is kept in a wrapper. The wrapper is kept in Unit Manager. The unit manager is kept in an arbiter.

I made a struct called Tag, it contains an enum and an int. The tag stores information of which unit manager it belongs to, and what is it's index inside the array wrapper (which is inside the unit manager). When a class wants the complete unit (which uses the physics object as a base class), based off one geom, it gives the arbiter the geom's tag, and the arbiter returns the unit (the arbiter can see all unit managers).

I hope that made sense.

Jun 2, 2009 at 10:59 PM

The thing with System.Runtime.Serialization, is that some of the classes are supported on the xbox 360, some aren't. I'm going through the MSDN documentation for it right now. I'm going to ask in the xna forums what is supported and what isn't supported.

Jun 2, 2009 at 11:05 PM

Found it:

http://forums.xna.com/forums/p/14955/78263.aspx#78263

Jun 2, 2009 at 11:34 PM

What about Zune, I know the XNA serializer doesn't work it, as far as I know only System.Xml works.  I think serialization would speed up the loading of my game since right now it takes an unexceptible 1-2 minutes.

Jun 3, 2009 at 12:14 AM

XML serialization is for loading and unloading xml documents. So if you have 5 different enemies, you can have 5 different xml documents which define the properties of the enemies. During run-time, the game will load the xml documents into the enemies. Taking 1-2 minutes to load a game might be due to something else.

Jun 3, 2009 at 12:23 AM

 

I looked a little bit on MSDN and XNA forums to see what the work around would be for Zune xml, turns out that using XNA content pipeline will work for zune. During run-time, the zune will need access to the ContentReader. The ContentReader is used whenever you do:

Unit unit = game.ContentManager.Load<Unit>("assetLocation");

On MSDN, if you look at the bottom, and around the Microsoft.XNA.Framework.Content, it's supported on the Zune platform. Now, the actual content pipeline itself, with the xml writers, is definitly not supported on the zune. This is because visual studio writes the xml files to binary .xnb during compile time. The compiler also checks between the readers, writers, and xml documents to make sure that the xml tags match.

Coordinator
Jun 3, 2009 at 1:08 AM

Since the content pipeline in my mind is just a fancy way of loading resources and most of it's features are not really something FPE will gain from. (Features like load once from disk and cache rest of time might be something worth) I think that simple XML serialization of the physics engine together with it's bodies, geometries, joints, springs and controllers would be a great thing.

Simply saving the state of the whole world in an XML file would make it easier for people to create save/load functions in their game. Having the basic structure in place also makes it possible to extend with binary serialization and send copies of the world (physics simulator along with dynamics) over the network.

I hope you come up with a solution that works on most platforms. If you come up with a solution in the next few days, I might be able to squeeze it into 2.1.

Jun 3, 2009 at 1:37 AM

Don't wait for me for 2.1. I'm going to teach my self System.XML (it's really just going through some tutorials) over the next few days, while continuing development on my project. I'm not going to port my XNA pipeline solution over until after the standard xml solution is written.

Probably the best thing would be to write a tool that will allow people to create and save physics objects to xml, and have classes built into farseerphysics.dll to read in the saved pre-created physics objects. Oh my, that's a lot more work than just adding tags so people can write it themselves :).

Coordinator
Jun 3, 2009 at 1:43 AM
Edited Jun 3, 2009 at 1:47 AM

I've used this simple generic XML serializer in some of my previous projects: http://geekswithblogs.net/paulwhitblog/archive/2007/07/20/114076.aspx

If you write down the tags the correct places, I will make sure those tags gets used. For now, we only implement standard XML serialization - any XNA pipeline stuff can come later.

Edit: A heavily updated implementation of the generic XML serializer I might add, but it has the fundamental idea.

Jun 4, 2009 at 2:23 AM

I was tired of manually updating the ContentTypeReaders/Writers for my game, so I just wrote a generic class that takes advantage of the Intermediate Serializer:

If it works on all XNA Platforms (awaiting answer from XNA Forums), I'm going to submit this as the XNA Serializer, then get to work on a .net standard XML serializer. If it doesn't, then it's great for development purposes, when classes are always changing etc. Maybe someone could put it to good use. It just relies on using a folder directory set-up to be exactly the same as your namespacing.

Basically, it does everything automatically for you :), just need to drop in some tags.


/// <summary>
    /// Generic class to deserialize any object based on namespace name
    /// Must have a matching content directory tree to match full namespace
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public static class ObjectSerialization<T> where T : new()
    {
        private static StringBuilder loc = new StringBuilder(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location));
        private static int directorylength = loc.Length - 14;

        static public void Serailize(string assetName)
        {
            T testData = new T();
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            settings.ConformanceLevel = ConformanceLevel.Auto;
            SetCurrentLocation(assetName);           
            using (XmlWriter writer = XmlWriter.Create(loc + ".xml", settings))
            {
                IntermediateSerializer.Serialize(writer, testData, loc.ToString());
            }
        }
        static public T Deserialize(string assetName)
        {
            SetCurrentLocation(assetName);
            //Create the xml reader
            using (XmlReader reader = XmlReader.Create(loc.ToString()))
            {
                //Deserialize the data
                return IntermediateSerializer.Deserialize<T>(reader, ".\\");
            }
        }

        private static void SetCurrentLocation(string assetName)
        {
            //Chop off "bin\x86\Debug" and anything else from the end
            loc.Remove(directorylength, (loc.Length - directorylength));
            //Set the location to the correct directory
            loc.Append("\\content\\" + typeof(T).FullName);
            //Using namespaces, so change the . to a \\
            loc.Replace(".", "\\");
            //Add the assetname
            loc.Append("\\" + assetName + ".xml");
        }
    }

Jun 4, 2009 at 10:46 AM

Sent patch for the tags and this previous copy pasted class. I'm not sure if you wanted the body and geom serialized in the springs and joints, so that's up to you. 

Going to write a demo screen which will use system.xml next.

Jun 6, 2009 at 8:15 AM
Edited Jun 6, 2009 at 10:59 AM

Hmm, so it looks like there are many ways to serialize the data.

  • Standard .net serialization, System.Runtime.Serialization
    • [NonSerialized]
    • Not supported on Xbox
    • Updated in .net 3.5
    • Fastest
  • XML serialization, System.Xml
    • [XmlIgnore]
    • Hasn't changed since .net 1.1
    • Supported on Xbox, PC, will work for standard class, silverlight.
  • XNA serialization, Microsoft.XNA.Framework.Content
    • [ContentSerializerIgnore]
    • Supported on Xbox, PC, dependent on XNA framework (always changing)
    • For writers, requires a second .dll

Me and my team have a fully working set using the 3rd method that works on Xbox, Pc and the Zune perfectly that we have intergrated into farseer

We will be submitting a patch sometime in the next week or so

Jun 7, 2009 at 11:54 PM

They already applied the patch for the [ContentSerializerIgnore]/[XmlIgnore]. It works great now. Been using the IntermediateSerializer until XNA 3.1 comes, which will have automated .xnb serialization. When I submitted the patch, I forgot to add tags to IsStatic in geom.cs. For IsStatic, it requires that the body be instantiated, which isn't during the deserialization of a geom. I'll submit another patch w/ just that fix.

IMO, The only editing which should be done to farseer is just tags, no readers/writers/anything. Anything else should be put into an advanced demo screen.

Nonetheless, I look forward to seeing your implementation for it.