XForge - Inventory X – Agnostic UI

The first complete C++ backend-first inventory plugin for Unreal Engine 5.1-5.7 on the marketplace. Grid layouts, equip slots, nested containers, complete multiplayer support with client prediction and server reconciliation — and a built-in cross-inventory system for player-to-chest interactions. No UI forced on you. Bring your own.

Discord | Documentation & Tutorial | Youtube

The Explainer - Interactive Documentation and Tutorials, chat directly with the codebase (link with Order verification)

What's included

Backend-first, UI-agnostic

Pure C++ runtime. No widget dependencies in the core. Build any UI on top using the fully exposed Blueprint API.

Grid, slot & nested containers

N×M items, 90° rotation, equip slots, and nested containers — bags inside bags inside bags.

Server authoritative + prediction

Full client prediction with a 7-phase reconciliation protocol, handle remap table and cascading invalidation.

Tag-driven rules

Acceptance, denial, equip compatibility, stacking and access policies — all driven by GameplayTags and data assets. No hardcoded game logic.

Cross-inventory sessions

Open a trusted server-authoritative session between two inventories. Multi-viewer, single-writer lock. Atomic commits across two components.

Sample UI included

Two complete sample modules — single inventory and dual-panel cross-inventory — built exclusively on the public API.

Two layers, one plugin

All current and future layers are separate modules and can be removed if the feature they provide isn’t needed for your project.

Layer 1 — Core

  • UInventoryComponent with flat registries

  • Grid layout engine (N×M, rotation, first-fit)

  • Rules engine with GameplayTag queries

  • 9 operations: add, remove, move, swap, split, merge, rotate, equip, unequip

  • Atomic batch operations

  • Delta replication via FFastArraySerializer

  • Client prediction & reconciliation

  • Full Blueprint public API

  • 39+ automation tests

Layer 2 — Cross-Inventory

  • Trusted interaction sessions (Open / Suspended / Closed)

  • Multi-view / single-writer lock model

  • Policy-driven security evaluator

  • TransferItem, SplitStack, MergeStack, SwapItems across components, Equip and Unequip

  • Rollback journal for atomic cross-component commits

  • Session prediction with dual RevisionBarrier

  • Scoped handle remap for item & container handles

  • SessionEpoch invalidation on lock change

  • Automation suite

Layer 3 — Crafting System

  • Not yet, it’s being planned.

Architecture at a glance

Definitions layer

Reusable data assets for item definitions, container layouts, stack rules, equip rules and cosmetics. Hard references for gameplay rules, soft references for cosmetics so dedicated servers stay lean.

Runtime state

Flat registries of container, item and fragment records. Typed handles with generation counters. No per-item UObject allocations. Instance fragments for durability, ammo, condition and any custom state you add.

Operation engine

Every mutation follows Validate → Simulate → Commit → Notify. Batches are all-or-nothing. Validation runs against pre-batch state, not cumulative intermediate state.

Networking

Owner-only OwnerTags, delta replication with explicit MarkArrayDirty / MarkItemDirty contracts, initial authoritative state flag, listen server host through the same logical pipeline as remote clients.

Cross-inventory

Session registry in a WorldSubsystem. UInventoryInteractionComponent on the PlayerController as the sole RPC entry point. Server always builds the authority context from the connection, never trusts client-declared identity.

Designed for real projects

Dedicated server safe

Cosmetic assets are soft-referenced and never loaded by the runtime core.

Extend without forking

Fragment system, open tag rules and data-asset pipeline let you add game-specific logic without touching the core.

Save/load ready

Stable handles, flat registries and FInventoryDefinitionId are designed to make persistence a natural addition.

No framework lock-in

No GAS, no CommonUI, no external dependencies beyond GameplayTags and NetCore.

1 Like

:package: Inventory_X Update! — v1.1

Major Architecture Update

A ground-up refresh of the fragment data model, replication boundary, and client prediction system. Focused on performance and stronger anti-cheat guarantees.

:bullseye: Highlights

:building_construction: New fragment data model

single source of truth (FragmentEntries asset-or-inline)

