Skip to content

dre0dru/LocalStorage

Repository files navigation

openupm

Description

Configurable generic classes for managing local data saved on device. Unity 2020.1+

Features

  • Two generic classes with configuration options for data read/write and serialization/deserialization via file system or player prefs.
  • Simple file provider that just reads/writes data.
  • Data transformations that allow to preprocess data on read/write:
    • IDataTransform that uses AES encryption to encrypt/decrypt data.
    • IDataTransform that uses GZip or Deflate to compress/decompress data.
  • Json serialization provider that uses JsonUtility for serialization.
  • File storage saves data to Application.persistentDataPath.
  • Player prefs storage saves data to PlayerPrefs. Data location depends on device, refer to Unity documentation.
  • Easy to use and understand abstractions that allow to create custom serialization/deserialization and data transformation processes.
  • Async/sync API.
  • Optional UniTask support for async API.

Installation

This package can be installed as unity module directly from git url in two ways:

  • By adding following line in Packages/manifest.json:
"com.dre0dru.localstorage": "https://github.com/dre0dru/LocalStorage.git#upm",
  • By using Window/Package Manager/Add package from git URL... in Unity:
https://github.com/dre0dru/LocalStorage.git#upm
openupm add com.dre0dru.localstorage

Optional UniTask support

UniTask package can be installed to convert async API from using Task to UniTask. No further actions are required after installation.

UniTask support can be disabled by using DISABLE_UNITASK_SUPPORT define.

Usage

FileStorage usage

//Serialization/deserialization implementation
ISerializationProvider serializationProvider = new UnityJsonSerializationProvider();

//Path to save/load from (optional)
string path = "dataFolder";  //Resulting path will be Application.persistentDataPath/dataFolder
//File save/load implementation
IFileProvider fileProvider = new FileProvider(path);

IFileStorage storage = new FileStorage(serializationProvider, fileProvider);

string fileName = "fileName.extension";

//Resulting path will be Application.persistentDataPath/dataFolder/fileName.extension
string filePath = storage.GetFilePath(fileName);

//Serializes data then saves file
storage.Save(new Vector2(1.0f, 1.0f), fileName);

//Async saving
await storage.SaveAsync(new Vector2(1.0f, 1.0f), fileName);

//Check if file exists
bool exists = storage.FileExists(fileName);

//Loads file then deserializes data
Vector2 deserialized = storage.Load<Vector2>(fileName);

//Async loading
Vector2 deserialized = await storage.LoadAsync<Vector2>(fileName);

//Deletes file if present
storage.Delete(fileName);

PlayerPrefsStorage usage

//Serialization/deserialization implementation
ISerializationProvider serializationProvider = new UnityJsonSerializationProvider();

IPlayerPrefsStorage storage = new PlayerPrefsStorage(serializationProvider);

string dataKey = "key";

//Serializes data using ISerializationProvider then puts it into PlayerPrefs under provided key
storage.SetData(dataKey, new Vector2(1, 1));

//Async saving
await storage.SetDataAsync(dataKey, new Vector2(1, 1));

//Loads data from PlayerPrefs by key then deserializes using ISerializationProvider
Vector2 deserialized = storage.GetData<Vector2>(dataKey);

//Async loading
Vector2 deserialized = await storage.GetDataAsync<Vector2>(dataKey);

The rest of IPlayerPrefsStorage API mimics Unity PlayerPrefs API.

Warning! PlayerPrefsStorage is not thread safe.

Data transformation usage

IDataTransform implementations can be used to preprocess data during serialization/deserialization process. Available data transformations are:

  • AesEncryptionDataTransform
  • DeflateDataTransform
  • GZipDataTransform
//This is just an example, don't generate new key/IV every time
public class ExampleEncryptionSettings : IEncryptionSettings
{
    public byte[] Key { get; private set; }
    public byte[] InitializationVector { get; private set; }

    public ExampleEncryptionSettings()
    {
        //Create AES instance
        using var aes = Aes.Create();
        //Save AES key somewhere
        Key = aes.Key;
        //Save AES IV somewhere
        InitializationVector = aes.IV;
    }
}

//Encryption settings for AES
IEncryptionSettings encryptionSettings = new ExampleEncryptionSettings();

//Setup desired IDataTransform implementation
IDataTransform encryptionDataTransform = new AesEncryptionDataTransform(encryptionSettings);

//Base ISerializationProvider that will be used before/after data transform is applied
ISerializationProvider baseSP = new UnityJsonSerializationProvider();

//Setup ISerializationProvider that will use target data transformation during serialization/deserialization process
ISerializationProvider transformSerializationProvider =
    new DataTransformSerializationProvider(baseSP, encryptionDataTransform);

//Use DataTransformSerializationProvider with FileStorage
IFileProvider fp = new FileProvider();
IFileStorage fileStorage = new FileStorage(transformSerializationProvider, fp);

//Or with PlayerPrefsStorage
IPlayerPrefsStorage playerPrefsStorage = new PlayerPrefsStorage(transformSerializationProvider);

You can combine multiple IDataTransform to create chained data transformations:

IEncryptionSettings encryptionSettings = new ExampleEncryptionSettings();

//Encryption data transform
IDataTransform encryptionDataTransform = new AesEncryptionDataTransform(encryptionSettings);

//Compression data transform
IDataTransform compressionDataTransform = new GZipDataTransform();

//Create combined data transform
//First it will encrypt data, then it will compress the result
IDataTransform combinedDataTransform = new CombinedDataTransform(encryptionDataTransform, compressionDataTransform);

//Pass it to DataTransformSerializationProvider implementation
ISerializationProvider serializationProvider =
    new DataTransformSerializationProvider(new UnityJsonSerializationProvider(),
        combinedDataTransform);

//Data transformation chains can be created indefinitely
IDataTransform customDataTransform = new CustomDataTransform();

//This will result in applying CustomDataTransform data transformations first,
//then applying data transformations specified by combinedDataTransform instance
IDataTransform multipleCombinedDataTransform =
    new CombinedDataTransform(customDataTransform, combinedDataTransform);

Sync/async API

All interfaces come in 3 variants:

  • Sync API
  • Async API
  • Both sync and async

Implementations that depends on mentioned interfaces have same 3 variants, e.g. FileStorage for both sync and async API, FileStorageSync for sync API only and FileStorageAsync for async API only.

License

The software released under the terms of the MIT license.