using UnityEngine; using UnityEngine.UI; using Subsystems; using GeoSus.Client; using System.Collections.Generic; using System; using System.Linq; using TMPro; namespace Subsystems { /// /// Reads from GameManager_Network.State (the authoritative GameState) and drives /// all in-game canvas panels. No business logic lives here. /// public class GameManager_UI { private GameClient _gameClient; private GameState _state => GameManager.Instance?.networkSubsystem?.State; // ── Canvas refs (wired by BindClientScene from Client.unity) ────────── public Canvas ClientCreateJoinLobby; public Canvas ClientInLobby; public Canvas ClientLoadingScreen; public Canvas ClientGameScreen; // ── HUD element refs (resolved once in BindClientScene) ─────────────── private TMP_Text _roleText; private TMP_Text _taskListText; private TMP_Text _taskProgressText; private Button _actionButton; private TMP_Text _actionButtonText; private TMP_Text _killCooldownText; private GameObject _sabotagePanel; private TMP_Text _sabotageTimerText; private GameObject _meetingPanel; private TMP_Text _meetingHeader; private TMP_Text _meetingPhaseLabel; private TMP_Text _meetingPhaseCountdown; private Image _meetingPhaseProgressBar; private TMP_Text _myVoteIndicator; private GameObject _meetingScrollGO; private Transform _meetingScrollContent; private TMP_Text _meetingFallbackText; private GameObject _voteResultPanel; private TMP_Text _voteResultText; private Button _skipButton; private GameObject _gameEndPanel; private TMP_Text _gameEndText; private RectTransform _returnToLobbyBtn; private TMP_Text _toastText; private GameObject _toastGO; private GameObject _reconnectOverlay; // ── Internal state ──────────────────────────────────────────────────── private bool _isDead; private bool _commsBlackout; private DateTime _sabotageMeltdownDeadline; private bool _sabotageTimerActive; private volatile bool _lobbyDirty; // Meeting vote-row references rebuilt each meeting private readonly List _voteRows = new List(); private string _pendingVoteResultDisplay; // shown after voting private Coroutine _meetingCloseCoroutine; // tracked so phase changes can cancel it public GameManager_UI(GameClient gameClient) { _gameClient = gameClient; } public void NotifyLobbyChanged() => _lobbyDirty = true; public bool IsCommsBlackout => _commsBlackout; public bool IsPlayerDead => _isDead; // ── Scene binding ───────────────────────────────────────────────────── public void BindClientScene(Canvas createJoin, Canvas inLobby, Canvas loading, Canvas game) { ClientCreateJoinLobby = createJoin; ClientInLobby = inLobby; ClientLoadingScreen = loading; ClientGameScreen = game; foreach (var c in new[] { createJoin, inLobby, loading, game }) EnsureCanvasReady(c); if (createJoin) createJoin.gameObject.SetActive(false); if (inLobby) inLobby.gameObject.SetActive(false); if (loading) loading.gameObject.SetActive(false); if (game) game.gameObject.SetActive(false); if (game == null) return; var t = game.transform; _roleText = FindTMP(t, "Role"); _taskListText = FindTMP(t, "TaskList"); _taskProgressText = FindTMP(t, "TaskProgress"); _killCooldownText = FindTMP(t, "KillCooldown"); _sabotageTimerText = FindTMP(t, "SabotageTimer"); _gameEndText = FindTMP(t, "GameEndText"); _toastText = FindTMP(t, "Toast"); _meetingHeader = FindTMP(t, "MeetingHeader"); _meetingPhaseLabel = FindTMP(t, "MeetingPhaseLabel"); _meetingPhaseCountdown = FindTMP(t, "MeetingPhaseCountdown"); _myVoteIndicator = FindTMP(t, "MyVoteIndicator"); _meetingFallbackText = FindTMP(t, "MeetingPlayerList"); _voteResultText = FindTMP(t, "VoteResult"); _meetingScrollContent = FindTransform(t, "MeetingContent"); _meetingScrollGO = FindTransformGO(t, "_MeetingScroll"); var progressBarGO = FindTransformGO(t, "MeetingPhaseProgressBar"); if (progressBarGO != null) _meetingPhaseProgressBar = progressBarGO.GetComponent(); var skipGO = FindTransformGO(t, "SkipButton"); if (skipGO != null) _skipButton = skipGO.GetComponent