Files

17 KiB
Raw Permalink Blame History

BPC_InventorySystem — Core Inventory System

Parent Class: ActorComponent Category: Inventory Target UE Version: 5.55.7 Build Phase: 4 — Inventory

C++ Status: Full ImplementationSource/PG_Framework/Public/Inventory/BPC_InventorySystem.h provides the complete inventory grid: add/remove/query/sort/consolidate/weight tracking with native-speed TArray operations. Attach directly to player pawn (Add Component → BPC_InventorySystem). Set GridWidth, GridHeight, MaxWeight in Details panel. Do NOT create a BP child — the C++ component has all logic. See docs/developer/cpp-integration-guide.md for usage patterns.

---## 1. Overview

BPC_InventorySystem is the central inventory authority on the player. It manages an array of item instances (stackable, tagged, data-driven), handles add/remove/use/transfer operations, enforces capacity limits, and communicates state changes via Event Dispatchers. All other inventory subsystems (weight, quick slots, UI, equipment) read from this component as their single source of truth.

Items are stored as S_InventoryEntry structs referencing a DA_ItemData primary data asset plus runtime state (stack count, durability, custom metadata). Operations are validated by category, stack limits, and capacity before execution.


2. Mermaid — Inventory Architecture

flowchart TD
    A[External Request] --> B{BPC_InventorySystem}
    B --> C{Operation Type}
    C -->|AddItem| D[Validate: Has Space?]
    C -->|RemoveItem| E[Validate: Has Item?]
    C -->|UseItem| F[Validate: Usable?]
    C -->|TransferItem| G[Validate: Target Has Space?]
    C -->|DropItem| H[Spawn BP_ItemPickup in World]

    D -->|Pass| I[Add to Array / Stack]
    D -->|Fail| J[Return Failure Reason]
    E -->|Pass| K[Remove from Array / Unstack]
    E -->|Fail| L[Return Failure Reason]
    F -->|Pass| M[Dispatch OnItemUsed]
    F -->|Fail| N[Return Failure Reason]

    I --> O[Broadcast OnInventoryChanged]
    K --> O
    M --> O
    G --> P[Remove from Source / Add to Target]
    P --> O

3. Enums

E_InventoryOperationResult

Value Description
Success Operation completed successfully.
InventoryFull No free slots available.
ItemNotFound Specified item not in inventory.
StackLimitReached Item exists but stack is at maximum.
InsufficientQuantity Not enough of the item to remove.
ItemNotUsable Item cannot be used from inventory.
CategoryRestricted Item category not allowed in this inventory.
WeightCapacityExceeded Adding would exceed max weight.

E_ItemCategory

Value Description
Consumable Health items, food, drink, batteries.
KeyItem Story keys, access cards, puzzle tokens.
Weapon Firearms, melee weapons, tools.
Ammo Bullets, shells, energy cells.
Resource Crafting materials, scrap, components.
Document Notes, letters, audio logs, data files.
Equipment Wearable gear (armor, backpack, goggles).
QuestItem Mission-specific objects.

E_SortMode

Value Description
ByName Alphabetical by item name.
ByCategory Grouped by item category.
ByRarity Sorted by item rarity value.
ByWeight Sorted by weight ascending.
ByQuantity Sorted by stack count descending.
ByRecent Most recently acquired first.

4. Structs

S_InventoryEntry

Field Type Description
ItemData DA_ItemData* Reference to the item's data asset.
ItemID FGuid Unique runtime ID for this item instance.
StackCount int32 Current number of this item in the stack.
MaxStackSize int32 Max per slot (from DA, overrideable).
Durability float Current durability (01).
CustomTags FGameplayTagContainer Runtime-added tags for quest tracking.
CustomData TMap<FName, FString> Generic key-value store for per-instance data.
SlotIndex int32 The slot this entry occupies.
bIsEquipped bool Whether this item is currently equipped.

S_InventorySlot

