修了不少东西

This commit is contained in:
2026-07-16 23:04:59 +08:00
parent 29972d0705
commit 73fe474cc6
134 changed files with 7673 additions and 741 deletions
+443 -3
View File
@@ -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)