From daf3083d29eefb45ef41f87d73cc26a86c016e2f Mon Sep 17 00:00:00 2001 From: simon <49937999+ck2739046@users.noreply.github.com> Date: Tue, 11 Feb 2025 07:15:40 +0800 Subject: [PATCH] [+] Custombutton (#31) --- AquaMai.Mods/Fancy/CustomButton.cs | 119 +++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 AquaMai.Mods/Fancy/CustomButton.cs diff --git a/AquaMai.Mods/Fancy/CustomButton.cs b/AquaMai.Mods/Fancy/CustomButton.cs new file mode 100644 index 00000000..2ebb25d5 --- /dev/null +++ b/AquaMai.Mods/Fancy/CustomButton.cs @@ -0,0 +1,119 @@ +using AquaMai.Config.Attributes; +using AquaMai.Core.Helpers; +using HarmonyLib; +using System.Reflection; +using MelonLoader; +using UnityEngine; +using System.Collections.Generic; +using System.IO; +using System; +using Monitor.Entry.Parts; + +namespace AquaMai.Mods.Fancy; + +[ConfigSection( + en: "Custom button textures\nLoad button textures from specified directory", + zh: "自定义按钮贴图\n从指定目录加载按钮贴图")] + +public class CustomButton +{ + [ConfigEntry( + en: "path to button texture directory", + zh: "按钮贴图的目录")] + private static readonly string buttonDir = "LocalAssets/Buttons"; + + private static readonly Dictionary spriteDict = new(); + private static bool isInitialized = false; + + public static void OnBeforePatch() { Initialize(); } + + private static void Initialize() + { + // resolve path + var buttonDir_r = FileSystem.ResolvePath(buttonDir); + if (!Directory.Exists(buttonDir_r)) { + MelonLogger.Msg($"[CustomButton] buttonDir not found: {buttonDir}"); + return; + } + // load button textures to dict + try { + foreach (var file in Directory.EnumerateFiles(buttonDir_r, "*.png")) { + var fileName = Path.GetFileNameWithoutExtension(file); + var bytes = File.ReadAllBytes(file); + var tex = new Texture2D(2, 2); + tex.LoadImage(bytes); + spriteDict[fileName] = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f)); + } + MelonLogger.Msg($"[CustomButton] Loaded {spriteDict.Count} Textures"); + isInitialized = true; + } catch (Exception e) {MelonLogger.Msg($"[CustomButton] Error in Initialize: {e}");} + } + + // 通用获取按钮贴图的方法,对于大多数按钮都适用 + [HarmonyPrefix] + [HarmonyPatch(typeof(ButtonControllerBase), "LoadDefaultResources")] + public static void LoadDefaultResourcesPrefix() + { + if (!isInitialized) return; + try { + // 通过反射获取FlatButtonParam字段 + var flatButtonParamField = typeof(ButtonControllerBase) + .GetField("FlatButtonParam", BindingFlags.NonPublic | BindingFlags.Static); + var flatButtonParams = flatButtonParamField.GetValue(null) as ButtonControllerBase.ButtonInformation[]; + // 遍历并替换贴图 + for (int i = 0; i < flatButtonParams.Length; i++) { + var buttonInfo = flatButtonParams[i]; + var buttonName = Path.GetFileNameWithoutExtension(buttonInfo.FileName); + if (spriteDict.TryGetValue(buttonName, out var sprite)) { + // 直接修改贴图 + buttonInfo.Image = sprite; + } else { + // 加载原始贴图 + buttonInfo.Image = Resources.Load(buttonInfo.FileName); + } + flatButtonParams[i] = buttonInfo; // 保存修改 + } + // 处理箭头贴图 + var arrowSpriteField = typeof(ButtonControllerBase) + .GetField("ArrowSprite", BindingFlags.NonPublic | BindingFlags.Static); + var arrowSelectorSpriteField = typeof(ButtonControllerBase) + .GetField("ArrowSelectorSprite", BindingFlags.NonPublic | BindingFlags.Static); + arrowSpriteField.SetValue(null, Resources.Load("Common/Sprites/Button/UI_CMN_Arrow")); + arrowSelectorSpriteField.SetValue(null, Resources.Load("Common/Sprites/Button/UI_MDS_Btn_Arrow")); + // 阻止原函数执行 + var loadedField = typeof(ButtonControllerBase) + .GetField("_isFlatButtonLoaded", BindingFlags.NonPublic | BindingFlags.Static); + loadedField.SetValue(null, true); + } catch (Exception e) {MelonLogger.Msg($"[CustomButton] {e}");} + } + + // ButtonManager会独立加载贴图为EntryButton,需要单独处理 + [HarmonyPostfix] + [HarmonyPatch(typeof(ButtonManager), "Initialize")] + public static void ButtonManagerInitializePostfix(ButtonManager __instance) + { + if (!isInitialized) return; + try { + // 通过反射获取_containers字段 + var containersField = typeof(ButtonManager).GetField("_containers", + BindingFlags.NonPublic | BindingFlags.Instance); + var containers = containersField.GetValue(__instance); + // 获取Container类 + var containerType = typeof(ButtonManager).GetNestedType("Container", + BindingFlags.NonPublic); + var spritePathField = containerType.GetField("SpritePath"); + var spriteField = containerType.GetField("Sprite"); + // 获取Values属性 + var valuesMethod = containers.GetType().GetProperty("Values").GetGetMethod(); + var values = valuesMethod.Invoke(containers, null) as System.Collections.IEnumerable; + // 遍历所有容器并修改贴图 + foreach (var container in values) { + var spritePath = spritePathField.GetValue(container) as string; + var buttonName = Path.GetFileNameWithoutExtension(spritePath); + if (spriteDict.TryGetValue(buttonName, out var sprite)) { + spriteField.SetValue(container, sprite); + } + } + } catch (Exception e) {MelonLogger.Msg($"[CustomButton] {e}");} + } +} \ No newline at end of file