diff --git a/Silksong.ModMenu/Directory.Build.props b/Silksong.ModMenu/Directory.Build.props index 38caff4..04fadb4 100644 --- a/Silksong.ModMenu/Directory.Build.props +++ b/Silksong.ModMenu/Directory.Build.props @@ -11,6 +11,6 @@ It should follow the format major.minor.patch (semantic versioning). If you publish your mod as a library to NuGet, this version will also be used as the package version. --> - 0.4.5 + 0.4.6 diff --git a/Silksong.ModMenu/Elements/FontSizeConstants.cs b/Silksong.ModMenu/Elements/FontSizeConstants.cs index 89567e3..f673995 100644 --- a/Silksong.ModMenu/Elements/FontSizeConstants.cs +++ b/Silksong.ModMenu/Elements/FontSizeConstants.cs @@ -35,17 +35,17 @@ public static int ChoiceSize(this FontSizes self) => /// /// Small font size for a choice description string. /// - public const int DESCRIPTION_SMALL = 4; + public const int DESCRIPTION_SMALL = 27; /// /// Standard font size for a choice description string. /// - public const int DESCRIPTION_MEDIUM = 6; + public const int DESCRIPTION_MEDIUM = 41; /// /// Large font size for a choice description string. /// - public const int DESCRIPTION_LARGE = 9; + public const int DESCRIPTION_LARGE = 55; /// /// Corresponding font size for a choice description string. @@ -72,7 +72,7 @@ public static int DescriptionSize(this FontSizes self) => /// /// Large font size for a basic label string. /// - public const int LABEL_LARGE = 68; + public const int LABEL_LARGE = 60; /// /// Corresponding font size for a basic label string. diff --git a/Silksong.ModMenu/Elements/MenuElement.cs b/Silksong.ModMenu/Elements/MenuElement.cs index 5f6e7b3..59d5cce 100644 --- a/Silksong.ModMenu/Elements/MenuElement.cs +++ b/Silksong.ModMenu/Elements/MenuElement.cs @@ -116,5 +116,6 @@ public void SetGameObjectParent(GameObject container) => Container.transform.SetParent(container.transform, false); /// - public void ClearGameObjectParent() => Container.transform.SetParent(null); + public void ClearGameObjectParent() => + Container.transform.SetParent(null, worldPositionStays: false); } diff --git a/Silksong.ModMenu/Internal/IndexedList.cs b/Silksong.ModMenu/Internal/IndexedList.cs index b2f9f4c..6f3d313 100644 --- a/Silksong.ModMenu/Internal/IndexedList.cs +++ b/Silksong.ModMenu/Internal/IndexedList.cs @@ -21,7 +21,7 @@ public T this[int index] if (index < 0 || index >= list.Count) throw new IndexOutOfRangeException($"{index} (Count: {list.Count})"); - if (lookup.TryGetValue(list[index], out var prev)) + if (lookup.TryGetValue(value, out var prev)) { if (prev == index) return; @@ -95,6 +95,7 @@ public bool TryRemoveAt(int index, [MaybeNullWhen(false)] out T item) item = list[index]; list.RemoveAt(index); + lookup.Remove(item); UpdateIndex(index); return true; } diff --git a/Silksong.ModMenu/Internal/MenuPrefabs.cs b/Silksong.ModMenu/Internal/MenuPrefabs.cs index a2712fc..d972177 100644 --- a/Silksong.ModMenu/Internal/MenuPrefabs.cs +++ b/Silksong.ModMenu/Internal/MenuPrefabs.cs @@ -44,14 +44,14 @@ private MenuPrefabs(UIManager uiManager) menuTemplate = Object.Instantiate(optionsScreen); menuTemplate.SetActive(false); menuTemplate.name = "ModMenuScreen"; - Object.Destroy(menuTemplate.GetComponent()); - Object.Destroy(menuTemplate.FindChild("Title")!.GetComponent()); + menuTemplate.RemoveComponent(); + menuTemplate.FindChild("Title")!.RemoveComponent(); Object.DontDestroyOnLoad(menuTemplate); emptyContentPane = menuTemplate.FindChild("Content")!; emptyContentPane.DestroyAllChildren(); - Object.Destroy(emptyContentPane.GetComponent()); - Object.Destroy(emptyContentPane.GetComponent()); + emptyContentPane.RemoveComponent(); + emptyContentPane.RemoveComponent(); Object.DontDestroyOnLoad(emptyContentPane); // MappableKey.OnEnable() breaks when instantiated outside the UIButtonSkins hierarchy. @@ -62,9 +62,9 @@ private MenuPrefabs(UIManager uiManager) ); } keyBindTemplate.SetActive(false); - Object.Destroy( - keyBindTemplate.FindChild("Input Button Text")!.GetComponent() - ); + keyBindTemplate + .FindChild("Input Button Text")! + .RemoveComponent(); Object.DontDestroyOnLoad(keyBindTemplate); textButtonTemplate = Object.Instantiate(optionsScreen.FindChild("Content/GameOptions")!); @@ -74,12 +74,16 @@ private MenuPrefabs(UIManager uiManager) var buttonChild = textButtonTemplate.FindChild("GameOptionsButton")!; buttonChild.name = "TextButton"; - Object.Destroy(buttonChild.GetComponent()); + // We have to remove this component as it's on a different GameObject to the Text, + // so it won't be removed by the LocalizedTextExtensions + buttonChild.RemoveComponent(); + buttonChild.FindChild("Menu Button Text")!.RemoveComponent(); textLabelTemplate = Object.Instantiate( optionsScreen.FindChild("Content/GameOptions/GameOptionsButton/Menu Button Text")! ); textLabelTemplate.SetActive(false); + textLabelTemplate.RemoveComponent(); textLabelTemplate.name = "TextLabel"; Object.DontDestroyOnLoad(textLabelTemplate); @@ -92,15 +96,17 @@ private MenuPrefabs(UIManager uiManager) var choiceChild = textChoiceTemplate.FindChild("CamShakePopupOption")!; choiceChild.name = "ValueChoice"; - Object.Destroy(choiceChild.GetComponent()); + choiceChild.RemoveComponent(); var moh = choiceChild.GetComponent(); moh.optionList = ["###INTERNAL###"]; moh.menuSetting = null; moh.localizeText = false; moh.applyButton = null; - Object.Destroy( - choiceChild.FindChild("Menu Option Label")!.GetComponent() - ); + choiceChild + .FindChild("Menu Option Label")! + .RemoveComponent(); + choiceChild.FindChild("Menu Option Text")!.RemoveComponent(); + choiceChild.FindChild("Description")!.RemoveComponent(); textInputTemplate = Object.Instantiate(textChoiceTemplate); textInputTemplate.SetActive(false); @@ -109,10 +115,10 @@ private MenuPrefabs(UIManager uiManager) var textInputChild = textInputTemplate.FindChild("ValueChoice")!; textInputChild.name = "TextInput"; - Object.Destroy(textInputChild.GetComponent()); - Object.Destroy(textInputChild.GetComponent()); + textInputChild.RemoveComponent(); + textInputChild.RemoveComponent(); Object.DestroyImmediate(textInputChild.GetComponent()); // We must delete the Selectable immediately to add a new one. - Object.Destroy(textInputChild.GetComponent()); + textInputChild.RemoveComponent(); var textInputField = textInputChild.AddComponent(); textInputField.textComponent = textInputChild .FindChild("Menu Option Text")! @@ -132,11 +138,11 @@ private MenuPrefabs(UIManager uiManager) var sliderChild = sliderTemplate.FindChild("MasterSlider")!; sliderChild.name = "Slider"; sliderChild.GetComponent().onValueChanged = new(); - Object.Destroy(sliderChild.GetComponent()); + sliderChild.RemoveComponent(); sliderChild.GetOrAddComponent(); - Object.Destroy( - sliderChild.FindChild("Menu Option Label")!.GetComponent() - ); + sliderChild + .FindChild("Menu Option Label")! + .RemoveComponent(); sliderChild.FindChild("MasterVolValue")!.name = "Value"; } diff --git a/Silksong.ModMenu/Silksong.ModMenu.csproj b/Silksong.ModMenu/Silksong.ModMenu.csproj index 2e9fbd8..efdf61c 100644 --- a/Silksong.ModMenu/Silksong.ModMenu.csproj +++ b/Silksong.ModMenu/Silksong.ModMenu.csproj @@ -41,7 +41,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/Silksong.ModMenuTesting/ModMenuTestingPlugin.cs b/Silksong.ModMenuTesting/ModMenuTestingPlugin.cs index 5017188..12a656c 100644 --- a/Silksong.ModMenuTesting/ModMenuTestingPlugin.cs +++ b/Silksong.ModMenuTesting/ModMenuTestingPlugin.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Reflection; using BepInEx; +using BepInEx.Logging; using Silksong.ModMenu.Elements; using Silksong.ModMenu.Plugin; using Silksong.ModMenu.Screens; @@ -12,9 +13,11 @@ namespace Silksong.ModMenuTesting; [BepInAutoPlugin(id: "org.silksong_modding.modmenutesting")] public partial class ModMenuTestingPlugin : BaseUnityPlugin, IModMenuCustomMenu { + internal static ManualLogSource InstanceLogger = null!; + private void Awake() { - // Put your initialization logic here + InstanceLogger = this.Logger; Logger.LogInfo($"Plugin {Name} ({Id}) has loaded!"); } diff --git a/Silksong.ModMenuTesting/Tests/ElementSizesTest.cs b/Silksong.ModMenuTesting/Tests/ElementSizesTest.cs new file mode 100644 index 0000000..df0358c --- /dev/null +++ b/Silksong.ModMenuTesting/Tests/ElementSizesTest.cs @@ -0,0 +1,34 @@ +using Silksong.ModMenu.Elements; +using Silksong.ModMenu.Screens; +using System.Collections.Generic; +using System.Linq; + +namespace Silksong.ModMenuTesting.Tests; + +internal class ElementSizesTest : ModMenuTest +{ + internal override string Name => "Element Sizes Test"; + + internal override AbstractMenuScreen BuildMenuScreen() + { + PaginatedMenuScreenBuilder builder = new(Name); + + TextButton makeSmall = new("Make Small"); + TextButton makeMedium = new("Make Medium"); + TextButton makeLarge = new("Make Large"); + + builder.Add(makeSmall); + builder.Add(makeMedium); + builder.Add(makeLarge); + + List elements = StandardElementsTest.CreateUnboundElements().ToList(); + + makeSmall.OnSubmit += () => elements.ForEach(x => x.SetFontSizes(FontSizes.Small)); + makeMedium.OnSubmit += () => elements.ForEach(x => x.SetFontSizes(FontSizes.Medium)); + makeLarge.OnSubmit += () => elements.ForEach(x => x.SetFontSizes(FontSizes.Large)); + + builder.AddRange(elements); + + return builder.Build(); + } +} diff --git a/Silksong.ModMenuTesting/Tests/StandardElementsTest.cs b/Silksong.ModMenuTesting/Tests/StandardElementsTest.cs new file mode 100644 index 0000000..9c8df1a --- /dev/null +++ b/Silksong.ModMenuTesting/Tests/StandardElementsTest.cs @@ -0,0 +1,68 @@ +using Silksong.ModMenu.Elements; +using Silksong.ModMenu.Models; +using Silksong.ModMenu.Screens; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Silksong.ModMenuTesting.Tests; + +internal class StandardElementsTest : ModMenuTest +{ + private static void Log(string message) => ModMenuTestingPlugin.InstanceLogger.LogInfo(message); + + internal override string Name => "Standard Elements"; + + /// + /// Yields common elements that log their value when changed. + /// + internal static IEnumerable CreateUnboundElements() + { + { + TextButton button = new("The Text Button"); + button.OnSubmit += () => Log($"Pressed text button"); + yield return button; + } + + { + IntSliderModel sliderModel = new(3, 8); + SliderElement intSliderElement = new("The Int Slider", sliderModel); + sliderModel.SetValue(6); + sliderModel.OnValueChanged += n => Log($"Int slider -> {n}"); + yield return intSliderElement; + } + + { + ListChoiceModel listChoiceModel = new(["First", "Second", "Third"]); + ChoiceElement choiceElement = new("The List Choice", listChoiceModel, "Here is where to choose option(s)"); + listChoiceModel.OnValueChanged += v => Log($"List choice -> {v}"); + yield return choiceElement; + } + + { + TextLabel label = new("The Label"); + // Commented out because this is bugged ATM + // yield return label; + } + + { + KeyBindElement keybindElement = new("The Keybind"); + keybindElement.Model.OnValueChanged += k => Log($"Keybind value -> {k}"); + yield return keybindElement; + } + + { + ITextModel textModel = TextModels.ForStrings(); + TextInput stringInput = new("The Text Input", textModel, "Here is where to input text"); + textModel.OnValueChanged += s => Log($"Text model -> {s}"); + yield return stringInput; + } + } + + internal override AbstractMenuScreen BuildMenuScreen() + { + PaginatedMenuScreenBuilder builder = new(Name); + builder.AddRange(CreateUnboundElements()); + return builder.Build(); + } +}