XML Saving System.

i found a tutorial on http://silverbackgames.com/blog/?p=27 how to make a XML Save system, but i have had some trouble with getting it functional,

Writable.js

import System; 
import System.Xml; 
import System.Xml.XPath; 
import System.IO; 


class Writable extends MonoBehaviour{
	private var priority : int;
	//public var savePosition : boolean = false;
	//public var saveParent : boolean = false;

	virtual function Priority() : int{
		return priority;
	}

	virtual function GetWritableType() : String {
		return this.GetType().ToString();
	}

	virtual function GetUniqueName() : String {
		return transform.name;
	}

    virtual function GetPosition(): Vector3 {
	  return transform.position;
	}
	
	virtual function GetActiveState(): boolean {
	  return gameObject.active;
	}
	
	function WriteToXml(writer : XmlWriter) : void{
		writer.WriteStartElement(GetWritableType());
		writer.WriteStartAttribute("name");
		writer.WriteValue(gameObject.name);
		writer.WriteEndAttribute();
		writer.WriteStartElement("state");
		writer.WriteStartAttribute("active");
		writer.WriteValue(gameObject.active);
		writer.WriteEndAttribute();
		writer.WriteEndElement();
		//if(savePosition){
			//SaveLoad.WriteTransform(writer, transform, saveParent);
		//}
		writer.WriteEndElement();
	}
	
	function ReadFromXml(nav : XPathNavigator) : void{
		var name : String = "/bksavegame/"+GetWritableType()+"[@name=\""+gameObject.name+"\"]";
		print(name);
		var tmp : XPathNavigator = nav.SelectSingleNode(name);
		if(tmp == null){
			Debug.LogError("No result found for savefile query: " + name);
			return;
		}
		var reader : XmlReader = tmp.ReadSubtree();
		reader.ReadStartElement(GetWritableType());
		if(reader.LocalName == "state")
			gameObject.SetActiveRecursively(System.Boolean.Parse(reader.GetAttribute("active")));
		else{
			Debug.LogError("Unexpected state");
		}
		//reader.Read();
		//if(reader.LocalName == "transform"){
		//	SaveLoad.ReadTransform(reader, transform);
		//}
		reader.ReadEndElement();
	}


	//virtual function WriteToXml(writer : XmlWriter) : void{;}
	//virtual function ReadFromXml(nav : XPathNavigator) : void{;}
}

and then

NewBehaviourScript 1.js:

import System; 
import System.Xml; 
import System.Xml.XPath; 
import System.IO; 

var Saveables: GameObject;

var toAdd = new ArrayList();

function Start() {
  GatherWritables();
  PrintWritables();
  LoadGame("FirstSave");
}

function PrintWritables() {
  for (var i : int = 0; i < toAdd.Count; i++)
    print(toAdd[i].GetUniqueName);
}

function SaveGame(filename : String) : void{
	var settings : XmlWriterSettings = new XmlWriterSettings();
	settings.CloseOutput = true;
	settings.Indent = true;
	settings.IndentChars = ("\t");

	var writer : XmlWriter = XmlWriter.Create(Application.dataPath + filename + ".xml",settings);
	try{
		writer.WriteStartDocument();
		writer.WriteStartElement("bksavegame");
			writer.WriteStartAttribute("version");
			writer.WriteValue("1.0.1.1");
			writer.WriteEndAttribute();
			for (var writable : Writable in toAdd){
				writable.WriteToXml(writer);
			}
		writer.WriteEndElement();
	}catch(e : System.Exception){
		Debug.LogError(e.ToString());
	}
	writer.Flush();
	writer.Close();
	//if(instance.saveScreenShot)
	//	Screenshot.SaveGameShot(filename);
	lastfile = filename;
	print("saved to " + Application.dataPath + filename + ".xml");
}

