Minimal Inventory Runtime Documentation

MINIMAL INVENTORY RUNTIME — DOCUMENTATION Version 2.0.0 | Unreal Engine 5.7 and 5.8 | Windows (Win64) Copyright 2026 CelestiaDominance. All Rights Reserved. Support: https://discord.gg/9Zc4wbwqG9

WHAT THE PLUGIN PROVIDES

Minimal Inventory Runtime supplies a replicated inventory component, item definitions, world pickups, containers, equipment, expiration, persistence, a built-in Slate interface, and base classes for your own UMG interface. Blueprint-callable integration functions let you connect the inventory to an existing HUD, interaction system, crafting flow, or merchant system.

The plugin contains C++ source and no Blueprint, item, mesh, icon-library, or example-map assets. You create the content and presentation appropriate to your project. The inventory framework does not supply NPC dialogue, quest authoring, recipe databases, merchant AI, a complete shop interface, or an external payment/database service.

The guides below use illustrative asset and widget names. Those examples are names to create in your project, not assets included in the plugin.

1. THE INVENTORY AND YOUR PLAYER FRAMEWORK

Add an InventoryComponent to the replicated actor that should own the inventory. A character or pawn is the most direct choice. PlayerController and PlayerState ownership are also supported by the integration helpers. Physical interactions, equipment visuals, and drops require an appropriate possessed pawn/avatar.

For client requests to reach the server, the component's owning actor must replicate and belong to that player's network ownership chain. A client generally cannot send a server RPC directly through a world container or merchant actor that it does not own. Use the player's owned inventory component as the entry point.

Useful initial component settings: - NumSlots: inventory capacity; 24 by default. Positive values create a fixed logical slot range. Nonpositive values allow growth, subject to the implementation's allocation limits. - MaxWeight: maximum weight of items in inventory slots; 0 means unlimited. Equipped items are separate and are not included in the slot-weight total. - HotbarSlotCount: the first N inventory slots form the hotbar. - bAutoCompactEnabled: fills early gaps after changes. Use SetAutoCompactSettings(false, ...) if your UI should preserve the player's exact slot arrangement. - bAutoCompactPreserveHotbarSlots: keeps compaction from moving items across the hotbar boundary. - bGrantStartupItems and StartupItems: optional server-side starting items. Do not combine unconditional starting rewards with an independently loaded saved inventory without deciding how first-time characters are identified.

Keep an explicit reference to the intended component when possible. FindInventoryOnActor resolves exactly one matching component, optionally selected by Component Tags. FindPlayerInventory checks the PlayerController, its pawn, and its PlayerState. Multiple matching inventories are deliberately treated as ambiguous.

For a custom framework or several inventories, implement InventoryProviderInterface on an actor or PlayerController and override ResolveInventory: 1. Store the inventory component reference that your framework has selected. 2. In ResolveInventory, inspect InventoryTag when you need names such as Main, Equipment, or Crafting. 3. Return the matching component. Return None when no inventory should be selected.

A provider on the PlayerController takes precedence over automatic player lookup. The returned component must be valid and in the same world. Returning None is deliberate; it does not fall back to another component. The provider may be implemented entirely in Blueprint. Do not call the same resolver recursively from its own ResolveInventory override.

Use the actual owning PlayerController or widget GetOwningPlayer. Avoid selecting player index 0 in reusable multiplayer or local-player UI code.

2. CREATING ITEM DEFINITIONS

Create a Data Asset using InventoryItemDefinition as the class. For example, create DA_Wood, DA_Coin, and DA_HealthPotion. These assets describe an item type; they are not individual stack instances.

Set a stable UniqueId for gameplay logic, plus DisplayName, Description, MaxStackSize, Weight, and an optional Icon. MaxStackSize must be positive and Weight must be finite and nonnegative. The inventory identifies quantities by item-definition reference; two separate definitions with the same display text are still different items. Keep UniqueId values unique within your own item catalog.

WorldMesh or WorldSkeletalMesh supplies the pickup/drop visual. A skeletal mesh takes precedence when configured. The definition also exposes pickup quantity, physics, impulse, equipment appearance, tooltip styling, and optional 3D hover-preview settings.

The definition is a shared Data Asset. Do not store per-player health, inventory quantity, or mutable item-instance state inside it. Put player effects on the appropriate actor or gameplay component.

