using System; using System.Collections; using Bansonic; using GameServer.Client; using UnityEngine; using UnityEngine.UI; public class roomDetails : MonoBehaviour { [Header("room Info")] public Text roomID; public Text roomRemainTime; public Button quitRoom; public Button quitRoom2; public Button getReady; public Button showRoomRankingList; [Header("song info")] public Text thisSongName; public Text thisSongDifficulty; [Header("objs")] public GameObject roommatePrefab; public Transform roommateParent; [Header("sprites")] public Sprite[] btmSprites; private ArenaRoomService _service; private Coroutine _countdownRoutine; private GameObject _roomRankingPrefabTemplate; private Transform _roomRankingSpawnParent; private GameObject _spawnedRoomRankingInstance; public void ConfigureRoomRanking(GameObject roomRankingPrefab, Transform roomRankingSpawnParent) { _roomRankingPrefabTemplate = roomRankingPrefab; _roomRankingSpawnParent = roomRankingSpawnParent; } public void Bind(ArenaRoomService service) { _service = service; if (_service == null) { Debug.LogWarning("[roomDetails] ArenaRoomService is missing."); return; } _service.OnRoomSnapshotChanged -= HandleRoomSnapshotChanged; _service.OnRoomSnapshotChanged += HandleRoomSnapshotChanged; _service.OnKicked -= HandleKicked; _service.OnKicked += HandleKicked; _service.OnRoomDismissed -= HandleRoomDismissed; _service.OnRoomDismissed += HandleRoomDismissed; if (quitRoom != null) { quitRoom.onClick.RemoveListener(OnQuitClicked); quitRoom.onClick.AddListener(OnQuitClicked); } if (quitRoom2 != null) { quitRoom2.onClick.RemoveListener(OnQuitClicked); quitRoom2.onClick.AddListener(OnQuitClicked); } if (getReady != null) { getReady.onClick.RemoveListener(OnReadyButtonClicked); getReady.onClick.AddListener(OnReadyButtonClicked); } if (showRoomRankingList != null) { showRoomRankingList.onClick.RemoveListener(OnShowRoomRankingClicked); showRoomRankingList.onClick.AddListener(OnShowRoomRankingClicked); } Refresh(_service.CurrentRoom); } private void OnDestroy() { if (_service != null) { _service.OnRoomSnapshotChanged -= HandleRoomSnapshotChanged; _service.OnKicked -= HandleKicked; _service.OnRoomDismissed -= HandleRoomDismissed; } if (quitRoom != null) { quitRoom.onClick.RemoveListener(OnQuitClicked); } if (quitRoom2 != null) { quitRoom2.onClick.RemoveListener(OnQuitClicked); } if (getReady != null) { getReady.onClick.RemoveListener(OnReadyButtonClicked); } if (showRoomRankingList != null) { showRoomRankingList.onClick.RemoveListener(OnShowRoomRankingClicked); } if (_countdownRoutine != null) { StopCoroutine(_countdownRoutine); _countdownRoutine = null; } if (_spawnedRoomRankingInstance != null) { Destroy(_spawnedRoomRankingInstance); _spawnedRoomRankingInstance = null; } } private void HandleRoomSnapshotChanged(ArenaRoomSnapshot snapshot) { if (snapshot == null) { Destroy(gameObject); return; } Refresh(snapshot); } private void HandleKicked(string kickedSteamId, string bySteamId) { Destroy(gameObject); } private void HandleRoomDismissed(string roomCode, string bySteamId) { Destroy(gameObject); } private async void OnQuitClicked() { if (_service == null) { Destroy(gameObject); return; } try { string localSteamId = NetworkManager.Instance != null ? NetworkManager.Instance.SteamId : string.Empty; bool localIsHost = IsLocalHost(_service.CurrentRoom, localSteamId); if (localIsHost) { await _service.DismissRoom(); } else { await _service.LeaveRoom(); } } catch (Exception ex) { Debug.LogWarning($"[roomDetails] Leave room failed: {ex.Message}"); } finally { Destroy(gameObject); } } private void Refresh(ArenaRoomSnapshot snapshot) { if (snapshot == null) { return; } if (roomID != null) { roomID.text = snapshot.room_code; } if (thisSongName != null) { thisSongName.text = !string.IsNullOrWhiteSpace(snapshot.song_name) ? snapshot.song_name : snapshot.song_id ?? string.Empty; } if (thisSongDifficulty != null) { thisSongDifficulty.text = FormatDifficulty(snapshot.difficulty); } if (_countdownRoutine != null) { StopCoroutine(_countdownRoutine); } _countdownRoutine = StartCoroutine(UpdateRemainTime(snapshot)); UpdateQuitButtonTexts(snapshot); UpdateReadyButton(snapshot); RenderParticipants(snapshot); } private IEnumerator UpdateRemainTime(ArenaRoomSnapshot snapshot) { while (snapshot != null && roomRemainTime != null) { long nowUnix = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); long remainSeconds = Math.Max(0L, snapshot.expires_at_unix - nowUnix); int remainMinutes = Mathf.CeilToInt(remainSeconds / 60f); roomRemainTime.text = $"{remainMinutes}分钟内不开始游戏将自动关闭房间"; yield return new WaitForSeconds(1f); } } private void RenderParticipants(ArenaRoomSnapshot snapshot) { if (roommateParent == null || roommatePrefab == null) { return; } for (int i = roommateParent.childCount - 1; i >= 0; i--) { Destroy(roommateParent.GetChild(i).gameObject); } string localSteamId = _service != null && NetworkManager.Instance != null ? NetworkManager.Instance.SteamId : string.Empty; bool localIsHost = IsLocalHost(snapshot, localSteamId); if (snapshot.participants == null) { return; } for (int i = 0; i < snapshot.participants.Count; i++) { ArenaRoomParticipant participant = snapshot.participants[i]; GameObject item = Instantiate(roommatePrefab, roommateParent); roomPrefab itemController = item.GetComponent(); if (itemController == null) { continue; } Sprite background = null; if (participant != null && participant.is_host) { if (btmSprites != null && btmSprites.Length > 0) { background = btmSprites[0]; } } else if (btmSprites != null && btmSprites.Length > 1) { background = btmSprites[1]; } itemController.Bind(participant, i + 1, localIsHost, localSteamId, background, HandleKickRequested); } } private async void HandleKickRequested(string targetSteamId) { if (_service == null || string.IsNullOrWhiteSpace(targetSteamId)) { return; } try { await _service.KickPlayer(targetSteamId); } catch (Exception ex) { Debug.LogWarning($"[roomDetails] Kick failed: {ex.Message}"); } } private async void OnReadyButtonClicked() { if (_service == null || _service.CurrentRoom == null) { return; } try { string localSteamId = NetworkManager.Instance != null ? NetworkManager.Instance.SteamId : string.Empty; bool localIsHost = IsLocalHost(_service.CurrentRoom, localSteamId); if (localIsHost) { if (CanHostStartGame(_service.CurrentRoom)) { await _service.StartGame(); } } else { await _service.ToggleReady(); } } catch (Exception ex) { Debug.LogWarning($"[roomDetails] Ready/start failed: {ex.Message}"); } } private void OnShowRoomRankingClicked() { if (_service == null) { return; } GameObject template = _roomRankingPrefabTemplate; Transform parent = _roomRankingSpawnParent != null ? _roomRankingSpawnParent : transform.parent; if (template == null || parent == null) { Debug.LogWarning("[roomDetails] Room ranking prefab or parent is missing."); return; } if (_spawnedRoomRankingInstance == null) { _spawnedRoomRankingInstance = Instantiate(template, parent, false); RectTransform rect = _spawnedRoomRankingInstance.GetComponent(); if (rect != null) { rect.localScale = Vector3.one; rect.anchoredPosition3D = Vector3.zero; } } rankingListPrefab ranking = _spawnedRoomRankingInstance.GetComponent(); if (ranking == null) { Debug.LogWarning("[roomDetails] Room ranking prefab is missing rankingListPrefab component."); return; } ArenaRoomSnapshot snapshot = _service.CurrentRoom; LeaderboardData roomRanking = _service.GetRoomRankingLeaderboardData(); string localSteamId = NetworkManager.Instance != null ? NetworkManager.Instance.SteamId : string.Empty; ranking.BindRoomRanking( snapshot != null ? snapshot.song_id : string.Empty, snapshot != null ? snapshot.song_name : string.Empty, roomRanking, localSteamId); } private void UpdateQuitButtonTexts(ArenaRoomSnapshot snapshot) { string localSteamId = NetworkManager.Instance != null ? NetworkManager.Instance.SteamId : string.Empty; bool localIsHost = IsLocalHost(snapshot, localSteamId); string buttonText = localIsHost ? "解散房间" : "退出房间"; SetButtonText(quitRoom, buttonText); SetButtonText(quitRoom2, buttonText); } private void UpdateReadyButton(ArenaRoomSnapshot snapshot) { if (getReady == null) { return; } string localSteamId = NetworkManager.Instance != null ? NetworkManager.Instance.SteamId : string.Empty; bool localIsHost = IsLocalHost(snapshot, localSteamId); int readyCount = CountReadyPlayers(snapshot); int totalCount = snapshot != null ? Mathf.Max(snapshot.player_count, snapshot.participants != null ? snapshot.participants.Count : 0) : 0; bool roomStarted = IsRoomStarted(snapshot); string buttonText; bool interactable; if (localIsHost) { buttonText = $"开始游戏({readyCount}/{totalCount})"; interactable = !roomStarted && CanHostStartGame(snapshot); } else { bool localReady = IsLocalReady(snapshot, localSteamId); buttonText = localReady ? "取消准备" : "准备"; interactable = !roomStarted; } getReady.interactable = interactable; SetButtonText(getReady, buttonText); } private static bool IsLocalHost(ArenaRoomSnapshot snapshot, string localSteamId) { if (snapshot == null || string.IsNullOrWhiteSpace(localSteamId)) { return false; } if (string.Equals(snapshot.host_steam_id, localSteamId, StringComparison.Ordinal)) { return true; } if (snapshot.participants == null) { return false; } foreach (ArenaRoomParticipant participant in snapshot.participants) { if (participant != null && string.Equals(participant.steam_id, localSteamId, StringComparison.Ordinal) && participant.is_host) { return true; } } return false; } private static bool IsLocalReady(ArenaRoomSnapshot snapshot, string localSteamId) { if (snapshot == null || snapshot.participants == null || string.IsNullOrWhiteSpace(localSteamId)) { return false; } foreach (ArenaRoomParticipant participant in snapshot.participants) { if (participant != null && string.Equals(participant.steam_id, localSteamId, StringComparison.Ordinal)) { return participant.is_ready; } } return false; } private static int CountReadyPlayers(ArenaRoomSnapshot snapshot) { if (snapshot == null || snapshot.participants == null) { return 0; } int count = 0; foreach (ArenaRoomParticipant participant in snapshot.participants) { if (participant != null && participant.is_ready) { count++; } } return count; } private static bool CanHostStartGame(ArenaRoomSnapshot snapshot) { if (snapshot == null || snapshot.participants == null || snapshot.participants.Count < 2) { return false; } foreach (ArenaRoomParticipant participant in snapshot.participants) { if (participant == null) { continue; } if (!participant.is_host && !participant.is_ready) { return false; } } return true; } private static bool IsRoomStarted(ArenaRoomSnapshot snapshot) { if (snapshot == null || string.IsNullOrWhiteSpace(snapshot.status)) { return false; } return string.Equals(snapshot.status, "STARTED", StringComparison.OrdinalIgnoreCase) || string.Equals(snapshot.status, "PLAYING", StringComparison.OrdinalIgnoreCase); } private static void SetButtonText(Button button, string text) { if (button == null) { return; } Text label = button.GetComponentInChildren(true); if (label != null) { label.text = text; } } private static string FormatDifficulty(string difficulty) { if (string.IsNullOrWhiteSpace(difficulty)) { return string.Empty; } switch (difficulty.Trim().ToLowerInvariant()) { case "ez": return "EZ"; case "hd": return "HD"; case "in": return "IN"; case "im": return "IM"; default: return difficulty; } } }