ItemVault Integration Guide
Overview
ItemVault is a small, engine-agnostic inventory service. The canonical architecture is:
- Core:
ItemVault.Coreinterface + implementation (IInventoryService,InventoryService,Inventory,ItemStack, events). - Optional core locator:
ItemVault.Core.InventoryServiceLocator.Current. - Optional Godot adapter:
ItemVault.Godot.Nodes.InventoryServiceNode. - Host game (e.g. Thistletide) decides how to construct and own the service; adapters are thin convenience wrappers only.
1. Core Service (Engine-Agnostic)
1.1 Interfaces and types
Core lives under ItemVault.Core:
IInventoryServiceGetOrCreateInventory(OwnerId ownerId, int capacity = 999)HasItem(OwnerId ownerId, string itemId, int quantity = 1)GetItemCount(OwnerId ownerId, string itemId)TryGiveItem(OwnerId ownerId, string itemId, int quantity)TryConsumeItem(OwnerId ownerId, string itemId, int quantity)event EventHandler<InventoryChangedEvent>? InventoryChanged
IInventory+Inventory- Simple, in-memory inventory implementation.
InventoryId,OwnerId,InventoryChangedEvent- Pure C# record/struct types; no engine dependencies.
1.2 Default implementation
InventoryService : IInventoryService- Maintains a
Dictionary<OwnerId, Inventory>. - Raises
InventoryChangedwhenever inventory state changes. - Suitable for tests and non-Godot hosts.
- Maintains a
1.3 Core service locator (optional)
InventoryServiceLocator.Current- Static property holding the game-owned
IInventoryServiceinstance. - Host game responsibility: set this during bootstrap.
- This is a convenience for small games and adapters; advanced games may use a DI container and still optionally assign this property.
- Static property holding the game-owned
2. Optional Godot Adapter Node
File: plugins/inventory/ItemVault/Godot/Nodes/InventoryServiceNode.cs
Namespace: ItemVault.Godot.Nodes
2.1 Purpose
- Optional, thin Godot adapter for games that:
- Do not use a full service architecture or DI container, and/or
- Prefer simple scene-graph + signal wiring (GDScript, basic C#).
- It:
- Resolves
IInventoryServicefromInventoryServiceLocator.Current. - Exposes methods:
GiveItem(string ownerId, string itemId, int quantity)ConsumeItem(string ownerId, string itemId, int quantity)GetItemCount(string ownerId, string itemId)
- Emits a Godot signal:
InventoryChanged(string ownerId, string inventoryId).
- Resolves
2.2 Architectural rules
- Node is a thin adapter only:
- No domain logic.
- No inventory state ownership.
- All state and behavior live in
ItemVault.Core.
- XML summary explicitly documents that:
- This node is an optional convenience.
- Production games with a service layer should prefer resolving
IInventoryServicedirectly.
2.3 Usage in non-DI Godot games
At startup, create the core service:
1 2 3 4 5 6 7 8 9using ItemVault.Core; public partial class GameBootstrap : Node { public override void _Ready() { InventoryServiceLocator.Current = new InventoryService(); } }Add
InventoryServiceNodeto your scene:- Attach the C# script
ItemVault.Godot.Nodes.InventoryServiceNode. - Optionally make it an autoload/singleton.
- Attach the C# script
Connect
InventoryChangedto your UI or gameplay scripts.Call
GiveItem,ConsumeItem,GetItemCountfrom GDScript or C#.
3. Usage in DI / Service-Architecture Games (Recommended)
For games with a composition root (like Thistletide):
Register the service in the game layer
- Use your DI container or manual composition to create a single
InventoryService(or customIInventoryServiceimplementation).
- Use your DI container or manual composition to create a single
Optionally assign the locator
- If you want to use
InventoryServiceNodeanywhere:1InventoryServiceLocator.Current = container.GetRequiredService<IInventoryService>(); - This keeps the adapter working without making it the primary pattern.
- If you want to use
Resolve IInventoryService directly in systems
- Player controllers, HUD, save systems, etc. should:
- Resolve
IInventoryServicefrom DI. - Subscribe to
InventoryChangedas needed. - Avoid relying on
InventoryServiceNodefor core behavior.
- Resolve
- Player controllers, HUD, save systems, etc. should:
Use adapter nodes only where they simplify UI wiring
- Example: a small GDScript-based debug panel that wants to call into the service without touching DI.
4. Thistletide Integration (Design Sketch)
This section captures the intended integration; actual wiring should happen after tests and build health are restored.
4.1 Where ItemVault fits
- Thistletide already owns:
- Session models (
PlayerSession,GameSession). - Game-level DI / composition logic for networking and services.
- Session models (
- ItemVault should be treated as a pure backend service:
IInventoryServiceis registered in Thistletide’s composition root.- Thistletide decides:
- How many inventories exist.
- How owners (
OwnerId) map to players/sessions.
4.2 Planned wiring steps (no code yet)
- Add ItemVault as a dependency to the Thistletide solution.
- In Thistletide’s bootstrap/composition root:
- Create or register a single
IInventoryServiceinstance. - Optionally assign
InventoryServiceLocator.Currentfrom DI soInventoryServiceNodeworks for any Godot-only integrations.
- Create or register a single
- Update player/session logic to:
- Use
OwnerIdor an adapter from Thistletide’s player identifiers. - Use
IInventoryServicefor item grants/consumption instead of a bespoke inventory implementation (where appropriate).
- Use
- Optionally add a small ItemVault-backed HUD component that resolves
IInventoryServiceand subscribes toInventoryChanged.
Until Thistletide’s build is green and dependencies are restored, this remains a design sketch rather than implemented wiring.
5. Recommended Inventory Bootstrap Pattern (OwnerId-centric)
For small demos it is acceptable for individual entities (e.g. PlayerEntity) to call:
GetOrCreateInventory(new OwnerId("some-id"))
directly in their own setup code.
For production games (like Thistletide), we recommend a central inventory bootstrap/manager instead:
Bootstrap phase (pure C# or early Godot node)
- Create a single
IInventoryServiceinstance. - Decide which
OwnerIds should exist at startup (players, NPCs, shops, chests, etc.). - Call
GetOrCreateInventory(ownerId)for each of them.
- Create a single
Entity adapters (Player/NPC/etc.)
- Each character/owner only needs to:
- Know its
OwnerId. - Call
TryGiveItem,TryConsumeItem,GetItemCountas needed.
- Know its
- They do not decide when or how inventories are created.
- Each character/owner only needs to:
Sessions vs ownership
- Session/user systems (GameUserSessions) work with
UserId. - Inventory systems (ItemVault) work with
OwnerId. - Game glue is responsible for mapping
UserId→OwnerIdwhen needed, keeping ItemVault independent of any particular user framework.
- Session/user systems (GameUserSessions) work with
This pattern keeps ItemVault focused on ownership and storage, while sessions and gameplay systems decide who the owners are.