# MOST Database

A lightweight, designer‑friendly save/state framework. You define named data entries (Int, Float, Bool, String) in one ScriptableObject; at runtime it seeds from your **InitialValue**s on first launch, then auto‑loads/auto‑saves JSON under `Application.persistentDataPath/MOST/`. It includes range clamping, best‑score tracking, safe file writes, and simple lookup APIs.

***

## <mark style="color:yellow;">Quick Start</mark>

1. **Create:** Right‑click → **Create → MOST → Database** → name it (e.g., `M_Database`).

<figure><img src="/files/6cAfkdSxBnwRGahFnaBW" alt=""><figcaption></figcaption></figure>

2. **Configure key (optional):** In the inspector, set **Database Key** (used for save filename). Otherwise, the asset name is used.
3. **Add Entries:** Use the list to add `IntData`, `FloatData`, `BoolData`, or `StringData`. Fill **DataName** and **InitialValue**; set Min/Max if needed.

<figure><img src="/files/gG78AOVfw2QuPMuDx1u8" alt=""><figcaption></figcaption></figure>

4. **Press Play:** First run seeds from InitialValue and writes JSON. Future runs load from JSON automatically.

<figure><img src="/files/cT6qdwOhEh9hSVBNZUaC" alt=""><figcaption></figcaption></figure>

> The <mark style="color:red;">**Initialized**</mark> flag in the inspector tells you whether a save exists and has been applied this session.

***

## <mark style="color:yellow;">Concepts & Terminology</mark>

* **Entry / Data:** A single variable (Int/Float/Bool/String) with a **DataName** and a unique generated **ID**.
* **InitialValue:** Author‑time default; used only for seeding when there is no save file yet, or as baseline before applying saved values.
* **Value:** Current runtime value (read‑only in inspector during play; modified by API).
* **HighestValue (Int/Float):** Auto‑tracked peak (useful for best scores or max currencies).
* **EnableMin/Max:** Optional clamping bounds; any Set/Add/Subtract passes through Clamp.
* **Database Key:** A file key used to build a save file path (`MOST/<key>.json`). Safe characters enforced.
* **Context Menu:** *Delete Save File (This DB)* removes the JSON for this database key (Editor‑only helper).

***

## <mark style="color:yellow;">Persistence Lifecycle (no code needed)</mark>

* **On first Play:** If no save exists, the DB **seeds Value from InitialValue** (and clamps), then saves JSON.
* **On subsequent Plays:** The DB loads JSON, overlays values onto a fresh InitialValue baseline, and marks **Initialized = true**.
* **On Quit:** Auto‑saves the latest values. Writes to a temporary `*.tmp` then **atomically replaces** the main file to avoid corruption.
* **File Location:** `{Application.persistentDataPath}/MOST/<DatabaseKey>.json`
* **Multiple Databases:** Each asset gets its own file based on its key; all loaded DBs will be saved on quit.

***

## <mark style="color:yellow;">**API & Live Example?**</mark>

1. Current Level: Start Level = 1 and Minimum ≥ 0 (No Level 0)
2. Score: Minimum> 0 (No negative score), and record the highest score
3. Currency: Init with 100 currency (Coins, Gems)

Bootstrap MonoBehaviour > inspector?

```csharp
// Hook database
public MOST_Database Database;
// Then drag the Database asset into a bootstrap MonoBehaviour.
```

<figure><img src="/files/JMYQ1QXE5ItBORz2wnk1" alt=""><figcaption></figcaption></figure>

Get all the loaded Databases

```csharp
MOST_Database.GetLoadedDatabases();
// return IEnumerable<MOST_Database> contains all loaded databases.

// example
foreach (var db in MOST_Database.GetLoadedDatabases())
{
        if (db == null) continue;
        db.TickDelayedSave(now);
}
```

Create a new data

