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<T>"]
VFD -->|reads| DB
VFD -->|"IValue<T>"| 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]