diff --git a/Data/Album.cs b/Data/Album.cs index 2f5058f..0fae3f4 100644 --- a/Data/Album.cs +++ b/Data/Album.cs @@ -10,9 +10,10 @@ public class Album { private static readonly Logger Logger = new(nameof(Album)); - public Album(string path, int index) + public Album(string path, int index, string packName = null) { - if (Directory.Exists(path)) + // 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")) @@ -27,6 +28,7 @@ public Album(string path, int index) 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) @@ -38,6 +40,9 @@ public Album(string path, int index) 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; } else { @@ -54,6 +59,8 @@ public Album(string path, int index) public int Index { get; } public string Path { get; } public bool IsPackaged { get; } + public bool IsPack { get; } + public string PackName { get; } public AlbumInfo Info { get; } public Sprite Cover => this.GetCover(); public AnimatedCover AnimatedCover => this.GetAnimatedCover(); @@ -61,7 +68,9 @@ public Album(string path, int index) public AudioClip Demo => this.GetAudio("demo"); public Dictionary Sheets { get; } = new(); public string AlbumName => - IsPackaged ? $"album_{System.IO.Path.GetFileNameWithoutExtension(Path)}" : $"album_{System.IO.Path.GetFileName(Path)}_folder"; + IsPackaged ? + $"album_{System.IO.Path.GetFileNameWithoutExtension(Path)}{(PackName != null ? $"_{PackName}" : string.Empty)}" + : $"album_{System.IO.Path.GetFileName(Path)}_folder"; public string Uid => $"{AlbumManager.Uid}-{Index}"; public bool HasFile(string name) diff --git a/Data/Pack.cs b/Data/Pack.cs new file mode 100644 index 0000000..b6957c7 --- /dev/null +++ b/Data/Pack.cs @@ -0,0 +1,14 @@ +using CustomAlbums.Managers; + +namespace CustomAlbums.Data +{ + public class Pack + { + public string Title { get; set; } = AlbumManager.GetCustomAlbumsTitle(); + public string TitleColorHex { get; set; } = "#ffffff"; + public bool LongTextScroll { get; set; } = false; + + internal int StartIndex; + internal int Length; + } +} diff --git a/Data/SceneEggs.cs b/Data/SceneEggs.cs index f0a2af8..e29a451 100644 --- a/Data/SceneEggs.cs +++ b/Data/SceneEggs.cs @@ -11,7 +11,8 @@ public enum SceneEggs Touhou = 3, Arknights = 4, Miku = 5, - RinLen = 6, + RinLen = 6, + BlueArchive = 7, BadApple = 129, Christmas = 999 } diff --git a/Data/Setlist.cs b/Data/Setlist.cs deleted file mode 100644 index f1cfb9f..0000000 --- a/Data/Setlist.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace CustomAlbums.Data -{ - public class Setlist - { - public string Title { get; set; } - } -} diff --git a/Main.cs b/Main.cs index f324a21..281d040 100644 --- a/Main.cs +++ b/Main.cs @@ -12,7 +12,7 @@ public class Main : MelonMod public const string MelonName = "CustomAlbums"; public const string MelonAuthor = "Two Fellas"; - public const string MelonVersion = "4.1.6"; + public const string MelonVersion = "4.1.7"; public override void OnInitializeMelon() { diff --git a/Managers/AlbumManager.cs b/Managers/AlbumManager.cs index e4e3974..03a2522 100644 --- a/Managers/AlbumManager.cs +++ b/Managers/AlbumManager.cs @@ -1,6 +1,8 @@ using CustomAlbums.Data; using CustomAlbums.ModExtensions; using CustomAlbums.Utilities; +using Il2CppAssets.Scripts.PeroTools.Commons; +using Il2CppAssets.Scripts.PeroTools.GeneralLocalization; using Il2CppPeroTools2.Resources; using UnityEngine; using Logger = CustomAlbums.Utilities.Logger; @@ -29,20 +31,55 @@ public static class AlbumManager internal static Events.LoadAlbumEvent OnAlbumLoaded; private static int MaxCount { get; set; } + internal static string CurrentPack { get; set; } = null; public static Dictionary LoadedAlbums { get; } = new(); + + public static void LoadMany(string directory) + { + // Get the files from the directory + var files = Directory.EnumerateFiles(directory); + + // Filter for .mdm files and find the pack.json file + var mdms = files.Where(file => Path.GetExtension(file).EqualsCaseInsensitive(".mdm")).ToList(); + var json = files.FirstOrDefault(file => Path.GetFileName(file).EqualsCaseInsensitive("pack.json")); + + // Initialize pack and variables + var pack = PackManager.CreatePack(json); + CurrentPack = pack.Title; + pack.StartIndex = MaxCount; + + // Count successfully loaded .mdm files + pack.Length = mdms.Count(file => LoadOne(file) != null); + + // Set the current pack to null and add the pack to the pack list + CurrentPack = null; + PackManager.AddPack(pack); + } + public static Album LoadOne(string path) { MaxCount = Math.Max(LoadedAlbums.Count, MaxCount); - var fileName = File.GetAttributes(path).HasFlag(FileAttributes.Directory) ? Path.GetFileName(path) : Path.GetFileNameWithoutExtension(path); + var isDirectory = File.GetAttributes(path).HasFlag(FileAttributes.Directory); + var fileName = isDirectory ? Path.GetFileName(path) : Path.GetFileNameWithoutExtension(path); + if (LoadedAlbums.ContainsKey(fileName)) return null; - + try { - var album = new Album(path, MaxCount); + if (isDirectory && Directory.EnumerateFiles(path) + .Any(file => Path.GetFileName(file) + .EqualsCaseInsensitive("pack.json"))) + { + LoadMany(path); + return null; + } + + var album = new Album(path, MaxCount, CurrentPack); if (album.Info is null) return null; var albumName = album.AlbumName; + LoadedAlbums.Add(albumName, album); if (album.HasFile("cover.png") || album.HasFile("cover.gif")) @@ -94,5 +131,17 @@ public static IEnumerable GetAlbumUidsFromNames(this IEnumerable return albumNames.Where(name => LoadedAlbums.ContainsKey(name)) .Select(name => $"{Uid}-{LoadedAlbums[name].Index}"); } + + /// + /// Gets the current "Custom Albums" title based on language. + /// + /// The current "Custom Albums" title based on language. + public static string GetCustomAlbumsTitle() + { + return Languages.GetValueOrDefault( + SingletonScriptableObject + .instance? + .GetActiveOption("Language") ?? "English"); + } } } \ No newline at end of file diff --git a/Managers/PackManager.cs b/Managers/PackManager.cs new file mode 100644 index 0000000..87b636e --- /dev/null +++ b/Managers/PackManager.cs @@ -0,0 +1,33 @@ +using CustomAlbums.Data; +using CustomAlbums.Utilities; + +namespace CustomAlbums.Managers +{ + internal class PackManager + { + private static readonly List Packs = new(); + internal static Pack GetPackFromUid(string uid) + { + // If the uid is not custom or parsing the index fails + if (!uid.StartsWith($"{AlbumManager.Uid}-") || + !uid[4..].TryParseAsInt(out var uidIndex)) return null; + + // Retrieve the pack that the uid belongs to + var pack = Packs.FirstOrDefault(pack => + uidIndex >= pack.StartIndex && uidIndex < pack.StartIndex + pack.Length); + + // If the pack has no albums in it return null, otherwise return pack (will be null if it doesn't exist) + return pack?.Length == 0 ? null : pack; + } + + internal static Pack CreatePack(string file) + { + return Json.Deserialize(File.OpenRead(file)); + } + + internal static void AddPack(Pack pack) + { + Packs.Add(pack); + } + } +} diff --git a/Managers/SaveManager.cs b/Managers/SaveManager.cs index 8959ab2..350ac8c 100644 --- a/Managers/SaveManager.cs +++ b/Managers/SaveManager.cs @@ -3,6 +3,7 @@ using CustomAlbums.Data; using CustomAlbums.Utilities; using System.IO.Compression; +using CustomAlbums.Patches; namespace CustomAlbums.Managers { @@ -216,9 +217,19 @@ internal static void SaveScore(string uid, int musicDifficulty, int score, float if (musicDifficulty is 2 && AlbumManager.LoadedAlbums[albumName].HasDifficulty(3) && newScore.Evaluate >= 4) SaveData.UnlockedMasters.Add(albumName); - if (miss != 0) return; + // Update the IData for the played chart + var dataIndex = DataInjectPatch.DataList.GetIndexByUid(album.Uid, musicDifficulty); + if (dataIndex != -1) + { + DataInjectPatch.DataList.RemoveAt(dataIndex); + } + + var newIData = DataInjectPatch.CreateIData(album, musicDifficulty, newScore); + DataInjectPatch.DataList.Add(newIData); // If there were no misses then add the chart/difficulty to the FullCombo list + if (miss != 0) return; + SaveData.FullCombo.TryAdd(albumName, new List()); if (!SaveData.FullCombo[albumName].Contains(musicDifficulty)) diff --git a/Patches/AssetPatch.cs b/Patches/AssetPatch.cs index f8d674c..1818ec2 100644 --- a/Patches/AssetPatch.cs +++ b/Patches/AssetPatch.cs @@ -39,7 +39,7 @@ internal class AssetPatch /// /// The old assetName. /// The new assetName where the value should be bound. - /// true if the key was successfully bound; otherwise, false. + /// if the key was successfully bound; otherwise, . internal static bool ModifyCacheKey(string oldAssetName, string newAssetName) { var success = AssetCache.Remove(oldAssetName, out var asset); @@ -50,7 +50,7 @@ internal static bool ModifyCacheKey(string oldAssetName, string newAssetName) /// Removes a KeyValuePair from the asset cache. /// /// The key corresponding to the value to be removed. - /// true if the entry was successfully removed; otherwise, false. + /// if the entry was successfully removed; otherwise, . internal static bool RemoveFromCache(string key) { return AssetCache.Remove(key); @@ -240,8 +240,8 @@ internal static void InitializeHandler() } /// - /// Gets LoadFromName<TextAsset> and detours it using a - /// NativeHook<LoadFromNameDelegate> to LoadFromNamePatch. + /// Gets where T : and detours it using a + /// where T : to LoadFromNamePatch. /// internal static unsafe void AttachHook() { @@ -277,11 +277,11 @@ internal static unsafe void AttachHook() /// Modifies certain game data as it get loaded. /// The game data that is modified directly adds support for custom albums. /// - /// The instance of ResourceManager calling LoadFromName. + /// The instance of ResourceManager calling LoadFromName. /// The pointer to the string assetName. /// Method info used by the original method. /// - /// A pointer of either a newly created asset if it exists or the original asset pointer if a new one was not + /// An of either a newly created asset if it exists or the original asset if a new one was not /// created. /// [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] @@ -348,7 +348,7 @@ private static IntPtr LoadFromNamePatch(IntPtr instance, IntPtr assetNamePtr, In /// /// /// - /// A new TextAsset initialized with the parameters. + /// A new initialized with the parameters. private static TextAsset CreateTextAsset(string name, string text) { return new TextAsset(text) diff --git a/Patches/DataInjectPatch.cs b/Patches/DataInjectPatch.cs new file mode 100644 index 0000000..54cb197 --- /dev/null +++ b/Patches/DataInjectPatch.cs @@ -0,0 +1,114 @@ +using CustomAlbums.Data; +using CustomAlbums.Managers; +using CustomAlbums.Utilities; +using HarmonyLib; +using Il2CppAssets.Scripts.Database; +using Il2CppAssets.Scripts.PeroTools.Nice.Interface; +using Il2CppAssets.Scripts.PeroTools.Nice.Variables; +using IDataList = Il2CppSystem.Collections.Generic.List; + +namespace CustomAlbums.Patches +{ + /// + /// This patch modifies the highest property of DataHelper to include custom charts. + /// + [HarmonyPatch(typeof(DataHelper), nameof(DataHelper.highest), MethodType.Getter)] + internal class DataInjectPatch + { + internal static readonly IDataList DataList = new(); + private static readonly Logger Logger = new(nameof(DataInjectPatch)); + + // ReSharper disable once InconsistentNaming + private static void Postfix(ref IDataList __result) + { + var highest = DataHelper.s_DataManager["Achievement"]["highest"].GetResult(); + if (highest == null) return; + + if (DataList.Count > 0) + { + var combined1 = new IDataList(); + foreach (var item in highest) + { + combined1.Add(item); + } + foreach (var item in DataList) + { + combined1.Add(item); + } + + __result = combined1; + return; + } + + var customsHighest = SaveManager.SaveData.Highest; + + foreach (var (albumName, albumDic) in customsHighest) + { + foreach (var (difficulty, save) in albumDic) + { + if (!AlbumManager.LoadedAlbums.TryGetValue(albumName, out var album)) + { + Logger.Warning($"No album found for key {albumName}."); + continue; + } + + var data = CreateIData(album, difficulty, save); + DataList.Add(data); + } + } + + // combine the two lists highest and data + var combined = new IDataList(); + foreach (var item in highest) + { + combined.Add(item); + } + foreach (var item in DataList) + { + combined.Add(item); + } + + // set the result to the combined list + __result = combined; + } + + /// + /// Creates a Muse Dash-compatible IData object from a CustomChartSave object. + /// + /// The album of the data to be created. + /// The difficulty of the chart. + /// The CustomChartSave object containing the save data. + /// + internal static IData CreateIData(Album album, int difficulty, CustomChartSave save) + { + var data = new Il2CppAssets.Scripts.PeroTools.Nice.Datas.Data(); + + data.fields.Add("uid", CreateIVariable($"{album.Uid}_{difficulty}")); + data.fields.Add("evaluate", CreateIVariable(save.Evaluate)); + data.fields.Add("score", CreateIVariable(save.Score)); + data.fields.Add("combo", CreateIVariable(save.Combo)); + data.fields.Add("accuracy", CreateIVariable(save.Accuracy)); + data.fields.Add("accuracyStr", CreateIVariable(save.AccuracyStr)); + data.fields.Add("clear", CreateIVariable(save.Clear)); + data.fields.Add("failCount", CreateIVariable(save.FailCount)); + data.fields.Add("passed", CreateIVariable(save.Passed)); + + return data.Cast(); + } + + /// + /// Creates a Muse Dash-compatible IVariable object from an Il2CppSystem.Object. + /// + /// The object (Il2Cpp) to be converted to IVariable. + /// + internal static IVariable CreateIVariable(Il2CppSystem.Object obj) + { + var constance = new Constance + { + result = obj + }; + + return constance.Cast(); + } + } +} diff --git a/Patches/PackPatch.cs b/Patches/PackPatch.cs new file mode 100644 index 0000000..a2f8995 --- /dev/null +++ b/Patches/PackPatch.cs @@ -0,0 +1,40 @@ +using CustomAlbums.Data; +using CustomAlbums.Managers; +using CustomAlbums.Utilities; +using HarmonyLib; +using Il2Cpp; +using Il2CppAssets.Scripts.Database; + +namespace CustomAlbums.Patches +{ + internal class PackPatch + { + private static readonly Logger Logger = new(nameof(PackPatch)); + + [HarmonyPatch(typeof(LongSongNameController), nameof(LongSongNameController.Refresh), new[] { typeof(string), typeof(bool), typeof(float) })] + internal class RefreshPatch { + private static void SetColor(string colorHex, LongSongNameController instance) + { + var fixedColor = UnityEngine.ColorUtility.TryParseHtmlString(colorHex, out var color) ? color : UnityEngine.Color.white; + if (instance.m_MidSimpleName != null) instance.m_MidSimpleName.color = fixedColor; + if (instance.m_TxtBackupName != null) instance.m_TxtBackupName.color = fixedColor; + if (instance.m_TxtSimpleName != null) instance.m_TxtSimpleName.color = fixedColor; + } + + private static void Prefix(ref string text, ref Pack __state) + { + var currentUid = DataHelper.selectedMusicUid; + if (currentUid == null || !currentUid.StartsWith($"{AlbumManager.Uid}-") || text != AlbumManager.GetCustomAlbumsTitle()) return; + + __state = PackManager.GetPackFromUid(currentUid); + text = __state?.Title ?? text; + } + + private static void Postfix(ref Pack __state, LongSongNameController __instance) + { + if (__instance == null) return; + SetColor(__state?.TitleColorHex, __instance); + } + } + } +} diff --git a/Patches/ReportCardPatch.cs b/Patches/ReportCardPatch.cs deleted file mode 100644 index 5c42eea..0000000 --- a/Patches/ReportCardPatch.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System.Globalization; -using System.Reflection; -using CustomAlbums.Managers; -using HarmonyLib; -using Il2Cpp; -using Il2CppAssets.Scripts.Database; -using Il2CppAssets.Scripts.GameCore.Managers; -using Il2CppAssets.Scripts.PeroTools.Commons; -using Il2CppAssets.Scripts.UI.Panels; - -namespace CustomAlbums.Patches -{ - [HarmonyPatch(typeof(PnlReportCard), nameof(PnlReportCard.RefreshBestRecord))] - internal static class ReportCardPatch - { - // ReSharper disable once InconsistentNaming - private static bool Prefix(PnlReportCard __instance) - { - var musicInfo = GlobalDataBase.s_DbMusicTag.CurMusicInfo(); - if (musicInfo.albumIndex != 999) return true; - - var mapDifficulty = GlobalDataBase.s_DbBattleStage.m_MapDifficulty; - var curMusicBestRankOrder = Singleton.instance.GetCurMusicBestRankOrder(); - - var album = AlbumManager.GetByUid(musicInfo.uid); - if (album == null) return false; - - var save = SaveManager.SaveData.Highest[album.AlbumName][mapDifficulty]; - if (save == null) return false; - - __instance.RefreshRecord(musicInfo, mapDifficulty, save.Score, save.Combo, save.AccuracyStr, save.Evaluate, save.Clear.ToString(CultureInfo.InvariantCulture), curMusicBestRankOrder); - return false; - } - } - - [HarmonyPatch] - internal static class TogglePatch - { - private static IEnumerable TargetMethods() - { - return new[] { nameof(PnlPreparation.OnDiffTglChanged), nameof(PnlPreparation.OnEnable) } - .Select(methodName => typeof(PnlPreparation).GetMethod(methodName)) - .ToArray(); - } - // ReSharper disable once InconsistentNaming - private static void Postfix(PnlPreparation __instance) - { - var musicInfo = GlobalDataBase.s_DbMusicTag.CurMusicInfo(); - if (musicInfo.albumIndex != 999) return; - - var mapDifficulty = GlobalDataBase.s_DbBattleStage.m_MapDifficulty; - var gameObject = __instance.btnDownloadReport.gameObject; - - var album = AlbumManager.GetByUid(musicInfo.uid); - if (album == null) - { - gameObject.SetActive(false); - return; - } - - if (!SaveManager.SaveData.Highest.TryGetValue(album.AlbumName, out var chart)) - { - gameObject.SetActive(false); - return; - } - - if (!chart.ContainsKey(mapDifficulty)) - { - gameObject.SetActive(false); - return; - } - - gameObject.SetActive(true); - } - } -} diff --git a/Patches/SavePatch.cs b/Patches/SavePatch.cs index 321bdb3..76489f4 100644 --- a/Patches/SavePatch.cs +++ b/Patches/SavePatch.cs @@ -10,6 +10,7 @@ using Il2CppAssets.Scripts.GameCore.HostComponent; using Il2CppAssets.Scripts.GameCore.Managers; using Il2CppAssets.Scripts.PeroTools.Commons; +using Il2CppAssets.Scripts.PeroTools.Nice.Interface; using Il2CppAssets.Scripts.PeroTools.Platforms.Steam; using Il2CppAssets.Scripts.Structs; using Il2CppAssets.Scripts.UI.Panels; @@ -52,9 +53,9 @@ internal static class SavePatch // /// - /// Sets the PnlRecord (score, combo, accuracy) to the custom chart data. + /// Sets the (score, combo, accuracy) to the custom chart data. /// - /// The PnlRecord instance to set. + /// The instance to set. /// The custom chart data. /// If the selected chart has been FCed. private static void SetPanelWithData(PnlRecord panel, CustomChartSave data, bool isFullCombo) @@ -79,9 +80,10 @@ private static void SetPanelWithData(PnlRecord panel, CustomChartSave data, bool /// /// Clears the current pnlRecord and refreshes the panel if needed. - /// The PnlPreparation instance. - /// Whether panelPreparation should force reload the leaderboards. - /// + /// + /// The instance. + /// Whether panelPreparation should force reload the leaderboards. + /// private static void ClearAndRefreshPanels(PnlPreparation panelPreparation, bool reload) { panelPreparation.pnlRecord.Clear(); @@ -111,8 +113,8 @@ private static int GetDifficulty(string uid) /// /// Grabs the custom chart data and injects the PnlRecord with the chart data. /// - /// The PnlPreparation instance. - /// Whether the PnlPreparation instance should force reload the leaderboards. + /// The instance. + /// Whether the instance should force reload the leaderboards. /// private static bool InjectPnlPreparation(PnlPreparation __instance, bool forceReload) { @@ -231,6 +233,8 @@ private static void CleanCustomData() (Il2CppSystem.Predicate)(uid => uid.StartsWith($"{AlbumManager.Uid}-"))); DataHelper.collections.RemoveAll( (Il2CppSystem.Predicate)(uid => uid.StartsWith($"{AlbumManager.Uid}-"))); + DataHelper.highest.RemoveAll( + (Il2CppSystem.Predicate)(data => data.GetUid().StartsWith($"{AlbumManager.Uid}-"))); if (DataHelper.selectedAlbumUid == "music_package_999") DataHelper.selectedAlbumUid = "music_package_0"; diff --git a/Patches/SceneEggPatch.cs b/Patches/SceneEggPatch.cs index fd98a97..735d741 100644 --- a/Patches/SceneEggPatch.cs +++ b/Patches/SceneEggPatch.cs @@ -39,6 +39,7 @@ internal class ControllerPatch { private static void Prefix(Il2CppSystem.Collections.Generic.List sceneEggIdsBuffer) { + // Return if there are no scene eggs or if the scene eggs have special logic if (IgnoreSceneEggs(out var album, SceneEggs.None, SceneEggs.Christmas, SceneEggs.BadApple)) return; // Adds the scene egg to the buffer @@ -52,18 +53,17 @@ private static void Prefix(Il2CppSystem.Collections.Generic.List sceneEggId } /// - /// Makes scene_05 be scene_05_christmas if the Christmas SceneEgg is enabled or scene_08 be scene_touhou_black if - /// BadApple is enabled. + /// Makes scene_05 be scene_05_christmas if the Christmas SceneEgg is enabled. /// [HarmonyPatch(typeof(GameMusicScene), nameof(GameMusicScene.SceneFestival))] internal class SceneFestivalPatch { private static bool Prefix(string sceneFestivalName, ref string __result) { - // If the scene is not scene_05 or scene_08 then there is no Christmas or Bad Apple + // If the scene is not scene_05 or scene_08 then there is no Christmas if (sceneFestivalName != "scene_05") return true; - // Ignore the actual SceneEggs (and BadApple) + // 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)) return true; @@ -97,10 +97,10 @@ private static bool Prefix(string bossFestivalName, ref string __result) [HarmonyPatch(typeof(DBTouhou), nameof(DBTouhou.AwakeInit))] internal class BadApplePatch { - private static void Postfix(ref string __state) + private static void Postfix() { if (IgnoreSceneEggs(out _, SceneEggs.Arknights, SceneEggs.Cytus, SceneEggs.None, - SceneEggs.Queen, SceneEggs.Touhou, SceneEggs.Wacca, SceneEggs.Miku, SceneEggs.Christmas, SceneEggs.RinLen)) return; + SceneEggs.Queen, SceneEggs.Touhou, SceneEggs.Wacca, SceneEggs.Miku, SceneEggs.Christmas, SceneEggs.RinLen, SceneEggs.BlueArchive)) return; GlobalDataBase.dbTouhou.isBadApple = true; diff --git a/Utilities/DataExtensions.cs b/Utilities/DataExtensions.cs new file mode 100644 index 0000000..4448e82 --- /dev/null +++ b/Utilities/DataExtensions.cs @@ -0,0 +1,43 @@ +using Il2CppAssets.Scripts.PeroTools.Nice.Interface; + +namespace CustomAlbums.Utilities +{ + internal static class DataExtensions + { + /// + /// Gets the uid field of the IData object. + /// + /// The IData object. + /// The uid or an empty string if not found. + public static string GetUid(this IData data) + { + var uidField = data.fields["uid"]; + return uidField == null ? string.Empty : uidField.GetResult(); + } + + /// + /// Gets the index of a chart in an IData list by its uid and difficulty. + /// + /// The IData list. + /// The uid of the chart. + /// The difficulty of the chart. + /// The index of the chart in the list, or -1 if not found. + public static int GetIndexByUid(this Il2CppSystem.Collections.Generic.List dataList, string uid, int difficulty) + { + var i = 0; + + // For loop doesn't work here + foreach (var data in dataList) + { + if (data.GetUid() == $"{uid}_{difficulty}") + { + return i; + } + + i++; + } + + return -1; + } + } +} diff --git a/Utilities/Json.cs b/Utilities/Json.cs index cc0b2f0..c8feddd 100644 --- a/Utilities/Json.cs +++ b/Utilities/Json.cs @@ -49,8 +49,8 @@ public static T Il2CppJsonDeserialize(string text) /// /// Fixes strange issue where getting a single as a decimal does not work. /// - /// A JsonNode - /// The decimal value + /// A + /// The parsed value public static decimal GetValueAsDecimal(this JsonNode node) { return node.ToString().TryParseAsDecimal(out var result) ? result : 0M; diff --git a/Utilities/SaveExtensions.cs b/Utilities/SaveExtensions.cs index 2bcf1f3..d956636 100644 --- a/Utilities/SaveExtensions.cs +++ b/Utilities/SaveExtensions.cs @@ -20,7 +20,7 @@ public class SaveData /// /// The save file data class. /// The chart UID. - /// A JsonObject consisting of score information from the current chart's UID. + /// A object consisting of score information from the current chart's UID. public static SaveData GetChartSaveDataFromUid(this CustomAlbumsSave save, string uid) { var album = AlbumManager.GetByUid(uid); diff --git a/Utilities/StringExtensions.cs b/Utilities/StringExtensions.cs new file mode 100644 index 0000000..bcd4449 --- /dev/null +++ b/Utilities/StringExtensions.cs @@ -0,0 +1,14 @@ +namespace CustomAlbums.Utilities +{ + public static class StringExtensions + { + /// + /// Compares two strings using the comparison type. + /// + /// First string to compare + /// + /// if the value of the is the same as this string; otherwise, . + public static bool EqualsCaseInsensitive(this string str1, string str2) + => str1.Equals(str2, StringComparison.OrdinalIgnoreCase); + } +}