:high_voltage: Runtime vs Static fragment lifecycle

new introduced static fragments now live on the definition only, eliminating per-item replication for read-only data and reducing network bandwidth on heavy inventories.

:shield: Hardened anti-cheat boundary

Closed an item-duplication attack vector.

:video_game: Handle-preserving rollback

chained predicted operations no longer drop dependent ops during reconcile. Fixes a long-standing prediction edge case in cross-inventory transfers.

:test_tube: +22 new automation tests across registry, prediction, rollback journal, and Layer2 transfer paths.

:package: Cleaner public API

explicit GetRuntime*, GetStatic*, GetEffective* family. Old generalist API removed.

Changelog (UE 5.1 - 5.7)

:package: Data Model

New

- FInventoryItemFragmentEntry — a single entry that is either an asset reference (reusable fragment definition) or inline data (one-off, completely defined in the item).

- EInventoryFragmentLifecycle enum on every fragment, with two values:
    - RuntimePerItem — creates a per-item record, replicates, participates in snapshots/merge     (legacy default behavior).
    - StaticDefinition — definition-side only, never replicated, never per-item — perfect for     read-only data shared across all instances of an item type.

- UInventoryItemFragmentDefinition extended with Lifecycle (defaults to RuntimePerItem for backward-compatible behavior).

Removed

- TArray<TObjectPtr<UInventoryItemFragmentDefinition>> FragmentDefinitions on UInventoryItemDefinition.

Why it matters
Static fragments (e.g., ammo type, weapon category, item rarity) no longer pay replication cost or per-item allocation cost. Runtime fragments (e.g., durability, current ammo, condition) keep their existing per-item replicated semantics.

:electric_plug: API

Old names have been removed in favor of explicit Runtime/Static/Effective families:

- GetItemFragments -> GetRuntimeItemFragments, GetStaticItemFragments, GetEffectiveItemFragments

- GetFragmentByTag -> GetRuntimeFragmentByTag, GetStaticFragmentByTag, GetEffectiveFragmentByTag

- HasFragment -Z HasRuntimeFragment, HasStaticFragment, HasEffectiveFragment

- TryGetDurabilityFragment -> TryGetRuntimeDurabilityFragment, TryGetStaticDurabilityFragment, TryGetEffectiveDurabilityFragment

- TryGetAmmoFragment -> Same Runtime/Static/Effective split

- TryGetConditionFragment -> Same Runtime/Static/Effective split

- GetFragmentsForItem -> GetRuntimeFragmentHandlesForItem

- Internal_CreateFragment -> Internal_CreateRuntimeFragment


New view types

- FInventoryStaticFragmentView — static fragment data, no handle (handles are runtime-only).

- FInventoryEffectiveFragmentView — unified view with Source = RuntimeRecord | StaticDefinition discriminator and a bIsMutableRuntime flag.

FInventoryFragmentHandle remains valid only for runtime fragments. No fake handles are ever generated for static fragments.

:counterclockwise_arrows_button: Replication, Snapshot, Drop/Pickup

- Trusted snapshot (ExportItemSubtreeSnapshot/ImportItemSubtreeTrusted) carries only runtime fragments. Static fragment data is derived server-side and client-side from DefinitionId.

- Drop actor PickupableItemComponent replicates only PresentationFragments (runtime-only). UI consumers should query GetEffective* to render full per-item state including static contributions.

- Layer2 cross-inventory bridge snapshots are runtime-only; static data is resolved per-endpoint from the resolved definition.

- Snapshot import now rejects any fragment payload whose FragmentTypeTag does not correspond to a RuntimePerItem spec on the resolved definition (defense against client-crafted snapshots).

:balance_scale: Stack Rules & Validation

- InventoryStackValidator::ValidateMerge (Layer1) and InventoryInteractionStackValidator::ValidateMerge (Layer2) compare only runtime fragments when bRequireMatchingFragmentsForMerge is true.

- Two stacks of the same definition with only static fragments always merge cleanly — static fragments are equal by construction.

- Layer2 merge no longer requires both endpoints to resolve the definition: as long as one endpoint resolves and DefinitionId matches, the merge proceeds. Fixes spurious rejections under asset streaming / hot-reload scenarios.

