Contents

Lix Save System - Full Documentation

Author: SillyLix
Version: 2.1.0
License: License
Unity Version: 6000.0.61f1+
Download: itch.io


2. Videos


Usage Guide Video

Video coming soon placeholder

How Lix Save System Works

Video coming soon placeholder

1. Overview

The Lix Save System is a robust and modular data persistence solution for Unity. It has been completely rewritten to support dependency injection, modular encryption, and flexible serialization.

For beginners, you may want to look at Example Usage and the Tutorial.

Look at the Change Log for a list of updates and improvements in the latest version (2.1.0).


Supported Types

  • All primitive types (e.g., int, float, bool, string, etc.)
  • Vector2, Vector3, Vector4
  • Quaternion
  • decimal
  • List<T> (Note: T must be a supported type)
  • Dictionary<TKey, TValue> (Note: TKey and TValue must be supported types)

Key Features

  • Modular Architecture: Fully extensible via dependency injection interfaces.
  • Type Safety: Validates that all saved types are supported; prevents type mismatches on load.
  • AES Encryption: Built-in encryption support with configurable keys.
  • Flexible Serialization: JSON by default; swap for custom serializers (XML, binary, etc.).
  • Custom Handlers: Replace encryption, serialization, or file I/O with your own implementations.
  • Null & Object Safety: SaveSystem.Set skips null values and rejects UnityEngine.Object references to avoid recursion.
  • File Lifecycle Helpers: Check if files exist, delete saves, clear data in memory.
  • Pretty Print Support: Generate human-readable JSON files for debugging.
  • (new) webGL Support: you can change the file I/O handler to support webGL environments. (It uses the PlayerPrefs in the backed to save data)

Namespaces

  • using SillyLixStudio.SaveSystem; – required to use GameData, SaveSystem, and related classes.
  • using SillyLixStudio.SaveSystem.Interfaces; – required if you implement custom handlers via IFileIO, IGameSerializer, or ISaveSystemEncryption.

2. Core Classes


GameData

GameData is the primary data container. It holds the dictionary of saved values and the configuration settings (GameDataConf). You will create one instance of GameData per save file.


GameDataConf

GameDataConf manages all settings for a specific GameData instance, including file paths, encryption keys, and the specific logic handlers (Encryption, Serialization, File I/O).

Defaults: file name LixSaveFile, encryption off, pretty print off, extension .lixsave, handlers AESEncryption + JsonGameSerializer + SaveFile. You can swap handlers via the interfaces below.


SaveSystem

SaveSystem is a static class that acts as the bridge between your game logic and the whole backend of the save system. It provides the main API for saving/loading data, checking keys, and managing save files. You will call its methods directly in your game code to interact with the save system.


3. System & Helper Classes

Beyond the core classes, the system uses several helper classes located in the Systems folder to handle specific tasks. While you rarely need to touch these directly, understanding them helps when extending the system.


SavedValue

A wrapper class stored inside the GameData dictionary. It holds two things:


SaveFile (Implements IFileIO)

This is the default File I/O handler. It is responsible for:


SaveWebGL (Implements IFileIO)

This is the webGL-compatible File I/O handler. It is responsible for:


JsonGameSerializer (Implements IGameSerializer)

The default serializer included with the asset. It uses JSON formatting to convert your C# objects into text. It supports "Pretty Print" (via GameDataConf) for human-readable save files, which is useful for debugging. You can extend support for additional types by supplying custom JSON converters in your own serializer implementation (see Custom Serialization below); keep UnityEngine's Object references out of converters to avoid recursion.


4. API Reference


● SaveSystem Class API

The primary static methods for managing data.

You call these methods directly on the class (e.g., SaveSystem.API_METHOD_NAME()). To save a value:

SaveSystem.Set(myGameData, "PlayerScore", 100);
Method Description
Set(GameData data, string key, object value)
Saves a value (primitives, string, decimal, Unity Vector2/3/4, Quaternion) to the data object. Null or unsupported types are skipped with a log. Updates if key exists.
Get<T>(GameData data, string key)
Retrieves a value of type T. Returns default(T) if not found or type mismatch.
HasKey(GameData data, string key)
Returns true if the key exists in memory for the provided GameData.
RemoveKey(GameData data, string key)
Permanently removes a key and its value from the data object.
ClearAllData(GameData data)
Wipes all saved keys/values from memory (does not delete the file on disk).
SaveFileExists(GameData data)
Checks if a save file exists for the configured path/name.
DeleteSaveFile(GameData data)
Deletes the save file on disk for the provided GameData configuration.
SaveToDisk(GameData data)
Serializes and writes the current data to the file system based on configuration.
LoadFromDisk(GameData data)
Reads from the file system and populates the provided GameData object.