For behavior implemented in Blueprint, use a Blueprint-derived item-definition class and override CanUseItem and UseItem. UseType selects None, Use, Equip, Eat, or Consume. Set bConsumeOnUse and ConsumeAmount when successful uses should remove items. The default UseItem reports success for a usable item; your game supplies effects such as healing or applying an ability.

CanUseItem and UseItem run on the server. Return false when use is disallowed or fails. QuantityToUse is the requested number of uses; available quantity and ConsumeAmount limit how many can succeed. Zero or negative requests do nothing. Do not separately remove the same consumables in your effect if the inventory is already configured to consume them.

OnItemUsed, OnItemActionSucceeded, and the corresponding ID/action events can drive feedback. Gameplay effects should execute once on authority. Owning-client notifications are suitable for local sound, animation, and UI; do not apply the same authoritative reward again there.

3. GRANTING ITEMS AND QUERYING STATE

Grant items from trusted server or standalone gameplay code. ServerGrantItems accepts an array of InventoryItemQuantity entries and returns the total amount accepted. GrantItemToInventory_ByItemDefinition and the player-controller convenience functions also report the accepted quantity. A full or overweight inventory can accept less than the requested grant.

ServerAddItem keeps its legacy name, but in version 2 it is an authority-only function, not a client-to-server RPC. It does not allow a client to request arbitrary items. If a button requests a quest reward, recipe, or purchase, send the relevant identifier to your own validated server event and grant items there.

For unconditional rewards that must fit completely, use ExchangeInventoryItems with an empty Costs array and the intended Rewards array, then check the result. It either accepts the complete reward or changes nothing.

Read helpers: - GetSlot: soft item reference and quantity for a zero-based slot index. - GetSlotUIData: display data including validity, name, description, quantity, weight, icon, and expiration. - GetItemQuantity: exact 64-bit quantity of one definition across inventory slots. - GetTotalItemCount: total slot quantity, saturated at the maximum 32-bit integer. - GetOccupiedSlotCount, GetTotalWeight, and GetSlotWeight. - GetSlotExpirationRemaining: remaining lifetime using synchronized server time when available.

Equipped items are separate from these slot quantity and weight queries. Use GetEquippedItem or EquippedItems for equipment.

OnInventoryChanged fires for local authority changes and replicated client changes. Use it to refresh presentation. Its callbacks are read-only: additional inventory mutations during a change notification are rejected. If another system needs a subsequent mutation, schedule it after the callback returns. Use one transaction when costs and rewards must form a single operation.

4. YOUR OWN UMG INVENTORY — MANAGED WINDOW

This route lets the plugin manage the inventory window while you design every part of its UMG layout.

1. Create a Widget Blueprint, for example WBP_InventoryWindow, with InventoryMainWidgetBase as its parent class. 2. Design your panels, slot widgets, item details, buttons, and optional container panel in the Designer. 3. Assign this class to InventoryComponent.InventoryUMGWidgetClass. 4. Keep bUseExternalInventoryUI false for this route. 5. From your own input action or menu button, call the Inventory UI Blueprint Library's ShowInventoryUI with the owning PlayerController, your explicit player inventory, and an optional container inventory.

ShowInventoryUI always shows or updates the managed window. OpenInventoryUI retains its earlier toggle behavior when ContainerInventory is None. CloseInventoryUI in the blueprint library explicitly closes the managed window. IsInventoryUIVisible reports its logical open state, including while a closing fade is running.

The UI manager supplies the inventory references before adding the widget to that player's screen. In your Widget Blueprint, implement these events: - On Inventories Set: receive the PlayerInventory and optional ContainerInventory and build/refresh both panels. - On Player Inventory Changed: refresh the player panel. - On Container Inventory Changed: refresh the container panel.

The base class binds and unbinds these notifications and rebinds when the widget is reconstructed. Do not add a second binding to the same inventory just to duplicate the base-class events. Existing deprecated BP_On... events remain for older projects; use the current events for new work and avoid implementing both versions for the same refresh action.

