Weight and durability
Both are additive modules built on Core's extension points, and both are worth reading as examples of how a feature is added without touching Core.
Weight policies
"20kg" is not one rule. A weight limit answers three independent questions, and keeping them apart is what lets one struct express games that look nothing alike.
Scope — what counts:
| Scope | Counts |
|---|---|
| Container | Only what sits directly in this container. Each bag is its own budget, so nesting buys capacity — deliberately |
| Container And Nested | Plus everything its items carry, however deep. Nesting stops being a way around the limit |
| Inventory | Everything the owner holds. One budget for the whole character |
Enforcement — what happens at the limit:
| Enforcement | Behaviour |
|---|---|
| Block | Refuse anything that would cross Max Weight. The limit is a wall |
| Allow | Never refuse. The limit is a line the game reads and reacts to |
And two numbers: Max Weight (the hard wall, 0 = none) and Encumbered Above (the soft line,
0 = never). They are independent, so a game can have one, the other, or both.
The games this covers
| Scope | Enforcement | Max | Encumbered above | |
|---|---|---|---|---|
| Roleplay server — a firm carry cap | Inventory | Block | 40 | — |
| Extraction shooter — take it all, walk home slowly | Inventory | Allow | — | 25 |
| ...with a ceiling you truly cannot pass | Inventory | Block | 60 | 25 |
| A pack with its own capacity | Container | Block | 20 | — |
| ...that its inner pouches must fit inside | Container And Nested | Block | 20 | — |
The second row is the one that changes how a game feels: you can always take the loot, you just have to carry it home.
Where each one goes
A limit that must refuse items belongs on containers, as a Weight Limit Rule — that is the only place an item can be turned away with a reason the UI can show. Put the same Inventory-scoped rule on every container to give a character one shared budget.
A limit that only reports belongs on UEDWeightComponent as its Carry Policy, which
publishes Is Encumbered, Get Over Encumbrance and On Encumbrance Changed. Nothing in the
framework reacts to encumbrance; the game decides what it costs.
Most games want both: the rule stops the impossible, the component reports the merely painful.
A packed bag carries the weight recorded when it was packed, so putting one away does not make its contents weightless — otherwise closing a bag would be a way to carry anything. An open bag is counted through its live container instead, never both.
Weight
FEDWeightFragment gives an item a unit weight. An item without one weighs nothing.
UEDWeightComponent sums the weight an actor is carrying and fires when it changes:
Weight->OnWeightChanged.AddDynamic(this, &AMyCharacter::HandleWeightChanged);
const float Total = Weight->GetTotalWeight();
By default it counts every container the actor has. Set bIncludeAllContainers false to count only
its main one — which is what you want if a stash should not slow the player down.
FEDWeightLimitRule is a container rule that refuses what would push it over a cap:
| Field | Meaning |
|---|---|
| Max Weight | The cap. |
| Weight Attribute | Optional GAS attribute, so a Strength perk raises it without touching the asset. |
Because it is a rule, it is consulted at the same acceptance gate as everything else. A vendor's Buy
button greys out with "That is too heavy" before the player clicks, and EvaluateAddItem and the
real add can never disagree.
const float Item = UEDWeightStatics::GetItemWeight(Entry);
const float Bag = UEDWeightStatics::GetContainerWeight(Container);
Durability
FEDDurabilityFragment gives an item a maximum durability and what happens when it runs out.
Current durability is per-stack state, not a fragment field — it lives in the entry's
FEDItemStateContainer, replicates with the entry, and saves with it.
UEDDurabilityStatics::GetDurability(Entry);
UEDDurabilityStatics::GetMaxDurability(Definition);
UEDDurabilityStatics::ApplyWear(Container, Handle, Amount);
UEDDurabilityStatics::Repair(Container, Handle, Amount);
Two consequences fall out of durability being per-stack state, and both are deliberate:
- Two swords at different durability never stack. Merging them would have to invent a number.
- A worn item keeps its wear through a move, because a transfer preserves handle and state.
What happens at zero — destroyed, rendered unusable, unequipped — is configured on the fragment, and the wear itself is your game's business. The framework does not know that swinging a sword should wear it out.
The pattern both follow
- A fragment describing the item's participation. Absent means not participating.
- Statics that read it, so Blueprint and C++ get the same surface.
- Optionally a rule or an observer component, registered through Core's registries.
Nothing in Core knows either module exists. That is what "additive" means here, and it is the shape to copy for a feature of your own — see Extending.
Where next
- Extending — writing a module like these
- Fragment reference