XML saving and loading question

I’m working on a system to save and load levels as XML files for my 2D game, and it’s already working great for a single object type – anything that only needs to save the id and position. Now I’m trying to find a way to save other types that will need different data saved, and I don’t really know where to start. Most of the stuff I’ve turned up from Googling only covers what I’ve gotten up to so far and not what I’m trying to do next.

These are the two scripts I’m using, the first one handles the actual serializing, saving, and loading of data. I got this from somewhere online and honestly don’t understand most of the technical stuff it does, which is the majority of my problem:

using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
using System.Text;

public class GameSaveLoad : MonoBehaviour
{
    Rect _Save, _Load;
    string _FileLocation, _FileName;
    List<SaveStructure.GameItems> _GameItems;
    string _data = string.Empty;
     
    public List<GameObject> objectList;
 
    [System.NonSerialized]
    public List<int> environmentList = new List<int>();
    [System.NonSerialized]
    public List<int> itemList = new List<int>();
    [System.NonSerialized]
    public List<int> enemyList = new List<int>();
 
    public Hashtable objectID = new Hashtable();
    void Awake()
    { 
        _GameItems = new List<SaveStructure.GameItems>();
     
        int i=0;
        foreach (GameObject thing in objectList) {
            objectID.Add(thing.GetComponent<Properties>().name,i); i++;
        } 
    }
       void Start()
    {
        // We setup our rectangles for our messages
          _Save = new Rect(10, 80, 100, 20);
        _Load = new Rect(10, 100, 100, 20);
        // Where we want to save and load to and from
        _FileLocation = Application.dataPath+"/Resources/Levels/";
        _FileName = Camera.main.GetComponent<MasterScript>().levelName+".xml";
    }
    bool isSaving = false;
    bool isLoading = false;
 
    void OnGUI()
    {
        //***************************************************
        // Loading The Layout...
        // **************************************************    
     
        if (GUI.Button(_Load, "Load") && !isLoading) {
            try {
                isLoading = true;
                LoadXML();             
                GameObject newObject;
             
                //Get all the Entries of the List _GameItems (equal to the Nodes in XML)
                foreach (SaveStructure.GameItems itm in _GameItems) {
                    newObject = Instantiate(objectList[itm.id], new Vector2(itm.posx,itm.posy), Quaternion.identity) as GameObject;
                    newObject.GetComponent<Properties>().flipped = itm.flipped;
                }
            }
            catch (Exception ex) {
                Debug.LogError(ex.ToString());
            }
            finally {
                isLoading = false;
            }
        }
     
        //***************************************************
        // Saving The Layout...
        // ************************************************** 
     
        if (GUI.Button(_Save, "Save") && !isSaving)
        {
            try
            {
                File.Delete(_FileLocation + _FileName);
                _GameItems.Clear();
                isSaving = true;
                SaveStructure.GameItems itm;
                foreach (Properties saveObject in UnityEngine.Object.FindObjectsOfType<Properties>()) {
                    itm = new SaveStructure.GameItems();
                    itm.id = (int)objectID[saveObject.name];
                    itm.posx = saveObject.transform.position.x;
                    itm.posy = saveObject.transform.position.y;
                    itm.flipped = saveObject.flipped;
                    _GameItems.Add(itm);
                }
             
                // Time to creat our XML!
                _data = SerializeObject(_GameItems);
                CreateXML();
            } catch (Exception ex) {
                Debug.LogError(ex.ToString());
            }
            finally {
                isSaving = false;
            }
        }
    }

