├── .gitignore ├── Editor.meta ├── Editor ├── CodeGen.meta ├── CodeGen │ ├── CodeGenerator.cs │ ├── CodeGenerator.cs.meta │ ├── Resources.meta │ ├── Resources │ │ ├── WrapperTemplate.cs.txt │ │ └── WrapperTemplate.cs.txt.meta │ ├── ScriptData.cs │ ├── ScriptData.cs.meta │ ├── WrapperDatabase.cs │ └── WrapperDatabase.cs.meta ├── Editor.asmdef └── Editor.asmdef.meta ├── LICENSE ├── LICENSE.meta ├── README.md ├── README.md.meta ├── Runtime.meta ├── Runtime ├── Runtime.asmdef ├── Runtime.asmdef.meta ├── SaveAttribute.cs ├── SaveAttribute.cs.meta ├── SaveService.cs ├── SaveService.cs.meta ├── SaveServiceType.cs ├── SaveServiceType.cs.meta ├── Services.meta └── Services │ ├── BinaryFormatterSaveService.cs │ ├── BinaryFormatterSaveService.cs.meta │ ├── JsonSaveService.cs │ ├── JsonSaveService.cs.meta │ ├── PlayerPrefsSaveService.cs │ └── PlayerPrefsSaveService.cs.meta ├── package.json └── package.json.meta /.gitignore: -------------------------------------------------------------------------------- 1 | [Ll]ibrary/ 2 | [Tt]emp/ 3 | [Oo]bj/ 4 | [Bb]uild/ 5 | [Bb]uilds/ 6 | Assets/AssetStoreTools* 7 | 8 | # Visual Studio cache directory 9 | .vs/ 10 | 11 | # Autogenerated VS/MD/Consulo solution and project files 12 | ExportedObj/ 13 | .consulo/ 14 | *.csproj 15 | *.unityproj 16 | *.sln 17 | *.suo 18 | *.tmp 19 | *.user 20 | *.userprefs 21 | *.pidb 22 | *.booproj 23 | *.svd 24 | *.pdb 25 | *.opendb 26 | 27 | # Unity3D generated meta files 28 | *.pidb.meta 29 | *.pdb.meta 30 | 31 | # Unity3D Generated File On Crash Reports 32 | sysinfo.txt 33 | 34 | # Builds 35 | *.apk 36 | *.unitypackage 37 | -------------------------------------------------------------------------------- /Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 61c0d12ac8f5f8a40b20f3c1542cf6d8 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/CodeGen.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 87dddb54d1f922d499c6a4d5677745ad 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/CodeGen/CodeGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using UnityEditor; 8 | using UnityEditor.Callbacks; 9 | using UnityEngine; 10 | 11 | namespace Subtegral.SaveUtility.CodeGen 12 | { 13 | public static class CodeGenerator 14 | { 15 | private const string SwitchMenuName = "Subtegral/SaveUtility/Auto Generate Wrappers"; 16 | private const string AutoGenerationPrefKey = "AutoWrapperGenerationEnabled"; 17 | 18 | private static string templatePath = null; 19 | 20 | private static string TemplatePath 21 | { 22 | get 23 | { 24 | if (templatePath != null) return templatePath; 25 | 26 | var template = Resources.Load("WrapperTemplate.cs"); 27 | templatePath = AssetDatabase.GetAssetPath(template); 28 | return templatePath; 29 | } 30 | } 31 | 32 | #region Menu Items 33 | [DidReloadScripts] 34 | private static void AutoGenerate() 35 | { 36 | if (EditorPrefs.GetBool(AutoGenerationPrefKey)) 37 | Generate(); 38 | } 39 | 40 | [InitializeOnLoadMethod] 41 | private static void UpdateSwitchStatus() 42 | { 43 | if (!EditorPrefs.HasKey(AutoGenerationPrefKey)) 44 | EditorPrefs.SetBool(AutoGenerationPrefKey, false); 45 | 46 | Menu.SetChecked(SwitchMenuName, EditorPrefs.GetBool(AutoGenerationPrefKey)); 47 | } 48 | 49 | [MenuItem(SwitchMenuName)] 50 | public static void AutoGenerateSwitch() 51 | { 52 | EditorPrefs.SetBool(AutoGenerationPrefKey, !EditorPrefs.GetBool(AutoGenerationPrefKey)); 53 | Menu.SetChecked(SwitchMenuName, EditorPrefs.GetBool(AutoGenerationPrefKey)); 54 | } 55 | #endregion 56 | 57 | [MenuItem("Subtegral/SaveUtility/Generate")] 58 | public static void Generate() 59 | { 60 | if (!Directory.Exists("Assets/Resources")) 61 | AssetDatabase.CreateFolder("Assets", "Resources"); 62 | if (!Directory.Exists("Assets/Resources/SaveUtility")) 63 | AssetDatabase.CreateFolder("Assets/Resources", "SaveUtility"); 64 | 65 | var wrapperDatabase = Resources.Load("SaveUtility/WrapperDB"); 66 | if (wrapperDatabase == null) 67 | { 68 | wrapperDatabase = ScriptableObject.CreateInstance(); 69 | wrapperDatabase.wrapperNames = new List(); 70 | AssetDatabase.CreateAsset(wrapperDatabase, "Assets/Resources/SaveUtility/WrapperDB.asset"); 71 | AssetDatabase.SaveAssets(); 72 | AssetDatabase.Refresh(); 73 | } 74 | 75 | var attributeUsage = FetchAttributeUsages(); 76 | var scriptDatas = attributeUsage.ToList(); 77 | var newClasses = scriptDatas.Select(x => x.DataClassName).Except(wrapperDatabase.wrapperNames); 78 | 79 | var obsoleteClasses = 80 | wrapperDatabase.wrapperNames.Except(scriptDatas.Select(x => x.DataClassName)).ToArray(); 81 | for (var i = 0; i < obsoleteClasses.Count(); i++) 82 | { 83 | if (scriptDatas.ToList().Exists(x => x.DataClassName == obsoleteClasses[i])) 84 | { 85 | var scriptData = scriptDatas.First(x => x.DataClassName == obsoleteClasses[i]); 86 | File.Delete($"Assets/Resources/SaveUtility/{scriptData.DataClassName}Wrapper.cs"); 87 | } 88 | wrapperDatabase.wrapperNames.Remove(obsoleteClasses[i]); 89 | } 90 | 91 | foreach (var newClass in newClasses) 92 | { 93 | Debug.Log("New Save Wrapper Class " + newClass + " generated."); 94 | var scriptData = scriptDatas.First(x => x.DataClassName == newClass); 95 | File.WriteAllText($"Assets/Resources/SaveUtility/{scriptData.DataClassName}Wrapper.cs", 96 | BuildScriptContents(scriptData)); 97 | wrapperDatabase.wrapperNames.Add(newClass); 98 | } 99 | 100 | AssetDatabase.Refresh(); 101 | } 102 | 103 | private static IEnumerable FetchAttributeUsages() 104 | { 105 | var scriptDataList = new List(); 106 | #if UNITY_2019_2_OR_NEWER 107 | var typeCollection = TypeCache.GetTypesWithAttribute(typeof(SaveAttribute)); 108 | foreach (var perType in typeCollection) 109 | { 110 | scriptDataList.Add(new ScriptData() 111 | { 112 | DataClassName = perType.Name, 113 | ServiceName = perType.GetCustomAttribute().saveService.ToString(), 114 | NameSpaceName = perType.Namespace 115 | }); 116 | } 117 | #else 118 | var monoBehaviourObjects = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes()) 119 | .Where(x => x.IsClass); 120 | try 121 | { 122 | foreach (var monoBehaviourObject in monoBehaviourObjects) 123 | { 124 | var typeInfo = monoBehaviourObject.GetTypeInfo(); 125 | if (typeInfo.IsDefined(typeof(SaveAttribute), false)) 126 | { 127 | scriptDataList.Add(new ScriptData 128 | { 129 | DataClassName = typeInfo.Name, 130 | ServiceName = typeInfo.GetCustomAttribute().saveService.ToString(), 131 | NameSpaceName = typeInfo.Namespace 132 | }); 133 | } 134 | } 135 | } 136 | catch (ReflectionTypeLoadException exception) {} 137 | #endif 138 | return scriptDataList; 139 | } 140 | 141 | private static string BuildScriptContents(ScriptData scriptData) 142 | { 143 | var wrapperContents = File.ReadAllText(TemplatePath); 144 | 145 | var replace = wrapperContents.Replace("#SCRIPT_NAME#", scriptData.DataClassName + "Wrapper") 146 | .Replace("#SERVICE_NAME#", scriptData.ServiceName) 147 | .Replace("#DATA_CLASS_NAME#", scriptData.DataClassName); 148 | 149 | var stringBuilder = new StringBuilder(); 150 | if (scriptData.DoesNameSpaceExists) 151 | stringBuilder.AppendLine($"using {scriptData.NameSpaceName};"); 152 | stringBuilder.Append(replace); 153 | return stringBuilder.ToString(); 154 | } 155 | } 156 | } -------------------------------------------------------------------------------- /Editor/CodeGen/CodeGenerator.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f41afd4a6ffc42909eac6d594b1eda87 3 | timeCreated: 1571950023 -------------------------------------------------------------------------------- /Editor/CodeGen/Resources.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c84e155e05360f44dbe5e184ef74d400 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/CodeGen/Resources/WrapperTemplate.cs.txt: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | namespace Subtegral.SaveUtility 3 | { 4 | [CreateAssetMenu(menuName = "SaveUtility/#SCRIPT_NAME# Wrapper")] 5 | public class #SCRIPT_NAME# : #SERVICE_NAME#<#DATA_CLASS_NAME#>{} 6 | } -------------------------------------------------------------------------------- /Editor/CodeGen/Resources/WrapperTemplate.cs.txt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c82ed002677abab43a184b782e7126f1 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor/CodeGen/ScriptData.cs: -------------------------------------------------------------------------------- 1 | namespace Subtegral.SaveUtility.CodeGen 2 | { 3 | public struct ScriptData 4 | { 5 | public string ServiceName; 6 | public string DataClassName; 7 | public string NameSpaceName; 8 | public bool DoesNameSpaceExists => !string.IsNullOrEmpty(NameSpaceName); 9 | } 10 | } -------------------------------------------------------------------------------- /Editor/CodeGen/ScriptData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8f17eaf300eb40409d1d292293deffb2 3 | timeCreated: 1572003594 -------------------------------------------------------------------------------- /Editor/CodeGen/WrapperDatabase.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | 4 | namespace Subtegral.SaveUtility.CodeGen 5 | { 6 | public class WrapperDatabase : ScriptableObject 7 | { 8 | public List wrapperNames; 9 | } 10 | } -------------------------------------------------------------------------------- /Editor/CodeGen/WrapperDatabase.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3780cea36fc94189b1e8e9d9d8ec42ae 3 | timeCreated: 1572004899 -------------------------------------------------------------------------------- /Editor/Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Editor", 3 | "references": [ 4 | "GUID:479833c42693a2847a2f5b80a9a3ae03" 5 | ], 6 | "includePlatforms": [ 7 | "Editor" 8 | ], 9 | "excludePlatforms": [], 10 | "allowUnsafeCode": false, 11 | "overrideReferences": false, 12 | "precompiledReferences": [], 13 | "autoReferenced": true, 14 | "defineConstraints": [], 15 | "versionDefines": [] 16 | } -------------------------------------------------------------------------------- /Editor/Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 531edbdf208685149a17c0db0568a7ef 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Mert Kırımgeri 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.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 63a417ec464df09439a06b6ba07d4770 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SaveUtility 2 | Modular Save System for Unity 3 | 4 | # Example 5 | - Go to Top Menu Subtegral>SaveUtility>Generate to manually generate wrapper scripts. 6 | - Use Subtegral>SaveUtility>Auto Generate to enable auto wrapper code generation. 7 | - Create a scriptable object from generated wrappers from Create Menu>Save Utility>Your Data Class' Wrapper 8 | - Use it in your class: 9 | ```C# 10 | public class MyAwesomeSaveManager 11 | { 12 | [SerializeField] private MyPotatoCountWrapper serviceWrapper; 13 | 14 | //Load data, returns a new instance with default values of your serialized class 15 | _data = serviceWrapper.LoadData(); 16 | 17 | //Saves data 18 | serviceWrapper.SaveData(_data); 19 | 20 | } 21 | ``` 22 | 23 | # Installation 24 | You can either clone the project and put it inside the "Packages" folder of your project or add it to your *package.json* file as follows: 25 | ```json 26 | { 27 | "dependencies": { 28 | "com.m3rt32.saveutility": "https://github.com/m3rt32/SaveUtility.git" 29 | } 30 | } 31 | ``` 32 | # TO-DO: 33 | - Default components 34 | - Add encryption feature(can be turned on/off) 35 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b6a0bb64c59c95a4b85f39900fdc79c7 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6262ff88a7a0aa145bc3972d945fd757 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Runtime.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Runtime" 3 | } 4 | -------------------------------------------------------------------------------- /Runtime/Runtime.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 479833c42693a2847a2f5b80a9a3ae03 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Runtime/SaveAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Subtegral.SaveUtility.CodeGen 4 | { 5 | [AttributeUsage(AttributeTargets.Class)] 6 | public class SaveAttribute : Attribute 7 | { 8 | public SaveServiceType saveService; 9 | public SaveAttribute(SaveServiceType saveService) 10 | { 11 | this.saveService = saveService; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Runtime/SaveAttribute.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cb860456e70a2c74d825e53615cf4c90 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/SaveService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | //TO-DO: Implement Codegen for serializable types 5 | //Use "[SaveObject]" attribute to find classes that gonna receive a wrapper class codegen 6 | namespace Subtegral.SaveUtility 7 | { 8 | [Serializable] 9 | public abstract class SaveService : ScriptableObject 10 | { 11 | public abstract T LoadData(); 12 | public abstract void SaveData(T data); 13 | } 14 | } -------------------------------------------------------------------------------- /Runtime/SaveService.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4274ec7e32f64847ae51533844f402d7 3 | timeCreated: 1571421648 -------------------------------------------------------------------------------- /Runtime/SaveServiceType.cs: -------------------------------------------------------------------------------- 1 | namespace Subtegral.SaveUtility.CodeGen 2 | { 3 | public enum SaveServiceType 4 | { 5 | PlayerPrefsSaveService, 6 | BinaryFormatterSaveService, 7 | JsonSaveService 8 | } 9 | } -------------------------------------------------------------------------------- /Runtime/SaveServiceType.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 037268f9d4d0f784b98657e54493cfea 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Services.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d2568b56c4abf934f861d2f59e990000 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Services/BinaryFormatterSaveService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Runtime.Serialization.Formatters.Binary; 4 | using UnityEngine; 5 | 6 | namespace Subtegral.SaveUtility 7 | { 8 | public class BinaryFormatterSaveService : SaveService where T : new() 9 | { 10 | private string _filePath; 11 | 12 | private void OnEnable() 13 | { 14 | _filePath = Path.Combine(Application.persistentDataPath, $"{typeof(T)}.pak"); 15 | } 16 | 17 | public override T LoadData() 18 | { 19 | if (!File.Exists(_filePath)) return new T(); 20 | var binaryFormatter = new BinaryFormatter(); 21 | var file = File.Open(_filePath, FileMode.Open); 22 | var deserializedData = (T) binaryFormatter.Deserialize(file); 23 | file.Close(); 24 | return deserializedData; 25 | } 26 | 27 | public override void SaveData(T data) 28 | { 29 | var binaryFormatter = new BinaryFormatter(); 30 | var fileStream = File.Create(_filePath); 31 | binaryFormatter.Serialize(fileStream, data); 32 | fileStream.Close(); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /Runtime/Services/BinaryFormatterSaveService.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b9675aef343b4ba19bf25ea944c40a28 3 | timeCreated: 1571423207 -------------------------------------------------------------------------------- /Runtime/Services/JsonSaveService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Runtime.Serialization.Formatters.Binary; 4 | using UnityEngine; 5 | 6 | namespace Subtegral.SaveUtility 7 | { 8 | public class JsonSaveService : SaveService where T : new() 9 | { 10 | private string _filePath; 11 | 12 | private void OnEnable() 13 | { 14 | _filePath = Path.Combine(Application.persistentDataPath, $"{typeof(T)}.json"); 15 | } 16 | 17 | public override T LoadData() 18 | { 19 | if (!File.Exists(_filePath)) return new T(); 20 | var file = File.ReadAllText(_filePath); 21 | var deserializedData = JsonUtility.FromJson(file); 22 | return deserializedData; 23 | } 24 | 25 | public override void SaveData(T data) 26 | { 27 | var serializedData = JsonUtility.ToJson(data, true); 28 | File.WriteAllText(_filePath, serializedData); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /Runtime/Services/JsonSaveService.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 73ae1f2b5f2c04842b700e8f483d9e74 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Services/PlayerPrefsSaveService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace Subtegral.SaveUtility 5 | { 6 | [Serializable] 7 | public class PlayerPrefsSaveService : SaveService where T:new() 8 | { 9 | 10 | public override T LoadData() 11 | { 12 | var loadedData = PlayerPrefs.HasKey(typeof(T).Name) ? PlayerPrefs.GetString(typeof(T).Name) : string.Empty; 13 | var data = string.IsNullOrEmpty(loadedData) ? new T() : JsonUtility.FromJson(loadedData); 14 | return data; 15 | } 16 | 17 | public override void SaveData(T data) 18 | { 19 | var jsonString = JsonUtility.ToJson(data); 20 | PlayerPrefs.SetString(typeof(T).Name,jsonString); 21 | PlayerPrefs.Save(); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /Runtime/Services/PlayerPrefsSaveService.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a4853236555944ed9ff923095b57fec4 3 | timeCreated: 1571421664 -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.m3rt32.saveutility", 3 | "displayName": "Save Utility", 4 | "version": "1.5.4", 5 | "unity": "2018.1", 6 | "description": "Modular save utility that can save data using different methods but once.", 7 | "keywords": [ 8 | "unity", 9 | "editor", 10 | "csharp", 11 | "save", 12 | "data" 13 | ], 14 | "category": "Productivity" 15 | } -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0446c032640ddec46bccd3ce688ff539 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------