```csharp

// Create or update an IntData entry
Database.CreateInt(
    string name,            // require
    int start = 0,          // default / Optional
    bool enableMin = false, // default / Optional
    int min = 0,            // default / Optional
    bool enableMax = false, // default / Optional
    int max = 0,            // default / Optional
    OnExistsPolicy policy = OnExistsPolicy.NoCondition // default / Optional
    // or OnExistsPolicy policy = OnExistsPolicy.IgnoreIfExists
    // or OnExistsPolicy policy = OnExistsPolicy.OverrideIfExists
)
// return true if the data was successfully created

// NoCondition policy => Create even if there is already data with the same name
// IgnoreIfExists policy => Ignore if there is data with the same name
// OverrideIfExists policy => Override if there is data with the same name

    // as instance
    IntData newIntData = new IntData
    {
        DataName     = name,
        InitialValue = initialValue,
        Value        = initialValue,
        HighestValue = initialValue,
        EnableMin    = enableMin,
        MinValue     = minValue,
        EnableMax    = enableMax,
        MaxValue     = maxValue,
        id           = NextFreeId()              // assign a free unique ID
    };
    
__________________________________________________________
    
// Create or update a FloatData entry
Database.CreateFloat(
    string name,            // require
    float start = 0f,       // default / Optional
    bool enableMin = false, // default / Optional
    float min = 0f,         // default / Optional
    bool enableMax = false, // default / Optional
    float max = 0f,         // default / Optional
    OnExistsPolicy policy = OnExistsPolicy.NoCondition // default / Optional
)
// return true if the data was successfully created

    // as instance
    FloatData newFloatData = new FloatData
    {
        DataName     = name,
        InitialValue = initialValue,
        Value        = initialValue,
        HighestValue = initialValue,
        EnableMin    = enableMin,
        MinValue     = minValue,
        EnableMax    = enableMax,
        MaxValue     = maxValue,
        id           = NextFreeId()              // assign a free unique ID
    };
    
__________________________________________________________

// Create or update a BoolData entry
Database.CreateBool(
    string name,
    bool initialValue = false,
    OnExistsPolicy policy = OnExistsPolicy.NoCondition
)
// return true if the data was successfully created

    // as instance
    BoolData NewBoolData = new BoolData
    {
        DataName     = name,
        InitialValue = initialValue,
        Value        = initialValue,
        id           = NextFreeId()
    };
    
__________________________________________________________

// Create or update a StringData entry
Database.CreateString(
    string name,
    string initialValue = "",
    OnExistsPolicy policy = OnExistsPolicy.NoCondition
)
// return true if the data was successfully created

    // as instance
    BoolData StringData = new StringData
    {
        DataName     = name,
        InitialValue = initialValue,
        Value        = initialValue,
        id           = NextFreeId()
    };
    
```

Get the Data (entries) from the database

```csharp
//
// Get a specific data
public MOST_Database Database;
// Then drag the Database asset into a bootstrap MonoBehaviour.

// Get data by ID
var data = Database.GetById(int id);


// Get data by Name
var data = Database.GetByName(int id);


// Get by Typed lookups (The best way for type-specific) (return null if not found)
// for int data
IntData data = Database.Get<IntData>(int id); // by id
IntData data = Database.Get<IntData>(string name); // by data name

// for float data
FloatData data = Database.Get<FloatData>(int id); // by id
FloatData data = Database.Get<FloatData>(string name); // by data name

// for bool data
BoolData data = Database.Get<BoolData>(int id); // by id
BoolData data = Database.Get<BoolData>(string name); // by data name

// for float data
StringData data = Database.Get<StringData>(int id); // by id
StringData data = Database.Get<StringData>(string name); // by data name

// _________________________________________________//

// Check for data, Try-get pattern
bool isFound = Database.TryGet(int id, out MData result); // for any type of data
bool isFound = Database.TryGet(int id, out IntData result); // for int data
bool isFound = Database.TryGet(int id, out FloatData result); // for float data
bool isFound = Database.TryGet(int id, out BoolData result); // for bool data
bool isFound = Database.TryGet(int id, out StringData result); // for string data

// Check if the database is initialized
bool isInit = Database.Initialized;
```

