Freeze hiders (pose + transform) during the resolution phase

While a match is in the resolution sub-phase, hiders that have not
been found hold their current pose and position: the pose graph is
frozen (mixer speed 0, current frame re-asserted) and owner input is
disabled while gravity/grounding keep them planted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 4.8 committed 2026-07-01 21:52:46 +02:00
1 parent 96528524a6
commit ff034870fc
2 files changed
+59

No files matched your search

+23
View File
@@ -156,6 +156,12 @@ public class PlayerPoseController : MonoBehaviour
/// <summary>Eased per-pose y-offset for the first-person eye, applied on top of the camera target by the FirstPersonController.</summary>
public float FirstPersonCameraYOffset => _firstPersonCameraOffset;
/// <summary>Holds the avatar on its current pose frame: the Playable graph stops advancing (its bones stay
/// exactly where they are) and all per-frame locomotion / rest-reset / capsule / camera work is skipped.
/// Set per-client for every still-in-play hider during the resolution reveal so nobody can wiggle in place.
/// Clearing it resumes normal playback. Independent of network drive — works on the owner and on remotes.</summary>
public bool Frozen { get; set; }
void Awake()
{
_player = GetComponent<PlayerCharacterController>();
@@ -169,6 +175,23 @@ public class PlayerPoseController : MonoBehaviour
void Update()
{
// Resolution freeze: hold the currently-evaluated pose. Keep the graph playing (so it re-asserts the
// frozen frame every render, even under Animator culling) but zero the mixer's speed so clip time
// stops advancing, and skip everything below so no locomotion/rest-reset moves a bone. The per-clip
// speeds PlayPose writes onto the mixer INPUTS are unaffected; only the mixer's own multiplier is
// zeroed here and restored on the first un-frozen frame just below.
if (Frozen)
{
if (_graph.IsValid())
{
if (!_graph.IsPlaying()) _graph.Play();
if (_mixer.IsValid()) PlayableExtensions.SetSpeed(_mixer, 0d);
}
return;
}
if (_mixer.IsValid() && PlayableExtensions.GetSpeed(_mixer) == 0d)
PlayableExtensions.SetSpeed(_mixer, 1d);
// Local control: the cycle key and the sprint reset choose the pose. A network-driven (remote)
// avatar skips this — its pose index is pushed in from the owner via SetNetworkState.
if (!_networkControlled)