Skip to content

Data

Store and retrieve typed data at runtime - numbers, strings, objects - using a simple key-value database that works in the Inspector.

Jungle.Data gives you two complementary storage systems. The database stores arbitrary typed values (int, float, bool, string, Color, Vector3, and more) that any part of your project can read and write. The inventory tracks quantities of identified items with automatic stacking and composable filter rules. Both are fully configurable in the Inspector and integrate with the rest of the Jungle framework.

Assembly: Jungle.Data Dependencies: Jungle.Core, Jungle.Spatial, Jungle.Graphics Namespace: Jungle.Data


Database

A database is a collection of typed key-value stores. You create named keys as ScriptableObject assets, assign values of any supported type, and read or write them from commands, value providers, or code. Each value type (int, float, bool, string, Color, Vector3, etc.) lives in its own store internally (a TypeDatabase), and the Database class routes lookups to the correct one at runtime.

DatabaseKey

A DatabaseKey is a ScriptableObject that acts as a named identifier for database entries. Create one via Create > Jungle > Data > Database Key.

Using ScriptableObject keys instead of raw strings avoids typos, enables Inspector drag-and-drop, and lets you rename keys without breaking references.

TypeDatabase

Each TypeDatabase stores entries of a single value type as (DatabaseKey, IValue<T>) pairs. The value side uses the value provider system, so entries can be constants, references to other components, or any IValue<T> implementation.

Built-in type databases:

Class Value Type
IntTypeDatabase int
FloatTypeDatabase float
BoolTypeDatabase bool
StringTypeDatabase string
ColorTypeDatabase Color
Vector3TypeDatabase Vector3
BoundsTypeDatabase Bounds
GameObjectTypeDatabase GameObject

Hosting a Database

Databases are plain [Serializable] classes. To use one in a scene or project, host it with one of these containers:

Container Type Use Case
DatabaseComponent MonoBehaviour Per-GameObject data (player stats, object state)
DatabaseAsset ScriptableObject Shared project-wide data (global config, level settings)

Create a DatabaseAsset via Create > Jungle > Data > Database Asset.

Reading and Writing Values

From C#, use the typed API on Database:

// Reading
if (database.TryGetValue<int>(healthKey, out int health))
    Debug.Log($"Health: {health}");

// Or with a default fallback
float speed = database.GetValue<float>(speedKey);

// Writing
database.SetValue(healthKey, 100);

You can also access a specific TypeDatabase directly:

var intDb = database.GetTypeDatabase<IntTypeDatabase>();
if (intDb.ContainsKey(scoreKey))
    int score = intDb.GetValue(scoreKey);

Database Commands

DatabaseCommand is a composable command that batches multiple write operations on a single database. Add it to any command-driven workflow (event responses, process triggers) and configure a list of IDatabaseAction entries in the Inspector.

Built-in Actions

Action Description
SetIntAction Writes an int value by key
SetFloatAction Writes a float value by key
SetBoolAction Writes a bool value by key
SetStringAction Writes a string value by key
IncrementIntAction Adds to an int entry; supports modulo wrapping

Each set action takes a DatabaseKey and an IValue<T> source, so the written value can come from a constant, another database entry, or any value provider.

IncrementIntAction

Adds an amount to an existing int entry. Useful for counters, cycling through indices, or decrementing resources.

Key:     scoreKey
Amount:  1          // negative to decrement
Modulo:  0          // > 0 enables wrapping: (current + amount) % modulo

With modulo: 4, values cycle through 0, 1, 2, 3, 0, 1, ... - useful for rotating through selections or animation states.

Custom Actions

Implement IDatabaseAction to create your own:

[Serializable]
[JungleClassInfo("Multiply Float", "Multiplies a float entry by a factor.", null, "Data")]
public class MultiplyFloatAction : IDatabaseAction
{
    [SerializeField] private DatabaseKey key;
    [SerializeField] private float factor = 2f;

    public void Execute(Database db)
    {
        if (!key) return;
        var current = db.GetValue<float>(key);
        db.SetValue(key, current * factor);
    }
}

Values From Database

Database entries can feed into any system that consumes value providers. The ValueFromDatabase<T> base class reads a typed value from a database by key, exposing it as an IValue<T>.

Built-in implementations:

Class Provides
IntFromDatabase IIntValue
FloatFromDatabase IFloatValue
BoolFromDatabase IBoolValue
StringFromDatabase IStringValue
ColorFromDatabase IColorValue
Vector3FromDatabase IVector3Value
BoundsFromDatabase IBoundsValue
GameObjectFromDatabase IGameObjectValue

Each one references an IDatabaseValue (where the database lives) and a DatabaseKey (which entry to read). These are also ISettableValue<T>, so pipelines can write back into the database.

Database Value Sources

The IDatabaseValue interface provides the database reference itself. Two built-in sources:

Source Description
DatabaseValueFromComponent References a DatabaseComponent on a GameObject
DatabaseValueFromAsset References a DatabaseAsset in the project

Inventory

