Add player-collision toggle and make conversion statues follow it
Add a per-machine "Players Collide" switch on GameModeManager: a self-healing reconciler routes the local capsule through other avatars' body colliders via Physics.IgnoreCollision when disabled, re-asserting every frame while off to survive the late-created runtime MeshCollider, conversion respawns and teleport resets. Expose Active/ActiveVersion/ BodyCollider on NetworkPlayerSetup for the reconciler. Give MatchStatue the same Active registry + BodyCollider pattern so the frozen conversion statues obey the same toggle (they carry their own paint MeshCollider but are deliberately not NetworkPlayerSetup avatars). Also drive the statue's steady X-ray reveal in Resolution, matching an un-found hider. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
8bafa2f10a
commit
414beaa403
3 files changed
+142
-1
No files matched your search
@@ -1,3 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using Unity.Netcode;
|
||||
using UnityEngine;
|
||||
using Chameleon.Components;
|
||||
@@ -62,6 +63,8 @@ public class MatchStatue : NetworkBehaviour
|
||||
|
||||
public override void OnNetworkSpawn()
|
||||
{
|
||||
_active.Add(this); // player-collision registry (paired with OnNetworkDespawn)
|
||||
|
||||
_painter = GetComponentInChildren<MeshPainter>(true);
|
||||
_paintSync = GetComponentInChildren<PlayerPaintSync>(true);
|
||||
_pose = GetComponentInChildren<PlayerPoseController>(true);
|
||||
@@ -92,6 +95,35 @@ public class MatchStatue : NetworkBehaviour
|
||||
_freezeAt = Time.time + Mathf.Max(0f, poseSettle);
|
||||
}
|
||||
|
||||
public override void OnNetworkDespawn()
|
||||
{
|
||||
_active.Remove(this);
|
||||
}
|
||||
|
||||
// Statues carry their own runtime paint MeshCollider (MeshPainter bakes it), so the local player's capsule
|
||||
// bumps into them like any body - but they are NOT NetworkPlayerSetup avatars and so aren't in that registry.
|
||||
// Tracked here so GameModeManager's player-collision toggle can let the local player pass through statues
|
||||
// too: a statue is a frozen player representation, so it follows the same "players collide" switch.
|
||||
private static readonly List<MatchStatue> _active = new List<MatchStatue>();
|
||||
|
||||
/// <summary>Read-only view of the statues spawned on this machine. Consumed by the player-collision
|
||||
/// reconciler so the local player passes through statues when player collision is off.</summary>
|
||||
public static IReadOnlyList<MatchStatue> Active => _active;
|
||||
|
||||
// The runtime body MeshCollider (baked skinned mesh) the local capsule collides with. MeshPainter creates
|
||||
// it in Start - a frame after OnNetworkSpawn - so resolve it lazily and cache once it exists.
|
||||
private MeshCollider _bodyCollider;
|
||||
|
||||
/// <summary>This statue's body collider (the paint MeshCollider), or null until it has been created.</summary>
|
||||
public MeshCollider BodyCollider
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_bodyCollider) _bodyCollider = GetComponentInChildren<MeshCollider>(true);
|
||||
return _bodyCollider;
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// Server owner: once the painter is set up, load the captured snapshot and push it to every peer over
|
||||
@@ -108,7 +140,14 @@ public class MatchStatue : NetworkBehaviour
|
||||
// Reveal once the painting is applied locally: the server right after its load/publish, a client once
|
||||
// its received snapshot has caught up to the published baseline.
|
||||
bool paintReady = IsServer ? _hostPaintDone : (_paintSync && _paintSync.PaintRevealReady);
|
||||
if (paintReady && !_bodyShown) SetBodyVisible(true);
|
||||
if (paintReady && !_bodyShown)
|
||||
{
|
||||
SetBodyVisible(true);
|
||||
// See-through-walls X-ray glow, exactly like an un-found hider during Resolution. The statue only
|
||||
// ever exists in the resolution phase, so the reveal is steadily on (no just-shot flash). Raised
|
||||
// together with the body so the authored _XRayColor eases in alongside it (per-client, cosmetic).
|
||||
if (_painter) _painter.XRayRevealed = true;
|
||||
}
|
||||
|
||||
// Re-assert the stance until it has settled (covers a pose index arriving a frame late), then freeze.
|
||||
if (_pose && !_frozen)
|
||||
|
||||
@@ -124,6 +124,7 @@ public class NetworkPlayerSetup : NetworkBehaviour
|
||||
public override void OnNetworkSpawn()
|
||||
{
|
||||
_active.Add(this); // scoreboard registry (paired with OnNetworkDespawn)
|
||||
ActiveVersion++; // signal the player-collision reconciler that the avatar set changed
|
||||
_bodyRenderers = GetComponentsInChildren<SkinnedMeshRenderer>(true);
|
||||
_furRenderers = GetComponentsInChildren<FurShellRenderer>(true);
|
||||
_painter = GetComponentInChildren<MeshPainter>(true);
|
||||
@@ -193,6 +194,7 @@ public class NetworkPlayerSetup : NetworkBehaviour
|
||||
public override void OnNetworkDespawn()
|
||||
{
|
||||
_active.Remove(this);
|
||||
ActiveVersion++;
|
||||
_isFound.OnValueChanged -= OnFoundChanged;
|
||||
}
|
||||
|
||||
@@ -462,6 +464,29 @@ public class NetworkPlayerSetup : NetworkBehaviour
|
||||
// Conversion hit despawns the hider object and spawns a hunter one, so both sides update from the registry).
|
||||
private static readonly List<NetworkPlayerSetup> _active = new List<NetworkPlayerSetup>();
|
||||
|
||||
/// <summary>Read-only view of all avatars spawned on this machine (the same registry the scoreboard uses).
|
||||
/// Consumed by the player-collision reconciler to find the bodies the local player should pass through.</summary>
|
||||
public static IReadOnlyList<NetworkPlayerSetup> Active => _active;
|
||||
|
||||
/// <summary>Bumped on every spawn/despawn so a per-frame consumer can cheaply detect a membership change
|
||||
/// without rescanning the list.</summary>
|
||||
public static int ActiveVersion { get; private set; }
|
||||
|
||||
// The runtime body MeshCollider (baked skinned mesh) other players' capsules collide with. MeshPainter
|
||||
// creates it in Start - a frame after OnNetworkSpawn - so resolve it lazily and cache once it exists.
|
||||
private MeshCollider _bodyCollider;
|
||||
|
||||
/// <summary>This avatar's body collider (the paint MeshCollider), or null until it has been created.
|
||||
/// Cached on first successful resolve.</summary>
|
||||
public MeshCollider BodyCollider
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_bodyCollider) _bodyCollider = GetComponentInChildren<MeshCollider>(true);
|
||||
return _bodyCollider;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void CountRoles(out int hunters, out int hiders)
|
||||
{
|
||||
hunters = 0;
|
||||
|
||||
Reference in new issue
Block a user