So, I’m working on a generic XML serialization system for my save games. I’ve patched it together through various tutorials, and I’m trying to make it so that I can pass it any one of my classes. So far, I’ve got it to be able to save some ScriptableObjects for my inventory.
I’m having trouble figuring out how to get it to load correctly, however.
Here is what it currently looks like:
using System.Xml.Serialization;
using System.Xml;
using System.IO;
public class SaveManager {
public static void Save<T>(T obj, string path){
var serializer = new XmlSerializer(obj.GetType());
var stream = new FileStream(path, FileMode.Create);
serializer.Serialize(stream, obj);
stream.Close ();
}
public static void Load<T>(ref T obj, string path){
var serializer = new XmlSerializer(obj.GetType());
var stream = new FileStream(path, FileMode.Open);
obj = (T)serializer.Deserialize(stream);
stream.Close ();
}
}
And here is my ItemData class, that is my first attempt at serializing:
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.Runtime.Serialization;
using System.Xml.Serialization;
using System.Xml;
public class ItemData : ScriptableObject{
[XmlIgnore]
public string myName;
[XmlIgnore]
public string description;
public int stack = 1;
[XmlIgnore]
public int maxStack = 1;
[XmlIgnore]
public int price;
[XmlIgnore]
public bool consumable;
[XmlIgnore]
public ConsumeType consumeType;
[XmlIgnore]
public int restoreAmount;
[XmlIgnore]
public Rarity rarity;
[XmlIgnore]
public Sprite icon;
[XmlAttribute("origin")]
public ItemData originalData;
public void CopyToInventory(scr_PlayerInventory invScript, int slot){
Debug.Log("Copying to inventory slot " + slot);
invScript.itemInv[slot] = ScriptableObject.CreateInstance<ItemData>();
invScript.itemInv[slot].myName = this.myName;
invScript.itemInv[slot].description = this.description;
invScript.itemInv[slot].stack = this.stack;
invScript.itemInv[slot].maxStack = this.maxStack;
invScript.itemInv[slot].price = this.price;
invScript.itemInv[slot].consumable = this.consumable;
invScript.itemInv[slot].consumeType = this.consumeType;
invScript.itemInv[slot].restoreAmount = this.restoreAmount;
invScript.itemInv[slot].rarity = this.rarity;
invScript.itemInv[slot].icon = this.icon;
//invScript.itemInv[slot].originalData = this.originalData;
invScript.itemInv[slot].name = this.name;
invScript.interactObject.GetComponent<scr_InteractTrigger>().interactList.RemoveAt(0);
}
public void CopyToSceneItem(GameObject sceneObject){
scr_SceneItem sceneData = sceneObject.GetComponent<scr_SceneItem>();
sceneData.myData = this;
}
public ItemData(){
}
}
public enum ConsumeType{
None,
HPRestore,
StamRestore
}
public enum Rarity{
Junk,
Common,
Uncommon,
Rare,
Legendary
}
The originalData variable holds a reference to it’s own asset in the folder. Since I’m copying this instance to other arrays, and adjusting its values and such, I want a reference to it’s original asset, so that I can restore it’s original values at any time. However, if I don’t comment it out, I get an error:
InvalidOperationException: A circular reference was detected while serializing an object of type ItemData
Essentially I just want to save the stack variable, and the originalData variable. When loading this item, I want to use the originalData variable to load the default values from (this way I can make changes to the original asset of an item, and have the changes reflected when loading) and then overwrite the stack variable with the saved one.
I’m still learning about serialization, so some help on doing this would be great.
Also, I get a warning that a ScriptableObject shouldn’t be created with “new” and the warning points to this line:
obj = (T)serializer.Deserialize(stream);
But I’m not sure how to switch that over to CreateInstance, but also have it work for other classes that aren’t ScriptableObjects.
Thanks for any help in advance.