很多更新,服务端连接,新UI和系统
This commit is contained in:
@@ -0,0 +1,544 @@
|
||||
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<roomPrefab>();
|
||||
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<RectTransform>();
|
||||
if (rect != null)
|
||||
{
|
||||
rect.localScale = Vector3.one;
|
||||
rect.anchoredPosition3D = Vector3.zero;
|
||||
}
|
||||
}
|
||||
|
||||
rankingListPrefab ranking = _spawnedRoomRankingInstance.GetComponent<rankingListPrefab>();
|
||||
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<Text>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user