├── .gitattributes ├── Examples ├── Inventory.meta └── Inventory │ ├── Inventory.cs │ ├── Inventory.cs.meta │ ├── Item.cs │ └── Item.cs.meta ├── LICENSE ├── README.md ├── SaveData.cs └── SaveData.cs.meta /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto -------------------------------------------------------------------------------- /Examples/Inventory.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 82e0d154e80f8c943b558bf7cf59f45a 3 | folderAsset: yes 4 | timeCreated: 1521975225 5 | licenseType: Free 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Examples/Inventory/Inventory.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | public class Inventory : MonoBehaviour { 6 | public List Items { get; set; } 7 | void Start () { 8 | // Complex data 9 | Items = new List() 10 | { 11 | new Item(0, "Golden Chalice", "A valuable chalice", new Dictionary(), 1250, Item.ItemRarity.Rare), 12 | new Item(1, "Cheese Slice", "A slice of processed cheese. Yum.", new Dictionary(), 6, Item.ItemRarity.Common), 13 | new Item(2, "Apprentice's Blade", "A sword for a beginner", new Dictionary() 14 | { 15 | {"Power", 5 }, 16 | {"Speed", 10 } 17 | }, 18 | 700, Item.ItemRarity.Rare), 19 | new Item(2, "Grandmaster Blade", "Big pointy sword", new Dictionary() 20 | { 21 | {"Power", 75 }, 22 | {"Speed", 16 } 23 | }, 24 | 4800, Item.ItemRarity.Legendary), 25 | }; 26 | 27 | SaveData.Save(Items, "Inventory"); 28 | // To make sure it's working, let's reset the inventory before we load it in 29 | Items = new List(); 30 | Items = SaveData.Load>("Inventory"); 31 | 32 | // Test it 33 | Debug.Log(Items[2].Stats["Speed"].ToString()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Examples/Inventory/Inventory.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fe0145eaf67d8d74d92e5ca61787dc4e 3 | timeCreated: 1521975232 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /Examples/Inventory/Item.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | [System.Serializable] 6 | public class Item { 7 | public enum ItemRarity { Common, Rare, Legendary } 8 | 9 | public int ID { get; set; } 10 | public string Name { get; set; } 11 | public string Description { get; set; } 12 | public Dictionary Stats { get; set; } 13 | public int Value { get; set; } 14 | public ItemRarity Rarity { get; set; } 15 | 16 | public Item(int id, string name, string description, Dictionary stats, int value, ItemRarity rarity) 17 | { 18 | this.ID = id; 19 | this.Name = name; 20 | this.Description = description; 21 | this.Stats = stats; 22 | this.Value = value; 23 | this.Rarity = rarity; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Examples/Inventory/Item.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fc64019da937ade4d8de373295e33353 3 | timeCreated: 1521975236 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Austin Gregory 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Binary Save/Load for Unity 2 | A simple tool for saving and loading data in Unity. Quickly serialize objects, from Dictionaries and Lists, to complex, serializable object structures. 3 | 4 | All it uses is a BinaryFormatter to serialize and deserialize objects. Any object type (as long as it is marked with a serializable attribute) can be saved and loaded. This does however mean that MonoBehaviour objects will need special attention if you want to save/load data for them. We'll go over that in a second. 5 | 6 | ## How to use it 7 | 8 | To save data, this is what you do: 9 | 10 | ````csharp 11 | SaveData.Save(Items, "Inventory"); 12 | ```` 13 | 14 | This takes the object you're saving as the first parameter, and the key you're saving it with for the second. For instance, this `Items` object looks like this: 15 | 16 | ````csharp 17 | Items = new Dictionary 18 | { 19 | { 12, "Broken Sword" }, 20 | { 20, "Health Scroll" } 21 | }; 22 | ```` 23 | For a more complex inventory structure example, check the examples directory. I'll be adding more over time. 24 | 25 | And then when you're loading your game, to load the Inventory data back in, just do this: 26 | ````csharp 27 | Items = SaveData.Load>("Inventory"); 28 | ```` 29 | 30 | Notice that the methods take a generic type so in this case I know I want an int/string Dictionary. Saving data uses a generic type as well, but the overload simply takes an `Object` so it's optional. 31 | 32 | ## Saving/Loading non-serializable objects 33 | This is something that we have to do a lot of in Unity since MonoBehaviours are quite special. For instance, let's say we want to save this Player object: 34 | 35 | ````csharp 36 | public class Player : MonoBehaviour { 37 | public int Health { get; set; } 38 | public int Level { get; set; } 39 | public float Coolness { get; set; } 40 | void Start() { 41 | Health = 154; 42 | Level = 12; 43 | Coolness = 12.7645f; 44 | } 45 | } 46 | ```` 47 | I need to save the `Health`, `Level`, and `Coolness` properties. Unlike a serializable type, I can't just pass a Player object to the `Save` and `Load` methods. 48 | 49 | We have a couple options, but what I'm going to do is within the same file, create a class called `SerializablePlayer` with those properties, and mark it with `[System.Serializable]`. I can now create an object from this, pass my values in, and save as I please. 50 | 51 | ````csharp 52 | [System.Serializable] 53 | public class SerializablePlayer 54 | { 55 | public int Health { get; set; } 56 | public int Level { get; set; } 57 | public float Coolness { get; set; } 58 | } 59 | ```` 60 | And then to save player: 61 | 62 | ````csharp 63 | SerializablePlayer serializedPlayer = new SerializablePlayer() 64 | { 65 | Health = this.Health, 66 | Level = this.Level, 67 | Coolness = this.Coolness 68 | }; 69 | SaveData.Save(serializedPlayer, "PlayerStats"); 70 | ```` 71 | Load player: 72 | 73 | ````csharp 74 | SerializablePlayer playerData = SaveData.Load("PlayerStats"); 75 | ```` 76 | 77 | This is a trick you may be familiar with if you've worked in Unity long enough. 78 | -------------------------------------------------------------------------------- /SaveData.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.IO; 3 | using System.Runtime.Serialization.Formatters.Binary; 4 | using System.Runtime.Serialization; 5 | 6 | public class SaveData 7 | { 8 | /// 9 | /// Save object with a string identifier 10 | /// 11 | /// Type of object to save 12 | /// Object to save 13 | /// String identifier for the data to load 14 | public static void Save(T objectToSave, string key) 15 | { 16 | SaveToFile(objectToSave, key); 17 | } 18 | 19 | /// 20 | /// Save object with a string identifier 21 | /// 22 | /// Object to save 23 | /// String identifier for the data to load 24 | public static void Save(Object objectToSave, string key) 25 | { 26 | SaveToFile(objectToSave, key); 27 | } 28 | 29 | /// 30 | /// Handle saving data to File 31 | /// 32 | /// Type of object to save 33 | /// Object to serialize 34 | /// Name of file to save to 35 | private static void SaveToFile(T objectToSave, string fileName) 36 | { 37 | // Set the path to the persistent data path (works on most devices by default) 38 | string path = Application.persistentDataPath + "/saves/"; 39 | // Create the directory IF it doesn't already exist 40 | Directory.CreateDirectory(path); 41 | // Grab an instance of the BinaryFormatter that will handle serializing our data 42 | BinaryFormatter formatter = new BinaryFormatter(); 43 | // Open up a filestream, combining the path and object key 44 | FileStream fileStream = new FileStream(path + fileName + ".txt", FileMode.Create); 45 | 46 | // Try/Catch/Finally block that will attempt to serialize/write-to-stream, closing stream when complete 47 | try 48 | { 49 | formatter.Serialize(fileStream, objectToSave); 50 | } 51 | catch (SerializationException exception) 52 | { 53 | Debug.Log("Save failed. Error: " + exception.Message); 54 | } 55 | finally 56 | { 57 | fileStream.Close(); 58 | } 59 | } 60 | 61 | /// 62 | /// Load data using a string identifier 63 | /// 64 | /// Type of object to load 65 | /// String identifier for the data to load 66 | /// 67 | public static T Load(string key) 68 | { 69 | // Set the path to the persistent data path (works on most devices by default) 70 | string path = Application.persistentDataPath + "/saves/"; 71 | // Grab an instance of the BinaryFormatter that will handle serializing our data 72 | BinaryFormatter formatter = new BinaryFormatter(); 73 | // Open up a filestream, combining the path and object key 74 | FileStream fileStream = new FileStream(path + key + ".txt", FileMode.Open); 75 | // Initialize a variable with the default value of whatever type we're using 76 | T returnValue = default(T); 77 | /* 78 | * Try/Catch/Finally block that will attempt to deserialize the data 79 | * If we fail to successfully deserialize the data, we'll just return the default value for Type 80 | */ 81 | try 82 | { 83 | returnValue = (T)formatter.Deserialize(fileStream); 84 | } 85 | catch (SerializationException exception) 86 | { 87 | Debug.Log("Load failed. Error: " + exception.Message); 88 | } 89 | finally 90 | { 91 | fileStream.Close(); 92 | } 93 | 94 | return returnValue; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /SaveData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0d93b425912a9fd4ab298c2432428bf1 3 | timeCreated: 1521701951 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | --------------------------------------------------------------------------------