🧰 Using the Inventory System¶
The Inventory system is a scene-scoped, authority-aware container service.
It powers adding, removing, sorting, searching, equipping, and using items through a result-first API (InvOpResult).
ℹ Containers are created lazily. Calling
Get(),GiveExact(),AddMax(),SplitResult(), etc. will create the container the first time it is accessed for a given owner + container name.
See also: - Services → lifecycle, deltas, authority, resolution rules - Data → ItemDefinition, ItemDatabase, ContainerSizePolicy - Equipment → equipping, slot filters, visuals - UI → optional reference UI (Unity UI)
If you want terse bool-returning helpers, import:
using RevGaming.RevFramework.Inventory.Extensions;
…but for gameplay logic you should always prefer the result-first APIs
(GiveExact, SplitResult, TransferResult, etc.) so failure reasons are explicit.
🚀 Quickstart¶
1. Add SceneInventoryService¶
- Create an empty GameObject
- Add
SceneInventoryService - Assign your ItemDatabase
- (Optional) assign a ContainerSizePolicy
⚠ Only one
SceneInventoryServicemay exist per scene. Extra instances auto-destroy (Awake) or auto-disable (OnEnable).
2. Add CharacterInventory to your player¶
This automatically adds InventoryOwnerHook and exposes:
playerCharacterInventory.Container
- Default backpack size = 24 slots
- May be overridden by ContainerSizePolicy
3. Subscribe to container deltas (UI / observers)¶
svc.OnContainerChanged += delta =>
{
bridge.Handle(delta); // e.g. InventoryUiBridge
};
🔔 Deltas only fire after a container exists. Containers are created lazily by
Get(),GiveExact(),AddMax(), etc.
🔑 Authority¶
All authoritative gameplay mutations should be performed through IInventoryService.
- Service-level mutations consult
IInventoryAuthority - Denied mutations return
InvOpCode.NoAuthority
Direct calls on InventoryContainer or CharacterInventory:
- Do not consult authority
- Are intended for single-player, local logic, or UI-only usage
❗ If you mutate inventory from a non-authoritative instance, the call may succeed locally but is logically rejected by authority.
Single-player¶
InventoryAuthorityBinder // allows all mutations
Multiplayer¶
- Implement your own authority binder (NGO / Mirror / Fusion / custom)
- Invoke mutations only on the authoritative instance (server / host)
1️⃣ Adding Items¶
Authority-safe (recommended for multiplayer)¶
var svc = SceneInventoryService.Instance;
var res = svc.GiveExact(
player,
new ItemStack { def = sword, quantity = 1 },
"Backpack"
);
if (!res.Success)
Debug.LogWarning($"Add failed: {res.Code} {res.Message}");
Local / single-player only¶
var inv = playerCharacterInventory.Container;
var stack = new ItemStack { def = sword, quantity = 1 };
var res = inv.TryAddAllResult(stack);
if (!res.Success)
Debug.LogWarning($"Add failed: {res.Code} {res.Message}");
⚠ Direct container calls bypass authority. Use service calls for authoritative gameplay.
2️⃣ Removing Items¶
Authority-safe¶
var res = svc.RemoveByGuid(
player,
"sword-guid",
2,
"Backpack"
);
For slot-specific removal, use
RemoveFromSlot(...).
Local / single-player only¶
var res = inv.TryRemoveResult("sword-guid", 2);
3️⃣ Splitting Stacks¶
var splitRes = svc.SplitResult(
player,
"Backpack",
srcIndex: 0,
amount: 2,
targetIndex: -1 // auto-place
);
Split fails if:
- amount >= stack.quantity
- destination cannot accept the item
- filters or capacity rules block placement
4️⃣ Equipping Items¶
var equipRes = playerCharacterEquipment.TryEquipFromInventoryResult(
playerCharacterInventory,
slotIndex: 0,
slotId: "Weapon"
);
⚠ Equipment slots store exactly one item (quantity is forced to 1).
5️⃣ Unequipping Items¶
var unequipRes = playerCharacterEquipment.TryUnequipToInventoryResult(
playerCharacterInventory,
"Weapon"
);
6️⃣ Using an Item¶
var useSys = FindFirstObjectByType<ItemUseSystem>();
var useRes = useSys.UseResult(player, slotIndex: 0);
- Effects run in order
- At least one effect must apply
- Exactly one item is consumed on success
- Consumption is authority-gated
7️⃣ Snapshots (Save / Load)¶
var dto = InventorySnapshots.Capture(playerInv, playerEquip);
InventorySnapshots.SaveToFile("mysave", dto);
var loaded = InventorySnapshots.LoadFromFile("mysave");
if (loaded != null)
{
InventorySnapshots.Apply(
playerInv,
playerEquip,
loaded,
myItemDatabase,
InventorySnapshotOptions.Default
);
}
⚠ Snapshots serialize inventory state only. They are not a full persistence or save-slot system.
Gotchas¶
- Extra snapshot slots are ignored
- Equipment quantities are forced to 1
- Unknown GUID handling:
- Skip
- OR SubstitutePlaceholder (requires
ItemDatabase.missingPlaceholder)
🔎 Sorting & Searching¶
svc.SortByRarity(player); // rarity desc
var hits = svc.Search(player, "potion");
Sorting is stable and idempotent. Re-sorting without changes preserves relative order.
💡 Tips¶
- Always check
Successbefore acting on results - Use both
.Codeand.Messagefor UX - Prefer service calls for gameplay; containers for local/UI logic
Common InvOpCodes¶
| Code | Meaning |
|---|---|
Ok |
Success |
NoSpace |
Not enough capacity |
NotFound |
Item not found |
NotEnoughQuantity |
Tried to remove too many |
FilterMismatch |
Slot cannot accept item |
NoAuthority |
Authority denied |
SwapBlocked |
Merge/swap not possible |
Partial |
Partially succeeded (Success = false) |
🧹 Optional / Safe to Delete¶
| Folder | Safe to Delete | Notes |
|---|---|---|
UI/ |
✅ Yes | Reference Unity UI only |
Bridges/ |
✅ Yes | Optional integrations (e.g. Pickups) |
Equipment/ |
✅ Yes | Only needed if you support equipping |
Snapshots/ |
✅ Yes | Optional save/load helpers |
Presentation/ |
✅ Yes | Rarity themes, visuals |
⏭ Next Steps¶
- Explore InventoryDebugPanel for hands-on testing
- Browse Samples/Inventory/ for example setups
- Read Services and Data
🎥 YouTube Playlist:
Inventory System Teaching Panels
https://www.youtube.com/playlist?list=PLRcFCSvBkJAGXfc2fbQQrJ5WfWVLNqsBJ