using UnityEngine; using System.Collections.Generic; using System.Collections; public class SongDataLibrary : MonoBehaviour { public static SongDataLibrary Instance; private Dictionary songDataDictionary = new Dictionary(); private Coroutine loadCoroutine; [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] private static void EnsureRuntimeInstance() { if (Instance != null) return; if (SceneObjectLookupCache.FindAny() != null) return; var go = new GameObject(nameof(SongDataLibrary)); Object.DontDestroyOnLoad(go); go.AddComponent(); } // Documentation text normalized. // Documentation text normalized. public string[] subfolderNames; [Header("Song List")] [SerializeField] SongList songList; [SerializeField] bool useSongListIfAvailable = true; [Header("Async Load Settings")] [SerializeField] int yieldEvery = 16; [SerializeField] bool logLoadProgress = false; public bool IsLoaded { get; private set; } public bool IsLoading { get; private set; } private void Awake() { if (Instance == null) { Instance = this; DontDestroyOnLoad(gameObject); BeginLoad(); } else { Destroy(gameObject); } } private IEnumerator LoadSongDataCoroutine() { if (IsLoading || IsLoaded) { loadCoroutine = null; yield break; } IsLoading = true; IsLoaded = false; songDataDictionary.Clear(); // Allow one frame to render before heavy load begins yield return null; // prefer SongList if available to avoid heavy Resources.LoadAll if (useSongListIfAvailable) { if (songList == null) { SongSelectUI ui = SceneObjectLookupCache.FindAny(); if (ui != null) { songList = ui.songList; } } if (songList != null && songList.songs != null && songList.songs.Count > 0) { yield return LoadFromList(songList.songs, "songList"); yield return LoadFromRuntimeRegistry("runtimeSongs"); IsLoaded = true; IsLoading = false; loadCoroutine = null; yield break; } } yield return LoadFromPath("song_songIndex", "root"); if (subfolderNames != null) { for (int i = 0; i < subfolderNames.Length; i++) { string subfolder = subfolderNames[i]; if (string.IsNullOrEmpty(subfolder)) { continue; } yield return LoadFromPath("song_songIndex/" + subfolder, subfolder); // yield a frame between folders to reduce hitch yield return null; } } IsLoaded = true; IsLoading = false; loadCoroutine = null; } private IEnumerator LoadFromPath(string path, string label) { SongData[] assets = RuntimeResourcesCache.LoadSongsFromPath(path); if (assets == null || assets.Length == 0) { if (logLoadProgress) { Debug.Log("SongDataLibrary: no assets found at '" + path + "'"); } yield break; } int yielded = 0; foreach (SongData data in assets) { if (data == null) { continue; } if (!songDataDictionary.ContainsKey(data.songID)) { songDataDictionary.Add(data.songID, data); if (logLoadProgress) { Debug.Log("Loaded SongData [" + label + "] songID: " + data.songID + ", name: " + data.songName); } } else if (logLoadProgress) { Debug.LogWarning("Duplicate songID: " + data.songID); } yielded++; if (yieldEvery > 0 && (yielded % yieldEvery) == 0) { // yield to spread work across frames yield return null; } } } private IEnumerator LoadFromList(List list, string label) { if (list == null || list.Count == 0) { yield break; } int yielded = 0; for (int i = 0; i < list.Count; i++) { SongData data = list[i]; if (data == null) continue; if (!songDataDictionary.ContainsKey(data.songID)) { songDataDictionary.Add(data.songID, data); if (logLoadProgress) { Debug.Log("Loaded SongData [" + label + "] songID: " + data.songID + ", name: " + data.songName); } } else if (logLoadProgress) { Debug.LogWarning("Duplicate songID: " + data.songID); } yielded++; if (yieldEvery > 0 && (yielded % yieldEvery) == 0) { yield return null; } } } private IEnumerator LoadFromRuntimeRegistry(string label) { SongData[] runtimeSongs = DlcRuntimeRegistry.GetAllSongs(); if (runtimeSongs == null || runtimeSongs.Length == 0) { yield break; } int yielded = 0; for (int i = 0; i < runtimeSongs.Length; i++) { SongData data = runtimeSongs[i]; if (data == null) { continue; } if (!songDataDictionary.ContainsKey(data.songID)) { songDataDictionary.Add(data.songID, data); if (logLoadProgress) { Debug.Log("Loaded SongData [" + label + "] songID: " + data.songID + ", name: " + data.songName); } } else if (logLoadProgress) { Debug.LogWarning("Duplicate songID: " + data.songID); } yielded++; if (yieldEvery > 0 && (yielded % yieldEvery) == 0) { yield return null; } } } public SongData GetSongDataByID(int songID) { if (songDataDictionary.ContainsKey(songID)) { SongData data = songDataDictionary[songID]; data.EnsurePersistentDataLoaded(); return data; } Debug.LogError("未找到 songID: " + songID); return null; } public List GetAllSongs() { return new List(songDataDictionary.Values); } public void RefreshLibrary() { if (!isActiveAndEnabled) { return; } if (loadCoroutine != null) { StopCoroutine(loadCoroutine); loadCoroutine = null; } IsLoaded = false; IsLoading = false; songDataDictionary.Clear(); BeginLoad(); } private void BeginLoad() { if (loadCoroutine != null) { StopCoroutine(loadCoroutine); } loadCoroutine = StartCoroutine(LoadSongDataCoroutine()); } }