A simple slot-grid implementation: 1. Give each of your slot widgets an InventoryComponent reference and an integer SlotIndex. 2. For a fixed inventory, create slots from 0 through NumSlots - 1. A four-column grid can use Row = SlotIndex / 4 and Column = SlotIndex % 4. 3. Call GetSlotUIData for that index. A false result or bValid false means render an empty slot; do not retain the previous item's image or text. 4. For a valid slot, show DisplayName, Quantity, and the resolved Icon. Provide an empty/default visual if the icon is unset. 5. Resolve/load soft icons before displaying them. For large catalogs, cache or asynchronously load presentation assets in your own UI so rebuilding a grid does not repeatedly load them. 6. Refresh the existing slot widgets when inventory events arrive. Make the refresh safe to call more than once.

For a growing inventory, use a bounded or virtualized layout and refresh after compaction. Do not create an unlimited number of UMG widgets. A slot index is an address in the current inventory, not a permanent item-instance ID.

The main widget base exposes actions for your buttons: - UseFromPlayerSlot and DropFromPlayerSlot. - SplitFromPlayerSlotToEmpty. - TakeFromContainerSlot and MovePlayerSlotToContainer. - TransferAllFromContainerToPlayer and TransferAllFromPlayerToContainer. - RequestClose for closing the managed window.

DropFromPlayerSlot uses Quantity = -1 for the whole stack. The lower-level ServerDropFromSlot instead uses INT32_MAX for the whole stack. Use positive quantities for partial drops.

For a custom drag/drop operation, call ServerSwapSlots on the player's inventory for its own slots. For container moves, call ServerMoveItem on the player's owned inventory and supply FromInventory, FromSlot, ToInventory, ToSlot, and Quantity. One endpoint must be that player's inventory, and access to the other inventory is checked on the server. ServerSwapInInventory supports rearranging an authorized container. Transfers can be partial; use an inventory transaction for an all-or-nothing trade or recipe.

Use your project's input system to choose bindings, input mode, and focus. The managed UI captures and restores the cursor/click/mouse-over flags it changes. It does not choose your game's complete input-mode policy. InventoryCloseKeys is an optional list for the built-in Slate window and is empty by default. For a UMG window, wire your chosen close action to RequestClose or the library's CloseInventoryUI.

5. KEEPING AN EXISTING HUD OR MENU FRAMEWORK

Use this route when your current HUD already owns screen layers, opening animations, focus, navigation, and cursor state. Your existing widget does not need to inherit from the plugin's widget classes.

1. Set bUseExternalInventoryUI true on the player's inventory on the owning client; class defaults are a convenient place to configure it. This presentation setting is not automatically replicated as a runtime server change. 2. Leave bAutoShowUIOnOwningClient and bAutoCreateHotbarOnOwningClient false when your HUD owns those elements. 3. Keep an explicit reference to the player's inventory in your HUD. 4. Bind OnContainerAccessed. Its ContainerInventory parameter identifies the server-approved container. 5. In that event, bind your container panel to that component and open your existing menu layer. 6. Bind OnInventoryChanged to refresh your own player/container displays; unbind the old component when switching containers and when your widget is removed.

OnContainerAccessed is delivered to the owning client when OpenContainerInventory succeeds on the server. It can arrive before all container contents finish replicating, so also refresh on subsequent inventory changes. Opening a display is not a permanent grant of access: server movement requests recheck the access policy.

For a player-only inventory menu, open your own HUD panel directly from your input action. Read the player's inventory and send its supported action requests. The external route does not automatically control your HUD's close animation or input state; use your framework's own close operation. The UI library's IsInventoryUIVisible describes the plugin-managed window, not an arbitrary external panel.

If you manually place an InventoryMainWidgetBase inside your HUD, call SetInventories yourself. Its binding and action helpers remain useful, but its RequestClose helper addresses the plugin-managed window. Wire your own close button to your HUD's close function.

6. CUSTOM HOTBAR

Create a Widget Blueprint derived from InventoryHotbarWidgetBase and assign HotbarUMGWidgetClass. Configure HotbarSlotCount, and either use bAutoCreateHotbarOnOwningClient or call EnsureHotbarUI with the correct PlayerController and inventory.

Handle On Inventory Set for initial population and On Inventory Changed for refreshes. Query slots 0 through HotbarSlotCount - 1. The base class provides use, drop, and split helpers. Bind number keys, gamepad actions, or touch buttons through your own input system; the plugin does not require a particular key mapping.