The inventory system tracks quantities of identified items with automatic stacking and composable filter rules.

Core Types

Inventory - a serializable collection of InventoryEntry instances. Each entry pairs a ScriptableObject identifier with an integer quantity. Items with the same identifier stack automatically.

InventoryEntry - a single (ScriptableObject Identifier, int Quantity) pair.

ItemIdentifier - a ScriptableObject that gives items a name, description, and an embedded Database for extensible metadata. Create via Create > Jungle > Storage > Item Identifier.

// ItemIdentifier carries metadata through its Database
[CreateAssetMenu(menuName = "Jungle/Storage/Item Identifier")]
public class ItemIdentifier : ScriptableObject, IDatabaseProvider
{
    public string Description;
    public Database Database { get; }  // query with any DatabaseKey
}

Any system can query an ItemIdentifier's database using its own keys - the inventory reads maxQuantity, an object pool reads prefab, the UI reads icon - without coupling to each other.

Hosting an Inventory

Container Type Use Case
InventoryComponent MonoBehaviour Per-GameObject inventory (player backpack, chest)
InventoryAsset ScriptableObject Shared inventory (party resources, shop stock)

InventoryComponent calls Initialize() automatically in Awake. For InventoryAsset, call Initialize() manually before first use.

Store and Retrieve

// Store 3 of an item
if (inventory.TryStore(healthPotionId, 3))
    Debug.Log("Stored!");

// Retrieve 1
if (inventory.TryRetrieve(healthPotionId, 1))
    Debug.Log("Retrieved!");

// Query
int count = inventory.GetQuantity(healthPotionId);
bool has = inventory.Contains(healthPotionId);

Both TryStore and TryRetrieve run through their respective filter lists before modifying data. If any filter rejects the operation, it returns false and the inventory is unchanged.

Events

Subscribe to inventory changes at runtime:

inventory.OnEntryAdded   += entry => Debug.Log($"New item: {entry.Identifier.name}");
inventory.OnEntryRemoved += entry => Debug.Log($"Removed: {entry.Identifier.name}");
inventory.OnEntryChanged += entry => Debug.Log($"Changed: {entry.Identifier.name} x{entry.Quantity}");

Inventory Filters

Filters gate store and retrieve operations with AND logic. Add multiple filters to an inventory to compose rules.

Filter Description
SlotCapacityFilter Limits the total number of distinct entry slots. Set maxSlots to -1 for unlimited.
PerItemCapacityFilter Limits quantity per item type by reading a maxQuantity int from the item's Database (via IDatabaseProvider).

Custom Filters

Extend InventoryFilter:

[Serializable]
[JungleClassInfo("Weight Limit", "Rejects if total weight exceeds a cap.", null, "Inventory")]
public class WeightLimitFilter : InventoryFilter
{
    [SerializeField] private DatabaseKey weightKey;
    [SerializeField] private float maxWeight = 100f;

    public override bool CanStore(Inventory inventory, ScriptableObject identifier, int quantity)
    {
        // Calculate total weight from all entries...
        return totalWeight <= maxWeight;
    }
}

Identity System

IIdentifiable - interface for components that carry a ScriptableObject identifier. Used to bridge scene objects with inventory entries.

IdentifiableComponent - simple MonoBehaviour that assigns an identifier to a GameObject. Add to prefabs that need to be tracked by inventory or other identity-aware systems.

Inventory Value Providers

Like databases, inventories integrate with the value provider system:

Source Description
InventoryValue Inline inventory stored directly on the owner
InventoryValueFromComponent References an InventoryComponent
InventoryValueFromAsset References an InventoryAsset

Component Lookup

FromDatabaseStrategy implements IComponentLookupStrategy to find components by database key. It looks for a DatabaseComponent on the target GameObject, then retrieves a Component reference stored under the given key.

This is useful when a system needs to resolve a component reference indirectly - for example, finding a specific collider or renderer stored as metadata on an object.


Data Flow

flowchart TD
    subgraph Storage
        DK[DatabaseKey]
        TD[TypeDatabase]
        DB[Database]
        DK --> TD --> DB
    end

    subgraph Containers
        DC[DatabaseComponent]
        DA[DatabaseAsset]
        DB --> DC
        DB --> DA
    end

    subgraph Commands
        CMD[DatabaseCommand]
        ACT[IDatabaseAction]
        ACT --> CMD
        CMD -->|writes| DB
    end

    subgraph "Value Integration"
        VFD["ValueFromDatabase&lt;T&gt;"]
        VFD -->|reads| DB
        VFD -->|"IValue&lt;T&gt;"| Consumer[Any Consumer]
    end
flowchart TD
    subgraph Inventory
        II[ItemIdentifier]
        IE[InventoryEntry]
        INV[Inventory]
        IF[InventoryFilter]
        II --> IE --> INV
        IF -->|gates| INV
    end

    subgraph Containers
        IC[InventoryComponent]
        IA[InventoryAsset]
        INV --> IC
        INV --> IA
    end

    II -->|IDatabaseProvider| DB[Database]