功能批量实现 优化 服务端 新浮动小游戏框架 新界面UI
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user