diff --git a/Albums/ArchiveAlbum.cs b/Albums/ArchiveAlbum.cs new file mode 100644 index 0000000..aaf773d --- /dev/null +++ b/Albums/ArchiveAlbum.cs @@ -0,0 +1,82 @@ +using System.IO.Compression; +using CustomAlbums.Data; +using CustomAlbums.Utilities; + +namespace CustomAlbums.Albums; + +public class ArchiveAlbum : Album +{ + public ArchiveAlbum(string path, int index) + { + if (!File.Exists(path)) + { + Logger.Error($"Could not find album package at: {path}"); + throw new FileNotFoundException(); + } + + using var zip = ZipFile.OpenRead(path); + var info = zip.GetEntry("info.json"); + if (info == null) + { + Logger.Error($"Could not find info.json in package: {path}"); + throw new FileNotFoundException(); + } + + using var stream = info.Open(); + Info = Json.Deserialize(stream); + HasPng = zip.GetEntry("cover.png") != null; + + Index = index; + Path = path; + + GetSheets(); + } + + public override string AlbumName => $"album_{System.IO.Path.GetFileNameWithoutExtension(Path)}"; + + public override bool HasFile(string name) + { + if (!File.Exists(Path)) return false; + try + { + using var zip = ZipFile.OpenRead(Path); + return zip.GetEntry(name) != null; + } + catch (IOException) + { + return false; + } + } + + public override Stream OpenFileStreamIfPossible(string file) + { + using var zip = ZipFile.OpenRead(Path); + var entry = zip.GetEntry(file); + + if (entry != null) return entry.Open().ToMemoryStream(); + + Logger.Error($"Could not find file in package: {file}"); + throw new FileNotFoundException(); + } + + public override Stream OpenNullableStream(string file) + { + using var zip = ZipFile.OpenRead(Path); + var entry = zip.GetEntry(file); + + if (entry != null) return entry.Open().ToMemoryStream(); + + return null; + } + + public override MemoryStream OpenMemoryStream(string file) + { + using var zip = ZipFile.OpenRead(Path); + var entry = zip.GetEntry(file); + + if (entry != null) return entry.Open().ToMemoryStream(); + + Logger.Error($"Could not find file in package: {file}"); + throw new FileNotFoundException(); + } +} \ No newline at end of file diff --git a/Albums/FolderAlbum.cs b/Albums/FolderAlbum.cs new file mode 100644 index 0000000..dd3e5a2 --- /dev/null +++ b/Albums/FolderAlbum.cs @@ -0,0 +1,74 @@ +using CustomAlbums.Data; +using CustomAlbums.Utilities; + +namespace CustomAlbums.Albums; + +public class FolderAlbum : Album +{ + public FolderAlbum(string path, int index) + { + if (!Directory.Exists(path)) + { + Logger.Error($"Could not find album directory at: {path}"); + throw new DirectoryNotFoundException(); + } + + var infoPath = System.IO.Path.Combine(path, "info.json"); + if (!File.Exists(infoPath)) + { + Logger.Error($"Could not find info.json at: {infoPath}"); + throw new FileNotFoundException(); + } + + using var fileStream = File.OpenRead(infoPath); + Info = Json.Deserialize(fileStream); + HasPng = File.Exists(System.IO.Path.Combine(path, "cover.png")); + + Index = index; + Path = path; + + GetSheets(); + } + + public override string AlbumName => $"album_{System.IO.Path.GetFileName(Path)}_folder"; + + protected override string GetCoverUrl(string cacheDir) + { + return "file:///" + System.IO.Path.Combine(Path, "cover.png").Replace('\\', '/'); + } + + public override bool HasFile(string name) + { + var path = System.IO.Path.Combine(Path, name); + return File.Exists(path); + } + + public override Stream OpenFileStreamIfPossible(string file) + { + var path = System.IO.Path.Combine(Path, file); + if (File.Exists(path)) + return File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + + Logger.Error($"Could not find file: {path}"); + throw new FileNotFoundException(); + } + + public override Stream OpenNullableStream(string file) + { + var path = System.IO.Path.Combine(Path, file); + if (File.Exists(path)) + return File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + + return null; + } + + public override MemoryStream OpenMemoryStream(string file) + { + var path = System.IO.Path.Combine(Path, file); + if (File.Exists(path)) + return File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite).ToMemoryStream(); + + Logger.Error($"Could not find file: {path}"); + throw new FileNotFoundException(); + } +} \ No newline at end of file diff --git a/Albums/PackAlbum.cs b/Albums/PackAlbum.cs new file mode 100644 index 0000000..e6a52ee --- /dev/null +++ b/Albums/PackAlbum.cs @@ -0,0 +1,89 @@ +using System.IO.Compression; +using CustomAlbums.Data; +using CustomAlbums.Utilities; + +namespace CustomAlbums.Albums; + +public class PackAlbum : Album +{ + public PackAlbum(string directory, ZipArchiveEntry mdm, int index, string packName = null) + { + if (!string.IsNullOrEmpty(packName)) PackName = packName; + + using var mdmStream = mdm.Open(); + using var openedZip = new ZipArchive(mdmStream); + + var info = openedZip.GetEntry("info.json"); + if (info == null) + { + Logger.Error($"Could not find info.json in package: {mdm.Name}"); + throw new FileNotFoundException(); + } + + using var stream = info.Open(); + Info = Json.Deserialize(stream); + HasPng = openedZip.GetEntry("cover.png") != null; + + Index = index; + Path = directory; + PackAlbumName = System.IO.Path.GetFileNameWithoutExtension(mdm.Name); + + GetSheets(); + } + + public string PackName { get; } + public string PackAlbumName { get; } + + public override string AlbumName => + $"album_{(string.IsNullOrEmpty(PackAlbumName) ? System.IO.Path.GetFileNameWithoutExtension(Path) : string.Empty)}{(PackName != null ? $"{PackAlbumName}_{PackName}" : string.Empty)}"; + + public override bool HasFile(string name) + { + if (!File.Exists(Path)) return false; + try + { + using var mdp = ZipFile.OpenRead(Path); + using var openedMdm = mdp.GetNestedZip(PackAlbumName + ".mdm"); + return openedMdm.GetEntry(name) != null; + } + catch (IOException) + { + return false; + } + } + + public override Stream OpenFileStreamIfPossible(string file) + { + using var mdp = ZipFile.OpenRead(Path); + using var openedMdm = mdp.GetNestedZip(PackAlbumName + ".mdm"); + var entry = openedMdm.GetEntry(file); + + if (entry != null) return entry.Open().ToMemoryStream(); + + Logger.Error($"Could not find file in package: {file}"); + throw new FileNotFoundException(); + } + + public override Stream OpenNullableStream(string file) + { + using var mdp = ZipFile.OpenRead(Path); + using var openedMdm = mdp.GetNestedZip(PackAlbumName + ".mdm"); + var entry = openedMdm.GetEntry(file); + + if (entry != null) return entry.Open().ToMemoryStream(); + + return null; + } + + public override MemoryStream OpenMemoryStream(string file) + { + using var mdp = ZipFile.OpenRead(Path); + using var openedMdm = mdp.GetNestedZip(PackAlbumName + ".mdm"); + var entry = openedMdm.GetEntry(file); + + if (entry != null) return entry.Open().ToMemoryStream(); + + Logger.Error($"Could not find file in package: {file}"); + throw new FileNotFoundException(); + } +} \ No newline at end of file diff --git a/BmsLoader.cs b/BmsLoader.cs index 1fb07d8..281daa6 100644 --- a/BmsLoader.cs +++ b/BmsLoader.cs @@ -1,6 +1,5 @@ using System.Diagnostics; using CustomAlbums.Data; -using CustomAlbums.Managers; using CustomAlbums.Utilities; using Il2Cpp; using Il2CppAssets.Scripts.GameCore; @@ -26,6 +25,11 @@ internal static class BmsLoader private static Decimal _delay; private static readonly Logger Logger = new(nameof(BmsLoader)); + /// + /// MusicData for the chart being transmuted. + /// + private static readonly List MusicDataList = new() { new MusicData() }; + private static readonly Dictionary StartDelayCache = new(); private static readonly Dictionary<(string scene, string animation), float> AnimationDurationCache = new(); @@ -320,23 +324,23 @@ internal static StageInfo TransmuteData(Bms bms) var stopwatch = Stopwatch.StartNew(); if (NoteData.Count == 0) InitNoteData(); - MusicDataManager.Clear(); + ClearMusicData(); _delay = 0; var noteData = bms.GetNoteData(); Logger.Msg("Got note data"); LoadMusicData(noteData); - MusicDataManager.Sort(); + SortMusicData(); ProcessBossData(bms); ProcessDelay(bms); - MusicDataManager.Sort(); + SortMusicData(); ProcessGeminis(); // Process the delay for each MusicData - foreach (var mData in MusicDataManager.Data) + foreach (var mData in MusicDataList) { mData.tick -= _delay; mData.showTick = Decimal.Round(mData.tick - mData.dt, 2); @@ -347,17 +351,49 @@ internal static StageInfo TransmuteData(Bms bms) // Transmute the MusicData to a new StageInfo object var stageInfo = ScriptableObject.CreateInstance(); stageInfo.musicDatas = new Il2CppSystem.Collections.Generic.List(); - foreach (var musicData in MusicDataManager.Data) + foreach (var musicData in MusicDataList) stageInfo.musicDatas.Add(musicData); stageInfo.delay = _delay; stopwatch.Stop(); - Logger.Msg($"Transmuted BMS in {stopwatch.Elapsed}", false); + Logger.Msg($"Transmuted BMS in {stopwatch.Elapsed}"); - MusicDataManager.Clear(); + ClearMusicData(); return stageInfo; } + private static void AddMusicData(MusicData data) + { + if (MusicDataList.Count >= short.MaxValue - 1) + { + Logger.Warning($"BMS is too large to load. Max MusicData allowed is {short.MaxValue}!"); + return; + } + + MusicDataList.Add(data); + } + + private static void SortMusicData() + { + MusicDataList.Sort(1, MusicDataList.Count - 1, + Comparer.Create((l, r) => !(r.tick - r.dt - (l.tick - l.dt) > 0) ? 1 : -1)); + + for (var i = 1; i < MusicDataList.Count; i++) + { + var musicData = MusicDataList[i]; + musicData.tick = Decimal.Round(musicData.tick, 3); + musicData.objId = (short)i; + } + + Logger.Msg("Sorted MusicData"); + } + + private static void ClearMusicData() + { + MusicDataList.Clear(); + MusicDataList.Add(new MusicData()); + } + private static void InitNoteData() { foreach (var nData in SingletonScriptableObject.instance.noteDatas) @@ -389,17 +425,19 @@ private static void LoadMusicData(List noteData) if (configData.time < 0) continue; // Create a new note for each configData - var newNote = Interop.CreateTypeValue(); - newNote.objId = noteId++; - newNote.tick = Decimal.Round(configData.time, 3); - newNote.configData = configData; - newNote.isLongPressEnd = false; - newNote.isLongPressing = false; + var newNote = new MusicData + { + objId = noteId++, + tick = Decimal.Round(configData.time, 3), + configData = configData, + isLongPressEnd = false, + isLongPressing = false + }; if (NoteData.TryGetValue(newNote.configData.note_uid, out var newNoteData)) newNote.noteData = newNoteData; - MusicDataManager.Add(newNote); + AddMusicData(newNote); // Create ticks for hold notes. If it isn't a hold note, there is no need to continue. if (!newNote.isLongPressStart) continue; @@ -412,25 +450,24 @@ private static void LoadMusicData(List noteData) for (var i = 1; i <= newNote.longPressCount; i++) { - var holdTick = Interop.CreateTypeValue(); - holdTick.objId = noteId++; - holdTick.tick = i == newNote.longPressCount - ? newNote.tick + newNote.configData.length - : newNote.tick + (Decimal)0.1f * i; - holdTick.configData = newNote.configData; - - // ACTUALLY REQUIRED TO WORK - var dataCopy = holdTick.configData; - dataCopy.length = 0; - holdTick.configData = dataCopy; - - holdTick.isLongPressing = i != newNote.longPressCount; - holdTick.isLongPressEnd = i == newNote.longPressCount; - holdTick.noteData = newNote.noteData; - holdTick.longPressPTick = newNote.configData.time; - holdTick.endIndex = endIndex; - - MusicDataManager.Add(holdTick); + var holdConfig = newNote.configData; + holdConfig.length = 0; + + var holdTick = new MusicData + { + objId = noteId++, + tick = i == newNote.longPressCount + ? newNote.tick + newNote.configData.length + : newNote.tick + (Decimal)0.1f * i, + configData = holdConfig, + isLongPressing = i != newNote.longPressCount, + isLongPressEnd = i == newNote.longPressCount, + noteData = newNote.noteData, + longPressPTick = newNote.configData.time, + endIndex = endIndex + }; + + AddMusicData(holdTick); } } @@ -440,7 +477,7 @@ private static void LoadMusicData(List noteData) private static void ProcessBossData(Bms bms) { var scene = bms.Info.Genre; - var bossData = MusicDataManager.Data.Where(mData => mData.isBossNote).ToList(); + var bossData = MusicDataList.Where(mData => mData.isBossNote).ToList(); // If the boss is not used for some reason, no need to process animations. if (bossData.Count == 0) return; @@ -449,7 +486,7 @@ private static void ProcessBossData(Bms bms) var finalData = bossData[^1]; if (AnimStatesRight[finalData.noteData.boss_action] != BossState.OffScreen) { - var finalNote = MusicDataManager.Data[^1]; + var finalNote = MusicDataList[^1]; var tick = finalNote.tick; if (finalNote.isBossNote) @@ -463,17 +500,21 @@ private static void ProcessBossData(Bms bms) var exitNoteData = BossData[scene]["out"]; - var exitConfig = Interop.CreateTypeValue(); - exitConfig.note_uid = exitNoteData.uid; - exitConfig.time = tick; + var exitConfig = new MusicConfigData + { + note_uid = exitNoteData.uid, + time = tick + }; - var exitMusicData = Interop.CreateTypeValue(); - exitMusicData.objId = 0; - exitMusicData.tick = exitConfig.time; - exitMusicData.configData = exitConfig; - exitMusicData.noteData = exitNoteData; + var exitMusicData = new MusicData + { + objId = 0, + tick = exitConfig.time, + configData = exitConfig, + noteData = exitNoteData + }; - MusicDataManager.Add(exitMusicData); + AddMusicData(exitMusicData); bossData.Add(exitMusicData); Logger.Msg("Added missing boss exit at " + exitConfig.time); } @@ -557,23 +598,27 @@ private static void ProcessBossData(Bms bms) if (cachedGearConfig == null) continue; var phaseGearConfig = cachedGearConfig; - var fixedConfigData = Interop.CreateTypeValue(); - fixedConfigData.blood = data.configData.blood; - fixedConfigData.id = data.configData.id; - fixedConfigData.length = data.configData.length; - fixedConfigData.note_uid = phaseGearConfig.uid; - fixedConfigData.pathway = data.configData.pathway; - fixedConfigData.time = data.configData.time; - - var fixedGear = Interop.CreateTypeValue(); - fixedGear.objId = data.objId; - fixedGear.tick = data.tick; - fixedGear.configData = fixedConfigData; - fixedGear.isLongPressEnd = data.isLongPressEnd; - fixedGear.isLongPressing = data.isLongPressing; - fixedGear.noteData = phaseGearConfig; - - MusicDataManager.Set(fixedGear.objId, fixedGear); + var fixedConfigData = new MusicConfigData + { + blood = data.configData.blood, + id = data.configData.id, + length = data.configData.length, + note_uid = phaseGearConfig.uid, + pathway = data.configData.pathway, + time = data.configData.time + }; + + var fixedGear = new MusicData + { + objId = data.objId, + tick = data.tick, + configData = fixedConfigData, + isLongPressEnd = data.isLongPressEnd, + isLongPressing = data.isLongPressing, + noteData = phaseGearConfig + }; + + MusicDataList[fixedGear.objId] = fixedGear; bossData[i] = fixedGear; Logger.Msg($"Fixed gear at tick {data.tick}."); } @@ -599,14 +644,18 @@ private static void ProcessBossData(Bms bms) var duration = (Decimal)GetAnimationDuration(scene, transfer); - var mConfig = Interop.CreateTypeValue(); - mConfig.note_uid = transferNoteData.uid; - mConfig.time = Decimal.Round(alignData.tick - alignDelay - duration * (int)alignment, 3); + var mConfig = new MusicConfigData + { + note_uid = transferNoteData.uid, + time = Decimal.Round(alignData.tick - alignDelay - duration * (int)alignment, 3) + }; - var mData = Interop.CreateTypeValue(); - mData.tick = mConfig.time; - mData.configData = mConfig; - mData.noteData = transferNoteData; + var mData = new MusicData + { + tick = mConfig.time, + configData = mConfig, + noteData = transferNoteData + }; var tolerance = (Decimal)0.300f; var fits = alignment switch @@ -621,7 +670,7 @@ private static void ProcessBossData(Bms bms) continue; } - MusicDataManager.Add(mData); + AddMusicData(mData); bossData.Insert(i, mData); i--; } @@ -641,9 +690,9 @@ private static void ProcessDelay(Bms bms) var sceneInfo = Singleton.instance.sceneInfo; var delayCache = new Dictionary(); - for (var i = 0; i < MusicDataManager.Data.Count; i++) + for (var i = 0; i < MusicDataList.Count; i++) { - var mData = MusicDataManager.Data[i]; + var mData = MusicDataList[i]; if (!string.IsNullOrEmpty(mData.noteData.ibms_id)) { var type = mData.noteData.GetNoteType(); @@ -671,11 +720,7 @@ private static void ProcessDelay(Bms bms) } } - if (delayCache.TryGetValue(prefabName, out var delay)) - { - mData.dt = delay; - MusicDataManager.Set(i, mData); - } + if (delayCache.TryGetValue(prefabName, out var delay)) mData.dt = delay; } } @@ -692,11 +737,10 @@ private static void ProcessGeminis() { var geminiCache = new Dictionary>(); - for (var i = 1; i < MusicDataManager.Data.Count; i++) + for (var i = 1; i < MusicDataList.Count; i++) { - var mData = MusicDataManager.Data[i]; + var mData = MusicDataList[i]; mData.doubleIdx = -1; - MusicDataManager.Set(i, mData); if (mData.noteData.GetNoteType() != NoteType.Monster && mData.noteData.GetNoteType() != NoteType.Hide) continue; @@ -705,7 +749,7 @@ private static void ProcessGeminis() { var isNoteGemini = Bms.BmsIds[mData.noteData.ibms_id] == Bms.BmsId.Gemini; var isTargetGemini = false; - var target = Interop.CreateTypeValue(); + var target = new MusicData(); foreach (var gemini in geminiList.Where(gemini => mData.isAir != gemini.isAir)) { @@ -722,9 +766,6 @@ private static void ProcessGeminis() mData.doubleIdx = target.objId; target.isDouble = isNoteGemini && isTargetGemini; target.doubleIdx = mData.objId; - - MusicDataManager.Set(mData.objId, mData); - MusicDataManager.Set(target.objId, target); } } else diff --git a/Data/Album.cs b/Data/Album.cs index c135c15..c43f53a 100644 --- a/Data/Album.cs +++ b/Data/Album.cs @@ -1,9 +1,7 @@ using System.Collections; -using System.IO.Compression; using System.Reflection; using CustomAlbums.Managers; using CustomAlbums.Patches; -using CustomAlbums.Utilities; using MelonLoader; using MelonLoader.Utils; using UnityEngine; @@ -12,115 +10,22 @@ namespace CustomAlbums.Data; -public class Album +public abstract class Album { - private static readonly Logger Logger = new(nameof(Album)); + protected static readonly Logger Logger = new(nameof(Album)); private static Sprite _defaultCover; private Sprite _cover; private bool _isCoverLoading; - public Album(string directory, ZipArchiveEntry mdm, int index, string packName = null) - { - if (!string.IsNullOrEmpty(packName)) PackName = packName; - - using var mdmStream = mdm.Open(); - using var openedZip = new ZipArchive(mdmStream); - - var info = openedZip.GetEntry("info.json"); - if (info == null) - { - Logger.Error($"Could not find info.json in package: {mdm.Name}"); - throw new FileNotFoundException(); - } - - using var stream = info.Open(); - Info = Json.Deserialize(stream); - IsPackaged = true; - - // CurrentPack will always be null if album is not in a pack - IsPack = AlbumManager.CurrentPack != null; - - HasPng = openedZip.GetEntry("cover.png") != null; - - Index = index; - Path = directory; - PackAlbumName = System.IO.Path.GetFileNameWithoutExtension(mdm.Name); - GetSheets(); - } - - public Album(string path, int index, string packName = null) - { - // If packName is not null then it's a file path, not a folder chart - if (Directory.Exists(path) && packName == null) - { - // Load album from directory - if (!File.Exists($"{path}\\info.json")) - { - Logger.Error($"Could not find info.json at: {path}\\info.json"); - throw new FileNotFoundException(); - } - - using var fileStream = File.OpenRead($"{path}\\info.json"); - Info = Json.Deserialize(fileStream); - HasPng = File.Exists(System.IO.Path.Combine(path, "cover.png")); - } - else if (File.Exists(path)) - { - // Load album from package - PackName = packName; - using var zip = ZipFile.OpenRead(path); - var info = zip.GetEntry("info.json"); - if (info == null) - { - Logger.Error($"Could not find info.json in package: {path}"); - throw new FileNotFoundException(); - } - - using var stream = info.Open(); - Info = Json.Deserialize(stream); - IsPackaged = true; - - // CurrentPack will always be null if album is not in a pack - IsPack = AlbumManager.CurrentPack != null; - - HasPng = zip.GetEntry("cover.png") != null; - } - else - { - Logger.Error($"Could not find album at: {path}"); - throw new FileNotFoundException(); - } - - Index = index; - Path = path; - - GetSheets(); - } - - public string PackAlbumName { get; } = string.Empty; public int Index { get; internal set; } - public string Path { get; } - public bool IsPackaged { get; } - public bool IsPack { get; } - public bool HasPng { get; } - - public bool HasCover - { - get - { - if (HasPng) - { - HotReloadManager.PnlStageInstance?.RefreshStageUI(); - return true; - } + public string Path { get; protected set; } + public bool HasPng { get; protected set; } + public AlbumInfo Info { get; protected set; } - return false; - } - } + public abstract string AlbumName { get; } - public string PackName { get; } - public AlbumInfo Info { get; } + public Dictionary Sheets { get; } = new(); public static Sprite DefaultCover { @@ -165,41 +70,41 @@ public Sprite Cover } } + public bool HasCover + { + get + { + if (HasPng) + { + HotReloadManager.PnlStageInstance?.RefreshStageUI(); + return true; + } + + return false; + } + } + public AudioClip Music => this.GetAudio(); public AudioClip Demo => this.GetAudio("demo"); - public Dictionary Sheets { get; } = new(); + public string Uid => $"{AlbumManager.Uid}-{Index}"; - public string AlbumName => - IsPackaged - ? $"album_{(string.IsNullOrEmpty(PackAlbumName) ? System.IO.Path.GetFileNameWithoutExtension(Path) : string.Empty)}{(PackName != null ? $"{PackAlbumName}_{PackName}" : string.Empty)}" - : $"album_{System.IO.Path.GetFileName(Path)}_folder"; + protected void GetSheets() + { + foreach (var difficulty in Info.Difficulties.Keys.Where(difficulty => HasFile($"map{difficulty}.bms"))) + Sheets.Add(difficulty, new Sheet(this, difficulty)); + } - public string Uid => $"{AlbumManager.Uid}-{Index}"; + public bool HasDifficulty(int difficulty) + { + return Sheets.ContainsKey(difficulty); + } private IEnumerator LoadCoverAsync() { - string url; var cacheDir = System.IO.Path.Combine(MelonEnvironment.UserDataDirectory, "CustomAlbums", "Cache"); if (!Directory.Exists(cacheDir)) Directory.CreateDirectory(cacheDir); - if (IsPack || IsPackaged) - { - var cacheFile = System.IO.Path.Combine(cacheDir, $"{Uid}_cover.png"); - if (File.Exists(cacheFile)) File.Delete(cacheFile); - - using var stream = OpenNullableStream("cover.png"); - if (stream != null) - { - using var fs = File.OpenWrite(cacheFile); - stream.CopyTo(fs); - } - - url = "file:///" + cacheFile.Replace('\\', '/'); - } - else - { - url = "file:///" + System.IO.Path.Combine(Path, "cover.png").Replace('\\', '/'); - } + var url = GetCoverUrl(cacheDir); var request = UnityWebRequestTexture.GetTexture(url); yield return request.SendWebRequest(); @@ -218,147 +123,23 @@ private IEnumerator LoadCoverAsync() _isCoverLoading = false; } - public bool HasFile(string name) + protected virtual string GetCoverUrl(string cacheDir) { - if (IsPack && !string.IsNullOrEmpty(PackAlbumName)) - { - if (!File.Exists(Path)) return false; - try - { - using var mdp = ZipFile.OpenRead(Path); - using var openedMdm = mdp.GetNestedZip(PackAlbumName + ".mdm"); - return openedMdm.GetEntry(name) != null; - } - catch (IOException) - { - return false; - } - } + var cacheFile = System.IO.Path.Combine(cacheDir, $"{Uid}_cover.png"); + if (File.Exists(cacheFile)) File.Delete(cacheFile); - if (IsPackaged) + using var stream = OpenNullableStream("cover.png"); + if (stream != null) { - if (!File.Exists(Path)) return false; - try - { - using var zip = ZipFile.OpenRead(Path); - return zip.GetEntry(name) != null; - } - catch (IOException) - { - // This is expected in the case of deleting an album - return false; - } + using var fs = File.OpenWrite(cacheFile); + stream.CopyTo(fs); } - var path = $"{Path}\\{name}"; - return File.Exists(path); + return "file:///" + cacheFile.Replace('\\', '/'); } - public Stream OpenFileStreamIfPossible(string file) - { - if (IsPack && !string.IsNullOrEmpty(PackAlbumName)) - { - using var mdp = ZipFile.OpenRead(Path); - using var openedMdm = mdp.GetNestedZip(PackAlbumName + ".mdm"); - var entry = openedMdm.GetEntry(file); - - if (entry != null) return entry.Open().ToMemoryStream(); - - Logger.Error($"Could not find file in package: {file}"); - throw new FileNotFoundException(); - } - - if (IsPackaged) - { - using var zip = ZipFile.OpenRead(Path); - var entry = zip.GetEntry(file); - - if (entry != null) return entry.Open().ToMemoryStream(); - - Logger.Error($"Could not find file in package: {file}"); - throw new FileNotFoundException(); - } - - var path = $"{Path}\\{file}"; - if (File.Exists(path)) - return File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - - Logger.Error($"Could not find file: {path}"); - throw new FileNotFoundException(); - } - - public Stream OpenNullableStream(string file) - { - if (IsPack && !string.IsNullOrEmpty(PackAlbumName)) - { - using var mdp = ZipFile.OpenRead(Path); - using var openedMdm = mdp.GetNestedZip(PackAlbumName + ".mdm"); - var entry = openedMdm.GetEntry(file); - - if (entry != null) return entry.Open().ToMemoryStream(); - - return null; - } - - if (IsPackaged) - { - using var zip = ZipFile.OpenRead(Path); - var entry = zip.GetEntry(file); - - if (entry != null) return entry.Open().ToMemoryStream(); - - return null; - } - - var path = $"{Path}\\{file}"; - if (File.Exists(path)) - return File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - - return null; - } - - public MemoryStream OpenMemoryStream(string file) - { - if (IsPack && !string.IsNullOrEmpty(PackAlbumName)) - { - using var mdp = ZipFile.OpenRead(Path); - using var openedMdm = mdp.GetNestedZip(PackAlbumName + ".mdm"); - var entry = openedMdm.GetEntry(file); - - if (entry != null) return entry.Open().ToMemoryStream(); - - Logger.Error($"Could not find file in package: {file}"); - throw new FileNotFoundException(); - } - - if (IsPackaged) - { - using var zip = ZipFile.OpenRead(Path); - var entry = zip.GetEntry(file); - - if (entry != null) return entry.Open().ToMemoryStream(); - - Logger.Error($"Could not find file in package: {file}"); - throw new FileNotFoundException(); - } - - var path = $"{Path}\\{file}"; - if (File.Exists(path)) - return File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite).ToMemoryStream(); - - Logger.Error($"Could not find file: {path}"); - throw new FileNotFoundException(); - } - - private void GetSheets() - { - // Adds to the Sheets dictionary - foreach (var difficulty in Info.Difficulties.Keys.Where(difficulty => HasFile($"map{difficulty}.bms"))) - Sheets.Add(difficulty, new Sheet(this, difficulty)); - } - - public bool HasDifficulty(int difficulty) - { - return Sheets.ContainsKey(difficulty); - } + public abstract bool HasFile(string name); + public abstract Stream OpenFileStreamIfPossible(string file); + public abstract Stream OpenNullableStream(string file); + public abstract MemoryStream OpenMemoryStream(string file); } \ No newline at end of file diff --git a/Main.cs b/Main.cs index ea16836..32ac58e 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.1"; + public const string MelonVersion = "4.2.2"; private static readonly Logger Logger = new("CustomAlbums"); public override void OnInitializeMelon() diff --git a/Managers/AlbumManager.cs b/Managers/AlbumManager.cs index 03988f4..21d49aa 100644 --- a/Managers/AlbumManager.cs +++ b/Managers/AlbumManager.cs @@ -1,5 +1,6 @@ using System.Diagnostics; using System.IO.Compression; +using CustomAlbums.Albums; using CustomAlbums.Data; using CustomAlbums.ModExtensions; using CustomAlbums.Utilities; @@ -41,22 +42,18 @@ public static class AlbumManager public static Pack LoadPack(string directory) { - // Get the files from the directory try { var zipFiles = ZipFile.OpenRead(directory); - // Filter for .mdm files and find the pack.json file var mdms = zipFiles.Entries.Where(file => file.Name.EndsWith(".mdm")); var json = zipFiles.Entries.FirstOrDefault(file => file.Name.EndsWith(".json")); - // Initialize pack and variables var pack = PackManager.CreatePack(json, directory); CurrentPack = pack.Title; pack.StartIndex = MaxCount; - // Count successfully loaded .mdm files pack.Length = mdms.Count(mdm => { var album = LoadOne(directory, mdm, mdm.FullName); @@ -69,7 +66,6 @@ public static Pack LoadPack(string directory) return false; }); - // Set the current pack to null and add the pack to the pack list CurrentPack = null; PackManager.AddPack(pack); @@ -89,35 +85,10 @@ public static Album LoadOne(string directory, ZipArchiveEntry mdm, string fullFi var fileName = Path.GetFileNameWithoutExtension(fullFileName); try { - var album = new Album(directory, mdm, 0, CurrentPack); - if (album.Info is null) return null; - - var albumName = album.AlbumName; - if (LoadedAlbums.ContainsKey(albumName)) return null; - - if (UidHistory.TryGetValue(albumName, out var oldIndex)) - { - album.Index = oldIndex; - } - else - { - album.Index = MaxCount; - MaxCount++; - UidHistory[albumName] = album.Index; - } - - Logger.Msg("Adding " + albumName + " as a pack!"); - - LoadedAlbums.Add(albumName, album); - - if (album.HasPng) - ResourcesManager.instance.LoadFromName($"{albumName}_cover").hideFlags |= - HideFlags.DontUnloadUnusedAsset; - - - Logger.Msg($"Loaded {albumName}: {album.Info.Name}"); - OnAlbumLoaded?.Invoke(typeof(AlbumManager), new AlbumEventArgs(album)); - return album; + var album = new PackAlbum(directory, mdm, 0, CurrentPack); + var registered = RegisterAlbum(album); + if (registered != null) Logger.Msg("Adding " + registered.AlbumName + " as a pack!"); + return registered; } catch (Exception ex) { @@ -134,32 +105,13 @@ public static Album LoadOne(string path) var fileName = isDirectory ? Path.GetFileName(path) : Path.GetFileNameWithoutExtension(path); try { - var album = new Album(path, 0, CurrentPack); - if (album.Info is null) return null; - - var albumName = album.AlbumName; - if (LoadedAlbums.ContainsKey(albumName)) return null; - - if (UidHistory.TryGetValue(albumName, out var oldIndex)) - { - album.Index = oldIndex; - } + Album album; + if (isDirectory) + album = new FolderAlbum(path, 0); else - { - album.Index = MaxCount; - MaxCount++; - UidHistory[albumName] = album.Index; - } + album = new ArchiveAlbum(path, 0); - LoadedAlbums.Add(albumName, album); - - if (album.HasPng) - ResourcesManager.instance.LoadFromName($"{albumName}_cover").hideFlags |= - HideFlags.DontUnloadUnusedAsset; - - Logger.Msg($"Loaded {albumName}: {album.Info.Name}"); - OnAlbumLoaded?.Invoke(typeof(AlbumManager), new AlbumEventArgs(album)); - return album; + return RegisterAlbum(album); } catch (Exception ex) { @@ -170,6 +122,35 @@ public static Album LoadOne(string path) return null; } + private static Album RegisterAlbum(Album album) + { + if (album.Info is null) return null; + + var albumName = album.AlbumName; + if (LoadedAlbums.ContainsKey(albumName)) return null; + + if (UidHistory.TryGetValue(albumName, out var oldIndex)) + { + album.Index = oldIndex; + } + else + { + album.Index = MaxCount; + MaxCount++; + UidHistory[albumName] = album.Index; + } + + LoadedAlbums.Add(albumName, album); + + if (album.HasPng) + ResourcesManager.instance.LoadFromName($"{albumName}_cover").hideFlags |= + HideFlags.DontUnloadUnusedAsset; + + Logger.Msg($"Loaded {albumName}: {album.Info.Name}"); + OnAlbumLoaded?.Invoke(typeof(AlbumManager), new AlbumEventArgs(album)); + return album; + } + public static void LoadAlbums() { LoadedAlbums.Clear(); @@ -199,7 +180,8 @@ public static IEnumerable GetAllUid() public static Album GetByUid(string uid) { - return LoadedAlbums.FirstOrDefault(album => album.Value.Index == uid[4..].ParseAsInt()).Value; + if (uid is null || !uid.StartsWith($"{Uid}-") || !uid[4..].TryParseAsInt(out var index)) return null; + return LoadedAlbums.FirstOrDefault(album => album.Value.Index == index).Value; } public static string GetAlbumNameFromUid(string uid) diff --git a/Managers/HotReloadManager.cs b/Managers/HotReloadManager.cs index a69a401..e8c640e 100644 --- a/Managers/HotReloadManager.cs +++ b/Managers/HotReloadManager.cs @@ -84,7 +84,7 @@ private static int ProcessAdditions() { var addedCount = 0; if (!AlbumsToAdd.TryDequeue(out var path)) return addedCount; - + try { var newAlbums = new List(); diff --git a/Managers/MusicDataManager.cs b/Managers/MusicDataManager.cs deleted file mode 100644 index edc6bdd..0000000 --- a/Managers/MusicDataManager.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System.Collections.ObjectModel; -using CustomAlbums.Utilities; -using Il2CppGameLogic; -using Decimal = Il2CppSystem.Decimal; - -namespace CustomAlbums.Managers; - -internal static class MusicDataManager -{ - private static readonly List MusicDataList = new(); - private static readonly Logger Logger = new(nameof(MusicDataManager)); - - static MusicDataManager() - { - // Add an empty music data to the list as a placeholder - MusicDataList.Add(Interop.CreateTypeValue()); - } - - public static ReadOnlyCollection Data => MusicDataList.AsReadOnly(); - - public static void Add(MusicData data) - { - if (MusicDataList.Count >= short.MaxValue - 1) - { - Logger.Warning($"BMS is too large to load. Max MusicData allowed is {short.MaxValue}!"); - return; - } - - MusicDataList.Add(data); - } - - public static void Sort() - { - // Remove placeholder music data - MusicDataList.RemoveAt(0); - - // Sort the list - MusicDataList.Sort((l, r) => !(r.tick - r.dt - (l.tick - l.dt) > 0) ? 1 : -1); - - // Add the placeholder music data back - MusicDataList.Insert(0, Interop.CreateTypeValue()); - - // Reapply object IDs and round tick to nearest 3 decimal places - for (var i = 1; i < MusicDataList.Count; i++) - { - var musicData = MusicDataList[i]; - musicData.tick = Decimal.Round(musicData.tick, 3); - musicData.objId = (short)i; - - MusicDataList[i] = musicData; - } - - Logger.Msg("Sorted MusicData"); - } - - public static void Set(int index, MusicData data) - { - MusicDataList[index] = data; - } - - public static void Clear() - { - // Clear the list - MusicDataList.Clear(); - - // Add an empty music data to the list as a placeholder - MusicDataList.Add(Interop.CreateTypeValue()); - } -} \ No newline at end of file diff --git a/Managers/SaveManager.cs b/Managers/SaveManager.cs index c6c3f61..fd879dd 100644 --- a/Managers/SaveManager.cs +++ b/Managers/SaveManager.cs @@ -1,6 +1,7 @@ -using System.IO.Compression; +using System.IO.Compression; using System.Text; using System.Text.Json; +using CustomAlbums.Albums; using CustomAlbums.Data; using CustomAlbums.Utilities; @@ -65,7 +66,7 @@ internal static void FixSaveFile() kv.Value.ContainsKey(3) && kv.Value.TryGetValue(2, out var chartSave) && chartSave.Evaluate >= 4) .Select(kv => kv.Key); var folderCharts = AlbumManager.LoadedAlbums - .Where(kv => kv.Value.HasDifficulty(2) && kv.Value.HasDifficulty(3) && !kv.Value.IsPackaged) + .Where(kv => kv.Value.HasDifficulty(2) && kv.Value.HasDifficulty(3) && kv.Value is FolderAlbum) .Select(kv => kv.Key); var concat = unlockedHighest.Concat(folderCharts); SaveData.UnlockedMasters.UnionWith(concat); @@ -183,7 +184,7 @@ internal static void SaveScore(string uid, int musicDifficulty, int score, float if (!ModSettings.SavingEnabled) return; var album = AlbumManager.GetByUid(uid); - if (!album?.IsPackaged ?? true) return; + if (album is null || album is FolderAlbum) return; var newEvaluate = evaluate switch { diff --git a/Patches/DifficultyGradeIconPatch.cs b/Patches/DifficultyGradeIconPatch.cs index c1b38f9..950eef4 100644 --- a/Patches/DifficultyGradeIconPatch.cs +++ b/Patches/DifficultyGradeIconPatch.cs @@ -17,6 +17,11 @@ private static int GetEvaluate(Dictionary highest, int diff) return highest.GetValueOrDefault(diff)?.Evaluate ?? -1; } + private static int GetVanillaEvaluate(string uid, int diff) + { + return DataHelper.highest.GetIDataByUid(uid, diff)?.ToChartSave().Evaluate ?? -1; + } + /// /// Enables the S logos on the difficulties for custom charts. /// @@ -28,12 +33,12 @@ private static void Postfix(MusicInfo musicInfo, PnlStage __instance) if (string.IsNullOrEmpty(uid)) return; + var isCustom = uid.StartsWith($"{AlbumManager.Uid}-"); + var customHighest = isCustom ? SaveManager.SaveData.GetChartSaveDataFromUid(uid)?.Highest : null; + // For custom charts, we need to set the S logos for each difficulty - if (uid.StartsWith($"{AlbumManager.Uid}-")) + if (isCustom) { - // Gets the highest data from save data - var customHighest = SaveManager.SaveData.GetChartSaveDataFromUid(uid)?.Highest; - if (customHighest == null) return; // Get the Evaluate value from each, set diff3 to diff4 if hidden is invoked @@ -54,8 +59,8 @@ private static void Postfix(MusicInfo musicInfo, PnlStage __instance) if (!specialSongInstance.m_HideBmsInfos.TryGetValue(uid, out var info)) return; // Get the difficulty evaluates - var hiddenEval = DataHelper.highest.GetIDataByUid(uid, 4).ToChartSave().Evaluate; - var masterEval = DataHelper.highest.GetIDataByUid(uid, 3).ToChartSave().Evaluate; + var hiddenEval = isCustom ? GetEvaluate(customHighest, 4) : GetVanillaEvaluate(uid, 4); + var masterEval = isCustom ? GetEvaluate(customHighest, 3) : GetVanillaEvaluate(uid, 3); // The game handles case 3 already, don't need to reinvent the wheel here switch (info.triggerDiff) diff --git a/Patches/SavePatch.cs b/Patches/SavePatch.cs index 1d9c714..6f072fa 100644 --- a/Patches/SavePatch.cs +++ b/Patches/SavePatch.cs @@ -1,5 +1,6 @@ -using System.Runtime.CompilerServices; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using CustomAlbums.Albums; using CustomAlbums.Data; using CustomAlbums.Managers; using CustomAlbums.Utilities; @@ -347,7 +348,7 @@ private static bool Prefix(MusicInfo musicInfo, ref bool __result) var cond = !vanillaParse || ability >= difficulty; __result = cond || DataHelper.unlockMasters.Contains(uid) || SaveData.UnlockedMasters.Contains(AlbumManager.GetAlbumNameFromUid(uid)) || - (!AlbumManager.GetByUid(musicInfo.uid)?.IsPackaged ?? false); + AlbumManager.GetByUid(musicInfo.uid) is FolderAlbum; return false; } @@ -360,7 +361,7 @@ private static bool Prefix(MusicInfo musicInfo, ref bool __result) __result = abilityConditionOrGimmick || SaveData.UnlockedMasters.Contains(AlbumManager.GetAlbumNameFromUid(uid)) || - !AlbumManager.GetByUid(musicInfo.uid).IsPackaged; + AlbumManager.GetByUid(musicInfo.uid) is FolderAlbum; return false; } } diff --git a/Patches/SceneEggPatch.cs b/Patches/SceneEggPatch.cs index b03dcb7..2a9add1 100644 --- a/Patches/SceneEggPatch.cs +++ b/Patches/SceneEggPatch.cs @@ -65,7 +65,8 @@ private static bool Prefix(string sceneFestivalName, ref string __result) // Ignore the actual SceneEggs if (IgnoreSceneEggs(out _, SceneEggs.Arknights, SceneEggs.Cytus, SceneEggs.None, - SceneEggs.Queen, SceneEggs.Touhou, SceneEggs.Wacca, SceneEggs.Miku, SceneEggs.BadApple, SceneEggs.RinLen, SceneEggs.BlueArchive)) return true; + SceneEggs.Queen, SceneEggs.Touhou, SceneEggs.Wacca, SceneEggs.Miku, SceneEggs.BadApple, + SceneEggs.RinLen, SceneEggs.BlueArchive)) return true; if (sceneFestivalName == "scene_05") __result = "scene_05_christmas"; return false; @@ -83,7 +84,8 @@ private static bool Prefix(string bossFestivalName, ref string __result) // If the boss is not 0501_boss then there is no Christmas if (bossFestivalName != "0501_boss") return true; if (IgnoreSceneEggs(out _, SceneEggs.Arknights, SceneEggs.Cytus, SceneEggs.None, - SceneEggs.Queen, SceneEggs.Touhou, SceneEggs.Wacca, SceneEggs.Miku, SceneEggs.BadApple, SceneEggs.RinLen, SceneEggs.BlueArchive)) return true; + SceneEggs.Queen, SceneEggs.Touhou, SceneEggs.Wacca, SceneEggs.Miku, SceneEggs.BadApple, + SceneEggs.RinLen, SceneEggs.BlueArchive)) return true; __result = "0501_boss_christmas"; return false; diff --git a/README.md b/README.md index ade8dcf..fbc0084 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,59 @@ -[![](https://dcbadge.vercel.app/api/server/mdmc)](https://discord.gg/mdmc) - # CustomAlbums -CustomAlbums is a MelonLoader mod for peropero's Muse Dash. It allows the loading of custom songs in MDM format into Muse Dash. -This mod was written from the ground-up by [MDMC](https://github.com/MDMods), so joining the Discord server is the best way to reach us for help and information. -## Usage -- Install MelonLoader into Muse Dash based on the dependency listed below -- Download the [latest release](https://github.com/MDMods/CustomAlbums/releases/latest) of CustomAlbums and place it in your Mods folder -- Place any custom chart (.mdm) files into the generated `Custom_Albums` folder and enjoy -## Dependencies -- [MelonLoader v0.6.1](https://github.com/LavaGang/MelonLoader/releases/tag/v0.6.1) +# CustomAlbums + +CustomAlbums is a MelonLoader mod for [Muse Dash](https://store.steampowered.com/app/774171/Muse_Dash/) that allows you to load and play custom songs, charts, and song packs (`.mdm` and `.mdp` formats). + +Maintained by the [Muse Dash Modding Community (MDMC)](https://github.com/MDMods). Join the [MDMC Discord Server](https://discord.gg/mdmc) for support, chart creation tools, and community charts. + +## Features + +- **Custom Songs & Packs**: Supports `.mdm` chart files, `.mdp` song packs, and uncompressed chart folders. +- **In-Game Song Menu**: Adds a "Custom Albums" category to the song selection screen. +- **Hot Reloading**: Automatically detects added, updated, or deleted chart files while the game is running without needing a restart. +- **Custom Local Saves**: Tracks scores, accuracy, and clear status in a separate local save file (`CustomAlbums.json`), keeping vanilla cloud saves and official leaderboards untouched. + +## Repository Structure + +- `Albums/` - Data structures for archive, folder, and pack albums. +- `Data/` - BMS note definitions, chart metadata, and save models. +- `Managers/` - Core logic for album loading, audio, hot reload, song packs, and save files. +- `Patches/` - Harmony hooks into game systems (assets, UI, save data, web APIs). +- `Utilities/` - Logging, file I/O, and asset loading helpers. +- `BmsLoader.cs` - BMS chart parser and timing engine. +- `Main.cs` - Mod entry point and MelonLoader lifecycle hooks. + +## Dependencies & Requirements + - [Muse Dash on Steam](https://store.steampowered.com/app/774171/Muse_Dash/) -- [Muse Plus DLC on Steam](https://store.steampowered.com/app/2593750/Muse_Dash__Muse_Plus/) (or Just as Planned) -## Building -- Install MelonLoader into Muse Dash and run it once -- Run SetPath.cmd as administrator and follow the instructions -- Build tested with Visual Studio 2022, MelonLoader v0.6.1, Muse Dash v5.3.0 -- Will NOT work on MelonLoader v0.6.2. Newer versions might work, but v0.6.1 is recommended +- [Muse Plus DLC on Steam](https://store.steampowered.com/app/2593750/Muse_Dash__Muse_Plus/) (or Just as Planned DLC) +- [MelonLoader v0.7.3](https://github.com/LavaGang/MelonLoader/releases/tag/v0.7.3) + +## Installation & Usage + +1. Install **MelonLoader v0.7.3** into your Muse Dash directory. +2. Download the [latest release](https://github.com/MDMods/CustomAlbums/releases/latest) of `CustomAlbums.dll` and place it in your `Muse Dash/Mods` folder. +3. Launch Muse Dash once to generate the `Custom_Albums` folder in your game directory. +4. Place `.mdm` files, `.mdp` packs, or chart folders into `Custom_Albums/`. + +## Building from Source + +1. Clone the repository: + ```bash + git clone https://github.com/MDMods/CustomAlbums.git + ``` +2. Install MelonLoader v0.7.3 into Muse Dash and run the game once to generate reference assemblies. +3. Run `SetPath.cmd` as Administrator and follow the instructions to set your game path. +4. Build using Visual Studio 2026 or the .NET CLI: + ```bash + dotnet build -c Release + ``` + ## Credits & Contributions + - [ALLMarvelous](https://github.com/ALLMarvelous) - Lead Developer - [Mr. Talk](https://github.com/SB15-MD) - Lead Developer - [gamrguy](https://github.com/gamrguy) - Original Maintainer (Feb 2022 - Jul 2023) - [某10](https://github.com/mo10) - Original Developer (Feb 2021 - Dec 2021) + ## Disclaimer + This repository and its contributors maintain no affiliation with Muse Dash, PeroPeroGames (peropero Ltd.), hasuhasu, or any associated entities. diff --git a/Utilities/ConfigDataExtensions.cs b/Utilities/ConfigDataExtensions.cs index 81cf054..528be7e 100644 --- a/Utilities/ConfigDataExtensions.cs +++ b/Utilities/ConfigDataExtensions.cs @@ -45,14 +45,14 @@ public static bool IsAnySpeed(this NoteConfigData config) /// public static MusicConfigData ToMusicConfigData(this ProcessedNote note) { - var config = Interop.CreateTypeValue(); - config.id = note.Id; - config.time = (Decimal)(float)note.Time; - config.note_uid = note.NoteUid; - config.length = (Decimal)(float)note.Length; - config.pathway = note.Pathway; - config.blood = note.Blood; - - return config; + return new MusicConfigData + { + id = note.Id, + time = (Decimal)(float)note.Time, + note_uid = note.NoteUid, + length = (Decimal)(float)note.Length, + pathway = note.Pathway, + blood = note.Blood + }; } } \ No newline at end of file diff --git a/Utilities/Interop.cs b/Utilities/Interop.cs deleted file mode 100644 index ec9bc70..0000000 --- a/Utilities/Interop.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Il2CppInterop.Runtime; - -namespace CustomAlbums.Utilities; - -public class Interop -{ - /// - /// A workaround to a memory corruption issue of creating Il2CppSystem.TypeValue types using C#'s new operator. - /// This will likely be deleted/become deprecated in the future. - /// - /// An Il2CppSystem.TypeValue type - /// A new object of type T - public static T CreateTypeValue() - { - return (T)Activator.CreateInstance(typeof(T), - IL2CPP.il2cpp_object_new(Il2CppClassPointerStore.NativeClassPtr)); - } -} \ No newline at end of file diff --git a/Utilities/Logger.cs b/Utilities/Logger.cs index 7517168..4980ac5 100644 --- a/Utilities/Logger.cs +++ b/Utilities/Logger.cs @@ -1,5 +1,5 @@ -using System.Drawing; -using MelonLoader; +using MelonLoader; +using MelonLoader.Logging; namespace CustomAlbums.Utilities; @@ -9,7 +9,7 @@ public class Logger public Logger(string className) { - _logger = new MelonLogger.Instance(className, Color.FromArgb(255, 0, 255, 150)); + _logger = new MelonLogger.Instance(className, ColorARGB.FromArgb(255, 0, 255, 150)); } public void Msg(string message, bool verbose = true) @@ -20,21 +20,21 @@ public void Msg(string message, bool verbose = true) public void Success(string message) { - _logger.Msg(ConsoleColor.Green, "Success: " + message); + _logger.Msg(ColorARGB.Green, "Success: " + message); } public void Warning(string message) { - _logger.Msg(ConsoleColor.Yellow, "Warning: " + message); + _logger.Msg(ColorARGB.Yellow, "Warning: " + message); } public void Fail(string message) { - _logger.Msg(ConsoleColor.Red, "FAILED: " + message); + _logger.Msg(ColorARGB.Red, "FAILED: " + message); } public void Error(string message) { - _logger.Msg(ConsoleColor.Red, "ERROR: " + message); + _logger.Msg(ColorARGB.Red, "ERROR: " + message); } } \ No newline at end of file