Skip to content

🛡️ Health Authority

⚠️ Not a multiplayer framework.
This folder provides only the authority gating seam used by HealthSystem to allow or deny mutations.
Replication, prediction, rollback, and reconciliation are explicitly out of scope.

The authority system is:

  • Runtime-only
  • Netcode-agnostic
  • Opt-in via HealthSystem.requireAuthority

It answers exactly one question:

“Is this mutation allowed right now?”


📦 What This Is (and Is Not)

This is - A mutation gate for damage/heal/kill/revive/max-health changes - A small, internal authority contract used by the engine - A scene-scoped resolver with caching (for the built-in local binder) - Safe for single-player and multiplayer projects

This is not - A networking layer - A replication system - An ownership model - A prediction/reconciliation framework


🧩 Supported Integration Seams

After the internal/public pass, the authority contract type is internal (not a public extension point).
You have two supported ways to integrate authority into gameplay/networking:

HealthSystem exposes a supported injection seam:

health.SetAuthorityResolver(() => /* return true when this side/caller is allowed to mutate */);
  • When requireAuthority is ON and a resolver is set, Health uses that delegate for mutation checks.
  • Your delegate can consult netcode ownership, server authority, prediction state, etc.
  • This keeps Health transport-agnostic and avoids coupling to any specific networking SDK.

To remove the injected policy:

health.ClearAuthorityResolver();

2) ✅ Use the built-in local binder (single-player / testing)

For local single-player and editor testing, you can use the provided HealthAuthorityBinder component.

  • Add it to the same GameObject as HealthSystem
  • Leave its alwaysTrue toggle enabled for permissive local play
  • If requireAuthority is ON and no resolver is injected, Health will attempt to resolve a binder in the scene

In multiplayer projects, prefer the resolver injection seam above.


🧠 How HealthSystem Uses Authority

HealthSystem exposes a requireAuthority toggle.

When OFF
→ Authority is ignored and all mutations are allowed.

When ON
→ Every mutating call passes through an internal guard, including:

  • ApplyDamage
  • TryHeal
  • Kill
  • Revive
  • SetMaxHealth*

The guard will:

  1. Use the injected authority delegate (if present), otherwise attempt to resolve a local binder in the scene
  2. Deny mutation if authority is missing or returns false
  3. Populate LastAuthorityError (display-only text)
  4. Raise AuthorityDenied with a short, HUD-friendly message

Authority only gates mutation — it does not alter damage/heal pipelines, replication, or event ordering.


🧭 Resolver & Caching (engine detail)

When using the built-in binder path (no injected delegate), the engine uses a scene-scoped resolver with caching to avoid repeated searches.

Resolution order (high-level):

  1. Scene cache (fast path)
  2. Local component on the Health host
  3. Parent transforms
  4. Scene roots
  5. Global scan (last resort; includes inactive objects for diagnostics)

Cache notes: - Cache is scene-scoped - Cleared on domain reload - Invalidate is handled automatically when the built-in binder enables/disables/destroys

Warning

Only active, enabled, in-hierarchy binders are ever used.
Inactive binders may be detected for diagnostics but are never cached/used.


🧰 Built-in Binder

HealthAuthorityBinder (Local / Single-player)

A simple permissive implementation intended for local play and testing.

Use cases: - Single-player projects - Offline simulations - Editor testing - Prototyping

In multiplayer, replace this approach with resolver injection.


🚀 Usage Patterns

Single-Player

Choose one: 1. Leave requireAuthority = OFF 2. Enable requireAuthority + add the local binder (alwaysTrue = ON)

Multiplayer (Authoritative)

  1. Set requireAuthority = ON
  2. Inject a resolver via SetAuthorityResolver(() => ...) that matches your netcode's authority model
  3. Perform mutations only on the authoritative side
  4. Replicate results via your netcode (RPCs, SyncVars, NetworkVariables, etc.)

Warning

With requireAuthority = ON, missing authority denies mutations.
Ensure you either inject a resolver or provide a valid active local binder (single-player/testing).


❓ FAQs

Q: Where should the local binder live?
A: Preferably on the same GameObject as HealthSystem. Parents and roots are fallbacks.

Q: Can multiple binders exist?
A: Yes. The resolver will use the first valid active binder it finds.

Q: Do I need to call an invalidate method?
A: Not for normal workflows. The built-in binder invalidates automatically on enable/disable/destroy.

Q: Does this replicate health?
A: No. Authority only gates mutation. Replication is your responsibility.

Q: Why not include netcode support here?
A: Authority models differ wildly across SDKs. This stays stable by remaining netcode-agnostic.


🧭 Troubleshooting

Symptom Likely Cause Fix
Mutation denied Resolver/binder returned false Check your authority logic / ownership
Mutation denied No resolver and no active binder Inject a resolver or add HealthAuthorityBinder
Health not syncing Authority works, no replication Sync via your netcode

❌ What You Should Not Do

  • Do not assume this provides networking
  • Do not bypass authority checks in gameplay code
  • Do not mutate health from non-authoritative contexts
  • Do not embed game rules into the resolver/caching layer

This system is a guardrail, not a gameplay system.


🔗 See Also