● GameDataConf Class API

Methods to configure how data is saved. Call them on the gameData.gameDataConf instance. For example:

GameData gameData = new GameData();
gameData.gameDataConf.SetFileName("MySaveFile");
Method Description
SetFileName(string name) & GetFileName()
Set or Get the name of the save file (e.g., "SaveFile1").
SetSavePath(string path) & GetSavePath()
Set a custom folder path. Defaults to Application.persistentDataPath.
SetIsEncrypted(bool enable) & GetIsEncrypted()
Enable or disable file encryption.
SetEncryptionKey(string key) & GetEncryptionKey()
Set the secret key used for encryption.
SetEncryptionIV(string iv) & GetEncryptionIV()
Set the Initialization Vector for AES encryption.
SetSaveFileExtension(string ext)
Set custom file extension (e.g., ".sav"). Only used for encrypted files.
SetUseJsonPrettyPrint(bool enable)
Enable readable JSON formatting (increases file size).
SetEncryptionHandler(ISaveSystemEncryption handler)
Inject a custom encryption logic (e.g., XOR, AES or custom).
SetSerializer(IGameSerializer handler)
Inject a custom serializer (e.g., JSON or custom).
SetFileIOHandler(IFileIO handler)
Inject a custom file writer (e.g., System.IO or custom).

5. Customization & Interfaces

The Lix Save System is designed to be modular. You can replace core components by implementing the following interfaces and injecting them into GameDataConf.


Custom Encryption (ISaveSystemEncryption)

To create your own encryption method (e.g., a simple Caesar Cipher or RSA), implement the ISaveSystemEncryption interface.

using SillyLixStudio.SaveSystem.Interfaces;
public class MyCustomEncryption : ISaveSystemEncryption
{
    public byte[] Encrypt(byte[] data, string key) { /* Your logic */ }
    public byte[] Decrypt(byte[] data, string key) { /* Your logic */ }
}

// Usage:
gameData.gameDataConf.SetEncryptionHandler(new MyCustomEncryption());

Custom Serialization (IGameSerializer)

If you prefer BinaryFormatter, XML, or a different JSON library, implement IGameSerializer.


using SillyLixStudio.SaveSystem.Interfaces;
public class XMLSerializer : IGameSerializer
{
    public string Serialize(GameData data) { /* Convert object to XML string */ }
    public GameData Deserialize(string rawData) { /* Convert XML string to object */ }
    public bool CanSerialize(System.Type type) { /* Check if type can be serialized */ }
}

// Usage:
gameData.gameDataConf.SetSerializer(new XMLSerializer());

You can also register custom converters in your serializer to support additional types. Only add types that do not contain UnityEngine.Object references to avoid recursion and stack overflows.


Custom Storage (IFileIO)

To change where files are stored (e.g., saving to Steam Cloud, PlayerPrefs, or a database), implement IFileIO.

 using SillyLixStudio.SaveSystem.Interfaces;
public class CloudStorage : IFileIO
{
    public void Write(GameData data) { /* Upload to cloud */ }
    public GameData Read(GameData data) { /* Download from cloud */ }
    public bool Exists(GameData data) { /* Check cloud for file */ }
    public void Delete(GameData data) { /* Delete from cloud */ }
}

// Usage:
gameData.gameDataConf.SetFileIOHandler(new CloudStorage());

Using Save System with WebGL

FULL DISCOLER: The Lix Save System uses the PlayerPrefs as the backend to save data in webGL. So when you call the SaveSystem.SaveToDisk(myGameData) method, it will serialize and encrypt (if enabled) the data and then save it to the PlayerPrefs. When you call SaveSystem.LoadFromDisk(myGameData), it will read from the PlayerPrefs, decrypt (if enabled), and deserialize the data back into your GameData object.
// For this you will need to use the following namespace:
using SillyLixStudio.SaveSystem.Interfaces;

// To use the webGL-compatible File I/O handler change the handler in your GameDataConf like this:
GameData gameData = new GameData();
IFileIO webGLFileIO = new SaveWebGL(gameData.gameDataConf.GetSerializer(), gameData.gameDataConf.GetEncryptionHandler());
gameData.gameDataConf.SetFileIOHandler(webGLFileIO);

// alternatively, you can directly set it like this:
GameData gameData = new GameData();
gameData.gameDataConf.SetFileIOHandler(new SaveWebGL(gameData.gameDataConf.GetSerializer(), gameData.gameDataConf.GetEncryptionHandler()));


