using UnityEngine; using UnityEngine.UI; using TMPro; using System; using System.Linq; using System.Threading.Tasks; using GameServer.Client; public class SongDetailsUI : MonoBehaviour { [Header("this_song_SO")] public ScriptableObject this_song_SO; [Header("ranking")] public Button rankingButton; public rankingList rkl; [Header("room")] public Button roomButton; public GameObject askPrefab; public GameObject roomDetailsPrefab; public GameObject roomRankingPrefab; public Transform roomSpawnPoint; [Header("basic UI")] public Image song_bgImage; public Text songNameText; public Text artistNameText; public Text painterNameText; public Text difficultyText; public Text difficultyDesciptionText; public Text charterNameText; public Text dlcNameText; public TextMeshProUGUI bpmText; public Text songSerialNumberText; public Text personalRecordText; // Documentation text normalized. public Text chartScoreText; public Text thisSong_progressText; public Text thisSong_lastScoreText; // will show last run total score if available public Text idolRecordText; public TextMeshProUGUI timeSpentText; public TextMeshProUGUI enterTimeText; public Text difficultyIdText; public Image progressImage; public GameObject progressNumberObject; public TextMeshProUGUI progressPercentText; public Image rankLevel_img; public RankConfig rc; //public Image songImage; public int id_of_thisSong; [Header("Inspector")] public GameObject picDetail; public Image profound_image; public Text detail_informations_text; [Header("Inspector")] public Button Button_EZ; public Button Button_HD; public Button Button_IN; public Button Button_IM; private SongData currentSong; private GameObject spawnedAskInstance; private GameObject spawnedRoomDetailsInstance; private SongData ResolveCurrentSong() { if (currentSong != null) { return currentSong; } if (this_song_SO is SongData soSong) { currentSong = soSong; return currentSong; } if (SongDataHolder.SelectedSongData != null) { currentSong = SongDataHolder.SelectedSongData; return currentSong; } return null; } private void OnEnable() { currentSong = ResolveCurrentSong(); ArenaRoomService roomService = ArenaRoomService.Instance; if (roomService != null) { roomService.OnRoomSnapshotChanged -= HandleArenaRoomSnapshotChanged; roomService.OnRoomSnapshotChanged += HandleArenaRoomSnapshotChanged; HandleArenaRoomSnapshotChanged(roomService.CurrentRoom); } if (roomButton == null) { roomButton = FindButtonByName("roomButton"); } if (rankingButton != null) { rankingButton.onClick.RemoveListener(OnRankingButtonClicked); rankingButton.onClick.AddListener(OnRankingButtonClicked); } if (roomButton != null) { roomButton.onClick.RemoveListener(OnRoomButtonClicked); roomButton.onClick.AddListener(OnRoomButtonClicked); } } private void OnDisable() { ArenaRoomService roomService = ArenaRoomService.Instance; if (roomService != null) { roomService.OnRoomSnapshotChanged -= HandleArenaRoomSnapshotChanged; } if (rankingButton != null) { rankingButton.onClick.RemoveListener(OnRankingButtonClicked); } if (roomButton != null) { roomButton.onClick.RemoveListener(OnRoomButtonClicked); } } private void HandleArenaRoomSnapshotChanged(ArenaRoomSnapshot snapshot) { if (snapshot == null || string.IsNullOrWhiteSpace(snapshot.song_id)) { return; } if (!int.TryParse(snapshot.song_id, out int songId)) { Debug.LogWarning($"[SongDetailsUI] Invalid arena room song_id: {snapshot.song_id}"); return; } SongDataLibrary library = SongDataLibrary.Instance; if (library == null) { Debug.LogWarning("[SongDetailsUI] SongDataLibrary is not initialized."); return; } SongData roomSong = library.GetSongDataByID(songId); if (roomSong == null) { Debug.LogWarning($"[SongDetailsUI] Room song not found for song_id={songId}"); return; } int roomDifficultyId = ConvertDifficultyKeyToId(snapshot.difficulty); bool sameSong = currentSong != null && currentSong.songID == roomSong.songID; bool sameDifficulty = sameSong && currentSong.thisLevel_selectedDifficultyID == roomDifficultyId; if (sameSong && sameDifficulty) { return; } ApplySongSelection(roomSong, roomDifficultyId); } private void ApplySongSelection(SongData song, int difficultyId) { if (song == null) { return; } difficultyId = Mathf.Clamp(difficultyId, 0, 3); song.thisLevel_selectedDifficultyID = difficultyId; currentSong = song; this_song_SO = song; SongDataHolder.SelectedSongData = song; id_of_thisSong = song.songID; RefreshSongPresentation(song); SetDifficultyButtons(difficultyId); UpdateDifficultyUI(difficultyId); } private void RefreshSongPresentation(SongData song) { if (song == null) { return; } if (song_bgImage != null) song_bgImage.sprite = song.backgroudPIC; if (songNameText != null) songNameText.text = song.songName; if (artistNameText != null) artistNameText.text = song.artistName; if (painterNameText != null) painterNameText.text = song.painter; if (charterNameText != null) charterNameText.text = song.level_creator; if (dlcNameText != null) dlcNameText.text = song.belongsTo_whichDLC; if (songSerialNumberText != null) songSerialNumberText.text = song.songID.ToString(); if (bpmText != null) bpmText.text = "BPM : " + song.bpm.ToString(); if (profound_image != null) profound_image.sprite = song.fullscreen_songPicture; if (timeSpentText != null) timeSpentText.text = "PlayTime: " + song.time_totalPlayingTime.ToString("F0") + "s"; if (enterTimeText != null) enterTimeText.text = "PlayCount: " + song.game_enterTimes.ToString(); if (detail_informations_text != null) { detail_informations_text.text = $"{song.artistName} - {song.songName} | 曲绘: {song.painter} | 制谱: {song.level_creator} | DLC: {song.belongsTo_whichDLC}"; } } private int ConvertDifficultyKeyToId(string difficultyKey) { if (string.IsNullOrWhiteSpace(difficultyKey)) { return 2; } switch (difficultyKey.Trim().ToLowerInvariant()) { case "ez": return 0; case "hd": return 1; case "im": return 3; case "in": default: return 2; } } void Start() { if (SongDataHolder.SelectedSongData != null) { // Documentation text normalized. currentSong = SongDataHolder.SelectedSongData; this_song_SO = currentSong; song_bgImage.sprite = currentSong.backgroudPIC; // Documentation text normalized. songNameText.text = currentSong.songName; artistNameText.text = currentSong.artistName; painterNameText.text = currentSong.painter; charterNameText.text = currentSong.level_creator; dlcNameText.text = currentSong.belongsTo_whichDLC; songSerialNumberText.text = currentSong.songID.ToString(); bpmText.text = "BPM : " + currentSong.bpm.ToString(); profound_image.sprite = currentSong.fullscreen_songPicture; if (timeSpentText != null) timeSpentText.text = "PlayTime: " + currentSong.time_totalPlayingTime.ToString("F0") + "s"; if (enterTimeText != null) enterTimeText.text = "PlayCount: " + currentSong.game_enterTimes.ToString(); id_of_thisSong = currentSong.songID; detail_informations_text.text = $"{currentSong.artistName}" + " - " + $"{currentSong.songName}" + " | " + $"曲绘: {currentSong.painter}" + " | " + $"制谱: {currentSong.level_creator}" + " | " + $"DLC: {currentSong.belongsTo_whichDLC}"; if (currentSong.illustration != null) { //songImage.sprite = currentSong.illustration; //songImage.enabled = true; } else { Debug.LogWarning("歌曲封面为空:" + currentSong.songName); } Debug.Log("加载歌曲数据: " + currentSong.songName); } else { // Documentation text normalized. } picDetail.SetActive(false); // Documentation text normalized. if (currentSong != null) { SetDifficultyButtons(currentSong.thisLevel_selectedDifficultyID); UpdateDifficultyUI(currentSong.thisLevel_selectedDifficultyID); Button_EZ.onClick.AddListener(() => OnDifficultySelected(0)); Button_HD.onClick.AddListener(() => OnDifficultySelected(1)); Button_IN.onClick.AddListener(() => OnDifficultySelected(2)); Button_IM.onClick.AddListener(() => OnDifficultySelected(3)); } } public void OnRankingButtonClicked() { SongData song = ResolveCurrentSong(); if (song == null) { Debug.LogWarning("[SongDetailsUI] Ranking button clicked, but no song is currently selected."); return; } if (rkl == null) { Debug.LogWarning("[SongDetailsUI] Ranking button clicked, but rankingList reference is missing."); return; } rkl.Open(song.songID.ToString(), song.songName); } public async void OnRoomButtonClicked() { SongData song = ResolveCurrentSong(); if (song == null) { Debug.LogWarning("[SongDetailsUI] Room button clicked, but no song is currently selected."); return; } ArenaRoomService roomService = ArenaRoomService.Instance; if (roomService == null) { Debug.LogWarning("[SongDetailsUI] ArenaRoomService is missing."); return; } if (roomService.IsInRoom) { try { await roomService.RefreshRoomInfo(); ShowRoomDetails(roomService); } catch (Exception ex) { Debug.LogWarning($"[SongDetailsUI] Failed to refresh current room: {ex.Message}"); DestroyRoomDetailsInstance(); ShowRoomAsk(song, roomService); } return; } DestroyRoomDetailsInstance(); ShowRoomAsk(song, roomService); } public void OpenRoomDetailsForCurrentRoom() { ArenaRoomService roomService = ArenaRoomService.Instance; if (roomService == null || !roomService.IsInRoom) { return; } HandleArenaRoomSnapshotChanged(roomService.CurrentRoom); DestroyAskInstance(); ShowRoomDetails(roomService); } private void ShowRoomAsk(SongData song, ArenaRoomService roomService) { if (spawnedAskInstance != null) { Destroy(spawnedAskInstance); } GameObject askTemplate = ResolveAskTemplate(); if (askTemplate == null) { Debug.LogWarning("[SongDetailsUI] Ask prefab/template is missing."); return; } spawnedAskInstance = Instantiate(askTemplate, ResolveRoomSpawnParent(), false); PrepareSpawnedPanel(spawnedAskInstance); roomAsk ask = spawnedAskInstance.GetComponent(); if (ask == null) { Debug.LogWarning("[SongDetailsUI] Spawned ask object has no roomAsk component."); return; } ask.Bind( async () => { await roomService.CreateRoom( song.songID.ToString(), song.songName, ResolveSelectedDifficultyKey(song), null); try { await roomService.RefreshRoomInfo(); } catch (Exception ex) { Debug.LogWarning($"[SongDetailsUI] Refresh room info after create failed: {ex.Message}"); } DestroyAskInstance(); ShowRoomDetails(roomService); }, async roomCode => { await roomService.JoinRoom(roomCode, null); try { await roomService.RefreshRoomInfo(); } catch (Exception ex) { Debug.LogWarning($"[SongDetailsUI] Refresh room info after join failed: {ex.Message}"); } DestroyAskInstance(); ShowRoomDetails(roomService); }); } private void ShowRoomDetails(ArenaRoomService roomService) { if (spawnedRoomDetailsInstance != null) { roomDetails existing = spawnedRoomDetailsInstance.GetComponent(); if (existing != null) { existing.ConfigureRoomRanking(roomRankingPrefab, ResolveRoomSpawnParent()); existing.Bind(roomService); } return; } GameObject roomTemplate = ResolveRoomDetailsTemplate(); if (roomTemplate == null) { Debug.LogWarning("[SongDetailsUI] Room details prefab/template is missing."); return; } spawnedRoomDetailsInstance = Instantiate(roomTemplate, ResolveRoomSpawnParent(), false); PrepareSpawnedPanel(spawnedRoomDetailsInstance); roomDetails details = spawnedRoomDetailsInstance.GetComponent(); if (details == null) { Debug.LogWarning("[SongDetailsUI] Spawned room details object has no roomDetails component."); return; } details.ConfigureRoomRanking(roomRankingPrefab, ResolveRoomSpawnParent()); details.Bind(roomService); } private void DestroyAskInstance() { if (spawnedAskInstance != null) { Destroy(spawnedAskInstance); spawnedAskInstance = null; } } private void DestroyRoomDetailsInstance() { if (spawnedRoomDetailsInstance != null) { Destroy(spawnedRoomDetailsInstance); spawnedRoomDetailsInstance = null; } } private GameObject ResolveAskTemplate() { if (askPrefab != null) { return askPrefab; } roomAsk sceneTemplate = FindSceneObject(); if (sceneTemplate != null) { sceneTemplate.gameObject.SetActive(false); return sceneTemplate.gameObject; } return null; } private GameObject ResolveRoomDetailsTemplate() { if (roomDetailsPrefab != null) { return roomDetailsPrefab; } roomDetails sceneTemplate = FindSceneObject(); if (sceneTemplate != null) { sceneTemplate.gameObject.SetActive(false); return sceneTemplate.gameObject; } return null; } private Transform ResolveRoomSpawnParent() { if (roomSpawnPoint != null && roomSpawnPoint.gameObject.activeInHierarchy && roomSpawnPoint.lossyScale.sqrMagnitude > 0.0001f) { return roomSpawnPoint; } Canvas canvas = null; if (roomButton != null) { canvas = roomButton.GetComponentsInParent(true).FirstOrDefault(); } if (canvas == null) { canvas = GetComponentsInParent(true).FirstOrDefault(); } if (canvas != null) { return canvas.transform; } return transform; } private void PrepareSpawnedPanel(GameObject panel) { if (panel == null) { return; } panel.SetActive(true); RectTransform rect = panel.GetComponent(); if (rect != null) { rect.localScale = Vector3.one; rect.anchoredPosition3D = Vector3.zero; } } private Button FindButtonByName(string objectName) { Button[] buttons = Resources.FindObjectsOfTypeAll