diff --git a/Menu/LocalisedChoiceElement.cs b/Menu/LocalisedChoiceElement.cs deleted file mode 100644 index 7d90981..0000000 --- a/Menu/LocalisedChoiceElement.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Silksong.ModMenu.Elements; -using Silksong.ModMenu.Models; -using System.Collections.Generic; -using TeamCherry.Localization; - -namespace VVVVVV.Menu; - -internal class LocalisedChoiceElement : ChoiceElement { - - private LocalisedString localisedLabel; - private LocalisedString? localisedDesc; - - public LocalisedChoiceElement(LocalisedString label, IChoiceModel model, LocalisedString? description = null) - : base(label.ToString(), model, description ?? "") - { - localisedLabel = label; - localisedDesc = description; - Container.name = $"{label.Key}"; - var updater = Container.AddComponentIfNotPresent(); - updater.OnLanguageChanged += UpdateLocalisation; - } - - public LocalisedChoiceElement(LocalisedString label, List items, LocalisedString? description = null) - : this(label, ChoiceModels.ForValues(items), description) { } - - private void UpdateLocalisation() { - LabelText.text = localisedLabel.ToString(); - DescriptionText.text = localisedDesc?.ToString() ?? ""; - } - -} diff --git a/Menu/LocalisedListChoiceModel.cs b/Menu/LocalisedListChoiceModel.cs deleted file mode 100644 index f159290..0000000 --- a/Menu/LocalisedListChoiceModel.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Silksong.ModMenu.Models; -using System.Collections.Generic; -using System.Linq; -using TeamCherry.Localization; - -namespace VVVVVV.Menu; - -internal class LocalisedListChoiceModel : ListChoiceModel { - - readonly List names; - - public LocalisedListChoiceModel(List<(T value, LocalisedString name)> values) : base([..values.Select(x => x.value)]) { - this.names = [.. values.Select(x => x.name)]; - } - - public override string DisplayString() => names[Index].ToString(); - -} diff --git a/Menu/LocalisedTextButton.cs b/Menu/LocalisedTextButton.cs deleted file mode 100644 index ff590cf..0000000 --- a/Menu/LocalisedTextButton.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Silksong.ModMenu.Elements; -using TeamCherry.Localization; - -namespace VVVVVV.Menu; - -internal class LocalisedTextButton : TextButton { - - private LocalisedString localisedText; - - public LocalisedTextButton(LocalisedString text) : base(text.ToString()) { - localisedText = text; - Container.name = $"{text.Key}"; - var updater = Container.AddComponentIfNotPresent(); - updater.OnLanguageChanged += UpdateLocalisation; - } - - private void UpdateLocalisation() { - ButtonText.text = localisedText.ToString(); - } - -} diff --git a/Menu/OnLanguageUpdatedHelper.cs b/Menu/OnLanguageUpdatedHelper.cs deleted file mode 100644 index de99155..0000000 --- a/Menu/OnLanguageUpdatedHelper.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using TeamCherry.Localization; -using UnityEngine; - -namespace VVVVVV.Menu; - -internal class OnLanguageUpdatedHelper : MonoBehaviour { - - private LanguageCode? prevLang; - public event Action? OnLanguageChanged; - - public void Update() { - if (prevLang == null || prevLang != Language._currentLanguage) { - prevLang = Language._currentLanguage; - OnLanguageChanged?.Invoke(); - } - } - -} diff --git a/Patches/ModMenuPatch.cs b/Patches/ModMenuPatch.cs new file mode 100644 index 0000000..d7c69de --- /dev/null +++ b/Patches/ModMenuPatch.cs @@ -0,0 +1,55 @@ +using HarmonyLib; +using Silksong.ModMenu.Elements; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; +using UnityEngine; + +namespace VVVVVV.Patches; + +/* +If you are reading this, DO NOT copy this because it's wicked fragile and incredibly cursed. + +Without this patch, MenuMod v0.4.1 is throwing an NRE because the component being +added immediately OnEnable's and attempts to access a member of its 'textField' member +before that actually is set to anything. + +I need to investigate and figure out if that's somehow my fault or not. +And then file a bug report if it's not me. And then remove this patch. +*/ +[HarmonyPatch(typeof(LocalizedTextExtensions), nameof(LocalizedTextExtensions.set_LocalizedText))] +internal static class ModMenuPatch { + + private static IEnumerable Transpiler(IEnumerable instructions) + => new CodeMatcher(instructions) + + // component = self.gameObject.AddComponent(); + .MatchStartForward([ + new(x => x.opcode == OpCodes.Callvirt && x.operand is MethodInfo m && m.Name == "AddComponent"), + ]) + .Insert([ + Transpilers.EmitDelegate(DeactivateAndReturnGO) + ]) + + // component.textField = self; + .MatchStartForward([ + new(x => x.opcode == OpCodes.Stfld && x.operand is FieldInfo f && f.Name == "textField"), + ]) + .Advance(1) + .Insert([ + new(OpCodes.Ldarg_0), + new(OpCodes.Callvirt, typeof(Component).GetMethod("get_gameObject")), + Transpilers.EmitDelegate(ActivateAndConsumeGO), + ]) + + .InstructionEnumeration(); + + static GameObject DeactivateAndReturnGO(GameObject go) { + go.SetActive(false); + return go; + } + + static void ActivateAndConsumeGO(GameObject go) + => go.SetActive(true); + +} diff --git a/Settings/FaydownState.cs b/Settings/FaydownState.cs index 6203424..4c2832d 100644 --- a/Settings/FaydownState.cs +++ b/Settings/FaydownState.cs @@ -1,6 +1,6 @@ -using System; +using Silksong.ModMenu.Models; +using System; using System.Linq; -using VVVVVV.Menu; using VVVVVV.Utils; namespace VVVVVV.Settings; @@ -15,17 +15,11 @@ internal static class FaydownStateExt { public static bool FlipsGravity(this FaydownState state) => state == FaydownState.FlipGravity; - public static bool DoubleJumps(this FaydownState state) - => state == FaydownState.DoubleJump; - public static bool IsDisabled(this FaydownState state) - => state == FaydownState.Disabled; - - public static LocalisedListChoiceModel LocalisedChoiceModel() - => new([ - .. Enum.GetValues(typeof(FaydownState)) - .Cast() - .Select(x => (x, LangUtil.String(x.MenuLangKey()))), - ]); + + public static ListChoiceModel LocalisedChoiceModel() + => new([.. Enum.GetValues(typeof(FaydownState)).Cast()]) { + DisplayFn = (int _, FaydownState val) => LangUtil.String(val.MenuLangKey()) + }; public static string MenuLangKey(this FaydownState state) => state.LangKey("MENU_FLIPDOWN"); diff --git a/Settings/ModSettings.cs b/Settings/ModSettings.cs index 29952a4..28ee611 100644 --- a/Settings/ModSettings.cs +++ b/Settings/ModSettings.cs @@ -2,9 +2,7 @@ using Silksong.ModMenu.Elements; using Silksong.ModMenu.Plugin; using Silksong.ModMenu.Screens; -using System.Collections.Generic; using UnityEngine; -using VVVVVV.Menu; using VVVVVV.Utils; namespace VVVVVV.Settings; @@ -18,49 +16,26 @@ internal class ModSettings : IModMenuCustomMenu { public FaydownState FaydownState => faydownState?.Value ?? FAYDOWN_STATE_DEFAULT; private ConfigEntry? faydownState; - private LocalisedChoiceElement? faydownOption; + private ChoiceElement? faydownOption; public KeyCode RespawnKey => respawnKey?.Value ?? RESPAWN_KEY_DEFAULT; private ConfigEntry? respawnKey; - private LocalisedChoiceElement? respawnKeyOption; - private static readonly List bindableKeys = [ - KeyCode.None, - KeyCode.F3, - KeyCode.F4, - KeyCode.F5, - KeyCode.F6, - KeyCode.F7, - KeyCode.F8, - KeyCode.F9, - KeyCode.F10, - KeyCode.Backspace, - KeyCode.Tab, - KeyCode.Backslash, - KeyCode.Slash, - KeyCode.LeftAlt, - KeyCode.RightAlt, - ]; + private KeyBindElement? respawnKeyOption; public void BindConfigEntries() { respawnKey = Config.Bind("", "RespawnKeybind", RESPAWN_KEY_DEFAULT); - if (!bindableKeys.Contains(respawnKey.Value)) - respawnKey.Value = KeyCode.None; - faydownState = Config.Bind("", "FayfornsGift", FAYDOWN_STATE_DEFAULT); } public string ModMenuName() => V6Plugin.Name; public AbstractMenuScreen BuildCustomMenu() { - LocalisedTextButton respawnBtn = new(LangUtil.String("MENU_RESPAWN_BUTTON")) { - OnSubmit = V6Plugin.QueueRespawnHero - }; + // This does nothing when you press the button, now. It used to work on ModMenu 0.2.0... + //TextButton respawnBtn = new(LangUtil.String("MENU_RESPAWN_BUTTON")) { + // OnSubmit = V6Plugin.QueueRespawnHero + //}; - respawnKeyOption = new( - LangUtil.String("MENU_RESPAWN_KEY_LABEL"), - bindableKeys, - LangUtil.String("MENU_RESPAWN_KEY_DESC") - ); + respawnKeyOption = new(LangUtil.String("MENU_RESPAWN_KEY_LABEL")); SyncEntryAndElement(respawnKey!, respawnKeyOption); faydownOption = new( @@ -71,7 +46,15 @@ public AbstractMenuScreen BuildCustomMenu() { SyncEntryAndElement(faydownState!, faydownOption); SimpleMenuScreen screen = new(ModMenuName()); - screen.AddRange([respawnBtn, respawnKeyOption, faydownOption]); + MenuElement[] elements = [ + //respawnBtn, + respawnKeyOption, + faydownOption, + ]; + screen.AddRange(elements); + // genuinely do not have a clue why this is needed, but it is + foreach(var elt in elements) + elt.Container.transform.SetParent(screen.Container.transform, false); return screen; } diff --git a/V6Plugin.cs b/V6Plugin.cs index 9ac98e7..69d8ae8 100644 --- a/V6Plugin.cs +++ b/V6Plugin.cs @@ -11,8 +11,8 @@ namespace VVVVVV; [BepInAutoPlugin(id: "io.github.kaycodes13.vvvvvv")] -[BepInDependency("org.silksong-modding.fsmutil", "0.3.12")] -[BepInDependency("org.silksong-modding.modmenu", "0.2.0")] +[BepInDependency("org.silksong-modding.fsmutil", "0.3.13")] +[BepInDependency("org.silksong-modding.modmenu", "0.4.1")] [BepInDependency("org.silksong-modding.i18n", "0.1.0")] public partial class V6Plugin : BaseUnityPlugin, IModMenuCustomMenu { diff --git a/VVVVVV.csproj b/VVVVVV.csproj index adca69b..cda54df 100644 --- a/VVVVVV.csproj +++ b/VVVVVV.csproj @@ -36,7 +36,7 @@ - + diff --git a/packages.lock.json b/packages.lock.json index 91bca68..c7f62ba 100644 --- a/packages.lock.json +++ b/packages.lock.json @@ -65,9 +65,9 @@ }, "Silksong.ModMenu": { "type": "Direct", - "requested": "[0.2.0, )", - "resolved": "0.2.0", - "contentHash": "4DPSOVaF7mZoHPyfF+hqI0BCm+OAZJpj9566ZwE93YmUZADf/6OlmI1jGY3/mHkRFrshwUpVdhE8okPZ06hpUQ==", + "requested": "[0.4.1, )", + "resolved": "0.4.1", + "contentHash": "eN1/ow8EREYoP/IggMZ0GQCOX3hCxL9RHLmWLwhrDrFdP/tHRiW0RYROwZ3hp9NiSnrqYtcYv+UcMBoavUO3Ag==", "dependencies": { "BepInEx.Core": "5.4.21", "HarmonyX": "2.9.0", diff --git a/thunderstore/thunderstore.toml b/thunderstore/thunderstore.toml index fbfde59..f807c9e 100644 --- a/thunderstore/thunderstore.toml +++ b/thunderstore/thunderstore.toml @@ -15,8 +15,8 @@ containsNsfwContent = false # dependencies are specified in the format AuthorName-PackageName = "version". You should always have at least BepInExPack_Silksong. [package.dependencies] BepInEx-BepInExPack_Silksong = "5.4.2304" -silksong_modding-FsmUtil = "0.3.12" -silksong_modding-ModMenu = "0.2.0" +silksong_modding-FsmUtil = "0.3.13" +silksong_modding-ModMenu = "0.4.1" silksong_modding-I18N = "0.1.0"