功能批量实现 优化 服务端 新浮动小游戏框架 新界面UI

This commit is contained in:
FloatGaming
2026-04-24 13:20:16 +08:00
parent e0bc0bbf08
commit 5eec879582
257 changed files with 38481 additions and 1288 deletions
+92 -27
View File
@@ -119,6 +119,7 @@ public class SongData : ScriptableObject
public string thisLevel_overallDescription;
private bool _isPersistentDataLoaded = false;
private bool _isPersistentDataLoading = false;
private void OnValidate()
{
@@ -291,14 +292,33 @@ public class SongData : ScriptableObject
if (chartFileMap == null) chartFileMap = new Dictionary<int, TextAsset>();
if (chartFiles == null) chartFiles = new List<ChartFileEntry>();
// 灏濊瘯浠庢寔涔呭寲瀛樺偍鍔犺浇鏁版嵁
LoadPersistent();
// Keep editor inspection behavior unchanged while avoiding full runtime restore for every song asset.
if (!Application.isPlaying)
{
LoadPersistent();
}
SyncRecordsFromChartFiles();
SyncChartFileMap();
}
public void EnsurePersistentDataLoaded()
{
if (_isPersistentDataLoaded || _isPersistentDataLoading)
{
return;
}
LoadPersistent();
}
public int CalculateHighestPersonalRecord()
{
EnsurePersistentDataLoaded();
return CalculateHighestPersonalRecordInternal();
}
private int CalculateHighestPersonalRecordInternal()
{
if (personalRecordMap == null) personalRecordMap = new Dictionary<int, int>();
if (idolRecordMap == null) idolRecordMap = new Dictionary<int, int>();
@@ -382,32 +402,47 @@ public class SongData : ScriptableObject
/// 浠庢寔涔呭寲 JSON 鎭㈠鏁版嵁銆? /// 鏍¢獙閫昏緫宸茶縼绉昏嚦 DataCheck 鑴氭湰锛屾澶勪粎鎵ц鍩虹鍔犺浇銆? /// </summary>
public void LoadPersistent()
{
if (_isPersistentDataLoaded) return;
string json;
if (SecureSaveVault.TryLoadRawJson(SecureSaveCategory, songID.ToString(), out json, GetLegacySavePath()))
if (_isPersistentDataLoaded || _isPersistentDataLoading)
{
try
return;
}
_isPersistentDataLoading = true;
try
{
string json;
if (SecureSaveVault.TryLoadRawJson(SecureSaveCategory, songID.ToString(), out json, GetLegacySavePath()))
{
// 灏濊瘯瑙f瀽鏁版嵁
SongDataSerializable serializable = JsonUtility.FromJson<SongDataSerializable>(json);
if (serializable != null)
try
{
serializable.ApplyTo(this);
SyncEntriesFromMaps();
_isPersistentDataLoaded = true;
Debug.Log($"[SongData] {songName} (ID:{songID}) data restored from persistent storage.");
SongDataSerializable serializable = JsonUtility.FromJson<SongDataSerializable>(json);
if (serializable != null)
{
serializable.ApplyTo(this);
SyncEntriesFromMaps();
}
else
{
ResetRuntimeProgressStateWithoutSaving();
}
}
catch (System.Exception e)
{
ResetRuntimeProgressStateWithoutSaving();
_isPersistentDataLoaded = true;
Debug.LogWarning($"[SongData] {songName} base load failed and was reset: {e.Message}");
}
}
catch (System.Exception e)
else
{
Debug.LogWarning($"[SongData] {songName} 鍩虹鍔犺浇澶辫触: {e.Message}");
ResetRuntimeProgressStateWithoutSaving();
_isPersistentDataLoaded = true;
}
}
else
finally
{
ResetRuntimeProgressStateWithoutSaving();
_isPersistentDataLoaded = true;
_isPersistentDataLoading = false;
}
}
@@ -602,6 +637,7 @@ public class SongData : ScriptableObject
public void UpdateDifficultyRecord(int difficulty, int pmScore, int idolScore)
{
EnsurePersistentDataLoaded();
if (personalRecordMap == null) personalRecordMap = new Dictionary<int, int>();
if (idolRecordMap == null) idolRecordMap = new Dictionary<int, int>();
@@ -621,11 +657,12 @@ public class SongData : ScriptableObject
entry.totalPersonalRecordForThisDifficulty = newTotal;
}
CalculateHighestPersonalRecord();
CalculateHighestPersonalRecordInternal();
}
public void ApplySettlementResult(int difficulty, int pmScore, int idolScore, int maxScoreSum)
{
EnsurePersistentDataLoaded();
if (difficulty < 0) return;
if (personalRecordMap == null) personalRecordMap = new Dictionary<int, int>();
@@ -710,8 +747,29 @@ public class SongData : ScriptableObject
UpdateOverallRecordsFromEntries();
}
private int GetPersonalRecordDirect(int difficulty)
{
if (personalRecordMap == null)
{
return 0;
}
return personalRecordMap.TryGetValue(difficulty, out int value) ? value : 0;
}
private int GetIdolRecordDirect(int difficulty)
{
if (idolRecordMap == null)
{
return 0;
}
return idolRecordMap.TryGetValue(difficulty, out int value) ? value : 0;
}
public void GetAbsoluteHighestScore(out int highestScore, out int bestDifficulty, out string bestDifficultyName)
{
EnsurePersistentDataLoaded();
highestScore = 0;
bestDifficulty = -1;
bestDifficultyName = "";
@@ -723,7 +781,7 @@ public class SongData : ScriptableObject
ChartFileEntry entry = chartFiles[i];
if (entry == null) continue;
int total = GetPersonalRecord(entry.difficulty) + GetIdolRecord(entry.difficulty);
int total = GetPersonalRecordDirect(entry.difficulty) + GetIdolRecordDirect(entry.difficulty);
if (total <= 0) total = entry.totalPersonalRecordForThisDifficulty;
if (total <= 0) total = entry.chartPersonalRecordForThisDifficulty + entry.idolPersonalRecordForThisDifficulty;
@@ -742,7 +800,7 @@ public class SongData : ScriptableObject
foreach (var kvp in personalRecordMap)
{
int diff = kvp.Key;
int total = kvp.Value + GetIdolRecord(diff);
int total = kvp.Value + GetIdolRecordDirect(diff);
if (total > highestScore || bestDifficulty == -1)
{
highestScore = total;
@@ -766,6 +824,7 @@ public class SongData : ScriptableObject
public void UpdatePersonalRecord(int difficulty, int newScore)
{
EnsurePersistentDataLoaded();
if (personalRecordMap == null) personalRecordMap = new Dictionary<int, int>();
if (!personalRecordMap.ContainsKey(difficulty) || newScore > personalRecordMap[difficulty])
personalRecordMap[difficulty] = newScore;
@@ -778,7 +837,7 @@ public class SongData : ScriptableObject
entry.totalPersonalRecordForThisDifficulty = personalRecordMap[difficulty] + idol;
}
CalculateHighestPersonalRecord();
CalculateHighestPersonalRecordInternal();
}
private void UpdateOverallRecordsFromEntries()
@@ -796,8 +855,8 @@ public class SongData : ScriptableObject
int total = entry.totalPersonalRecordForThisDifficulty;
if (total <= 0)
{
int p = GetPersonalRecord(entry.difficulty);
int idol = GetIdolRecord(entry.difficulty);
int p = GetPersonalRecordDirect(entry.difficulty);
int idol = GetIdolRecordDirect(entry.difficulty);
total = p + idol;
}
@@ -822,7 +881,7 @@ public class SongData : ScriptableObject
foreach (var kvp in personalRecordMap)
{
int diff = kvp.Key;
int total = kvp.Value + GetIdolRecord(diff);
int total = kvp.Value + GetIdolRecordDirect(diff);
if (total > highestTotal) highestTotal = total;
}
personalRecord = highestTotal;
@@ -843,6 +902,7 @@ public class SongData : ScriptableObject
public void UpdateIdolRecord(int difficulty, int newIdolScore)
{
EnsurePersistentDataLoaded();
if (idolRecordMap == null) idolRecordMap = new Dictionary<int, int>();
if (!idolRecordMap.ContainsKey(difficulty) || newIdolScore > idolRecordMap[difficulty])
idolRecordMap[difficulty] = newIdolScore;
@@ -855,11 +915,12 @@ public class SongData : ScriptableObject
entry.totalPersonalRecordForThisDifficulty = personal + idolRecordMap[difficulty];
}
CalculateHighestPersonalRecord();
CalculateHighestPersonalRecordInternal();
}
public void UpdateChartScore(int difficulty, int newChartScore)
{
EnsurePersistentDataLoaded();
if (chartScoreMap == null) chartScoreMap = new Dictionary<int, int>();
chartScoreMap[difficulty] = newChartScore;
@@ -870,24 +931,28 @@ public class SongData : ScriptableObject
public int GetPersonalRecord(int difficulty)
{
EnsurePersistentDataLoaded();
if (personalRecordMap == null) return 0;
return personalRecordMap.TryGetValue(difficulty, out int v) ? v : 0;
}
public int GetIdolRecord(int difficulty)
{
EnsurePersistentDataLoaded();
if (idolRecordMap == null) return 0;
return idolRecordMap.TryGetValue(difficulty, out int v) ? v : 0;
}
public int GetChartScore(int difficulty)
{
EnsurePersistentDataLoaded();
if (chartScoreMap == null) return 0;
return chartScoreMap.TryGetValue(difficulty, out int v) ? v : 0;
}
public TextAsset GetChartFile(int difficulty)
{
EnsurePersistentDataLoaded();
if (chartFiles != null)
{
for (int i = 0; i < chartFiles.Count; i++)
@@ -952,7 +1017,7 @@ public class SongData : ScriptableObject
entry.totalPersonalRecordForThisDifficulty = p + idol;
}
CalculateHighestPersonalRecord();
CalculateHighestPersonalRecordInternal();
}
}
@@ -6,6 +6,7 @@ using DG.Tweening;
public class SongButton : MonoBehaviour
{
private const bool VerboseLogs = false;
[Header("thisSong_so")]
public ScriptableObject thisSong_so;
[Header("Inspector")]
@@ -42,6 +43,21 @@ public class SongButton : MonoBehaviour
private Coroutine fadeCoroutine;
private Coroutine blinkCoroutine;
public bool IsSelectedForQuickEnter()
{
return selected_boarder != null && selected_boarder.color.a > 0.5f;
}
public SongData GetAssignedSongData()
{
return thisSong_so as SongData;
}
public int GetSongSerialId()
{
return song_songSerialID;
}
public void Start()
{
if (selected_boarder != null)
@@ -58,12 +74,39 @@ public class SongButton : MonoBehaviour
}
}
private void OnDisable()
{
StopVisualCoroutines();
}
private void OnDestroy()
{
StopVisualCoroutines();
if (currentSelected == this)
{
currentSelected = null;
}
}
private void StopVisualCoroutines()
{
if (fadeCoroutine != null)
{
StopCoroutine(fadeCoroutine);
fadeCoroutine = null;
}
if (blinkCoroutine != null)
{
StopCoroutine(blinkCoroutine);
blinkCoroutine = null;
}
}
public void SetButtonData(string songName, int highestScore, int difficultyID, Sprite songSprite, int songID)
{
Debug.Log("SetButtonData called, songID: " + songID);
SongData sd = thisSong_so as SongData;
if (sd != null) sd.LoadPersistent();
if (sd != null) sd.EnsurePersistentDataLoaded();
if (SongDataLibrary.Instance != null && SongDataLibrary.Instance.IsLoaded)
sd = SongDataLibrary.Instance.GetSongDataByID(songID) ?? sd;
if (sd != null)
@@ -193,7 +236,6 @@ public class SongButton : MonoBehaviour
public void OnSongButtonClick()
{
Debug.Log("Song button clicked, song_songSerialID: " + song_songSerialID);
SongData selectedSong = null;
if (SongDataLibrary.Instance != null && SongDataLibrary.Instance.IsLoaded)
{
@@ -205,7 +247,7 @@ public class SongButton : MonoBehaviour
}
if (selectedSong != null)
{
selectedSong.LoadPersistent();
selectedSong.EnsurePersistentDataLoaded();
selectedSong.GetAbsoluteHighestScore(out int bestTotal, out int bestDiff, out string bestDiffName);
if (bestDiff >= 0)
{
@@ -232,7 +274,7 @@ public class SongButton : MonoBehaviour
int index = GetIndexAmongSongButtons();
PlayerPrefs.SetInt(prefsKey, index);
PlayerPrefs.Save();
Debug.Log($"SongButton: saved selected song index {index} for key {prefsKey}");
if (VerboseLogs) Debug.Log($"SongButton: saved selected song index {index} for key {prefsKey}");
}
else
{
@@ -8,6 +8,7 @@ using DG.Tweening;
public class SongSelectUI : MonoBehaviour
{
private const bool VerboseLogs = false;
public SongList songList; // Documentation text normalized.
public GameObject songButtonPrefab; // Documentation text normalized.
public Transform contentPanel; // Documentation text normalized.
@@ -70,6 +71,48 @@ public class SongSelectUI : MonoBehaviour
}
}
private void OnDisable()
{
KillActiveTweensAndCoroutines();
}
private void OnDestroy()
{
KillActiveTweensAndCoroutines();
}
private void KillActiveTweensAndCoroutines()
{
if (buildCoroutine != null)
{
StopCoroutine(buildCoroutine);
buildCoroutine = null;
}
if (switchCoroutine != null)
{
StopCoroutine(switchCoroutine);
switchCoroutine = null;
}
if (restoreCoroutine != null)
{
StopCoroutine(restoreCoroutine);
restoreCoroutine = null;
}
RectTransform root = GetListAnimRoot();
if (root != null)
{
root.DOKill();
}
if (listCanvasGroup != null)
{
listCanvasGroup.DOKill();
}
}
private IEnumerator LoadSceneAsync(string sceneName)
{
AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Single);
@@ -270,7 +313,7 @@ public class SongSelectUI : MonoBehaviour
var allSongButtons = contentPanel.GetComponentsInChildren<SongButton>(true);
if (allSongButtons == null || allSongButtons.Length == 0)
{
Debug.LogWarning("SongSelectUI.RestoreSelectedSongForCurrentDlc: no song buttons found to restore selection");
if (VerboseLogs) Debug.LogWarning("SongSelectUI.RestoreSelectedSongForCurrentDlc: no song buttons found to restore selection");
return;
}
@@ -300,10 +343,10 @@ public class SongSelectUI : MonoBehaviour
if (btn != null)
{
// simulate click
btn.OnSongButtonClick();
Debug.Log($"SongSelectUI: restored and clicked song index={savedIndex} for key={key}, totalButtons={allSongButtons.Length}");
btn.OnSongButtonClick();
if (VerboseLogs) Debug.Log($"SongSelectUI: restored and clicked song index={savedIndex} for key={key}, totalButtons={allSongButtons.Length}");
}
}
}
private void ClearSongList()
{
@@ -372,8 +415,7 @@ public class SongSelectUI : MonoBehaviour
}
Button button = songButtonObj.GetComponent<Button>();
if (button != null && songButton != null)
button.onClick.AddListener(() => songButton.OnSongButtonClick());
// SongButton.Awake already binds its own click handler. Avoid double invocation here.
}
// helper to avoid hardcoding scene name string in delegate - keeps serializer-friendly field
+4 -4
View File
@@ -102,7 +102,7 @@ public class SongDataLibrary : MonoBehaviour
private IEnumerator LoadFromPath(string path, string label)
{
SongData[] assets = Resources.LoadAll<SongData>(path);
SongData[] assets = RuntimeResourcesCache.LoadSongsFromPath(path);
if (assets == null || assets.Length == 0)
{
if (logLoadProgress)
@@ -121,7 +121,6 @@ public class SongDataLibrary : MonoBehaviour
}
if (!songDataDictionary.ContainsKey(data.songID))
{
data.LoadPersistent(); // 启动时从持久化存档恢复数据
songDataDictionary.Add(data.songID, data);
if (logLoadProgress)
{
@@ -157,7 +156,6 @@ public class SongDataLibrary : MonoBehaviour
if (data == null) continue;
if (!songDataDictionary.ContainsKey(data.songID))
{
data.LoadPersistent(); // 启动时从持久化存档恢复数据
songDataDictionary.Add(data.songID, data);
if (logLoadProgress)
{
@@ -180,7 +178,9 @@ public SongData GetSongDataByID(int songID)
{
if (songDataDictionary.ContainsKey(songID))
{
return songDataDictionary[songID];
SongData data = songDataDictionary[songID];
data.EnsurePersistentDataLoaded();
return data;
}
Debug.LogError("未找到 songID: " + songID);
return null;
+17 -16
View File
@@ -7,6 +7,7 @@ using System.IO;
public class dlcButton : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
private const bool VerboseLogs = false;
[Header("Inspector")]
public Image dlc_profileImgae;
public Text dlcName;
@@ -118,7 +119,7 @@ public class dlcButton : MonoBehaviour, IPointerEnterHandler, IPointerExitHandle
dlc_nowSelectedImageBoarder.gameObject.SetActive(false);
}
Debug.Log($"dlcButton.Awake: registered '{gameObject.name}' as index {instanceIndex}");
if (VerboseLogs) Debug.Log($"dlcButton.Awake: registered '{gameObject.name}' as index {instanceIndex}");
}
private void RegisterInstance()
@@ -175,7 +176,7 @@ public class dlcButton : MonoBehaviour, IPointerEnterHandler, IPointerExitHandle
selectedIndex = instanceIndex;
PlayerPrefs.SetInt(PlayerPrefsKey, selectedIndex);
PlayerPrefs.Save();
Debug.Log($"dlcButton.Select: '{gameObject.name}' selected (index {instanceIndex}) and saved to PlayerPrefs");
if (VerboseLogs) Debug.Log($"dlcButton.Select: '{gameObject.name}' selected (index {instanceIndex}) and saved to PlayerPrefs");
}
private static void ApplySelectionToAll(int selectIdx)
@@ -330,7 +331,7 @@ public class dlcButton : MonoBehaviour, IPointerEnterHandler, IPointerExitHandle
// Try to find a dlcData SO by id and apply its songList to dlcContent
public void LoadDlcDataById(int id)
{
Debug.Log($"dlcButton.LoadDlcDataById: searching for id={id} (editorFolder='{editorSearchFolder}', runtimeFolder='{runtimeResourcesFolder}') on '{gameObject.name}'");
if (VerboseLogs) Debug.Log($"dlcButton.LoadDlcDataById: searching for id={id} (editorFolder='{editorSearchFolder}', runtimeFolder='{runtimeResourcesFolder}') on '{gameObject.name}'");
#if UNITY_EDITOR
// Editor search: search recursively for asset files under editorSearchFolder
if (!string.IsNullOrEmpty(editorSearchFolder) && Directory.Exists(editorSearchFolder))
@@ -338,18 +339,18 @@ public class dlcButton : MonoBehaviour, IPointerEnterHandler, IPointerExitHandle
try
{
var files = Directory.GetFiles(editorSearchFolder, "*.asset", SearchOption.AllDirectories);
Debug.Log($"dlcButton.LoadDlcDataById: found {files.Length} asset files under {editorSearchFolder}");
if (VerboseLogs) Debug.Log($"dlcButton.LoadDlcDataById: found {files.Length} asset files under {editorSearchFolder}");
foreach (var path in files)
{
string fileName = Path.GetFileNameWithoutExtension(path);
if (fileName.StartsWith(id.ToString()))
{
string assetPath = path.Replace("\\", "/");
Debug.Log($"dlcButton.LoadDlcDataById: candidate assetPath={assetPath}");
if (VerboseLogs) Debug.Log($"dlcButton.LoadDlcDataById: candidate assetPath={assetPath}");
var so = UnityEditor.AssetDatabase.LoadAssetAtPath<dlcData>(assetPath);
if (so != null)
{
Debug.Log($"dlcButton.LoadDlcDataById: loaded dlcData SO '{so.name}' for id={id}");
if (VerboseLogs) Debug.Log($"dlcButton.LoadDlcDataById: loaded dlcData SO '{so.name}' for id={id}");
dlcDataSO = so;
ApplyDlcData(so);
return;
@@ -364,14 +365,14 @@ public class dlcButton : MonoBehaviour, IPointerEnterHandler, IPointerExitHandle
}
else
{
Debug.Log($"dlcButton.LoadDlcDataById: editorSearchFolder '{editorSearchFolder}' does not exist or not set");
if (VerboseLogs) Debug.Log($"dlcButton.LoadDlcDataById: editorSearchFolder '{editorSearchFolder}' does not exist or not set");
}
#endif
// Runtime: search Resources (load all dlcData then filter by name prefix)
try
{
var arr = Resources.LoadAll<dlcData>(runtimeResourcesFolder);
Debug.Log($"dlcButton.LoadDlcDataById: Resources.LoadAll('{runtimeResourcesFolder}') returned {(arr != null ? arr.Length : 0)} items");
if (VerboseLogs) Debug.Log($"dlcButton.LoadDlcDataById: Resources.LoadAll('{runtimeResourcesFolder}') returned {(arr != null ? arr.Length : 0)} items");
if (arr != null)
{
foreach (var so in arr)
@@ -379,7 +380,7 @@ public class dlcButton : MonoBehaviour, IPointerEnterHandler, IPointerExitHandle
if (so == null) continue;
if (so.name.StartsWith(id.ToString()))
{
Debug.Log($"dlcButton.LoadDlcDataById: found runtime dlcData '{so.name}' for id={id}");
if (VerboseLogs) Debug.Log($"dlcButton.LoadDlcDataById: found runtime dlcData '{so.name}' for id={id}");
dlcDataSO = so;
ApplyDlcData(so);
return;
@@ -394,7 +395,7 @@ public class dlcButton : MonoBehaviour, IPointerEnterHandler, IPointerExitHandle
// fallback: search all Resources
var all = Resources.LoadAll<dlcData>("");
Debug.Log("dlcButton.LoadDlcDataById: Resources.LoadAll(\"\") returned " + (all != null ? all.Length : 0) + " items");
if (VerboseLogs) Debug.Log("dlcButton.LoadDlcDataById: Resources.LoadAll(\"\") returned " + (all != null ? all.Length : 0) + " items");
if (all != null)
{
foreach (var so in all)
@@ -402,7 +403,7 @@ public class dlcButton : MonoBehaviour, IPointerEnterHandler, IPointerExitHandle
if (so == null) continue;
if (so.name.StartsWith(id.ToString()))
{
Debug.Log($"dlcButton.LoadDlcDataById: found fallback dlcData '{so.name}' for id={id}");
if (VerboseLogs) Debug.Log($"dlcButton.LoadDlcDataById: found fallback dlcData '{so.name}' for id={id}");
dlcDataSO = so;
ApplyDlcData(so);
return;
@@ -411,7 +412,7 @@ public class dlcButton : MonoBehaviour, IPointerEnterHandler, IPointerExitHandle
}
// if no dlcData found, keep dlcContent empty but attempt old behavior: search SongData by id prefix
Debug.Log($"dlcButton.LoadDlcDataById: no dlcData found for id={id}, falling back to song prefix search");
if (VerboseLogs) Debug.Log($"dlcButton.LoadDlcDataById: no dlcData found for id={id}, falling back to song prefix search");
LoadContentBySongIdPrefix(id);
}
@@ -441,7 +442,7 @@ public class dlcButton : MonoBehaviour, IPointerEnterHandler, IPointerExitHandle
dlc_profileImgae.enabled = so.dlc_image != null;
}
Debug.Log($"dlcButton.ApplyDlcData: applied dlcData '{so.name}' with {dlcContent.Count} songs to button '{gameObject.name}'");
if (VerboseLogs) Debug.Log($"dlcButton.ApplyDlcData: applied dlcData '{so.name}' with {dlcContent.Count} songs to button '{gameObject.name}'");
}
// Legacy: if no dlcData SO, search SongData assets by id prefix and fill dlcContent
@@ -497,7 +498,7 @@ public class dlcButton : MonoBehaviour, IPointerEnterHandler, IPointerExitHandle
}
}
Debug.Log($"dlcButton: Loaded {dlcContent.Count} SongData entries for DLC id={id} (fallback search)");
if (VerboseLogs) Debug.Log($"dlcButton: Loaded {dlcContent.Count} SongData entries for DLC id={id} (fallback search)");
}
// Resolve dlcData after all buttons have been instantiated
@@ -517,11 +518,11 @@ public class dlcButton : MonoBehaviour, IPointerEnterHandler, IPointerExitHandle
yield break;
}
Debug.Log($"dlcButton.ResolveDlcData called on '{gameObject.name}'");
if (VerboseLogs) Debug.Log($"dlcButton.ResolveDlcData called on '{gameObject.name}'");
if (dlcDataSO != null)
{
Debug.Log($"dlcButton: dlcDataSO already assigned on '{gameObject.name}' -> {dlcDataSO.name}");
if (VerboseLogs) Debug.Log($"dlcButton: dlcDataSO already assigned on '{gameObject.name}' -> {dlcDataSO.name}");
ApplyDlcData(dlcDataSO);
Resolved = true;
yield break;
+4 -3
View File
@@ -5,6 +5,7 @@ using System.Collections.Generic;
public class loadDlcListPrefab : MonoBehaviour
{
private const bool VerboseLogs = false;
[System.Serializable]
public class Column
{
@@ -140,16 +141,16 @@ public class loadDlcListPrefab : MonoBehaviour
{
// simulate a user clicking the button: this will Select() and display its songs
savedBtn.OnButtonClicked_ShowSongs();
Debug.Log($"loadDlcListPrefab: restored and clicked saved dlc button index={savedIndex} name={savedBtn.gameObject.name}");
if (VerboseLogs) Debug.Log($"loadDlcListPrefab: restored and clicked saved dlc button index={savedIndex} name={savedBtn.gameObject.name}");
}
else
{
Debug.LogWarning($"loadDlcListPrefab: saved dlc button at index {savedIndex} was null");
if (VerboseLogs) Debug.LogWarning($"loadDlcListPrefab: saved dlc button at index {savedIndex} was null");
}
}
else
{
Debug.LogWarning("loadDlcListPrefab: no dlc buttons found after RefreshUI");
if (VerboseLogs) Debug.LogWarning("loadDlcListPrefab: no dlc buttons found after RefreshUI");
}
}
+65 -33
View File
@@ -9,6 +9,7 @@ using Bansonic;
public class selected_songInfo : MonoBehaviour
{
private const bool VerboseLogs = false;
[Header("ranking")]
public Button rankingButton;
public rankingList s_rl;
@@ -320,6 +321,8 @@ public class selected_songInfo : MonoBehaviour
StopCoroutine(difficultyIdRollCoroutine);
difficultyIdRollCoroutine = null;
}
KillTweens();
}
void OnDestroy()
@@ -327,6 +330,50 @@ public class selected_songInfo : MonoBehaviour
LogVerbose("selected_songInfo.OnDestroy called");
// ensure we remove sceneLoaded subscription if still present
SceneManager.sceneLoaded -= OnSceneLoadedAfterQuickEnter;
KillTweens();
}
private void KillTweens()
{
if (songInfo_Root != null)
{
songInfo_Root.DOKill();
}
if (songInfo_Canvas != null)
{
songInfo_Canvas.DOKill();
}
if (currentDifficulty != null)
{
currentDifficulty.DOKill();
}
if (sumScore_thisDifficulty != null)
{
sumScore_thisDifficulty.DOKill();
}
if (c_DifficultyImage != null)
{
c_DifficultyImage.DOKill();
}
if (c_imageMask != null)
{
c_imageMask.DOKill();
}
if (blackMaskImage != null)
{
blackMaskImage.DOKill();
}
if (Music_Mgr.Singleton != null && Music_Mgr.Singleton.AudioSource != null)
{
Music_Mgr.Singleton.AudioSource.DOKill();
}
}
void Start()
@@ -1225,8 +1272,6 @@ public class selected_songInfo : MonoBehaviour
// keep selected in holder to make it accessible in new scene
SongDataHolder.SelectedSongData = sd;
// mark this object to persist across scene load so callbacks/coroutines are valid
DontDestroyOnLoad(this.gameObject);
// start fade and load sequence
StartCoroutine(QuickEnterSequence());
}
@@ -1335,8 +1380,8 @@ public class selected_songInfo : MonoBehaviour
}
LogVerbose("Fade complete, loading gameplay scene...");
// after black screen, load gameplay scene asynchronously and wait for completion
SceneManager.sceneLoaded += OnSceneLoadedAfterQuickEnter;
// selected_songInfo is scene UI and must not survive scene switching.
// Gameplay startup is already handled by BeatmapManager/GameManager via pendingSongData.
var asyncOp = SceneManager.LoadSceneAsync("gamePlay_gamePlay");
if (asyncOp != null)
{
@@ -1364,39 +1409,26 @@ public class selected_songInfo : MonoBehaviour
if (sb == null) continue;
try
{
// log selection marker info for each button to help debugging
var field = sb.GetType().GetField("selected_boarder", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);
Image img = null;
if (field != null) img = field.GetValue(sb) as Image;
Image img = sb.selected_boarder;
float alpha = img != null ? img.color.a : -1f;
LogVerbose($"SongButton id field value for '{sb.name}': selected_boarder alpha={alpha}");
if (img != null && img.color.a > 0.5f)
if (sb.IsSelectedForQuickEnter())
{
// prefer thisSong_so if present
var soField = sb.GetType().GetField("thisSong_so", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic);
if (soField != null)
SongData assignedSong = sb.GetAssignedSongData();
if (assignedSong != null)
{
var soObj = soField.GetValue(sb);
if (soObj != null && soObj is SongData)
{
LogVerbose($"Selected SongButton has thisSong_so assigned: {((SongData)soObj).songName}");
return soObj as SongData;
}
LogVerbose($"Selected SongButton has thisSong_so assigned: {assignedSong.songName}");
return assignedSong;
}
// fallback: use song id on SongButton
var idField = sb.GetType().GetField("song_songSerialID", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic);
if (idField != null)
int id = sb.GetSongSerialId();
LogVerbose($"Selected SongButton id = {id}");
var sd = SongDataLibrary.Instance != null ? SongDataLibrary.Instance.GetSongDataByID(id) : null;
if (sd != null)
{
int id = (int)idField.GetValue(sb);
LogVerbose($"Selected SongButton id = {id}");
var sd = SongDataLibrary.Instance != null ? SongDataLibrary.Instance.GetSongDataByID(id) : null;
if (sd != null)
{
LogVerbose($"Found SongData by id: {sd.songName}");
return sd;
}
LogVerbose($"Found SongData by id: {sd.songName}");
return sd;
}
}
}
@@ -1448,7 +1480,7 @@ public class selected_songInfo : MonoBehaviour
LogVerbose("OnSceneLoadedAfterQuickEnter: SelectedSongData is null");
SceneManager.sceneLoaded -= OnSceneLoadedAfterQuickEnter;
// allow this object to be destroyed now
Destroy(this.gameObject);
Destroy(gameObject);
return;
}
@@ -1511,11 +1543,11 @@ public class selected_songInfo : MonoBehaviour
{
gameManager.musicSource.mute = true;
gameManager.musicSource.Play();
Debug.LogWarning("Warmed audio playback (muted) after assigning SongData.audioFile");
if (VerboseLogs) Debug.Log("Warmed audio playback (muted) after assigning SongData.audioFile");
}
catch (System.Exception ex)
{
Debug.LogWarning("Failed to Play() for warmup: " + ex.Message);
if (VerboseLogs) Debug.Log("Failed to Play() for warmup: " + ex.Message);
}
LogVerbose("Assigned SongData.audioFile to GameManager.musicSource.clip (playOnAwake disabled)");
@@ -1672,7 +1704,7 @@ public class selected_songInfo : MonoBehaviour
}
// done with this helper object - allow it to be destroyed
Destroy(this.gameObject);
Destroy(gameObject);
yield break;
}