Your existing HUD can instead render the hotbar directly from the same component and own its lifecycle. Managed UMG widgets and hotbar overlays are associated with the supplied local player. The built-in world look-prompt implementation is not a complete split-screen prompt solution; use your own per-player prompts for that workflow.

7. CONNECTING A DIFFERENT INTERACTION SYSTEM

You can keep a generic interaction system for items, containers, NPCs, dialogue, and quests. Minimal Inventory Runtime does not need to own all those interactions.

On the inventory, call SetBuiltInInteractionEnabled(false) when another system owns target tracing and prompts. This disables the built-in trace/prompt flow while retaining the explicit entry points. Route each input interaction through one selected system to avoid processing the same action twice.

Client-driven focus route: 1. Let your existing system identify the currently focused actor on that client. 2. For an inventory target, call InteractWithActor(Target) on the player's owned InventoryComponent. 3. The component sends the request to the server, validates the target, and invokes the inventory interaction. 4. Keep non-inventory targets on your existing dialogue, quest, or other interaction path.

The target must implement InventoryInteractableInterface. InventoryPickupActor and InventoryContainerActor already do. A custom interactable implements Interact and uses the supplied interactor to resolve the intended inventory. For multiple inventories, use an explicit provider or the direct functions below.

The default CanInteractWithActor policy requires a valid avatar and target in the same world, a positive finite InteractionTraceDistance, range to the target's bounds, and visibility through the Visibility collision channel. The distance defaults to 350 Unreal units. A Blueprint-derived InventoryComponent can override this policy for your game's collision channels and permissions. This override runs on the server; it must independently validate the request.

Already-validated server interaction route: - For an InventoryPickupActor, call PickupIntoInventory(TargetInventory). It returns the quantity actually accepted. A partial pickup preserves the remainder in the world. - For an InventoryContainerActor, call OpenForInventory(PlayerInventory). It returns whether the container was opened through the inventory access policy. - For another custom storage actor, call PlayerInventory.OpenContainerInventory(TargetInventory) after defining an appropriate CanAccessInventory policy.

PickupIntoInventory is an authority-only entry for a server interaction that your system has already approved. Do not expose it through an unrestricted RPC that accepts an arbitrary inventory, item, or actor from the client. InteractWithActor is the convenient route when the inventory should perform its own range and visibility validation.

CanAccessInventory is evaluated for remote move, swap, and transfer operations. Its default allows the player's own inventory and nearby built-in containers with bAllowPlayerAccess true. A custom storage actor must be explicitly authorized by your override. Include the relevant ownership, lock, team, session, or distance rules. Simply displaying another inventory does not allow taking from it.

Nice Interaction System V2 and similar systems: connect their confirmed interaction callback to one of these two routes according to whether that callback runs locally or has already been validated on the server. Keep that system's own target interface/component requirements. No dependency on Nice Interaction System V2 is included. Exact callback names depend on its version and your project; the actual third-party package has not been used to certify a turnkey integration.

C++ interface calls must use Unreal's generated dispatcher when invoking an interface event:

IInventoryInteractableInterface::Execute_Interact(TargetActor, Interactor); IInventoryProviderInterface::Execute_ResolveInventory(ProviderActor, NAME_None);

Calling the interface event directly can assert in Unreal. Functions declared directly on PickupActor or ContainerActor, such as PickupIntoInventory and OpenForInventory, are called normally.

8. CRAFTING AND MERCHANT TRANSACTIONS

InventoryTransactionLibrary provides atomic changes to inventory contents. Build costs and rewards from server-owned recipe/product data. Execute the transaction on the server and check EInventoryTransactionResult. It is not a network RPC and does not supply your menu, catalog, recipes, merchant behavior, or purchase authorization.

One-inventory crafting example: 1. Your crafting button sends a RecipeId to your own server event on a player-owned actor/component. 2. The server resolves that RecipeId from an allowed recipe table and checks the player's crafting permissions. 3. Build Costs: DA_Wood x3 and DA_Stone x2. 4. Build Rewards: DA_Axe x1. 5. Call ExchangeInventoryItems(PlayerInventory, Costs, Rewards). 6. On Success, the recipe is committed. Otherwise, no ingredients are consumed and no output is added.

Costs are removed from the staged candidate first, so the reward can occupy space freed by its ingredients. Equipped items are not consumed as recipe ingredients.

