Skip to content

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 IHealthMutator and IHealthWriter over concrete HealthSystem references 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:

  • Current
  • Max
  • Normalized01
  • IsAlive
  • IsDead
  • IsFull
  • IsEmpty

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 Died
  • event 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:

  • Attacker
  • Victim
  • RawAmount
  • Tags
  • Multiplier
  • FlatDelta
  • BypassShields
  • Cancelled
  • BypassRules
  • IsPreview
  • FinalApplied
  • optional hit/source metadata

Factory/helper surface includes:

  • DamageContext.CreateBasic(...)
  • WithHit(...)
  • WithImpulse(...)
  • WithSource(...)

DamageResult

Returned by ApplyDamage(...).

Supported members:

  • Applied
  • FinalApplied
  • Reason
  • BypassedShields

Factory helpers:

  • DamageResult.Success(...)
  • DamageResult.Rejected(...)

DamageRejectionReason

Stable rejection codes for blocked or rejected damage attempts.

Includes values such as:

  • None
  • TargetIsDead
  • ZeroOrNegativeAmount
  • Invincible
  • ImmuneToTags
  • AbsorbedByShield
  • AuthorityBlocked
  • DamageLocked
  • Other

DamageTag

Bitflag value type describing semantic damage tags.

Examples include:

  • Melee
  • Ranged
  • Fire
  • Poison
  • Crit
  • True
  • Reflect

RuleBypass

Bitflag value type allowing a hit to skip specific rule families.

Current supported flags:

  • None
  • Armor
  • Affinity

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:

  • Target
  • RawAmount
  • Multiplier
  • FlatDelta
  • Cancelled
  • IsPreview
  • FinalApplied

Factory helper:

  • HealContext.CreateBasic(...)

HealthSnapshot

Serializable health snapshot.

Supported fields:

  • Max
  • Current
  • Dead

LastDamageReport

Stable, minimal public snapshot.

Supported fields:

  • Requested
  • Applied
  • Cancelled
  • BypassShields
  • FromKillCommand
  • Attacker
  • SourceId

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

  • IDamageRule
  • IHealRule

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:

  • IPostDamageRule
  • IPostHealRule

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:

  • DamageRulePriority
  • HealRulePriority

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:

  • IShield
  • IShieldPreview

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:

  • CapacityShield
  • RechargeableShield
  • OverhealShield
  • ReductionShield
  • ShieldChain
  • ShieldPool

ShieldChain is the supported shield aggregator component for ordered multi-shield behaviour.

OverhealShield.AddTemp(int) returns the points actually added after clamping to MaxTemp0 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:

  • IHealthLifecycle
  • IBeforeDeathHandler
  • IHealthDeathHandler
  • IInvincibilityHandler
  • IInvincibilityTimeMode
  • IInvincibilityResettable
  • IHealthRegenerator

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:

  1. damage is finalized
  2. IBeforeDeathHandler gets a chance to cancel death
  3. death state is finalized
  4. IHealthDeathHandler runs
  5. 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 IShieldPreview are 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:

  • DotEffect
  • HotEffect

Supporting public types include:

  • DotEffect.StackMode
  • HotEffect.StackMode
  • DotEffect.TickStackInfo
  • HotEffect.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:

  • AnimatorDeathHandler
  • ExtraLifeTotemHandler
  • HealthDeathEffectHandler
  • HealthInvincibilityHandler
  • MaxHealthModifierStack
  • TeamProvider

These are supported optional components that integrate with Health using the public seams described above.


Affinity Authoring & Providers

Supported affinity authoring/runtime components include:

  • AffinityProfile
  • AffinityProfileProvider
  • SimpleAffinityProvider

Use these to provide victim-side affinity multipliers without coupling game logic directly to custom rule implementations.


UI Connectors

Supported UI helper components include:

  • HealthBarUIConnector
  • WorldSpaceHealthBar

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 Died
  • event Action Revived
  • event 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.
  • DamageAttempted fires 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 HealthSystem independence 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.