2

As a hobby, I'm making a 2D RPG in XNA and C#. I have a class called ObjectiveData. Its only member is a string called objectiveID. Derived from this are various other classes (GatherItemsObjectiveData, SpeakToNPCObjectiveData, etc) - all of them are suppose to store their own objective data related to that particular objective (gatherItemsObjectiveData would hold details on which item to collect and how many, etc). The only commonality between them is objectiveID, hence why it's in the parent class.

I had XML serialization of this working when each of the derived classes had their own objectiveID variable, but I want it to be in the parent class so that I can get the objectiveID without knowing what derived class it is, etc. When I made the switch to putting objectiveID in the parent, it no longer works (says XMl element "objective" not found). So now I'm trying to figure out how to get it to pass the objectiveID to its parent in the XML file.

C# Code:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml.Serialization;

    namespace RpgLibrary.QuestClasses
    {
        public class ObjectivesData
        {
            [XmlArray("ObjectivesList")]
            [XmlArrayItem("KillXObjectiveData", typeof(KillXObjectiveData))]
            [XmlArrayItem("GatherXItemsObjectiveData", typeof(GatherXItemsObjectiveData))]
            [XmlArrayItem("SpeakToNPCObjectiveData", typeof(SpeakToNPCObjectiveData))]
            [XmlArrayItem("VisitAreaObjectiveData", typeof(VisitAreaObjectiveData))]
            public List<ObjectiveData> ObjectivesList;

            public ObjectivesData()
            {
                ObjectivesList = new List<ObjectiveData>();
            }
        }

        [XmlInclude(typeof(KillXObjectiveData))]
        [XmlInclude(typeof(GatherXItemsObjectiveData))]
        [XmlInclude(typeof(SpeakToNPCObjectiveData))]
        [XmlInclude(typeof(VisitAreaObjectiveData))]
        public class ObjectiveData
        {
            public string objectiveID;

            public ObjectiveData()
            {

            }

            public ObjectiveData(string objectiveID)
            {
                this.objectiveID = objectiveID;
            }
        } 

        [XmlType(TypeName = "KillXObjectiveData")]
        public class KillXObjectiveData : ObjectiveData
        {
            public string killTotal;
            public string npcID;

            public KillXObjectiveData()
            {

            }

            public KillXObjectiveData(string killTotal, string npcID, string objectiveID)
                : base(objectiveID)
            {
                this.killTotal = killTotal;
                this.npcID = npcID;
            }
        }

        [XmlType(TypeName = "GatherXItemsObjectiveData")]
        public class GatherXItemsObjectiveData : ObjectiveData
        {
            public string gatherTotal;
            public string itemID;

            public GatherXItemsObjectiveData()
            {

            }

            public GatherXItemsObjectiveData(string gatherTotal, string itemID, string objectiveID)
                : base(objectiveID)
            {
                this.gatherTotal = gatherTotal;
                this.itemID = itemID;
            }
        }

        [XmlType(TypeName = "SpeakToNPCObjectiveData")]
        public class SpeakToNPCObjectiveData : ObjectiveData
        {
            public string npcID;

            public SpeakToNPCObjectiveData()
            {

            }

            public SpeakToNPCObjectiveData(string npcID, string objectiveID)
                : base(objectiveID)
            {
                this.npcID = npcID;
            }
        }

        [XmlType(TypeName = "VisitAreaObjectiveData")]
        public class VisitAreaObjectiveData : ObjectiveData
        {
            public string areaID;

            public VisitAreaObjectiveData()
            {

            }

            public VisitAreaObjectiveData(string areaID, string objectiveID)
                : base(objectiveID)
            {
                this.areaID = areaID;
            }
        }
    }

XML file:

  <?xml version="1.0" encoding="utf-8"?>
  <XnaContent xmlns:QuestClasses="RpgLibrary.QuestClasses">
    <Asset Type="QuestClasses:ObjectivesData">
        <ObjectivesList>
          <Item Type="QuestClasses:GatherXItemsObjectiveData">
            <gatherTotal>5</gatherTotal>
            <itemID>1</itemID>
            <objectiveID>1</objectiveID>
          </Item>
          <Item Type="QuestClasses:KillXObjectiveData">
            <killTotal>5</killTotal>
            <npcID>900</npcID>
            <objectiveID>2</objectiveID>
          </Item>
        </ObjectivesList>
    </Asset>
  </XnaContent>

The end result should be that I get a list of ObjectiveData with all the derived class objects stored in it, and I just need the objectiveID to be properly set in the parent class.

  • 1
    What serializer are you using? – dbc May 13 '15 at 02:33
  • Well, it's a XNA project. I'm using the ContentManager from the Microsoft.Xna.Framework.Content namespace, and using the Load method to read in the file. So the XNA pipeline. – Robert Joseph Dacunto May 13 '15 at 02:38
  • [Base class members are serialized before data from the derived type](http://blogs.msdn.com/b/shawnhar/archive/2008/08/12/everything-you-ever-wanted-to-know-about-intermediateserializer.aspx), so you need to move the `` element to the beginning of its containing element in pre-existing XML files. – dbc May 13 '15 at 03:13
  • 1
    Wow, what an easy fix.. can't believe I missed that. Thanks a lot! – Robert Joseph Dacunto May 13 '15 at 03:15
  • `DataContractSerializer` has the same limitation/issue, that's how I figured it out. Shall I make it an answer? – dbc May 13 '15 at 03:16
  • Sure, it worked and helped me out a lot :) – Robert Joseph Dacunto May 13 '15 at 03:19

1 Answers1

1

According to Everything you ever wanted to know about IntermediateSerializer:

Base class members are serialized before data from the derived type

Thus you need to move the <objectiveID> element to the beginning of its containing element in pre-existing XML files.

dbc
  • 104,963
  • 20
  • 228
  • 340