GearFlow
A fully modular inventory, equipment, and crafting system for Unreal Engine 5. Fragment-based item definitions, tag-driven gear slots, categorized inventory, timed crafting queues, and built-in save serialization, multiplayer-ready out of the box.
Overview
GearFlow is a modular inventory, equipment, and crafting framework for Unreal Engine 5. Items are UGearItemDefinition data assets, a small set of flat fields (name, description, icon) plus an opt-in Fragments array. Each fragment owns one concern: stacking lives on UGearStackFragment, equipment slot data on UGearEquipmentFragment, purchase cost on UGearCostFragment, world pickup visuals on UGearPickupFragment, and inventory category on UGearCategoryFragment. An item carries only the fragments it needs.
Three storage components, Inventory, Equipment, and Wallet, extend a shared UGearStorageComponent base that owns the replicated slot array and the full Add/Remove/Query API. Crafting supports both immediate execution and a timed queue. A save library serializes and restores all three component types. A world-facing layer of pickup actors and loot tables covers every item-movement pattern without custom code. GAS is optional.
Fragment System
Item behaviour is composed via opt-in fragments. Shared, Instanced, and InstancedReplicated policies control how fragment data is owned and replicated. Lifecycle hooks fire on equip, unequip, create, and destroy.
Modular Components
Add only what each actor needs. A chest uses Inventory. A player adds Equipment. A shop NPC adds Wallet. Each component is self-contained and independently replicated.
Multiplayer Ready
FastArray replication with delta compression on all storage components. Server-authoritative. Works with Listen and Dedicated servers out of the box. InstancedReplicated fragments replicate per-instance state automatically.
Designer Friendly
All items, recipes, and loot tables are data assets. Designers create and iterate entirely in the Content Browser. Built-in gameplay tags cover equipment slots, item types, and currencies out of the box.
Transfer Model
All item movement, looting, buying, dropping, runs through UGearFunctionLibrary. One unified path, one set of delegates, no custom movement code required in your project.
Crafting System
Data-driven recipes with multi-output support. Instant crafting via UGearCraftingComponent or time-queued crafting via UGearTimedCraftingComponent. Custom validation rules for skill gates and positional grids.
Equipment Slots
Tag-driven named gear slots. UGearEquipmentFragment declares accepted slot types and an array of visual entries, each entry provides an actor class and optional socket override for multi-mesh weapon setups.
Save System
UGearSaveLibrary serializes inventory, equipment, and wallet state to structured save data types. Per-instance save hooks let custom fragments persist their own state alongside the slot data.
Getting Started
A working inventory is up and running in five steps. The fastest path requires no C++ beyond adding the module dependency.
Enable the plugin
In the Unreal Editor, open Edit → Plugins, search for GearFlow, and enable it. Restart the editor when prompted.
Add the module dependency
Open your project's Build.cs and add "GearFlow" to PublicDependencyModuleNames. This gives access to all GearFlow C++ headers in your module.
Create an Item Definition
Right-click in the Content Browser and select GearFlow → Item Definition. Open the asset and set DisplayName and Icon. Add fragments to the Fragments array as needed, for example, a UGearStackFragment to allow stacking, or a UGearEquipmentFragment to make the item equippable.
Add UGearInventoryComponent to your character
In your character Blueprint or C++, add a UGearInventoryComponent and set SlotCount to the number of inventory slots you want. No further setup is required, the component replicates automatically.
Add an item
Call AddItem(ItemDefinition, Count) on the component from the server. The item fills existing stacks first for stackable items, then creates new slots. Replication to clients is automatic.
Item Definition
UGearItemDefinition extends UPrimaryDataAsset and is the immutable template for an item type. It is never modified at runtime, all runtime state lives on the UGearItemInstance. A small set of flat fields is present on every item; all optional behaviour is added via the Fragments array.
| Property | Type | Description |
|---|---|---|
| DisplayName | FText | Shown in inventory UI. |
| Description | FText | Tooltip or detail panel text. |
| Icon | TSoftObjectPtr<UTexture2D> | Inventory slot icon. Soft reference, loaded on demand, not held in memory when the item is not displayed. |
| Fragments | TArray<UGearItemFragment*> | Instanced fragment objects that attach optional behaviour to this item. Absence of a fragment means the item simply does not have that capability. |
| InstanceClass | TSubclassOf<UGearItemInstance> | Custom instance class override. Leave unset to use the default UGearItemInstance. Override when you need Blueprint-subclassed instances with per-item state (durability, enchantments). |
Fragment access
| Function | Description |
|---|---|
| FindFragment<T>() | Template accessor returning the first fragment of type T, or nullptr. Use in C++. |
| FindFragmentByClass(Class) | Blueprint-accessible equivalent. Pass the fragment class and cast the result. |
Fragments
UGearItemFragment is the base class for all item fragments. Every fragment declares a policy that controls how the fragment is owned and replicated at runtime. Add your own fragment subclasses in Blueprint or C++ to attach custom per-item data without modifying the definition asset itself.
EGearFragmentPolicy
| Value | Description |
|---|---|
| Shared | Fragment data is read directly from the definition asset. No per-instance copy is made. Use for read-only data that all instances share (e.g. display name overrides, category tags). |
| Instanced | A copy of the fragment is made per instance, owned locally on the server. Use for mutable per-instance data that does not need to reach clients (server-only durability tracking). |
| InstancedReplicated | A copy is made per instance and replicated to clients. Use for data that must be visible to clients, ability charges, enchantment level, or any state the UI reads. |
Lifecycle hooks
Override these in your fragment subclass to react to item events. All hooks run server-side.
| Hook | When it fires |
|---|---|
| OnCreated(Instance) | After the item instance is created and the definition is assigned. Use for one-time initialization, roll random stats, set initial charges. |
| OnDestroyed(Instance) | Before the instance is destroyed (item removed from all storage). Use to clean up side effects or grant replacement items. |
| OnEquipped(Instance, SlotTag) | After the item is placed in a gear slot. Use to apply passive stat modifiers or grant abilities. |
| OnUnequipped(Instance, SlotTag) | After the item is removed from a gear slot. Use to revoke any effects applied by OnEquipped. |
Built-in fragment classes
| Class | Key Property | Purpose |
|---|---|---|
| UGearStackFragment | MaxStackSize: int32 | Makes the item stackable. Maximum units per slot. Absence means one unit per slot, each with its own instance. |
| UGearEquipmentFragment | AcceptedSlotTypes: FGameplayTagContainer | Makes the item equippable. Declares which slot tags accept this item. Also holds EquippedVisuals, an array of visual entries, each with an actor class and optional socket override for multi-mesh setups. |
| UGearCostFragment | Cost: TMap<FGameplayTag, int32> | Attaches a purchase price. Currency tag → amount pairs. Used by TransferItem when a wallet is provided, the transfer fails atomically if the wallet cannot cover all entries. |
| UGearPickupFragment | PickupActorClass, WorldMesh | Makes the item droppable. Specifies the pickup actor class (null uses the built-in static mesh pickup) and the mesh to display. Absence means the item cannot be dropped. |
| UGearCategoryFragment | CategoryTag: FGameplayTag | Tags the item with an inventory category. Matched against FGearInventoryCategory.ItemTypeFilter to route the item into the correct category slots when added to a categorized inventory. |
Custom fragment example
// Declare a replicated, per-instance durability fragment
UCLASS()
class UDurabilityFragment : public UGearItemFragment
{
GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly)
float MaxDurability = 100.f;
UPROPERTY(Replicated)
float CurrentDurability = 100.f;
virtual EGearFragmentPolicy GetPolicy() const override
{ return EGearFragmentPolicy::InstancedReplicated; }
virtual void OnCreated(UGearItemInstance* Instance) override
{ CurrentDurability = MaxDurability; }
}; Item Instance
UGearItemInstance is the runtime handle for an item occupying a slot. It holds a pointer to the immutable definition and the per-instance copies of any Instanced or InstancedReplicated fragments. Stackable items share one instance per slot; non-stackable items get one instance per unit so each can carry individual state. Instances are owned and replicated by the storage component, never construct one manually. Subclass in Blueprint or C++ via the definition's InstanceClass override.
| Property | Type | Description |
|---|---|---|
| Definition | UGearItemDefinition* | The definition this instance was created from. Replicated. |
| InstancedFragments | TArray<UGearItemFragment*> | Per-instance copies of fragments with Instanced or InstancedReplicated policy. Query through FindFragment rather than accessing this array directly. |
| Function | Returns | Description |
|---|---|---|
| GetDefinition() | UGearItemDefinition* | Inline getter for the definition. |
| IsStackable() | bool | True when the definition carries a UGearStackFragment. |
| FindFragment<T>() | T* | Searches instanced fragments first, then falls back to the definition's shared fragments. Use this in C++ to access fragment data from an instance. |
| FindFragmentByClass(Class) | UGearItemFragment* | Blueprint-accessible equivalent of FindFragment<T>. |
| OnInstanceCreated() | Blueprint event | Called once after Definition is assigned. Override to initialize per-instance state. Fragment OnCreated hooks fire before this. |
| GetInstanceSaveData(out TMap<FString,FString>) | Blueprint event | Return custom key/value pairs for save serialization. Called by UGearSaveLibrary::CaptureInventory. |
| SetInstanceSaveData(TMap<FString,FString>) | Blueprint event | Restore custom save data on load. Called by UGearSaveLibrary::RestoreInventory before OnInstanceCreated. |
Storage Component
UGearStorageComponent is the abstract base shared by Inventory and Equipment. It owns the replicated slot array (FastArray via FGearContainerSlot) and exposes the full Add/Remove/Query/Move API. All mutating functions are server-authoritative, calling them on a client has no effect.
FGearContainerSlot
| Field | Type | Description |
|---|---|---|
| Instance | UGearItemInstance* | The item instance occupying this slot. nullptr if empty. |
| Count | int32 | Stack count for stackable items. Always 1 for non-stackable items. |
| bStackable | bool | Whether this slot allows stacking. |
| MaxStackSize | int32 | Maximum stack count for this slot. |
| SlotFilter | FGameplayTag | Tag filter for this slot. An empty tag accepts any item. Used by equipment slots to restrict item types. |
Functions
| Function | Description |
|---|---|
| AddItem(Definition, Count) | Adds Count units; fills existing stacks first, then new slots. Returns the amount actually added. Server only. |
| AddItemInstance(Instance) | Places a pre-created instance into the first available matching slot. Server only. |
| RemoveItem(Definition, Count) | Removes Count units by item type. Returns false if insufficient. Server only. |
| RemoveItemInstance(Instance) | Removes a specific instance. Server only. |
| SwapSlots(IndexA, IndexB) | Swaps two slots within this component. Server only. |
| SwapSlotsBetween(IndexA, OtherComponent, IndexB) | Swaps a slot in this component with a slot in another component. Server only. |
| SplitStack(SlotIndex, SplitCount) | Splits a stack by moving SplitCount units to the next available empty slot. Server only. |
| ConsolidateStacks() | Merges split stacks of the same item where possible, freeing slots. Server only. |
| MoveItem(SlotIndex, TargetComponent, TargetSlotIndex) | Moves a slot to a specific slot in another (or the same) component. Server only. |
| GetItemCount(Definition) | Returns total units of an item across all slots. |
| HasItem(Definition, Count) | Returns true if at least Count units of the item are present. |
| CanAddItem(Definition, Count) | Returns true if there is room to add Count units without losing any. |
| GetItemInstance(Definition) | Returns the first instance of the given item type, or nullptr. |
| GetSlots() | Returns all slots as an array snapshot. Safe to call on client. |
| FindAvailableSlotIndex(Definition) | Returns the index of the first available slot for the item, or -1 if none. |
Delegates
| Delegate | Parameters | Description |
|---|---|---|
| OnSlotChanged | SlotIndex, FGearContainerSlot | Fires on any slot mutation, add, remove, or stack count change. Broadcasts on both server and client after replication. Bind here to keep UI in sync. |
| OnStorageFull | Item, AmountNotAdded | Fires when AddItem cannot place all units due to capacity. Use to show an inventory-full notification. |
Inventory Component
UGearInventoryComponent extends UGearStorageComponent and acts as the player bag, chest, or loot container. Slots can be configured uniformly or split into named categories, each category owns a fixed slice of the slot array and accepts only items whose UGearCategoryFragment tag matches the category's ItemTypeFilter.
Properties
| Property | Type | Description |
|---|---|---|
| SlotCount | int32 | Total number of slots when not using categories. Ignored if Categories is populated. |
| bDefaultStackable | bool | Default stacking behaviour applied to all slots unless overridden per-slot or per-category. |
| DefaultMaxStackSize | int32 | Default max stack count when bDefaultStackable is true. |
| SlotFilters | TArray<FGameplayTag> | Per-slot tag filters, index-matched to the slot array. Slots without an entry use an empty filter (accepts anything). |
| Categories | TArray<FGearInventoryCategory> | Defines named category groups. When populated, the inventory is divided into category-owned slot ranges instead of using SlotCount. |
FGearInventoryCategory
Each entry in the Categories array defines a named slot group. The total inventory slot count is the sum of all category SlotCount values.
| Field | Type | Description |
|---|---|---|
| CategoryTag | FGameplayTag | Unique identifier for this category. Used as the key in GetSlotsByCategory. |
| DisplayName | FText | UI display name for this category tab or section. |
| Icon | TSoftObjectPtr<UTexture2D> | Icon for this category's UI tab. |
| SlotCount | int32 | Number of slots in this category's range. |
| ItemTypeFilter | FGameplayTag | Matched against the item's UGearCategoryFragment.CategoryTag. Only matching items can enter this category's slots. |
| bAcceptsUncategorized | bool | When true, items without a UGearCategoryFragment can spill into this category. Useful as a catch-all "Misc" category. |
| bDefaultStackable | bool | Stacking behaviour applied to all slots in this category, overriding the component-level default. |
| DefaultMaxStackSize | int32 | Max stack size for slots in this category. |
Category functions
| Function | Description |
|---|---|
| GetSlotsByCategory(CategoryTag) | Returns the slot indices belonging to the given category. Use to drive per-category UI panels. |
| ResizeInventory(NewSlotCount) | Resizes the total slot count at runtime. New slots are empty; items are not moved. Existing items beyond NewSlotCount overflow via the OnStorageFull delegate path. Server only. |
| ResizeCategory(CategoryTag, NewSlotCount) | Resizes a single category's slot range at runtime. Server only. |
Equipment Component
UGearEquipmentComponent extends UGearStorageComponent and manages named gear slots, one item per slot, identified by Gameplay Tag. Only items carrying a UGearEquipmentFragment can be equipped; the fragment's AcceptedSlotTypes must overlap with the target slot tag. When an item is equipped, the component iterates the fragment's EquippedVisuals array and spawns each visual actor server-side, attaching it to the specified socket on VisualAttachTarget. All visual actors replicate to clients. Unequipping destroys them.
Properties
| Property | Type | Description |
|---|---|---|
| EquipmentSlotDefinitions | TArray<FGameplayTag> | The set of valid slot tags recognized by this component (e.g. GearFlow.Slot.MainHand). Only listed tags can receive items. |
| VisualAttachTarget | USceneComponent* | Component to attach visual actors to, typically the character's skeletal mesh. |
| SlotAttachSockets | TMap<FGameplayTag, FName> | Maps slot tag to socket name on VisualAttachTarget. If a slot has no entry, visuals attach at the component root. |
| EquipmentRule | UGearEquipmentRule* | Optional custom validation object. Default validation is tag matching only. Subclass UGearEquipmentRule and override ValidateEquip() to add level requirements, class restrictions, or other conditions. |
Functions
| Function | Description |
|---|---|
| EquipItem(Definition, SlotTag) | Creates a new instance from the definition and equips it to the slot. Unequips the current occupant first if needed. Server only. |
| UnequipSlot(SlotTag) | Removes the item from the slot. Does not destroy the instance. Server only. |
| UnequipItem(Definition) | Finds and unequips the first slot holding this item type. Server only. |
| GetItemInSlot(SlotTag) | Returns the UGearItemDefinition* in that slot, or nullptr if empty. |
| GetItemInstanceInSlot(SlotTag) | Returns the UGearItemInstance* in that slot, or nullptr. |
| IsSlotOccupied(SlotTag) | Returns true if the slot has an item. |
Delegates
| Delegate | Parameters | Description |
|---|---|---|
| OnItemEquipped | SlotTag, Instance | Fires after equip replication reaches clients. Safe to use for UI and VFX responses. |
| OnItemUnequipped | SlotTag, OldInstance | Fires after unequip replication reaches clients. |
| OnVisualSpawned | SlotTag, SpawnedActor | Fires on the server when a visual actor is spawned for a slot. Use to call setup functions on the visual actor before clients receive it. |
GearFlow.Slot.MainHand, GearFlow.Slot.OffHand, GearFlow.Slot.Head, GearFlow.Slot.Chest, GearFlow.Slot.Legs, GearFlow.Slot.Feet, GearFlow.Slot.Hands, GearFlow.Slot.Ring, GearFlow.Slot.Neck, GearFlow.Slot.Back. Define your own in your project's gameplay tags for custom slots. Wallet Component
UGearWalletComponent is a tag-keyed currency store with FastArray replication. Any number of currency types are supported, each identified by a Gameplay Tag. Multi-currency cost checks and atomic payment are first-class, CanAfford and PayCost operate on a whole cost map, making vendor transactions and recipe costs a single call. GearFlow ships built-in currency tags: GearFlow.Currency.Gold, GearFlow.Currency.Silver, and GearFlow.Currency.Premium.
| Function | Description |
|---|---|
| AddCurrency(CurrencyTag, Amount) | Adds Amount to the given currency. Server only. |
| RemoveCurrency(CurrencyTag, Amount) | Removes Amount. Returns false if insufficient. Server only. |
| HasCurrency(CurrencyTag, Amount) | Returns true if at least Amount is present for that tag. |
| GetCurrency(CurrencyTag) | Returns current balance, or 0 if the tag has never been added. |
| CanAfford(TMap<FGameplayTag,int32>) | Returns true if all entries in the cost map can be met simultaneously. |
| PayCost(TMap<FGameplayTag,int32>) | Deducts all entries atomically. Returns false and applies no change if any single entry is insufficient. Server only. |
| GetCurrencies() | Returns all currency entries as a snapshot array. |
| ClearAllCurrencies() | Removes all currencies. Server only. |
| Delegate | Parameters | Description |
|---|---|---|
| OnCurrencyChanged | CurrencyTag, NewAmount | Fires on client after replication. Use to refresh currency UI without polling. |
Crafting Component
GearFlow provides two crafting components. UGearCraftingComponent executes recipes immediately, ingredients are consumed and outputs are delivered in the same frame. UGearTimedCraftingComponent extends it with a queued model: each craft takes CraftingTime seconds, multiple crafts can be queued up to MaxQueueSize, and progress is queryable at any time. Both components can be placed on a player character or a workbench actor, the caller supplies the source and output storage, so the component is agnostic about where items come from and go.
UGearCraftingComponent
| Property / Function | Description |
|---|---|
| AvailableRecipes | The set of recipes this component knows. Replicated to the owner only. |
| CraftingRule | Optional validation object. Subclass UGearCraftingRule and override ValidateRecipe() for skill gates, positional grids, or other conditions. |
| Craft(Recipe, SourceStorage, OutputStorage) | Validates via CanCraft, removes ingredients from SourceStorage, and delivers outputs to OutputStorage. Server only. |
| CanCraft(Recipe, SourceStorage) | Returns true if all ingredients can be satisfied without consuming anything. |
| GetAvailableRecipes() | Returns all known recipes. |
| GetCraftableRecipes(SourceStorage) | Returns the subset of known recipes that pass CanCraft. |
| AddRecipe(Recipe) | Adds a recipe at runtime, use for discovery systems. Replicated to owner. |
| RemoveRecipe(Recipe) | Removes a known recipe. Replicated to owner. |
| Delegate | Description |
|---|---|
| OnCraftingCompleted(Recipe) | Fires on the server after a successful craft. |
| OnCraftingFailed(Recipe) | Fires when CanCraft returns false. Use to communicate the specific failure reason. |
UGearTimedCraftingComponent
Drop-in replacement for UGearCraftingComponent. Adds a time-based crafting queue. The CraftingTime field on each recipe asset controls how long each craft takes.
| Property / Function | Description |
|---|---|
| MaxQueueSize | Maximum number of crafts that can be queued simultaneously. Additional StartCraft calls are rejected if the queue is full. |
| StartCraft(Recipe, SourceStorage, OutputStorage) | Validates and enqueues the craft. Ingredients are consumed immediately on enqueue. Server only. |
| CancelCraft(QueueIndex) | Removes the craft at the given queue position. Ingredients are refunded to SourceStorage if they can fit. Server only. |
| GetCraftingProgress() | Returns 0.0–1.0 progress of the currently active craft. Safe to call on client. |
| GetCraftingQueue() | Returns the current queue as an array of recipe references. Safe to call on client. |
| Delegate | Description |
|---|---|
| OnCraftingStarted(Recipe) | Fires when a queued craft begins its timer. |
| OnCraftingProgress(Recipe, Progress) | Fires periodically while a craft is in progress. Use to drive a crafting progress bar. |
| OnCraftingCancelled(Recipe) | Fires when a craft is cancelled via CancelCraft. |
| OnCraftingQueueChanged() | Fires whenever the queue is modified, enqueue, dequeue, or cancel. Use to refresh the queue UI. |
// Start a timed craft on the server
TimedCraftingComp->StartCraft(SwordRecipe, PlayerInventory, PlayerInventory);
// Bind progress for UI (safe on client after replication)
TimedCraftingComp->OnCraftingProgress.AddDynamic(this, &AMyHUD::OnCraftProgress);
// Poll progress directly if needed
float Progress = TimedCraftingComp->GetCraftingProgress(); Recipes
A UGearCraftingRecipeDataAsset declares what is consumed, what is produced, and how long it takes. Items are referenced by direct UGearItemDefinition pointer, not by tag, so renaming or moving assets never breaks recipe references. Multiple outputs allow byproduct modelling (e.g. smelting ore yields ingots and slag).
| Property | Type | Description |
|---|---|---|
| Inputs | TArray<FGearCraftingIngredient> | Required items. Each entry holds a definition reference and a required quantity. |
| Outputs | TArray<FGearCraftingOutput> | Produced items. Each entry holds a definition reference and a quantity to add. Multiple entries enable byproduct drops. |
| CraftingTime | float | Duration in seconds for UGearTimedCraftingComponent. Ignored by the instant UGearCraftingComponent. |
ValidateRecipe() to return false under any custom condition. Assign the instance to UGearCraftingComponent.CraftingRule. The rule is checked by both CanCraft and Craft. Loot Tables
UGearLootTableDataAsset is a weighted pool for procedural inventory population. Define a set of entries each with a weight and quantity range, then call UGearFunctionLibrary::PopulateFromLootTable to roll the table and add results directly to a storage component, useful for chest contents, enemy drops, and random shop stock.
| Property | Type | Description |
|---|---|---|
| Entries | TArray<FGearLootEntry> | Each entry holds: Item (UGearItemDefinition*), Weight (float), MinQuantity (int32), MaxQuantity (int32). Higher weight increases the chance of selection on each roll. |
| RollCount | int32 | Number of independent rolls performed when the table is evaluated. The same entry can be selected multiple times. |
World Pickups
AGearPickupActor is the world-space item representation. The actor class and world mesh are configured per item via UGearPickupFragment. The built-in AGearStaticMeshPickupActor loads and applies the fragment's mesh asynchronously; subclass AGearPickupActor for custom visuals or interaction. Spawn pickups via UGearFunctionLibrary::DropItem, pre-placed pickups call InitializePickup at BeginPlay.
Properties
| Property | Type | Description |
|---|---|---|
| ItemInstance | UGearItemInstance* | The item this pickup represents. Replicated so clients can display the correct icon before picking up. |
| Quantity | int32 | Units of the item this pickup contains. |
| bAutoPickup | bool | When true, automatically calls Pickup when a UGearStorageComponent overlaps the sphere. |
| PickupRadius | float | Radius of the overlap sphere used for auto-pickup detection. |
| LifetimeMode | EGearPickupLifetime | Persistent never expires. Timed destroys after LifetimeDuration seconds. ProjectDefined delegates expiry to your project code. |
| LifetimeDuration | float | Seconds before the pickup expires when LifetimeMode is Timed. |
Functions
| Function | Description |
|---|---|
| InitializePickup(Definition, Count) | Creates a new instance from the definition. Use for fresh drops with no prior instance state. |
| InitializePickupFromInstance(Instance, Count) | Uses a pre-created instance, preserves per-instance state (durability, enchantments) when dropping equipped items. |
| Pickup(Instigator) | Adds the item to the first UGearStorageComponent found on the Instigator actor. Destroys the pickup actor on success. |
| OnVisualSetup() | Blueprint-overridable event called after ItemInstance is set. Override to configure custom visuals or VFX on the pickup actor. |
Delegates
| Delegate | Parameters | Description |
|---|---|---|
| OnPickedUp | PickupActor, Instigator | Fires when the item is successfully added to the instigator's storage. Use to play pickup SFX or show a notification. |
| OnLifetimeExpired | PickupActor | Fires when the Timed lifetime elapses before pickup. Use to play a despawn effect. |
Item Transfer
UGearFunctionLibrary is the static utility layer for all cross-component item movement and world population. Every transfer pattern in GearFlow, looting a chest, buying from a vendor, dropping an item, populating a loot chest, runs through one of these functions. The unified model means OnSlotChanged delegates fire normally on both endpoints.
// Loot a chest into player inventory
UGearFunctionLibrary::TransferItem(ChestInventory, PlayerInventory, Item, Count);
// Buy from vendor (deducts Cost from wallet atomically)
UGearFunctionLibrary::TransferItem(VendorInventory, PlayerInventory, Item, 1, PlayerWallet);
// Drop item to world at a given transform
UGearFunctionLibrary::DropItem(WorldContext, PlayerInventory, Item, 1, DropTransform);
// Populate a chest from a loot table
UGearFunctionLibrary::PopulateFromLootTable(ChestInventory, LootTable); | Function | Description |
|---|---|
| TransferItem(From, To, Item, Count, Wallet) | Moves Count units from From to To. If Wallet is provided and the item carries a UGearCostFragment, deducts the cost map first, the entire transfer fails atomically if the wallet cannot cover all currencies. Server only. |
| PopulateFromLootTable(Storage, LootTable) | Rolls the loot table and adds results to Storage. Returns the number of items actually added (may be less than RollCount if the storage is nearly full). |
| DropItem(WorldContext, Storage, Item, Count, Transform) | Removes the item from Storage and spawns a pickup actor at Transform. The actor class is determined by the item's UGearPickupFragment. Returns nullptr if the item has no pickup fragment. Server only. |
| DropItemInstance(WorldContext, Storage, Instance, Transform) | Drops a specific instance, preserves per-instance state (durability, enchantments) on the spawned pickup actor. Server only. |
Save System
UGearSaveLibrary provides static capture and restore functions for all three storage components. Capture functions extract the current component state into a structured save data type that you write to your project's save game object. Restore functions rebuild the component from that saved state, including per-instance custom data via the GetInstanceSaveData / SetInstanceSaveData hooks on UGearItemInstance.
UGearSaveLibrary functions
| Function | Save data type | Description |
|---|---|---|
| CaptureInventory(Component, out SaveData) | FGearInventorySaveData | Serializes the inventory to an array of slot saves, each with slot index, item ID, count, and custom instance data. |
| RestoreInventory(Component, SaveData) | FGearInventorySaveData | Rebuilds each slot from the saved state. Calls SetInstanceSaveData on each instance before OnInstanceCreated. |
| CaptureEquipment(Component, out SaveData) | FGearEquipmentSaveData | Serializes equipped items keyed by slot tag, including custom instance data. |
| RestoreEquipment(Component, SaveData) | FGearEquipmentSaveData | Re-equips saved items into their recorded slots and restores instance data. |
| CaptureWallet(Component, out SaveData) | FGearWalletSaveData | Serializes currency tag + amount pairs. |
| RestoreWallet(Component, SaveData) | FGearWalletSaveData | Restores all currency balances from saved entries. |
// On save, in your SaveGame object population
UGearSaveLibrary::CaptureInventory(InventoryComp, MySaveGame->InventoryData);
UGearSaveLibrary::CaptureEquipment(EquipmentComp, MySaveGame->EquipmentData);
UGearSaveLibrary::CaptureWallet(WalletComp, MySaveGame->WalletData);
// On load, after the SaveGame object is read back
UGearSaveLibrary::RestoreInventory(InventoryComp, MySaveGame->InventoryData);
UGearSaveLibrary::RestoreEquipment(EquipmentComp, MySaveGame->EquipmentData);
UGearSaveLibrary::RestoreWallet(WalletComp, MySaveGame->WalletData); Debug Tools
GearFlow registers a UGearCheatExtension (a UCheatManagerExtension subclass) automatically at module startup. The cheat commands are available in any build that has the CheatManager enabled, no manual setup required.
| Command | Description |
|---|---|
| GearGive <ItemName> [Count] | Adds the named item to the local player's first UGearInventoryComponent. Count defaults to 1. |
| GearClear | Clears all items from the local player's inventory. |
| GearPrintInventory | Logs all occupied inventory slots to the output log and on-screen debug area. |
| GearGiveCurrency <Tag> <Amount> | Adds the specified amount of the given currency tag to the local player's wallet. |
UGearEquipmentFragment, or calling mutating functions from a client, produce on-screen debug messages in non-Shipping builds via the GEARFLOW_LOG_WARNING and GEARFLOW_LOG_ERROR macros. Replication
All three storage components, Inventory, Equipment, and Wallet, use FastArray replication with delta compression. Only changed slot entries are transmitted per frame; a 100-slot inventory that receives one item sends roughly 20–30 bytes, not a full snapshot. The model is server-authoritative: all mutating functions must originate on the server, client-side calls are silently ignored. The recommended pattern is: client sends a Server RPC → server validates and mutates → FastArray replicates the delta → delegates fire on client with the new state.
Delta Compression
FastArray sends only the slot entries that changed since the last ACK. Full snapshots are never retransmitted after the initial connection sync.
Server Authoritative
Inventory state lives on the server. Clients receive replicated copies. No client can forge an item grant or craft result.
Visual Replication
Equipment visual actors are spawned server-side and replicated to all clients, so every player sees the correct visuals without extra RPC code. Multi-mesh items spawn all visual actors simultaneously.
InstancedReplicated Fragments
Fragment data with the InstancedReplicated policy is replicated per instance via the storage component's FastArray, so per-item state (charges, durability) reaches clients automatically.
Delegates on Client
OnSlotChanged, OnItemEquipped, and OnCurrencyChanged all fire on the client after replication, making UI bindings straightforward with no polling.
Timed Crafting Queue
The crafting queue and progress are replicated to the owning client. OnCraftingProgress fires on the client during the craft timer, enabling live progress bar updates without additional RPCs.