Docs: reduce over-documentation across gameplay scripts

Trim restated narration, dead commented-out code, and oversized class
headers; keep all why-comments (authority, timing, edge cases), tooltips,
and serialization caveats.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Fable 5 committed 2026-07-02 10:08:28 +02:00
1 parent 882d30797e
commit 066e308cde
21 files changed
+478 -902

No files matched your search

+49 -85
View File
@@ -71,9 +71,8 @@ public class NetworkPlayerSetup : NetworkBehaviour
/// neutral lobby Player prefab (full mode set). Baked per prefab variant.</summary>
public bool ScopedModes => scopedModes;
// Server-authoritative "this hider has been shot/found". Server-write (a hunter's hit is validated on
// the server, not by the hider's owner); read by everyone. When it flips true the body is hidden on
// every client and the owning client drops into free-cam-only spectating. Stays false on hunters/lobby.
// Server-authoritative "this hider has been shot/found" (a hit is validated on the server, not by the
// hider's owner). When it flips true the body hides on every client and the owner drops to spectating.
private readonly NetworkVariable<bool> _isFound =
new NetworkVariable<bool>(false, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server);
@@ -81,25 +80,21 @@ public class NetworkPlayerSetup : NetworkBehaviour
/// target that is already out of play.</summary>
public bool IsFound => _isFound.Value;
// Owner-authoritative "this hider is buried too deep" flag. Only the OWNER runs the ConcealmentMeter
// (it is disabled on remotes), so the owner compares its EmbeddedPercent against MatchManager's
// threshold and writes this; every client reads it to switch the through-walls X-ray glow on/off for
// this avatar. Stays false on hunters / the lobby avatar and whenever no match is running.
// Owner-authoritative "this hider is buried too deep" flag: only the OWNER runs the ConcealmentMeter,
// so it compares EmbeddedPercent against the threshold and writes; every client reads it to switch
// the through-walls X-ray glow.
private readonly NetworkVariable<bool> _embeddedReveal =
new NetworkVariable<bool>(false, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Owner);
// Conversion-mode in-place respawn position. The owner holds authority over the NetworkTransform, so the
// server's Instantiate position is NOT honoured on the owner (it would otherwise snap to the prefab origin,
// 0,0,0). The server writes the tagged world position here in its OnNetworkSpawn so it rides the initial
// spawn snapshot to the owner, which then restores it itself. The NaN sentinel means "no override" (a
// normal lobby/match-start spawn) -> the owner runs its usual spawn-area/ring placement.
// Conversion-mode in-place respawn position. The owner holds transform authority, so the server's
// Instantiate position is NOT honoured there; the server writes the tagged position here so it rides
// the spawn snapshot and the owner restores it itself. NaN sentinel = no override (normal placement).
private static readonly Vector3 NoSpawnOverride = new Vector3(float.NaN, float.NaN, float.NaN);
private readonly NetworkVariable<Vector3> _spawnOverride =
new NetworkVariable<Vector3>(NoSpawnOverride, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server);
// Server-only handoff from MatchManager.ConvertToHunter: the world position the converted hunter must keep.
// Pushed into the replicated _spawnOverride during OnNetworkSpawn (where the variable is spawned and the
// server is allowed to write it - a pre-spawn write is silently dropped); a plain field needs no replication.
// Server-only handoff from MatchManager.ConvertToHunter, pushed into _spawnOverride during
// OnNetworkSpawn (a pre-spawn write to the NetworkVariable is silently dropped).
private Vector3? _conversionSpawnPos;
/// <summary>Server-only. Call on a freshly-instantiated Conversion hunter BEFORE spawning it so the owner
@@ -126,8 +121,7 @@ public class NetworkPlayerSetup : NetworkBehaviour
_isFound.OnValueChanged += OnFoundChanged;
if (_isFound.Value) ApplyFound(); // defensive: an avatar is never normally spawned already-found
// Server pushes a Conversion respawn's tagged position into the replicated override before the spawn
// snapshot goes out, so the owner (which owns the transform) can restore it in its own OnNetworkSpawn.
// Push the Conversion position into the replicated override before the spawn snapshot goes out.
if (IsServer && _conversionSpawnPos.HasValue)
_spawnOverride.Value = _conversionSpawnPos.Value;
@@ -135,10 +129,8 @@ public class NetworkPlayerSetup : NetworkBehaviour
if (IsOwner)
{
// A Conversion-mode tag respawns the hider as this Hunter variant in place. The owner-authoritative
// transform ignores the server's Instantiate position, so without help the owner snaps to the prefab
// origin (0,0,0); the server delivers the tagged position via _spawnOverride, restored here. A normal
// spawn (NaN override) runs the usual spawn-area/ring placement instead.
// Conversion respawn: restore the server-tagged position (the owner-authoritative transform
// ignores the server's Instantiate pos); NaN override = normal spawn placement.
Vector3 overridePos = _spawnOverride.Value;
if (float.IsNaN(overridePos.x))
PlaceAtSpawn();
@@ -157,36 +149,25 @@ public class NetworkPlayerSetup : NetworkBehaviour
var cc = GetComponent<CharacterController>();
if (cc) cc.enabled = false;
// Owner cleanup: the concealment meter is a per-frame skinned-mesh bake + voxelization +
// physics overlap whose result only feeds the LOCAL player (HUD / gameplay + the embedded-reveal
// flag). A remote avatar's concealment is computed on its own owner's machine, so running it here
// is pure wasted CPU.
// The concealment meter (per-frame bake + voxelization + overlap) only feeds the LOCAL player;
// a remote's concealment is computed on its own owner's machine, so here it is wasted CPU.
if (_concealment) _concealment.enabled = false;
// NOTE: SkinnedColliderBaker deliberately stays ENABLED on remotes. MeshPainter's stamp replay
// (ApplyNetworkStamp -> DrawBrushGpu) rasterizes the baker's live, per-frame BakedMesh to map a
// 3D brush placement into UV space; freezing the bake would mis-map replicated paint onto any
// non-rest pose. Its bake is the necessary cost of correct remote paint, not wasted work.
// NOTE: SkinnedColliderBaker deliberately stays ENABLED on remotes - stamp replay rasterizes its
// live per-frame BakedMesh to map 3D brush placements into UV space; freezing the bake would
// mis-map replicated paint onto any non-rest pose.
// The rig must keep evaluating even while this body is HIDDEN on the local client. During the hide
// phase a hider's body is hidden on hunter clients (UpdateVisibility sets renderer.enabled = false),
// and a remote can also sit off-screen. The avatar's Animator is authored as CullUpdateTransforms,
// which STOPS writing the bone transforms whenever its renderer isn't visible. PlayerPoseController
// drives the rig through a PlayableGraph on this Animator and resets un-keyed bones to rest every
// frame, so a culled Animator leaves the rig frozen at the rest/T-pose. SkinnedColliderBaker then
// bakes that wrong pose, and any paint stamp replicated during the hidden window lands on the wrong
// body part - a desync that persists once the body is shown again. Forcing AlwaysAnimate keeps the
// pose (and thus the baked mesh paint replay rasterizes) correct regardless of visibility. Remote
// replicas only: an owner is never hidden from its own camera.
// Force AlwaysAnimate so the rig keeps evaluating while this body is HIDDEN locally (hide phase /
// off-screen): the authored CullUpdateTransforms stops writing bones when the renderer isn't
// visible, the pose reset then freezes the rig at rest, SkinnedColliderBaker bakes that wrong
// pose, and replicated paint lands on the wrong body part - a desync that persists once shown
// again. Remote replicas only (an owner is never hidden from its own camera).
foreach (var anim in GetComponentsInChildren<Animator>(true))
anim.cullingMode = AnimatorCullingMode.AlwaysAnimate;
// Conversion mode: a hider shot during Seek is despawned and respawned in place as this Hunter
// variant. Keep the fresh hunter hidden on this (remote) client for a short settle window so nobody
// sees it appear or interpolate from the spawn frame - the shot hider is already gone, then the
// hunter cleanly materializes in its place. Detected via the replicated override the server wrote
// above; it rides the spawn snapshot, so it is already valid here. The owner returned early above
// (first-person, own body self-hidden), so it is never gated.
// Conversion: keep the fresh in-place hunter hidden on this remote client for a short settle
// window so nobody sees it pop in or interpolate from the spawn frame. Detected via the
// replicated override (already valid here); the owner returned early above, so it is never gated.
if (!float.IsNaN(_spawnOverride.Value.x))
{
_renderGate = true;
@@ -243,12 +224,10 @@ public class NetworkPlayerSetup : NetworkBehaviour
UpdateResolutionFreeze();
}
// Per-client. During the resolution phase every still-in-play hider is frozen in place on every machine:
// its pose graph holds the current frame (PlayerPoseController.Frozen) and, on the owning client, its
// movement input is cut (ControlEnabled) so the owner-authoritative transform stops and replicates as
// frozen. Mirrors the resolution X-ray reveal predicate. The pose flag is change-guarded (toggled only on
// a transition); the owner's ControlEnabled is re-asserted every frozen frame so a stray mode toggle can't
// quietly re-enable movement during the reveal. Nothing is restored — EndMatch despawns this avatar.
// Per-client. During Resolution every still-in-play hider is frozen: the pose graph holds the frame
// (PlayerPoseController.Frozen, change-guarded) and the owner's movement input is cut - re-asserted
// every frozen frame so a stray mode toggle can't quietly re-enable movement during the reveal.
// Nothing is restored: EndMatch despawns this avatar.
private void UpdateResolutionFreeze()
{
bool freeze = ComputeResolutionFreeze();
@@ -277,10 +256,8 @@ public class NetworkPlayerSetup : NetworkBehaviour
}
// Per-client visibility: each machine decides whether to render THIS avatar's body from the LOCAL
// viewer's perspective (hunter bodies are always visible; only hider bodies are ever hidden). A found
// hider (Classic) is hidden for everyone. Otherwise it depends on the match MODE - see ComputeVisible.
// The local owner's own body is left alone unless found, so this never fights the FirstPersonController's
// own-body self-hide.
// viewer's perspective (see ComputeVisible). The owner's own body is left alone unless found, so this
// never fights the FirstPersonController's own-body self-hide.
private void UpdateVisibility()
{
bool found = _isFound.Value;
@@ -341,10 +318,8 @@ public class NetworkPlayerSetup : NetworkBehaviour
return true;
}
// Owner-only. Publishes whether this hider is buried too deep to the replicated flag every client reads.
// Only a Hider avatar during a running match qualifies (the anti-burrow reveal targets hiders); the meter
// runs owner-side only, so this is where EmbeddedPercent is available. Cheap: a bool compare, one network
// write only on an actual edge (NetworkVariable dirties on assignment, so guard against no-op writes).
// Owner-only (the meter runs owner-side, so EmbeddedPercent is only available here). Publishes the
// buried-too-deep flag; one network write per actual edge (guarded - the variable dirties on assignment).
private void UpdateEmbeddedReveal()
{
if (!IsOwner) return;
@@ -358,10 +333,9 @@ public class NetworkPlayerSetup : NetworkBehaviour
if (over != _embeddedReveal.Value) _embeddedReveal.Value = over;
}
// Per-client. Switches this avatar's see-through-walls X-ray glow on/off by driving the material's
// _XRayColor alpha (via MeshPainter). Two independent triggers, OR-combined: the replicated embedded
// flag (a buried hider, from its owner) and the local resolution phase (every un-found hider is revealed
// to everyone at the end). Change-guarded so the material is only touched on an actual transition.
// Per-client X-ray glow via the material's _XRayColor alpha (through MeshPainter). Two OR-combined
// triggers: the replicated embedded flag and the local resolution phase. Change-guarded so the
// material is only touched on an actual transition.
private void UpdateXRayReveal()
{
if (!_painter) return;
@@ -397,11 +371,9 @@ public class NetworkPlayerSetup : NetworkBehaviour
}
/// <summary>
/// Places the freshly-spawned owner. Prefers this avatar's role-specific spawn area (Hunter/Hider tag),
/// then the shared <see cref="spawnAreaTag"/> area; if a matching area is loaded the owner drops at a
/// random point inside that collider (designer-authored spawn region). With no area present it falls back
/// to the deterministic client-id ring. Owner-authoritative either way - the NetworkTransform replicates
/// the result, and PlayerCharacterController captures it on its first Update as the kill-plane rescue target.
/// Places the freshly-spawned owner: role-specific spawn area first, then the shared area (a random
/// point inside the collider), falling back to the deterministic client-id ring. Owner-authoritative -
/// the NetworkTransform replicates the result.
/// </summary>
private void PlaceAtSpawn()
{
@@ -412,13 +384,10 @@ public class NetworkPlayerSetup : NetworkBehaviour
}
/// <summary>
/// Re-asserts the server-delivered Conversion position on the owner. The owner-authoritative
/// NetworkTransform makes the owner's transform the source of truth, so the server's Instantiate
/// position alone doesn't stick - the owner must set it here, BEFORE PlayerCharacterController's first
/// Update snapshots the kill-plane rescue target (otherwise a hider tagged mid-wall-climb spawns, falls
/// off the fresh hunter capsule below the kill plane, and is rescued to the still-zero default target =
/// origin). The CharacterController is toggled around the write because it otherwise overrides direct
/// transform writes (same pattern as PlaceOnSpawnRing/PlaceRandomlyInArea).
/// Re-asserts the server-delivered Conversion position on the owner (whose transform is the source of
/// truth), BEFORE PlayerCharacterController's first Update snapshots the kill-plane rescue target -
/// otherwise a hider tagged mid-climb could fall and be rescued to the still-zero default (origin).
/// The CharacterController is toggled around the write (it overrides direct transform writes).
/// </summary>
private void ApplyOwnerPosition(Vector3 worldPos)
{
@@ -454,11 +423,9 @@ public class NetworkPlayerSetup : NetworkBehaviour
}
/// <summary>
/// Drops the owner at a random point inside the spawn-area collider. X/Z are sampled within the
/// collider's footprint (rejection-sampled against the convex shape so the irregular outline is honoured,
/// not just its bounding box); Y sits a touch above the area floor so gravity settles the avatar onto the
/// ground. The CharacterController is toggled around the move because it otherwise overrides direct
/// transform writes (same pattern as <see cref="PlaceOnSpawnRing"/>).
/// Drops the owner at a random point inside the spawn-area collider: X/Z rejection-sampled against
/// the convex shape (honours the real outline, not just the AABB), Y a touch above the floor so
/// gravity settles. The CharacterController is toggled around the move (see ApplyOwnerPosition).
/// </summary>
private void PlaceRandomlyInArea(Collider area)
{
@@ -496,11 +463,8 @@ public class NetworkPlayerSetup : NetworkBehaviour
/// <summary>
/// Offsets the freshly-spawned owner onto a deterministic ring keyed by its client id so avatars
/// don't pile up at the shared prefab spawn point. Id 0 (the host) keeps the origin so single-player
/// "host alone" is unchanged; every later joiner takes the next ring slot, stepping the radius out
/// once a ring fills. Only X/Z are shifted (gravity settles Y), and the CharacterController is toggled
/// around the move because it otherwise overrides direct transform writes. Owner-authoritative, so the
/// NetworkTransform replicates the placement outward.
/// don't pile up at the shared prefab spawn point. Id 0 (host) keeps the origin; later joiners take
/// ring slots, stepping the radius out once a ring fills. Only X/Z shift (gravity settles Y).
/// </summary>
private void PlaceOnSpawnRing()
{