🩺 Health Abstractions¶
This folder defines the stable runtime interfaces that the Health system is built on.
These abstractions are:
- Engine-level contracts, not implementations
- Safe to reference from gameplay, AI, UI, networking, and editor tooling
- Designed to outlive concrete implementations such as
HealthSystem
If you understand this folder, you understand how to extend Health without touching core code.
🧩 Core Health Interaction Surfaces¶
IHealthReadonly, IHealthWriter, IDamageable¶
These interfaces form the canonical interaction surfaces for health.
-
IHealthReadonly
Read-only access to health state (Current, Max, Normalized, IsAlive, etc.).
Intended for UI, AI, and decision-making systems. -
IHealthWriter
Controlled mutation surface (Heal, SetCurrent, SetMax).
Used by regeneration systems, lifesteal, revive logic, and scripted effects. -
IDamageable
Minimal “can take damage” surface.
Useful for traps, environmental hazards, or generic hit systems.
HealthSystem implements all of these, but nothing requires you to depend on it directly.
UI layers, proxies, remote mirrors, or test doubles can expose these interfaces without owning or implementing full health logic.
🔄 Lifecycle Control¶
IHealthLifecycle¶
Explicit lifecycle control surface used by death and revive handlers.
- Exposes lifecycle operations such as:
Revive(int)SetCurrent(int)- Includes
IHealthReadonlyso handlers can reason about state without casting - Passed to lifecycle handlers instead of a concrete
HealthSystem
This interface exists to: - Avoid coupling extensions to a specific health owner - Allow last-chance intervention logic without leaking internals
Used by:
- IBeforeDeathHandler
- Lifecycle-focused gameplay systems
🧭 Authority Contract¶
IHealthAuthority¶
(see Authority)
Determines whether a caller is allowed to mutate a health instance.
Important clarifications:
- Authority only gates mutation
- It does not replicate state
- It does not synchronize health
- It does not define network ownership
This keeps Health:
- multiplayer-safe
- simulation-friendly
- transport-agnostic
💥 Damage Pipeline Abstractions¶
Execution Order
PRE rules (IDamageRule) run in ascending Priority order.
POST rules (IPostDamageRule) run after the engine finalizes the hit.
Any PRE rule may short-circuit processing by:
- returning false (stop further PRE rules), or
- setting ctx.Cancelled = true (explicitly reject the hit).
Damage Interfaces¶
-
IDamageRule
PRE-damage mutators (armor, crits, execute thresholds, buffs). -
IPostDamageRule
POST-damage observers (reflect, lifesteal, VFX/SFX, analytics).
These should not directly mutate the victim’s internal health state. -
IDamageAffinity
Victim-side, per-tag damage multipliers (immune / resist / weak).
Typically evaluated per single-bit tag. -
IAttackerDamageModifier
Attacker-side multipliers (berserk, frenzy, debuffs).
These interfaces are intentionally small and allocation-free, as they may run on every hit.
💚 Healing Pipeline Abstractions¶
-
IHealRule
PRE-heal mutators (anti-heal, clutch bonuses, scaling effects). -
IPostHealRule
POST-heal observers (VFX, SFX, telemetry, UI hooks). -
IHealingModifier
Simple per-component healing multipliers.
Tip
The healing pipeline mirrors damage exactly:
ordered PRE → final applied → POST.
⚰ Lifecycle & Death Hooks¶
-
IBeforeDeathHandler
Last-chance intercept before death resolves.
Receives anIHealthLifecyclesurface and may cancel death.
If death is cancelled, the handler is responsible for restoring a valid alive state (e.g., revive or set current health above zero). -
IHealthDeathHandler
Executes the canonical death pipeline
(animations, ragdoll, disabling input, cleanup).
This is a side-effects hook; death state has already been finalized.
These hooks are ordered, explicit, and idempotent.
⚙️ State & Utility Contracts¶
-
IHealthRegenerator
Allows regeneration systems to reset cooldowns after damage. -
IInvincibilityHandler
Temporary invulnerability windows (i-frames).
Ticked explicitly by the Health system. -
IShieldPreview
Non-mutating damage preview for UI / AI
(“How much damage would reach health?”).
Shields that do not implement
IShieldPrevieware ignored during previews.
📊 Result & Context Contracts¶
Note: Damage context and tagging types live in
Health/Shared.
| Type | Description |
|---|---|
DamageContext |
Full snapshot of a hit flowing through PRE → Shields → POST. |
DamageResult |
Structured outcome (Applied, FinalApplied, Reason, BypassedShields). |
DamageRejectionReason |
Canonical reasons a hit was rejected. |
LastDamageReport |
Minimal, stable snapshot for lifecycle hooks, UI, and telemetry. |
Why return DamageResult instead of a bool?
Explicit outcomes prevent guesswork:
var result = health.ApplyDamage(ctx);
if (!result.Applied)
Debug.Log($"Hit blocked: {result.Reason}");
else
Debug.Log($"Applied {result.FinalApplied} damage");
❌ What You Should Not Do¶
- Do not bypass these interfaces to mutate health
- Do not couple gameplay directly to
HealthSystem - Do not encode game rules inside abstractions
- Do not assume networking, replication, or authority behaviour here
These contracts exist to protect the core system from misuse.