Infinite-stock purchase example: Represent currency as a DA_Coin inventory item. The server validates ProductId, looks up a price of 3 coins, and calls ExchangeInventoryItems with Costs = DA_Coin x3 and Rewards = DA_HealthPotion x1. No merchant stock inventory is needed. Selling an item can use the reverse costs/rewards, with the sell price chosen by the server.

Finite-stock merchant example: Create two InventoryTransactionChange entries and pass both to ExecuteInventoryTransaction: - Player entry: Inventory = PlayerInventory; RemoveItems = Coin x3; AddItems = Potion x1. - Merchant entry: Inventory = MerchantInventory; RemoveItems = Potion x1; AddItems = Coin x3.

Both sides are validated before either side changes. If the player lacks coins, the merchant lacks stock, or either resulting inventory exceeds space/weight limits, neither side changes. All live inventory contents are committed before inventory-change observers are notified. The merchant can also have limited room for purchased goods or accumulated currency; configure that inventory intentionally.

C++ equivalent, called from an already-authorized server purchase handler:

#include "InventoryTransactionLibrary.h" #include "InventoryComponent.h" #include "InventoryItemDefinition.h"

FInventoryItemQuantity Cost; Cost.Item = CoinDefinition; Cost.Quantity = 3; FInventoryItemQuantity Product; Product.Item = PotionDefinition; Product.Quantity = 1;

FInventoryTransactionChange Buyer; Buyer.Inventory = PlayerInventory; Buyer.RemoveItems = {Cost}; Buyer.AddItems = {Product}; FInventoryTransactionChange Seller; Seller.Inventory = MerchantInventory; Seller.RemoveItems = {Product}; Seller.AddItems = {Cost};

const EInventoryTransactionResult Result = UInventoryTransactionLibrary::ExecuteInventoryTransaction({Buyer, Seller});

Here, the two component references and the two definition references are variables obtained from your server-owned gameplay state. Add MinimalInventoryRuntime to your module's dependencies when using its C++ APIs.

CanExecuteInventoryTransaction provides a read-only preview, including on the client. Use it to explain a disabled button or likely failure. Always execute and revalidate on the server; contents may change between preview and execution.

Transaction results: - Success: the operation succeeded, or the preview currently fits. - InvalidRequest: invalid references/worlds, invalid quantities/configuration, duplicate inventory entries, or an empty request. - NotAuthority: execution attempted on a non-authority inventory. - InventoryBusy: execution attempted during a guarded update or change notification. - MissingItemDefinition: a required definition could not be loaded. - InsufficientItems: at least one complete cost is unavailable. - InsufficientSpace: the complete result does not fit a fixed inventory. - WeightLimitExceeded: the result exceeds the allowed weight. - LimitExceeded: a request exceeds supported processing/allocation limits.

Repeated entries for the same item within a cost or reward list are aggregated. Put each inventory into the Changes array only once. Use strictly positive quantities; an empty Costs or Rewards array is allowed, but an inventory entry cannot have both arrays empty. All inventories must be in the same authority world for execution.

Limits are 64 inventories per transaction, 4,096 entries per cost/reward list, up to 65,536 staged slot records per inventory, and at most INT32_MAX aggregated units per item in a cost/reward list. These are defensive upper limits, not recommended UI sizes. Inventory definition loading is synchronous; keep frequently used definitions available and avoid sending huge transactions during a frame.

The transaction only covers these inventory components. A separate wallet variable, bank balance, database write, or external economy service is not part of the atomic commit. Represent currency as an inventory item when you want the built-in atomic purchase behavior, or coordinate your external economy through your own server transaction system.

9. EQUIPMENT, DROPS, AND EXPIRATION

For equipment, set the definition's UseType to Equip and choose an EquipmentSlot name such as Head or Weapon. The inventory's AllowedEquipmentSlots can restrict valid names. EquipFromSlot and UnequipSlot route client requests to the server; the immediate client-side return is not an authoritative completion result. Observe replicated equipment and equipment-change events for the final state.

Configure EquipAttachSocketName, EquipRelativeTransform, and EquipVisualMode on the definition. EquipmentAttachComponentTag on the inventory can select the exact avatar component that receives the visual. A missing or duplicate explicit tag does not silently fall back to another mesh. Without a tag, a character's mesh is preferred; generic actors require an unambiguous suitable component or root.

