Skip to content

Attributes — Unity Integration

Folder Overview

The one component: AttributeSet, the container an owner carries.


Purpose

Everything stateful about attributes fronts through this component. Authored rows are seeded into the internal store on first use, runtime writes go through SetBaseValue, reads come back through TryGetValue, and the save participant round-trips CaptureSnapshot / RestoreSnapshot.


What Lives Here

AttributeSet

Implements IAttributeSource, which is how consumers find it — GetComponentInParent on the owner's chain, never a direct reference to this type.

The behaviour worth knowing before wiring one:

  • Lazy by design. State is created at the head of every public member, not in Awake, so EditMode tests and editor tooling see what a player sees.
  • Reads are pull. With a combiner wired, each effective-value read collects IAttributeModifierProvider contributions from the owner's chain and hands them through the project's IAttributeCombiner, then clamps to bounds. Without a combiner, reads return clamped base values and consult nobody — and the component says so, once, if providers exist that it has no combiner for.
  • Events carry both values. BaseValueChanged reports owner, id, before and after, and fires only on an actual change — designer UnityEvent first, then the C# event, the emit order every system here pins.
  • Restore is a rewind. RestoreSnapshot re-seeds the authored rows and applies the saved base values on top, silently. A runtime-created attribute the save does not mention is gone afterwards, because at the moment the save was taken it did not exist.

Important Notes

A nested read is legitimate, and costs an allocation

A combiner that reads another attribute of the same owner — a derived stat — re-enters the component mid-read. The shared collection buffers cannot serve a read that is still filling them for the read outside it, so a nested read allocates fresh ones for as long as it runs. The ordinary, non-re-entrant case reuses the same buffers every time.

Inspector edits after first use do not re-seed

Authored rows are read once, when the component is first touched. Changing the rows in the inspector during Play Mode does not rewrite live values — the same posture Health takes with its defaults asset. OnValidate reports inverted bound pairs at authoring time, and the full row validation runs at first read.