2024-02-07 18:16:07 +08:00
|
|
|
|
using System;
|
2024-09-30 01:26:54 +08:00
|
|
|
|
using System.Globalization;
|
2024-09-17 03:24:35 +08:00
|
|
|
|
using System.IO;
|
2024-09-28 15:31:58 +08:00
|
|
|
|
using System.Reflection;
|
2024-09-17 02:58:37 +08:00
|
|
|
|
using System.Runtime.InteropServices;
|
2024-10-27 23:34:41 +08:00
|
|
|
|
using AquaMai.Attributes;
|
2024-02-07 18:16:07 +08:00
|
|
|
|
using AquaMai.Fix;
|
2024-09-05 02:31:07 +08:00
|
|
|
|
using AquaMai.Helpers;
|
2024-11-01 17:03:57 +08:00
|
|
|
|
using AquaMai.ModKeyMap;
|
2024-09-30 01:26:54 +08:00
|
|
|
|
using AquaMai.Resources;
|
2024-09-17 04:13:51 +08:00
|
|
|
|
using AquaMai.Utils;
|
2024-04-08 14:59:54 +08:00
|
|
|
|
using AquaMai.UX;
|
2024-10-28 06:09:42 +08:00
|
|
|
|
using AquaMai.Visual;
|
2024-02-07 15:38:36 +08:00
|
|
|
|
using MelonLoader;
|
2024-02-07 17:06:58 +08:00
|
|
|
|
using Tomlet;
|
2024-09-30 01:26:54 +08:00
|
|
|
|
using UnityEngine;
|
2024-02-07 13:45:47 +08:00
|
|
|
|
|
|
|
|
|
namespace AquaMai
|
|
|
|
|
{
|
|
|
|
|
public static class BuildInfo
|
|
|
|
|
{
|
|
|
|
|
public const string Name = "AquaMai";
|
|
|
|
|
public const string Description = "Mod for Sinmai";
|
|
|
|
|
public const string Author = "Aza";
|
|
|
|
|
public const string Company = null;
|
2024-10-30 07:27:54 +08:00
|
|
|
|
public const string Version = "1.2.2";
|
2024-02-07 13:45:47 +08:00
|
|
|
|
public const string DownloadLink = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class AquaMai : MelonMod
|
|
|
|
|
{
|
2024-02-07 15:38:36 +08:00
|
|
|
|
public static Config AppConfig { get; private set; }
|
2024-09-17 02:58:37 +08:00
|
|
|
|
private static bool _hasErrors;
|
2024-09-02 17:35:31 +08:00
|
|
|
|
|
2024-10-27 23:34:41 +08:00
|
|
|
|
private void Patch(Type type, bool isNested = false)
|
2024-02-07 18:16:07 +08:00
|
|
|
|
{
|
2024-10-27 23:34:41 +08:00
|
|
|
|
var versionAttr = type.GetCustomAttribute<GameVersionAttribute>();
|
|
|
|
|
var compatible = true;
|
|
|
|
|
if (versionAttr != null)
|
|
|
|
|
{
|
|
|
|
|
if (versionAttr.MinVersion > 0 && versionAttr.MinVersion > GameInfo.GameVersion) compatible = false;
|
|
|
|
|
if (versionAttr.MaxVersion > 0 && versionAttr.MaxVersion < GameInfo.GameVersion) compatible = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!compatible)
|
|
|
|
|
{
|
|
|
|
|
if (!isNested)
|
|
|
|
|
{
|
2024-10-27 23:56:26 +08:00
|
|
|
|
MelonLogger.Warning(string.Format(Locale.SkipIncompatiblePatch, type));
|
2024-10-27 23:34:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-07 18:16:07 +08:00
|
|
|
|
MelonLogger.Msg($"> Patching {type}");
|
2024-09-17 02:48:07 +08:00
|
|
|
|
try
|
2024-09-11 00:38:13 +08:00
|
|
|
|
{
|
2024-09-17 02:48:07 +08:00
|
|
|
|
HarmonyInstance.PatchAll(type);
|
|
|
|
|
foreach (var nested in type.GetNestedTypes())
|
|
|
|
|
{
|
2024-10-27 23:34:41 +08:00
|
|
|
|
Patch(nested, true);
|
2024-09-17 02:48:07 +08:00
|
|
|
|
}
|
2024-09-28 15:31:58 +08:00
|
|
|
|
|
|
|
|
|
var customMethod = type.GetMethod("DoCustomPatch", BindingFlags.Public | BindingFlags.Static);
|
|
|
|
|
customMethod?.Invoke(null, [HarmonyInstance]);
|
2024-09-17 02:48:07 +08:00
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
MelonLogger.Error($"Failed to patch {type}: {e}");
|
2024-09-17 02:58:37 +08:00
|
|
|
|
_hasErrors = true;
|
2024-09-11 00:38:13 +08:00
|
|
|
|
}
|
2024-02-07 18:16:07 +08:00
|
|
|
|
}
|
2024-09-02 17:35:31 +08:00
|
|
|
|
|
2024-02-07 18:40:13 +08:00
|
|
|
|
/**
|
|
|
|
|
* Apply patches using reflection, based on the settings
|
|
|
|
|
*/
|
2024-09-11 00:26:45 +08:00
|
|
|
|
private void ApplyPatches()
|
2024-02-07 18:40:13 +08:00
|
|
|
|
{
|
|
|
|
|
// Iterate over all properties of AppConfig
|
|
|
|
|
foreach (var categoryProp in AppConfig.GetType().GetProperties())
|
|
|
|
|
{
|
|
|
|
|
// Get the value of the category property (e.g., UX, Cheat)
|
|
|
|
|
var categoryValue = categoryProp.GetValue(AppConfig);
|
|
|
|
|
if (categoryValue == null) continue;
|
|
|
|
|
var categoryType = categoryValue.GetType();
|
|
|
|
|
|
|
|
|
|
// Iterate over properties in the category (e.g., SkipWarningScreen, SinglePlayer)
|
|
|
|
|
foreach (var settingProp in categoryType.GetProperties())
|
|
|
|
|
{
|
|
|
|
|
// The property should be a boolean
|
|
|
|
|
if (settingProp.PropertyType != typeof(bool)) continue;
|
2024-09-02 17:35:31 +08:00
|
|
|
|
|
2024-02-07 18:40:13 +08:00
|
|
|
|
// Check if the boolean value is true
|
2024-09-05 02:31:07 +08:00
|
|
|
|
if (!(bool)settingProp.GetValue(categoryValue)) continue;
|
2024-09-02 17:35:31 +08:00
|
|
|
|
|
2024-02-07 18:40:13 +08:00
|
|
|
|
// Get the Type from the config directive name
|
|
|
|
|
var directiveType = Type.GetType($"AquaMai.{categoryProp.Name}.{settingProp.Name}");
|
2024-02-07 18:20:39 +08:00
|
|
|
|
|
2024-02-07 18:40:13 +08:00
|
|
|
|
// If the type is found, call the Patch method
|
2024-09-11 00:26:45 +08:00
|
|
|
|
if (directiveType != null)
|
|
|
|
|
{
|
|
|
|
|
Patch(directiveType);
|
|
|
|
|
}
|
2024-02-07 18:40:13 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-09-02 17:35:31 +08:00
|
|
|
|
|
2024-09-17 02:58:37 +08:00
|
|
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|
|
|
|
private static extern bool SetConsoleOutputCP(uint wCodePageID);
|
|
|
|
|
|
2024-09-30 01:26:54 +08:00
|
|
|
|
private static void InitLocale()
|
|
|
|
|
{
|
|
|
|
|
if (!string.IsNullOrEmpty(AppConfig.UX.Locale))
|
|
|
|
|
{
|
|
|
|
|
Locale.Culture = CultureInfo.GetCultureInfo(AppConfig.UX.Locale);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Locale.Culture = Application.systemLanguage switch
|
|
|
|
|
{
|
|
|
|
|
SystemLanguage.Chinese or SystemLanguage.ChineseSimplified or SystemLanguage.ChineseTraditional => CultureInfo.GetCultureInfo("zh"),
|
|
|
|
|
SystemLanguage.English => CultureInfo.GetCultureInfo("en"),
|
|
|
|
|
_ => CultureInfo.InvariantCulture
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-02 17:35:31 +08:00
|
|
|
|
public override void OnInitializeMelon()
|
2024-02-07 13:45:47 +08:00
|
|
|
|
{
|
2024-09-17 02:58:37 +08:00
|
|
|
|
// Prevent Chinese characters from being garbled
|
|
|
|
|
SetConsoleOutputCP(65001);
|
|
|
|
|
|
2024-02-07 16:53:13 +08:00
|
|
|
|
MelonLogger.Msg("Loading mod settings...");
|
2024-02-07 18:16:24 +08:00
|
|
|
|
|
2024-02-07 17:06:58 +08:00
|
|
|
|
// Check if AquaMai.toml exists
|
2024-09-17 03:24:35 +08:00
|
|
|
|
if (!File.Exists("AquaMai.toml"))
|
2024-02-07 17:06:58 +08:00
|
|
|
|
{
|
2024-10-27 22:44:12 +08:00
|
|
|
|
ConfigGenerator.GenerateConfig();
|
2024-09-17 03:24:35 +08:00
|
|
|
|
MelonLogger.Error("======================================!!!");
|
2024-02-07 17:06:58 +08:00
|
|
|
|
MelonLogger.Error("AquaMai.toml not found! Please create it.");
|
2024-09-17 03:24:35 +08:00
|
|
|
|
MelonLogger.Error("找不到配置文件 AquaMai.toml!请创建。");
|
2024-10-27 22:44:12 +08:00
|
|
|
|
MelonLogger.Error("Example copied to AquaMai.en.toml");
|
|
|
|
|
MelonLogger.Error("示例已复制到 AquaMai.zh.toml");
|
2024-09-17 03:24:35 +08:00
|
|
|
|
MelonLogger.Error("=========================================");
|
2024-02-07 17:06:58 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
2024-02-07 18:16:24 +08:00
|
|
|
|
|
2024-02-07 17:06:58 +08:00
|
|
|
|
// Read AquaMai.toml to load settings
|
2024-09-17 03:24:35 +08:00
|
|
|
|
AppConfig = TomletMain.To<Config>(File.ReadAllText("AquaMai.toml"));
|
2024-09-02 17:35:31 +08:00
|
|
|
|
|
2024-09-30 01:26:54 +08:00
|
|
|
|
// Init locale with patching C# runtime
|
|
|
|
|
// https://stackoverflow.com/questions/1952638/single-assembly-multi-language-windows-forms-deployment-ilmerge-and-satellite-a
|
|
|
|
|
Patch(typeof(I18nSingleAssemblyHook));
|
|
|
|
|
InitLocale();
|
|
|
|
|
|
2024-02-07 18:16:07 +08:00
|
|
|
|
// Fixes that does not have side effects
|
|
|
|
|
// These don't need to be configurable
|
2024-09-05 02:31:07 +08:00
|
|
|
|
|
|
|
|
|
// Helpers
|
|
|
|
|
Patch(typeof(MessageHelper));
|
|
|
|
|
Patch(typeof(MusicDirHelper));
|
|
|
|
|
Patch(typeof(SharedInstances));
|
2024-10-24 02:12:36 +08:00
|
|
|
|
Patch(typeof(GuiSizes));
|
2024-09-05 02:31:07 +08:00
|
|
|
|
// Fixes
|
2024-02-07 18:16:07 +08:00
|
|
|
|
Patch(typeof(FixCharaCrash));
|
2024-09-05 02:31:07 +08:00
|
|
|
|
Patch(typeof(BasicFix));
|
|
|
|
|
Patch(typeof(DisableReboot));
|
2024-10-27 23:34:41 +08:00
|
|
|
|
Patch(typeof(ExtendNotesPool));
|
2024-09-17 02:48:07 +08:00
|
|
|
|
Patch(typeof(FixCheckAuth));
|
2024-09-27 20:18:53 +08:00
|
|
|
|
Patch(typeof(DebugFeature));
|
2024-10-27 23:34:41 +08:00
|
|
|
|
Patch(typeof(FixConnSlide));
|
2024-11-01 17:03:57 +08:00
|
|
|
|
Patch(typeof(FestivalQuickRetryFix));
|
2024-10-28 06:09:42 +08:00
|
|
|
|
// Visual
|
2024-10-25 20:42:08 +08:00
|
|
|
|
Patch(typeof(FixSlideAutoPlay)); // Rename: SlideAutoPlayTweak -> FixSlideAutoPlay, 不过这个应该无副作用所以不需要改配置文件
|
2024-10-28 05:43:55 +08:00
|
|
|
|
Patch(typeof(FixCircleSlideJudge)); // 这个我觉得算无副作用, 可以常开
|
2024-10-27 23:34:41 +08:00
|
|
|
|
Patch(typeof(FixLevelDisplay));
|
2024-10-28 06:09:42 +08:00
|
|
|
|
Patch(typeof(CustomLogo));
|
2024-09-05 02:31:07 +08:00
|
|
|
|
// UX
|
2024-04-08 14:59:54 +08:00
|
|
|
|
Patch(typeof(CustomVersionString));
|
2024-09-02 23:02:47 +08:00
|
|
|
|
Patch(typeof(CustomPlaceName));
|
2024-05-20 22:31:27 +08:00
|
|
|
|
Patch(typeof(RunCommandOnEvents));
|
2024-09-17 04:13:51 +08:00
|
|
|
|
// Utils
|
|
|
|
|
Patch(typeof(JudgeAdjust));
|
2024-10-22 00:19:12 +08:00
|
|
|
|
Patch(typeof(TouchPanelBaudRate));
|
2024-11-01 17:03:57 +08:00
|
|
|
|
// ModKeyMap
|
|
|
|
|
// TODO: Make it configurable
|
|
|
|
|
Patch(typeof(ModKeyListener));
|
|
|
|
|
Patch(typeof(QuickSkip));
|
|
|
|
|
Patch(typeof(TestProof));
|
|
|
|
|
Patch(typeof(PractiseMode));
|
|
|
|
|
Patch(typeof(HideSelfMadeCharts));
|
2024-11-06 11:39:54 +08:00
|
|
|
|
# if CI
|
|
|
|
|
Patch(typeof(CiBuildAlert));
|
|
|
|
|
# endif
|
2024-10-25 20:42:08 +08:00
|
|
|
|
|
2024-09-05 02:31:07 +08:00
|
|
|
|
// Apply patches based on the settings
|
|
|
|
|
ApplyPatches();
|
2024-02-07 18:20:39 +08:00
|
|
|
|
|
2024-09-17 02:58:37 +08:00
|
|
|
|
if (_hasErrors)
|
|
|
|
|
{
|
2024-10-01 01:00:32 +08:00
|
|
|
|
MelonLogger.Warning("========================================================================!!!\n" + Locale.LoadError);
|
2024-09-17 03:24:35 +08:00
|
|
|
|
MelonLogger.Warning("===========================================================================");
|
2024-09-17 02:58:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-11-06 11:39:54 +08:00
|
|
|
|
# if CI
|
|
|
|
|
MelonLogger.Warning(Locale.CiBuildAlertTitle);
|
|
|
|
|
MelonLogger.Warning(Locale.CiBuildAlertContent);
|
|
|
|
|
# endif
|
|
|
|
|
|
2024-10-01 00:15:55 +08:00
|
|
|
|
MelonLogger.Msg(Locale.Loaded);
|
2024-02-07 13:45:47 +08:00
|
|
|
|
}
|
2024-10-24 02:12:36 +08:00
|
|
|
|
|
|
|
|
|
public override void OnGUI()
|
|
|
|
|
{
|
|
|
|
|
GuiSizes.SetupStyles();
|
|
|
|
|
base.OnGUI();
|
|
|
|
|
}
|
2024-02-07 13:45:47 +08:00
|
|
|
|
}
|
2024-02-07 18:16:24 +08:00
|
|
|
|
}
|