{"id":28564785,"url":"https://github.com/andantetribe/localprefs","last_synced_at":"2026-05-06T08:32:49.282Z","repository":{"id":297064140,"uuid":"995535184","full_name":"AndanteTribe/LocalPrefs","owner":"AndanteTribe","description":"A local persistence library as an alternative to UnityEngine.PlayerPrefs, for .NET and Unity.","archived":false,"fork":false,"pushed_at":"2025-06-19T15:05:52.000Z","size":230,"stargazers_count":0,"open_issues_count":3,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-19T16:23:50.299Z","etag":null,"topics":["dotnet","playerprefs","unity"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AndanteTribe.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-03T16:17:01.000Z","updated_at":"2025-06-19T15:05:54.000Z","dependencies_parsed_at":"2025-06-19T16:21:09.113Z","dependency_job_id":"f527f4e6-1d5e-47ff-9cdf-95c12239027f","html_url":"https://github.com/AndanteTribe/LocalPrefs","commit_stats":null,"previous_names":["andantetribe/localprefs"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/AndanteTribe/LocalPrefs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndanteTribe%2FLocalPrefs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndanteTribe%2FLocalPrefs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndanteTribe%2FLocalPrefs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndanteTribe%2FLocalPrefs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AndanteTribe","download_url":"https://codeload.github.com/AndanteTribe/LocalPrefs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndanteTribe%2FLocalPrefs/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261374407,"owners_count":23148975,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["dotnet","playerprefs","unity"],"created_at":"2025-06-10T14:00:27.756Z","updated_at":"2026-05-06T08:32:49.277Z","avatar_url":"https://github.com/AndanteTribe.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# LocalPrefs\n[![dotnet-test](https://github.com/AndanteTribe/LocalPrefs/actions/workflows/dotnet-test.yml/badge.svg)](https://github.com/AndanteTribe/LocalPrefs/actions/workflows/dotnet-test.yml)\n[![unity-test](https://github.com/AndanteTribe/LocalPrefs/actions/workflows/unity-test.yml/badge.svg)](https://github.com/AndanteTribe/LocalPrefs/actions/workflows/unity-test.yml)\n[![nuget-core](https://img.shields.io/nuget/v/LocalPrefs.Core.svg)](https://www.nuget.org/packages/LocalPrefs.Core/)\n[![nuget-json](https://img.shields.io/nuget/v/LocalPrefs.Json.svg)](https://www.nuget.org/packages/LocalPrefs.Json/)\n[![nuget-msgpack](https://img.shields.io/nuget/v/LocalPrefs.MessagePack.svg)](https://www.nuget.org/packages/LocalPrefs.MessagePack/)\n[![Releases](https://img.shields.io/github/release/AndanteTribe/LocalPrefs.svg)](https://github.com/AndanteTribe/LocalPrefs/releases)\n[![GitHub license](https://img.shields.io/github/license/AndanteTribe/LocalPrefs.svg)](./LICENSE)\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/AndanteTribe/LocalPrefs)\n\nEnglish | [日本語](README_JA.md)\n\n## Overview\n**LocalPrefs** is a library that provides local save/load functionality for .NET and Unity.\n\nUnity’s built-in `UnityEngine.PlayerPrefs` API is known for several critical issues, including:\n\n1. On Windows, data is saved to the system registry.\n2. On Web platforms, data is stored in IndexedDB, but the key includes an inexplicable hash that may change with each build under certain conditions. This behavior can interfere with game updates or pollute IndexedDB with entries using different hashed keys.\n3. On Web platforms, the storage limit is capped at 1MB.\n4. On Web platforms, saving is not immediate and is instead asynchronous, making it difficult to determine when data is actually persisted.\n5. The supported data types are limited (only `int`, `float`, and `string`).\n\n**LocalPrefs** addresses these problems and offers a high-performance implementation.\n\n1. The save path of `LocalPrefs.Shared` (`LocalPrefs.Unity`) defaults to `Application.persistentDataPath`. On WebGL, the optimal save destination is automatically configured.\n2. It provides APIs that allow customization, such as defining save paths and encryption. It also offers an abstraction layer through the `ILocalPrefs` interface to enable unified save/load management.\n3. It supports high-performance serialization using either `System.Text.Json` or [MessagePack-CSharp](https://github.com/MessagePack-CSharp/MessagePack-CSharp).\n4. By integrating with native JavaScript, it supports APIs for saving/loading using Local Storage and IndexedDB, along with unified implementations based on these.\n\n## Installation\n### NuGet Packages\nLocalPrefs requires .NET Standard 2.1 or higher. The package can be obtained from NuGet.\n\n### .NET CLI\n#### LocalPrefs.Json (uses System.Text.Json)\n```ps1\ndotnet add package LocalPrefs.Json\n```\n\n#### LocalPrefs.MessagePack (uses MessagePack-CSharp)\n```ps1\ndotnet add package LocalPrefs.MessagePack\n```\n\n### Package Manager\n#### LocalPrefs.Json (uses System.Text.Json)\n```ps1\nInstall-Package LocalPrefs.Json\n```\n\n#### LocalPrefs.MessagePack (uses MessagePack-CSharp)\n```ps1\nInstall-Package LocalPrefs.MessagePack\n```\n\n### Unity\nSee the [Unity](#unity-1) section below for details.\n\n## Quick Start\nThe simplest implementation uses `LocalPrefs.Shared`.\nThe types that can be saved/loaded depend on the serializer used. As long as the serializer’s requirements are met, any type can be handled.\n\n```csharp\nusing AndanteTribe.IO.Unity;\n\nvar hoge = new Hoge();\n\n// Save\nawait LocalPrefs.Shared.SaveAsync(\"hogeKey\", hoge);\n\n// HasKey\nbool hasHoge = LocalPrefs.Shared.HasKey(\"hogeKey\");\n\n// Load\nvar hoge2 = LocalPrefs.Shared.Load\u003cHoge\u003e(\"hogeKey\");\n\n// Delete\nawait LocalPrefs.Shared.DeleteAsync(\"hogeKey\");\n\n// DeleteAll\nawait LocalPrefs.Shared.DeleteAllAsync();\n```\n\nIf you want to define a custom save path, you’ll need to instantiate the prefs yourself.\nIn that case, using the `ILocalPrefs` interface as an abstraction layer is recommended.\n\n```csharp\nusing AndanteTribe.IO;\nusing AndanteTribe.IO.Json;\n\nstring path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), \"DefaultCompany\", \"test\", \"localprefs-test\");\n\n// System.Text.Json\nILocalPrefs jsonPrefs = new JsonLocalPrefs(path);\n```\n\n```csharp\nusing AndanteTribe.IO;\nusing AndanteTribe.IO.MessagePack;\n\nstring path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), \"DefaultCompany\", \"test\", \"localprefs-test\");\n\n// MessagePack-CSharp\nILocalPrefs msgpackPrefs = new MessagePackLocalPrefs(path);\n```\n\n## FileAccessor\nThis is an abstraction layer for file I/O used in LocalPrefs.\nYou can subclass `FileAccessor` to implement custom file-handling logic.\n\nThe factory method `FileAccessor.Create(in string path)` provides a default implementation using `System.IO`.\n\n## Encryption\n`CryptoFileAccessor` is a general-purpose implementation that enables encrypted saving and decrypted loading.\nIt can be passed to a `JsonLocalPrefs` instance as shown below:\n\n```csharp\nusing AndanteTribe.IO;\nusing AndanteTribe.IO.Json;\n\nstring path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), \"DefaultCompany\", \"test\", \"localprefs-test\");\n\nbyte[] key = {\n    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,\n    0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,\n    0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,\n    0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20\n};\n\npublic static readonly byte[] iv = {\n    0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,\n    0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30\n};\n\n// Set CryptoFileAccessor\nILocalPrefs prefs = new JsonLocalPrefs(new CryptoFileAccessor(path, key, iv));\n\n// Save\nawait prefs.SaveAsync(\"intkey\", 123);\n\n// Load\nint value = prefs.Load\u003cint\u003e(\"intkey\");\n```\n\n## System.Text.Json\nBy using `LocalPrefs.Json`, you can perform local save/load operations based on `System.Text.Json`.\nThe `JsonLocalPrefs` class implements `ILocalPrefs` and provides the following constructors:\n\n```csharp\npublic JsonLocalPrefs(in string savePath, JsonSerializerOptions? options = null);\n\npublic JsonLocalPrefs(FileAccessor fileAccessor, JsonSerializerOptions? options = null);\n```\n\n## MessagePack-CSharp\nBy using `LocalPrefs.MessagePack`, you can perform local save/load operations based on [MessagePack-CSharp](https://github.com/MessagePack-CSharp/MessagePack-CSharp).\nThe `MessagePackLocalPrefs` class implements `ILocalPrefs` and provides the following constructors:\n\n```csharp\npublic MessagePackLocalPrefs(in string savePath, IFormatterResolver? resolver);\n\npublic MessagePackLocalPrefs(FileAccessor fileAccessor, IFormatterResolver? resolver);\n\npublic MessagePackLocalPrefs(in string savePath, MessagePackSerializerOptions? options = null);\n\npublic MessagePackLocalPrefs(FileAccessor fileAccessor, MessagePackSerializerOptions? options = null);\n```\n\n## Unity\nLocalPrefs is available for use in Unity.\nA Unity-specific extension package, `LocalPrefs.Unity`, is also provided.\n\n### Requirements\n- Unity 2022.3 or later\n\n### Installation\n1. Install [NuGetForUnity](https://github.com/GlitchEnzo/NuGetForUnity).\n2. Open `NuGet \u003e Manage NuGet Packages` and search for and install the `LocalPrefs.Json` or `LocalPrefs.MessagePack` package.\n3. If you use `LocalPrefs.MessagePack` (depends on `MessagePack-CSharp`), also install the `MessagePack.Unity` package.\n   \u003e Install `MessagePack.Unity` package by referencing the git URL. Open Package Manager window and press `Add Package from git URL...`, enter following path\n   \u003e\n   \u003e https://github.com/MessagePack-CSharp/MessagePack-CSharp.git?path=src/MessagePack.UnityClient/Assets/Scripts/MessagePack\n   \u003e [MessagePack-CSharp README.md](https://github.com/MessagePack-CSharp/MessagePack-CSharp?tab=readme-ov-file#unity-support)\n4. Open `Window \u003e Package Manager`, select `[+] \u003e Add package from git URL`, and enter the following URL:\n    ```\n   https://github.com/AndanteTribe/LocalPrefs.git?path=src/LocalPrefs.Unity/Packages/jp.andantetribe.localprefs\n    ```\n\n### Auto Configuration of Save Path for LocalPrefs.Shared\nWhen `LocalPrefs.Unity` is included, `LocalPrefs.Shared` will automatically configure the save path at startup.\nBy default, `Application.persistentDataPath` is used for non-web platforms, and Local Storage for web platforms.\n\n### Web Support\n`LocalPrefs.Unity` supports browser-based local saving/loading via native JavaScript integration.\n\nBoth **IndexedDB** and **Local Storage** are supported as storage backends.\nIf the data is small, Local Storage performs faster than IndexedDB. However, for large data like screenshots, IndexedDB is more suitable.\n\n* Use `IDBUtils` for IndexedDB\n* Use `LSUtils` for Local Storage\n\nFor advanced usage, `IDBStream` and `LSStream` are also available, implementing the .NET stream decorator paradigm.\n\n#### IDBUtils\n```csharp\npublic static async ValueTask WriteAllBytesAsync(string path, byte[] bytes, CancellationToken cancellationToken = default);\n\npublic static async ValueTask WriteAllBytesAsync(string path, ReadOnlyMemory\u003cbyte\u003e bytes, CancellationToken cancellationToken = default);\n\npublic static async ValueTask DeleteAsync(string path, CancellationToken cancellationToken = default);\n\npublic static async ValueTask\u003cbyte[]\u003e ReadAllBytesAsync(string path, CancellationToken cancellationToken = default);\n```\n\n#### LSUtils\n```csharp\npublic static void WriteAllBytes(in string path, in ReadOnlySpan\u003cbyte\u003e bytes);\n\npublic static void WriteAllText(in string path, in string contents);\n\npublic static void Delete(in string path);\n\npublic static byte[] ReadAllBytes(in string path);\n\npublic static string ReadAllText(in string path);\n```\n\n## License\nThis library is released under the MIT license.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandantetribe%2Flocalprefs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandantetribe%2Flocalprefs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandantetribe%2Flocalprefs/lists"}