Spawn hider statues in resolution phase for classic mode too
Classic hit path now captures a statue record like conversion does; rename the statue infrastructure (CaptureStatue/SpawnStatues/ DespawnStatues/_statueRecords) since it is no longer conversion-only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
14015d7134
commit
a2a0e85831
2 files changed
+34
-30
No files matched your search
@@ -321,11 +321,11 @@ public class MatchManager : MonoBehaviour
|
||||
private int _loadGenerationClient;
|
||||
private Coroutine _clientLoadPoll;
|
||||
|
||||
// Server-only. Conversion statues: a snapshot of each converted hider (spot / stance / painting) captured
|
||||
// on the conversion, materialized as frozen statue objects only at the start of Resolution and despawned
|
||||
// when the match ends. Only populated in Conversion mode (ConvertToHunter is the sole capture site).
|
||||
// Server-only. Statues: a snapshot of each hit hider (spot / stance / painting) captured on the hit
|
||||
// (Conversion convert / Classic found), materialized as frozen statue objects only at the start of
|
||||
// Resolution and despawned when the match ends.
|
||||
private class StatueRecord { public Vector3 pos; public Quaternion rot; public int poseIndex; public byte[] paint; }
|
||||
private readonly List<StatueRecord> _conversionRecords = new List<StatueRecord>();
|
||||
private readonly List<StatueRecord> _statueRecords = new List<StatueRecord>();
|
||||
private readonly List<NetworkObject> _statues = new List<NetworkObject>();
|
||||
|
||||
// Server-only. Per-participant outcome records for the running match, keyed by clientId. Created on match
|
||||
@@ -496,7 +496,7 @@ public class MatchManager : MonoBehaviour
|
||||
_clientLoadPoll = null;
|
||||
// Teardown unloads the gameplay scenes (destroys the statue objects); just drop our references.
|
||||
_statues.Clear();
|
||||
_conversionRecords.Clear();
|
||||
_statueRecords.Clear();
|
||||
_matchRecords.Clear();
|
||||
if (_net) UnhookSessionCallbacks();
|
||||
|
||||
@@ -717,7 +717,7 @@ public class MatchManager : MonoBehaviour
|
||||
|
||||
private IEnumerator MatchSequence(HashSet<ulong> hunterIds)
|
||||
{
|
||||
_conversionRecords.Clear(); // fresh match inherits no stale statue captures (EndMatch also clears)
|
||||
_statueRecords.Clear(); // fresh match inherits no stale statue captures (EndMatch also clears)
|
||||
|
||||
// One outcome record per participant. Survived is the pending-hider default (flips on a hit /
|
||||
// disconnect); names are resolved later - the freshly respawned avatars' name NetworkVariables
|
||||
@@ -774,14 +774,14 @@ public class MatchManager : MonoBehaviour
|
||||
// (which was already live during the match).
|
||||
FinalizeMatchResults();
|
||||
|
||||
// Conversion mode: materialize a frozen statue of every converted hider at its capture spot. The last
|
||||
// hider is often still converting (its statue's painting hasn't replicated to every client yet), so
|
||||
// Materialize a frozen statue of every hit hider (converted / found) at its capture spot. The last
|
||||
// hider is often still resolving (its statue's painting hasn't replicated to every client yet), so
|
||||
// hold the Resolution countdown - frozen at 0:00, exactly like the pre-match loading barrier - until
|
||||
// every client has each statue spawned & painted. Then release the timer. No statue prefab / no
|
||||
// conversions / Classic -> no hold, the countdown starts immediately (unchanged behaviour).
|
||||
bool holdForStatues = statuePrefab && _conversionRecords.Count > 0;
|
||||
// hits -> no hold, the countdown starts immediately (unchanged behaviour).
|
||||
bool holdForStatues = statuePrefab && _statueRecords.Count > 0;
|
||||
SetPhaseServer(MatchSubPhase.Resolution, holdForStatues ? 0f : resolveDuration);
|
||||
SpawnConversionStatues();
|
||||
SpawnStatues();
|
||||
if (holdForStatues)
|
||||
{
|
||||
yield return RunStatueBarrier();
|
||||
@@ -1308,6 +1308,10 @@ public class MatchManager : MonoBehaviour
|
||||
ConvertToHunter(hiderClientId, c.PlayerObject);
|
||||
else
|
||||
{
|
||||
// Classic: snapshot the spot/stance/painting too, so Resolution shows a statue of every
|
||||
// found hider (the found avatar itself stays hidden - its owner is free-cam spectating).
|
||||
CaptureStatue(c.PlayerObject.transform.position, c.PlayerObject.transform.rotation,
|
||||
c.PlayerObject);
|
||||
var setup = c.PlayerObject.GetComponent<NetworkPlayerSetup>();
|
||||
if (setup) setup.ServerMarkFound();
|
||||
}
|
||||
@@ -1331,8 +1335,8 @@ public class MatchManager : MonoBehaviour
|
||||
Vector3 pos = current.transform.position;
|
||||
Quaternion rot = current.transform.rotation;
|
||||
// Snapshot the hider's spot / stance / painting NOW, before it despawns - a frozen statue is
|
||||
// materialized from this at the start of Resolution (see SpawnConversionStatues).
|
||||
CaptureConversionStatue(pos, rot, current);
|
||||
// materialized from this at the start of Resolution (see SpawnStatues).
|
||||
CaptureStatue(pos, rot, current);
|
||||
current.Despawn(true);
|
||||
|
||||
var go = Instantiate(hunterPrefab, pos, rot);
|
||||
@@ -1343,11 +1347,11 @@ public class MatchManager : MonoBehaviour
|
||||
go.GetComponent<NetworkObject>().SpawnAsPlayerObject(clientId);
|
||||
}
|
||||
|
||||
// Server-only. Captures a converting hider's spot / stance / painting so a frozen statue can be
|
||||
// materialized from it at Resolution. Skipped entirely when no statue prefab is assigned. The painting
|
||||
// is captured from the SERVER's own replica (the host holds the full paint via the live stream); a
|
||||
// capture miss stores a null snapshot -> the statue simply stays on the blank seed look.
|
||||
private void CaptureConversionStatue(Vector3 pos, Quaternion rot, NetworkObject hider)
|
||||
// Server-only. Captures a hit hider's spot / stance / painting (Conversion convert AND Classic found) so
|
||||
// a frozen statue can be materialized from it at Resolution. Skipped entirely when no statue prefab is
|
||||
// assigned. The painting is captured from the SERVER's own replica (the host holds the full paint via the
|
||||
// live stream); a capture miss stores a null snapshot -> the statue simply stays on the blank seed look.
|
||||
private void CaptureStatue(Vector3 pos, Quaternion rot, NetworkObject hider)
|
||||
{
|
||||
if (!statuePrefab) return;
|
||||
|
||||
@@ -1359,17 +1363,17 @@ public class MatchManager : MonoBehaviour
|
||||
var painter = hider.GetComponentInChildren<MeshPainter>(true);
|
||||
if (painter) painter.TryCaptureSnapshot(out paint);
|
||||
|
||||
_conversionRecords.Add(new StatueRecord { pos = pos, rot = rot, poseIndex = poseIndex, paint = paint });
|
||||
_statueRecords.Add(new StatueRecord { pos = pos, rot = rot, poseIndex = poseIndex, paint = paint });
|
||||
}
|
||||
|
||||
// Server-only. Spawns one frozen statue per captured conversion at its recorded pos/rot, handing each the
|
||||
// stance + painting snapshot before it spawns (server-owned, non-player). Called once at Resolution start;
|
||||
// the records are consumed here. No-op with no prefab / no records (Classic never records any).
|
||||
private void SpawnConversionStatues()
|
||||
// the records are consumed here. No-op with no prefab / no records (no hider was hit).
|
||||
private void SpawnStatues()
|
||||
{
|
||||
if (!statuePrefab || _conversionRecords.Count == 0) return;
|
||||
if (!statuePrefab || _statueRecords.Count == 0) return;
|
||||
|
||||
foreach (var rec in _conversionRecords)
|
||||
foreach (var rec in _statueRecords)
|
||||
{
|
||||
var go = Instantiate(statuePrefab, rec.pos, rec.rot);
|
||||
var statue = go.GetComponent<MatchStatue>();
|
||||
@@ -1386,10 +1390,10 @@ public class MatchManager : MonoBehaviour
|
||||
Destroy(go);
|
||||
}
|
||||
}
|
||||
_conversionRecords.Clear();
|
||||
_statueRecords.Clear();
|
||||
}
|
||||
|
||||
private void DespawnConversionStatues()
|
||||
private void DespawnStatues()
|
||||
{
|
||||
for (int i = 0; i < _statues.Count; i++)
|
||||
{
|
||||
@@ -1575,8 +1579,8 @@ public class MatchManager : MonoBehaviour
|
||||
// the replicated sub-phase so every client drops its match HUD/visibility before the scene swaps.
|
||||
if (_phaseRoutine != null) { StopCoroutine(_phaseRoutine); _phaseRoutine = null; }
|
||||
_pendingHiders.Clear();
|
||||
DespawnConversionStatues(); // drop any Resolution statues before the map unloads
|
||||
_conversionRecords.Clear(); // and any captures from a match ended before Resolution
|
||||
DespawnStatues(); // drop any Resolution statues before the map unloads
|
||||
_statueRecords.Clear(); // and any captures from a match ended before Resolution
|
||||
_matchRecords.Clear(); // and the outcome records (the None broadcast clears every client's mirror)
|
||||
SetPhaseServer(MatchSubPhase.None, 0f);
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ 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 Resolution start. Purely presentational (no
|
||||
/// hit (Conversion: converted into a hunter; Classic: marked found); <see cref="MatchManager"/> captures
|
||||
/// those on the hit and spawns one statue per hit 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.
|
||||
///
|
||||
@@ -24,7 +24,7 @@ public class MatchStatue : NetworkBehaviour
|
||||
[Min(0f)]
|
||||
[SerializeField] private float poseSettle = 0.35f;
|
||||
|
||||
// Server-only handoff from MatchManager.SpawnConversionStatues, consumed in OnNetworkSpawn / the first
|
||||
// Server-only handoff from MatchManager.SpawnStatues, consumed in OnNetworkSpawn / the first
|
||||
// ready frame. The paint may be null (capture failed) -> the statue stays on the blank seed look.
|
||||
private byte[] _serverPaint;
|
||||
private int _serverPoseIndex;
|
||||
|
||||
Reference in new issue
Block a user