🛡️ 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:
1) ✅ Inject an authority resolver (recommended for multiplayer)¶
HealthSystem exposes a supported injection seam:
health.SetAuthorityResolver(() => /* return true when this side/caller is allowed to mutate */);
- When
requireAuthorityis 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
alwaysTruetoggle enabled for permissive local play - If
requireAuthorityis 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:
ApplyDamageTryHealKillReviveSetMaxHealth*
The guard will:
- Use the injected authority delegate (if present), otherwise attempt to resolve a local binder in the scene
- Deny mutation if authority is missing or returns false
- Populate
LastAuthorityError(display-only text) - Raise
AuthorityDeniedwith 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):
- Scene cache (fast path)
- Local component on the Health host
- Parent transforms
- Scene roots
- 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)¶
- Set
requireAuthority = ON - Inject a resolver via
SetAuthorityResolver(() => ...)that matches your netcode's authority model - Perform mutations only on the authoritative side
- 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¶
- Health System
- Health Abstractions
- (Optional) Netcode binders in your project (Mirror / NGO / Fusion) should target the resolver injection seam