📐 Abstractions¶
Interfaces, identifiers, and core result types that every other Inventory subsystem builds on. These are stable runtime contracts — safe to reference from any runtime or editor assembly.
These types contain no gameplay logic or mutable state. They define contracts, identifiers, and result semantics only.
Core Interfaces¶
-
IInventoryService
Scene-scoped inventory API for mutations (write operations).
Exposes result-first methods (GiveExact,RemoveByGuid,SplitResult,ResizeContainer, etc.).
All mutating operations are authority-gated, returningInvOpCode.NoAuthorityif denied.
Inherits fromIReadOnlyInventoryService, so readers and writers share the same access surface. -
IReadOnlyInventoryService
Read-only view of inventory data — used by UI and systems that must not mutate state.
Exposes: Get(GameObject owner, ContainerId container)Search(GameObject owner, ContainerId container, string query)event Action<InventoryDelta> OnContainerChanged
This event is fired only after successful service-level mutations.
Direct container mutations do not emit deltas.
IInventorySearch/IInventorySorter
Strategy seams for searching and sorting slot lists.
SceneInventoryServiceprovides default implementations (DefaultInventorySearch,DefaultInventorySorter),
but projects may replace these strategy instances during initialisation to customise behaviour globally.
Canonical IDs¶
ContainerId— immutable, canonical container identifier- Normalised to trimmed, lowercase
- Defaults to
"backpack"when null/empty -
Implicit conversion to/from
string -
ItemGuid— canonicalised item GUID for saves and lookups - Normalised to trimmed, lowercase
IsEmptyflag for “no GUID”
Both are lightweight value types with strict value equality.
Note:
Internally, SceneInventoryService uses the same canonicalised lowercase keys,
ensuring snapshot and delta tracking is stable and case-insensitive.
Result-First Contracts¶
InvOpResult— a simple(Success, Code, Message)triple returned by every mutationInvOpCode— enumeration of all possible outcomes
Examples:
var res = svc.RemoveByGuid(player, swordGuid, 2, "Backpack");
if (!res.Success)
Debug.LogWarning($"Remove failed: {res.Code} {res.Message}");
var res = svc.SplitResult(player, "Backpack", slotIndex, 3, -1);
if (!res.Success)
ui.ShowError(res.ToUserMessage("Split"));
Convenience Helpers¶
Located in Inventory/Extensions/Results:
InvOpResultUtil.ToUserMessage(this InvOpResult, string prefix)
Converts a result into a short, user-friendly message (used heavily by Teachable Panels).
Toast(res.ToUserMessage("Split"));
A matching helper exists for Currency (CurOpResultUtil) when REV_CURRENCY_PRESENT is defined,
using the same tone and phrasing.
Why result-first?
- Expected failures never throw exceptions
- No silent bools — every operation includes context for UI/logs
- Easy to propagate results into HUDs, overlays, and debugging panels
Common Result Codes¶
| Code | Meaning |
|---|---|
Ok |
Operation succeeded |
NoSpace |
Container full / not enough capacity |
NotFound |
Item not found |
NotEnoughQuantity |
Tried to remove more than available |
FilterMismatch |
Item doesn’t fit this slot/filter |
SwapBlocked |
Merge/swap not possible |
NoAuthority |
Mutation denied by authority policy |
Partial |
Operation partially succeeded (Success = false by design) |
Other codes include argument errors, invalid indices, service-missing cases, and unknown errors.
Who Should Reference Abstractions?¶
These contracts are intended to be referenced by:
- Gameplay systems (inventory, crafting, shops, equipment)
- UI and HUD layers
- Save/load and snapshot systems
- Multiplayer adapters and authority implementations
- Editor tools, diagnostics, and Teachable Panels
Concrete implementations (containers, services, UI bridges) should live behind these contracts.
See Also¶
- Authority → authority policy and mutation permissions
- Containers → slot rules, stack behaviour, and events
- Services → runtime implementation and container deltas