UCrimsonInventoryManagerComponent

The central authority component. Add it to a PlayerState, Pawn, PlayerController, or a world container actor. All mutating functions are BlueprintAuthorityOnly. The inventory list replicates via FFastArraySerializer; the layout asset replicates COND_InitialOnly; ActiveConstraints replicates as a subobject array; tag-stack constraints are COND_OwnerOnly.

Initialization & layout

cpp
// Layout (set before init; replicated COND_InitialOnly)
UCrimsonInventoryLayout* GetLayout() const;
void SetLayout(UCrimsonInventoryLayout* InLayout); // authority-only
const FCrimsonLayoutRuntimeState& GetLayoutRuntime() const;
FCrimsonPlacementContext MakePlacementContext(int32 LayoutGroupId = 0) const;
void RebuildLayoutRuntime();
// Init: tag-stack caps + currency tables
void InitializeInventory(
const TArray<UDataTable*>& ConstraintDataTables,
const TArray<FCrimsonTagStack>& DefaultIntConstraints,
const TArray<FCrimsonFloatTagStack>& DefaultFloatConstraints,
const TArray<UDataTable*>& CurrencyDataTables);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnInventoryInitialized);
UPROPERTY(BlueprintAssignable) FOnInventoryInitialized OnInventoryInitialized;

Item operations (authority-only, EntryId-based)

MethodDescription
CanAddItemDefinition(ItemDef, Count)Returns false (and broadcasts failure) if adding would violate any constraint
AddItemDefinition(ItemDef, Count, Policy, ExplicitTarget)Adds items via the layout's FindPlacement. Policy = MergeFirst / FirstFree / LastFree / MergeOnly / ExplicitTarget
AddItemInstance(Instance, Count, Policy, ExplicitTarget)Adds a pre-existing instance (e.g. from inventory transfer)
RemoveItemsByDefinition(ItemDef, Count)Removes N items by definition; -1 removes all
RemoveItemInstance(Instance)Removes a specific instance entirely
MoveItemByEntry(SourceEntryId, Target)Moves an entry; layout decides Move/Swap/Merge. Returns FCrimsonMoveResult.
DropItemByEntry(EntryId, Qty, Location)Removes items and broadcasts FCrimsonInventory_Message_ItemDropped; spawns one pickup actor if the item has PickupActorClass
DropItemsByDefinition(ItemDef, Count, Location)Same but finds items by definition; spawns one pickup actor per consumed instance
DropEntriesAsBag(EntryIds, Location, BagActorClass)Server-only: packs every supplied entry's full stack into a single ACrimsonPickupActorBase bag actor. Preserves per-instance state.
SplitStackByEntry(SourceEntryId, Amount)Creates a new entry with the split portion via the layout
MergeStacksByEntry(SourceEntryId, TargetEntryId)Merges source into target up to MaxStackSize
MergeStack(Instance)Finds compatible stacks and merges into them
LockEntry(EntryId, bLocked)Lock/unlock an entry. Locked entries are skipped by sort / consume / quick-merge
ConsumeItemsByDefinition(ItemDef, Count, OutConsumed)Removes N items and populates OutConsumed; skips locked entries

Read operations

MethodDescription
GetAllItems()All item instances
FindFirstItemStackByDefinition(ItemDef)First instance matching definition
FindEntryByEntryId(EntryId)Entry by stable id
FindEntryAtTarget(Target)Entry at a layout target
GetSlottedEntries()Raw entry array
GetFilteredItems(Filter) / PartitionItemsByFilter(...)Filter-based queries
GetTotalItemCountByInstance / ByDefinitionAggregate stack counts
HasRoomFor(ItemDef, Count)Convenience: would Count items fit?
CalculateAddableQuantity(ItemDef, Requested, OutReason)Max that can actually be added given current constraints

Constraint stack

cpp
// Runtime mutation (authority-only)
void AddConstraint(UCrimsonInventoryConstraint* Constraint);
bool RemoveConstraint(UCrimsonInventoryConstraint* Constraint);
// Read
TArray<UCrimsonInventoryConstraint*> GetActiveConstraints() const;
TArray<UCrimsonInventoryConstraint*> GetConstraintsByTag(FGameplayTag Tag) const;
// Tag-stack caps (replicated FastArray)
int32 GetCurrentIntConstraintValue(FGameplayTag Tag) const;
int32 GetMaxIntConstraintValue(FGameplayTag Tag) const;
float GetCurrentFloatConstraintValue(FGameplayTag Tag) const;
float GetMaxFloatConstraintValue(FGameplayTag Tag) const;
void ModifyIntConstraintValue(FGameplayTag Tag, int32 Delta); // authority-only
void ModifyFloatConstraintValue(FGameplayTag Tag, float Delta); // authority-only

Async sort

cpp
FCrimsonInventorySortRequest Request;
Request.bMergeAfterSort = true;
Request.Rules = {
{ TAG_Crimson_Inventory_Sort_ByItemType, true },
{ TAG_Crimson_Inventory_Sort_ByName, true }
};
InventoryComponent->RequestAsyncSort(Request); // locked entries are excluded

Currency API

cpp
InventoryComponent->AddCurrency(GoldRowHandle, 100);
bool bOk = InventoryComponent->RemoveCurrency(GoldRowHandle, 50);
int64 Amount = InventoryComponent->GetCurrencyAmount(GoldRowHandle);
TArray<UCrimsonInventoryCurrency*> AllGold = InventoryComponent->FindAllCurrencyByTag(TAG_Currency_Gold);
UCrimsonInventoryCurrency* Coins = InventoryComponent->FindCurrencyByName(TEXT("Gold"));
InventoryComponent->DropCurrency(GoldRowHandle, 10, DropLocation);
InventoryComponent->RemoveCurrencyByTag(TAG_Currency_Gold, 25);

Save / Load

cpp
FCrimsonInventorySaveData SaveData = InventoryComponent->GetSaveData();
// ... serialize
InventoryComponent->ApplySaveData(SaveData); // authority-only

Replication notes

- FCrimsonInventoryList uses FFastArraySerializer. Every mutation calls MarkItemDirty (per entry) or MarkArrayDirty (bulk).
- LayoutAsset is Replicated, COND_InitialOnly - set during init, immutable thereafter.
- ActiveConstraints replicates as a subobject array (AddReplicatedSubObject / RemoveReplicatedSubObject on add/remove).
- LayoutRuntime is Transient, NotReplicated. Rebuilt from entries in OnRep_InventoryList and FastArray PostReplicatedAdd/Change/Remove.
- ConstraintTags (int) and ConstraintFloatTags (float) are COND_OwnerOnly.
- Currencies are replicated subobjects.
- Constraint-change notifications use Client Reliable RPCs, re-broadcast via UCrimsonMessageSubsystem so UI can subscribe without seeing the RPC plumbing.