Replacing equipped gear returns the old item to the inventory when the resulting inventory has space. A full inventory can replace gear if removing the new item frees the needed slot. Unequipping requires available inventory capacity. Equipped expiration is preserved while equipping, replacing, unequipping, and saving.

ServerDropFromSlot, ServerDropAll, and the UI helpers create configured pickup actors or a dropped container/bag. DropVisualMode selects the item visual or an override container. Supply your own meshes/classes and configure bag capacity, physics, and optional despawn duration. Dropped bags with a despawn timer can destroy their remaining contents when they expire.

For a manually spawned pickup, set Item, quantity overrides, physics options, and expiration before finishing a deferred C++ spawn, or use the exposed spawn properties in Blueprint. If you change its definition afterward, call RefreshFromItemDefinition. The definition's pickup defaults can override actor values unless their corresponding override flags are enabled.

Set bExpires, ExpireSeconds, and ExpireAction on a definition. Expiration uses authority time. Items can be removed or transformed according to their definition; transformed outputs remain subject to inventory capacity. Choose output quantities and space rules so your game does not rely on overflow being preserved. Merging expiring stacks uses the earlier expiration rather than resetting older items to a fresh lifetime.

10. SAVE/LOAD AND YOUR EXISTING SAVE SYSTEM

Standalone convenience route: Set InventorySaveSlotName, InventorySaveUserIndex, and a stable InventorySaveKey. Use AutoSaveNow/AutoLoadNow, or enable the component's automatic save/load options. The standalone route uses SaveGame slots directly. If multiple inventories share a slot file, give them distinct stable keys.

The default autosave debounce is 0.25 seconds. Call AutoSaveNow at a controlled checkpoint or shutdown stage if your game must not rely on a pending timer. Treat a false return as a save/load failure and handle it in your game.

Existing save-system route: Call MakeSaveData on authority and store the returned InventorySaveData inside your own save record. On load, resolve the intended component and call ApplySaveData. The complete payload is validated before live inventory/equipment is replaced. Invalid item references, duplicate slot indices, invalid quantities, unsupported save versions, or a result that violates capacity/weight rules are rejected without clearing the live inventory.

ApplySaveData with bClearExisting false overlays saved entries by slot index and equipment slot name, then validates the combined state. It is not a free-space item grant or an additive reward function. Use a transaction for adding rewards to existing contents.

Version 2.0.0 writes inventory payload schema version 3 and reads schemas 1–3. Schema 3 stores equipped-item remaining lifetime. Earlier equipment records did not contain that value, so legacy equipped items use their definition's configured lifetime when restored. Saved lifetime is remaining game time; this does not implement real-time offline expiration. Supply an explicit offline-time policy in your own save system if needed.

Networked persistence route: 1. On the server, obtain InventoryPersistenceSubsystem from the GameInstance. 2. Use GetProviderObject to obtain the active provider. The default is InventorySaveGamePersistenceProvider. 3. After your authentication/character selection resolves a trusted stable account or character ID, call SetPersistentPlayerId(PlayerState, PersistentId) on that provider. 4. Enable bAutoSaveLoadInNetworkedGames for the inventories that use this flow. 5. Set stable InventorySaveKey values and explicitly call AutoLoadNow after identity and inventory ownership are ready. 6. Save through AutoSaveNow or your chosen autosave/checkpoint policy.

The persistent player ID must be nonblank, at most 256 characters, and stable across reconnects. Active duplicate IDs are rejected by SetPersistentPlayerId. Do not use a client-supplied identity without server authentication. Display names and session PlayerId values are not stable account identifiers.

You can derive a provider Blueprint from InventorySaveGamePersistenceProvider and override GetPlayerIdString, or implement InventoryPersistenceProvider on your own provider object and assign it with SetProviderObject. Implement SaveInventoryForPlayer, LoadInventoryForPlayer, and DeleteInventoryForPlayer. Keep a valid provider object owned by your game/subsystem and maintain any additional authorization and storage guarantees required by your backend.

C++ callers invoke persistence interface events with Execute_SaveInventoryForPlayer, Execute_LoadInventoryForPlayer, and Execute_DeleteInventoryForPlayer, passing the provider UObject as the first argument. A Blueprint-only implementation does not necessarily have a native C++ interface pointer; GetProviderObject plus the Execute dispatcher supports it.