:shield: Security & Anti-Cheat

- AddItem and RemoveItem are strictly server-authoritative. The validation gate enforces bServerInitiated == true, and Server_SubmitOperation_Implementation deliberately does not propagate that flag from client RPCs. Client autonomous proxies cannot directly create or destroy items via RPC.

- Closed an item-duplication attack vector. A bypass flag introduced during an early version was identified as a regression and removed. The flag had allowed client-side validation to accept arbitrary AddItem predictions; it has been fully eliminated, and explicit anti-pattern documentation has been added to the architecture guide.

- New security tests confirm that RequestOperation(AddItem) and RequestOperation(RemoveItem) from ROLE_AutonomousProxy:
    - return Rejected immediately at local validation;
    - never enqueue a pending prediction;
    - never emit a Server_SubmitOperation RPC.

:video_game: Client Prediction

Predicted operations now:

- create only runtime fragment records (static specs do not allocate);
- rollback removes only the runtime records they created (handle-preserving);
- replay correctly preserves source item identity through chained operation reconciliation.


Handle-Preserving Rollback (new in this version)

A subtle bug in Layer2 chained predictions has been fixed. Previously, when a client predicted two transfers in a fast sequence (e.g., move backpack to other inventory, then move weapon into backpack's child container), the authoritative reconciliation of the first operation would re-import the destroyed source items with new handles, breaking the second operation's source resolution and silently invalidating it.


The fix:

- New CreateRecordWithExistingHandle registry primitive that re-uses original handle + generation across destroy/restore cycles.

- Trusted seam variants (ImportItemSubtreePredictedPreservingHandles, ImportItemSubtreeTrustedPreservingHandles) that preserve identity through rollback.

- Symmetric application to both predicted rollback and trusted (server-side transaction failure) rollback for architectural consistency.

- Atomic prevalidation prevents partial registry mutations.


Idempotency Hardening

The rollback idempotency check has been upgraded from a presence-only check to a full tri-state structural verification:

- NotPresent -> proceed with handle-preserving import.
- PresentEquivalent -> idempotent skip (handles + structure match snapshot exactly).
- PresentMismatch -> fail loudly with audit log instead of silent success.

Conservative fallback for runtime fragments: if any item in the snapshot carries fragment data, the idempotency shortcut is bypassed

:high_voltage: Performance

- Definition-side fragment cache is array-first: contiguous TArray<FInventoryResolvedFragmentSpec> with linear-scan helpers. No TMap for tag lookup — small fragment counts make linear scan cache-friendlier than hash maps with allocations and pointer chasing.

- Cache prepared in PostLoad and PostEditChangeProperty, not re-resolved on every query.

- Repeated GetEffectiveFragmentSpecs() calls return stable storage (verified by automation test) — zero re-resolution cost on hot paths like tooltip rendering.

- Static-heavy inventories (e.g., shops, world containers with read-only items) see significantly reduced FragmentFastArray size on both server and client.

- Network bandwidth reduction: items with only StaticDefinition fragments replicate zero fragment records.

:test_tube: Test Coverage

Significant suite expansion:

- +11 prediction tests covering Move/Split/Merge/Equip rollback, runtime fragment preservation, and security boundaries.

- +9 rollback journal tests including all 4 structural drift detection cases (Quantity, Placement, ParentContainer, ChildContainerLink), runtime fragment fallback, and idempotency happy path.

- +6 trusted seam tests for handle-preserving import/export.

- +3 registry tests for CreateRecordWithExistingHandle (revive after release, duplicate id rejection, generation preservation).

- Reconciliation suite cleaned: removed orphan tests and updated old tests

Final test status: 117/117 broad Layer2 tests + 9/9 rollback journal + 4/4 handle preserve regression — all green

:bug: Bug Fixes

- Chained Layer2 predictions silently invalidated — fixed via handle-preserving rollback re-import.

- Idempotent rollback could mask state corruption — replaced presence-only check with structural verification + audit logging.

- Partial subtree presence treated as success — now correctly classified as PresentMismatch and fails with explicit log.

- Layer2 merge spurious rejection under asset streaming — fallback resolution path uses whichever endpoint resolves the definition (both items must already share DefinitionId).

:wrench: Internal Improvements

- Internal_CreateFragment renamed to Internal_CreateRuntimeFragment for consistency with the runtime-only contract.

- LookupCache.ItemToFragments is documented and enforced as runtime-only.

- New FInventoryResolvedFragmentSpec cache type unifies runtime, static, and effective spec views on the definition.

- Editor UX: when BaseFragmentAsset is set, inline fields are hidden via EditCondition/EditConditionHides to make the asset-or-inline contract visually unambiguous.

- PostEditChangeProperty clears inline fields when an asset is assigned to prevent zombie data.

:package: Inventory_X Update! — v1.2

Fragment Mutation Pipeline – changelog


A new server-authoritative pipeline for mutating runtime fragment data, with client-side prediction, zero-allocation hot paths on modern UE versions, and an extensible mutation verb system.
Built around a clean public API and validated under 100-player, high-frequency mutation scenarios. This is an additive update: no breaking changes, no asset migration required.


:bullseye: Highlights

  • :high_voltage: Production-grade mutation pipeline — server-side validation, client prediction with rollback, compact prediction snapshots, no heap allocations on the hot path in supported engine versions.
  • :puzzle_piece: Extensible mutation verbs — register custom semantic verbs and payloads from Project Settings, without modifying the plugin core or recompiling the engine.
  • :shield: Anti-cheat focused — generic “replace” calls from clients are deny-by-default, and semantic verbs are gated by server-side policies with payload size limits.
  • :globe_with_meridians: Scale-tested — stress-tested with 100 autonomous-proxy clients × 10 mutations/sec each, p95 server overhead 0.641 ms , owner-only replication topology.
  • :test_tube: +200 automation tests across prediction, rollback, anti-cheat negative paths, serialization, Blueprint nodes, and editor tooling.


:package: Inventory_X — 1.2 Changelog (UE 5.3 – 5.7)

Fragment Mutation Pipeline – Announcement


:building_construction: The Fragment Mutation Pipeline

The core of this release: a single, coherent path to mutate runtime fragment data — built-in or custom — with prediction, replication, and policy enforcement, all through a public API on UInventoryComponent.

New capabilities on UInventoryComponent (high level):

  • Generic semantic mutation entry point driven by registered verbs.
  • Controlled “replace” APIs for fragment data by tag or handle.
  • Built-in helpers for common ammo/durability/condition flows, ready to use in gameplay code and Blueprints.

Three prediction modes:

  • Auto — lets the policy decide when prediction is safe, otherwise falls back to server roundtrip.
  • NoPredict — purely authoritative, no client-side prediction.
  • ServerOnly — callable from server only; client calls are rejected.

Support for optimistic concurrency and revision-based acks to avoid confirming predicted operations against stale state.


:puzzle_piece: Extensible Verb Registry

Project Settings now expose a registry where you can define your own mutation verbs.

  • Each verb binds a gameplay tag and a payload struct (C++ or Blueprint).
  • Per-verb bandwidth caps and client-origin flags are configurable in editor.
  • Built-in verbs (ammo, durability, condition) are registered through the same mechanism, so your custom verbs behave like first-class citizens.

The wire format is compact and schema-backed, but all of that is handled internally; you only work with tags and strongly-typed payloads.


:electric_plug: Public API

New public functions on UInventoryComponent exposed to both C++ and Blueprint:

  • A generic semantic mutation function driven by verbs.
  • Controlled “replace” functions for fragment data.
  • A small set of built-in helpers for ammo, durability, and condition flows.

New supporting types include request/response structs, a compact prediction snapshot, and a richer fragment change view for events, all Blueprint-accessible.


:shield: Anti-Cheat & Security

The mutation pipeline is server-authoritative end-to-end: there are no client write paths that bypass policy validation.

  • Generic “replace” calls from clients are rejected unless explicitly allowed by policy.
  • Semantic verbs are validated server-side against current state before any mutation is committed.
  • Payloads are bound by size limits and validated before allocation to close bandwidth-flood vectors.
  • Revision checks prevent confirming predictions against outdated baselines.

Example: a cheater trying to force abnormal ammo changes is blocked either by policy or by the generic gate, not by client-side conventions.


:video_game: Client Prediction

Predictable through the new pipeline:

  • All semantic verbs whose policy explicitly marks them as safe to predict.
  • Built-in helpers (fire/reload/durability/condition) can be predicted locally and reconciled on the server response.

The prediction layer uses compact snapshots to capture pre-mutation state and roll back on reject, with zero allocations on the hot path when using compatible payload layouts.
Blueprint helpers are available to pack/unpack lightweight snapshot data for custom fragment types.


:high_voltage: Performance

  • Fragment record replication uses a native serialization path backed by a schema, replacing the previous reflection-based approach for better performance.
  • Inline payload storage is used for common payload sizes, avoiding heap allocations on hot paths; dynamic or large payloads fall back to a general path suitable for non-hot usage.
  • The pipeline has been profiled under 100-player, high-frequency mutation scenarios and kept well within acceptable frame budgets.

:dna: Custom Fragment Authoring

Blueprint-only:

  • Define your fragment as a User Defined Struct.
  • Register it in Project Settings with the corresponding fragment tag and policy.
  • The full pipeline (prediction, replication, events, K2 nodes) is available out of the box.

C++:

  • Define a USTRUCT fragment data type and register it in the same settings panel.
  • Suitable layouts automatically benefit from the zero-allocation hot path.

Editor validation catches mismatches between tags and structs and offers tools to realign assets when you change mappings.


:balance_scale: Policy Framework

All mutation business logic lives in UInventoryFragmentMutationPolicy subclasses.

  • C++ subclasses for maximum performance.
  • Blueprint subclasses with K2 hooks for validation, mutation, and post-commit logic.
  • A data-driven mode for simple rules (numbers, tags, booleans, vectors) without any code.

Policies are resolved via a global registry optimized for small and large projects and rebuilt only when settings change or modules reload, not per component.


:hammer_and_wrench: Editor Module & K2 Nodes

New Inventory_XEditor module with typed K2 nodes to remove manual struct handling from Blueprint graphs:

  • Get Runtime Fragment Data
  • Modify Runtime Fragment Data
  • Apply Runtime Fragment Mutation

Discovery caches update automatically on asset rename/hot reload, and there is an asset factory for UInventoryItemFragmentDefinition to streamline authoring.


:satellite_antenna: Event System

New typed delegate for fragment changes, exposing handles, owning item, fragment tag, change type, and whether the change is predicted or authoritative.

  • The legacy event remains available and unchanged.
  • Predicted vs authoritative events are clearly distinguishable, and a specific change type is used when predictions are reverted.
  • The revert event fires only on terminal reject/timeout/invalidation — not on intermediate rebases, so your UI won’t get spurious events.

:bullseye: Sample Weapon

Example weapon in the Inventory_XSample module:

  • C++ base class plus a Blueprint child for designers.
  • Fire/Reload use the new mutation helpers with prediction.
  • A HUD widget binds to the new fragment change event for responsive UI updates.
  • No direct client-side writes to runtime ammo data; all networking paths are validated under SP, listen server, and dedicated server.

:test_tube: Test Coverage

+200 automation tests covering:

  • Primitive serialization and payload bounds.
  • Policy resolution and validation phases.
  • Public API behaviors and prediction modes.
  • Custom authoring flows, Blueprint nodes, events, and sample weapon scenarios.
  • Zero-allocation hot paths and multi-client scale scenarios.

You can run the full suite via the Automation framework to verify integration in your environment.


:warning: Known Limits

  • Data-driven policies target numeric/tag/bool/vector fields; complex or dynamic data still require C++ or Blueprint policies.
  • Zero-allocation inline payloads apply to compact, POD-like payloads; larger or dynamic payloads use the general path (fine for non-hot usage).
  • Built-in helpers are wired to the built-in fragments; for custom fragments, wrap the generic mutation entry point in your own helper.