From 49914e5b343d4b9d59415b1f5e6255c23c2aa476 Mon Sep 17 00:00:00 2001 From: ALLMarvelous <53633401+ALLMarvelous@users.noreply.github.com> Date: Wed, 1 Jul 2026 16:25:40 -0500 Subject: [PATCH 1/4] Fix all charts showing up in-game as master --- Managers/HotReloadManager.cs | 40 +++++++++++++++++------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/Managers/HotReloadManager.cs b/Managers/HotReloadManager.cs index 24ab785..f3e938f 100644 --- a/Managers/HotReloadManager.cs +++ b/Managers/HotReloadManager.cs @@ -22,8 +22,6 @@ internal static class HotReloadManager { private static readonly Logger Logger = new(nameof(HotReloadManager)); - // Hot-loaded MusicInfo cache: uid -> MusicInfo - // Used by GetMusicInfoFromAll Harmony Postfix private static readonly Dictionary HotLoadedMusicInfos = new(); private static readonly Dictionary HotLoadedMusicNames = new(); private static readonly Dictionary HotLoadedMusicAuthors = new(); @@ -68,28 +66,28 @@ private static string GetTopLevelName(string relativePath) return separatorIndex >= 0 ? relativePath.Substring(0, separatorIndex) : relativePath; } - private static int ParseDifficulty(string difficulty) - { - return int.TryParse(difficulty, out var value) ? value : 0; - } + private static MusicExInfo CreateMusicExInfo(Album album) { - var albumInfo = album.Info; - var changedDiff = new Il2CppStructArray(5); - changedDiff[0] = ParseDifficulty(albumInfo.Difficulty1); - changedDiff[1] = ParseDifficulty(albumInfo.Difficulty2); - changedDiff[2] = ParseDifficulty(albumInfo.Difficulty3); - changedDiff[3] = ParseDifficulty(albumInfo.Difficulty4); - changedDiff[4] = ParseDifficulty(albumInfo.Difficulty5); - - var musicExInfo = new MusicExInfo(); - musicExInfo.m_AlbumIndex = AlbumManager.Uid + 1; - musicExInfo.m_AlbumUidIndex = AlbumManager.Uid; - musicExInfo.m_MusicIndex = album.Index; - musicExInfo.m_AlbumUidName = $"music_package_{AlbumManager.Uid}"; - musicExInfo.m_AlbumJsonName = AlbumManager.JsonName; - musicExInfo.m_ChangedDiff = changedDiff; + var changedDiff = new Il2CppStructArray(5) + { + [0] = 1, // Easy + [1] = 2, // Hard + [2] = 3, // Master + [3] = 4, // Supreme + [4] = 5 // Touhou thing + }; + + var musicExInfo = new MusicExInfo + { + m_AlbumIndex = AlbumManager.Uid + 1, + m_AlbumUidIndex = AlbumManager.Uid, + m_MusicIndex = album.Index, + m_AlbumUidName = $"music_package_{AlbumManager.Uid}", + m_AlbumJsonName = AlbumManager.JsonName, + m_ChangedDiff = changedDiff + }; return musicExInfo; } From 9fa70999b4a0577d8160f25a0bcb80221510520c Mon Sep 17 00:00:00 2001 From: ALLMarvelous <53633401+ALLMarvelous@users.noreply.github.com> Date: Wed, 1 Jul 2026 16:37:13 -0500 Subject: [PATCH 2/4] Fix hidden support for hot-loaded charts --- Managers/HotReloadManager.cs | 18 ++++++ Patches/HiddenSupportPatch.cs | 112 ++++++++++++++++++++++++++++++++-- 2 files changed, 126 insertions(+), 4 deletions(-) diff --git a/Managers/HotReloadManager.cs b/Managers/HotReloadManager.cs index f3e938f..9fc9787 100644 --- a/Managers/HotReloadManager.cs +++ b/Managers/HotReloadManager.cs @@ -293,6 +293,15 @@ private static int ProcessAdditions() Logger.Warning($"Failed to preload cover: {ex.Message}"); } + try + { + HiddenSupportPatch.AddHidden(album); + } + catch (Exception ex) + { + Logger.Warning($"Failed to add hidden support: {ex.Message}"); + } + addedCount++; Logger.Msg($"Successfully added {albumInfo.Name}"); } @@ -323,6 +332,15 @@ private static int ProcessDeletions() HotLoadedMusicNames.Remove(uid); HotLoadedMusicAuthors.Remove(uid); + try + { + HiddenSupportPatch.RemoveHidden(uid); + } + catch (Exception ex) + { + Logger.Warning($"Failed to remove hidden support: {ex.Message}"); + } + // Remove from game music database try { diff --git a/Patches/HiddenSupportPatch.cs b/Patches/HiddenSupportPatch.cs index 87f48e4..838603a 100644 --- a/Patches/HiddenSupportPatch.cs +++ b/Patches/HiddenSupportPatch.cs @@ -1,4 +1,5 @@ -using CustomAlbums.Managers; +using CustomAlbums.Data; +using CustomAlbums.Managers; using CustomAlbums.Utilities; using HarmonyLib; using Il2Cpp; @@ -15,10 +16,113 @@ internal class HiddenSupportPatch { internal static HashSet LoadedHiddens = new(); - internal static void UpdateHiddenCharts() + internal static void AddHidden(Album album) { - HideBmsInfoDicPatch.HasUpdate = true; - MusicTagPatch.HasUpdate = true; + var uid = album.Uid; + if (!album.HasDifficulty(4) && !album.HasDifficulty(5)) return; + + if (album.HasDifficulty(5)) + { + var touhouList = new List(); + foreach (var s in DBMusicTagDefine.s_BarrageModeSongUid) touhouList.Add(s); + if (!touhouList.Contains(uid)) + { + touhouList.Add(uid); + var newTouhouArray = new Il2CppStringArray(touhouList.Count); + for (var i = 0; i < touhouList.Count; i++) newTouhouArray[i] = touhouList[i]; + DBMusicTagDefine.s_BarrageModeSongUid = newTouhouArray; + } + } + + if (!album.HasDifficulty(4)) return; + + if (LoadedHiddens.Add(uid)) + { + var hiddenList = new List(); + foreach (var s in DBMusicTagDefine.s_HiddenLocal) hiddenList.Add(s); + if (!hiddenList.Contains(uid)) + { + hiddenList.Add(uid); + var newHiddenArray = new Il2CppStringArray(hiddenList.Count); + for (var i = 0; i < hiddenList.Count; i++) newHiddenArray[i] = hiddenList[i]; + DBMusicTagDefine.s_HiddenLocal = newHiddenArray; + } + + var tagInfo = GlobalDataBase.dbMusicTag.GetAlbumTagInfo(32776); + if (tagInfo?.m_MusicUids != null && !tagInfo.m_MusicUids.Contains(uid)) + tagInfo.m_MusicUids.Add(uid); + } + + var instance = Singleton.instance; + if (instance != null) + { + if (!instance.m_HideBmsInfos.ContainsKey(uid)) + { + instance.m_HideBmsInfos.Add(uid, + new SpecialSongManager.HideBmsInfo( + uid, + album.Info.HideBmsDifficulty == "0" + ? album.HasDifficulty(3) ? 3 : 2 + : album.Info.HideBmsDifficulty.ParseAsInt(), + 4, + $"{album.AlbumName}_map4", + new Func(() => instance.IsInvokeHideBms(uid)) + )); + } + + if (!instance.m_ConfigHideMusic.m_HideMusicObjectMapping.ContainsKey(uid)) + { + var hideMusicInfo = new HideMusicInfo + { + musicUid = uid, + invokeType = album.Info.HideBmsMode switch + { + "CLICK" => (int)HiddenInvokeType.Click, + "PRESS" => (int)HiddenInvokeType.LongPress, + "TOGGLE" => (int)HiddenInvokeType.Toggle, + _ => (int)HiddenInvokeType.None + } + }; + instance.m_ConfigHideMusic.m_HideMusicObjectMapping[uid] = hideMusicInfo; + } + } + } + + internal static void RemoveHidden(string uid) + { + if (LoadedHiddens.Remove(uid)) + { + var hiddenList = new List(); + foreach (var s in DBMusicTagDefine.s_HiddenLocal) hiddenList.Add(s); + if (hiddenList.Remove(uid)) + { + var newHiddenArray = new Il2CppStringArray(hiddenList.Count); + for (var i = 0; i < hiddenList.Count; i++) newHiddenArray[i] = hiddenList[i]; + DBMusicTagDefine.s_HiddenLocal = newHiddenArray; + } + + var tagInfo = GlobalDataBase.dbMusicTag.GetAlbumTagInfo(32776); + if (tagInfo?.m_MusicUids != null) tagInfo.m_MusicUids.Remove(uid); + } + + var touhouList = new List(); + foreach (var s in DBMusicTagDefine.s_BarrageModeSongUid) touhouList.Add(s); + if (touhouList.Remove(uid)) + { + var newTouhouArray = new Il2CppStringArray(touhouList.Count); + for (var i = 0; i < touhouList.Count; i++) newTouhouArray[i] = touhouList[i]; + DBMusicTagDefine.s_BarrageModeSongUid = newTouhouArray; + } + + var instance = Singleton.instance; + if (instance != null) + { + if (instance.m_HideBmsInfos.ContainsKey(uid)) + instance.m_HideBmsInfos.Remove(uid); + + if (instance.m_ConfigHideMusic.m_HideMusicObjectMapping.ContainsKey(uid)) + instance.m_ConfigHideMusic.m_HideMusicObjectMapping.Remove(uid); + } } [HarmonyPatch(typeof(SpecialSongManager), nameof(SpecialSongManager.InitHideBmsInfoDic))] From 2b65d1c598c3c2a430dc5e668ab0a7f2d3da22b4 Mon Sep 17 00:00:00 2001 From: ALLMarvelous <53633401+ALLMarvelous@users.noreply.github.com> Date: Thu, 2 Jul 2026 10:20:33 -0500 Subject: [PATCH 3/4] Remove folder support from hot-reloading entirely --- Managers/HotReloadManager.cs | 548 ++++++++++++++++------------------ Managers/PackManager.cs | 8 +- Patches/AssetPatch.cs | 10 +- Patches/HiddenSupportPatch.cs | 5 +- 4 files changed, 269 insertions(+), 302 deletions(-) diff --git a/Managers/HotReloadManager.cs b/Managers/HotReloadManager.cs index 9fc9787..a69a401 100644 --- a/Managers/HotReloadManager.cs +++ b/Managers/HotReloadManager.cs @@ -38,20 +38,9 @@ private static bool IsFileUnlocked(string path) { try { - if (Directory.Exists(path)) - { - var infoPath = Path.Combine(path, "info.json"); - if (!File.Exists(infoPath)) return false; - - using var fileStream = File.Open(infoPath, FileMode.Open, FileAccess.Read, FileShare.None); - return fileStream.Length > 0; - } - else - { - if (!File.Exists(path)) return false; - using var fileStream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None); - return fileStream.Length > 0; - } + if (!File.Exists(path)) return false; + using var fileStream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None); + return fileStream.Length > 0; } catch (Exception ex) when (ex is FileNotFoundException or IOException or UnauthorizedAccessException) { @@ -62,12 +51,12 @@ private static bool IsFileUnlocked(string path) private static string GetTopLevelName(string relativePath) { - var separatorIndex = relativePath.IndexOfAny(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }); + var separatorIndex = + relativePath.IndexOfAny(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }); return separatorIndex >= 0 ? relativePath.Substring(0, separatorIndex) : relativePath; } - private static MusicExInfo CreateMusicExInfo(Album album) { var changedDiff = new Il2CppStructArray(5) @@ -94,134 +83,152 @@ private static MusicExInfo CreateMusicExInfo(Album album) private static int ProcessAdditions() { var addedCount = 0; - - if (AlbumsToAdd.TryDequeue(out var path)) - try + if (!AlbumsToAdd.TryDequeue(out var path)) return addedCount; + + try + { + var newAlbums = new List(); + if (path.EndsWith(".mdp", StringComparison.OrdinalIgnoreCase)) + { + var pack = AlbumManager.LoadPack(path); + if (pack != null) newAlbums.AddRange(pack.Albums); + } + else { var album = AlbumManager.LoadOne(path); - if (album == null) Logger.Warning($"Failed to load album from {path}"); + if (album != null) newAlbums.Add(album); + } - var albumName = album.AlbumName; + if (newAlbums.Count == 0) + { + Logger.Warning($"Failed to load album(s) from {path}"); + return 0; // Abort this addition + } + + foreach (var album in newAlbums) + { var uid = $"{AlbumManager.Uid}-{album.Index}"; - var albumInfo = album.Info; - Logger.Msg($"Adding {albumName} (UID: {uid})"); + Logger.Msg($"Adding {album.AlbumName} (UID: {uid})"); + } + + var masterAlbums = Singleton.instance.GetConfigObject(); + var albumsInfo = masterAlbums?.GetAlbumsInfoByUid(AlbumManager.MusicPackage); + var globalAlbumConfig = albumsInfo != null + ? Singleton.instance.GetConfigObject(albumsInfo.albumJsonIndex) + : null; - var masterAlbums = Singleton.instance.GetConfigObject(); - var albumsInfo = masterAlbums?.GetAlbumsInfoByUid(AlbumManager.MusicPackage); - var globalAlbumConfig = albumsInfo != null - ? Singleton.instance.GetConfigObject(albumsInfo.albumJsonIndex) - : null; + if (globalAlbumConfig != null) + { + var jsonArray = new JsonArray(); + var localJsonArray = new JsonArray(); - if (globalAlbumConfig != null) + foreach (var (albumStr, albumObj) in AlbumManager.LoadedAlbums) { - var jsonArray = new JsonArray(); - var localJsonArray = new JsonArray(); + var aInfo = albumObj.Info; + var displayName = aInfo.Name ?? ""; - foreach (var (albumStr, albumObj) in AlbumManager.LoadedAlbums) + var customChartJson = new { - var aInfo = albumObj.Info; - var displayName = aInfo.Name ?? ""; + uid = albumObj.Uid, + name = displayName, + author = aInfo.Author ?? "", + bpm = aInfo.Bpm ?? "0", + music = $"{albumStr}_music", + demo = $"{albumStr}_demo", + cover = $"{albumStr}_cover", + noteJson = $"{albumStr}_map", + scene = aInfo.Scene ?? "scene_01", + unlockLevel = "0", + levelDesigner = aInfo.LevelDesigner ?? "", + levelDesigner1 = aInfo.LevelDesigner1 ?? aInfo.LevelDesigner ?? "", + levelDesigner2 = aInfo.LevelDesigner2 ?? aInfo.LevelDesigner ?? "", + levelDesigner3 = aInfo.LevelDesigner3 ?? aInfo.LevelDesigner ?? "", + levelDesigner4 = aInfo.LevelDesigner4 ?? aInfo.LevelDesigner ?? "", + levelDesigner5 = aInfo.LevelDesigner5 ?? aInfo.LevelDesigner ?? "", + difficulty1 = albumObj.HasDifficulty(1) ? aInfo.Difficulty1 ?? "0" : "0", + difficulty2 = albumObj.HasDifficulty(2) ? aInfo.Difficulty2 ?? "0" : "0", + difficulty3 = albumObj.HasDifficulty(3) ? aInfo.Difficulty3 ?? "0" : "0", + difficulty4 = albumObj.HasDifficulty(4) ? aInfo.Difficulty4 ?? "0" : "0", + difficulty5 = albumObj.HasDifficulty(5) ? aInfo.Difficulty5 ?? "0" : "0" + }; + jsonArray.Add(JsonSerializer.SerializeToNode(customChartJson)); - var customChartJson = new - { - uid = albumObj.Uid, - name = displayName, - author = aInfo.Author ?? "", - bpm = aInfo.Bpm ?? "0", - music = $"{albumStr}_music", - demo = $"{albumStr}_demo", - cover = $"{albumStr}_cover", - noteJson = $"{albumStr}_map", - scene = aInfo.Scene ?? "scene_01", - unlockLevel = "0", - levelDesigner = aInfo.LevelDesigner ?? "", - levelDesigner1 = aInfo.LevelDesigner1 ?? aInfo.LevelDesigner ?? "", - levelDesigner2 = aInfo.LevelDesigner2 ?? aInfo.LevelDesigner ?? "", - levelDesigner3 = aInfo.LevelDesigner3 ?? aInfo.LevelDesigner ?? "", - levelDesigner4 = aInfo.LevelDesigner4 ?? aInfo.LevelDesigner ?? "", - levelDesigner5 = aInfo.LevelDesigner5 ?? aInfo.LevelDesigner ?? "", - difficulty1 = aInfo.Difficulty1 ?? "0", - difficulty2 = aInfo.Difficulty2 ?? "0", - difficulty3 = aInfo.Difficulty3 ?? "0", - difficulty4 = aInfo.Difficulty4 ?? "0", - difficulty5 = aInfo.Difficulty5 ?? "0" - }; - jsonArray.Add(JsonSerializer.SerializeToNode(customChartJson)); - - localJsonArray.Add(JsonSerializer.SerializeToNode(new - { - name = displayName, - author = aInfo.Author ?? "" - })); - } + localJsonArray.Add(JsonSerializer.SerializeToNode(new + { + name = displayName, + author = aInfo.Author ?? "" + })); + } - var fullJsonStr = JsonSerializer.Serialize(jsonArray); - var fullLocalJsonStr = JsonSerializer.Serialize(localJsonArray); + var fullJsonStr = JsonSerializer.Serialize(jsonArray); + var fullLocalJsonStr = JsonSerializer.Serialize(localJsonArray); - globalAlbumConfig.Deserialize(fullJsonStr); + globalAlbumConfig.Deserialize(fullJsonStr); - var localDicProp = - typeof(BaseDBConfigLocalObject).GetProperty("m_LocalDic", - BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); - if (localDicProp != null) + var localDicProp = + typeof(BaseDBConfigLocalObject).GetProperty("m_LocalDic", + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + if (localDicProp != null) + if (localDicProp.GetValue(globalAlbumConfig) is + Il2CppSystem.Collections.Generic.Dictionary globalLocalDic) { - var globalLocalDic = - localDicProp.GetValue(globalAlbumConfig) as - Il2CppSystem.Collections.Generic.Dictionary; - if (globalLocalDic != null) + globalLocalDic.Clear(); + for (var i = 0; i <= 15; i++) { - globalLocalDic.Clear(); - for (var i = 0; i <= 15; i++) - { - var newLocalAlbum = new DBConfigLocalALBUM(); - newLocalAlbum.Deserialize(fullLocalJsonStr); - globalLocalDic.Add(i, newLocalAlbum); - } + var newLocalAlbum = new DBConfigLocalALBUM(); + newLocalAlbum.Deserialize(fullLocalJsonStr); + globalLocalDic.Add(i, newLocalAlbum); } } - GlobalDataBase.s_DbMusicTag.AddAllMusicInfo(globalAlbumConfig); + GlobalDataBase.s_DbMusicTag.AddAllMusicInfo(globalAlbumConfig); - var newMusicInfoList = new Il2CppSystem.Collections.Generic.List(); - globalAlbumConfig.GetAllMusicInfo(newMusicInfoList); - var idx = 0; - foreach (var m in newMusicInfoList) + var newMusicInfoList = new Il2CppSystem.Collections.Generic.List(); + globalAlbumConfig.GetAllMusicInfo(newMusicInfoList); + var idx = 0; + foreach (var m in newMusicInfoList) + { + var uidSplit = m.uid.Split('-'); + if (uidSplit.Length < 2) { - var uidSplit = m.uid.Split('-'); - if (uidSplit.Length < 2) - { - idx++; - continue; - } - - if (!int.TryParse(uidSplit[1], out var parsedIndex)) - { - idx++; - continue; - } + idx++; + continue; + } - var aObj = AlbumManager.LoadedAlbums.Values.FirstOrDefault(a => a.Index == parsedIndex); - if (aObj != null) - { - m.Init(idx); - m.InitExInfo(); - m.m_MusicExInfo = CreateMusicExInfo(aObj); + if (!int.TryParse(uidSplit[1], out var parsedIndex)) + { + idx++; + continue; + } - HotLoadedMusicInfos[m.uid] = m; - HotLoadedMusicNames[m.uid] = aObj.Info.Name ?? ""; - HotLoadedMusicAuthors[m.uid] = aObj.Info.Author ?? ""; - } + var aObj = AlbumManager.LoadedAlbums.Values.FirstOrDefault(a => a.Index == parsedIndex); + if (aObj != null) + { + m.Init(idx); + m.InitExInfo(); + m.m_MusicExInfo = CreateMusicExInfo(aObj); - idx++; + HotLoadedMusicInfos[m.uid] = m; + HotLoadedMusicNames[m.uid] = aObj.Info.Name ?? ""; + HotLoadedMusicAuthors[m.uid] = aObj.Info.Author ?? ""; } - Logger.Msg($"Transmuted MusicInfo for {uid}"); - } - else - { - Logger.Error("globalAlbumConfig is null! Cannot inject metadata."); + idx++; } + Logger.Msg("Transmuted MusicInfo for new albums"); + } + else + { + Logger.Error("globalAlbumConfig is null! Cannot inject metadata."); + } + + foreach (var album in newAlbums) + { + var uid = album.Uid; + var albumName = album.AlbumName; + var albumInfo = album.Info; + try { var dhColBase = DataHelper.collections; @@ -301,16 +308,17 @@ private static int ProcessAdditions() { Logger.Warning($"Failed to add hidden support: {ex.Message}"); } - - addedCount++; - Logger.Msg($"Successfully added {albumInfo.Name}"); - } - catch (Exception ex) - { - Logger.Warning($"Error adding album: {ex.Message}"); - Logger.Warning(ex.StackTrace); } + addedCount += newAlbums.Count; + Logger.Msg($"Successfully added {newAlbums.Count} albums"); + } + catch (Exception ex) + { + Logger.Warning($"Error adding album: {ex.Message}"); + Logger.Warning(ex.StackTrace); + } + return addedCount; } @@ -318,80 +326,98 @@ private static int ProcessDeletions() { var deletedCount = 0; - if (AlbumsToDelete.TryDequeue(out var albumKey)) + if (AlbumsToDelete.TryDequeue(out var path)) try { - Logger.Msg($"Removing {albumKey}"); + Logger.Msg($"Processing deletion for {path}"); - if (!AlbumManager.LoadedAlbums.TryGetValue(albumKey, out var album)) - Logger.Warning($"Album {albumKey} not found"); + var fullPath = Path.GetFullPath(path); + var albumsToRemove = AlbumManager.LoadedAlbums.Values + .Where(a => Path.GetFullPath(a.Path).Equals(fullPath, StringComparison.OrdinalIgnoreCase)) + .ToList(); - var uid = $"{AlbumManager.Uid}-{album.Index}"; - - HotLoadedMusicInfos.Remove(uid); - HotLoadedMusicNames.Remove(uid); - HotLoadedMusicAuthors.Remove(uid); - - try + if (path.EndsWith(".mdp", StringComparison.OrdinalIgnoreCase)) { - HiddenSupportPatch.RemoveHidden(uid); + PackManager.RemovePacksByPath(fullPath); + Logger.Msg($"Removed pack at {fullPath}"); } - catch (Exception ex) + + if (albumsToRemove.Count == 0) { - Logger.Warning($"Failed to remove hidden support: {ex.Message}"); + Logger.Warning($"No loaded albums found for path {path}"); + return 0; } - // Remove from game music database - try + foreach (var album in albumsToRemove) { - var musicInfo = GlobalDataBase.s_DbMusicTag.GetMusicInfoFromAll(uid); - if (musicInfo != null) GlobalDataBase.s_DbMusicTag.RemoveShowMusicUid(musicInfo); + var albumKey = album.AlbumName; + var uid = $"{AlbumManager.Uid}-{album.Index}"; - var allMusicInfo = GlobalDataBase.s_DbMusicTag.m_AllMusicInfo; - if (allMusicInfo != null && allMusicInfo.ContainsKey(uid)) allMusicInfo.Remove(uid); + HotLoadedMusicInfos.Remove(uid); + HotLoadedMusicNames.Remove(uid); + HotLoadedMusicAuthors.Remove(uid); - if (GlobalDataBase.s_DbMusicTag.m_AllAlbumTagData != null) - foreach (var tag in GlobalDataBase.s_DbMusicTag.m_AllAlbumTagData) - { - var tagInfo = tag.Value; - if (tagInfo.m_MusicUids != null && tagInfo.m_MusicUids.Contains(uid)) - tagInfo.m_MusicUids.Remove(uid); - if (tagInfo.m_DisplayMusicUids != null) - foreach (var d in tagInfo.m_DisplayMusicUids) - if (d.musicUids != null && d.musicUids.Contains(uid)) - d.musicUids.Remove(uid); - } - } - catch (Exception ex) - { - Logger.Warning($"Failed to remove from database: {ex.Message}"); - } + try + { + HiddenSupportPatch.RemoveHidden(uid); + } + catch (Exception ex) + { + Logger.Warning($"Failed to remove hidden support: {ex.Message}"); + } - // Remove from ConfigManager - try - { - var config = Singleton.instance.GetConfigObject(); - if (config != null) - if (config.m_Dictionary.ContainsKey(uid)) - { - var tagInfo = config.m_Dictionary[uid]; - config.m_Dictionary.Remove(uid); - config.list.Remove(tagInfo); - } - } - catch (Exception ex) - { - Logger.Warning($"Failed to remove search tags: {ex.Message}"); - } + // Remove from game music database + try + { + var musicInfo = GlobalDataBase.s_DbMusicTag.GetMusicInfoFromAll(uid); + if (musicInfo != null) GlobalDataBase.s_DbMusicTag.RemoveShowMusicUid(musicInfo); - // Clear resource cache - AlbumManager.LoadedAlbums.Remove(albumKey); - AssetPatch.RemoveFromCache($"{albumKey}_demo"); - AssetPatch.RemoveFromCache($"{albumKey}_music"); - AssetPatch.RemoveFromCache($"{albumKey}_cover"); + var allMusicInfo = GlobalDataBase.s_DbMusicTag.m_AllMusicInfo; + if (allMusicInfo != null && allMusicInfo.ContainsKey(uid)) allMusicInfo.Remove(uid); - deletedCount++; - Logger.Msg($"Removed {albumKey}"); + if (GlobalDataBase.s_DbMusicTag.m_AllAlbumTagData != null) + foreach (var tag in GlobalDataBase.s_DbMusicTag.m_AllAlbumTagData) + { + var tagInfo = tag.Value; + if (tagInfo.m_MusicUids != null && tagInfo.m_MusicUids.Contains(uid)) + tagInfo.m_MusicUids.Remove(uid); + if (tagInfo.m_DisplayMusicUids != null) + foreach (var d in tagInfo.m_DisplayMusicUids) + if (d.musicUids != null && d.musicUids.Contains(uid)) + d.musicUids.Remove(uid); + } + } + catch (Exception ex) + { + Logger.Warning($"Failed to remove from database: {ex.Message}"); + } + + // Remove from ConfigManager + try + { + var config = Singleton.instance.GetConfigObject(); + if (config != null) + if (config.m_Dictionary.ContainsKey(uid)) + { + var tagInfo = config.m_Dictionary[uid]; + config.m_Dictionary.Remove(uid); + config.list.Remove(tagInfo); + } + } + catch (Exception ex) + { + Logger.Warning($"Failed to remove search tags: {ex.Message}"); + } + + // Clear resource cache + AlbumManager.LoadedAlbums.Remove(albumKey); + AssetPatch.RemoveFromCache($"{albumKey}_demo"); + AssetPatch.RemoveFromCache($"{albumKey}_music"); + AssetPatch.RemoveFromCache($"{albumKey}_cover"); + + deletedCount++; + Logger.Msg($"Removed {albumKey}"); + } } catch (Exception ex) { @@ -444,7 +470,7 @@ private static void RefreshUI() if (stage != null && stage.gameObject.activeInHierarchy) { stage.RefreshStageUI(); - Logger.Msg("UI refreshed"); + Logger.Msg("UI refreshed (without InitSpecialsMusic)"); } } catch (Exception ex) @@ -466,8 +492,7 @@ internal static void FixedUpdate() var oldSelectedAlbumName = AlbumManager.GetAlbumNameFromUid(oldSelectedUid); var deletedCount = ProcessDeletions(); - var addedCount = 0; - if (deletedCount == 0) addedCount = ProcessAdditions(); + var addedCount = ProcessAdditions(); if (deletedCount > 0 || addedCount > 0) { @@ -510,22 +535,21 @@ internal static void OnLateInitializeMelon() } AlbumManager.AlbumWatcher.Path = watchPath; - AlbumManager.AlbumWatcher.IncludeSubdirectories = true; + // No longer tracking subdirectories, only single mdm/mdp files in Custom_Albums + AlbumManager.AlbumWatcher.IncludeSubdirectories = false; AlbumManager.AlbumWatcher.Created += (_, e) => { - var topLevelName = GetTopLevelName(e.Name); - var fullPath = Path.Combine(watchPath, topLevelName); + if (!e.Name.EndsWith(".mdm", StringComparison.OrdinalIgnoreCase) && + !e.Name.EndsWith(".mdp", StringComparison.OrdinalIgnoreCase)) return; var now = DateTime.Now; - if (LastFileEvent.TryGetValue(topLevelName, out var lastTime) && + if (LastFileEvent.TryGetValue(e.Name, out var lastTime) && (now - lastTime).TotalMilliseconds < 500) return; - LastFileEvent[topLevelName] = now; + LastFileEvent[e.Name] = now; - var isMdm = topLevelName.EndsWith(".mdm"); - if (!isMdm && !Directory.Exists(fullPath)) return; - - Logger.Msg($"Detected new file or folder: {topLevelName}"); + var fullPath = e.FullPath; + Logger.Msg($"Detected new file: {e.Name}"); Task.Run(() => { var attempts = 0; @@ -538,71 +562,42 @@ internal static void OnLateInitializeMelon() if (attempts < 50) { AlbumsToAdd.Enqueue(fullPath); - Logger.Msg($"Queued for addition: {topLevelName}"); + Logger.Msg($"Queued for addition: {e.Name}"); } else { - Logger.Warning($"Timed out waiting for file: {topLevelName}"); + Logger.Warning($"Timed out waiting for file: {e.Name}"); } }); }; AlbumManager.AlbumWatcher.Deleted += (_, e) => { - var topLevelName = GetTopLevelName(e.Name); - var isInnerFile = e.Name != topLevelName; - var fullPath = Path.Combine(watchPath, topLevelName); + if (!e.Name.EndsWith(".mdm", StringComparison.OrdinalIgnoreCase) && + !e.Name.EndsWith(".mdp", StringComparison.OrdinalIgnoreCase)) return; var now = DateTime.Now; - if (LastFileEvent.TryGetValue(topLevelName, out var lastTime) && + if (LastFileEvent.TryGetValue(e.Name, out var lastTime) && (now - lastTime).TotalMilliseconds < 500) return; - LastFileEvent[topLevelName] = now; - - var isMdm = topLevelName.EndsWith(".mdm"); - var albumKey = isMdm ? $"album_{Path.GetFileNameWithoutExtension(topLevelName)}" : $"album_{topLevelName}_folder"; - if (!isMdm && !AlbumManager.LoadedAlbums.ContainsKey(albumKey)) return; + LastFileEvent[e.Name] = now; - if (isInnerFile) - { - Logger.Msg($"Detected inner deletion: {e.Name}, reloading {topLevelName}"); - Task.Run(() => - { - var attempts = 0; - while (!IsFileUnlocked(fullPath) && attempts < 50) - { - Thread.Sleep(200); - attempts++; - } - if (attempts < 50) - { - AlbumsToDelete.Enqueue(albumKey); - AlbumsToAdd.Enqueue(fullPath); - Logger.Msg($"Queued for reload: {topLevelName}"); - } - }); - } - else - { - Logger.Msg($"Detected deletion: {topLevelName}"); - AlbumsToDelete.Enqueue(albumKey); - } + Logger.Msg($"Detected deletion: {e.Name}"); + AlbumsToDelete.Enqueue(e.FullPath); }; AlbumManager.AlbumWatcher.Changed += (_, e) => { if (e.ChangeType != WatcherChangeTypes.Changed) return; - var topLevelName = GetTopLevelName(e.Name); - var fullPath = Path.Combine(watchPath, topLevelName); + + if (!e.Name.EndsWith(".mdm", StringComparison.OrdinalIgnoreCase) && + !e.Name.EndsWith(".mdp", StringComparison.OrdinalIgnoreCase)) return; var now = DateTime.Now; - if (LastFileEvent.TryGetValue(topLevelName, out var lastTime) && + if (LastFileEvent.TryGetValue(e.Name, out var lastTime) && (now - lastTime).TotalMilliseconds < 500) return; - LastFileEvent[topLevelName] = now; - - var isMdm = topLevelName.EndsWith(".mdm"); - var albumKey = isMdm ? $"album_{Path.GetFileNameWithoutExtension(topLevelName)}" : $"album_{topLevelName}_folder"; - if (!isMdm && !AlbumManager.LoadedAlbums.ContainsKey(albumKey)) return; + LastFileEvent[e.Name] = now; + var fullPath = e.FullPath; Logger.Msg($"Detected change: {e.Name}"); Task.Run(() => { @@ -615,75 +610,40 @@ internal static void OnLateInitializeMelon() if (attempts < 50) { - AlbumsToDelete.Enqueue(albumKey); + AlbumsToDelete.Enqueue(fullPath); AlbumsToAdd.Enqueue(fullPath); - Logger.Msg($"Queued for reload: {topLevelName}"); + Logger.Msg($"Queued for reload: {e.Name}"); } else { - Logger.Warning($"Timed out waiting for file: {topLevelName}"); + Logger.Warning($"Timed out waiting for file: {e.Name}"); } }); }; AlbumManager.AlbumWatcher.Renamed += (_, e) => { - var oldTopLevelName = GetTopLevelName(e.OldName); - var newTopLevelName = GetTopLevelName(e.Name); - var isInnerRename = e.OldName != oldTopLevelName || e.Name != newTopLevelName; - var fullPath = Path.Combine(watchPath, newTopLevelName); - - var now = DateTime.Now; - if (LastFileEvent.TryGetValue(newTopLevelName, out var lastTime) && - (now - lastTime).TotalMilliseconds < 500) return; - LastFileEvent[newTopLevelName] = now; + var isOldMdm = e.OldName.EndsWith(".mdm", StringComparison.OrdinalIgnoreCase); + var isOldMdp = e.OldName.EndsWith(".mdp", StringComparison.OrdinalIgnoreCase); + var isNewMdm = e.Name.EndsWith(".mdm", StringComparison.OrdinalIgnoreCase); + var isNewMdp = e.Name.EndsWith(".mdp", StringComparison.OrdinalIgnoreCase); - if (isInnerRename) - { - var isMdm = newTopLevelName.EndsWith(".mdm"); - var albumKey = isMdm ? $"album_{Path.GetFileNameWithoutExtension(newTopLevelName)}" : $"album_{newTopLevelName}_folder"; - if (!isMdm && !AlbumManager.LoadedAlbums.ContainsKey(albumKey)) return; + if (!isOldMdm && !isOldMdp && !isNewMdm && !isNewMdp) return; - Logger.Msg($"Detected inner rename: {e.OldName} -> {e.Name}, reloading {newTopLevelName}"); - Task.Run(() => - { - var attempts = 0; - while (!IsFileUnlocked(fullPath) && attempts < 50) - { - Thread.Sleep(200); - attempts++; - } - if (attempts < 50) - { - AlbumsToDelete.Enqueue(albumKey); - AlbumsToAdd.Enqueue(fullPath); - Logger.Msg($"Queued for reload: {newTopLevelName}"); - } - }); - return; - } - - var isOldMdm = oldTopLevelName.EndsWith(".mdm"); - var isNewMdm = newTopLevelName.EndsWith(".mdm"); - - var oldKey = isOldMdm ? $"album_{Path.GetFileNameWithoutExtension(oldTopLevelName)}" : $"album_{oldTopLevelName}_folder"; - var newKey = isNewMdm ? $"album_{Path.GetFileNameWithoutExtension(newTopLevelName)}" : $"album_{newTopLevelName}_folder"; + var now = DateTime.Now; + if (LastFileEvent.TryGetValue(e.Name, out var lastTime) && + (now - lastTime).TotalMilliseconds < 500) return; + LastFileEvent[e.Name] = now; - if (!isOldMdm && !isNewMdm && !AlbumManager.LoadedAlbums.ContainsKey(oldKey) && !Directory.Exists(fullPath)) return; + Logger.Msg($"Detected rename: {e.OldName} -> {e.Name}"); - Logger.Msg($"Detected rename: {oldTopLevelName} -> {newTopLevelName}"); + // Enqueue deletion for the old path (if it was an mdm/mdp) + if (isOldMdm || isOldMdp) AlbumsToDelete.Enqueue(e.OldFullPath); - if (AlbumManager.LoadedAlbums.Remove(oldKey, out var album)) - { - AlbumManager.LoadedAlbums.TryAdd(newKey, album); - AssetPatch.ModifyCacheKey($"{oldKey}_demo", $"{newKey}_demo"); - AssetPatch.ModifyCacheKey($"{oldKey}_music", $"{newKey}_music"); - AssetPatch.ModifyCacheKey($"{oldKey}_cover", $"{newKey}_cover"); - Logger.Msg($"Renamed {oldKey} -> {newKey}"); - } - else + // Enqueue addition for the new path (if it is an mdm/mdp) + if (isNewMdm || isNewMdp) { - Logger.Msg($"Old file was not loaded, treating as new file: {newTopLevelName}"); + var fullPath = e.FullPath; Task.Run(() => { var attempts = 0; @@ -696,11 +656,11 @@ internal static void OnLateInitializeMelon() if (attempts < 50) { AlbumsToAdd.Enqueue(fullPath); - Logger.Msg($"Queued for addition: {newTopLevelName}"); + Logger.Msg($"Queued for addition: {e.Name}"); } else { - Logger.Warning($"Timed out waiting for file: {newTopLevelName}"); + Logger.Warning($"Timed out waiting for file: {e.Name}"); } }); } diff --git a/Managers/PackManager.cs b/Managers/PackManager.cs index dbe35b3..7ca19a5 100644 --- a/Managers/PackManager.cs +++ b/Managers/PackManager.cs @@ -1,4 +1,4 @@ -using System.IO.Compression; +using System.IO.Compression; using CustomAlbums.Data; using CustomAlbums.Utilities; @@ -33,4 +33,10 @@ internal static void AddPack(Pack pack) { Packs.Add(pack); } + + internal static void RemovePacksByPath(string path) + { + var fullPath = Path.GetFullPath(path); + Packs.RemoveAll(p => Path.GetFullPath(p.Path).Equals(fullPath, StringComparison.OrdinalIgnoreCase)); + } } \ No newline at end of file diff --git a/Patches/AssetPatch.cs b/Patches/AssetPatch.cs index 8c84f5e..64bb10e 100644 --- a/Patches/AssetPatch.cs +++ b/Patches/AssetPatch.cs @@ -122,11 +122,11 @@ internal static void InitializeHandler() levelDesigner3 = albumInfo.LevelDesigner3 ?? albumInfo.LevelDesigner, levelDesigner4 = albumInfo.LevelDesigner4 ?? albumInfo.LevelDesigner, levelDesigner5 = albumInfo.LevelDesigner5 ?? albumInfo.LevelDesigner, - difficulty1 = albumInfo.Difficulty1 ?? "0", - difficulty2 = albumInfo.Difficulty2, - difficulty3 = albumInfo.Difficulty3 ?? "0", - difficulty4 = albumInfo.Difficulty4 ?? "0", - difficulty5 = albumInfo.Difficulty5 ?? "0" + difficulty1 = albumObj.HasDifficulty(1) ? albumInfo.Difficulty1 ?? "0" : "0", + difficulty2 = albumObj.HasDifficulty(2) ? albumInfo.Difficulty2 ?? "0" : "0", + difficulty3 = albumObj.HasDifficulty(3) ? albumInfo.Difficulty3 ?? "0" : "0", + difficulty4 = albumObj.HasDifficulty(4) ? albumInfo.Difficulty4 ?? "0" : "0", + difficulty5 = albumObj.HasDifficulty(5) ? albumInfo.Difficulty5 ?? "0" : "0" }; jsonArray.Add(customChartJson); diff --git a/Patches/HiddenSupportPatch.cs b/Patches/HiddenSupportPatch.cs index 838603a..0c3c9be 100644 --- a/Patches/HiddenSupportPatch.cs +++ b/Patches/HiddenSupportPatch.cs @@ -57,7 +57,6 @@ internal static void AddHidden(Album album) if (instance != null) { if (!instance.m_HideBmsInfos.ContainsKey(uid)) - { instance.m_HideBmsInfos.Add(uid, new SpecialSongManager.HideBmsInfo( uid, @@ -68,7 +67,6 @@ internal static void AddHidden(Album album) $"{album.AlbumName}_map4", new Func(() => instance.IsInvokeHideBms(uid)) )); - } if (!instance.m_ConfigHideMusic.m_HideMusicObjectMapping.ContainsKey(uid)) { @@ -122,6 +120,9 @@ internal static void RemoveHidden(string uid) if (instance.m_ConfigHideMusic.m_HideMusicObjectMapping.ContainsKey(uid)) instance.m_ConfigHideMusic.m_HideMusicObjectMapping.Remove(uid); + + if (instance.m_IsInvokeHideDic.ContainsKey(uid)) + instance.m_IsInvokeHideDic.Remove(uid); } } From 11bdecfb7df82219576e1156f38647d518fabf06 Mon Sep 17 00:00:00 2001 From: ALLMarvelous <53633401+ALLMarvelous@users.noreply.github.com> Date: Thu, 2 Jul 2026 12:19:51 -0500 Subject: [PATCH 4/4] Bump version --- Main.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Main.cs b/Main.cs index 59d5849..ea16836 100644 --- a/Main.cs +++ b/Main.cs @@ -10,7 +10,7 @@ public class Main : MelonMod { public const string MelonName = "CustomAlbums"; public const string MelonAuthor = "Two Fellas"; - public const string MelonVersion = "4.2.0"; + public const string MelonVersion = "4.2.1"; private static readonly Logger Logger = new("CustomAlbums"); public override void OnInitializeMelon()