The built-in SaveGame provider is a local server-file implementation. It does not supply database replication, multi-server locking, cloud synchronization, or a complete account system.

11. ITEM REGISTRIES AND COOKING YOUR CONTENT

InventoryItemRegistry maps your chosen keys to item-definition references. Registry-key grant helpers let an existing quest/reward system work with a small stable catalog. Direct definition references are also supported.

PrimaryAssetId-string grant helpers require actual primary-asset registration in your project's Asset Manager. InventoryItemDefinition derives from UDataAsset; assigning UniqueId does not automatically register a Primary Asset or generate a PrimaryAssetId. Use explicit definition references or the registry when you do not have a primary-asset strategy. A PrimaryAssetId helper can return an empty/invalid ID when registration is missing.

Ensure item definitions, meshes, icons, widget classes, sounds, and indirect recipe/shop references are included in your project's cook. Use the project's Asset Manager/cook rules or explicit referenced content as appropriate. A soft path created only from a string at runtime does not by itself guarantee that the asset is packaged. Test a packaged game with representative item definitions; an editor-only test can hide missing cooked content.

12. UPGRADING FROM 1.0.0

- Move client-side ServerAddItem grants to trusted server gameplay handlers. The node name remains, but it is no longer a remote arbitrary-item grant. - For the default multiplayer SaveGame provider, assign a stable persistent player ID before loading. bAllowLegacySessionPlayerIds is an explicit compatibility option for older prototype saves; it is false by default. Old session/name keys do not become stable reconnect identities automatically. Migrate those saved keys deliberately if they contain data you need to preserve. - Custom storage actors must be allowed by CanAccessInventory for remote moves/transfers. The default permits nearby accessible built-in containers, not arbitrary actor inventories. - Wire your own close action or configure InventoryCloseKeys for the Slate window. The default close-key list is empty. - Keep OnInventoryChanged handlers read-only. Queue a later mutation or combine related costs/rewards in one transaction. - Resolve multiple inventories explicitly through a component tag or InventoryProviderInterface. - Recompile project Blueprints after upgrading and review any intentionally retained deprecated UI nodes. Current widget events and UI-library Show/Close functions are preferred for new graphs.

13. TROUBLESHOOTING

My inventory lookup returns None: Check the actual component owner, possession state, tags, and provider result. A controller, pawn, or PlayerState containing several matching components is ambiguous. An explicit provider returning None is respected.

My custom UI is empty: Check that the intended InventoryMainWidgetBase subclass is assigned for the managed route, or that your HUD has a valid component reference for the external route. Read the actual slot indices, handle empty GetSlotUIData results, and refresh after replication. Do not rely solely on Event Construct to populate a reusable widget.

My UI opens but stops updating after reopening: Use the current base class lifecycle and events, or rebind/unbind notifications in your own HUD. Do not keep a reference to a destroyed pawn's old inventory after respawn; resolve and assign the replacement component.

I cannot move items from a custom chest: Call the request through the player's owned inventory. Check server range, visibility, locks, bAllowPlayerAccess, and CanAccessInventory. A custom actor type needs an explicit access policy. Moving the cursor over a UI slot does not bypass those rules.

My interaction fires twice: Disable built-in interaction when your external system owns it, and route one input event through one interaction path.

My crafting or purchase removes nothing: Read the transaction result. Confirm server authority, positive quantities, valid cooked definitions, complete ingredients/currency, stock, capacity, weight, and server purchase/recipe validation. An all-or-nothing failure intentionally leaves the inventory unchanged.

My save does not load after reconnecting: Verify stable persistent identity assignment before loading, a stable InventorySaveKey, server persistence opt-in, and the same provider storage configuration. A changed display name or session PlayerId must not change the saved character's identity.

It works in the editor but not in the packaged game: Check cooked item/UI/visual assets, server ownership of RPC calls, current plugin binaries for the engine version, and the packaged-game log. Test with the same save IDs and permissions used in your actual game.

SUPPORT

When reporting a problem, include your Unreal Engine version, plugin version, whether the issue occurs in standalone/listen-server/remote-client play, the inventory's owner actor type, relevant integration settings, and a short reproduction. For third-party interaction issues, include that system's version and whether the connected callback executes on the client or server.