Toggle session panel with Escape as in-game pause overlay

- Panel shows in Main while disconnected, auto-hides once a connection is
  established, and toggles open/closed with Escape in the Lobby or on a Map.
- Escape now pauses gameplay (active mode exits, cursor freed, paint and
  movement disabled) instead of ending the match directly; closing restores
  the prior mode via SwitchTo.
- Disconnect button is context-aware: leaves the session in the Lobby, acts
  as "Back to Lobby" (EndMatch) for the match authority on a Map, and stays a
  plain disconnect for non-authority clients on a Map.
- Removed the Escape->EndMatch handler from MatchManager; match end now routes
  through RequestEndMatch with the same authority routing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 4.8 committed 2026-06-28 11:34:13 +02:00
1 parent d27ee16004
commit cdfec364b2
4 files changed
+248 -51

No files matched your search

+61
View File
@@ -63,6 +63,11 @@ public class GameModeManager : MonoBehaviour
private readonly List<GameMode> _modes = new List<GameMode>();
private int _activeIndex = -1;
private bool _paused;
private int _resumeIndex = -1;
/// <summary>True while local gameplay is suspended for a modal overlay (see <see cref="SetPaused"/>).</summary>
public bool IsPaused => _paused;
/// <summary>The currently active mode (null before startup).</summary>
public GameMode ActiveMode =>
@@ -145,6 +150,9 @@ public class GameModeManager : MonoBehaviour
/// </summary>
public void BindSpectator()
{
_paused = false;
_resumeIndex = -1;
player = null;
painter = null;
PainterChanged?.Invoke(null);
@@ -165,6 +173,10 @@ public class GameModeManager : MonoBehaviour
{
if (!localPlayer) return;
// A fresh bind is a definitive state reset - drop any modal pause so the new avatar starts live.
_paused = false;
_resumeIndex = -1;
var setup = localPlayer.GetComponent<NetworkPlayerSetup>();
player = localPlayer;
@@ -216,6 +228,9 @@ public class GameModeManager : MonoBehaviour
/// </summary>
public void ReleaseToNoPlayer()
{
_paused = false;
_resumeIndex = -1;
ActiveMode?.Exit();
_activeIndex = -1;
_modes.Clear();
@@ -236,8 +251,54 @@ public class GameModeManager : MonoBehaviour
Cursor.visible = true;
}
/// <summary>
/// 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
/// <see cref="ReleaseToNoPlayer"/> 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.
/// </summary>
public void SetPaused(bool paused)
{
if (paused == _paused) return;
_paused = paused;
if (paused)
{
_resumeIndex = _activeIndex;
ActiveMode?.Exit(); // undo any FreeCam/First-Person takeover (also releases the cursor)
_activeIndex = -1;
// 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).
if (player) player.ControlEnabled = false;
if (painter) painter.PaintingEnabled = false;
if (cameraInput)
{
cameraInput.enabled = true;
cameraInput.LookMode = ThirdPersonOrbitInput.OrbitLookMode.Disabled;
}
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
ModeChanged?.Invoke(null); // hide mode-following UI (the paint HUD) beneath the overlay
}
else
{
int resume = _resumeIndex;
_resumeIndex = -1;
if (resume >= 0 && resume < _modes.Count)
SwitchTo(resume); // re-Enter restores player/painter/look + cursor (+ re-shows the HUD)
else
ModeChanged?.Invoke(ActiveMode);
}
}
private void Update()
{
if (_paused) return;
if (_modes.Count == 0) return;
if (WasSwitchPressed())