Contents

Lix Save System v2.0 – Full Documentation

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


1. Overview

The Lix Save System v2.0 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 Beginner you may want to look at Example Usage and Tutorial

Supported Types: All C# primitive types, string, decimal, and Unity structs Vector2, Vector3, Vector4, and Quaternion.

Nulls & UnityEngine.Object: SaveSystem.Set skips null values and rejects UnityEngine.Object references to avoid recursion.

Namespaces to Import:

  • 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 usually create one instance of GameData per save 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 data. It validates types through the configured serializer, offers Set/Get<T>, HasKey, file lifecycle helpers (SaveFileExists, DeleteSaveFile, ClearAllData), and marshals through the configured File I/O and encryption handlers.


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:

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. Supported types: all primitives, string, decimal, and Unity structs Vector2/Vector3/Vector4/Quaternion. UnityEngine.Object references (MonoBehaviour, GameObject, Rigidbody, etc.) are rejected to avoid serialization loops. You can extend support for additional types by supplying custom JSON converters in your own serializer implementation (see Custom Serialization below); keep UnityEngine.Object references out of converters to avoid recursion.


4. API Reference

🔹 SaveSystem Class API

The primary static methods for managing data.

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. Accessed via gameData.gameDataConf.

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(T data) { /* Convert object to XML string */ }
    public T Deserialize(string data) { /* Convert XML string to object */ }
}

// 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 */ }
}

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

6. Example Usage

using UnityEngine;
using SillyLixStudio.SaveSystem;

public class SaveSystemExample : MonoBehaviour
{
    private GameData mySaveData;

    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
                string playerName = SaveSystem.Get(mySaveData, "PlayerName");
            }
            if (SaveSystem.HasKey(mySaveData, "HighScore"))
            {
                int highScore = SaveSystem.Get(mySaveData, "HighScore");
            }
            if (SaveSystem.HasKey(mySaveData, "PlayerPosition"))
            {
                Vector3 playerPosition = SaveSystem.Get(mySaveData, "PlayerPosition");
            }

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

Quick Notes:

  • Namespaces: Add using SillyLixStudio.SaveSystem;. For custom handlers, also add using SillyLixStudio.SaveSystem.Interfaces;.
  • Supported Types: All primitives, string, decimal, and Unity 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.

7. 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.