修了不少东西
This commit is contained in:
@@ -38,6 +38,10 @@ public class roomDetails : MonoBehaviour
|
||||
public Text thisSongName;
|
||||
public Text thisSongDifficulty;
|
||||
|
||||
[Header("change songs")]
|
||||
public Dropdown songDropdown;
|
||||
public Dropdown difficultyDropdown;
|
||||
|
||||
[Header("objs")]
|
||||
public GameObject roommatePrefab;
|
||||
public Transform roommateParent;
|
||||
@@ -82,6 +86,11 @@ public class roomDetails : MonoBehaviour
|
||||
private readonly List<RectTransform> _pendingMessageLayoutDirtyRoots = new List<RectTransform>();
|
||||
private Coroutine _refocusChatInputCoroutine;
|
||||
private bool _refocusChatInputRequested;
|
||||
private readonly List<SongData> _selectableSongs = new List<SongData>();
|
||||
private readonly List<int> _selectableDifficulties = new List<int>();
|
||||
private Coroutine _songLibraryWaitRoutine;
|
||||
private bool _suppressSongDropdownEvents;
|
||||
private bool _isChangingRoomSong;
|
||||
|
||||
private const float ChatSendCooldownSeconds = 3f;
|
||||
private const int InitialHistoryLoadLimit = 20;
|
||||
@@ -162,6 +171,18 @@ public class roomDetails : MonoBehaviour
|
||||
sendMessageButton.onClick.AddListener(OnSendMessageClicked);
|
||||
}
|
||||
|
||||
if (songDropdown != null)
|
||||
{
|
||||
songDropdown.onValueChanged.RemoveListener(OnSongDropdownChanged);
|
||||
songDropdown.onValueChanged.AddListener(OnSongDropdownChanged);
|
||||
}
|
||||
|
||||
if (difficultyDropdown != null)
|
||||
{
|
||||
difficultyDropdown.onValueChanged.RemoveListener(OnDifficultyDropdownChanged);
|
||||
difficultyDropdown.onValueChanged.AddListener(OnDifficultyDropdownChanged);
|
||||
}
|
||||
|
||||
if (playerMessageInputField != null)
|
||||
{
|
||||
playerMessageInputField.onEndEdit.RemoveListener(OnChatInputEndEdit);
|
||||
@@ -185,6 +206,7 @@ public class roomDetails : MonoBehaviour
|
||||
_ = InitializeRoomChatAsync();
|
||||
|
||||
Refresh(_service.CurrentRoom);
|
||||
EnsureSongDropdownsReady();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
@@ -225,6 +247,16 @@ public class roomDetails : MonoBehaviour
|
||||
sendMessageButton.onClick.RemoveListener(OnSendMessageClicked);
|
||||
}
|
||||
|
||||
if (songDropdown != null)
|
||||
{
|
||||
songDropdown.onValueChanged.RemoveListener(OnSongDropdownChanged);
|
||||
}
|
||||
|
||||
if (difficultyDropdown != null)
|
||||
{
|
||||
difficultyDropdown.onValueChanged.RemoveListener(OnDifficultyDropdownChanged);
|
||||
}
|
||||
|
||||
if (playerMessageInputField != null)
|
||||
{
|
||||
playerMessageInputField.onEndEdit.RemoveListener(OnChatInputEndEdit);
|
||||
@@ -259,6 +291,12 @@ public class roomDetails : MonoBehaviour
|
||||
_refocusChatInputCoroutine = null;
|
||||
}
|
||||
|
||||
if (_songLibraryWaitRoutine != null)
|
||||
{
|
||||
StopCoroutine(_songLibraryWaitRoutine);
|
||||
_songLibraryWaitRoutine = null;
|
||||
}
|
||||
|
||||
RestoreDefaultChatPlaceholder();
|
||||
|
||||
if (_spawnedRoomRankingInstance != null)
|
||||
@@ -396,6 +434,7 @@ public class roomDetails : MonoBehaviour
|
||||
UpdateQuitButtonTexts(snapshot);
|
||||
UpdateReadyButton(snapshot);
|
||||
RenderParticipants(snapshot);
|
||||
RefreshSongDropdowns(snapshot);
|
||||
}
|
||||
|
||||
private IEnumerator UpdateRemainTime(ArenaRoomSnapshot snapshot)
|
||||
@@ -760,7 +799,7 @@ public class roomDetails : MonoBehaviour
|
||||
&& string.Equals(senderSteamId, localSteamId, StringComparison.Ordinal);
|
||||
Color bubbleColor = ResolveMessageBubbleColor(isSelf);
|
||||
string displayName = ResolveMessageDisplayName(message, isSelf);
|
||||
string title = ResolveMessageTitle();
|
||||
string title = ResolveMessageTitle(message);
|
||||
|
||||
GameObject instance = Instantiate(playerMessagePrefab, messageParent, false);
|
||||
playerMessagePrefab controller = instance.GetComponent<playerMessagePrefab>();
|
||||
@@ -1026,9 +1065,11 @@ public class roomDetails : MonoBehaviour
|
||||
return GameServer.Client.NetworkManager.ResolveDisplayName(message != null ? message.display_name : string.Empty, messageSteamId, false);
|
||||
}
|
||||
|
||||
private static string ResolveMessageTitle()
|
||||
private static string ResolveMessageTitle(ArenaRoomChatMessage message)
|
||||
{
|
||||
return string.Empty;
|
||||
return message != null && !string.IsNullOrWhiteSpace(message.player_title)
|
||||
? message.player_title
|
||||
: string.Empty;
|
||||
}
|
||||
|
||||
private static string GetMessageSenderSteamId(ArenaRoomChatMessage message)
|
||||
@@ -1387,6 +1428,405 @@ public class roomDetails : MonoBehaviour
|
||||
|| string.Equals(snapshot.status, "PLAYING", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private void EnsureSongDropdownsReady()
|
||||
{
|
||||
if (songDropdown == null && difficultyDropdown == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SongDataLibrary library = SongDataLibrary.Instance;
|
||||
if (library != null && library.IsLoaded)
|
||||
{
|
||||
RefreshSongDropdowns(_service != null ? _service.CurrentRoom : null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_songLibraryWaitRoutine == null)
|
||||
{
|
||||
_songLibraryWaitRoutine = StartCoroutine(WaitForSongLibraryAndRefresh());
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator WaitForSongLibraryAndRefresh()
|
||||
{
|
||||
float timeoutAt = Time.realtimeSinceStartup + 8f;
|
||||
while (Time.realtimeSinceStartup < timeoutAt)
|
||||
{
|
||||
SongDataLibrary library = SongDataLibrary.Instance;
|
||||
if (library != null && library.IsLoaded)
|
||||
{
|
||||
_songLibraryWaitRoutine = null;
|
||||
RefreshSongDropdowns(_service != null ? _service.CurrentRoom : null);
|
||||
yield break;
|
||||
}
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
_songLibraryWaitRoutine = null;
|
||||
Debug.LogWarning("[roomDetails] SongDataLibrary was not ready; song dropdowns were left empty.");
|
||||
}
|
||||
|
||||
private void RefreshSongDropdowns(ArenaRoomSnapshot snapshot)
|
||||
{
|
||||
if (songDropdown == null && difficultyDropdown == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SongDataLibrary library = SongDataLibrary.Instance;
|
||||
if (library == null || !library.IsLoaded)
|
||||
{
|
||||
EnsureSongDropdownsReady();
|
||||
UpdateSongDropdownInteractable(snapshot);
|
||||
return;
|
||||
}
|
||||
|
||||
RebuildSelectableSongs(library);
|
||||
SongData selectedSong = ResolveSnapshotSong(snapshot);
|
||||
if (selectedSong == null && _selectableSongs.Count > 0)
|
||||
{
|
||||
selectedSong = _selectableSongs[0];
|
||||
}
|
||||
|
||||
int selectedDifficulty = ConvertDifficultyKeyToId(snapshot != null ? snapshot.difficulty : null);
|
||||
if (selectedSong != null)
|
||||
{
|
||||
RebuildSelectableDifficulties(selectedSong);
|
||||
if (!_selectableDifficulties.Contains(selectedDifficulty))
|
||||
{
|
||||
selectedDifficulty = _selectableDifficulties.Count > 0 ? _selectableDifficulties[0] : selectedDifficulty;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_selectableDifficulties.Clear();
|
||||
}
|
||||
|
||||
_suppressSongDropdownEvents = true;
|
||||
try
|
||||
{
|
||||
PopulateSongDropdown(selectedSong);
|
||||
PopulateDifficultyDropdown(selectedSong, selectedDifficulty);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_suppressSongDropdownEvents = false;
|
||||
}
|
||||
|
||||
UpdateSongDropdownInteractable(snapshot);
|
||||
}
|
||||
|
||||
private void RebuildSelectableSongs(SongDataLibrary library)
|
||||
{
|
||||
_selectableSongs.Clear();
|
||||
|
||||
List<SongData> songs = library != null ? library.GetAllSongs() : null;
|
||||
if (songs == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
songs.Sort((left, right) =>
|
||||
{
|
||||
int idCompare = (left != null ? left.songID : int.MaxValue).CompareTo(right != null ? right.songID : int.MaxValue);
|
||||
if (idCompare != 0)
|
||||
{
|
||||
return idCompare;
|
||||
}
|
||||
|
||||
return string.Compare(left != null ? left.songName : string.Empty,
|
||||
right != null ? right.songName : string.Empty,
|
||||
StringComparison.CurrentCulture);
|
||||
});
|
||||
|
||||
foreach (SongData song in songs)
|
||||
{
|
||||
if (song != null && HasPlayableDifficulty(song))
|
||||
{
|
||||
_selectableSongs.Add(song);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private SongData ResolveSnapshotSong(ArenaRoomSnapshot snapshot)
|
||||
{
|
||||
if (snapshot != null && int.TryParse(snapshot.song_id, out int songId))
|
||||
{
|
||||
for (int i = 0; i < _selectableSongs.Count; i++)
|
||||
{
|
||||
SongData song = _selectableSongs[i];
|
||||
if (song != null && song.songID == songId)
|
||||
{
|
||||
return song;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void RebuildSelectableDifficulties(SongData song)
|
||||
{
|
||||
_selectableDifficulties.Clear();
|
||||
if (song == null || song.chartFiles == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (ChartFileEntry entry in song.chartFiles)
|
||||
{
|
||||
if (entry == null || entry.chartFile == null || _selectableDifficulties.Contains(entry.difficulty))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_selectableDifficulties.Add(entry.difficulty);
|
||||
}
|
||||
|
||||
_selectableDifficulties.Sort();
|
||||
}
|
||||
|
||||
private void PopulateSongDropdown(SongData selectedSong)
|
||||
{
|
||||
if (songDropdown == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
songDropdown.ClearOptions();
|
||||
List<string> options = new List<string>();
|
||||
for (int i = 0; i < _selectableSongs.Count; i++)
|
||||
{
|
||||
SongData song = _selectableSongs[i];
|
||||
options.Add(song != null && !string.IsNullOrWhiteSpace(song.songName) ? song.songName : $"Song {song?.songID ?? 0}");
|
||||
}
|
||||
|
||||
songDropdown.AddOptions(options);
|
||||
int selectedIndex = selectedSong != null ? _selectableSongs.IndexOf(selectedSong) : -1;
|
||||
songDropdown.value = Mathf.Clamp(selectedIndex, 0, Mathf.Max(0, _selectableSongs.Count - 1));
|
||||
songDropdown.RefreshShownValue();
|
||||
}
|
||||
|
||||
private void PopulateDifficultyDropdown(SongData selectedSong, int selectedDifficulty)
|
||||
{
|
||||
if (difficultyDropdown == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
difficultyDropdown.ClearOptions();
|
||||
List<string> options = new List<string>();
|
||||
for (int i = 0; i < _selectableDifficulties.Count; i++)
|
||||
{
|
||||
options.Add(FormatDifficultyOption(selectedSong, _selectableDifficulties[i]));
|
||||
}
|
||||
|
||||
difficultyDropdown.AddOptions(options);
|
||||
int selectedIndex = _selectableDifficulties.IndexOf(selectedDifficulty);
|
||||
difficultyDropdown.value = Mathf.Clamp(selectedIndex, 0, Mathf.Max(0, _selectableDifficulties.Count - 1));
|
||||
difficultyDropdown.RefreshShownValue();
|
||||
}
|
||||
|
||||
private void UpdateSongDropdownInteractable(ArenaRoomSnapshot snapshot)
|
||||
{
|
||||
string localSteamId = NetworkManager.Instance != null ? NetworkManager.Instance.SteamId : string.Empty;
|
||||
bool canChange = !_isChangingRoomSong
|
||||
&& snapshot != null
|
||||
&& IsLocalHost(snapshot, localSteamId)
|
||||
&& !IsRoomStarted(snapshot)
|
||||
&& _selectableSongs.Count > 0;
|
||||
|
||||
if (songDropdown != null)
|
||||
{
|
||||
songDropdown.interactable = canChange;
|
||||
}
|
||||
|
||||
if (difficultyDropdown != null)
|
||||
{
|
||||
difficultyDropdown.interactable = canChange && _selectableDifficulties.Count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSongDropdownChanged(int index)
|
||||
{
|
||||
if (_suppressSongDropdownEvents || index < 0 || index >= _selectableSongs.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SongData song = _selectableSongs[index];
|
||||
int currentDifficulty = GetSelectedDifficultyId();
|
||||
RebuildSelectableDifficulties(song);
|
||||
if (!_selectableDifficulties.Contains(currentDifficulty))
|
||||
{
|
||||
currentDifficulty = _selectableDifficulties.Count > 0 ? _selectableDifficulties[0] : 2;
|
||||
}
|
||||
|
||||
_suppressSongDropdownEvents = true;
|
||||
try
|
||||
{
|
||||
PopulateDifficultyDropdown(song, currentDifficulty);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_suppressSongDropdownEvents = false;
|
||||
}
|
||||
|
||||
RequestChangeRoomSong(song, currentDifficulty);
|
||||
}
|
||||
|
||||
private void OnDifficultyDropdownChanged(int index)
|
||||
{
|
||||
if (_suppressSongDropdownEvents || index < 0 || index >= _selectableDifficulties.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SongData song = GetSelectedSong();
|
||||
RequestChangeRoomSong(song, _selectableDifficulties[index]);
|
||||
}
|
||||
|
||||
private async void RequestChangeRoomSong(SongData song, int difficultyId)
|
||||
{
|
||||
if (_service == null || song == null || _isChangingRoomSong)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ArenaRoomSnapshot snapshot = _service.CurrentRoom;
|
||||
string localSteamId = NetworkManager.Instance != null ? NetworkManager.Instance.SteamId : string.Empty;
|
||||
if (!IsLocalHost(snapshot, localSteamId) || IsRoomStarted(snapshot))
|
||||
{
|
||||
RefreshSongDropdowns(snapshot);
|
||||
return;
|
||||
}
|
||||
|
||||
string difficultyKey = ConvertDifficultyIdToKey(difficultyId);
|
||||
if (snapshot != null
|
||||
&& string.Equals(snapshot.song_id, song.songID.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal)
|
||||
&& string.Equals((snapshot.difficulty ?? string.Empty).Trim(), difficultyKey, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isChangingRoomSong = true;
|
||||
UpdateSongDropdownInteractable(snapshot);
|
||||
try
|
||||
{
|
||||
await _service.ChangeRoomSong(
|
||||
song.songID.ToString(CultureInfo.InvariantCulture),
|
||||
song.songName,
|
||||
difficultyKey);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogWarning($"[roomDetails] Change room song failed: {ex.Message}");
|
||||
RefreshSongDropdowns(_service.CurrentRoom);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isChangingRoomSong = false;
|
||||
UpdateSongDropdownInteractable(_service.CurrentRoom);
|
||||
}
|
||||
}
|
||||
|
||||
private SongData GetSelectedSong()
|
||||
{
|
||||
if (songDropdown == null)
|
||||
{
|
||||
return ResolveSnapshotSong(_service != null ? _service.CurrentRoom : null);
|
||||
}
|
||||
|
||||
int index = songDropdown.value;
|
||||
return index >= 0 && index < _selectableSongs.Count ? _selectableSongs[index] : null;
|
||||
}
|
||||
|
||||
private int GetSelectedDifficultyId()
|
||||
{
|
||||
if (difficultyDropdown != null)
|
||||
{
|
||||
int index = difficultyDropdown.value;
|
||||
if (index >= 0 && index < _selectableDifficulties.Count)
|
||||
{
|
||||
return _selectableDifficulties[index];
|
||||
}
|
||||
}
|
||||
|
||||
return ConvertDifficultyKeyToId(_service != null && _service.CurrentRoom != null ? _service.CurrentRoom.difficulty : null);
|
||||
}
|
||||
|
||||
private static bool HasPlayableDifficulty(SongData song)
|
||||
{
|
||||
if (song == null || song.chartFiles == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (ChartFileEntry entry in song.chartFiles)
|
||||
{
|
||||
if (entry != null && entry.chartFile != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static string FormatDifficultyOption(SongData song, int difficultyId)
|
||||
{
|
||||
string shortName = FormatDifficulty(ConvertDifficultyIdToKey(difficultyId));
|
||||
ChartFileEntry entry = song != null && song.chartFiles != null
|
||||
? song.chartFiles.Find(item => item != null && item.difficulty == difficultyId)
|
||||
: null;
|
||||
|
||||
if (entry != null && entry.difficultyLEVEL > 0f)
|
||||
{
|
||||
return $"{shortName} Lv.{entry.difficultyLEVEL:0.#}";
|
||||
}
|
||||
|
||||
return shortName;
|
||||
}
|
||||
|
||||
private static 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;
|
||||
}
|
||||
}
|
||||
|
||||
private static string ConvertDifficultyIdToKey(int difficultyId)
|
||||
{
|
||||
switch (difficultyId)
|
||||
{
|
||||
case 0:
|
||||
return "ez";
|
||||
case 1:
|
||||
return "hd";
|
||||
case 3:
|
||||
return "im";
|
||||
case 2:
|
||||
default:
|
||||
return "in";
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetButtonText(Button button, string text)
|
||||
{
|
||||
if (button == null)
|
||||
|
||||
Reference in New Issue
Block a user