📦 Abstractions¶
Interfaces, identifiers, and core result types that every other Inventory subsystem builds on. These are stable runtime contracts and are safe to reference from runtime or editor assemblies.
These types contain no runtime mutation logic or container behaviour. They define contracts, identifiers, and result semantics only.
🎯 Purpose¶
Abstractions provide:
- Shared contracts across all Inventory subsystems
- Stable identifiers and value types
- Result semantics for mutation operations
They allow systems to depend on behaviour without depending on concrete implementations.
🧩 What Lives Here¶
Core Interfaces¶
IInventoryServiceScene-scoped inventory API for mutations (write operations). Exposes result-first methods (GiveExact,RemoveByGuid,SplitResult,ResizeContainer, etc.).
Service-level mutations consult authority and may return InvOpCode.NoAuthority when denied.
Direct container access or convenience wrappers may bypass authority. Use the service when authority enforcement is required.
Inherits from IReadOnlyInventoryService.
IReadOnlyInventoryServiceRead-only view of inventory data.
Exposes:
Get(GameObject owner, ContainerId container)Search(GameObject owner, ContainerId container, string query)event Action<InventoryDelta> OnContainerChanged
Events are raised after service-level mutations.
Direct container mutations do not emit deltas.
IInventorySearch/IInventorySorterStrategy seams for searching and sorting.
Default implementations are provided by SceneInventoryService.
Projects may replace these strategies during service initialisation if they control the service instance.
Canonical IDs¶
-
ContainerId -
Normalised to trimmed, lowercase
- Defaults to
"backpack"when null or empty -
Supports implicit conversion to and from
string -
ItemGuid -
Normalised to trimmed, lowercase
- Provides
IsEmptyfor "no GUID"
Both are lightweight value types with strict equality.
Internal systems use canonicalised lowercase keys for stable and case-insensitive behaviour.
Result Contracts¶
-
InvOpResultRepresents(Success, Code, Message)for mutation outcomes -
InvOpCodeEnumerates possible operation results
Example:
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:
InvOpResultExtensions.ToUserMessage(this InvOpResult, string prefix)
Converts a result into a short user-facing message.
A matching helper exists for Currency (CurOpResultUtil) when REV_CURRENCY_PRESENT is defined.
🧠 Usage Guidance¶
Why result-first?¶
- Expected failures do not rely on exceptions
- Operations return structured outcomes instead of booleans
- Results can be passed directly into UI, logs, or diagnostics
⚠️ Important Notes¶
- These types define contracts only
- They do not implement runtime behaviour
- They should not be extended with gameplay logic
Concrete implementations (services, containers, UI bridges) should exist behind these contracts.
🧩 Common Result Codes¶
| Code | Meaning |
|---|---|
| Ok | Operation succeeded |
| NoSpace | Not enough capacity |
| NotFound | Item not found |
| NotEnoughQuantity | Too many removed |
| FilterMismatch | Slot cannot accept item |
| SwapBlocked | Merge or swap blocked |
| NoAuthority | Mutation denied |
| Partial | Partial success (Success = false) |