Field Type Description
SlotIndex int32 Unique slot number within the inventory.
Entry S_InventoryEntry The item occupying this slot (empty = null ItemData).
bIsLocked bool If true, this slot cannot be modified.
bIsQuickSlot bool If true, this slot is mapped to a hotkey.
CategoryRestriction E_ItemCategory Only items of this category can occupy this slot.

S_InventorySnapshot

Field Type Description
Slots TArray<S_InventorySlot> Copy of all inventory slots at snapshot time.
TotalWeight float Weight at snapshot time.
TotalItems int32 Count of non-empty slots.
SnapshotTimestamp float Game time when snapshot was taken.

S_ItemQuery

Field Type Description
CategoryFilter E_ItemCategory Only return items of this category.
TagFilter FGameplayTag Only return items with this tag.
NameFilter FString Partial name match (case-insensitive).
bIncludeEquipped bool If false, exclude equipped items.
bSortResult bool If true, sort results by name.

5. Variables

Configuration (Instance Editable, Expose On Spawn)

Variable Type Description
MaxSlots int32 Total number of inventory slots (default 24).
MaxWeightCapacity float Maximum carry weight in kg.
bUseWeightSystem bool If true, weight limits are enforced.
AllowedCategories TArray<E_ItemCategory> Categories permitted in this inventory. Empty = all.
StartingItems TArray<FStartingItemEntry> Items to add at BeginPlay.
bReplicates bool Whether inventory state is replicated.

FStartingItemEntry

Field Type Description
ItemData DA_ItemData* Item data asset to add.
StackCount int32 Quantity to add.
AutoEquip bool If true, equip immediately if possible.

State (Blueprint Read Only)

Variable Type Description
Slots TArray<S_InventorySlot> The actual inventory array. Replicated.
TotalWeight float Current total weight of all items.
TotalItems int32 Current count of non-empty slots.
bIsOverEncumbered bool True when TotalWeight exceeds MaxWeightCapacity.

Internal (Not Replicated)

Variable Type Description
OwningPawn APawn* Cached owning pawn reference.
OnItemCooldowns TMap<FGuid, float> Map of ItemID → remaining cooldown seconds.

6. Functions & Events

Public Functions — Core Operations

Function Description
AddItem Adds an item instance. Returns E_InventoryOperationResult and the slot index. Handles stacking if item already exists and stack not full.
RemoveItem Removes Quantity of an item by ItemID or SlotIndex. Returns result and how many were actually removed.
RemoveItemByTag Removes first matching item by FGameplayTag. Returns result.
UseItem Uses/consumes item at slot. Returns result. Dispatches OnItemUsed. If consumable with limited uses, reduces stack.
DropItem Drops Quantity of item at slot. Creates BP_ItemPickup in world. Returns result and spawned actor.
TransferItem Moves item from this inventory to a target BPC_InventorySystem. Validates target capacity.
MoveItemToSlot Moves item from one slot to another (rearrange). Handles swapping if target slot is occupied.
SplitStack Splits a stack into two slots. Returns new slot index.
CombineStack Combines two stacks of the same item into one (if max allows).

Public Functions — Query

Function Description
HasItem Returns true if inventory contains an item with the given ItemID or matching FGameplayTag.
HasItemQuantity Returns total count of items matching a tag or data asset.
FindItemByTag Returns first S_InventoryEntry matching a gameplay tag.
FindAllItemsByCategory Returns TArray<S_InventoryEntry> filtered by category.
FindAllItemsByTag Returns TArray<S_InventoryEntry> filtered by gameplay tag.
GetItemAtSlot Returns S_InventoryEntry at the given slot index (or empty if slot is free).
GetSlotCount Returns total number of slots (empty + filled).
GetFreeSlotCount Returns number of empty slots.
IsInventoryFull Returns true if no free slots.
SortInventory Reorders slots by the given E_SortMode.
GetTotalWeight Returns current TotalWeight.
IsOverEncumbered Returns bIsOverEncumbered.
GetItemCooldownRemaining Returns seconds remaining for a given ItemID cooldown.

Protected Functions

