How-To: Add Constraints
Goal: restrict what an inventory accepts - by type, by quantity, by weight, by grid region - with rule objects you can add and remove at runtime, and write your own.
1. Know the built-in constraints
| Class | Display name | Rule properties (all replicated) | What it checks |
|---|---|---|---|
UCrimsonInventoryConstraint_Slot | Constraint: Inventory Slots | MaxSlotsTag, FailureMessage | Slot count against the int cap under MaxSlotsTag. |
UCrimsonInventoryConstraint_IntTag | Constraint: Int Tag Value | TrackedTag, ValueContributedPerItem, FailureMessage | An integer budget: each item adds ValueContributedPerItem to TrackedTag. |
UCrimsonInventoryConstraint_FloatTag | Constraint: Float Tag Value | TrackedTag, ValueContributedPerItem, bReadFromFootprintFragment, bAllowOverflow, FailureMessage | A float budget. With bReadFromFootprintFragment it reads Weight from the item's Footprint fragment - this is the weight limit. With bAllowOverflow it never vetoes an add and never clamps a quantity, it only counts: the cap becomes a soft threshold for an observer to react to (step 6). |
UCrimsonInventoryConstraint_GridCellRule | Constraint: Grid Cell Rule | Rules (FCrimsonGridCellRule: Min, Max, RequiredTags, BlockedTags, FailureMessage) | Per-region type rules on a grid layout. |
UCrimsonInventoryConstraint_StackLimit | Constraint: Stack Limit | ItemTagFilter, MaxTotalQuantity, FailureMessage | Total quantity of matching items across all entries. |
UCrimsonInventoryConstraint_TypeFilter | Constraint: Type Filter | RequiredTags, BlockedTags, FailureMessage | Allow-list / block-list on the item's ItemType. |
2. Add constraints in the Details panel
Select the manager component. Under Inventory|Constraints -> Active Constraints click +, pick the class, expand it, fill the rule properties. These are instanced and replicate to every client that sees the owner.
ConstraintFailureMessage with your FailureMessage text.3. Add and remove at runtime
Server only: Construct Object from Class (Class = CrimsonInventoryConstraint_TypeFilter, Outer = the manager), set its properties, then Add Constraint. Remove Constraint takes the same object. Get Constraints By Tag finds existing ones by ConstraintTag.
4. Write your own constraint
Override CanAcceptItem (whole-inventory rule), CanAcceptAt (per-target rule), and CalculateMaxAllowedQuantity (partial accepts). OnItemAdded / OnItemRemoved let the constraint keep a running tally. Mark every rule property Replicated so client previews agree with the server.
Create a Blueprint child of CrimsonInventoryConstraint. Override Can Accept Item: return Make Crimson Constraint Check Result with bPassed false and a Failure Reason, or call Success for the default. Blueprint properties on the constraint are not replicated automatically - set the Replicated checkbox on each rule variable.
Item.Epic item: the add fails with Requires level 10. on both server and client previews.5. Per-item constraints
UCrimsonInventoryItemFragment_Constraint on an item definition carries ConstraintsToCheck - rules evaluated only when that item is placed (for example, a two-handed weapon that refuses a bag whose ConstraintTag is Container.Small).
6. Observe capacity values
A constraint's value is a number, not a rule - reacting to it is your job. GetConstraintCapacity reads one tag's FCrimsonInventoryCapacityView (Current, Max, bIsFloat, and Fraction = Current / Max unclamped, so 1.2 is 20% over the cap and 0 means there is no cap); GetConstraintFraction is the shortcut. To hear about changes, bind the manager's OnConstraintValueChanged delegate, drop the Observe Inventory Constraint node, or listen on Crimson.Inventory.Message.ConstraintChanged.
All three fire on the server and on the owning client, with the replicated authoritative values, once per tag per change. A value can be announced more than once in a frame (a cross-group move dips the counter, then settles it); the last announce of the frame is the settled one, so handlers must be safe to run on an intermediate value.
Add the async node Observe Inventory Constraint (category Crimson | Inventory): feed it the Inventory manager component and a Constraint Tag, and wire its On Constraint Changed pin. It fires once immediately with the current value and then on every change of that tag, so there is nothing to prime by hand. The pin gives you bHasConstraint (false while the inventory does not track that tag yet - the view is zeroed apart from its Tag) and Capacity; Break Crimson Inventory Capacity View for Current, Max, bIsFloat and Fraction.
The node registers with the game instance and unbinds itself when the inventory goes away, so a widget can start it in Event Construct and forget it. For a one-off read with no subscription, call Get Constraint Capacity or Get Constraint Fraction directly.
ConstraintChanged per tag with real values instead of zeros. Equip an ExpandRoot bag with no item moving: Max alone is announced. With bAllowOverflow set, push past the cap - the add succeeds and Fraction goes above 1.0.See also
- How-To: Choose a Layout
- How-To: React to Inventory Messages
- How-To: Save and Restore
- Concept: Layouts and Groups
- Concept: Multiplayer