Introduction
SaveUtility is an open-source save game plugin designed for full level serialization, with a minimal impact on the way you develop your game and write your scripts. SaveUtility was influenced by UnitySerializer which unfortunately hasn’t received any recent updates.
Installation
You can get the project from Github. The project comes with example scenes and scripts that show you how to use the API.
Platforms
Compatible with Windows 7/8 Desktop, Windows 8 Store, Mac OSX and Linux. Requires the latest version of Unity.
Known Issues
You can’t use Ctrl(CMD) + D to duplicate game-objects with a GameObjectSerializer or UniqueIdentifier component because you’ll end up with duplicate IDs. You have to use the Duplicate button located in the GameObjectSerializer/UniqueIdentifier inspector.
If you have a prefab with a GameObjectSerializer or a UniqueIdentifier component you can’t use the default Apply button to apply instance changes to the prefab. You’ll need to use the custom Apply Changes button located in the GameObjectSerializer/UniqueIdentifier inspector.
If you have a prefab with a GameObjectSerializer or a UniqueIdentifier component you can’t use the default Revert button to revert the instance to prefab state. You’ll need to use the custom Revert Changes button located in the GameObjectSerializer/UniqueIdentifier inspector.
Getting Started
Before you start using SaveUtility you should read the wiki.
License
SaveUtility is released under the MIT License.
Code Samples
Making a savable script:
using UnityEngine;
using TeamUtility.IO.SaveUtility;
[SaveComponent] // Only MonoBehaviours with the SaveComponent attribute are saved
public class Health : Monobehaviour
{
public int maxHealth;
[SaveField] // Only fields with the SaveField attribute are saved
private int m_health;
private void Awake()
{
m_health = maxHealth;
}
private void Start()
{
if(m_health <= 0)
gameObject.SetActive(false);
}
public void Damage(int amount)
{
m_health -= amount;
if(m_health < 0)
m_health = 0;
}
// OnSerialized is called after the game object has been saved
private void OnSerialized()
{
Debug.Log("Health has been saved with value: " + m_health);
}
// OnDeserialized is called after the game object has been loaded, sometime between Awake and Start
private void OnDeserialized()
{
Debug.Log("Health has been loaded with value: " + m_health);
}
}
Saving and Loading:
public string checkpointFile;
public bool useJsonSerialization;
private void Update()
{
// Save chekpoint
if(Input.GetKeyDown(KeyCode.F5))
{
IDataSerialier serialier;
if(useJsonSerialization)
{
serializer = new JsonSerializer(checkpointFile);
}
else
{
serializer = new BinarySerializer(checkpointFile);
}
SaveGameManager.Save(serializer);
}
// Load checkpoint
if(Input.GetKeyDown(KeyCode.F9))
{
IDataDeserializer deserializer;
if(useJsonSerialization)
{
deserializer = new JsonDeserializer(chekpointFile);
}
else
{
deserializer = new BinaryDeserializer(chekpointFile);
}
SaveGameManager.Load(deserializer);
}
}
Thanks for making this tool available. However, I encountered a problem when I tried to use it.
I downloaded SaveUtility (v. 1.6) and imported the examples to a new project. The second example “02 - Save Dynamic Objects” has a prefab “Ball”. I registered Ball in Required Assets in SaveUtility. Then I put two Ball objects in the scene (by dragging prefab Ball to the scene). Both objects Ball have the same ID values in GameObjectSerializer component.
When I run the game I get error:
ArgumentException: An element with the same key already exists in the dictionary.
System.Collections.Generic.Dictionary`2[System.String,UnityEngine.GameObject].Add (System.String key, UnityEngine.GameObject value) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Collections.Generic/Dictionary.cs:404)
TeamUtility.IO.SaveUtility.SaveUtility.BuildReferenceTable () (at Assets/SaveUtility/Source/Runtime/SaveUtility.cs:100)
TeamUtility.IO.SaveUtility.SaveUtility.Awake () (at Assets/SaveUtility/Source/Runtime/SaveUtility.cs:89)
You shouldn’t have dragged the prefab in the scene. Normally your prefabs shouldn’t have a GameObjectSerializer unless you plan to only instantiate them at runtime using SaveUtility.Instantiate, as is the case in the second example.
Another thing to keep in mind is that you shouldn’t duplicate objects that have a UniqueIdentifier or a GameObjectSerializer because you’ll end up with duplicate IDs which will throw the error you mentioned.
Thank you for answering.
I expected that two instances of the same prefab would have different ID when placed in a scene, like with UnitySerializer tool. As I understand there’s no way to use SaveUtility for prefabs dragged in a scene and not only used at runtime?
You can use SaveUtility with prefabs just don’t put the GameObjectSerializer on the prefab. Put it on the instance after you drag the prefab in the scene. You also need to make sure you don’t hit the Apply button in the inspector because it will override the GameObjectSerializers of all instances.
Thanks so much for making this! I’ve been fiddling with it in my game Project Peacefulgame, and I’m really liking it. Just wondering, could you make a network-enabled version of SaveUtility.InstantiateSavable? Thanks!
When you load the game, it does a normal GameObject.Instantiate(), which means stuff loaded in from your first save won’t appear in your second save.
E.G, I open the game and place a log down, save, quit, load again a few minutes later, build a second log on top of the first, save, quit, load again, only one log will exist.
Add a SaveUtility.InstantiateSavable in your Deserialize function to fix this!
I tried to replicate your bug using the second example and it worked fine. I spawned 3 balls, saved, loaded the level, spawned 2 more balls and saved again. When I loaded the second time I had 5 balls in the level.
Did you add a GameObjectSerializer to the log prefab? Prefabs that are instantiated at runtime need a GameObjectSerializer component to be saved. If the prefab doesn’t have a GameObjectSerializer when you load the game the prefab is instantiated but it isn’t deserialized and registered with the SaveUtility so they don’t get saved the second time.
Maybe you should look for another save solution. SaveUtility was not designed for multiplayer or open world games so you’ll have a hard time getting it to work in your game.
I’m having a bit of trouble instantiating multiple prefabs using instantiate.savable. I can get one prefab to spawn just fine using a reference to template as public gameobject. But can’t seem to spawn different types of prefab. I tried using a public array. Not a great coder so I could be making a basic error. But is what I’m trying to describe possible? Thanks.
How does instantiate savable fail? Does it fail to create the object or does it fail to load it after you save? Did you add the prefabs to the “Required Assets” tab in the SaveUtility component inspector? Can you post the spawn code here so I can have a look at it?
Thanks for the quick response. I think I’ve got it working now. It was failing to load rather than failing to spawn. And yes I did add the prefabs to required assets. Problem was with my array. Just re-tested and was able to save/load two different prefabs. Pretty happy about that, had tried unity serialiser but couldn’t get it to work.