## <mark style="color:yellow;">**Important (Save/Load)**</mark>

```csharp
//
Database.Save(); // writes current Values to disk (safe temp+replace)
```

{% hint style="success" %}
**Use&#x20;**<mark style="color:red;">**Save()**</mark>**&#x20;after critical state changes (IAP unlocks, progression checkpoints) to guarantee persistence even if the app is killed.**
{% endhint %}

## <mark style="color:yellow;">Opreations</mark>

```csharp
//
// Get a specific data
public MOST_Database Database;
// Then drag the Database asset into a bootstrap MonoBehaviour.

// For Int Data
IntData data = Database.Get<IntData>(string name); // by data name "Currency" for ex

data.Get(); or data.Value // returns data Value
data.HighestValue; // returns data's Highest Value
data.MinValue; // return or set the minimum value that this data can be
data.MaxValue; // return or set the maximum value that this data can be
data.EnableMin; // return, enable or disable Minimum control 
data.EnableMax; // return, enable or disable Maximum control 

data.Set(int v); or data.Value  // sets Value (clamped), updates HighestValue
data.Add(int delta); // Add (negative becomes Subtract)
data.Subtract(int delta); // Subtract (negative becomes Add)
data.TrySubtract(int amount); // return boolean > safe spend check against min/0
data.SetIfGreater(int candidate); // return boolean > best-score style update
data.ClampMinZero(); // floor at 0

// For Float Data
FloatData data = Database.Get<FloatData>(string name); // by data name "Currency" for ex

data.Get(); or data.Value // returns data Value
data.HighestValue; // returns data's Highest Value
data.MinValue; // return or set the minimum value that this data can be
data.MaxValue; // return or set the maximum value that this data can be
data.EnableMin; // return, enable or disable Minimum control 
data.EnableMax; // return, enable or disable Maximum control 

data.Set(float v); or data.Value // sets Value (clamped), updates HighestValue
data.Add(float delta); // Add (negative becomes Subtract)
data.Subtract(float delta); // Subtract (negative becomes Add)
data.TrySubtract(float amount); // return boolean > safe spend check against min/0
data.SetIfGreater(float candidate); // return boolean > best-score style update
data.ClampMinZero(); // floor at 0


// For Bool Data
BoolData data = Database.Get<BoolData>(string name); // by data name

data.Value; // return or set the data value
data.ToggleValue(); // Toggle current bool value
data.SetBool(bool value); // Set the data value

// For string value
StringData data = Database.Get<StringData>(string name); // by data name

data.Value; // return or set the data value

```

## <mark style="color:red;">FAQ</mark>

<mark style="color:yellow;">**Q: Do I need to manually load on start?**</mark>\
A: No. The database auto‑initializes on play, loads if a file exists, otherwise seeds and saves.

<mark style="color:yellow;">**Q: Can I have multiple databases?**</mark>\
A: Yes—each gets its own JSON by key/asset name. All loaded DBs are saved on quit.

<mark style="color:yellow;">**Q: What if I rename DataName after shipping?**</mark>\
A: Saves are keyed by **id**, not by name. Renaming the display name is safe; removing or re‑ordering entries may affect semantics. Prefer adding new entries instead of recycling IDs.

<mark style="color:yellow;">**Q: Is the file safe from corruption?**</mark>\
A: Writes use a temporary file then **File.Replace** where available; this minimizes corruption risk.

<mark style="color:yellow;">**Q: When is**</mark><mark style="color:yellow;">**&#x20;**</mark><mark style="color:yellow;">**`Initialized`**</mark><mark style="color:yellow;">**&#x20;**</mark><mark style="color:yellow;">**true?**</mark>\
A: After the DB loads from disk or writes a first save during the current play session.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://solo-player.gitbook.io/most-in-one/most-systems/most-database.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
