diff --git a/AquaMai/AquaMai.csproj b/AquaMai/AquaMai.csproj
index e7d11e79..dfa62a84 100644
--- a/AquaMai/AquaMai.csproj
+++ b/AquaMai/AquaMai.csproj
@@ -293,6 +293,9 @@
+
+
+
@@ -300,6 +303,7 @@
+
diff --git a/AquaMai/AquaMai.toml b/AquaMai/AquaMai.toml
index 028b7762..5580314a 100644
--- a/AquaMai/AquaMai.toml
+++ b/AquaMai/AquaMai.toml
@@ -51,6 +51,9 @@ TestProof=false
# Custom shop name in photo
# Also enable shop name display in SDGA
CustomPlaceName=""
+# In the song selection screen, press the Service button or the "7" key (the round button in the middle of the arrow keys in the default ADX firmware) to toggle the display of self-made charts.
+# A directory is considered to contain self-made charts if it does not have DataConfig.xml or OfficialChartsMark.txt in the Axxx directory.
+HideSelfMadeCharts=true
[Performance]
# Disable some useless delays to speed up the game boot process
diff --git a/AquaMai/AquaMai.zh.toml b/AquaMai/AquaMai.zh.toml
index 801401dc..b4e0c448 100644
--- a/AquaMai/AquaMai.zh.toml
+++ b/AquaMai/AquaMai.zh.toml
@@ -57,6 +57,9 @@ TestProof=false
# 自定义拍照的店铺名称
# 同时在 SDGA 中会启用店铺名称的显示(但是不会在游戏里有设置)
CustomPlaceName=""
+# 选歌界面按下 Service 键或者键盘上的 “7” 键(ADX 默认固件下箭头键中间的圆形按键)切换自制谱的显示和隐藏
+# 是否是自制谱的判断方式是 Axxx 目录里没有 DataConfig.xml 或 OfficialChartsMark.txt 就认为这个目录里是自制谱
+HideSelfMadeCharts=true
# ===================================
# 一些性能优化
diff --git a/AquaMai/Config.cs b/AquaMai/Config.cs
index 6c819fd3..fc35ce67 100644
--- a/AquaMai/Config.cs
+++ b/AquaMai/Config.cs
@@ -33,6 +33,7 @@ public class UXConfig
public bool ImmediateSave { get; set; }
public bool LoadLocalBga { get; set; }
public bool TestProof { get; set; }
+ public bool HideSelfMadeCharts { get; set; }
public string CustomVersionString { get; set; }
public string CustomPlaceName { get; set; }
public string ExecOnIdle { get; set; }
diff --git a/AquaMai/Helpers/MessageHelper.cs b/AquaMai/Helpers/MessageHelper.cs
new file mode 100644
index 00000000..6dbacfef
--- /dev/null
+++ b/AquaMai/Helpers/MessageHelper.cs
@@ -0,0 +1,37 @@
+using DB;
+using HarmonyLib;
+using Manager;
+using MelonLoader;
+using Process;
+
+namespace AquaMai.Helpers;
+
+public class MessageHelper
+{
+ private static IGenericManager _genericManager = null;
+
+ [HarmonyPostfix]
+ [HarmonyPatch(typeof(ProcessManager), "SetMessageManager")]
+ private static void OnSetMessageManager(IGenericManager genericManager)
+ {
+ _genericManager = genericManager;
+ }
+
+ public static void ShowMessage(string message, WindowSizeID size = WindowSizeID.Middle)
+ {
+ if (_genericManager is null)
+ {
+ MelonLogger.Error($"[MessageHelper] Unable to show message: `{message}` GenericManager is null");
+ return;
+ }
+
+ _genericManager.Enqueue(0, WindowMessageID.CollectionAttentionEmptyFavorite, new WindowParam()
+ {
+ hideTitle = true,
+ replaceText = true,
+ text = message,
+ changeSize = true,
+ sizeID = size
+ });
+ }
+}
diff --git a/AquaMai/Helpers/MusicDirHelper.cs b/AquaMai/Helpers/MusicDirHelper.cs
new file mode 100644
index 00000000..8d7b4979
--- /dev/null
+++ b/AquaMai/Helpers/MusicDirHelper.cs
@@ -0,0 +1,34 @@
+using System.Collections.Generic;
+using System.Diagnostics;
+using HarmonyLib;
+using Manager;
+using MelonLoader;
+
+namespace AquaMai.Helpers;
+
+public class MusicDirHelper
+{
+ private static Dictionary _map = new();
+
+ [HarmonyPostfix]
+ [HarmonyPatch(typeof(Manager.MaiStudio.Serialize.MusicData), "AddPath")]
+ private static void AddPath(Manager.MaiStudio.Serialize.MusicData __instance, string parentPath)
+ {
+ _map[__instance.GetID()] = parentPath;
+ }
+
+ public static string LookupPath(int id)
+ {
+ return _map.GetValueOrDefault(id);
+ }
+
+ public static string LookupPath(Manager.MaiStudio.Serialize.MusicData musicData)
+ {
+ return LookupPath(musicData.GetID());
+ }
+
+ public static string LookupPath(Manager.MaiStudio.MusicData musicData)
+ {
+ return LookupPath(musicData.GetID());
+ }
+}
diff --git a/AquaMai/Helpers/SharedInstances.cs b/AquaMai/Helpers/SharedInstances.cs
new file mode 100644
index 00000000..c37ea446
--- /dev/null
+++ b/AquaMai/Helpers/SharedInstances.cs
@@ -0,0 +1,16 @@
+using HarmonyLib;
+using Process;
+
+namespace AquaMai.Helpers;
+
+public class SharedInstances
+{
+ public static ProcessDataContainer ProcessDataContainer { get; private set; }
+
+ [HarmonyPrefix]
+ [HarmonyPatch(typeof(ProcessDataContainer), MethodType.Constructor)]
+ public static void OnCreateProcessDataContainer(ProcessDataContainer __instance)
+ {
+ ProcessDataContainer = __instance;
+ }
+}
diff --git a/AquaMai/Main.cs b/AquaMai/Main.cs
index a0cde41b..e6596b6f 100644
--- a/AquaMai/Main.cs
+++ b/AquaMai/Main.cs
@@ -1,5 +1,6 @@
using System;
using AquaMai.Fix;
+using AquaMai.Helpers;
using AquaMai.UX;
using MelonLoader;
using Tomlet;
@@ -46,7 +47,7 @@ private static void ApplyPatches()
if (settingProp.PropertyType != typeof(bool)) continue;
// Check if the boolean value is true
- if (!(bool) settingProp.GetValue(categoryValue)) continue;
+ if (!(bool)settingProp.GetValue(categoryValue)) continue;
// Get the Type from the config directive name
var directiveType = Type.GetType($"AquaMai.{categoryProp.Name}.{settingProp.Name}");
@@ -72,17 +73,24 @@ public override void OnInitializeMelon()
// Read AquaMai.toml to load settings
AppConfig = TomletMain.To(System.IO.File.ReadAllText("AquaMai.toml"));
- // Apply patches based on the settings
- ApplyPatches();
-
// Fixes that does not have side effects
// These don't need to be configurable
+
+ // Helpers
+ Patch(typeof(MessageHelper));
+ Patch(typeof(MusicDirHelper));
+ Patch(typeof(SharedInstances));
+ // Fixes
Patch(typeof(FixCharaCrash));
+ Patch(typeof(BasicFix));
+ Patch(typeof(DisableReboot));
+ // UX
Patch(typeof(CustomVersionString));
Patch(typeof(CustomPlaceName));
- Patch(typeof(DisableReboot));
Patch(typeof(RunCommandOnEvents));
- Patch(typeof(BasicFix));
+
+ // Apply patches based on the settings
+ ApplyPatches();
MelonLogger.Msg("Loaded!");
}
diff --git a/AquaMai/UX/HideSelfMadeCharts.cs b/AquaMai/UX/HideSelfMadeCharts.cs
new file mode 100644
index 00000000..625e0e58
--- /dev/null
+++ b/AquaMai/UX/HideSelfMadeCharts.cs
@@ -0,0 +1,80 @@
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using AquaMai.Helpers;
+using HarmonyLib;
+using Manager;
+using MelonLoader;
+using Process;
+using UnityEngine;
+using Util;
+
+namespace AquaMai.UX;
+
+public class HideSelfMadeCharts
+{
+ private static Safe.ReadonlySortedDictionary _musics;
+ private static Safe.ReadonlySortedDictionary _musicsNoneSelfMade;
+
+ private static bool isShowSelfMadeCharts = true;
+
+ [HarmonyPostfix]
+ [HarmonyPatch(typeof(DataManager), "GetMusics")]
+ public static void GetMusics(ref Safe.ReadonlySortedDictionary __result, List ____targetDirs)
+ {
+ if (_musics is null)
+ {
+ // init musics for the first time
+ if (__result.Count == 0) return;
+ _musics = __result;
+ var nonSelfMadeList = new SortedDictionary();
+ var officialDirs = ____targetDirs.Where(it => File.Exists(Path.Combine(it, "DataConfig.xml")) || File.Exists(Path.Combine(it, "OfficialChartsMark.txt")));
+ foreach (var music in __result)
+ {
+ if (officialDirs.Any(it => MusicDirHelper.LookupPath(music.Value).StartsWith(it)))
+ {
+ nonSelfMadeList.Add(music.Key, music.Value);
+ }
+ }
+
+ _musicsNoneSelfMade = new Safe.ReadonlySortedDictionary(nonSelfMadeList);
+ MelonLogger.Msg($"[HideSelfMadeCharts] All music count: {__result.Count}, Official music count: {_musicsNoneSelfMade.Count}");
+ }
+
+ var stackTrace = new StackTrace(); // get call stack
+ var stackFrames = stackTrace.GetFrames(); // get method calls (frames)
+ if (stackFrames.All(it => it.GetMethod().DeclaringType.Name != "MusicSelectProcess")) return;
+ if (isShowSelfMadeCharts) return;
+ __result = _musicsNoneSelfMade;
+ }
+
+ private static int _keyPressFrames;
+
+ [HarmonyPostfix]
+ [HarmonyPatch(typeof(MusicSelectProcess), "OnUpdate")]
+ public static void MusicSelectProcessOnUpdate(ref MusicSelectProcess __instance)
+ {
+ if (Input.GetKey(KeyCode.Alpha7) || InputManager.GetSystemInputPush(InputManager.SystemButtonSetting.ButtonService))
+ {
+ _keyPressFrames++;
+ }
+ else if (_keyPressFrames is > 0 and < 30 && !Input.GetKey(KeyCode.Alpha7) && !InputManager.GetSystemInputPush(InputManager.SystemButtonSetting.ButtonService))
+ {
+ _keyPressFrames = 0;
+ isShowSelfMadeCharts = !isShowSelfMadeCharts;
+ MelonLogger.Msg($"[HideSelfMadeCharts] isShowSelfMadeCharts: {isShowSelfMadeCharts}");
+ SharedInstances.ProcessDataContainer.processManager.AddProcess(new FadeProcess(SharedInstances.ProcessDataContainer, __instance, new MusicSelectProcess(SharedInstances.ProcessDataContainer)));
+ Task.Run(async () =>
+ {
+ await Task.Delay(1000);
+ MessageHelper.ShowMessage($"{(isShowSelfMadeCharts ? "Show" : "Hide")} Self-Made Charts");
+ });
+ }
+ else
+ {
+ _keyPressFrames = 0;
+ }
+ }
+}
diff --git a/AquaMai/UX/LoadJacketPng.cs b/AquaMai/UX/LoadJacketPng.cs
index 0a2b712a..fd35956f 100644
--- a/AquaMai/UX/LoadJacketPng.cs
+++ b/AquaMai/UX/LoadJacketPng.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Reflection;
@@ -67,7 +66,7 @@ public static void LoadMusicPostfix(List ____targetDirs)
jacketPaths[match.Groups[1].Value] = laFile;
}
- MelonLogger.Msg($"Loaded {jacketPaths.Count} custom jacket images.");
+ MelonLogger.Msg($"[LoadJacketPng] Loaded {jacketPaths.Count} custom jacket images.");
}
private static string GetJacketPath(string id)
diff --git a/AquaMai/UX/QuickSkip.cs b/AquaMai/UX/QuickSkip.cs
index 1c1badfb..2226b9b1 100644
--- a/AquaMai/UX/QuickSkip.cs
+++ b/AquaMai/UX/QuickSkip.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using AquaMai.Helpers;
using HarmonyLib;
using Mai2.Mai2Cue;
using MAI2.Util;
@@ -12,16 +13,8 @@ namespace AquaMai.UX
{
public class QuickSkip
{
- private static ProcessDataContainer _container;
private static int _keyPressFrames;
- [HarmonyPrefix]
- [HarmonyPatch(typeof(ProcessDataContainer), MethodType.Constructor)]
- public static void OnCreateProcessDataContainer(ProcessDataContainer __instance)
- {
- _container = __instance;
- }
-
[HarmonyPrefix]
[HarmonyPatch(typeof(GameMainObject), "Update")]
public static void OnGameMainObjectUpdate()
@@ -32,14 +25,14 @@ public static void OnGameMainObjectUpdate()
if (_keyPressFrames > 0 && !Input.GetKey(KeyCode.Alpha7) && !InputManager.GetSystemInputPush(InputManager.SystemButtonSetting.ButtonService))
{
_keyPressFrames = 0;
- MelonLogger.Msg(_container.processManager.Dump());
+ MelonLogger.Msg(SharedInstances.ProcessDataContainer.processManager.Dump());
return;
}
if (_keyPressFrames != 60) return;
MelonLogger.Msg("[QuickSkip] Activated");
- var traverse = Traverse.Create(_container.processManager);
+ var traverse = Traverse.Create(SharedInstances.ProcessDataContainer.processManager);
var processList = traverse.Field("_processList").GetValue>();
ProcessBase processToRelease = null;
@@ -61,7 +54,7 @@ public static void OnGameMainObjectUpdate()
// Skip to save
SoundManager.PreviewEnd();
SoundManager.PlayBGM(Cue.BGM_COLLECTION, 2);
- _container.processManager.AddProcess(new FadeProcess(_container, process.Process, new UnlockMusicProcess(_container)));
+ SharedInstances.ProcessDataContainer.processManager.AddProcess(new FadeProcess(SharedInstances.ProcessDataContainer, process.Process, new UnlockMusicProcess(SharedInstances.ProcessDataContainer)));
break;
}
}
@@ -69,7 +62,7 @@ public static void OnGameMainObjectUpdate()
if (processToRelease != null)
{
GameManager.SetMaxTrack();
- _container.processManager.AddProcess(new FadeProcess(_container, processToRelease, new MusicSelectProcess(_container)));
+ SharedInstances.ProcessDataContainer.processManager.AddProcess(new FadeProcess(SharedInstances.ProcessDataContainer, processToRelease, new MusicSelectProcess(SharedInstances.ProcessDataContainer)));
}
}