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.

Prerequisites
How-To: Choose a Layout (capacity tags seeded) and How-To: Get the Building Blocks.

1. Know the built-in constraints

ClassDisplay nameRule properties (all replicated)What it checks
UCrimsonInventoryConstraint_SlotConstraint: Inventory SlotsMaxSlotsTag, FailureMessageSlot count against the int cap under MaxSlotsTag.
UCrimsonInventoryConstraint_IntTagConstraint: Int Tag ValueTrackedTag, ValueContributedPerItem, FailureMessageAn integer budget: each item adds ValueContributedPerItem to TrackedTag.
UCrimsonInventoryConstraint_FloatTagConstraint: Float Tag ValueTrackedTag, ValueContributedPerItem, bReadFromFootprintFragment, bAllowOverflow, FailureMessageA 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_GridCellRuleConstraint: Grid Cell RuleRules (FCrimsonGridCellRule: Min, Max, RequiredTags, BlockedTags, FailureMessage)Per-region type rules on a grid layout.
UCrimsonInventoryConstraint_StackLimitConstraint: Stack LimitItemTagFilter, MaxTotalQuantity, FailureMessageTotal quantity of matching items across all entries.
UCrimsonInventoryConstraint_TypeFilterConstraint: Type FilterRequiredTags, BlockedTags, FailureMessageAllow-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.

Verify
Try to give a blocked item from Dev Tools -> Items. The add fails, and Messages shows a 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.

Verify
Dev Tools -> Layout -> Active Constraints lists the new objects on the server and, after a tick, on a Play As Client window.

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.

Verify
Add the constraint, give an 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).

Verify
An item with a Type Filter fragment requiring a tag the destination inventory's constraints do not carry is rejected; the same item enters an inventory without that constraint.

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.

Whose values you can see
A player inventory's capacity containers replicate owner-only (the manager resolves this per send: owner-only when the owning actor has a net owning player, unrestricted otherwise). An unowned container's - a world chest - replicate to everyone who sees it, so every viewer announces. You therefore cannot read another player's capacity from your own client: compute the derived stat on the server and replicate that.
Verify
Play As Client with a weight constraint seeded. Give the client items on the server: one announce per changed tag arrives on both sides with matching numbers, and Dev Tools -> Messages lists one 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