    string UTF8ByteArrayToString(byte[] characters)
    {
        UTF8Encoding encoding = new UTF8Encoding();
        string constructedString = encoding.GetString(characters);
        return (constructedString);
    }
    byte[] StringToUTF8ByteArray(string pXmlString)
    {
        UTF8Encoding encoding = new UTF8Encoding();
        byte[] byteArray = encoding.GetBytes(pXmlString);
        return byteArray;
    }
    // Here we serialize our UserData object of myData
    string SerializeObject(object pObject)
    {
        string XmlizedString = null;
        MemoryStream memoryStream = new MemoryStream();
        XmlSerializer xs = new XmlSerializer(typeof(List<SaveStructure.GameItems>));
        XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
        xs.Serialize(xmlTextWriter, pObject);
        memoryStream = (MemoryStream)xmlTextWriter.BaseStream;
        XmlizedString = UTF8ByteArrayToString(memoryStream.ToArray());
        return XmlizedString;
    }
    // Here we deserialize it back into its original form
    object DeserializeObject(string pXmlizedString)
    {
        XmlSerializer xs = new XmlSerializer(typeof(List<SaveStructure.GameItems>));
        MemoryStream memoryStream = new MemoryStream(StringToUTF8ByteArray(pXmlizedString));
        return xs.Deserialize(memoryStream);
    }
    // Finally our save and load methods for the file itself
    void CreateXML()
    {
        StreamWriter writer;
        FileInfo t = new FileInfo(_FileLocation + _FileName);
        if (!t.Exists)
        {
            writer = t.CreateText();
        }
        else
        {
            writer = t.CreateText();
        }
        writer.Write(_data);
        writer.Close();
    }
    void LoadXML()
    {
        if (File.Exists(_FileLocation + "/" + _FileName))
        {         
            StreamReader r = File.OpenText(_FileLocation + "/" + _FileName);
            string _info = r.ReadToEnd();
            r.Close();
         
            _GameItems = (List<SaveStructure.GameItems>)DeserializeObject(_info);
        }
        else
        {
           // Debug.Log("Files does not exist: " + _FileLocation + "/" + _FileName);
        }
    }
}

And the second script provides the save structure for the objects, currently only with slots for the object id (not Unity’s instance id, one that I’ve assigned to each level piece), x and y position, and a bool for whether or not the level piece is flipped:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

/* Provides save structure for saving objects to an XML file. Currently only saves id, X position, and Y position. */
[Serializable()]
public class SaveStructure : ISerializable
{
    [Serializable()]
    public class GameItems : ISerializable
    {
          public int id;
        public float posx;
        public float posy;
        public bool flipped;
        public GameItems()
        {
            id = 0;
            posx = 0;
            posy = 0;
            flipped = false;
        }
        // Deserialization
        public GameItems(SerializationInfo info, StreamingContext ctxt)
        {
            id = (int)info.GetValue("id",typeof(int));
            posx = (float)info.GetValue("posx", typeof(float));
            posy = (float)info.GetValue("posy", typeof(float));
               flipped = (bool)info.GetValue("flipped", typeof(bool));
        }
        // Serialization
        public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
        {
            info.AddValue ("id", id);
            info.AddValue("posx", posx);
            info.AddValue("posy", posy);
              info.AddValue("flipped", flipped);
        }
    }
 
    public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
    {
    }
}

That works great for objects that only need to save that much. But now I’m trying to be able to save, for example, invisible triggers that shift the camera’s focus when the player enters them. Those need to save x and y position, x and y dimensions of the trigger, and the x and y position of the focus point for the camera. How would I go about creating different object structures to save? Is this setup even capable of doing that?

Bump, any ideas?

That’s a fairly roundabout way to move data back and forth with XML. Why don’t you simply create a series of classes representing your final data structure and annotate them with the XML attributes in System.Xml.Serialization? You’re code is already halfway there anyway. This at least automates the serialization/deserialization process.

1 Like

Your problem is one you already stated: you don’t even know how what you’re doing works. So study it until you do, and learn about how serialization works.

1 Like

Ahh jeez, somehow I missed your post earlier and only saw Mr. Helpful below you. I found a post with a much simpler method than my current one and managed to get it working for exactly what I need. Thank you though.
http://forum.unity3d.com/threads/saving-and-loading-data-xmlserializer.85925/