function LoadGame(filename : String){
	var settings: XmlReaderSettings = new XmlReaderSettings();
	settings.IgnoreWhitespace = true;
	settings.CloseInput = true;
	var reader : XmlReader = XmlReader.Create(Application.dataPath + filename + ".xml", settings);
	var doc : XPathDocument = new XPathDocument(reader);
	var nav : XPathNavigator = doc.CreateNavigator();
	try{
		for(var writable : Writable in toAdd){
			writable.ReadFromXml(nav);
		}
	}catch(e : System.Exception){
		Debug.LogError(e.ToString());
	}
	reader.Close();
	lastfile = filename;
	print("Loaded from " + Application.dataPath + filename + ".xml");
}

function GatherWritables() {
  for(var c : Component in Saveables.GetComponentsInChildren(Writable, true)){
	  toAdd.Add(c);
	  //print(c.name);
  }
  
  //toAdd.Sort(new CompareWritables());

  var duplicates : ArrayList = new ArrayList();

  for (var i : int = 0; i < toAdd.Count; i++)
	for (var j : int = i+1; j < toAdd.Count; j++)
		if (toAdd[i].GetUniqueName() == toAdd[j].GetUniqueName() 
			toAdd[i].GetWritableType() == toAdd[j].GetWritableType()){
			duplicates.Add(toAdd[j]);
			break;
		}

  for (var w : Writable in duplicates) {
	Debug.LogError("Error collecting Writables: \"" + w.GetUniqueName() + "\" exists more than once with Writable type: " + w.GetType(), w);
  }

  writables = new Writable[toAdd.Count];
  toAdd.CopyTo(writables);
}

any help fixing this bug would be more then awesome, the editor only shows one bug and that is:

System.Xml.XmlException: ‘Element’ is an invalid node type.
at System.Xml.XmlReader.ReadEndElement () [0x00000]
at Writable.ReadFromXml (System.Xml.XPath.XPathNavigator nav) [0x000b6] in C:\Documents and Settings\Administrator\My Documents\TheZombieGame\Assets\Writable.js:68
at NewBehaviourScript 1.LoadGame (System.String filename) [0x0006d] in C:\Documents and Settings\Administrator\My Documents\TheZombieGame\Assets\NewBehaviourScript 1.js:59
UnityEngine.Debug:LogError(Object)
NewBehaviourScript 1:LoadGame(String) (at Assets\NewBehaviourScript 1.js:62)
NewBehaviourScript 1:Start() (at Assets\NewBehaviourScript 1.js:14)[/code]

Simplafy your life, seriously :wink:

using System.Xml;
using System.Xml.Serialization;

Then use XmlSerializer, refer to the following links:

http://www.eggheadcafe.com/articles/system.xml.xmlserialization.asp

hmm, i’ll look in to it, but the code is pasted (mostly) of the tutorial, i have made some minor changes my self, creating the variables and some other stuff, there is a small bug here, i just can’t seem to point out what, and how to fix it…

Hi

This is my code. It is however not a complete package. It was meant as direction more than for actual use.

I’ll see about putting together a unitypackage later this week that makes it more clear. You should not be putting any code in the Writable class, as it is intended to be abstract. When you want to make something that saves, you can extend Writable.

Sounds great, i’ll be looking forward to seeing the package. :o

else that that i have been brain storming on this, because i believe this is a cleaver way to save games, i managed to save the file, but to load it up again was a problem that is still unsolved, but i guess i can move to another corner of the game until the package is released.

(!!unmeasurable gratitude!!) :smile:

In my thread that I have started:
http://forum.unity3d.com/viewtopic.php?t=28597

This does what you are wanting to do with xml saving and loading, just extend the UserData class to save what you want to save and rip out anything you don’t need. It should be pretty straight forward. I have other issues I am trying to resolve in that discussion thread, but the project is linked if you want to download it and look at how it is setup.
The script that does the work is in the Scripts folder called

_GameSaveLoad.cs

I designed it so that you can attach any GameObject and then pull any properties you want to use to store in your XML and then load back in from the XML and assign back to that game object. Idealistically you can set this up so that the game object is the one that the script is attached too and you can do a mass save of all game objects and properties this way.

I’m trying to do a mass save/load but it doesn’t work. How exactly is that possible?!
Thanks in advance.