AquaDX/AquaMai/Main.cs

223 lines
8.6 KiB
C#
Raw Normal View History

2024-02-07 18:16:07 +08:00
using System;
2024-09-30 01:26:54 +08:00
using System.Globalization;
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-09-30 01:26:54 +08:00
using System.Threading;
2024-02-07 18:16:07 +08:00
using AquaMai.Fix;
using AquaMai.Helpers;
using AquaMai.MaimaiDX2077;
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-02-07 15:38:36 +08:00
using MelonLoader;
using Monitor;
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-22 00:19:43 +08:00
public const string Version = "1.2.1";
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;
private void Patch(Type type)
2024-02-07 18:16:07 +08:00
{
MelonLogger.Msg($"> Patching {type}");
try
{
HarmonyInstance.PatchAll(type);
foreach (var nested in type.GetNestedTypes())
{
Patch(nested);
}
2024-09-28 15:31:58 +08:00
var customMethod = type.GetMethod("DoCustomPatch", BindingFlags.Public | BindingFlags.Static);
customMethod?.Invoke(null, [HarmonyInstance]);
}
catch (Exception e)
{
MelonLogger.Error($"Failed to patch {type}: {e}");
2024-09-17 02:58:37 +08:00
_hasErrors = true;
}
2024-02-07 18:16:07 +08:00
}
2024-02-07 18:40:13 +08:00
/**
* Apply patches using reflection, based on the settings
*/
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-02-07 18:40:13 +08:00
// Check if the boolean value is true
if (!(bool)settingProp.GetValue(categoryValue)) continue;
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:40:13 +08:00
// If the type is found, call the Patch method
if (directiveType != null)
{
Patch(directiveType);
}
2024-02-07 18:40:13 +08:00
}
}
}
2024-09-17 02:58:37 +08:00
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetConsoleOutputCP(uint wCodePageID);
private void WriteEmbeddedResourceToFile(string resource, string file)
{
using var s = MelonAssembly.Assembly.GetManifestResourceStream(resource);
using var fs = File.Open(file, FileMode.Create);
s.CopyTo(fs);
}
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
};
}
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 17:06:58 +08:00
// Check if AquaMai.toml exists
if (!File.Exists("AquaMai.toml"))
2024-02-07 17:06:58 +08:00
{
WriteEmbeddedResourceToFile("AquaMai.AquaMai.toml", "AquaMai.example.toml");
WriteEmbeddedResourceToFile("AquaMai.AquaMai.zh.toml", "AquaMai.example.zh.toml");
MelonLogger.Error("======================================!!!");
2024-02-07 17:06:58 +08:00
MelonLogger.Error("AquaMai.toml not found! Please create it.");
MelonLogger.Error("找不到配置文件 AquaMai.toml请创建。");
MelonLogger.Error("Example copied to AquaMai.example.toml");
MelonLogger.Error("示例已复制到 AquaMai.example.zh.toml");
MelonLogger.Error("=========================================");
2024-02-07 17:06:58 +08:00
return;
}
2024-02-07 17:06:58 +08:00
// Read AquaMai.toml to load settings
AppConfig = TomletMain.To<Config>(File.ReadAllText("AquaMai.toml"));
2024-09-06 23:15:53 +08:00
// Migrate old settings
AppConfig.UX.LoadAssetsPng = AppConfig.UX.LoadAssetsPng || AppConfig.UX.LoadJacketPng;
AppConfig.UX.LoadJacketPng = false;
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
// Helpers
Patch(typeof(MessageHelper));
Patch(typeof(MusicDirHelper));
Patch(typeof(SharedInstances));
2024-10-24 02:12:36 +08:00
Patch(typeof(GuiSizes));
// Fixes
2024-02-07 18:16:07 +08:00
Patch(typeof(FixCharaCrash));
Patch(typeof(BasicFix));
Patch(typeof(DisableReboot));
2024-10-24 01:15:55 +08:00
if (GameInfo.GameVersion >= 23000)
Patch(typeof(ExtendNotesPool));
Patch(typeof(FixCheckAuth));
Patch(typeof(DebugFeature));
2024-10-24 01:15:55 +08:00
if (GameInfo.GameVersion >= 23000)
Patch(typeof(FixConnSlide));
Patch(typeof(FixSlideAutoPlay)); // Rename: SlideAutoPlayTweak -> FixSlideAutoPlay, 不过这个应该无副作用所以不需要改配置文件
2024-10-24 01:15:55 +08:00
if (GameInfo.GameVersion >= 24000)
Patch(typeof(FixLevelDisplay));
// UX
2024-04-08 14:59:54 +08:00
Patch(typeof(CustomVersionString));
2024-09-02 23:02:47 +08:00
Patch(typeof(CustomPlaceName));
Patch(typeof(RunCommandOnEvents));
2024-10-04 22:45:48 +08:00
Patch(typeof(CustomLogo));
2024-09-17 04:13:51 +08:00
// Utils
Patch(typeof(JudgeAdjust));
2024-10-22 00:19:12 +08:00
Patch(typeof(TouchPanelBaudRate));
// New Features & Changes
// 现在自定义皮肤相关的功能应该有 CustomSkin, JudgeDisplay4B, CustomTrackStartDiff
// 后续应该还会接着做, 所以也许可以考虑把自定义皮肤相关的部分单独分一类 ?
Patch(typeof(CustomSkins)); // Rename: CustomNoteSkin -> CustomSkins
Patch(typeof(JudgeDisplay4B));
Patch(typeof(CustomTrackStartDiff));
Patch(typeof(RealisticRandomJudge)); // 本来是用来调试判定显示4B的, 觉得还挺有趣就单独做成功能了
Patch(typeof(DisableTrackStartTabs)); // 从 TrackStartProcessTweak 里单独拆出来了
// 以下三项拆分自 SlideJudgeTweak
Patch(typeof(FanJudgeFlip));
Patch(typeof(BreakSlideJudgeBlink));
Patch(typeof(FixCircleSlideJudge)); // 这个我觉得算无副作用, 可以常开
// 这是一项往 Sinmai 里加各种新 note 的企划, 目前只完成了可高度自定义形状的星星
// 未来还会缓慢更新, 我建议单开一个功能分类
// 注意需要往 UserLib 里放入 System.Numeric.dll
Patch(typeof(CustomNoteTypePatch));
# if DEBUG
Patch(typeof(LogNetworkErrors));
# endif
// Apply patches based on the settings
ApplyPatches();
2024-09-17 02:58:37 +08:00
if (_hasErrors)
{
2024-10-01 01:00:32 +08:00
MelonLogger.Warning("========================================================================!!!\n" + Locale.LoadError);
MelonLogger.Warning("===========================================================================");
2024-09-17 02:58:37 +08:00
}
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
}
}