Skip to content

⚙️ Health — Rules Core

This folder contains the runtime backbone of the Health rule system.

It defines the data structures, hubs, and utilities that power both the damage and healing pipelines. Every rule, modifier, and observer ultimately flows through the types in this folder.

Nothing here encodes gameplay decisions — this layer exists purely to orchestrate, order, and safely execute rules.


📦 What Lives Here (and Why)

The Rules Core layer is responsible for: - Transporting damage and heal data through the pipeline - Providing safe, explicit mutation surfaces for PRE rules - Dispatching finalized results to POST observers - Keeping execution deterministic and low-allocation at runtime

It deliberately does not: - Apply health directly - Contain gameplay logic - Know about abilities, buffs, UI, or networking


🧱 Core Context Structs

DamageContext

Encapsulates a single damage attempt as it flows through:

PRE rules → Shields → HealthSystem → POST rules

It is passed by ref to PRE rules and by readonly ref to POST rules.

Field Categories

Category Fields Purpose
Inputs RawAmount, Tags Base damage and semantic flags (Melee, Fire, Poison, etc.).
Mutables (PRE) Multiplier, FlatDelta, BypassShields, BypassRules, Cancelled Edited by PRE rules to shape the hit.
Outputs FinalApplied Final HP lost after all rules, shields, and clamps.
Metadata Attacker, Victim, TeamId, SourceId, HitPoint, HitNormal, Direction, Impulse Context for AI, VFX, analytics, and reactions.

PRE rules may: - mutate values - set Cancelled = true - return false to short-circuit the chain

POST rules may: - observe only - never mutate or cancel


Helper Construction

DamageContext provides factory helpers to reduce boilerplate and ensure consistent defaults when creating damage attempts:

  • CreateBasic(attacker, victim, amount, tags)

Additional metadata (hit point, impulse, source id, team id, bypass flags, etc.) is applied by direct field assignment before the context enters the pipeline. This keeps construction explicit and avoids hidden allocations or side effects.


HealContext

Healing counterpart to DamageContext, flowing through:

PRE heal rules → modifiers → HealthSystem → POST heal rules

Key Fields

Field Purpose
RawAmount Base heal before any rules.
Multiplier / FlatDelta Modified by PRE heal rules.
Cancelled Abort healing before application.
FinalApplied Actual HP restored.

Heal rules never mutate health directly — they only shape the final input to HealthSystem.TryHeal.


🧠 Rule Hubs

DamageRuleHub

Central aggregator and executor for damage-side rules.

public sealed class DamageRuleHub : MonoBehaviour
{
    bool ApplyRules(ref DamageContext ctx);
    void NotifyPost(in DamageContext ctx);
}

Behaviour

  • PRE phase
  • Gathers all IDamageRule components
  • Sorts by ascending Priority
  • Stops execution if:

    • a rule returns false, or
    • ctx.Cancelled is set
  • POST phase

  • Invokes all IPostDamageRule observers
  • Notified once per attempt when the engine finalizes the outcome
  • Receives the finalized DamageContext (including FinalApplied)

The hub refreshes its cache on: - Awake - OnEnable

This makes it safe for: - pooling - runtime enable/disable - prefab composition changes


HealRuleHub

Exact structural mirror of DamageRuleHub, but for healing.

  • Executes IHealRule in ascending priority
  • Short-circuits on false or ctx.Cancelled
  • Invokes all IPostHealRule observers after healing is applied
  • Ideal for:
  • anti-heal
  • clutch boosts
  • SFX / VFX
  • telemetry

🧠 Design Guarantees

  • Rule hubs avoid per-hit allocations during execution
  • Context structs are explicit and self-documenting
  • PRE rules mutate context — POST rules observe results
  • Components can be added/removed at runtime
  • Each HealthSystem instance can define its own rule composition

This layer exists to stay boring, stable, and predictable.


❌ What This Layer Should Not Do

  • Do not apply health directly
  • Do not contain gameplay decisions
  • Do not assume networking or authority
  • Do not encode UI or presentation logic

If something here feels “game-specific”, it’s in the wrong place.


🔗 See Also