Function Description
BeginPlay Caches owner, adds starting items, initialises empty slots array.
FindFreeSlot Returns the index of the first empty slot. Returns -1 if full.
FindExistingStack Finds slot index with same ItemData that is below MaxStackSize.
RecalculateWeight Iterates all slots and sums item weight. Updates TotalWeight and bIsOverEncumbered.
ValidateAddItem Pre-checks slot availability, weight capacity, category restrictions. Returns result.
ValidateRemoveItem Pre-checks item exists and has sufficient quantity.
SetSlot Internal: writes an entry to a specific slot index.
ClearSlot Internal: empties a slot.
OnRep_Slots RepNotify: recalculates weight and broadcasts OnInventoryChanged.

Event Dispatchers

Dispatcher Payload Description
OnInventoryChanged Fired on any add/remove/transfer/sort operation.
OnItemAdded S_InventoryEntry Item, int32 SlotIndex Fired after an item is successfully added.
OnItemRemoved S_InventoryEntry Item, int32 SlotIndex, int32 Quantity Fired after an item is removed.
OnItemUsed S_InventoryEntry Item, AActor* Instigator Fired when UseItem successfully executes.
OnItemDropped S_InventoryEntry Item, BP_ItemPickup* DroppedActor Fired when an item is dropped into the world.
OnItemTransferred S_InventoryEntry Item, BPC_InventorySystem* TargetInventory Fired after transfer to another inventory.
OnStackSplit S_InventoryEntry Original, S_InventoryEntry NewStack Fired when a stack is split into two.
OnStackCombined S_InventoryEntry CombinedStack Fired when two stacks are merged.
OnOverEncumberedStateChanged bool bIsOverEncumbered Fired when weight crosses the threshold.
OnItemCooldownStarted FGuid ItemID, float Duration Fired when an item cooldown begins.
OnInventoryFull Fired when all slots are filled.

7. Blueprint Graph Flow

Event BeginPlay
    → Set MaxSlots (from config)
    → Create empty Slots array (Size = MaxSlots)
    → For each StartingItem:
        → Call AddItem (StartingItem.ItemData, StartingItem.StackCount)
        → If StartingItem.AutoEquip → Call EquipItem on slot (via EquipmentSlotSystem)

AddItem (ItemData, Quantity)
    → Call ValidateAddItem → If Fail → return result
    → FindExistingStack (same ItemData, not full)
    → Branch: Found?
        → Yes → Increment stack by Quantity (clamped to MaxStackSize)
            → If Quantity > remaining → FindFreeSlot for overflow
        → No → FindFreeSlot
            → If no free slot → return InventoryFull
            → Create new S_InventoryEntry → Assign SlotIndex
    → RecalculateWeight
    → If bReplicates → Mark slots array dirty
    → Broadcast OnItemAdded, OnInventoryChanged
    → Return Success

RemoveItem (SlotIndex, Quantity)
    → Call ValidateRemoveItem → If Fail → return result
    → Decrement stack count by Quantity
    → If stack count <= 0 → ClearSlot
    → RecalculateWeight
    → Broadcast OnItemRemoved, OnInventoryChanged
    → Return Success

UseItem (SlotIndex)
    → GetItemAtSlot → If empty → return ItemNotFound
    → Check cooldown → If on cooldown → return failure
    → Check bIsUsable from DA_ItemData → If not → return ItemNotUsable
    → If item has cooldown → Add to OnItemCooldowns map
    → Broadcast OnItemUsed
    → If item is consumable (bConsumeOnUse from DA):
        → Reduce stack by 1
        → If stack = 0 → ClearSlot
    → Broadcast OnInventoryChanged
    → Return Success

DropItem (SlotIndex, Quantity, SpawnLocation, SpawnRotation)
    → RemoveItem (SlotIndex, Quantity) → If fail → return
    → SpawnActor BP_ItemPickup at location/rotation
    → Set pickup's ItemData and StackCount
    → Broadcast OnItemDropped
    → Return Success + spawned actor

TransferItem (SlotIndex, TargetInventory, Quantity)
    → Validate item exists and quantity sufficient
    → Call TargetInventory.ValidateAddItem → If fail → return
    → RemoveItem (SlotIndex, Quantity)
    → TargetInventory.AddItem (ItemData, Quantity)
    → Broadcast OnItemTransferred
    → Return Success