That is all. Now when you call SaveSystem.SaveToDisk(playerData) or SaveSystem.LoadFromDisk(playerData), it will use the SaveWebGL handler which saves data to PlayerPrefs in webGL builds.


6. Example Usage

using UnityEngine;
using SillyLixStudio.SaveSystem;

public class SaveSystemExample : MonoBehaviour
{
    private GameData mySaveData;
    private string playerName;
    private int highScore;
    private Vector3 playerPosition;

    private void Start()
    {
        // 1. Create GameData instance
        mySaveData = new GameData();
        mySaveData.gameDataConf.SetFileName("PlayerSave1");
        mySaveData.gameDataConf.SetIsEncrypted(true);
        mySaveData.gameDataConf.SetEncryptionKey("unique-key-12345");
        mySaveData.gameDataConf.SetEncryptionIV("unique-iv-67890");
    }

    void SaveData()
    {
        // 2. Save some data
        SaveSystem.Set(mySaveData, "PlayerName", "Hero");
        SaveSystem.Set(mySaveData, "HighScore", 1500);
        SaveSystem.Set(mySaveData, "PlayerPosition", new Vector3(10f, 0f, 5f));

        // 3. Write to disk
        SaveSystem.SaveToDisk(mySaveData);
    }

    void Load()
    {
        // 4. Load from disk
        if (SaveSystem.SaveFileExists(mySaveData))
        {
            SaveSystem.LoadFromDisk(mySaveData);

            // 5. Retrieve data
            // check if keys exist before getting
            if (SaveSystem.HasKey(mySaveData, "PlayerName"))
            {
                // get values
                playerName = SaveSystem.Get(mySaveData, "PlayerName");
            }
            if (SaveSystem.HasKey(mySaveData, "HighScore"))
            {
                highScore = SaveSystem.Get(mySaveData, "HighScore");
            }
            if (SaveSystem.HasKey(mySaveData, "PlayerPosition"))
            {
                playerPosition = SaveSystem.Get(mySaveData, "PlayerPosition");
            }

            Debug.Log($"Player Name: {playerName}, High Score: {highScore}, Position: {playerPosition}");
        }
        else
        {
            Debug.Log("No save file found.");
        }
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.S))
        {
            SaveData();
        }
        if (Input.GetKeyDown(KeyCode.L))
        {
            Load();
        }
    }
}

Quick Notes:

  • Namespaces: Add using SillyLixStudio.SaveSystem;. For custom handlers (example SaveWebGL), also add using SillyLixStudio.SaveSystem.Interfaces;.
  • Supported Types: All primitives, string, decimal, and Vector2/3/4, Quaternion.
  • Safety: Call LoadFromDisk first, then check keys with SaveSystem.HasKey(data, key) before Get<T>.
  • Unsupported Types: Unsupported values are skipped and logged without crashing.
  • Encryption: Use SetIsEncrypted(true) in production and provide secure key/IV.
  • File Ops: SaveFileExists, DeleteSaveFile, ClearAllData are available for lifecycle management.

Third-Party Attributions

The Lix Save System uses the following third-party libraries:

  • Newtonsoft.Json (Json.NET) - Used for JSON serialization and deserialization. Licensed under the MIT License. newtonsoft.com

Contributors

Special thanks to all contributors and supporters of the Lix Save System.

Visual designer: Zahra


9. License


Unity Asset Store License

The Lix Save System is licensed under the Unity Asset Store End User License Agreement (EULA) if downloaded from the Unity Asset Store. By downloading or using this asset, you agree to the terms of the EULA. For full license details, please refer to the official Unity Asset Store EULA: https://unity3d.com/legal/as_terms


Itch.IO License

Overview: This license governs use of the provided assets and the rights granted to the Licensee.

1. Definitions

Asset(s): The files, code, and other materials provided by the Licensor.

End Product: A game, application, or other finished product in which the Asset is incorporated and distributed to end users.

2. Grant of License

The Licensor grants the Licensee a worldwide, non-exclusive, non-transferable license to:

3. Restrictions

Licensee may not:

4. Attribution

Attribution is NOT required for this asset, but it is very much so appreciated.

5. Ownership

Ownership: The Licensor retains all copyright and moral rights in the Asset. The Licensee receives only the rights expressly granted in this license.

6. Termination

Violation of any term of this license automatically terminates the rights granted. Upon termination the Licensee must cease using the Asset and remove it from any End Product distribution.

7. Disclaimer

Assets are provided "as is" without warranty of any kind. The Licensor is not responsible for any damages arising from the use of the Asset.