1
\$\begingroup\$

This is the situation I'm in:

I'm developing a game with C# using unity. In the game I have characters which is either locked or unlocked, and they're pretty much the same. For every character, they have their respective rank, level, type and race (provides additional effects), HP and MP as well as some stats, unique abilities with arbitrary effects to the game suited to them.

Then, the complication comes in as there's also a "Inventory" with predefined "Items", which every one of them holds arbitrary effects, can be either passive or active, as well as another set of rank and level for every item.

So, now I have to do planning. I want all the parameters for the characters to be in a single file (for obvious reasons), where the character class should read these file, retrieve the relevant part, and apply it to the character.

The game will be updated with new characters/items, or changed abilities/stats/effects. My saving system has to generate save data that persist from all versions too. (Say, a character is added. Then the old save should still load fine, with the new character initialized at locked and basic stats)

And I'm not sure what should be used to implement it with such a multi-layered nested structure, which still has to persist. My idea is to make the whole character structure a list with each character being the element, but then I can't see how to make a flexible system when there are apparently lists of lists of lists of lists, which is basically a mess to work with. I need some way to store the structure in a abstracted way that allows me to save all the parameters in all the nested stuff of a list of characters in a save file, and then also be able to read them (and fill those missing parts with initialized value).

\$\endgroup\$
  • \$\begingroup\$ I don't understand what you're asking. Do you need a human-readable save-file? There are lots of human-readable data-formats that allow nested structures. \$\endgroup\$ – bummzack Aug 1 '14 at 7:56
2
\$\begingroup\$

When you have deeply nested types, you should use a data format which supports unlimited nesting of objects. Two possible alternatives are the simple JSON and the more complex XML. Both formats look different but work surprisingly similar. They are basically key/value maps where values can also be either primitive data types, other key/value maps or lists of values. This is really useful for backward-compatibility: When you come up with a new key and you don't find it in an old document, you can just assume a reasonable default value. As an additional bonus, both formats are easily human-readable and editable with a common text editor, which is really comfortable for testing and debugging.

When you have no problems deciding on one, you could have each class implement a toJson or toXml method which creates a node for that data format. This method not only serializes the object itself, it also calls the appropriate method of any sub-objects and embeds these as a sub-node in the node it returns.

Deserialization works by having each class also implement a constructor which builds the object from a JSON/XML node. This constructor would also call the constructors of its sub-objects passing the sub-nodes to it.

When you are not sure which data format you are going to use and want to keep your options open, you could alternatively use the Visitor pattern. In this pattern the serialization is done by a Visitor object. Each serializable object has a visit(Visitor) method. This method passes all information about the object to the visitor and then passes the visitor on to the visit-method of all its sub-objects. The visitor itself decides what to do with the information. So you can have different visitor classes which serialize the information in different formats.

A very simple example of a character with an inventory and an item in JSON:

{
     name:"Bob",
     level:10,
     class:"Fighter",
     inventory: {
          capacity: 1000,
          content: [
               { 
                    name: "Axe", 
                    type: "weapon",
                    attack: 10
               }, 
               {
                    name: "Healing Potion",
                    type: "potion",
                    amount: 5
               }
          ]
     }
}

This is how the same character could look in XML:

<character>
     <name>Bob</name>
     <level>10</level>
     <class>Fighter</class>
     <inventory capacity=1000>
         <item>
             <name>Axe</name>
             <type>weapon</type>
             <attack>10</attack>
         </item>
         <item>
             <name>Healing Potion</name>
             <type>potion</type>
             <amount>10</amount>
         </item>
     </inventory>
</character>

Which one you choose is subjective. Personally I prefer JSON over XML because I consider XML to be quite over-engineered for most use-cases (my examples show almost everything JSON has to offer but only scratch the surface of the features of XML), but that's just my opinion.

There are mature libraries available for either for most programming languages, so there is no need to fiddle around with string operations. The .NET framework has both an XML library and a JSON library.

\$\endgroup\$
0
\$\begingroup\$

Why not split it in lists by type? An item in inventory can be [some data] just as well as index(or handle) in array of all items. This index can be always generated from a pointer(and back) when saving, same applies to other non numeric attributes. When you got an array of POD(that is the goal) it is really easy to save it as binary.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.