Skip to content

Attributes — Abstractions

Folder Overview

The contracts. Everything here is an interface or a value type; nothing has behaviour of its own.


Purpose

Consumers and contributors meet the attribute container through these types without either side referencing the container itself. A HUD that watches AttributeDelta events, an equipment component that implements IAttributeModifierProvider, and a combiner the project writes once all compile against this folder alone.


What Lives Here

IAttributeSource

The read seam: TryGetValue(id, out value), non-throwing, found with GetComponentInParent. This is the interface adapters and consumer code should hold — it is the whole dependency a reader needs.

IAttributeModifierProvider

The contribution seam. Implemented on components along the owner's chain; collected the way Loot collects ILootModifier. Every contributor is the same shape — an equipped item, a status, a system of your own — so no source is ever special-cased by name.

IAttributeCombiner

The combine step, which is always the project's. The container calls it with the base value and the collected modifiers; how they fold together is the one decision this system refuses to make. No implementation ships.

AttributeModifier

One contribution: a value and an optional tag. Both are opaque to the framework and interpreted only by your combiner.

AttributeDelta

The change-event payload: owner, id, before, after. The old value travels with the new one because a threshold consumer cannot be written without it, and adding a parameter to a shipped event is a breaking change.


Important Notes

Providers run only when a combiner exists

Without an IAttributeCombiner, contributions have no defined meaning, so providers are not consulted at all and effective values are clamped base values. The container warns once when it finds providers it has no combiner for, so the silence is a message rather than a mystery.