SortInventory (SortMode)
    → Build TMap of slot index → entry for non-empty slots
    → Sort entries by SortMode rules
    → Clear all slots
    → Write sorted entries back into sequential slots
    → Broadcast OnInventoryChanged

RecalculateWeight
    → Sum = 0
    → For each slot with non-null ItemData:
        → Sum += ItemData.Weight * StackCount
    → TotalWeight = Sum
    → OldEncumbered = bIsOverEncumbered
    → bIsOverEncumbered = Sum > MaxWeightCapacity
    → If OldEncumbered != bIsOverEncumbered
        → Broadcast OnOverEncumberedStateChanged

8. Replication

Variable Replication Callback
Slots RepNotify OnRep_Slots — refreshes UI, recalculates weight
TotalWeight Replicated
bIsOverEncumbered Replicated
TotalItems Replicated

Authority: Server is authoritative for all add/remove/use operations. Clients predict UI updates but server validates and corrects.

Cooldowns: Managed locally (not replicated) but validated on server for authoritative actions.


9. Dependencies & Communication

System Relationship
DA_ItemData Each slot references a Data Asset for item properties.
BPC_ActiveItemSystem Listens to OnInventoryChanged and OnOverEncumberedStateChanged.
WBP_InventoryMenu Subscribes to all event dispatchers to update UI.
BPC_EquipmentSlotSystem Reads bIsEquipped flag; equips/unequips items via slot.
BP_ItemPickup Receives dropped items; sends pickup requests to AddItem.
BPC_InteractionDetector Routes pickup interaction to AddItem.
BPC_HealthSystem Consumed health items via UseItem trigger healing.
BPC_StaminaSystem Consumed stamina items via UseItem trigger stamina restore.
Save/Load System Serializes Slots array for save/restore.
BPC_PlayerMetricsTracker Logs item acquisition events.
BPC_DifficultyManager May adjust MaxSlots or MaxWeightCapacity based on difficulty.

10. Success Criteria

  1. Items can be added to inventory; duplicates stack up to MaxStackSize.
  2. Adding beyond slot capacity returns InventoryFull.
  3. Adding beyond weight capacity returns WeightCapacityExceeded.
  4. Items can be removed by slot index or gameplay tag; stacks decrement correctly.
  5. Using a consumable item reduces stack; item is removed at 0.
  6. Dropping an item spawns BP_ItemPickup in the world with correct data.
  7. Items can be transferred between inventories (player ↔ container).
  8. Inventory can be sorted by all sort modes.
  9. Stack splitting creates a new slot; combining merges stacks.
  10. Event dispatchers fire correctly for all operations.
  11. Multiplayer: inventory state is server-authoritative and syncs to clients.
  12. Save/load restores exact inventory state including custom data.

11. Data Flow Summary

Player picks up item
    → BPC_InteractionDetector detects BP_ItemPickup
    → Player presses Interact
    → BP_ItemPickup.ExecuteInteraction → BPC_InventorySystem.AddItem
    → Validate (space, weight, category)
    → Add to array / increment stack
    → RecalculateWeight
    → Broadcast OnItemAdded / OnInventoryChanged
    → UI updates / Weight system reacts / Metrics logs

Player uses health item from inventory
    → UI calls BPC_InventorySystem.UseItem (SlotIndex)
    → Validate (exists, usable, cooldown)
    → Broadcast OnItemUsed
    → BPC_HealthSystem.OnItemUsed → ApplyHealing
    → If consumable → reduce stack
    → Broadcast OnInventoryChanged

12. Reuse Notes

  • Renamed from BPC_InventoryComponent to BPC_InventorySystem per Master naming convention.
  • Cross-references updated: BPC_InventoryWeightSystemBPC_ActiveItemSystem, BPC_InventoryQuickSlotBPC_ActiveItemSystem, BPC_InventoryUIManagerWBP_InventoryMenu, BPC_EquipmentSystemBPC_EquipmentSlotSystem.