diff --git a/Assets/Scripts/GameModeManager.cs b/Assets/Scripts/GameModeManager.cs
index bdfe957..9cf7597 100644
--- a/Assets/Scripts/GameModeManager.cs
+++ b/Assets/Scripts/GameModeManager.cs
@@ -255,9 +255,15 @@ public class GameModeManager : MonoBehaviour
/// Pauses or resumes local gameplay for a full-screen modal overlay (the online session panel, opened
/// with Esc in the lobby/map). Pausing frees the OS cursor and suppresses ALL local input - movement,
/// painting, camera look and the mode-switch key - WITHOUT tearing down the mode cycle, so resuming
- /// re-enters the exact mode that was active and restores its camera/cursor state. It mirrors the
- /// cursor handling (Exit the active mode, then park the orbit rig in
- /// Disabled so it stops re-grabbing the cursor every frame) but is reversible. No-op if unchanged.
+ /// re-enters the exact mode that was active and restores its camera/cursor state.
+ ///
+ /// Crucially it does NOT Exit the active mode while pausing: the First-Person / Free-Cam rigs keep their
+ /// CinemachineCamera at its live priority, so the view stays frozen exactly where it is instead of
+ /// blending back to the orbit camera (the camera "jump" when the menu opened). Pausing therefore only
+ /// disables each rig's per-frame look input - dropping the controller's enabled freezes its look
+ /// without touching its priority - and parks the orbit rig in Disabled so it stops re-grabbing the cursor
+ /// every frame. Resuming re-runs the same mode's Enter(); because no priority was lowered, that mode's
+ /// snap-to-current-view is a no-op, so there is no jump on close either. No-op if unchanged.
///
public void SetPaused(bool paused)
{
@@ -267,14 +273,18 @@ public class GameModeManager : MonoBehaviour
if (paused)
{
_resumeIndex = _activeIndex;
- ActiveMode?.Exit(); // undo any FreeCam/First-Person takeover (also releases the cursor)
- _activeIndex = -1;
+ _activeIndex = -1; // bookkeeping: no live mode while paused (Tick won't run)
- // Painting and movement run off their own flags/Update loops and the orbit rig re-asserts the
- // cursor each frame from its LookMode, so stop them all explicitly, then free the cursor. A
- // Disabled look-mode keeps the cursor free every frame (the same trick ReleaseToNoPlayer uses).
+ // Freeze every input source but leave the active camera rig untouched (priority unchanged) so the
+ // view stays put. Painting/movement run off their own flags; the FP/freecam rigs drive their own
+ // CinemachineCamera each frame, so dropping their `enabled` freezes the look in place WITHOUT
+ // lowering priority; the orbit rig re-asserts the cursor each frame from its LookMode, so a
+ // Disabled look-mode keeps the cursor free every frame. At most one camera rig is ever enabled,
+ // so disabling both here is safe regardless of which mode was active.
if (player) player.ControlEnabled = false;
if (painter) painter.PaintingEnabled = false;
+ if (firstPerson) firstPerson.enabled = false;
+ if (freeCam) freeCam.enabled = false;
if (cameraInput)
{
cameraInput.enabled = true;
@@ -290,7 +300,14 @@ public class GameModeManager : MonoBehaviour
int resume = _resumeIndex;
_resumeIndex = -1;
if (resume >= 0 && resume < _modes.Count)
- SwitchTo(resume); // re-Enter restores player/painter/look + cursor (+ re-shows the HUD)
+ {
+ // Re-Enter the SAME mode (it was never Exited). The active rig still holds the current view,
+ // so Enter()'s sync-to-current-view is a no-op -> no jump. Enter restores control/painting/
+ // look + cursor and re-shows the HUD.
+ _activeIndex = resume;
+ ActiveMode.Enter();
+ ModeChanged?.Invoke(ActiveMode);
+ }
else
ModeChanged?.Invoke(ActiveMode);
}