Health System — Public API¶
This page defines the supported, stable public API for the RevFramework Health System.
This is the contract
If something is not listed here, it is not supported as a public integration point — even if it appears accessible in code.
Audience: Developers integrating Health into gameplay, UI, effects, or persistence
Scope: Runtime public API only (Editor / Teaching helpers excluded)
Stability: Breaking changes to items listed here are avoided or clearly versioned
Core Concepts¶
- Health is component-driven and interface-first.
-
Damage flows through a structured pipeline:
-
authority checks (when enabled)
- state guards (dead, invincible, damage-locked)
- PRE rules
- damage evaluation (raw → multiplier → flat)
- shield interception (unless bypassed)
- state mutation
- POST observers (when the attempt reaches POST evaluation)
- death handling (if health reaches zero)
- Healing uses a separate supported mutation surface and may flow through:
- authority / state checks (implementation-defined guards)
- heal PRE rules (when present)
- healing modifiers
- state mutation
- optional overheal routing (e.g. OverhealShield when enabled)
- heal POST observers (when present and applied)
- Read-only consumers should depend on
IHealthReadonly. - Runtime mutation systems should prefer
IHealthMutatorandIHealthWriterover concreteHealthSystemreferences where possible. - Optional gameplay systems such as regen, invincibility, DOT/HOT, combat state, affinities, and shield composition are layered on top of the core health host.
Core Interfaces¶
IHealthReadonly¶
Canonical read-only health view.
Supported members:
CurrentMaxNormalized01IsAliveIsDeadIsFullIsEmpty
Use this for:
- UI
- AI checks
- save/load reads
- generic gameplay queries
IHealthMutator¶
Primary runtime damage mutation seam.
Supported members:
ApplyDamage(in DamageContext ctx)event Action Diedevent Action Revived
Guarantees¶
-
Damage flows through a structured pipeline:
-
authority checks (when enabled)
- state guards (dead, invincible, damage-locked)
- PRE rules
- damage evaluation (raw → multiplier → flat)
- shield interception (unless bypassed)
- state mutation
- POST observers (when the attempt reaches POST evaluation)
- death handling (if health reaches zero)
This is the supported damage entry point for runtime systems that should not depend directly on HealthSystem.
IHealthWriter¶
Supported write surface for healing and controlled non-combat state mutation workflows.
⚠️ This surface mixes: - healing entry points (pipeline-aware) - direct state mutation helpers (implementation-defined behaviour)
⚠️ Direct mutation methods (e.g. SetCurrent, SetMax) do not run the standard damage or healing pipelines. They may bypass rules, shields, and lifecycle hooks depending on the implementation.
Supported members:
TryHeal(int amount)Heal(int amount)SetCurrent(int value)SetMax(int value, bool clampCurrent = true)ResetToMax()
Use this for:
- healing
- setup
- save/load restore flows
- controlled non-combat mutation
IHealable¶
Minimal healing seam used by lightweight systems.
TryHeal(int amount)
ShieldDebugger¶
Scene-view debug component: draws a bar and label for the shield on its GameObject. Everything it draws is behind #if UNITY_EDITOR and costs nothing in a player build.
Moved in 1.2.0
It used to live under Editor/Gizmos/, which no asmdef covers — so Unity compiled it into Assembly-CSharp-Editor and a component a designer attaches to a scene object existed only in the Editor. Scenes using it shipped a missing script. It now lives in the Health runtime assembly. The script GUID is unchanged, so existing scenes keep their reference and a broken build is repaired by updating.
Damage locks¶
LockDamage()/UnlockDamage()— counted, so nested holders compose.LockDamageScoped()— disposable scope releasing one lock.ClearDamageLocks()— releases every outstanding lock.
The count has no owner and nothing resets it: not Awake, Revive, RestoreSnapshot, or disabling the component. A scoped lock whose holder is destroyed before disposing therefore leaves an object permanently undamageable, and ClearDamageLocks() is the way back.
It is deliberately not called by the lifecycle. Holding a lock across a revive is legitimate, so clearing one is a decision only the caller can make.
Runtime Result & Value Types¶
DamageContext¶
Public contract describing a damage attempt flowing through the Health pipeline.
⚠️ This is a mutable struct.
Prefer DamageContext.CreateBasic(...) — the default struct leaves Multiplier = 0, which typically results in zero damage.
Key fields include:
AttackerVictimRawAmountTagsMultiplierFlatDeltaBypassShieldsCancelledBypassRulesIsPreviewFinalApplied- optional hit/source metadata
Factory/helper surface includes:
DamageContext.CreateBasic(...)WithHit(...)WithImpulse(...)WithSource(...)
DamageResult¶
Returned by ApplyDamage(...).
Supported members:
AppliedFinalAppliedReasonBypassedShields
Factory helpers:
DamageResult.Success(...)DamageResult.Rejected(...)
DamageRejectionReason¶
Stable rejection codes for blocked or rejected damage attempts.
Includes values such as:
NoneTargetIsDeadZeroOrNegativeAmountInvincibleImmuneToTagsAbsorbedByShieldAuthorityBlockedDamageLockedOther
DamageTag¶
Bitflag value type describing semantic damage tags.
Examples include:
MeleeRangedFirePoisonCritTrueReflect
RuleBypass¶
Bitflag value type allowing a hit to skip specific rule families.
Current supported flags:
NoneArmorAffinity
HealContext¶
Public contract describing a heal attempt flowing through the heal pipeline.
⚠️ Prefer HealContext.CreateBasic(...) — the default struct leaves Multiplier = 0, resulting in zero effective healing.
Supported fields include:
TargetRawAmountMultiplierFlatDeltaCancelledIsPreviewFinalApplied
Factory helper:
HealContext.CreateBasic(...)
HealthSnapshot¶
Serializable health snapshot.
Supported fields:
MaxCurrentDead
LastDamageReport¶
Stable, minimal public snapshot.
Supported fields:
RequestedAppliedCancelledBypassShieldsFromKillCommandAttackerSourceId
This exists to provide a supported, smaller surface than exposing full internal pipeline mechanics.
Not every attempt produces a report
A report is recorded for every damage attempt that reaches the rules and the damage math — including ones a PRE rule cancels, ones that evaluate to zero, and ones a shield fully absorbs.
Attempts stopped earlier by a state guard — invincibility, a damage lock, or a non-positive RawAmount — record nothing and leave the previous report in place. Nothing was evaluated, so there is no outcome to describe, and overwriting would erase the record of the hit that actually landed.
IPostDamageRule observers follow the same boundary. If you need the complete feed of attempts including guard-rejected ones, subscribe to DamageAttempted — it is raised on all of them.
Rule System Contracts¶
PRE Rules¶
IDamageRuleIHealRule
Rules: - run in ascending Priority - may mutate context - may stop chain by returning false - must set Cancelled = true to explicitly cancel
POST Observers¶
Supported POST observer seams:
IPostDamageRuleIPostHealRule
POST observers are not guaranteed to run for early-rejected attempts.
They should be treated as observer hooks, not as a place to mutate host internals directly.
Affinity¶
IDamageAffinity¶
Optional victim-side affinity seam.
Built-in Health affinity behaviour combines multipliers multiplicatively across matching providers and tag bits.
Built-in Rule Ordering Constants¶
The following priority vocabularies are public and supported for custom rule authoring:
DamageRulePriorityHealRulePriority
Use them to align custom rules with the built-in rule ordering model rather than relying on unexplained magic numbers.
Shields¶
Core Shield Seams¶
Supported contracts:
IShieldIShieldPreview
Shields may absorb or reduce damage before it reaches health.
IShieldPreview allows non-mutating preview estimation when supported by the active shield implementation.
Ticketed Shield Pool¶
IShieldTicketPool¶
Optional shared shield-value seam for systems that want ticket-based shield contributions.
Supported members:
AddReturnTicket(int amount)RemoveByTicket(int ticket)Total
Built-in Shield Components¶
The following runtime shield components are part of the supported Health surface:
CapacityShieldRechargeableShieldOverhealShieldReductionShieldShieldChainShieldPool
ShieldChain is the supported shield aggregator component for ordered multi-shield behaviour.
OverhealShield.AddTemp(int) returns the points actually added after clamping to MaxTemp — 0 when the shield was already full. It previously returned nothing, which made "the shield absorbed the whole request and gained nothing" indistinguishable from a full grant; a pickup granting temporary shield could not tell, and consumed itself either way. The return is additive: a call that ignores it compiles and behaves exactly as before.
Authority¶
IHealthAuthority¶
Supported member:
bool HasAuthority(IHealthReadonly health)
Authority gates mutation only. When authority is required but not resolved, mutation is denied.
It does not define:
- replication
- ownership models
- networking transport
- state synchronization
Reading which authority is in play¶
HealthSystem exposes two independent questions:
| Member | True when |
|---|---|
HasAuthorityResolver | A resolver was injected with SetAuthorityResolver, and not since cleared |
HasDerivedAuthority | This component resolved one from the scene for itself, on its first gated mutation |
They are mutually exclusive, and both are false before the first gated mutation, because scene resolution is lazy. A tool that wants "is anything gating this?" reads both; one that wants "is something gating this that is not mine?" reads HasAuthorityResolver, which is what the Cookbook Lockdown recipe does before it installs its own.
HasAuthorityResolver reported both until 1.3.0
It was _hasAuthority != null, which is also true of a scene-derived resolver — so it answered "injected" for any actor that had simply been damaged once, and a caller acting on it skipped that actor. HasDerivedAuthority is the half that was missing rather than a new capability.
Default Runtime Binder¶
HealthAuthorityBinder¶
Supported default local authority component for single-player or simple local-authority setups.
Projects with custom multiplayer authority models should provide their own IHealthAuthority implementation instead of depending on the binder’s behaviour.
Lifecycle Contracts¶
Supported lifecycle seams:
IHealthLifecycleIBeforeDeathHandlerIHealthDeathHandlerIInvincibilityHandlerIInvincibilityTimeModeIInvincibilityResettableIHealthRegenerator
Lifecycle Behaviour Notes¶
IHealthLifecycle intentionally exposes lifecycle utilities that bypass the normal damage/heal rule pipeline, including:
Revive()Revive(int health)SetCurrent(int value)
Concrete host APIs may also expose additional direct-state helpers such as max/current setters and snapshot restore flows.
Death Flow¶
When death is reached through the normal damage/death finalization flow, the supported order is:
- damage is finalized
IBeforeDeathHandlergets a chance to cancel death- death state is finalized
IHealthDeathHandlerruns- death events fire
Lethality is decided at the moment damage is applied. It is not re-checked after damage events have run.
Averted Death¶
A damage-event listener may restore health before the death flow resolves — an "emergency heal on taking damage" setup, for example.
When that happens the target survives, Died does not fire, and DeathAverted fires instead.
⚠️ IBeforeDeathHandler is not consulted on this path.
This is deliberate: a single-use handler such as ExtraLifeTotemHandler would otherwise be consumed by a hit the target had already survived.
Kill() is unconditional and never reports an averted death.
⚠️ Not all mutations trigger the death pipeline.
Operations such as direct state setters, silent clamps, or snapshot restore may set a dead state without invoking IBeforeDeathHandler or IHealthDeathHandler.
If death is cancelled, the cancelling handler is responsible for restoring a valid alive state.
Preview Surface¶
Health previews are exposed by the host implementation.
Supported preview operations on HealthSystem include:
PreviewDamage(...)PreviewDamageDetailed(...)PreviewHeal(...)PreviewHealDetailed(...)
Built-in preview methods on HealthSystem:
- do not mutate health, shields or death state
- do not emit runtime events
- do not consume shield state
- resolve and refresh the rule hub exactly as a real hit does, so a hub or rule added at runtime is visible to both
Preview and rule state¶
Preview runs the live rule components — the same instances the real hit runs. That is what makes the two agree, and it is why a preview is capable of changing something.
Each rule is told through DamageContext.IsPreview / HealContext.IsPreview that the evaluation will not be committed. Every rule RevFramework ships leaves its own state alone when it sees that flag:
| Rule | During a preview |
|---|---|
CritRule | Does not roll. Reports the non-critical figure. Force Crit still previews as a crit. |
AntiHealRule | Does not roll its block chance. Reports the heal as not blocked; the multiplier still applies. |
| all other built-ins | Hold no state to advance. |
The flag is forced by the framework in both directions, so passing IsPreview = true into TryTakeDamage cannot talk rules out of running, and reusing a previewed context for a real hit cannot leave them sitting out.
Custom rules must honour IsPreview
A rule of your own that ignores the flag will still mutate its own state during a preview — charges, cooldowns, counters, random draws. Nothing in the framework can prevent that; the guarantee above is over the rules RevFramework ships, not over arbitrary code preview calls into. A UI that previews every frame calls these rules at frame rate.
Preview determinism depends on rule/modifier implementations and current runtime state.
⚠️ Important limitations:
- Shields that do not implement
IShieldPrevieware ignored by preview methods. Actual runtime damage may be lower than preview results. - Invincibility and some runtime guards (e.g. damage locks) are not simulated in preview.
- Custom rules and modifiers may introduce non-deterministic behaviour.
Preview is an estimate
Preview methods are estimates, not guaranteed outcomes.
Regeneration¶
Core Contract¶
IHealthRegenerator
This is the supported seam used by Health and companion systems to restart or delay regeneration cooldowns.
Built-in Runtime Component¶
HealthRegenerationHandler
This is the supported optional runtime regeneration component.
It includes:
- enable/disable control
- cooldown-based activation
- smooth or discrete regen modes
- optional regen ceiling support
HealthRegenerationHandler.RegenCeilingMode¶
Public enum used by HealthRegenerationHandler when the optional regen ceiling feature is enabled.
Effects¶
Optional gameplay effect components in the Health surface include:
DotEffectHotEffect
Supporting public types include:
DotEffect.StackModeHotEffect.StackModeDotEffect.TickStackInfoHotEffect.TickStackInfo
Effects:
- apply damage through
IHealthMutator - apply healing through
IHealthWriter - expose allocation-conscious stack inspection helpers
- do not mutate Health internals directly
Combat State¶
Built-in Runtime Component¶
HealthCombatState
This optional gameplay helper tracks whether a unit is considered “in combat”.
It is not part of the mutation pipeline and exists as layered gameplay state.
Runtime Handlers & Companion Components¶
The following supported runtime components are part of the Health gameplay surface:
AnimatorDeathHandlerExtraLifeTotemHandlerHealthDeathEffectHandlerHealthInvincibilityHandlerMaxHealthModifierStackTeamProvider
These are supported optional components that integrate with Health using the public seams described above.
Affinity Authoring & Providers¶
Supported affinity authoring/runtime components include:
AffinityProfileAffinityProfileProviderSimpleAffinityProvider
Use these to provide victim-side affinity multipliers without coupling game logic directly to custom rule implementations.
UI Connectors¶
Supported UI helper components include:
HealthBarUIConnectorWorldSpaceHealthBar
These are optional convenience components built against IHealthReadonly.
Supported Helpers¶
DamageExtensions¶
Convenience helpers for constructing damage contexts and routing damage into the standard Health runtime pipeline.
Includes result-based and bool-based convenience overloads.
HealingUtility¶
Public helper for evaluating and applying IHealingModifier multipliers.
Useful for:
- previews
- AI evaluation
- UI estimates
- custom gameplay logic
Concrete Runtime Host¶
HealthSystem¶
HealthSystem itself is part of the supported runtime Health surface.
It acts as the default concrete host for:
- read-only health state
- damage mutation
- healing
- lifecycle control
- previews
- snapshots
- authority binding
- damage reporting
- shield integration
- rule hub integration
Supported lifecycle events on the concrete host:
event Action Diedevent Action Revivedevent Action DeathAverted
DeathAverted reports a hit that was lethal when it landed but did not kill, because health was restored in-flight by a listener. See Death Flow → Averted Death.
⚠️ DeathAverted is declared on HealthSystem only. It is deliberately not on IHealthMutator, so existing implementers of that interface are unaffected.
Gameplay code should still prefer the narrower public interfaces when concrete HealthSystem access is not required.
Explicitly Not Supported¶
The following are not public API
- internal namespaces such as
RevGaming.RevFramework.Health.Internal - internal shield selection / authority resolution plumbing
- internal RNG wrappers
- internal report factories
- internal marker interfaces
- editor-only helpers
- teaching-only helpers
- undocumented internal overloads and convenience methods
If it is not listed on this page, it should be treated as unsupported.
Runtime Guarantees¶
- Damage sent through supported mutation seams routes through the Health evaluation pipeline.
DamageAttemptedfires for both applied and rejected damage attempts.- Healing sent through supported healing seams routes through the host’s supported healing flow.
- PRE rules run in ascending priority order.
- POST observers may receive finalized contexts for attempts that reach the post phase.
- Snapshot restore and lifecycle utilities are intentionally distinct from combat mutation.
- Optional layered systems (regen, effects, shields, authority, combat state) remain opt-in.
Not Guaranteed¶
- network replication
- deterministic preview results across arbitrary custom rule implementations
- automatic use of every optional component just because it exists on the GameObject
- compatibility with undocumented internal helpers
- concrete
HealthSystemindependence for every optional companion component
TL;DR¶
TL;DR
If it’s not on this page, it’s not part of the supported Health API.