{"id":24857399,"url":"https://github.com/pspkurara/localsave","last_synced_at":"2026-05-01T15:39:35.816Z","repository":{"id":58770270,"uuid":"533621492","full_name":"pspkurara/localsave","owner":"pspkurara","description":"Supports Unity's simple local save utility.","archived":false,"fork":false,"pushed_at":"2022-09-21T13:03:15.000Z","size":248,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-26T15:54:52.141Z","etag":null,"topics":["playerprefs","savegame","simple","unity"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pspkurara.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-09-07T05:37:32.000Z","updated_at":"2022-09-07T06:09:07.000Z","dependencies_parsed_at":"2023-01-18T17:32:16.880Z","dependency_job_id":null,"html_url":"https://github.com/pspkurara/localsave","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/pspkurara/localsave","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pspkurara%2Flocalsave","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pspkurara%2Flocalsave/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pspkurara%2Flocalsave/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pspkurara%2Flocalsave/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pspkurara","download_url":"https://codeload.github.com/pspkurara/localsave/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pspkurara%2Flocalsave/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32503203,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-30T13:12:12.517Z","status":"online","status_checked_at":"2026-05-01T02:00:05.856Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["playerprefs","savegame","simple","unity"],"created_at":"2025-01-31T17:53:23.236Z","updated_at":"2026-05-01T15:39:35.781Z","avatar_url":"https://github.com/pspkurara.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# LocalSave\r\n\r\nSupports Unity's simple local save utility.\r\n\r\n[![](https://img.shields.io/npm/v/com.pspkurara.localsave?label=openupm\u0026registry_uri=https://package.openupm.com)](https://openupm.com/packages/com.pspkurara.localsave/)\r\n[![](https://img.shields.io/github/v/release/pspkurara/localsave)](https://github.com/pspkurara/localsave/releases/)\r\n[![](https://img.shields.io/github/watchers/pspkurara/localsave?style=social)](https://github.com/pspkurara/external-selecion-state/subscription)\r\n\r\n## Usage\r\n\r\n### Simple use\r\n\r\nDeclare a static variable in the XXSavePrefs class and specify the PlayerPrefs key as an argument.\r\nbool, int, bool, float, string, enum, class, struct are supported.\r\nBe careful not to duplicate key values within the project you are using.\r\n```\r\nusing UnityEngine;\r\nusing Pspkurara.LocalSave;\r\n\r\npublic static class SampleSaves\r\n{\r\n\tpublic static readonly IntSavePrefs SampleIntegerSaveData = new IntSavePrefs(\"SAMPLE_INTEGER_SAVE_KEY\");\r\n\tpublic static readonly BoolSavePrefs SampleBooleanSaveData = new BoolSavePrefs(\"SAMPLE_BOOLEAN_SAVE_KEY\");\r\n\tpublic static readonly StringSavePrefs SampleStringSaveData = new StringSavePrefs(\"SAMPLE_STRING_SAVE_KEY\");\r\n\tpublic static readonly FloatSavePrefs SampleFloatSaveData = new FloatSavePrefs(\"SAMPLE_FLOAT_SAVE_KEY\");\r\n\tpublic static readonly EnumSavePrefs\u003cEnumSample\u003e SampleEnumSaveData = new EnumSavePrefs\u003cEnumSample\u003e(\"SAMPLE_ENUM_SAVE_KEY\");\r\n}\r\n\r\npublic enum EnumSample\r\n{\r\n\tState1,\r\n\tState2,\r\n}\r\n```\r\n\r\nClasses and structs with public and SerializeField attributes are stored internally in Json.\r\nSpecify the type you want to use in the generic.\r\nAnything that can be serialized in Unity is supported.\r\n```\r\nusing UnityEngine;\r\nusing Pspkurara.LocalSave;\r\n\r\npublic static class SampleSaves\r\n{\r\n\tpublic static readonly StructSavePrefs\u003cVector3\u003e SampleVector3SaveData = new StructSavePrefs\u003cVector3\u003e(\"SAMPLE_VECTOR3_SAVE_KEY\");\r\n\tpublic static readonly ClassSavePrefs\u003cDataClass\u003e SampleClassSaveData = new ClassSavePrefs\u003cDataClass\u003e(\"SAMPLE_CLASS_SAVE_KEY\");\r\n}\r\n\r\n[System.Serializable]\r\npublic class DataClass\r\n{\r\n\tpublic int SampleValue;\r\n\tpublic int[] SampleArray = System.Array.Empty\u003cint\u003e();\r\n\t\r\n\tpublic override string ToString()\r\n\t{\r\n\t\treturn \"Value: \" + SampleValue.ToString() + \", Length: \" + SampleArray.Length.ToString();\r\n\t}\r\n}\r\n```\r\n\r\nReads or write datas.\r\n```\r\nusing UnityEngine;\r\n\r\npublic class SampleSystemLogic : MonoBehaviour\r\n{\r\n\tprivate void Start()\r\n\t{\r\n\t\t// primitive value\r\n\t\tDebug.Log(SampleSaves.SampleIntegerSaveData.GetValue());\t// output: 0 (default value)\r\n\t\t\r\n\t\tDebug.Log(SampleSaves.SampleIntegerSaveData.GetValue(1));\t// output: 1 (If a value is specified for the argument, it will be the default value)\r\n\t\t\r\n\t\tSampleSaves.SampleIntegerSaveData.SetValue(2);\t\t\t\t// write: 2\r\n\t\tDebug.Log(SampleSaves.SampleIntegerSaveData.GetValue());\t// output: 2 (Once written, the value is returned)\r\n\t\t\r\n\t\t// -----------\r\n\t\t\r\n\t\t// class value (ToString overrided)\r\n\t\tDebug.Log(SampleSaves.SampleClassSaveData.GetValue());\t\t// output: null (default value)\r\n\t\t\r\n\t\tDebug.Log(SampleSaves.SampleClassSaveData.GetValue(new DataClass()));\t// output: Value: 0. Length: 0 (If a value is specified for the argument, it will be the default value)\r\n\t\t\r\n\t\tDebug.Log(SampleSaves.SampleClassSaveData.GetValue(()=\u003enew DataClass()));\t// output: Value: 0. Length: 0 (Generation methods can be used as arguments to avoid wasting heap space when data is available)\r\n\t\t\r\n\t\tDataClass tempData = SampleSaves.SampleClassSaveData.GetValue(new DataClass());\r\n\t\ttempData.SampleValue = 10;\r\n\t\tSampleSaves.SampleClassSaveData.SetValue(tempData);\t\t\t// write: simple value is default to 10\r\n\t\tDebug.Log(SampleSaves.SampleClassSaveData.GetValue());\t\t// output: output: Value: 10. Length: 0 (Once written, the value is returned)\r\n\t}\r\n}\r\n```\r\n\r\n### Advanced use\r\n\r\n#### Save and load from outside the library\r\n\r\nUse ExternalSavePrefs.\r\nSpecify methods and inject behaviors when declaring variables.\r\n```\r\nusing UnityEngine;\r\nusing System.Collections.Generic;\r\nusing Pspkurara.LocalSave;\r\n\r\npublic class SampleExternalSavePrefs : MonoBehaviour\r\n{\r\n\r\n\tprivate ExternalSavePrefs\u003cint\u003e ExtSave;\r\n\r\n\tprivate Dictionary\u003cstring, int\u003e m_RawSaveData = new Dictionary\u003cstring, int\u003e();\r\n\r\n\tprivate void Start()\r\n    {\r\n\t\t// declared here to set from an instance member.\r\n\t\tExtSave = new ExternalSavePrefs\u003cint\u003e(\"EXT_SAVE_KEY\", GetExtValue, SetExtValue);\r\n\r\n\t\tDebug.Log(ExtSave.GetValue());\t// output: 0 (default value)\r\n\r\n\t\tDebug.Log(ExtSave.GetValue(1)); // output: 1\r\n\r\n\t\tExtSave.SetValue(2);\t\t\t// write value.\r\n\t\tDebug.Log(ExtSave.GetValue());\t// output : 2\r\n\t}\r\n\r\n\tprivate int GetExtValue(string key, int defaultValue)\r\n\t{\r\n\t\t// find and return saved or default value.\r\n\t\tif (!m_RawSaveData.ContainsKey(key)) return defaultValue;\r\n\t\treturn m_RawSaveData[key];\r\n\t}\r\n\r\n\tprivate void SetExtValue(string key, int value)\r\n\t{\r\n\t\t// add or update value.\r\n\t\tif (m_RawSaveData.ContainsKey(key)) m_RawSaveData.Add(key, value);\r\n\t\telse m_RawSaveData[key] = value;\r\n\t}\r\n\r\n}\r\n```\r\n\r\n#### Want to make the existing storage system compatible with the new type\r\n\r\nUse SavePrefsBase.\r\nAll SavePrefs are derived from this class.\r\nBy inheriting, you can create your own completely new type-aware SavePrefs.\r\n```\r\nusing UnityEngine;\r\nusing Pspkurara.LocalSave;\r\n\r\npublic class SampleSavePrefsBase : MonoBehaviour\r\n{\r\n\r\n\tprivate static LongSavePrefs LongSave = new LongSavePrefs(\"LONG_SAVE_KEY\");\r\n\r\n\t// Start is called before the first frame update\r\n\tvoid Start()\r\n\t{\r\n\t\tDebug.Log(LongSave.GetValue());\t\t// output: 0 (default value)\r\n\r\n\t\tDebug.Log(LongSave.GetValue(1));\t// output: 1\r\n\r\n\t\tLongSave.SetValue(long.MaxValue);\t// write value.\r\n\t\tDebug.Log(LongSave.GetValue());     // output : 9223372036854775807 (long.MaxValue)\r\n\t}\r\n}\r\n\r\n// proprietary system that supports long save.\r\npublic class LongSavePrefs : SavePrefsBase\u003clong\u003e\r\n{\r\n\tpublic LongSavePrefs(string key) : base(key) { }\r\n\tpublic LongSavePrefs(string key, ILocalSaveSystem saveSystem) : base(key, saveSystem) { }\r\n\r\n\tpublic override long GetValue(long defaultValue = 0)\r\n\t{\r\n\t\t// find key and if not exist, return default.\r\n\t\tif (!SaveSystem.HasKey(Key)) return defaultValue;\r\n\t\t// long to string.\r\n\t\treturn long.Parse(SaveSystem.GetString(Key, null));\r\n\t}\r\n\r\n\tpublic override void SetValue(long value)\r\n\t{\r\n\t\t// string to long.\r\n\t\tSaveSystem.SetString(Key, value.ToString());\r\n\t}\r\n}\r\n```\r\n\r\n#### Want to handle SavePrefs consistently\r\n\r\nUse ISavePrefs.\r\nSavePrefsBase is Generic, but inherits from ISavePrefs and all SavePrefs can be batched through it.\r\n```\r\nusing UnityEngine;\r\nusing Pspkurara.LocalSave;\r\n\r\npublic class SampleISavePrefs : MonoBehaviour\r\n{\r\n\tprivate static IntSavePrefs Save1 = new IntSavePrefs(\"SAVE_1_KEY\");\r\n\tprivate static BoolSavePrefs Save2 = new BoolSavePrefs(\"SAVE_2_KEY\");\r\n\tprivate static StringSavePrefs Save3 = new StringSavePrefs(\"SAVE_3_KEY\");\r\n\r\n    private void Start()\r\n    {\r\n\t\t// to combined data.\r\n\t\tvar savePrefsArray = new ISavePrefs[] { Save1, Save2, Save3 };\r\n\r\n\t\tforeach (var save in savePrefsArray)\r\n\t\t{\r\n\t\t\tDebug.Log(save.Key); // output : SAVE_?_KEY (various save keys)\r\n\t\t}\r\n    }\r\n}\r\n```\r\n\r\n#### Want to save to a location other than PlayerPrefs\r\n\r\nUse ILocalSaveSystem and LocalSaveSettings.\r\nILocalSaveSystem allows you to decide where to save your own raw data and how it behaves.\r\nLocalSaveSettings contains the base SaveSystem for all SavePrefs, so you can replace them all at once.\r\n\r\n```\r\nusing UnityEngine;\r\nusing System.Collections.Generic;\r\nusing Pspkurara.LocalSave;\r\nusing System.IO;\r\n\r\npublic class SampleLocalSaveSystem : MonoBehaviour\r\n{\r\n\tprivate static IntSavePrefs SampleLocalSave = new IntSavePrefs(\"SAVE_SAMPLE_LOCAL_SAVE_KEY\");\r\n\tprivate static IntSavePrefs SampleLocalSave2;\r\n\r\n\tprivate void Start()\r\n    {\r\n\t\t// your own save system.\r\n\t\t// output for Assets/.sample_save.txt.\r\n\t\tvar fileLocalSaveSystem = new FileLocalSaveSystem();\r\n\r\n\t\t// replace all default save systems.\r\n\t\tLocalSaveSettings.SaveSystem = fileLocalSaveSystem;\r\n\r\n\t\t// or it is also possible to specify with an argument individually.\r\n\t\tSampleLocalSave2 = new IntSavePrefs(\"SAVE_SAMPLE_LOCAL_SAVE_2_KEY\", fileLocalSaveSystem);\r\n\r\n\t\tDebug.Log(SampleLocalSave.GetValue());\t\t// output: 0 (default value)\r\n\r\n\t\tDebug.Log(SampleLocalSave.GetValue(1));\t\t// output: 1\r\n\r\n\t\tSampleLocalSave.SetValue(2);\t\t\t\t// write value.\r\n\t\tDebug.Log(SampleLocalSave.GetValue());      // output : 2\r\n\r\n\t\tSampleLocalSave2.SetValue(3);                // write value.\r\n\t\tDebug.Log(SampleLocalSave2.GetValue());      // output : 3\r\n\t}\r\n}\r\n\r\npublic class FileLocalSaveSystem : ILocalSaveSystem\r\n{\r\n\r\n\t// raw data array.\r\n\t[System.Serializable]\r\n\tpublic class JsonArray\r\n\t{\r\n\t\tpublic List\u003cJsonData\u003e Array = new List\u003cJsonData\u003e();\r\n\t}\r\n\r\n\t// raw data element.\r\n\t[System.Serializable]\r\n\tpublic class JsonData\r\n\t{\r\n\t\tpublic string Key;\r\n\t\tpublic string Value;\r\n\t}\r\n\r\n\t// raw data json file path.\r\n\tprivate const string SaveFilePath = \"Assets/.sample_save.txt\";\r\n\r\n\tprivate bool ReadFile(string key, out string result)\r\n\t{\r\n\t\t// get save from file.\r\n\t\tresult = null;\r\n\t\ttry\r\n\t\t{\r\n\t\t\t// load file.\r\n\t\t\tif (!File.Exists(SaveFilePath)) return false;\r\n\t\t\tresult = File.ReadAllText(SaveFilePath);\r\n\t\t\t// to json convert.\r\n\t\t\tJsonArray jsonResult = JsonUtility.FromJson\u003cJsonArray\u003e(result);\r\n\t\t\t// find data from key.\r\n\t\t\tint jsonArrayIndex = jsonResult.Array.FindIndex(j =\u003e j.Key == key);\r\n\t\t\t// if not exists, failed.\r\n\t\t\tif (jsonArrayIndex == -1) return false;\r\n\t\t\t// set data for result.\r\n\t\t\tresult = jsonResult.Array[jsonArrayIndex].Value;\r\n\t\t\t// success.\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tcatch (System.Exception)\r\n\t\t{\r\n\t\t\t// failed load.\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n\r\n\t// set save to file.\r\n\tprivate void WriteFile(string key, string value)\r\n\t{\r\n\t\ttry\r\n\t\t{\r\n\t\t\t// load file.\r\n\t\t\tif (!File.Exists(SaveFilePath)) return;\r\n\t\t\tstring rawJson = File.ReadAllText(SaveFilePath);\r\n\t\t\t// to json convert.\r\n\t\t\tJsonArray jsonResult = JsonUtility.FromJson\u003cJsonArray\u003e(rawJson);\r\n\t\t\t// find data from key.\r\n\t\t\tint jsonArrayIndex = jsonResult.Array.FindIndex(j =\u003e j.Key == key);\r\n\t\t\t// key exists or not exists.\r\n\t\t\tif (jsonArrayIndex != -1)\r\n\t\t\t{\r\n\t\t\t\t// update value.\r\n\t\t\t\tjsonResult.Array[jsonArrayIndex].Value = value;\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\t// add new value.\r\n\t\t\t\tjsonResult.Array.Add(new JsonData() { Key = key, Value = value });\r\n\t\t\t}\r\n\t\t\t// write on file.\r\n\t\t\tstring updatedJson = JsonUtility.ToJson(jsonResult);\r\n\t\t\tFile.WriteAllText(SaveFilePath, updatedJson);\r\n\t\t}\r\n\t\t// failed.\r\n\t\tcatch (System.Exception) { }\r\n\t}\r\n\r\n\tpublic bool HasKey(string key)\r\n\t{\r\n\t\t// get save from file.\r\n\t\ttry\r\n\t\t{\r\n\t\t\t// load file.\r\n\t\t\tif (!File.Exists(SaveFilePath)) return false;\r\n\t\t\tstring rawJson = File.ReadAllText(SaveFilePath);\r\n\t\t\t// to json convert.\r\n\t\t\tJsonArray jsonResult = JsonUtility.FromJson\u003cJsonArray\u003e(rawJson);\r\n\t\t\t// check exists key.\r\n\t\t\treturn jsonResult.Array.Exists(j =\u003e j.Key == key);\r\n\t\t}\r\n\t\tcatch (System.Exception)\r\n\t\t{\r\n\t\t\t// failed load.\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic float GetFloat(string key, float defaultValue)\r\n\t{\r\n\t\tif (!ReadFile(key, out string result)) return defaultValue;\r\n\t\treturn float.Parse(result);\r\n\t}\r\n\r\n\tpublic int GetInt(string key, int defaultValue)\r\n\t{\r\n\t\tif (!ReadFile(key, out string result)) return defaultValue;\r\n\t\treturn int.Parse(result);\r\n\t}\r\n\r\n\tpublic string GetString(string key, string defaultValue)\r\n\t{\r\n\t\tif (!ReadFile(key, out string result)) return defaultValue;\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic void SetFloat(string key, float value)\r\n\t{\r\n\t\tWriteFile(key, value.ToString());\r\n\t}\r\n\r\n\tpublic void SetInt(string key, int value)\r\n\t{\r\n\t\tWriteFile(key, value.ToString());\r\n\t}\r\n\r\n\tpublic void SetString(string key, string value)\r\n\t{\r\n\t\tWriteFile(key, value);\r\n\t}\r\n}\r\n```\r\n\r\n### Full API references\r\n* https://pspkurara.github.io/localsave/\r\n\r\n## Installation\r\n\r\n### Using OpenUPM\r\nGo to Unity's project folder on the command line and call:\r\n\r\n```\r\nopenupm add com.pspkurara.localsave\r\n```\r\n\r\n### Using Unity Package Manager (For Unity 2018.3 or later)\r\nFind the manifest.json file in the Packages folder of your project and edit it to look like this:\r\n\r\n```\r\n{\r\n  \"dependencies\": {\r\n    \"com.pspkurara.localsave\": \"https://github.com/pspkurara/localsave.git#upm\",\r\n    ...\r\n  },\r\n}\r\n```\r\n\r\n#### Requirement\r\nUnity 2018.1 or later\u003cbr\u003e\r\nMay work in Unity5, but unofficial.\r\n\r\n## License\r\n\r\n* [MIT](https://github.com/pspkurara/localsave/blob/master/Packages/LocalSave/LICENSE.md)\r\n\r\n## Author\r\n\r\n* [pspkurara](https://github.com/pspkurara) \r\n[![](https://img.shields.io/twitter/follow/pspkurara.svg?label=Follow\u0026style=social)](https://twitter.com/intent/follow?screen_name=pspkurara) \r\n\r\n## See Also\r\n\r\n* GitHub page : https://github.com/pspkurara/localsave\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpspkurara%2Flocalsave","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpspkurara%2Flocalsave","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpspkurara%2Flocalsave/lists"}