Quick Start

1. Enable the plugin

Open Edit -> Plugins, type Crimson in the search box, tick CrimsonInventory's checkbox (and its dependency CrimsonCommon), and restart the editor when prompted. For a Blueprint project that's the entire install - you never hand-edit the .uproject or any .Build.cs.

Screenshot pendingImages/CrimsonInventory/qs-enable-plugin.png
Edit -> Plugins -> search 'Crimson' -> tick CrimsonInventory's Enabled checkbox -> restart the editor.
Blueprint-only project?
Enabling the plugin in Edit -> Plugins is the whole installation - there is no .uproject or .Build.cs to edit. The editor writes the plugin entry for you. The C++ step below is needed only when you reference CrimsonInventory types from your own C++ code.

C++ projects: after enabling the plugin above, add its module to your build file so your game code can use its types:

csharp
// YourGame.Build.cs
PublicDependencyModuleNames.Add("CrimsonInventory");

2. Pick (or author) a layout asset

Create a Layout data asset in the Content Browser. The three built-ins are UCrimsonInventoryLayout_FlatSlot (MMO/RPG), UCrimsonInventoryLayout_Grid (Diablo/Tarkov spatial), and UCrimsonInventoryLayout_Weight (Skyrim list). Subclass UCrimsonInventoryLayout in BP or C++ if you need a custom topology.

3. Add the component, set the layout, initialize, attach constraints

cpp
// MyPlayerState.h
#include "CrimsonInventoryManagerComponent.h"
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
TObjectPtr<UCrimsonInventoryManagerComponent> InventoryComponent;
// MyPlayerState.cpp - BeginPlay (server only)
void AMyPlayerState::BeginPlay()
{
Super::BeginPlay();
if (!HasAuthority()) return;
InventoryComponent->SetLayout(MyFlatSlotLayoutAsset);
TArray<FCrimsonTagStack> IntConstraints = {
{ TAG_Crimson_Inventory_Constraint_Slots, 30 } // max 30 slots
};
TArray<FCrimsonFloatTagStack> FloatConstraints = {
{ TAG_Crimson_Inventory_Constraint_Weight, 100.f } // max 100 weight
};
InventoryComponent->InitializeInventory(
{ ConstraintDT }, // optional design-time constraint defs
IntConstraints,
FloatConstraints,
{ CurrencyDT } // currency data tables
);
// Runtime rule stack - add the rules you want to enforce
InventoryComponent->AddConstraint(NewObject<UCrimsonInventoryConstraint_Slot>(InventoryComponent));
InventoryComponent->AddConstraint(NewObject<UCrimsonInventoryConstraint_FloatTag>(InventoryComponent));
}
Bag Extension example
When the player picks up a Backpack item, increase both caps at runtime - no new constraints needed:

InventoryComponent->ModifyIntConstraintValue(TAG_Crimson_Inventory_Constraint_Slots, +10);
InventoryComponent->ModifyFloatConstraintValue(TAG_Crimson_Inventory_Constraint_Weight, +50.f);

UI subscribed to FCrimsonInventory_Message_ConstraintChanged refreshes capacity bars automatically.

4. Create an item definition

Content Browser -> right-click -> Crimson -> Inventory -> Item Definition. Add fragments to the Fragments array:

- Inventory Data (UCrimsonInventoryItemFragment_Data): bStackable, MaxStackSize, bUnique
- Inventory Footprint (UCrimsonInventoryItemFragment_Footprint): Dimensions (for grid), Weight (for weight cap), SlotCost, bAllowRotation
- Item Visuals (UCrimsonInventoryItemFragment_Visuals): icon, slot widget, pickup actor class
- Inventory Constraints (UCrimsonInventoryItemFragment_Constraint): per-item attached constraints

5. Add the routing component to your PlayerController

UCrimsonInventoryRoutingComponent owns all Server_ RPCs the plugin needs (move / split / drop / lock / transfer / open container). Your UI calls it directly - no boilerplate to write.

cpp
// MyPlayerController.h
#include "Routing/CrimsonInventoryRoutingComponent.h"
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
TObjectPtr<UCrimsonInventoryRoutingComponent> InventoryRouting;
// MyPlayerController.cpp ctor
InventoryRouting = CreateDefaultSubobject<UCrimsonInventoryRoutingComponent>(TEXT("InventoryRouting"));
// From any client widget:
InventoryRouting->MoveItem(MyInventory, SourceEntryId, NewTarget);
InventoryRouting->TransferItem(MyInventory, ChestInventory, EntryId, 1);
InventoryRouting->OpenContainer(ChestActor);
// (override CanAccessInventory / CanOpenContainer in a BP/C++ subclass for stricter rules)

6. Add an item (server authority)

cpp
// Simple: let the layout pick where it goes
UCrimsonInventoryItemInstance* Item = InventoryComponent->AddItemDefinition(
UMyHealthPotion::StaticClass(), 5);
// Explicit placement (drag-and-drop onto a known target):
FCrimsonPlacementTarget Target;
Target.GridPosition = FIntPoint(3, 1); // grid layouts
Target.Rotation = ECrimsonItemRotation::CW90;
InventoryComponent->AddItemDefinition(
USwordDef::StaticClass(), 1,
ECrimsonPlacementPolicy::ExplicitTarget, Target);

7. Pickup from a world actor (async node)

Use the Attempt Pickup async node in Blueprint. It runs all constraints, adds what fits, and routes to OnSuccess, OnPartialSuccess, or OnFailure with the leftover pickup.

8. Listen for changes on the client (UI)

cpp
#include "Messaging/CrimsonMessageSubsystem.h"
#include "CrimsonInventoryMessagePayloads.h"
#include "CrimsonInventoryTags.h"
UCrimsonMessageSubsystem* Msgs = GetWorld()->GetSubsystem<UCrimsonMessageSubsystem>();
Msgs->RegisterListener<FCrimsonInventoryChangeMessage>(
CrimsonInventoryTags::TAG_Crimson_Inventory_Message_StackChanged,
this, &UMyInventoryWidget::OnStackChanged);
Msgs->RegisterListener<FCrimsonInventory_Message_ConstraintChanged>(
CrimsonInventoryTags::TAG_Crimson_Inventory_Message_ConstraintChanged,
this, &UMyInventoryWidget::OnCapacityChanged);