├── .codacy.yml
├── .gitattributes
├── .gitignore
├── .travis.yml
├── Editor.meta
├── Editor
├── SaveLoadManagerEditor.cs
├── SaveLoadManagerEditor.cs.meta
├── com.gameframe.saveload.Editor.asmdef
└── com.gameframe.saveload.Editor.asmdef.meta
├── LICENSE.md
├── LICENSE.md.meta
├── README.md
├── README.md.meta
├── Runtime.meta
├── Runtime
├── EncryptionUtility.cs
├── EncryptionUtility.cs.meta
├── ISerializationMethod.cs
├── ISerializationMethod.cs.meta
├── ISerializationMethodEncrypted.cs
├── ISerializationMethodEncrypted.cs.meta
├── SaveLoadManager.cs
├── SaveLoadManager.cs.meta
├── SaveLoadUtility.cs
├── SaveLoadUtility.cs.meta
├── SerializationMethodBinary.cs
├── SerializationMethodBinary.cs.meta
├── SerializationMethodBinaryEncrypted.cs
├── SerializationMethodBinaryEncrypted.cs.meta
├── SerializationMethodJsonDotNet.cs
├── SerializationMethodJsonDotNet.cs.meta
├── SerializationMethodJsonDotNetEncrypted.cs
├── SerializationMethodJsonDotNetEncrypted.cs.meta
├── SerializationMethodType.cs
├── SerializationMethodType.cs.meta
├── SerializationMethodUnityJson.cs
├── SerializationMethodUnityJson.cs.meta
├── SerializationMethodUnityJsonEncrypted.cs
├── SerializationMethodUnityJsonEncrypted.cs.meta
├── com.gameframe.saveload.asmdef
├── com.gameframe.saveload.asmdef.meta
├── csc.rsp
└── csc.rsp.meta
├── Tests.meta
├── Tests
├── Editor.meta
├── Editor
│ ├── SaveLoadUtilityTests.cs
│ ├── SaveLoadUtilityTests.cs.meta
│ ├── com.gameframe.saveload.editor.tests.asmdef
│ └── com.gameframe.saveload.editor.tests.asmdef.meta
├── Runtime.meta
└── Runtime
│ ├── SaveLoadManagerTests.cs
│ ├── SaveLoadManagerTests.cs.meta
│ ├── com.gameframe.saveload.Tests.asmdef
│ └── com.gameframe.saveload.Tests.asmdef.meta
├── package.json
└── package.json.meta
/.codacy.yml:
--------------------------------------------------------------------------------
1 | exclude_paths:
2 | - '*.md'
3 | - 'Tests/Runtime/*.cs'
4 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # This .gitignore file should be placed at the root of your Unity project directory
2 | #
3 | # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore
4 | #
5 | /[Ll]ibrary/
6 | /[Tt]emp/
7 | /[Oo]bj/
8 | /[Bb]uild/
9 | /[Bb]uilds/
10 | /[Ll]ogs/
11 | /[Mm]emoryCaptures/
12 |
13 | # Never ignore Asset meta data
14 | !/[Aa]ssets/**/*.meta
15 |
16 | # Uncomment this line if you wish to ignore the asset store tools plugin
17 | # /[Aa]ssets/AssetStoreTools*
18 |
19 | # Autogenerated Jetbrains Rider plugin
20 | [Aa]ssets/Plugins/Editor/JetBrains*
21 |
22 | # Visual Studio cache directory
23 | .vs/
24 |
25 | # Gradle cache directory
26 | .gradle/
27 |
28 | # Autogenerated VS/MD/Consulo solution and project files
29 | ExportedObj/
30 | .consulo/
31 | *.csproj
32 | *.unityproj
33 | *.sln
34 | *.suo
35 | *.tmp
36 | *.user
37 | *.userprefs
38 | *.pidb
39 | *.booproj
40 | *.svd
41 | *.pdb
42 | *.mdb
43 | *.opendb
44 | *.VC.db
45 |
46 | # Unity3D generated meta files
47 | *.pidb.meta
48 | *.pdb.meta
49 | *.mdb.meta
50 |
51 | # Unity3D generated file on crash reports
52 | sysinfo.txt
53 |
54 | # Builds
55 | *.apk
56 | *.unitypackage
57 |
58 | # Crashlytics generated file
59 | crashlytics-build.properties
60 |
61 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: objective-c
2 | os: osx
3 | osx_image: xcode11.2
4 | branches:
5 | only:
6 | - master
7 | cache:
8 | timeout: 86400
9 | directories:
10 | - $HOME/unity_download_cache/ #Cache unity installer files
11 | - $HOME/project_cache/ #Cache for created unity projects
12 | before_install:
13 | - bash <(curl -fsSL https://raw.githubusercontent.com/coryleach/UnityTravisCI/master/bin/before-install.sh)
14 | install:
15 | - ./install.sh
16 | - source ./find-unity.sh #source this because it exports required env vars
17 | before_script:
18 | - ./get-license.sh
19 | script:
20 | - source ./setup-project.sh #source this because it exports project path
21 | - ./run-tests.sh playmode
22 | after_success:
23 | - ./return-license.sh
24 | - ./clean-project.sh
25 | after_failure:
26 | - ./return-license.sh
27 | - ./clean-project.sh
28 |
29 |
--------------------------------------------------------------------------------
/Editor.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 7237aab39c2354afeb45924421f8dbc7
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Editor/SaveLoadManagerEditor.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using UnityEditor;
3 | using UnityEngine;
4 |
5 | namespace Gameframe.SaveLoad.Editor
6 | {
7 | ///
8 | /// Editor for SaveLoadManager
9 | ///
10 | [CustomEditor(typeof(SaveLoadManager))]
11 | public class SaveLoadManagerEditor : UnityEditor.Editor
12 | {
13 | public override void OnInspectorGUI()
14 | {
15 | EditorGUILayout.BeginVertical("Box");
16 | base.OnInspectorGUI();
17 | EditorGUILayout.EndVertical();
18 |
19 | var manager = (SaveLoadManager) target;
20 |
21 | if (manager.IsEncrypted && (string.IsNullOrEmpty(manager.Key)))
22 | {
23 | EditorGUILayout.HelpBox("Encryption key cannot be null or empty.",MessageType.Error);
24 | }
25 |
26 | if (manager.IsEncrypted && (string.IsNullOrEmpty(manager.Salt)))
27 | {
28 | EditorGUILayout.HelpBox("Salt cannot be null or empty.",MessageType.Error);
29 | }
30 |
31 | var savePath = SaveLoadUtility.GetRuntimeSavePath(manager.DefaultFolder, manager.BaseFolder);
32 |
33 | EditorGUILayout.BeginVertical("Box");
34 | EditorGUILayout.LabelField("Default Save Path");
35 | EditorGUILayout.LabelField(savePath);
36 | EditorGUILayout.EndVertical();
37 |
38 | if (GUILayout.Button("Open Data Folder"))
39 | {
40 | if (!Directory.Exists(savePath))
41 | {
42 | //Create directory if it does not exist
43 | Directory.CreateDirectory(savePath);
44 | }
45 | EditorUtility.RevealInFinder(savePath);
46 | }
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/Editor/SaveLoadManagerEditor.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: a2eb6021040d8244a9d0ccbe547c7d51
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/com.gameframe.saveload.Editor.asmdef:
--------------------------------------------------------------------------------
1 | { "name": "com.gameframe.saveload.Editor", "references": [ "com.gameframe.saveload" ], "optionalUnityReferences": [], "includePlatforms": [ "Editor" ], "excludePlatforms": [] }
--------------------------------------------------------------------------------
/Editor/com.gameframe.saveload.Editor.asmdef.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 8460321a66021460f9f0ff8e7dcd619a
3 | AssemblyDefinitionImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Cory
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.
22 |
--------------------------------------------------------------------------------
/LICENSE.md.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: ccfbd4aa49301dc43a3c4f0934fe7d60
3 | DefaultImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Gameframe.SaveLoad 👋
5 |
6 |
17 |
18 | Serialization helper utility that supports save, load and encryption.
19 |
20 | ## Quick Package Install
21 |
22 | #### Using UnityPackageManager (for Unity 2019.3 or later)
23 | Open the package manager window (menu: Window > Package Manager)
24 | Select "Add package from git URL...", fill in the pop-up with the following link:
25 | https://github.com/coryleach/UnitySaveLoad.git#1.0.10
26 |
27 | #### Using UnityPackageManager (for Unity 2019.1 or later)
28 |
29 | Find the manifest.json file in the Packages folder of your project and edit it to look like this:
30 | ```js
31 | {
32 | "dependencies": {
33 | "com.gameframe.saveload": "https://github.com/coryleach/UnitySaveLoad.git#1.0.10",
34 | ...
35 | },
36 | }
37 | ```
38 |
39 |
40 |
43 |
44 | ## Usage
45 |
46 | SaveLoadManager is not a singleton. Multiple instances may be used and created.
47 | In the project tab menu select Create->Gameframe->SaveLoad->SaveLoadManager
48 | This will create an instance of a SaveLoadManager asset.
49 | Select the created object and configure options via the inspector.
50 |
51 | ```C#
52 | //Use the Project tab's create menu GameFrame->SaveLoad->SaveLoadManager to create a manager
53 | //You can then use public or serialized fields to reference your save system.
54 | // OR
55 | //Create a Manager at Runtime like this
56 | manager = SaveLoadManager.Create("BaseDirectory","SaveDirectory",SerializationMethod.Default);
57 |
58 | //Save object to disk in a file named "MySave.data"
59 | manager.Save("MySave.data",objectToBeSaved);
60 |
61 | //Load from disk
62 | //loadedObject will be null if the file does not exist
63 | var loadedObject = manager.Load("MySave.data");
64 |
65 | //Delete saved file
66 | manager.DeleteSave("MySave.data");
67 |
68 | //Setup a Custom Save/Load Method by passing any object that implements ISerializationMethod
69 | manager.SetCustomSerializationMethod(new MyCustomSerializationMethod());
70 |
71 | //Save a ScriptableObject or any object derived from UnityEngine.Object directly to disk
72 | var myScriptableObject = ScriptableObject.CreateInstance();
73 | manager.SaveUnityObject(myScriptableObject,"MyUnityObjectData.dat");
74 |
75 | //Loading a UnityEngine.Object type requires an existing object to overwrite
76 | //The following method will overwrite all the serialized fields on myScriptableObject with values loaded from disk
77 | manager.LoadUnityObjectOverwrite(myScriptableObject,"MyUnityObjectData.data");
78 | ```
79 |
80 | ## Enable Json.Net Support
81 |
82 | This package has been tested with version 3.0.2 of the newtonsoft json package.
83 | Import the Netwonsoft Json package from the package manager or copy and paste the below into your package manifest.
84 | ```C#
85 | "com.unity.nuget.newtonsoft-json": "3.0.2"
86 | ```
87 | In player settings add the string 'JSON_DOT_NET' to Scripting Define Symbols.
88 |
89 |
90 |
91 | ## Author
92 |
93 | 👤 **Cory Leach**
94 |
95 | * Twitter: [@coryleach](https://twitter.com/coryleach)
96 | * Github: [@coryleach](https://github.com/coryleach)
97 |
98 |
99 | ## Show your support
100 | Give a ⭐️ if this project helped you!
101 |
102 |
103 | ***
104 | _This README was generated with ❤️ by [Gameframe.Packages](https://github.com/coryleach/unitypackages)_
105 |
--------------------------------------------------------------------------------
/README.md.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 49313290095b441d3b6620ef487b5d20
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Runtime.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 8fc3e020d626c4f93b89105982d4d1cb
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Runtime/EncryptionUtility.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Security.Cryptography;
3 | using System.Text;
4 |
5 | namespace Gameframe.SaveLoad
6 | {
7 | public static class EncryptionUtility
8 | {
9 | ///
10 | /// Encrypt an input stream
11 | ///
12 | /// Stream to be encrypted
13 | /// Stream ecrypted data will be output to
14 | /// Encryption Key
15 | /// Encryption Salt
16 | public static void Encrypt(Stream inputStream, Stream outputStream, string key, string salt)
17 | {
18 | var cryptoMethod = new RijndaelManaged();
19 | var cryptoKey = new Rfc2898DeriveBytes(key, Encoding.ASCII.GetBytes(salt));
20 | cryptoMethod.Key = cryptoKey.GetBytes(cryptoMethod.KeySize / 8);
21 | cryptoMethod.IV = cryptoKey.GetBytes(cryptoMethod.BlockSize / 8);
22 | using (var cryptostream = new CryptoStream(inputStream, cryptoMethod.CreateEncryptor(), CryptoStreamMode.Read))
23 | {
24 | cryptostream.CopyTo(outputStream);
25 | }
26 | }
27 |
28 | ///
29 | /// Decrypt an input stream to an output stream.
30 | ///
31 | /// Stream with encrypted bytes to be read from
32 | /// Stream that decrypted bytes will be written to
33 | /// Encryption Key
34 | /// Encryption Salt
35 | public static void Decrypt(Stream inputStream, Stream outputStream, string key, string salt)
36 | {
37 | var cryptoMethod = new RijndaelManaged();
38 | var cryptoKey = new Rfc2898DeriveBytes(key, Encoding.ASCII.GetBytes(salt));
39 | cryptoMethod.Key = cryptoKey.GetBytes(cryptoMethod.KeySize / 8);
40 | cryptoMethod.IV = cryptoKey.GetBytes(cryptoMethod.BlockSize / 8);
41 | using (var cryptostream = new CryptoStream(inputStream, cryptoMethod.CreateDecryptor(), CryptoStreamMode.Read))
42 | {
43 | cryptostream.CopyTo(outputStream);
44 | }
45 | }
46 | }
47 | }
48 |
49 |
50 |
--------------------------------------------------------------------------------
/Runtime/EncryptionUtility.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 5cfa2a0edb04aa748a79f4a756d30148
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/ISerializationMethod.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 |
3 | namespace Gameframe.SaveLoad
4 | {
5 | ///
6 | /// Interface for a method of serializing and deserializing an object tagged with the Serializable attribute
7 | ///
8 | public interface ISerializationMethod
9 | {
10 | void Save(object savedObject, FileStream fileStream);
11 | object Load(System.Type savedObjectType, FileStream fileStream);
12 | object Copy(object copyObject);
13 | }
14 | }
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Runtime/ISerializationMethod.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 1ddf8d2e1522cf6408ed75c49182d026
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/ISerializationMethodEncrypted.cs:
--------------------------------------------------------------------------------
1 | namespace Gameframe.SaveLoad
2 | {
3 | ///
4 | /// Interface for an encrypted method of serializing and deserializing an object tagged with the Serializable attribute
5 | ///
6 | public interface ISerializationMethodEncrypted : ISerializationMethod
7 | {
8 | void SetEncryption(string key, string salt);
9 | }
10 | }
--------------------------------------------------------------------------------
/Runtime/ISerializationMethodEncrypted.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f2ca7b1f5ba36c044b4af60afa6f982a
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/SaveLoadManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 |
5 | namespace Gameframe.SaveLoad
6 | {
7 | ///
8 | /// SaveLoadManager
9 | /// Manager for saving and loading objects to/from disk.
10 | ///
11 | [CreateAssetMenu(menuName = "Gameframe/SaveLoad/SaveLoadManager")]
12 | public class SaveLoadManager : ScriptableObject
13 | {
14 | [Header("Settings"),SerializeField] private string defaultFolder = "SaveData";
15 | public string DefaultFolder => defaultFolder;
16 |
17 | [SerializeField] private string baseFolder = "GameData";
18 | public string BaseFolder => baseFolder;
19 |
20 | [SerializeField] private SerializationMethodType saveMethod = SerializationMethodType.Default;
21 |
22 | [Header("Encryption"),SerializeField] protected string key = string.Empty;
23 | public string Key => key;
24 |
25 | [SerializeField] protected string salt = string.Empty;
26 | public string Salt => salt;
27 |
28 | private Dictionary _methods;
29 |
30 | private void OnEnable()
31 | {
32 | //OnEnabled will be called when entering play mode in editor but also when selecting the object in editor
33 | //Constructor may only be called once which may lead to some weird behaviour if we use it for initializing this dictionary
34 | //Using OnEnabled ensures we do this initialization and the dictionary is fresh when we hit the play button in editor
35 | _methods = new Dictionary();
36 | }
37 |
38 | ///
39 | /// Helper Method for constructing a new instance of SaveLoadManager which specific protected settings
40 | ///
41 | /// Base directory folder
42 | /// Default folder to save files to
43 | /// Method to use to save and load files
44 | /// Encryption key is required if using an encrypted method.
45 | /// Encryption salt is required if using an ecrypted method.
46 | /// Newly created instance of SaveLoadManager
47 | public static SaveLoadManager Create(string baseFolder, string defaultFolder, SerializationMethodType saveMethod, string key = null, string salt = null)
48 | {
49 | var instance = CreateInstance();
50 |
51 | instance.baseFolder = baseFolder;
52 | instance.defaultFolder = defaultFolder;
53 | instance.key = key;
54 | instance.salt = salt;
55 | instance.saveMethod = saveMethod;
56 |
57 | return instance;
58 | }
59 |
60 | ///
61 | /// Save an object to disk
62 | ///
63 | /// object to be saved
64 | /// Name of file that will be written to
65 | /// Name of the folder that should contain the file
66 | public void Save(object obj, string filename, string folder = null)
67 | {
68 | if (string.IsNullOrEmpty(folder))
69 | {
70 | folder = defaultFolder;
71 | }
72 | var saveLoadMethod = GetSaveLoadMethod(saveMethod);
73 | SaveLoadUtility.Save(obj,saveLoadMethod,filename,folder, baseFolder);
74 | }
75 |
76 | ///
77 | /// Gets the list of save files that have been created
78 | ///
79 | /// sub folder
80 | ///
81 | /// Will use Application.streamingAssetsPath as base path if true otherwise Application.persistentDataPath
82 | /// list of file names (excludes the path)
83 | public string[] GetFiles(string folder = null, string extension = null, bool streamingAssets = false)
84 | {
85 | if (string.IsNullOrEmpty(folder))
86 | {
87 | folder = defaultFolder;
88 | }
89 | return SaveLoadUtility.GetSavedFiles(folder,baseFolder, extension, streamingAssets);
90 | }
91 |
92 | ///
93 | /// Gets the list of save files that have been created
94 | ///
95 | /// list to be populated with file names
96 | /// sub folder
97 | ///
98 | /// Will use Application.streamingAssetsPath as base path if true otherwise Application.persistentDataPath
99 | /// list of file names (excludes the path)
100 | public void GetFiles(List list, string folder = null, string extension = null, bool streamingAssets = false)
101 | {
102 | if (string.IsNullOrEmpty(folder))
103 | {
104 | folder = defaultFolder;
105 | }
106 |
107 | SaveLoadUtility.GetSavedFiles(list, folder,baseFolder, extension, streamingAssets);
108 | }
109 |
110 | ///
111 | /// Creat a copy of an object by serializing and deserializing it.
112 | /// Not compatible with unity objects.
113 | ///
114 | /// object to be copied
115 | /// duplicated instance
116 | public object Copy(object obj)
117 | {
118 | if (obj is UnityEngine.Object)
119 | {
120 | throw new ArgumentException("UnityEngine.Object and child types not supported by copy method.");
121 | }
122 | var saveLoadMethod = GetSaveLoadMethod(saveMethod);
123 | return saveLoadMethod.Copy(obj);
124 | }
125 |
126 | ///
127 | /// Creat a copy of an object by serializing and deserializing it.
128 | /// Not compatible with Unity objects.
129 | ///
130 | /// object to be copied
131 | /// Type of object to be copied.
132 | /// duplicated instance
133 | public T Copy(T obj)
134 | {
135 | if (obj is UnityEngine.Object)
136 | {
137 | throw new ArgumentException("UnityEngine.Object and child types not supported by copy method.");
138 | }
139 | var saveLoadMethod = GetSaveLoadMethod(saveMethod);
140 | return (T)saveLoadMethod.Copy(obj);
141 | }
142 |
143 | ///
144 | /// Get the full path to a save file
145 | ///
146 | /// Name of file
147 | /// Name of folder containing file
148 | /// true if saves are from streaming assets
149 | /// full path to the file on disk
150 | public string GetPath(string filename, string folder = null, bool streamingAssets = false)
151 | {
152 | if (string.IsNullOrEmpty(folder))
153 | {
154 | folder = defaultFolder;
155 | }
156 | var savePath = SaveLoadUtility.GetSavePath(folder, baseFolder, streamingAssets);
157 | var saveFilename = savePath + filename;
158 | return saveFilename;
159 | }
160 |
161 | ///
162 | /// Load an object from disk
163 | ///
164 | /// Name of file to load from
165 | /// Name of folder containing the file
166 | /// Load file from streaming assets
167 | /// Type of object to be loaded from file
168 | /// Instance of object loaded from file
169 | public T Load(string filename, string folder = null, bool streamingAssets = false)
170 | {
171 | return (T)Load(typeof(T), filename, folder, streamingAssets);
172 | }
173 |
174 | ///
175 | /// Load an object from disk
176 | ///
177 | /// Type of object to be loaded
178 | /// Name of file to load object from
179 | /// Name of folder containing the file to be loaded
180 | /// Load file from streaming assets
181 | /// Instance of object to be loaded. Null if file did not exist.
182 | public object Load(Type type, string filename, string folder = null, bool streamingAssets = false)
183 | {
184 | if (string.IsNullOrEmpty(folder))
185 | {
186 | folder = defaultFolder;
187 | }
188 | var saveLoadMethod = GetSaveLoadMethod(saveMethod);
189 | return SaveLoadUtility.Load(type, saveLoadMethod,filename,folder, baseFolder, streamingAssets);
190 | }
191 |
192 | ///
193 | /// Delete saved file from disk
194 | ///
195 | ///
196 | ///
197 | public void DeleteSave(string filename, string folder = null)
198 | {
199 | if (string.IsNullOrEmpty(folder))
200 | {
201 | folder = defaultFolder;
202 | }
203 | SaveLoadUtility.DeleteSavedFile(filename,folder, baseFolder);
204 | }
205 |
206 | ///
207 | /// Save object to file and specify the method of save/load
208 | ///
209 | /// Method to be used to save the file to disk.
210 | /// Object to be written to disk.
211 | /// Name of file to write to.
212 | /// Name of folder to save to. If null the default folder will be used.
213 | public void SaveWithMethod(SerializationMethodType methodType, object obj, string filename, string folder = null)
214 | {
215 | var saveLoadMethod = GetSaveLoadMethod(methodType);
216 | SaveLoadUtility.Save(obj,saveLoadMethod,filename,folder);
217 | }
218 |
219 | ///
220 | /// Load object from file and specify the method of save/load
221 | ///
222 | /// Method to be used to save the file to disk.
223 | /// Name of file to be read from.
224 | /// Name of the folder containing the file.
225 | /// Type of object to be loaded from the file.
226 | /// Object instance loaded from file. Null if file does not exist or load failed.
227 | public object LoadWithMethod(SerializationMethodType methodType, string filename, string folder = null)
228 | {
229 | return (T)LoadWithMethod(methodType, typeof(T), filename, folder);
230 | }
231 |
232 | ///
233 | /// Load object from file and specify the method of save/load
234 | ///
235 | /// Method to be used to save the file to disk.
236 | /// Name of file to be read from.
237 | /// Name of the folder containing the file.
238 | /// Type of object to be loaded from the file.
239 | /// Object instance loaded from file. Null if file does not exist or load failed.
240 | public object LoadWithMethod(SerializationMethodType methodType, Type type, string filename, string folder = null)
241 | {
242 | var saveLoadMethod = GetSaveLoadMethod(methodType);
243 | return SaveLoadUtility.Load(type, saveLoadMethod,filename,folder);
244 | }
245 |
246 | ///
247 | /// Saves a unity object to a file.
248 | /// First converts the object to JSON using the Unity Json utility.
249 | /// Then wraps the json string in an object so that object can be serialized with the normal methods.
250 | ///
251 | /// Object to be saved.
252 | /// Name of file to save to
253 | /// Name of folder to save the file in. Uses defualt folder when null.
254 | public void SaveUnityObject(UnityEngine.Object unityObj, string filename, string folder = null)
255 | {
256 | var savedObj = new JsonSerializedUnityObject
257 | {
258 | jsonData = JsonUtility.ToJson(unityObj)
259 | };
260 |
261 | Save(savedObj,filename,folder);
262 | }
263 |
264 | ///
265 | /// Loads from file and overwrites the given object with the saved values.
266 | /// File must have been saved with SaveUnityObject method.
267 | /// Uses Unity's JsonUtility and has the same limitations.
268 | ///
269 | /// Object onto which the values from file will be written
270 | /// Name of file to read from.
271 | /// Name of folder containing file. If null the default folder will be used.
272 | /// True when something is loaded. False if file or data was not found.
273 | public bool LoadUnityObjectOverwrite(UnityEngine.Object objectToOverwrite, string filename, string folder = null)
274 | {
275 | var savedObj = Load(filename, folder);
276 |
277 | if (savedObj == null || string.IsNullOrEmpty(savedObj.jsonData))
278 | {
279 | return false;
280 | }
281 |
282 | JsonUtility.FromJsonOverwrite(savedObj.jsonData,objectToOverwrite);
283 | return true;
284 | }
285 |
286 | ///
287 | /// Copies the serializable fields from one UnityEngine.Object to another
288 | ///
289 | /// object which should be copied
290 | /// object onto which copied fields should be written
291 | public void CopyUnityObjectOverwrite(UnityEngine.Object toCopy, UnityEngine.Object toOverwrite)
292 | {
293 | var jsonData = JsonUtility.ToJson(toCopy);
294 | JsonUtility.FromJsonOverwrite(jsonData,toOverwrite);
295 | }
296 |
297 | ///
298 | /// JsonSerializedUnityObject
299 | /// Wrapper for json data created when using Unity's JsonUtility to serialize an object derived from UnityEngine.Object
300 | /// This allows us to bypass some of the limitations of BinaryFormatter and serializing unity types such as Vector3, Quaternion etc.
301 | /// Many Unity structs are oddly not marked as serializable.
302 | ///
303 | [Serializable]
304 | private class JsonSerializedUnityObject
305 | {
306 | public string jsonData;
307 | }
308 |
309 | public bool IsEncrypted => (saveMethod == SerializationMethodType.BinaryEncrypted || saveMethod == SerializationMethodType.UnityJsonEncrypted);
310 |
311 | ///
312 | /// Sets a custom serialization method
313 | ///
314 | ///
315 | public void SetCustomSerializationMethod(ISerializationMethod customSerializationMethod)
316 | {
317 | if (_methods == null)
318 | {
319 | _methods = new Dictionary();
320 | }
321 | _methods[SerializationMethodType.Custom] = customSerializationMethod;
322 | }
323 |
324 | private ISerializationMethod GetSaveLoadMethod(SerializationMethodType methodType)
325 | {
326 | if (_methods == null)
327 | {
328 | _methods = new Dictionary();
329 | }
330 |
331 | if (_methods.TryGetValue(methodType, out var method))
332 | {
333 | return method;
334 | }
335 |
336 | //Create method if it did not yet exist
337 | switch (methodType)
338 | {
339 | case SerializationMethodType.Default:
340 | method = GetSaveLoadMethod(SerializationMethodType.UnityJson);
341 | break;
342 | case SerializationMethodType.Binary:
343 | method = new SerializationMethodBinary();
344 | break;
345 | case SerializationMethodType.UnityJson:
346 | method = new SerializationMethodUnityJson();
347 | break;
348 |
349 | case SerializationMethodType.BinaryEncrypted:
350 | method = new SerializationMethodBinaryEncrypted(key,salt);
351 | break;
352 | case SerializationMethodType.UnityJsonEncrypted:
353 | method = new SerializationMethodUnityJsonEncrypted(key,salt);
354 | break;
355 |
356 | #if JSON_DOT_NET
357 | case SerializationMethodType.JsonDotNet:
358 | method = new SerializationMethodJsonDotNet();
359 | break;
360 | case SerializationMethodType.JsonDotNetEncrypted:
361 | method = new SerializationMethodJsonDotNetEncrypted(key,salt);
362 | break;
363 | #endif
364 |
365 | case SerializationMethodType.Custom:
366 | throw new MissingComponentException("SerializationMethodType is Custom but no custom ISerializationMethod was found.");
367 | default:
368 | throw new ArgumentOutOfRangeException(nameof(methodType), methodType, "SaveLoadMethodType not supported");
369 | }
370 |
371 | _methods[methodType] = method;
372 |
373 | return method;
374 | }
375 |
376 | }
377 | }
378 |
--------------------------------------------------------------------------------
/Runtime/SaveLoadManager.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: b7aea37aa7edc45cf8b8ecbba9748cc3
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/SaveLoadUtility.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.IO;
3 | using System.Linq;
4 | using UnityEngine;
5 |
6 | namespace Gameframe.SaveLoad
7 | {
8 | public static class SaveLoadUtility
9 | {
10 | //Default folder name will be used if none is provided.
11 | private const string DefaultFolderName = "SaveLoad";
12 | private const string DefaultBaseFolderPath = "GameData";
13 |
14 | public static string GetSavePath(string folderName = null, string baseFolderPath = null, bool streamingAssets = false)
15 | {
16 | return !streamingAssets ? GetRuntimeSavePath(folderName, baseFolderPath) : GetStreamingAssetsSavePath(folderName, baseFolderPath);
17 | }
18 |
19 | public static string GetRuntimeSavePath(string folderName = null, string baseFolderPath = null)
20 | {
21 | if (string.IsNullOrEmpty(folderName))
22 | {
23 | folderName = DefaultFolderName;
24 | }
25 |
26 | if (string.IsNullOrEmpty(baseFolderPath))
27 | {
28 | baseFolderPath = DefaultBaseFolderPath;
29 | }
30 |
31 | var savePath = $"{Application.persistentDataPath}/{baseFolderPath}/";
32 | savePath = $"{savePath}{folderName}/";
33 | return savePath;
34 | }
35 |
36 | public static string GetStreamingAssetsSavePath(string folderName = null, string baseFolderPath = null)
37 | {
38 | if (string.IsNullOrEmpty(folderName))
39 | {
40 | folderName = DefaultFolderName;
41 | }
42 |
43 | if (string.IsNullOrEmpty(baseFolderPath))
44 | {
45 | baseFolderPath = DefaultBaseFolderPath;
46 | }
47 |
48 | var savePath = $"{Application.streamingAssetsPath}/{baseFolderPath}/";
49 | savePath = $"{savePath}{folderName}/";
50 | return savePath;
51 | }
52 |
53 | ///
54 | ///
55 | ///
56 | ///
57 | ///
58 | private static string GetSaveFileName(string fileName)
59 | {
60 | return fileName;
61 | }
62 |
63 | ///
64 | ///
65 | ///
66 | ///
67 | ///
68 | ///
69 | ///
70 | ///
71 | public static void Save(object saveObject, ISerializationMethod serializationMethod, string filename, string folderName = null, string baseFolderPath = null)
72 | {
73 | var savePath = GetSavePath(folderName,baseFolderPath);
74 | var saveFilename = GetSaveFileName(filename);
75 |
76 | //Create directory if it does not exist
77 | if (!Directory.Exists(savePath))
78 | {
79 | Directory.CreateDirectory(savePath);
80 | }
81 |
82 | using (var saveFile = File.Create(savePath + saveFilename))
83 | {
84 | serializationMethod.Save(saveObject,saveFile);
85 | saveFile.Close();
86 | }
87 | }
88 |
89 | ///
90 | /// Load object from file
91 | ///
92 | ///
93 | ///
94 | ///
95 | ///
96 | ///
97 | ///
98 | ///
99 | public static object Load(System.Type objectType, ISerializationMethod serializationMethod, string filename, string folderName = null, string baseFolderPath = null, bool streamingAssets = false)
100 | {
101 | var savePath = GetSavePath(folderName, baseFolderPath, streamingAssets);
102 | var saveFilename = savePath + GetSaveFileName(filename);
103 |
104 | object returnObject = null;
105 |
106 | if (!Directory.Exists(savePath) || !File.Exists(saveFilename))
107 | {
108 | return null;
109 | }
110 |
111 | using (var saveFile = File.Open(saveFilename, FileMode.Open, FileAccess.Read, FileShare.Read))
112 | {
113 | returnObject = serializationMethod.Load(objectType, saveFile);
114 | saveFile.Close();
115 | }
116 |
117 | return returnObject;
118 | }
119 |
120 | ///
121 | /// Enumerate files in the save directory
122 | ///
123 | /// folder containing the save files
124 | /// base path to the folder
125 | /// include only files with this extension
126 | /// Will use Application.streamingAssetsPath as base path if true otherwise Application.persistentDataPath
127 | /// list of file names
128 | public static IEnumerable EnumerateSavedFiles(string folderName = null, string baseFolderPath = null, string extension = null, bool streamingAssets = false)
129 | {
130 | var savePath = GetSavePath(folderName,baseFolderPath,streamingAssets);
131 |
132 | //If directory does not exist we're done
133 | if (!Directory.Exists(savePath))
134 | {
135 | yield break;
136 | }
137 |
138 | var searchPattern = string.IsNullOrEmpty(extension) ? "*" : $"*.{extension}";
139 | foreach ( var file in Directory.EnumerateFiles(savePath,searchPattern,SearchOption.AllDirectories) )
140 | {
141 | yield return Path.GetFileName(file);
142 | }
143 | }
144 |
145 | ///
146 | /// Creates an array list of save files in the given folder and path
147 | ///
148 | ///
149 | ///
150 | /// include only files with this extension
151 | /// Will use Application.streamingAssetsPath as base path if true otherwise Application.persistentDataPath
152 | /// Array of file names
153 | public static string[] GetSavedFiles(string folderName = null, string baseFolderPath = null, string extension = null, bool streamingAssets = false)
154 | {
155 | return EnumerateSavedFiles(folderName, baseFolderPath, extension, streamingAssets).ToArray();
156 | }
157 |
158 | ///
159 | /// Populates a given array with a list of save files in the given folder and path
160 | ///
161 | /// list to be populated with file names
162 | ///
163 | ///
164 | /// include only files with this extension
165 | /// Will use Application.streamingAssetsPath as base path if true otherwise Application.persistentDataPath
166 | /// Array of file names
167 | public static void GetSavedFiles(List list, string folderName = null, string baseFolderPath = null, string extension = null, bool streamingAssets = false)
168 | {
169 | list.Clear();
170 | list.AddRange(EnumerateSavedFiles(folderName, baseFolderPath, extension, streamingAssets));
171 | }
172 |
173 | ///
174 | /// Check if a saved file exists
175 | ///
176 | ///
177 | ///
178 | ///
179 | ///
180 | public static bool Exists(string filename, string folderName = null, string baseFolderPath = null)
181 | {
182 | var savePath = GetSavePath(folderName, baseFolderPath);
183 | var saveFilename = savePath + GetSaveFileName(filename);
184 | return Directory.Exists(savePath) && File.Exists(saveFilename);
185 | }
186 |
187 | ///
188 | /// Delete a savedd file
189 | ///
190 | ///
191 | ///
192 | ///
193 | public static void DeleteSavedFile(string filename, string folderName = null, string baseFolderPath = null)
194 | {
195 | var saveFilename = GetSavePath(folderName,baseFolderPath) + GetSaveFileName(filename);
196 | if (File.Exists(saveFilename))
197 | {
198 | File.Delete(saveFilename);
199 | }
200 | }
201 |
202 | public static void DeleteDirectory(string path)
203 | {
204 | var files = Directory.GetFiles(path);
205 | var dirs = Directory.GetDirectories(path);
206 |
207 | foreach (var file in files)
208 | {
209 | File.Delete(file);
210 | }
211 |
212 | foreach (var dir in dirs)
213 | {
214 | DeleteDirectory(dir);
215 | }
216 |
217 | Directory.Delete(path,false);
218 | }
219 | }
220 | }
221 |
--------------------------------------------------------------------------------
/Runtime/SaveLoadUtility.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 3e4ec672a805d4c189f9f1e9bca2a310
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/SerializationMethodBinary.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Runtime.Serialization.Formatters.Binary;
4 |
5 | namespace Gameframe.SaveLoad
6 | {
7 | public class SerializationMethodBinary : ISerializationMethod
8 | {
9 | ///
10 | ///
11 | ///
12 | ///
13 | ///
14 | public void Save(object savedObject, FileStream fileStream)
15 | {
16 | //Creating the formatter every time because this may get used in a task and I'm not sure if it's thread safe
17 | var formatter = new BinaryFormatter();
18 | formatter.Serialize(fileStream, savedObject);
19 | }
20 |
21 | ///
22 | ///
23 | ///
24 | ///
25 | ///
26 | ///
27 | public object Load(Type savedObjectType, FileStream fileStream)
28 | {
29 | object loadedObj = null;
30 | //Creating the formatter every time because this may get used in a task and I'm not sure if it's thread safe
31 | var formatter = new BinaryFormatter();
32 | loadedObj = formatter.Deserialize(fileStream);
33 | return loadedObj;
34 | }
35 |
36 | public object Copy(object copyObject)
37 | {
38 | using (var stream = new MemoryStream())
39 | {
40 | var formatter = new BinaryFormatter();
41 | formatter.Serialize(stream, copyObject);
42 | stream.Position = 0;
43 | return formatter.Deserialize(stream);
44 | }
45 | }
46 |
47 | }
48 | }
49 |
50 |
51 |
--------------------------------------------------------------------------------
/Runtime/SerializationMethodBinary.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: ebd6753c90488724a8f045860f9786dd
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/SerializationMethodBinaryEncrypted.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Runtime.Serialization.Formatters.Binary;
4 |
5 | namespace Gameframe.SaveLoad
6 | {
7 | public class SerializationMethodBinaryEncrypted : ISerializationMethod
8 | {
9 | private string _key;
10 | private string _salt;
11 |
12 | public SerializationMethodBinaryEncrypted(string key, string salt)
13 | {
14 | SetEncryption(key,salt);
15 | }
16 |
17 | public void Save(object savedObject, FileStream fileStream)
18 | {
19 | using (var serializationStream = new MemoryStream())
20 | {
21 | //Creating the formatter every time because this may get used in a task and I'm not sure if it's thread safe
22 | var formatter = new BinaryFormatter();
23 | formatter.Serialize(serializationStream, savedObject);
24 | serializationStream.Flush();
25 | serializationStream.Position = 0;
26 | EncryptionUtility.Encrypt(serializationStream,fileStream,_key,_salt);
27 | }
28 | }
29 |
30 | public object Load(Type savedObjectType, FileStream fileStream)
31 | {
32 | object loadedObj = null;
33 |
34 | using (var memoryStream = new MemoryStream())
35 | {
36 | EncryptionUtility.Decrypt(fileStream,memoryStream,_key,_salt);
37 | memoryStream.Position = 0;
38 | //Creating the formatter every time because this may get used in a task and I'm not sure if it's thread safe
39 | var formatter = new BinaryFormatter();
40 | loadedObj = formatter.Deserialize(memoryStream);
41 | }
42 |
43 | return loadedObj;
44 | }
45 |
46 | public void SetEncryption(string key, string salt)
47 | {
48 | if (string.IsNullOrEmpty(key))
49 | {
50 | throw new ArgumentNullException(nameof(key));
51 | }
52 |
53 | if (string.IsNullOrEmpty(salt))
54 | {
55 | throw new ArgumentNullException(nameof(salt));
56 | }
57 |
58 | _key = key;
59 | _salt = salt;
60 | }
61 |
62 | public object Copy(object copyObject)
63 | {
64 | using (var stream = new MemoryStream())
65 | {
66 | var formatter = new BinaryFormatter();
67 | formatter.Serialize(stream, copyObject);
68 | stream.Position = 0;
69 | return formatter.Deserialize(stream);
70 | }
71 | }
72 | }
73 | }
74 |
75 |
76 |
--------------------------------------------------------------------------------
/Runtime/SerializationMethodBinaryEncrypted.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: a29866f639295e342978b5f9210cd24e
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/SerializationMethodJsonDotNet.cs:
--------------------------------------------------------------------------------
1 | #if JSON_DOT_NET
2 |
3 | using System;
4 | using System.IO;
5 | using Newtonsoft.Json;
6 |
7 | namespace Gameframe.SaveLoad
8 | {
9 | public class SerializationMethodJsonDotNet : ISerializationMethod
10 | {
11 | public void Save(object savedObject, FileStream fileStream)
12 | {
13 | var json = JsonConvert.SerializeObject(savedObject);
14 | using (var streamWriter = new StreamWriter(fileStream))
15 | {
16 | streamWriter.Write(json);
17 | streamWriter.Close();
18 | }
19 | }
20 |
21 | public object Load(Type savedObjectType, FileStream fileStream)
22 | {
23 | object loadedObj = null;
24 |
25 | using (var streamReader = new StreamReader(fileStream))
26 | {
27 | var json = streamReader.ReadToEnd();
28 | streamReader.Close();
29 | loadedObj = JsonConvert.DeserializeObject(json,savedObjectType);
30 | }
31 |
32 | return loadedObj;
33 | }
34 |
35 | public object Copy(object copyObject)
36 | {
37 | using (var stream = new MemoryStream())
38 | {
39 | var writeJson = JsonConvert.SerializeObject(copyObject);
40 |
41 | var streamWriter = new StreamWriter(stream);
42 | streamWriter.Write(writeJson);
43 | streamWriter.Flush();
44 |
45 | stream.Position = 0;
46 |
47 | using (var streamReader = new StreamReader(stream))
48 | {
49 | var readJson = streamReader.ReadToEnd();
50 | return JsonConvert.DeserializeObject(readJson, copyObject.GetType());
51 | }
52 | }
53 | }
54 | }
55 | }
56 |
57 | #endif
--------------------------------------------------------------------------------
/Runtime/SerializationMethodJsonDotNet.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f6d6b7773beac984a93e8a0219034c81
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/SerializationMethodJsonDotNetEncrypted.cs:
--------------------------------------------------------------------------------
1 | #if JSON_DOT_NET
2 |
3 | using System;
4 | using System.IO;
5 | using Newtonsoft.Json;
6 |
7 | namespace Gameframe.SaveLoad
8 | {
9 | public class SerializationMethodJsonDotNetEncrypted : ISerializationMethodEncrypted
10 | {
11 | private string _key = null;
12 | private string _salt = null;
13 |
14 | public SerializationMethodJsonDotNetEncrypted(string key, string salt)
15 | {
16 | SetEncryption(key,salt);
17 | }
18 |
19 | public void Save(object savedObject, FileStream fileStream)
20 | {
21 | //TODO: Using Unity's json serializer... does not support dictionaries. Do better.
22 | var json = JsonConvert.SerializeObject(savedObject);
23 | using (var memoryStream = new MemoryStream())
24 | {
25 | using (var streamWriter = new StreamWriter(memoryStream))
26 | {
27 | streamWriter.Write(json);
28 | streamWriter.Flush();
29 | memoryStream.Position = 0;
30 | EncryptionUtility.Encrypt(memoryStream,fileStream,_key,_salt);
31 | }
32 | }
33 | }
34 |
35 | public object Load(Type savedObjectType, FileStream fileStream)
36 | {
37 | object loadedObj = null;
38 |
39 | using (var memoryStream = new MemoryStream())
40 | {
41 | EncryptionUtility.Decrypt(fileStream, memoryStream, _key, _salt);
42 | memoryStream.Position = 0;
43 | using (var streamReader = new StreamReader(memoryStream))
44 | {
45 | var json = streamReader.ReadToEnd();
46 | loadedObj = JsonConvert.DeserializeObject(json, savedObjectType);
47 | streamReader.Close();
48 | }
49 | }
50 |
51 | return loadedObj;
52 | }
53 |
54 | public void SetEncryption(string key, string salt)
55 | {
56 | if (string.IsNullOrEmpty(key))
57 | {
58 | throw new ArgumentNullException(nameof(key));
59 | }
60 |
61 | if (string.IsNullOrEmpty(salt))
62 | {
63 | throw new ArgumentNullException(nameof(salt));
64 | }
65 |
66 | _key = key;
67 | _salt = salt;
68 | }
69 |
70 | public object Copy(object copyObject)
71 | {
72 | using (var stream = new MemoryStream())
73 | {
74 | var writeJson = JsonConvert.SerializeObject(copyObject);
75 |
76 | var streamWriter = new StreamWriter(stream);
77 | streamWriter.Write(writeJson);
78 | streamWriter.Flush();
79 |
80 | stream.Position = 0;
81 |
82 | using (var streamReader = new StreamReader(stream))
83 | {
84 | var readJson = streamReader.ReadToEnd();
85 | return JsonConvert.DeserializeObject(readJson, copyObject.GetType());
86 | }
87 | }
88 | }
89 |
90 | }
91 | }
92 |
93 | #endif
--------------------------------------------------------------------------------
/Runtime/SerializationMethodJsonDotNetEncrypted.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 022e3bf0dc9178945ba7b689a956de70
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/SerializationMethodType.cs:
--------------------------------------------------------------------------------
1 | namespace Gameframe.SaveLoad
2 | {
3 | public enum SerializationMethodType
4 | {
5 | Default = 0,
6 |
7 | Binary = 1,
8 | BinaryEncrypted = 101,
9 |
10 | UnityJson = 2,
11 | UnityJsonEncrypted = 102,
12 |
13 | #if JSON_DOT_NET
14 | JsonDotNet = 3,
15 | JsonDotNetEncrypted = 103,
16 | #endif
17 |
18 | Custom = 1000
19 | }
20 | }
--------------------------------------------------------------------------------
/Runtime/SerializationMethodType.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 4e6e90cfc267139438e3c50ea17db84d
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/SerializationMethodUnityJson.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using UnityEngine;
4 |
5 | namespace Gameframe.SaveLoad
6 | {
7 | public class SerializationMethodUnityJson : ISerializationMethod
8 | {
9 | public void Save(object savedObject, FileStream fileStream)
10 | {
11 | //TODO: Using Unity's json serializer... does not support dictionaries. Do better.
12 | var json = JsonUtility.ToJson(savedObject);
13 | using (var streamWriter = new StreamWriter(fileStream))
14 | {
15 | streamWriter.Write(json);
16 | streamWriter.Close();
17 | }
18 | }
19 |
20 | public object Load(Type savedObjectType, FileStream fileStream)
21 | {
22 | object loadedObj = null;
23 |
24 | using (var streamReader = new StreamReader(fileStream))
25 | {
26 | var json = streamReader.ReadToEnd();
27 | streamReader.Close();
28 | loadedObj = JsonUtility.FromJson(json, savedObjectType);
29 | }
30 |
31 | return loadedObj;
32 | }
33 |
34 | public object Copy(object copyObject)
35 | {
36 | using (var stream = new MemoryStream())
37 | {
38 | var writeJson = JsonUtility.ToJson(copyObject);
39 | var streamWriter = new StreamWriter(stream);
40 | streamWriter.Write(writeJson);
41 | streamWriter.Flush();
42 |
43 | stream.Position = 0;
44 |
45 | using (var streamReader = new StreamReader(stream))
46 | {
47 | var readJson = streamReader.ReadToEnd();
48 | streamReader.Close();
49 | return JsonUtility.FromJson(readJson, copyObject.GetType());
50 | }
51 | }
52 | }
53 |
54 | }
55 | }
56 |
57 |
58 |
--------------------------------------------------------------------------------
/Runtime/SerializationMethodUnityJson.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 4c270d5b8e4d49d4c9102562c929b599
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/SerializationMethodUnityJsonEncrypted.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using UnityEngine;
4 |
5 | namespace Gameframe.SaveLoad
6 | {
7 | public class SerializationMethodUnityJsonEncrypted : ISerializationMethodEncrypted
8 | {
9 | private string _key;
10 | private string _salt;
11 |
12 | public SerializationMethodUnityJsonEncrypted(string key, string salt)
13 | {
14 | SetEncryption(key,salt);
15 | }
16 |
17 | public void Save(object savedObject, FileStream fileStream)
18 | {
19 | //Note: Use JsonDotNet method for Dictionary serialization
20 | var json = JsonUtility.ToJson(savedObject);
21 | using (var memoryStream = new MemoryStream())
22 | {
23 | using (var streamWriter = new StreamWriter(memoryStream))
24 | {
25 | streamWriter.Write(json);
26 | streamWriter.Flush();
27 | memoryStream.Position = 0;
28 | EncryptionUtility.Encrypt(memoryStream,fileStream,_key,_salt);
29 | }
30 | }
31 | }
32 |
33 | public object Load(Type savedObjectType, FileStream fileStream)
34 | {
35 | object loadedObj = null;
36 |
37 | using (var memoryStream = new MemoryStream())
38 | {
39 | EncryptionUtility.Decrypt(fileStream, memoryStream, _key, _salt);
40 | memoryStream.Position = 0;
41 | using (var streamReader = new StreamReader(memoryStream))
42 | {
43 | var json = streamReader.ReadToEnd();
44 | loadedObj = JsonUtility.FromJson(json, savedObjectType);
45 | streamReader.Close();
46 | }
47 | }
48 |
49 | return loadedObj;
50 | }
51 |
52 | public void SetEncryption(string key, string salt)
53 | {
54 | if (string.IsNullOrEmpty(key))
55 | {
56 | throw new ArgumentNullException(nameof(key));
57 | }
58 |
59 | if (string.IsNullOrEmpty(salt))
60 | {
61 | throw new ArgumentNullException(nameof(salt));
62 | }
63 |
64 | _key = key;
65 | _salt = salt;
66 | }
67 |
68 | public object Copy(object copyObject)
69 | {
70 | using (var stream = new MemoryStream())
71 | {
72 | var writeJson = JsonUtility.ToJson(copyObject);
73 | var streamWriter = new StreamWriter(stream);
74 | streamWriter.Write(writeJson);
75 | streamWriter.Flush();
76 |
77 | stream.Position = 0;
78 |
79 | using (var streamReader = new StreamReader(stream))
80 | {
81 | var readJson = streamReader.ReadToEnd();
82 | streamReader.Close();
83 | return JsonUtility.FromJson(readJson, copyObject.GetType());
84 | }
85 | }
86 | }
87 |
88 | }
89 | }
90 |
91 |
92 |
--------------------------------------------------------------------------------
/Runtime/SerializationMethodUnityJsonEncrypted.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: c19fd85bc76de1742bac0a8cbb30bb17
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/com.gameframe.saveload.asmdef:
--------------------------------------------------------------------------------
1 | {
2 | "name": "com.gameframe.saveload",
3 | "references": [],
4 | "optionalUnityReferences": [],
5 | "includePlatforms": [],
6 | "excludePlatforms": [],
7 | "allowUnsafeCode": false,
8 | "overrideReferences": false,
9 | "precompiledReferences": [],
10 | "autoReferenced": true,
11 | "defineConstraints": [],
12 | "versionDefines": []
13 | }
--------------------------------------------------------------------------------
/Runtime/com.gameframe.saveload.asmdef.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: b894308b0ac81480cb726cb405d83944
3 | AssemblyDefinitionImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Runtime/csc.rsp:
--------------------------------------------------------------------------------
1 | -nowarn:CS0649
2 |
--------------------------------------------------------------------------------
/Runtime/csc.rsp.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f4cbf938e4839c64f9b94dec3d64d438
3 | DefaultImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Tests.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 4d8793a46ee6e4234a75d69ab4613bba
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Tests/Editor.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 82c2c60cb8dc3430787b7a0ac6533c5a
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Tests/Editor/SaveLoadUtilityTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using NUnit.Framework;
5 | using UnityEngine;
6 | using Object = UnityEngine.Object;
7 |
8 | namespace Gameframe.SaveLoad.Tests
9 | {
10 | public class SaveLoadUtilityTests
11 | {
12 | private string TestKey = "TestKey";
13 | private string TestSalt = "TestSalt";
14 |
15 | private ISerializationMethod GetSerializationMethod(SerializationMethodType method)
16 | {
17 | switch (method)
18 | {
19 | case SerializationMethodType.Default:
20 | return new SerializationMethodUnityJson();
21 | case SerializationMethodType.Binary:
22 | return new SerializationMethodBinary();
23 | case SerializationMethodType.BinaryEncrypted:
24 | return new SerializationMethodBinaryEncrypted(TestKey,TestSalt);
25 | case SerializationMethodType.UnityJson:
26 | return new SerializationMethodUnityJson();
27 | case SerializationMethodType.UnityJsonEncrypted:
28 | return new SerializationMethodUnityJsonEncrypted(TestKey,TestSalt);
29 | #if JSON_DOT_NET
30 | case SerializationMethodType.JsonDotNet:
31 | return new SerializationMethodJsonDotNet();
32 | case SerializationMethodType.JsonDotNetEncrypted:
33 | return new SerializationMethodJsonDotNetEncrypted(TestKey,TestSalt);
34 | #endif
35 | case SerializationMethodType.Custom:
36 | return new SerializationMethodBinary();
37 | default:
38 | throw new ArgumentOutOfRangeException(nameof(method), method, null);
39 | }
40 | }
41 |
42 | [Serializable]
43 | public class SaveLoadTestObject
44 | {
45 | public string testData;
46 | }
47 |
48 | [Test]
49 | public void SaveLoadAndDelete([Values]SerializationMethodType method)
50 | {
51 | var testSave = new SaveLoadTestObject() {testData = "SaveFileExists"};
52 | var serializationMethod = GetSerializationMethod(method);
53 | var filename = "TestSave.sav";
54 |
55 | SaveLoadUtility.Save(testSave,serializationMethod,filename);
56 |
57 | Assert.IsTrue(SaveLoadUtility.Exists(filename));
58 |
59 | var loadedSave = (SaveLoadTestObject)SaveLoadUtility.Load(typeof(SaveLoadTestObject), serializationMethod, filename);
60 | Assert.NotNull(loadedSave);
61 | Assert.IsTrue(loadedSave.testData == testSave.testData);
62 |
63 | SaveLoadUtility.DeleteSavedFile(filename);
64 |
65 | Assert.IsFalse(SaveLoadUtility.Exists(filename));
66 | }
67 |
68 | [Test]
69 | public void CanGetFiles_Empty()
70 | {
71 | var files = SaveLoadUtility.GetSavedFiles();
72 | Assert.IsTrue(files.Length == 0);
73 | }
74 |
75 | [Test]
76 | public void CanGetFiles()
77 | {
78 | var testSave = new SaveLoadTestObject() {testData = "SaveFileExists"};
79 | var serializationMethod = GetSerializationMethod(SerializationMethodType.Binary);
80 | var filename = "TestSave.sav";
81 | var folder = "TestFolder";
82 |
83 | SaveLoadUtility.Save(testSave,serializationMethod,filename,folder);
84 |
85 | var files = SaveLoadUtility.GetSavedFiles(folder);
86 | Assert.IsTrue(files.Length == 1,$"Total Save Files: {files.Length} Expected 1");
87 |
88 | //Files should contain a list of names that exactly match the file name used
89 | //omits the path of the file
90 | Assert.IsTrue(files[0] == filename);
91 |
92 | SaveLoadUtility.DeleteSavedFile(filename,folder);
93 |
94 | files = SaveLoadUtility.GetSavedFiles();
95 | Assert.IsTrue(files.Length == 0);
96 | }
97 |
98 | [Test]
99 | public void CanGetFilesWithExtension()
100 | {
101 | var testSave = new SaveLoadTestObject() {testData = "SaveFileExists"};
102 | var serializationMethod = GetSerializationMethod(SerializationMethodType.Binary);
103 | var filename = "TestSave.sav";
104 | var folder = "TestFolder";
105 |
106 | SaveLoadUtility.Save(testSave,serializationMethod,filename,folder);
107 |
108 | var files = SaveLoadUtility.GetSavedFiles(folder,null, "sav");
109 | Assert.IsTrue(files.Length == 1);
110 |
111 | //Files should contain a list of names that exactly match the file name used
112 | //omits the path of the file
113 | Assert.IsTrue(files[0] == filename);
114 |
115 | SaveLoadUtility.DeleteSavedFile(filename,folder);
116 |
117 | files = SaveLoadUtility.GetSavedFiles();
118 | Assert.IsTrue(files.Length == 0);
119 | }
120 |
121 | [TearDown]
122 | public void TearDown()
123 | {
124 | var path = SaveLoadUtility.GetSavePath();
125 | string[] files = {"TestSave.sav"};
126 |
127 | foreach (var file in files)
128 | {
129 | var filename = path + file;
130 | if (File.Exists(filename))
131 | {
132 | File.Delete(filename);
133 | }
134 | }
135 | }
136 |
137 | }
138 |
139 | }
140 |
--------------------------------------------------------------------------------
/Tests/Editor/SaveLoadUtilityTests.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: fb0d9e8f35733426d91318d9dbc2bbf7
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Tests/Editor/com.gameframe.saveload.editor.tests.asmdef:
--------------------------------------------------------------------------------
1 | {
2 | "name": "com.gameframe.saveload.editor.tests",
3 | "references": [
4 | "GUID:b894308b0ac81480cb726cb405d83944",
5 | "GUID:0acc523941302664db1f4e527237feb3",
6 | "GUID:27619889b8ba8c24980f49ee34dbb44a"
7 | ],
8 | "includePlatforms": [
9 | "Editor"
10 | ],
11 | "excludePlatforms": [],
12 | "allowUnsafeCode": false,
13 | "overrideReferences": true,
14 | "precompiledReferences": [
15 | "nunit.framework.dll"
16 | ],
17 | "autoReferenced": false,
18 | "defineConstraints": [],
19 | "versionDefines": [],
20 | "noEngineReferences": false
21 | }
--------------------------------------------------------------------------------
/Tests/Editor/com.gameframe.saveload.editor.tests.asmdef.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 8e17acf757b454b0c965a783efb26873
3 | AssemblyDefinitionImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Tests/Runtime.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: e94cb5d8801bd4e80958aa690d01f560
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Tests/Runtime/SaveLoadManagerTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using NUnit.Framework;
5 | using UnityEngine;
6 | using Object = UnityEngine.Object;
7 |
8 | namespace Gameframe.SaveLoad.Tests
9 | {
10 | public class SaveLoadManagerTests
11 | {
12 |
13 | [Serializable]
14 | public class SaveLoadTestObject
15 | {
16 | public List listOfStrings = new List();
17 | public int count;
18 | }
19 |
20 | [Serializable]
21 | public class SaveLoadTestUnityObject : ScriptableObject
22 | {
23 | public string textValue = "";
24 | public Vector3 pt;
25 | public Quaternion rot;
26 | }
27 |
28 | [Serializable]
29 | public class SaveLoadDictionaryTestObject
30 | {
31 | public Dictionary dict = new Dictionary();
32 | public string name = "";
33 | }
34 |
35 | private static readonly string BaseDirectory = "GameData";
36 | private static readonly string SaveDirectory = "SaveData";
37 | private static readonly string TestEncryptionKey = "SaveLoadTestEncryptionKey";
38 | private static readonly string TestEncryptionSalt = "SaveLoadTestEncryptionSalt";
39 |
40 | private static SaveLoadManager CreateManager(SerializationMethodType method = SerializationMethodType.Default)
41 | {
42 | var manager = SaveLoadManager.Create(BaseDirectory,SaveDirectory,method,TestEncryptionKey, TestEncryptionSalt);
43 | if (method == SerializationMethodType.Custom)
44 | {
45 | manager.SetCustomSerializationMethod(new SerializationMethodUnityJson());
46 | }
47 | return manager;
48 | }
49 |
50 | private static void CleanupFiles()
51 | {
52 | //Cleaning up some files that were made by tests
53 | const string filename = "Testfile";
54 | var filepath = $"{SaveLoadUtility.GetSavePath(SaveDirectory, BaseDirectory)}/{filename}";
55 | if (File.Exists(filepath))
56 | {
57 | File.Delete(filepath);
58 | }
59 | }
60 |
61 | [SetUp]
62 | public void Setup()
63 | {
64 | CleanupFiles();
65 | }
66 |
67 | [TearDown]
68 | public void Teardown()
69 | {
70 | CleanupFiles();
71 | }
72 |
73 | [Test]
74 | public void CanCreateManager([Values] SerializationMethodType method)
75 | {
76 | var manager = CreateManager(method);
77 | Assert.IsTrue(manager != null);
78 | Object.Destroy(manager);
79 | }
80 |
81 | [Test]
82 | public void CanSave([Values] SerializationMethodType method)
83 | {
84 | var manager = CreateManager(method);
85 |
86 | var testObject = new SaveLoadTestObject()
87 | {
88 | listOfStrings = new List {"one", "two"},
89 | count = 10,
90 | };
91 |
92 | const string filename = "Testfile";
93 |
94 | manager.Save(testObject,filename);
95 |
96 | var filepath = $"{SaveLoadUtility.GetSavePath(SaveDirectory, BaseDirectory)}/{filename}";
97 | Assert.IsTrue(File.Exists(filepath));
98 |
99 | manager.DeleteSave(filename);
100 | Assert.IsFalse(File.Exists(filepath));
101 |
102 | Object.Destroy(manager);
103 | }
104 |
105 | [Test]
106 | public void GetPath([Values] SerializationMethodType method)
107 | {
108 | var manager = CreateManager(method);
109 | Debug.Log(manager.GetPath("MyFile.sav"));
110 | }
111 |
112 | [Test]
113 | public void GetFiles([Values] SerializationMethodType method)
114 | {
115 | var manager = CreateManager(method);
116 |
117 | var testObject = new SaveLoadTestObject()
118 | {
119 | listOfStrings = new List {"one", "two"},
120 | count = 10,
121 | };
122 |
123 | const string filename = "Testfile";
124 |
125 | manager.Save(testObject,filename);
126 |
127 | var filepath = $"{SaveLoadUtility.GetSavePath(SaveDirectory, BaseDirectory)}/{filename}";
128 | Assert.IsTrue(File.Exists(filepath));
129 |
130 | var files = manager.GetFiles();
131 | Assert.IsTrue(files.Length == 1,$"Expected 1 file but found {files.Length}");
132 | Assert.IsTrue(files[0] == filename);
133 |
134 | manager.DeleteSave(filename);
135 | Assert.IsFalse(File.Exists(filepath));
136 |
137 | Object.Destroy(manager);
138 | }
139 |
140 |
141 |
142 | [Test]
143 | public void CanSaveAndLoad([Values] SerializationMethodType method)
144 | {
145 | var manager = CreateManager(method);
146 |
147 | var testObject = new SaveLoadTestObject()
148 | {
149 | listOfStrings = new List {"one", "two"},
150 | count = 10,
151 | };
152 |
153 | const string filename = "Testfile";
154 |
155 | manager.Save(testObject,filename);
156 |
157 | var filepath = $"{SaveLoadUtility.GetSavePath(SaveDirectory, BaseDirectory)}/{filename}";
158 | Assert.IsTrue(File.Exists(filepath));
159 |
160 | var loadedObject = manager.Load(filename);
161 |
162 | Assert.IsTrue(loadedObject.listOfStrings.Count == testObject.listOfStrings.Count);
163 |
164 | for (int i = 0; i < testObject.listOfStrings.Count; i++)
165 | {
166 | Assert.IsTrue(testObject.listOfStrings[i] == loadedObject.listOfStrings[i]);
167 | }
168 |
169 | Assert.IsTrue(testObject.count == loadedObject.count);
170 |
171 | manager.DeleteSave(filename);
172 | Assert.IsFalse(File.Exists(filepath));
173 |
174 | Object.Destroy(manager);
175 | }
176 |
177 | [Test]
178 | public void CanCopy([Values] SerializationMethodType method)
179 | {
180 | var manager = CreateManager(method);
181 |
182 | var testObject = new SaveLoadTestObject()
183 | {
184 | listOfStrings = new List {"one", "two"},
185 | count = 10,
186 | };
187 |
188 | var loadedObject = manager.Copy(testObject);
189 |
190 | Assert.NotNull(loadedObject);
191 | Assert.IsFalse(ReferenceEquals(testObject,loadedObject));
192 | Assert.NotNull(loadedObject.listOfStrings);
193 | Assert.IsTrue(loadedObject.listOfStrings.Count == testObject.listOfStrings.Count);
194 |
195 | for (int i = 0; i < testObject.listOfStrings.Count; i++)
196 | {
197 | Assert.IsTrue(testObject.listOfStrings[i] == loadedObject.listOfStrings[i]);
198 | }
199 |
200 | Assert.IsTrue(testObject.count == loadedObject.count);
201 |
202 | Object.Destroy(manager);
203 | }
204 |
205 | [Test]
206 | public void LoadReturnsNullWhenFileDoesnotExist([Values] SerializationMethodType method)
207 | {
208 | var manager = CreateManager(method);
209 | const string filename = "Testfile";
210 |
211 | var loadedObject = manager.Load(filename);
212 | Assert.IsTrue(loadedObject == null);
213 |
214 | Object.Destroy(manager);
215 | }
216 |
217 | [Test]
218 | public void CanSaveUnityObject([Values] SerializationMethodType method)
219 | {
220 | const string filename = "Testfile";
221 |
222 | var manager = CreateManager(method);
223 | var testObj = ScriptableObject.CreateInstance();
224 |
225 | testObj.textValue = "MyValue";
226 |
227 | manager.SaveUnityObject(testObj,filename);
228 |
229 | var filepath = $"{SaveLoadUtility.GetSavePath(SaveDirectory, BaseDirectory)}/{filename}";
230 | Assert.IsTrue(File.Exists(filepath));
231 |
232 | manager.DeleteSave(filename);
233 | Assert.IsFalse(File.Exists(filepath));
234 |
235 | Object.Destroy(testObj);
236 | Object.Destroy(manager);
237 | }
238 |
239 | [Test]
240 | public void CanSaveLoadUnityObject([Values] SerializationMethodType method)
241 | {
242 | const string filename = "Testfile";
243 |
244 | var manager = CreateManager(method);
245 | var testObj = ScriptableObject.CreateInstance();
246 | var loadedTestObj = ScriptableObject.CreateInstance();
247 |
248 | testObj.textValue = "MyValue";
249 |
250 | manager.SaveUnityObject(testObj,filename);
251 |
252 | var filepath = $"{SaveLoadUtility.GetSavePath(SaveDirectory, BaseDirectory)}/{filename}";
253 | Assert.IsTrue(File.Exists(filepath));
254 |
255 | manager.LoadUnityObjectOverwrite(loadedTestObj,filename);
256 | Assert.IsTrue(loadedTestObj.textValue == testObj.textValue);
257 |
258 | manager.DeleteSave(filename);
259 | Assert.IsFalse(File.Exists(filepath));
260 |
261 | Object.Destroy(testObj);
262 | Object.Destroy(loadedTestObj);
263 | Object.Destroy(manager);
264 | }
265 |
266 | [Test]
267 | public void CanCopyUnityObject([Values] SerializationMethodType method)
268 | {
269 | var manager = CreateManager(method);
270 | var testObj = ScriptableObject.CreateInstance();
271 | var loadedTestObj = ScriptableObject.CreateInstance();
272 |
273 | testObj.textValue = "MyValue";
274 |
275 | manager.CopyUnityObjectOverwrite(testObj,loadedTestObj);
276 |
277 | Assert.IsTrue(loadedTestObj.textValue == testObj.textValue);
278 |
279 | Object.Destroy(testObj);
280 | Object.Destroy(loadedTestObj);
281 | Object.Destroy(manager);
282 | }
283 |
284 | [Test]
285 | public void CopyThrowsArgumentExceptionOnUnityObject([Values] SerializationMethodType method)
286 | {
287 | var manager = CreateManager(method);
288 | var testObj = ScriptableObject.CreateInstance();
289 |
290 | Assert.Throws(() =>
291 | {
292 | manager.Copy(testObj);
293 | });
294 |
295 | Object.Destroy(testObj);
296 | Object.Destroy(manager);
297 | }
298 |
299 | [Test]
300 | public void CanSaveAndLoadDictionary([Values(
301 | SerializationMethodType.Binary,
302 | SerializationMethodType.BinaryEncrypted
303 | #if JSON_DOT_NET
304 | ,SerializationMethodType.JsonDotNet,
305 | SerializationMethodType.JsonDotNetEncrypted
306 | #endif
307 | )] SerializationMethodType method)
308 | {
309 | var manager = CreateManager(method);
310 |
311 | var testObject = new SaveLoadDictionaryTestObject()
312 | {
313 | dict = new Dictionary
314 | {
315 | {"one", 1},
316 | {"two", 2}
317 | },
318 | name = "Test",
319 | };
320 |
321 | const string filename = "Testfile";
322 |
323 | manager.Save(testObject,filename);
324 |
325 | var filepath = $"{SaveLoadUtility.GetSavePath(SaveDirectory, BaseDirectory)}/{filename}";
326 | Assert.IsTrue(File.Exists(filepath));
327 |
328 | var loadedObject = manager.Load(filename);
329 |
330 | Assert.IsTrue(loadedObject.name == testObject.name);
331 | Assert.IsTrue(loadedObject.dict.Count == testObject.dict.Count);
332 | Assert.IsTrue(loadedObject.dict.ContainsKey("one"));
333 | Assert.IsTrue(loadedObject.dict.ContainsKey("two"));
334 | Assert.IsTrue(loadedObject.dict["one"] == 1);
335 | Assert.IsTrue(loadedObject.dict["two"] == 2);
336 |
337 | manager.DeleteSave(filename);
338 | Assert.IsFalse(File.Exists(filepath));
339 |
340 | Object.Destroy(manager);
341 | }
342 |
343 | }
344 | }
345 |
--------------------------------------------------------------------------------
/Tests/Runtime/SaveLoadManagerTests.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 874e7f7b182ed7c429b077818517b220
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Tests/Runtime/com.gameframe.saveload.Tests.asmdef:
--------------------------------------------------------------------------------
1 | { "name": "com.gameframe.saveload.Tests", "references": [ "com.gameframe.saveload" ], "optionalUnityReferences": ["TestAssemblies"], "includePlatforms": [], "excludePlatforms": [] }
--------------------------------------------------------------------------------
/Tests/Runtime/com.gameframe.saveload.Tests.asmdef.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 8114fb25aa37d4aeeb48586537359895
3 | AssemblyDefinitionImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "com.gameframe.saveload",
3 | "displayName": "Gameframe.SaveLoad",
4 | "version": "1.0.10",
5 | "description": "Serialization helper utility that supports save, load and encryption.",
6 | "keywords": [],
7 | "author": {
8 | "name": "Cory Leach",
9 | "email": "cory.leach@gmail.com",
10 | "url": "https://github.com/coryleach",
11 | "github": "coryleach",
12 | "twitter": "coryleach"
13 | },
14 | "repositoryName": "UnitySaveLoad",
15 | "type": "library",
16 | "hideInEditor": false
17 | }
--------------------------------------------------------------------------------
/package.json.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 4cad32cb7b3b3412699c08facccd45ce
3 | PackageManifestImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------