Refactor Assets/Scripts: trim restating comments, minor structure cleanups

Sweep over 48 files (Editor/ excluded): remove comments that restate the
code, condense class summaries, fix three stale doc statements
(HsvColorPicker alpha bar, PaintHud layoutPrefab, MasterVolume
FallbackDefault). Inline two single-use wrappers (IsPointerOverUi,
BuildModes), drop an unused using, replace a magic literal with the
existing ParallaxBase constant, and convert ~10 UnityEngine.Object null
checks to the implicit-bool convention. No serialized fields, signatures,
RPC/NetworkVariable names, defaults, or #if blocks touched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Fable 5 committed 2026-07-08 08:29:18 +02:00
1 parent eeee5fc2f0
commit 6c03e5d3f6
48 files changed
+289 -481

No files matched your search

@@ -5,12 +5,9 @@ using UnityEngine.InputSystem;
#endif
/// <summary>
/// Dev-only connection harness for local multiplayer testing across the junction-mirror clones: one
/// instance clicks Host and the others click Client (loopback 127.0.0.1 via the configured
/// UnityTransport). Everyone spawns as the neutral Player prefab into the Lobby; roles (Hunter/Hider)
/// are rolled and applied by <see cref="MatchManager"/> when the match starts, not here. Hotkeys:
/// H = Host, C = Client, J = Server, K = Shutdown. Purely a testing scaffold - replace with real
/// lobby/menu UI later. Attach to the same GameObject as the NetworkManager.
/// Dev-only connection harness for local multiplayer testing: Host/Client/Server over loopback via the
/// configured UnityTransport (hotkeys H/C/J, K = Shutdown). Roles are rolled by <see cref="MatchManager"/>
/// at match start, not here. Testing scaffold only - replace with real lobby/menu UI later.
/// </summary>
[RequireComponent(typeof(NetworkManager))]
[DisallowMultipleComponent]
@@ -41,7 +38,7 @@ public class NetworkBootstrap : MonoBehaviour
if (TypingGuard.IsTyping) return; // don't fire H/C/J/K while typing in a text field
#if ENABLE_INPUT_SYSTEM
var kb = Keyboard.current;
if (kb == null || _net == null) return;
if (kb == null || !_net) return;
if (!_net.IsListening)
{
if (kb.hKey.wasPressedThisFrame) _net.StartHost();
@@ -57,7 +54,7 @@ public class NetworkBootstrap : MonoBehaviour
private void OnGUI()
{
if (!showGui || _net == null) return;
if (!showGui || !_net) return;
GUILayout.BeginArea(new Rect(10, 10, 220, 160), GUI.skin.box);
if (!_net.IsListening)
+32 -41
View File
@@ -307,7 +307,7 @@ public class MatchManager : MonoBehaviour
// Disable NGO auto-spawn (decided purely by PlayerPrefab != null); keep the reference and spawn
// manually once a floored scene exists. Runtime-only mutation - no asset diff.
if (_net != null)
if (_net)
{
_playerPrefab = _net.NetworkConfig.PlayerPrefab;
_net.NetworkConfig.PlayerPrefab = null;
@@ -337,7 +337,6 @@ public class MatchManager : MonoBehaviour
if (Instance == this) Instance = null;
}
// Unhooks the per-session callbacks and named-message handlers (shared by OnDisable and OnNetStopped).
private void UnhookSessionCallbacks()
{
_net.OnClientConnectedCallback -= OnClientConnected;
@@ -455,7 +454,7 @@ public class MatchManager : MonoBehaviour
private void HookSceneManager()
{
if (_hooked || _net == null || _net.SceneManager == null) return;
if (_hooked || !_net || _net.SceneManager == null) return;
_net.SceneManager.OnSceneEvent += OnSceneEvent;
_hooked = true;
}
@@ -483,7 +482,7 @@ public class MatchManager : MonoBehaviour
// the load/respawn routine covers it (the PlayerObject guard in SpawnFor prevents a double spawn).
private void OnClientConnected(ulong clientId)
{
if (_net == null || !_net.IsServer) return;
if (!_net || !_net.IsServer) return;
// Dedicated-server case: the first client to connect becomes the match authority (a host already
// claimed it at server start). Told via named message so it reads Esc locally.
@@ -514,7 +513,7 @@ public class MatchManager : MonoBehaviour
// dedicated-server match stays controllable.
private void OnClientDisconnected(ulong clientId)
{
if (_net == null || !_net.IsServer) return;
if (!_net || !_net.IsServer) return;
// A hider that leaves mid-match can never be found - drop it so "all hiders found" can still trigger.
_pendingHiders.Remove(clientId);
@@ -545,7 +544,7 @@ public class MatchManager : MonoBehaviour
// the server, so it records its own identity directly; a pure client reports it to the server by message.
private void OnLocalClientConnected(ulong clientId)
{
if (_net == null || clientId != _net.LocalClientId) return;
if (!_net || clientId != _net.LocalClientId) return;
if (_net.IsServer) RegisterIdentity(_net.LocalClientId, PersistentPlayerId.Value);
else SendIdentityToServer(PersistentPlayerId.Value);
@@ -554,7 +553,7 @@ public class MatchManager : MonoBehaviour
// Client -> server: report this install's persistent id so the server can map it to our ephemeral clientId.
private void SendIdentityToServer(string persistentId)
{
var cmm = _net != null ? _net.CustomMessagingManager : null;
var cmm = _net ? _net.CustomMessagingManager : null;
if (cmm == null || string.IsNullOrEmpty(persistentId)) return;
// Grows up to the cap if a future id source is longer than the initial buffer (persistent ids are short).
using (var writer = new FastBufferWriter(256, Allocator.Temp, 1024))
@@ -568,7 +567,7 @@ public class MatchManager : MonoBehaviour
private void OnIdentityMessage(ulong senderClientId, FastBufferReader reader)
{
reader.ReadValueSafe(out string persistentId);
if (_net == null || !_net.IsServer) return;
if (!_net || !_net.IsServer) return;
RegisterIdentity(senderClientId, persistentId);
}
@@ -605,8 +604,8 @@ public class MatchManager : MonoBehaviour
/// Safe to call repeatedly (only acts once, while still in the lobby phase).</summary>
public void StartMatch()
{
if (_net == null || !_net.IsServer) return;
if (Phase != MatchPhase.Lobby) return; // double-start / not-in-lobby guard
if (!_net || !_net.IsServer) return;
if (Phase != MatchPhase.Lobby) return;
if (!hunterPrefab || !hiderPrefab)
{
Debug.LogError("[MatchManager] Role prefabs not assigned - cannot start match.", this);
@@ -730,7 +729,6 @@ public class MatchManager : MonoBehaviour
}
}
// Waits up to 'seconds' of server real time, returning early the moment 'until' (if supplied) is true.
private IEnumerator WaitPhase(float seconds, System.Func<bool> until)
{
_skipPhase = false; // drop a stale debug-skip from the previous phase; only this phase may set it
@@ -760,7 +758,7 @@ public class MatchManager : MonoBehaviour
[ContextMenu("Next Sub-Phase (Debug)")]
public void DebugSkipToNextSubPhase()
{
if (_net == null) return;
if (!_net) return;
if (_net.IsServer) { DebugSkipServer(); return; }
if (_isLocalAuthority) SendEmptyNamedMessage(MsgDebugSkip, NetworkManager.ServerClientId);
}
@@ -768,7 +766,7 @@ public class MatchManager : MonoBehaviour
// Server-only. Flags the running phase-wait loop to break early so RunMatchPhases moves to the next sub-phase.
private void DebugSkipServer()
{
if (_net == null || !_net.IsServer) return;
if (!_net || !_net.IsServer) return;
if (_subPhase == MatchSubPhase.None) return; // nothing running to skip
_skipPhase = true;
Debug.Log($"[MatchManager] DEBUG: skipping the rest of {_subPhase}.", this);
@@ -777,7 +775,7 @@ public class MatchManager : MonoBehaviour
// Server handler: an authority client asked to skip to the next sub-phase.
private void OnDebugSkipMessage(ulong senderClientId, FastBufferReader reader)
{
if (_net == null || !_net.IsServer) return;
if (!_net || !_net.IsServer) return;
if (!IsMatchAuthority(senderClientId)) return;
DebugSkipServer();
}
@@ -859,7 +857,7 @@ public class MatchManager : MonoBehaviour
// applied paint cutoff - exactly the condition the per-client reveal uses to un-hide the body.
private bool LocalClientReady(List<ulong> ids)
{
var sm = _net != null ? _net.SpawnManager : null;
var sm = _net ? _net.SpawnManager : null;
if (sm == null) return false;
for (int i = 0; i < ids.Count; i++)
{
@@ -873,7 +871,7 @@ public class MatchManager : MonoBehaviour
// Server -> every other client: the target ids + holding phase + generation for this barrier round.
private void BroadcastBeginLoad(MatchSubPhase activePhase)
{
var cmm = _net != null ? _net.CustomMessagingManager : null;
var cmm = _net ? _net.CustomMessagingManager : null;
if (cmm == null) return;
_loadRecipients.Clear();
@@ -932,7 +930,7 @@ public class MatchManager : MonoBehaviour
// Client -> server: this machine finished loading (echoes the generation so a stale reply is ignored).
private void SendReadyToServer(int generation)
{
var cmm = _net != null ? _net.CustomMessagingManager : null;
var cmm = _net ? _net.CustomMessagingManager : null;
if (cmm == null) return;
using (var writer = new FastBufferWriter(sizeof(int), Allocator.Temp))
{
@@ -945,19 +943,17 @@ public class MatchManager : MonoBehaviour
private void OnReadyMessage(ulong senderClientId, FastBufferReader reader)
{
reader.ReadValueSafe(out int generation);
if (_net == null || !_net.IsServer) return;
if (!_net || !_net.IsServer) return;
if (generation != _loadGeneration) return; // stale ack from a previous barrier round
_readyClients.Add(senderClientId);
}
// Server-only. Applies the sub-phase to the server's own mirror and broadcasts it to every other client.
private void SetPhaseServer(MatchSubPhase phase, float duration)
{
ApplyPhaseLocal(phase, duration, matchMode);
BroadcastPhase(phase, duration, matchMode, 0, true);
}
// Sets this machine's sub-phase mirror + countdown + mode (followers poll LocalSubPhase).
// Shared by the server's SetPhaseServer and a client's OnPhaseMessage handler.
private void ApplyPhaseLocal(MatchSubPhase phase, float duration, MatchMode mode)
{
@@ -987,7 +983,7 @@ public class MatchManager : MonoBehaviour
// (which applied it directly in SetPhaseServer, so it must not double-apply via loopback).
private void BroadcastPhase(MatchSubPhase phase, float duration, MatchMode mode, ulong targetClient, bool toAll)
{
var cmm = _net != null ? _net.CustomMessagingManager : null;
var cmm = _net ? _net.CustomMessagingManager : null;
if (cmm == null) return;
using (var writer = new FastBufferWriter(sizeof(byte) + sizeof(float) + sizeof(byte), Allocator.Temp))
{
@@ -1023,7 +1019,7 @@ public class MatchManager : MonoBehaviour
// locally (no loopback message, mirroring SetPhaseServer). Hiders and spectators never receive a ping.
private void BroadcastRadarPings()
{
if (_net == null || !_net.IsServer || _pendingHiders.Count == 0) return;
if (!_net || !_net.IsServer || _pendingHiders.Count == 0) return;
_radarPingIds.Clear();
foreach (ulong hiderClientId in _pendingHiders)
@@ -1067,7 +1063,7 @@ public class MatchManager : MonoBehaviour
/// directly. No-op outside the Seek phase.</summary>
public void RequestManualPing()
{
if (_net == null || _subPhase != MatchSubPhase.Seek) return;
if (!_net || _subPhase != MatchSubPhase.Seek) return;
if (_net.IsServer) { ServerManualPing(_net.LocalClientId); return; }
SendEmptyNamedMessage(MsgManualPing, NetworkManager.ServerClientId);
@@ -1077,7 +1073,7 @@ public class MatchManager : MonoBehaviour
// ServerManualPing validates it is a live hider during Seek.
private void OnManualPingMessage(ulong senderClientId, FastBufferReader reader)
{
if (_net == null || !_net.IsServer) return;
if (!_net || !_net.IsServer) return;
ServerManualPing(senderClientId);
}
@@ -1099,7 +1095,7 @@ public class MatchManager : MonoBehaviour
private void SpawnRadarBlipsLocal()
{
var radar = Radar.Instance;
var spawnMgr = _net != null ? _net.SpawnManager : null;
var spawnMgr = _net ? _net.SpawnManager : null;
if (!radar || spawnMgr == null) return;
for (int i = 0; i < _radarPingIds.Count; i++)
if (spawnMgr.SpawnedObjects.TryGetValue(_radarPingIds[i], out var no) && no)
@@ -1113,7 +1109,7 @@ public class MatchManager : MonoBehaviour
reader.ReadValueSafe(out float lifetime);
reader.ReadValueSafe(out int count);
var radar = Radar.Instance;
var spawnMgr = _net != null ? _net.SpawnManager : null;
var spawnMgr = _net ? _net.SpawnManager : null;
for (int i = 0; i < count; i++)
{
reader.ReadValueSafe(out ulong netObjId);
@@ -1128,7 +1124,7 @@ public class MatchManager : MonoBehaviour
/// applies directly. No-op outside the seek phase.</summary>
public void ReportHit(ulong targetClientId)
{
if (_net == null || _subPhase != MatchSubPhase.Seek) return;
if (!_net || _subPhase != MatchSubPhase.Seek) return;
if (_net.IsServer)
{
@@ -1152,7 +1148,7 @@ public class MatchManager : MonoBehaviour
private void OnReportHitMessage(ulong senderClientId, FastBufferReader reader)
{
reader.ReadValueSafe(out ulong targetClientId);
if (_net == null || !_net.IsServer) return;
if (!_net || !_net.IsServer) return;
if (_subPhase != MatchSubPhase.Seek) return;
if (!_pendingHiders.Contains(targetClientId)) return; // not a live (un-found) hider
if (!IsHunter(senderClientId)) return; // only a hunter may shoot
@@ -1186,7 +1182,7 @@ public class MatchManager : MonoBehaviour
if (hitRevealDelay > 0f) yield return new WaitForSeconds(hitRevealDelay);
_revealingHiders.Remove(hiderClientId);
if (_net == null || !_net.IsServer) yield break;
if (!_net || !_net.IsServer) yield break;
_pendingHiders.Remove(hiderClientId);
@@ -1280,7 +1276,6 @@ public class MatchManager : MonoBehaviour
_conversionRecords.Clear();
}
// Server-only. Despawns every live conversion statue (match ending / back to lobby) and drops the list.
private void DespawnConversionStatues()
{
for (int i = 0; i < _statues.Count; i++)
@@ -1291,7 +1286,6 @@ public class MatchManager : MonoBehaviour
_statues.Clear();
}
// True if the client's current avatar is a Hunter role variant (used to gate shooting server-side).
private bool IsHunter(ulong clientId)
{
if (!_net.ConnectedClients.TryGetValue(clientId, out var c) || !c.PlayerObject) return false;
@@ -1303,7 +1297,7 @@ public class MatchManager : MonoBehaviour
/// neutral lobby Player (including any spectator-held mid-match joiners). Only acts while in a match.</summary>
public void EndMatch()
{
if (_net == null || !_net.IsServer) return;
if (!_net || !_net.IsServer) return;
if (Phase != MatchPhase.InMatch) return; // only endable mid-match
// Stop the sub-phase machine if the match is being ended early (authority's Back-to-Lobby) and clear
@@ -1329,8 +1323,6 @@ public class MatchManager : MonoBehaviour
Debug.Log("[MatchManager] Back in lobby.", this);
}
// Unloads one gameplay scene (if loaded), then additively loads the next (shared by the match
// start/end sequences).
private IEnumerator SwapScenes(string unloadSceneName, string loadSceneName)
{
var sm = _net.SceneManager;
@@ -1366,9 +1358,8 @@ public class MatchManager : MonoBehaviour
_net.SceneManager.OnSceneEvent -= OnEvt;
}
// Despawns each connected client's current avatar (if any) and spawns the prefab chosen by
// prefabFor at the given position. Used for both lobby->match (role variants) and match->lobby
// (neutral Player); the latter also gives spectator-held joiners their first avatar.
// Used for both lobby->match (role variants) and match->lobby (neutral Player); the latter also
// gives spectator-held joiners their first avatar.
private void RespawnAll(System.Func<ulong, GameObject> prefabFor, Vector3 at)
{
var ids = new List<ulong>(_net.ConnectedClientsIds);
@@ -1437,7 +1428,7 @@ public class MatchManager : MonoBehaviour
{
get
{
if (_net == null) return false;
if (!_net) return false;
if (_net.IsServer) return IsMatchAuthority(_net.LocalClientId);
return _isLocalAuthority;
}
@@ -1448,7 +1439,7 @@ public class MatchManager : MonoBehaviour
/// the authority or no match is running.</summary>
public void RequestEndMatch()
{
if (_net == null) return;
if (!_net) return;
if (_net.IsServer) { EndMatch(); return; } // EndMatch itself guards Phase == InMatch
if (_isLocalAuthority) RequestEndMatchFromServer();
}
@@ -1480,7 +1471,7 @@ public class MatchManager : MonoBehaviour
// so a single dummy byte is written).
private void SendEmptyNamedMessage(string messageName, ulong targetClientId)
{
var cmm = _net != null ? _net.CustomMessagingManager : null;
var cmm = _net ? _net.CustomMessagingManager : null;
if (cmm == null) return;
using (var writer = new FastBufferWriter(sizeof(byte), Allocator.Temp))
{
@@ -1506,7 +1497,7 @@ public class MatchManager : MonoBehaviour
// Server handler: an authority client asked to end the match.
private void OnRequestEndMatchMessage(ulong senderClientId, FastBufferReader reader)
{
if (_net == null || !_net.IsServer) return;
if (!_net || !_net.IsServer) return;
if (!IsMatchAuthority(senderClientId)) return;
EndMatch(); // guards Phase == InMatch itself
}
+9 -18
View File
@@ -5,25 +5,16 @@ using Chameleon.Components;
/// <summary>
/// A frozen, painted "statue" of a hider at the exact spot / stance / painting it held the moment it was
/// CONVERTED into a hunter (Conversion mode only). <see cref="MatchManager"/> captures those on the
/// conversion and spawns one statue per converted hider at the start of the Resolution phase, so every
/// player sees where each hider was caught as a faithful representation (same skinned body, camo painting
/// and fur) - independent of the now-hunter avatar, which has long since moved on.
/// CONVERTED into a hunter (Conversion mode only); <see cref="MatchManager"/> captures those on the
/// conversion and spawns one statue per converted hider at Resolution start. Purely presentational (no
/// controller / collision / role) and a dedicated prefab, NOT a <see cref="NetworkPlayerSetup"/> avatar -
/// so it never pollutes the scoreboard, per-client visibility matrix or resolution X-ray reveal.
///
/// Purely presentational: no controller, no collision, no gameplay role. It is a dedicated prefab (NOT a
/// <see cref="NetworkPlayerSetup"/> avatar), so it never pollutes the scoreboard, per-client visibility
/// matrix or resolution X-ray reveal - those all key off NetworkPlayerSetup, which the statue lacks.
///
/// Server-owned. Three replicated ingredients rebuild it identically on every client:
/// <list type="bullet">
/// <item><b>Transform</b> - the server Instantiates it at the captured pos/rot; the (server-authoritative)
/// NetworkTransform replicates that.</item>
/// <item><b>Painting</b> - rides the existing <see cref="PlayerPaintSync"/> snapshot transfer; this object
/// drives the push explicitly (server loads the captured snapshot, then broadcasts it), and PlayerPaintSync
/// suppresses its own auto pull/publish for a statue receiver so the two never race.</item>
/// <item><b>Stance</b> - a single replicated pose index the pose controller reproduces (network-driven),
/// then freezes.</item>
/// </list>
/// Server-owned; three replicated ingredients rebuild it identically on every client: transform
/// (server-authoritative NetworkTransform), painting (rides the existing <see cref="PlayerPaintSync"/>
/// snapshot transfer, pushed explicitly by the server - PlayerPaintSync suppresses its own auto
/// pull/publish for a statue receiver so the two never race) and stance (a replicated pose index the
/// pose controller reproduces, then freezes).
/// </summary>
[DisallowMultipleComponent]
public class MatchStatue : NetworkBehaviour
@@ -7,7 +7,6 @@ using Chameleon.Components;
/// Per-avatar network glue on the spawned player. The local owner binds the scene singletons
/// (GameModeManager, cameras) to itself via <see cref="GameModeManager.BindLocalPlayer"/>; remote
/// avatars stop simulating so their transform is driven purely by the NetworkTransform replication.
/// Position-sync milestone: remote avatars still show their mesh/idle pose, just no local control.
/// </summary>
[RequireComponent(typeof(PlayerCharacterController))]
[DisallowMultipleComponent]
@@ -297,7 +296,6 @@ public class NetworkPlayerSetup : NetworkBehaviour
SetBodyRenderers(visible);
}
// Toggles every body renderer and records the applied state for the change-guard above.
private void SetBodyRenderers(bool visible)
{
if (_bodyRenderers != null)
+12 -20
View File
@@ -9,25 +9,17 @@ using Unity.Services.Multiplayer;
using UnityEngine;
/// <summary>
/// Online hosting/joining over Unity Gaming Services so players can connect across the internet
/// without port forwarding. Uses the unified Multiplayer Services "Sessions" API, which bundles
/// Relay (NAT-free messaging via Unity's relay servers) + Lobby (the public server list) + anonymous
/// Authentication behind single calls, and configures + starts the NGO transport itself - so we do
/// NOT call <see cref="NetworkManager.StartHost"/>/<c>StartClient</c> here; CreateSessionAsync starts
/// the host and JoinSession* starts the client.
/// Online hosting/joining over Unity Gaming Services (unified Multiplayer "Sessions" API: Relay + Lobby +
/// anonymous Authentication behind single calls). The Sessions API configures and starts the NGO transport
/// itself, so we do NOT call <see cref="NetworkManager.StartHost"/>/<c>StartClient</c> here -
/// CreateSessionAsync starts the host, JoinSession* starts the client; the usual NetworkManager callbacks
/// then fire exactly as for loopback hosting, so MatchManager, spawning and authority are unaffected.
/// Note the UGS "session" (the public server-list entry) is distinct from the in-game "Lobby" scene.
///
/// Terminology: the UGS "session" is the entry in the public server list (network layer). It is a
/// different thing from the in-game "Lobby" scene (the pre-match staging area that <see cref="MatchManager"/>
/// loads after the connection is up). This component does not touch the match flow at all - the usual
/// NetworkManager callbacks fire exactly as they do for loopback hosting, so MatchManager, spawning and
/// authority are unaffected.
///
/// This is the logic layer only: state + async host/refresh/join/disconnect calls, surfaced through the
/// <see cref="Changed"/>/<see cref="SessionsChanged"/> events. The uGUI server browser that drives it lives
/// on its own canvas (<see cref="OnlineSessionBrowserUI"/>); this component carries no UI of its own.
/// Requires the project to be linked to a UGS cloud project (Project Settings > Services) with Relay,
/// Lobby and Authentication (Anonymous) enabled; otherwise sign-in fails with a clear status message.
/// Attach to the same GameObject as the NetworkManager.
/// Logic layer only, surfaced through the <see cref="Changed"/>/<see cref="SessionsChanged"/> events; the
/// uGUI browser driving it is <see cref="OnlineSessionBrowserUI"/>. Requires the project to be linked to a
/// UGS cloud project (Project Settings > Services) with Relay, Lobby and Authentication (Anonymous)
/// enabled; otherwise sign-in fails with a clear status message.
/// </summary>
[RequireComponent(typeof(NetworkManager))]
[DisallowMultipleComponent]
@@ -122,7 +114,7 @@ public class OnlineSessionManager : MonoBehaviour
Changed?.Invoke();
}
private async System.Threading.Tasks.Task EnsureSignedInAsync()
private async Task EnsureSignedInAsync()
{
if (UnityServices.State != ServicesInitializationState.Initialized)
{
@@ -156,7 +148,7 @@ public class OnlineSessionManager : MonoBehaviour
// Shared busy/sign-in/error skeleton around one session operation; the body carries the
// op-specific statuses and state. ownsConnection = the op starts NGO (host/join), so a timeout that
// left the transport half-up must tear it down.
private async System.Threading.Tasks.Task RunSessionOpAsync(string failLabel, bool ownsConnection, Func<System.Threading.Tasks.Task> body)
private async Task RunSessionOpAsync(string failLabel, bool ownsConnection, Func<Task> body)
{
SetBusy(true);
try
+5 -13
View File
@@ -2,19 +2,11 @@ using Unity.Netcode;
using UnityEngine;
/// <summary>
/// Replicates the visual body state that the disabled-on-remote controller / pose system would
/// otherwise drive: the owner publishes its selected pose index, resolved locomotion category
/// (idle / walk / run / fall) AND the wall-lean / ground-raise / ceiling mesh offset, so a remote
/// avatar shows the same pose, walk/run/fall animation and leans into walls / raises off the ground
/// like the owner — not just a sliding, upright idle.
///
/// Body position/rotation come from the NetworkTransform; this only carries the small extra state on
/// top. Pose index and locomotion change rarely (a pose cycle, a locomotion transition), so those
/// NetworkVariables send a delta only when the value actually changes. The mesh offset is the visual
/// model's child-local position (<see cref="PlayerCharacterController.MeshOffsetTarget"/>) — a tiny
/// vector the owner eases continuously; the remote eases onto the replicated value so it doesn't
/// tick-step (the body itself is already interpolated by the NetworkTransform).
///
/// Replicates the visual body state the disabled-on-remote controller / pose system would otherwise
/// drive: the owner publishes its pose index, resolved locomotion category and the wall-lean /
/// ground-raise mesh offset (<see cref="PlayerCharacterController.MeshOffsetTarget"/>), so a remote
/// avatar animates like the owner instead of sliding in an upright idle. Body position/rotation come
/// from the NetworkTransform; the remote eases onto the replicated mesh offset so it doesn't tick-step.
/// Runs after the PlayerPoseController (execution order 100) so the owner reads this frame's resolved
/// state; remote avatars apply via OnValueChanged / per-frame easing, independent of frame order.
/// </summary>
+1 -2
View File
@@ -607,7 +607,7 @@ public class PlayerPaintSync : NetworkBehaviour
CopyChunkInto(_snapBuffer, offset, chunk);
}
/// <summary>Copies a received chunk into the reassembly buffer, ignoring out-of-bounds offsets.</summary>
// Out-of-bounds offsets are ignored rather than thrown on.
private static void CopyChunkInto(byte[] buffer, int offset, byte[] chunk)
{
if (offset >= 0 && offset + chunk.Length <= buffer.Length)
@@ -693,7 +693,6 @@ public class PlayerPaintSync : NetworkBehaviour
_uploadBuffer = null;
}
/// <summary>All connected client ids except the given one (server-side).</summary>
private ulong[] OtherClientIds(ulong except)
{
var ids = NetworkManager.ConnectedClientsIds;
+4 -6
View File
@@ -2,12 +2,10 @@ using Unity.Netcode;
using UnityEngine;
/// <summary>
/// Per-avatar glue for a mid-match SPECTATOR. The spectator object is deliberately empty - no body, no
/// renderer, no collider, no controller - because the free-fly camera is a separate, persistent scene
/// object (in Main) that drives its own rig off Camera.main and needs nothing from this avatar. So the
/// spectator only has to exist as the owner's player object and flip the local mode set to free-cam-only.
/// The owner does that here; remote peers do nothing (there is no body to show or simulate). When the
/// host ends the match, MatchManager respawns this client as a neutral lobby Player.
/// Per-avatar glue for a mid-match SPECTATOR. The spectator object is deliberately empty (no body,
/// renderer, collider or controller) - the free-fly camera is a separate, persistent scene object in
/// Main, so this only has to exist as the owner's player object and flip the local mode set to
/// free-cam-only; remote peers do nothing. MatchManager respawns it as a lobby Player at match end.
/// </summary>
[DisallowMultipleComponent]
public class SpectatorSetup : NetworkBehaviour
+6 -9
View File
@@ -2,15 +2,12 @@ using TMPro;
using UnityEngine;
/// <summary>
/// On-screen match HUD binder: drives the authored <c>MatchHudCanvas</c> widgets from live match state -
/// the current sub-phase + countdown (top centre) and a hunter crosshair during the seek phase. The visual
/// layout lives in the scene; this component creates nothing at runtime, it only binds. Attach it to the
/// MatchHudCanvas and wire the references in the Inspector.
///
/// Passive overlay: the authored canvas has no <see cref="UnityEngine.UI.GraphicRaycaster"/> and every graphic
/// is raycastTarget=false, so it never consumes pointer events, and its sortingOrder (90) sits below PaintHud's
/// (100) so tool panels always win. There is no change event for the phase/timer, so the values are polled once
/// per frame; the visible strings are only rebuilt when the displayed second / phase actually changes.
/// Binds the authored <c>MatchHudCanvas</c> widgets to live match state (sub-phase + countdowns, role
/// counts, hunter crosshair); creates nothing at runtime. Passive overlay: the canvas has no
/// <see cref="UnityEngine.UI.GraphicRaycaster"/> and every graphic is raycastTarget=false, and its
/// sortingOrder (90) sits below PaintHud's (100) so tool panels always win. There is no change event for
/// the phase/timer, so values are polled per frame; the visible strings are only rebuilt when the
/// displayed second / phase actually changes.
/// </summary>
[DisallowMultipleComponent]
public class MatchHud : MonoBehaviour
@@ -8,24 +8,16 @@ using UnityEngine.InputSystem;
#endif
/// <summary>
/// uGUI binding for <see cref="OnlineSessionManager"/>. Drives the server-browser canvas - Host / Refresh /
/// pick a row / Join / Disconnect plus a status line - and mirrors the manager's state through its
/// <see cref="OnlineSessionManager.Changed"/> / <see cref="OnlineSessionManager.SessionsChanged"/> events.
/// Lives on the browser canvas; the session logic stays on the NetworkManager's
/// <see cref="OnlineSessionManager"/>.
/// uGUI binding for <see cref="OnlineSessionManager"/>: Host / Refresh / row select / Join / Disconnect
/// plus a status line, mirroring the manager through its <see cref="OnlineSessionManager.Changed"/> /
/// <see cref="OnlineSessionManager.SessionsChanged"/> events; the session logic stays on the manager.
///
/// Selection model: Refresh fills the list with clones of <see cref="entryTemplate"/> (each a clickable row
/// showing name + player count). Clicking a row selects it; Join connects to the selected session. While
/// connected, only Disconnect is interactable.
///
/// Overlay behaviour: the panel is always shown in Main (not connected). Once a connection is up it hides;
/// in the lobby/map Esc toggles it back as a modal pause overlay (cursor freed, local gameplay suspended via
/// <see cref="GameModeManager.SetPaused"/>). The Disconnect button is context-sensitive: in Main (not
/// connected) it is an application "Exit" (quits the build, or stops play mode in the editor) so the player
/// can leave without Alt+F4; on the map it becomes "Back to Lobby" for the match authority (ends the match);
/// everyone else (in the lobby, or a non-authority client on the map) gets a plain disconnect. Only the
/// visual <see cref="panelRoot"/> is toggled - this binder stays alive on its (always-active) canvas so it
/// keeps reading Esc while the panel is hidden.
/// The panel is always shown in Main (not connected); once a connection is up it hides, and in the
/// lobby/map Esc toggles it back as a modal pause overlay (cursor freed, gameplay suspended via
/// <see cref="GameModeManager.SetPaused"/>). The Disconnect button is context-sensitive: in Main it is an
/// application "Exit"; on the map it becomes "Back to Lobby" for the match authority (ends the match);
/// everyone else gets a plain disconnect. Only the visual <see cref="panelRoot"/> is toggled - this binder
/// stays alive on its (always-active) canvas so it keeps reading Esc while the panel is hidden.
/// </summary>
public class OnlineSessionBrowserUI : MonoBehaviour
{