XNA Creators Club Online
Page 1 of 1 (22 items)
Sort Posts: Previous Next

Serialization of Collections with derived classes as items...

Last post 8/7/2008 7:32 PM by Kong. 21 replies.
  • 7/24/2008 8:21 PM

    Serialization of Collections with derived classes as items...

    So I'm trying to write a data-driven, component-based engine with XNA.  I have basic XML loading/serialization/deserialization. My entities will have components which I'm currently storing in a List<Component>. However the components will be derived from Component. I don't want to specify every derived class as an attribute.  Does anyone have any suggestions/neat tricks?

    Thanks a bunch in advance!

  • 7/25/2008 12:09 AM In reply to

    Re: Serialization of Collections with derived classes as items...

    Have you tried using XmlArray and XmlArrayItem?

    Code below, but note I haven't compiled it -- I'll get around to that later tonight hopefully. =)  I'm assuming that you have a base class "Component" and two derived classes "DerivedClassName1" and "DerivedClassName2".  I know this'll work for a Component[, I'm pretty sure it'd by extension work for List<Component>.  Using XmlArrayItem will satisfy the strongly typed requirements that XML serialization has.

    [XmlArray(ElementName="Components")]  
    [XmlArrayItem(typeof(DerivedClassName1)), XmlArrayItem(typeof(DerviedClassName2))]  
    Component[ ] components; 

    Or is this what you meant by not wanting to specify every derived class as an attribute?  If so, my apologies.  Though I'm pretty sure that XML serialization will demand some indication of exactly what types are OK and which aren't, and expect each derived type to be in an appropriately named element.

    On further thought, this is probably precisely what you are trying to avoid.  I'll still post in case this is what you were looking for.

     

  • 7/25/2008 1:22 AM In reply to

    Re: Serialization of Collections with derived classes as items...

    The XmlSerializer class in the .NET Framework requires attributes listing all the possible derived types that it might ever encounter.

    The IntermediateSerializer class we developed for the XNA Framework Content Pipeline does not have that restriction. In fact this was one of the main reasons we decided to make IntermediateSerializer, rather than just using the regular XmlSerializer!


    XNA Framework Developer - blog - homepage
  • 7/25/2008 4:02 PM In reply to

    Re: Serialization of Collections with derived classes as items...

    Thanks Shawn! So I already found the IntermediateSerializer, but I'm a little confused on how to use it(mostly just my specific needs).  So here's my updated sitrep:

    When I serialize my data I don't get the XNAContent/Asset tags, probably because I'm not using the  ISer right now.  I would like to.  I would like to have code that first: Generates the XML file for the data with the appropriate tags , including the serialization of the derived classes, and second able to read that XML from the Pipeline ( I know I have to add it to the project pipeline).  I don't necessarily need code, just the step-by-step.  Note I need to be able to serialize due to end-user content generation.

    Thanks for the help!

  • 7/25/2008 4:38 PM In reply to

    Re: Serialization of Collections with derived classes as items...

    http://msdn.microsoft.com/en-us/library/bb198817.aspx you can use this method to serialize out your file. Then add the .xml file to your content project, and you can import it with the XmlImporter.

    Note that the content pipeline assembly, which contains the intermediate serializer, is not part of the framework redist. So, this may not be a good solution if you're trying to allow your end users to invoke this code.

    Eli Tayrien - XNA Framework Developer
  • 7/25/2008 5:26 PM In reply to

    Re: Serialization of Collections with derived classes as items...

    I might be misunderstanding, but is your question how to take an object in memory and save it to XML using the IntermedateSerializer?

    That is really easy:

    • Make sure your project is referencing the Content Pipeline assembly
    • Call XmlWriter.Create to open the output XML file (typically in a using statement which will automatically close it when done)
    • Call IntermediateSerializer.Serialize

    XNA Framework Developer - blog - homepage
  • 7/25/2008 5:27 PM In reply to

    Re: Serialization of Collections with derived classes as items...

    Dang, Eli beat me to it :-)  That NEVER happens!
    XNA Framework Developer - blog - homepage
  • 7/25/2008 6:06 PM In reply to

    Re: Serialization of Collections with derived classes as items...

    sweet guys thanks Ill post the results soon!
  • 7/25/2008 8:12 PM In reply to

    Re: Serialization of Collections with derived classes as items...

    Hey guys, I don't have much experience(none) with using statements.  I saw in one example where someone used one for XML, but i cant find it.  Can you gimme a basic example?
  • 7/25/2008 8:39 PM In reply to

    Re: Serialization of Collections with derived classes as items...


    using (XmlWriter writer = XmlWriter.Create(...)) 
        IntermediateSerializer.Serialize(writer, ...); 
     
    XNA Framework Developer - blog - homepage
  • 7/25/2008 9:35 PM In reply to
    • (2342)
    • premium membership MVP
    • Posts 1,226

    Re: Serialization of Collections with derived classes as items...

    The other guys seem to have gotten you on your way with IntermediateSerializer, but just to point out an alternative...

    If you don't want to use attributes you can also specify an array of additional Types when you create the XmlSerializer.  So what I do is before I deserialize my level data from XML is I search though my assembly for all Types that are derived from the Type of the List.  It looks like this...



    protected List<Type> GetLevelObjectTypes() 
        AssemblyName assemblyName = new AssemblyName(); 
        assemblyName.Name = "JSEngine"
        Assembly assembly = Assembly.Load(assemblyName); 
        List<Type> objectTypes = new List<Type>(); 
        foreach(Type type in assembly.GetTypes()) 
        {             
            if (type.IsSubclassOf(typeof(LevelObject))) 
                objectTypes.Add(type); 
        } 
     
        return objectTypes;     
     
    protected void LoadFromFile() 
    {             
        List<Type> objectTypes = GetLevelObjectTypes(); 
     
        Stream stream = File.OpenRead(fileName); 
        XmlSerializer serializer = new XmlSerializer(typeof(LevelData), objectTypes.ToArray()); 
        LevelData levelData = (LevelData)serializer.Deserialize(stream); 
        stream.Close(); 
     
        Load(levelData);     
    Matt Pettineo | DirectX/XNA MVP


    Ride into The Danger Zone | PIX With XNA Tutorial
  • 7/28/2008 2:03 PM In reply to

    Re: Serialization of Collections with derived classes as items...

    Thanks MJP I was looking to do something similar in the future.  So now I used the ISer to serialize in XML my "entity" but how do I use the content writer/reader to access them.  Currently I can only get the basic types to read in.  Heres my stuff...

    public class Entity  
    {  
        private string m_Template;  
        private string m_Name;  
        private List<Component> m_Components;  
     
        public string Template  
        {get/set}  
        public string Name  
        {get/set}  
        public List<Component> Components  
        {get/set}  
     
    }  
    public abstract class Component  
        {  
            public Component()  
            {  
                Type = "Component";  
            }  
     
            private string m_Type;  
            public string Type  

            {  

                get { return m_Type; }  
                set { m_Type = value; }  
            }  
        }  
          
        public abstract class PhysicsComponent:Component  
        {   
          
        }  
          
        public class Location : PhysicsComponent  
        {  
            public Location():base()  
            {  
                base.Type = "Position";  
                Position = Vector3.Zero;  
            }  
            Vector3 m_Position;  
            public Vector3 Position  
            {  
                get { return m_Position; }  
                set { m_Position = value; }  
            }  
        } 
    I guess my next question is what methods do I call to get the "components" read correctly.  Currently when I call Load<> all I get is the template and name variables loaded.  This of course is because I only read/write those.  Also could you show me how to read from the ISer.  I had some problems with reading past end of stream and using the XmlReader in a similar fashion as above!  You guys make my day!  Thanks!
  • 7/28/2008 7:31 PM In reply to

    Re: Serialization of Collections with derived classes as items...

    I'm afraid I don't understand what you are asking here.

    By "ISer" do you mean "IntermediateSerializer"?

    What exactly are you trying to do when you get this error? Is this at the point where you call ContentManager.Load? If so you need to post the code for your ContentTypeWriter and ContentTypeReader.

    The ContentTypeWriter and Reader have nothing to do with XML or the IntermediateSerializer. If you are using the built in XmlImporter to read asset data from XML, that calls the IntermediateSerializer to pull the source data into memory. It is then written into a binary .xnb file by calling the ContentTypeWriter, and loaded into your game by the ContentTypeReader. So the XML part happens long before the ContentTypeWriter is invoked. It's important to understand which part of the pipeline you are having trouble with, so we can know what advice to give.


    XNA Framework Developer - blog - homepage
  • 7/29/2008 1:50 PM In reply to

    Re: Serialization of Collections with derived classes as items...

    Heh, sorry I thought it might  be a little confusing. I used the IntermediateSerializer to generate the XML file.  When I call Load<>, it calls the ContentTypeWriter/Reader.  My question is which functions should I use to read/write the data.  I used write/read string for my strings, so for the List would I use write/read Object(), RawObject(), or another function?

    Thanks again

  • 7/29/2008 4:33 PM In reply to

    Re: Serialization of Collections with derived classes as items...

    Christopher Gay1:
    When I call Load<>, it calls the ContentTypeWriter/Reader. 

    Being pedantic, ContentManager.Load only calls into your ContentTypeReader.

    The ContentTypeWriter is invoked earlier, inside Visual Studio when you build your project.

    Christopher Gay1:
    My question is which functions should I use to read/write the data.  I used write/read string for my strings, so for the List would I use write/read Object(), RawObject(), or another function?

    Most likely you want ReadObject.

    XNA Framework Developer - blog - homepage
  • 7/30/2008 2:00 PM In reply to

    Re: Serialization of Collections with derived classes as items...

    Ok guys, thanks again for all the feedback and quick responses.  So heres what I've come up with so far:
    [ContentTypeWriter]  
        class EntityWriter : ContentTypeWriter<Entity>  
        {  
            protected override void Write(ContentWriter output, Entity value)  
            {  
     
     
                output.Write(value.Template);  
                output.Write(value.Name);  
                output.WriteObject(value.Components);  
     
            }  
     
            public override string GetRuntimeType(TargetPlatform targetPlatform)  
            {  
                return "Shared.Entity, Shared";  
            }  
     
     
            public override string GetRuntimeReader(TargetPlatform targetPlatform)  
            {  
                return "Shared.EntityReader, Shared";  
            }  
        }  
     
        class EntityReader : ContentTypeReader<Entity>  
        {  
            protected override Entity Read(ContentReader input,  
                                                     Entity existingInstance)  
            {  
                Entity e = new Entity();  
     
                e.Template = input.ReadString();  
                e.Name = input.ReadString();  
                input.ReadObject(e.Components);  
                return e;  
            }  
        } 

    So I get an error saying there is no ContentTypeWriter(and probably reader if I were to write one) for Shared.Components.  Since Components is an ABC, and Location derives from it, does that mean that I will have to write a ContentTypeWriter for every single component, including my ABC's.  Or (hopefully!!!!!!!!!!!!!) am I just being a tard and not seeing what I should be doing?

    Thanks again oh so very much

  • 7/30/2008 2:27 PM In reply to

    Re: Serialization of Collections with derived classes as items...

    Side note:  Should I look into using John Doe's serializer?
  • 7/30/2008 5:28 PM In reply to

    Re: Serialization of Collections with derived classes as items...

    You have to provide a ContentTypeWriter for every different class you want to serialize.
    XNA Framework Developer - blog - homepage
  • 7/31/2008 2:29 PM In reply to

    Re: Serialization of Collections with derived classes as items...

    Seeing that I'm gonna make lots o' components, that makes me cry... . So I simply created a Serializer wrapper that uses the IntermediateSerializer.  For anyone who is following here's my new plan of attack:

    Use the Serializer to generate my XML files. In the game, "Load" (not using Content.Load<>) XML files, and store the XmlReader.  When ever I want an entity just deserialize the stream! Simple and productive.

    On a another side note:  I have a couple of questions regarding VS 2005 C# Express (You may want me to re-post this in a separate thread). If I want to use a dll, and it is not COMVisible, I have to set the reference path.  The question is how can I choose a relative path for the dlls.

    Second Question:  The default output for executables is bin\(debug\release).  Do you recommend keeping this setting or should I customize so that files like my XNB files are stored nearer to my project/code files.  My students will want to have their friends play their games, and I don't want them to have them give the entire project to all their friends.  My concern is that with my Serializer I don't need to add the XML to the pipeline, but doing so(adding to pipeline) with property settings of Build Action: None, Copy if Newer, puts a copy of the XML in the bin\(debug\release)\Content, which means they can just hand their friends the bin folder.  Suggestions appreciated.

    Final:  Since the students friends may not have XNA installed, their machines won't have the necessary XNA framework dlls, is there settings I can set to make the dlls embedded or added to the bin folder, etc?  Is this the purpose of Build as Creater Club game?

    Thanks a bunch for all the help over the last two weeks guys, you are awesome and deserve a raise!

  • 7/31/2008 4:19 PM In reply to

    Re: Serialization of Collections with derived classes as items...

    Be aware that using IntermediateSerializer directly inside your game means this won't run on Xbox, if that is important to you.

    I don't think the VS UI supports relative paths for DLL references. You could set that up manually if you hand-edited the project XML, but I'm not sure what directory these would be resolved relative to.

    I don't understand why you would want to change the output path? What is wrong with the default setting?

    To run XNA Framework games, you need to install the XNA Framework first. The FAQ folder on these forums has detailed instructions on the various things you need to install for this to work. Read it carefully: people often just skip everything after the first couple of steps, and then get in a muddle!

    XNA Framework Developer - blog - homepage
  • 8/1/2008 2:54 PM In reply to

    Re: Serialization of Collections with derived classes as items...

    Don't need it to run on XBox yet(if ever).  Thanks for the heads up.  You guys might want to think about allowing users to play XNA games even if they don't have it installed, maybe an option like Build for a Friend which puts a copy of the dlls in the bin folder?

    You guys are awesome keep up all of the great work!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1!!!!!11!!!1!!!1!!1!

  • 8/7/2008 7:32 PM In reply to

    Re: Serialization of Collections with derived classes as items...

    first of all i have to sorry about my poor english

     i got a similar problem like Christopher , i have one class called GameObject which contain a List<GameComponent> which this list will contain variety of classes that derive from GameComponent class  , eg. DrawAnimateSprite component , Physic component , Collisble component and so on

    is there a trick to working around this under Xbox?

Page 1 of 1 (22 items) Previous Next