diff --git a/Silksong.ModMenu/Elements/TextInput.cs b/Silksong.ModMenu/Elements/TextInput.cs index 91dede6..d0910ec 100644 --- a/Silksong.ModMenu/Elements/TextInput.cs +++ b/Silksong.ModMenu/Elements/TextInput.cs @@ -24,6 +24,14 @@ public class TextInput : SelectableValueElement typeof(ulong), ]; private static readonly HashSet floatTypes = [typeof(float), typeof(double)]; + private static readonly HashSet floatListTypes = + [ + typeof(Vector2), + typeof(Vector3), + typeof(Vector4), + typeof(Quaternion), + typeof(Rect), + ]; /// /// Construct a basic text input. @@ -48,6 +56,14 @@ public TextInput(LocalizedText label, ITextModel model, LocalizedText descrip InputField.contentType = InputField.ContentType.IntegerNumber; else if (floatTypes.Contains(typeof(T))) InputField.contentType = InputField.ContentType.DecimalNumber; + else if (floatListTypes.Contains(typeof(T))) + { + InputField.contentType = InputField.ContentType.Custom; + InputField.onValidateInput = FloatListValidation; + ApplyDefaultColors = true; + OnTextValueChanged += _ => + State = TextModel.IsTextValid ? ElementState.DEFAULT : ElementState.INVALID; + } } /// @@ -100,4 +116,31 @@ public override void SetFontSizes(FontSizes fontSizes) DescriptionText.fontSize = fontSizes.DescriptionSize(); InputField.textComponent.fontSize = fontSizes.ChoiceSize(); } + + /// + /// validation for comma-delimited lists + /// of float values, with or without enclosing brackets. + /// + static char FloatListValidation(string input, int pos, char ch) + { + int leftPos = input.IndexOf('('), + rightPos = input.IndexOf(')'); + + // Everything must go within the brackets, if they're present + if (leftPos >= pos || (rightPos < pos && rightPos >= 0)) + return '\0'; + + if ( + // Brackets must be unique and positioned on the appropriate end of the string + (ch == '(' && leftPos == -1 && pos == 0) + || (ch == ')' && rightPos == -1 && pos == input.Length) + // Other valid characters + || char.IsDigit(ch) + || char.IsWhiteSpace(ch) + || ",.-".Contains(ch) + ) + return ch; + + return '\0'; + } } diff --git a/Silksong.ModMenu/Generator/RGBElementFactory.cs b/Silksong.ModMenu/Generator/RGBElementFactory.cs new file mode 100644 index 0000000..9967608 --- /dev/null +++ b/Silksong.ModMenu/Generator/RGBElementFactory.cs @@ -0,0 +1,14 @@ +using Silksong.ModMenu.Elements; +using UnityEngine; + +namespace Silksong.ModMenu.Generator; + +/// +/// Generator for a element which only accepts RGB values with full alpha. +/// +public class RGBElementFactory : IElementFactory +{ + /// + public ColorInput CreateElement(LocalizedText name, LocalizedText description) => + new(name, description) { Format = ColorInput.InputFormat.RGB }; +} diff --git a/Silksong.ModMenu/Internal/MenuPrefabs.cs b/Silksong.ModMenu/Internal/MenuPrefabs.cs index 23dd401..cfc6efb 100644 --- a/Silksong.ModMenu/Internal/MenuPrefabs.cs +++ b/Silksong.ModMenu/Internal/MenuPrefabs.cs @@ -151,6 +151,12 @@ private MenuPrefabs(UIManager uiManager) textInputChild.FindChild("CursorRight")!.GetComponent(), ]; + GameObject underlineObj = new("Underline") { layer = (int)PhysLayers.UI }; + underlineObj.transform.SetParentReset(textInputField.textComponent.transform); + underlineObj.AddComponent(); + underlineObj.RectTransform.FitToParentHorizontal(anchorY: 0); + underlineObj.RectTransform.sizeDelta = new Vector2(0, 3); + sliderTemplate = Object.Instantiate( canvas.FindChild("AudioMenuScreen/Content/MasterVolume")! ); diff --git a/Silksong.ModMenu/Models/TextModels.cs b/Silksong.ModMenu/Models/TextModels.cs index 12733e1..40f5bdc 100644 --- a/Silksong.ModMenu/Models/TextModels.cs +++ b/Silksong.ModMenu/Models/TextModels.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Silksong.ModMenu.Internal; using UnityEngine; @@ -17,6 +18,8 @@ public static class TextModels public static ParserTextModel ForStrings() => new(DefaultUnparse, DefaultUnparse); + #region Numbers + /// /// An ITextModel which parses its input into a signed byte. /// @@ -172,6 +175,8 @@ public static ParserTextModel ForDoubles(double min, double max) return model; } + #endregion + private static bool DefaultUnparse(T value, out string text) { text = $"{value}"; @@ -193,6 +198,8 @@ bool Check(T value) return Check; } + #region Colors + /// /// An ITextModel which parses 3, 6, or 8 character hex strings to and from s. /// @@ -243,4 +250,149 @@ private static bool HexUnparser(Color c, out string x) x = "###"; return false; } + + #endregion + #region Vectors & Quaternions & Rects + + /// + /// An ITextModel which parses comma-delimited pairs of numbers to and from s. + /// + public static ParserTextModel ForVector2() => + new(Vector2Parser, Vector2Unparser, INVALID_VECTOR); + + /// + /// An ITextModel which parses comma-delimited trios of numbers to and from s. + /// + public static ParserTextModel ForVector3() => + new(Vector3Parser, Vector3Unparser, INVALID_VECTOR); + + /// + /// An ITextModel which parses comma-delimited quartets of numbers to and from s. + /// + public static ParserTextModel ForVector4() => + new(Vector4Parser, Vector4Unparser, INVALID_VECTOR); + + /// + /// An ITextModel which parses comma-delimited quartets of numbers to and from s. + /// + public static ParserTextModel ForQuaternion() => + new(QuaternionParser, QuaternionUnparser, INVALID_QUATERNION); + + /// + /// An ITextModel which parses comma-delimited quartets of numbers to and from s. + /// + public static ParserTextModel ForRect() => new(RectParser, RectUnparser, INVALID_RECT); + + private static readonly Vector4 INVALID_VECTOR = Vector4.positiveInfinity; + private static readonly Quaternion INVALID_QUATERNION = new( + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity + ); + private static readonly Rect INVALID_RECT = new( + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity, + float.PositiveInfinity + ); + + private static bool Vector2Parser(string x, out Vector2 v) + { + bool success = FloatListParser(x, out float[] c) && c.Length == 2; + v = success ? new(c[0], c[1]) : INVALID_VECTOR; + return success; + } + + private static bool Vector2Unparser(Vector2 v, out string x) + { + x = v.ToString("F2", CultureInfo.InvariantCulture.NumberFormat); + return true; + } + + private static bool Vector3Parser(string x, out Vector3 v) + { + bool success = FloatListParser(x, out float[] c) && c.Length == 3; + v = success ? new(c[0], c[1], c[2]) : INVALID_VECTOR; + return success; + } + + private static bool Vector3Unparser(Vector3 v, out string x) + { + x = v.ToString("F2", CultureInfo.InvariantCulture.NumberFormat); + return true; + } + + private static bool Vector4Parser(string x, out Vector4 v) + { + bool success = FloatListParser(x, out float[] c) && c.Length == 4; + v = success ? new(c[0], c[1], c[2], c[3]) : INVALID_VECTOR; + return success; + } + + private static bool Vector4Unparser(Vector4 v, out string x) + { + x = v.ToString("F2", CultureInfo.InvariantCulture.NumberFormat); + return true; + } + + private static bool QuaternionParser(string x, out Quaternion q) + { + bool success = FloatListParser(x, out float[] c) && c.Length == 4; + q = success ? new(c[0], c[1], c[2], c[3]) : INVALID_QUATERNION; + return success; + } + + private static bool QuaternionUnparser(Quaternion q, out string x) + { + x = q.ToString("F3", CultureInfo.InvariantCulture.NumberFormat); + return true; + } + + private static bool RectParser(string x, out Rect r) + { + bool success = FloatListParser(x, out float[] c) && c.Length == 4; + r = success ? new(c[0], c[1], c[2], c[3]) : INVALID_RECT; + return success; + } + + private static bool RectUnparser(Rect r, out string x) + { + const string format = "F2"; + var provider = CultureInfo.InvariantCulture.NumberFormat; + x = UnityString.Format( + "({0}, {1}, {2}, {3})", + r.x.ToString(format, provider), + r.y.ToString(format, provider), + r.width.ToString(format, provider), + r.height.ToString(format, provider) + ); + return true; + } + + /// + /// Parses strings of the format "(-0.0, -0.0, ... , -0.0)" with or without brackets + /// into an array of floats. + /// + private static bool FloatListParser(string x, out float[] results) + { + x = x.Trim(); + if (x[0] == '(') + x = x[1..]; + if (x[^1] == ')') + x = x[..^1]; + + string[] rawVals = x.Split(','); + results = new float[rawVals.Length]; + + NumberFormatInfo format = CultureInfo.InvariantCulture.NumberFormat; + + for (int i = 0; i < rawVals.Length; i++) + if (!float.TryParse(rawVals[i], NumberStyles.Float, format, out results[i])) + return false; + + return true; + } + + #endregion } diff --git a/Silksong.ModMenu/Plugin/ConfigEntryFactory.cs b/Silksong.ModMenu/Plugin/ConfigEntryFactory.cs index 143c257..b0c58fd 100644 --- a/Silksong.ModMenu/Plugin/ConfigEntryFactory.cs +++ b/Silksong.ModMenu/Plugin/ConfigEntryFactory.cs @@ -45,6 +45,11 @@ public delegate bool MenuElementGenerator( GenerateDoubleElement, GenerateStringElement, GenerateColorElement, + GenerateVector2Element, + GenerateVector3Element, + GenerateVector4Element, + GenerateQuaternionElement, + GenerateRectElement, ]; /// @@ -388,26 +393,14 @@ public static bool GenerateBoolElement( public static bool GenerateSByteElement( ConfigEntryBase entry, [MaybeNullWhen(false)] out MenuElement menuElement - ) - { - if (entry is not ConfigEntry sByteEntry) - { - menuElement = default; - return false; - } - - var acceptableValues = entry.Description.AcceptableValues; - var model = - (acceptableValues is AcceptableValueRange range) - ? TextModels.ForSignedBytes(range.MinValue, range.MaxValue) - : TextModels.ForSignedBytes(); - - TextInput text = new(entry.LabelName(), model, entry.DescriptionLine()); - text.SynchronizeWith(sByteEntry); - - menuElement = text; - return true; - } + ) => + GenerateTextInput( + (entry.Description.AcceptableValues is AcceptableValueRange range) + ? () => TextModels.ForSignedBytes(range.MinValue, range.MaxValue) + : TextModels.ForSignedBytes, + entry, + out menuElement + ); /// /// Generates a menu element for a config setting with a free or ranged byte value. @@ -415,26 +408,14 @@ public static bool GenerateSByteElement( public static bool GenerateByteElement( ConfigEntryBase entry, [MaybeNullWhen(false)] out MenuElement menuElement - ) - { - if (entry is not ConfigEntry byteEntry) - { - menuElement = default; - return false; - } - - var acceptableValues = entry.Description.AcceptableValues; - var model = - (acceptableValues is AcceptableValueRange range) - ? TextModels.ForBytes(range.MinValue, range.MaxValue) - : TextModels.ForBytes(); - - TextInput text = new(entry.LabelName(), model, entry.DescriptionLine()); - text.SynchronizeWith(byteEntry); - - menuElement = text; - return true; - } + ) => + GenerateTextInput( + (entry.Description.AcceptableValues is AcceptableValueRange range) + ? () => TextModels.ForBytes(range.MinValue, range.MaxValue) + : TextModels.ForBytes, + entry, + out menuElement + ); /// /// Generates a menu element for a config setting with a free or ranged short value. @@ -442,26 +423,14 @@ public static bool GenerateByteElement( public static bool GenerateShortElement( ConfigEntryBase entry, [MaybeNullWhen(false)] out MenuElement menuElement - ) - { - if (entry is not ConfigEntry shortEntry) - { - menuElement = default; - return false; - } - - var acceptableValues = entry.Description.AcceptableValues; - var model = - (acceptableValues is AcceptableValueRange range) - ? TextModels.ForShorts(range.MinValue, range.MaxValue) - : TextModels.ForShorts(); - - TextInput text = new(entry.LabelName(), model, entry.DescriptionLine()); - text.SynchronizeWith(shortEntry); - - menuElement = text; - return true; - } + ) => + GenerateTextInput( + (entry.Description.AcceptableValues is AcceptableValueRange range) + ? () => TextModels.ForShorts(range.MinValue, range.MaxValue) + : TextModels.ForShorts, + entry, + out menuElement + ); /// /// Generates a menu element for a config setting with a free or ranged unsigned short value. @@ -469,26 +438,14 @@ public static bool GenerateShortElement( public static bool GenerateUShortElement( ConfigEntryBase entry, [MaybeNullWhen(false)] out MenuElement menuElement - ) - { - if (entry is not ConfigEntry uShortEntry) - { - menuElement = default; - return false; - } - - var acceptableValues = entry.Description.AcceptableValues; - var model = - (acceptableValues is AcceptableValueRange range) - ? TextModels.ForUnsignedShorts(range.MinValue, range.MaxValue) - : TextModels.ForUnsignedShorts(); - - TextInput text = new(entry.LabelName(), model, entry.DescriptionLine()); - text.SynchronizeWith(uShortEntry); - - menuElement = text; - return true; - } + ) => + GenerateTextInput( + (entry.Description.AcceptableValues is AcceptableValueRange range) + ? () => TextModels.ForUnsignedShorts(range.MinValue, range.MaxValue) + : TextModels.ForUnsignedShorts, + entry, + out menuElement + ); /// /// Generates a menu element for a config setting with a free or ranged int value. @@ -496,26 +453,14 @@ public static bool GenerateUShortElement( public static bool GenerateIntElement( ConfigEntryBase entry, [MaybeNullWhen(false)] out MenuElement menuElement - ) - { - if (entry is not ConfigEntry intEntry) - { - menuElement = default; - return false; - } - - var acceptableValues = entry.Description.AcceptableValues; - var model = - (acceptableValues is AcceptableValueRange range) - ? TextModels.ForIntegers(range.MinValue, range.MaxValue) - : TextModels.ForIntegers(); - - TextInput text = new(entry.LabelName(), model, entry.DescriptionLine()); - text.SynchronizeWith(intEntry); - - menuElement = text; - return true; - } + ) => + GenerateTextInput( + (entry.Description.AcceptableValues is AcceptableValueRange range) + ? () => TextModels.ForIntegers(range.MinValue, range.MaxValue) + : TextModels.ForIntegers, + entry, + out menuElement + ); /// /// Generates a menu element for a config setting with a free or ranged unsigned int value. @@ -523,26 +468,14 @@ public static bool GenerateIntElement( public static bool GenerateUIntElement( ConfigEntryBase entry, [MaybeNullWhen(false)] out MenuElement menuElement - ) - { - if (entry is not ConfigEntry uIntEntry) - { - menuElement = default; - return false; - } - - var acceptableValues = entry.Description.AcceptableValues; - var model = - (acceptableValues is AcceptableValueRange range) - ? TextModels.ForUnsignedIntegers(range.MinValue, range.MaxValue) - : TextModels.ForUnsignedIntegers(); - - TextInput text = new(entry.LabelName(), model, entry.DescriptionLine()); - text.SynchronizeWith(uIntEntry); - - menuElement = text; - return true; - } + ) => + GenerateTextInput( + (entry.Description.AcceptableValues is AcceptableValueRange range) + ? () => TextModels.ForUnsignedIntegers(range.MinValue, range.MaxValue) + : TextModels.ForUnsignedIntegers, + entry, + out menuElement + ); /// /// Generates a menu element for a config setting with a free or ranged long value. @@ -550,26 +483,14 @@ public static bool GenerateUIntElement( public static bool GenerateLongElement( ConfigEntryBase entry, [MaybeNullWhen(false)] out MenuElement menuElement - ) - { - if (entry is not ConfigEntry longEntry) - { - menuElement = default; - return false; - } - - var acceptableValues = entry.Description.AcceptableValues; - var model = - (acceptableValues is AcceptableValueRange range) - ? TextModels.ForLongs(range.MinValue, range.MaxValue) - : TextModels.ForLongs(); - - TextInput text = new(entry.LabelName(), model, entry.DescriptionLine()); - text.SynchronizeWith(longEntry); - - menuElement = text; - return true; - } + ) => + GenerateTextInput( + (entry.Description.AcceptableValues is AcceptableValueRange range) + ? () => TextModels.ForLongs(range.MinValue, range.MaxValue) + : TextModels.ForLongs, + entry, + out menuElement + ); /// /// Generates a menu element for a config setting with a free or ranged unsigned long value. @@ -577,26 +498,14 @@ public static bool GenerateLongElement( public static bool GenerateULongElement( ConfigEntryBase entry, [MaybeNullWhen(false)] out MenuElement menuElement - ) - { - if (entry is not ConfigEntry uLongEntry) - { - menuElement = default; - return false; - } - - var acceptableValues = entry.Description.AcceptableValues; - var model = - (acceptableValues is AcceptableValueRange range) - ? TextModels.ForUnsignedLongs(range.MinValue, range.MaxValue) - : TextModels.ForUnsignedLongs(); - - TextInput text = new(entry.LabelName(), model, entry.DescriptionLine()); - text.SynchronizeWith(uLongEntry); - - menuElement = text; - return true; - } + ) => + GenerateTextInput( + (entry.Description.AcceptableValues is AcceptableValueRange range) + ? () => TextModels.ForUnsignedLongs(range.MinValue, range.MaxValue) + : TextModels.ForUnsignedLongs, + entry, + out menuElement + ); /// /// Generates a menu element for a config setting with a free or ranged float value. @@ -604,26 +513,14 @@ public static bool GenerateULongElement( public static bool GenerateFloatElement( ConfigEntryBase entry, [MaybeNullWhen(false)] out MenuElement menuElement - ) - { - if (entry is not ConfigEntry floatEntry) - { - menuElement = default; - return false; - } - - var acceptableValues = entry.Description.AcceptableValues; - var model = - (acceptableValues is AcceptableValueRange range) - ? TextModels.ForFloats(range.MinValue, range.MaxValue) - : TextModels.ForFloats(); - - TextInput text = new(entry.LabelName(), model, entry.DescriptionLine()); - text.SynchronizeWith(floatEntry); - - menuElement = text; - return true; - } + ) => + GenerateTextInput( + (entry.Description.AcceptableValues is AcceptableValueRange range) + ? () => TextModels.ForFloats(range.MinValue, range.MaxValue) + : TextModels.ForFloats, + entry, + out menuElement + ); /// /// Generates a menu element for a config setting with a free or ranged double value. @@ -631,26 +528,14 @@ public static bool GenerateFloatElement( public static bool GenerateDoubleElement( ConfigEntryBase entry, [MaybeNullWhen(false)] out MenuElement menuElement - ) - { - if (entry is not ConfigEntry doubleEntry) - { - menuElement = default; - return false; - } - - var acceptableValues = entry.Description.AcceptableValues; - var model = - (acceptableValues is AcceptableValueRange range) - ? TextModels.ForDoubles(range.MinValue, range.MaxValue) - : TextModels.ForDoubles(); - - TextInput text = new(entry.LabelName(), model, entry.DescriptionLine()); - text.SynchronizeWith(doubleEntry); - - menuElement = text; - return true; - } + ) => + GenerateTextInput( + (entry.Description.AcceptableValues is AcceptableValueRange range) + ? () => TextModels.ForDoubles(range.MinValue, range.MaxValue) + : TextModels.ForDoubles, + entry, + out menuElement + ); /// /// Generate a text element for an arbitrary string. @@ -658,24 +543,7 @@ public static bool GenerateDoubleElement( public static bool GenerateStringElement( ConfigEntryBase entry, [MaybeNullWhen(false)] out MenuElement menuElement - ) - { - if (entry is not ConfigEntry stringEntry) - { - menuElement = default; - return false; - } - - TextInput text = new( - entry.LabelName(), - TextModels.ForStrings(), - entry.DescriptionLine() - ); - text.SynchronizeWith(stringEntry); - - menuElement = text; - return true; - } + ) => GenerateTextInput(TextModels.ForStrings, entry, out menuElement); /// /// Generate a text element for a color. @@ -704,6 +572,67 @@ public static bool GenerateColorElement( return true; } + /// + /// Generate a text element for a Vector2. + /// + public static bool GenerateVector2Element( + ConfigEntryBase entry, + [MaybeNullWhen(false)] out MenuElement menuElement + ) => GenerateTextInput(TextModels.ForVector2, entry, out menuElement); + + /// + /// Generate a text element for a Vector3. + /// + public static bool GenerateVector3Element( + ConfigEntryBase entry, + [MaybeNullWhen(false)] out MenuElement menuElement + ) => GenerateTextInput(TextModels.ForVector3, entry, out menuElement); + + /// + /// Generate a text element for a Vector4. + /// + public static bool GenerateVector4Element( + ConfigEntryBase entry, + [MaybeNullWhen(false)] out MenuElement menuElement + ) => GenerateTextInput(TextModels.ForVector4, entry, out menuElement); + + /// + /// Generate a text element for a Quaternion. + /// + public static bool GenerateQuaternionElement( + ConfigEntryBase entry, + [MaybeNullWhen(false)] out MenuElement menuElement + ) => GenerateTextInput(TextModels.ForQuaternion, entry, out menuElement); + + /// + /// Generate a text element for a Rect. + /// + public static bool GenerateRectElement( + ConfigEntryBase entry, + [MaybeNullWhen(false)] out MenuElement menuElement + ) => GenerateTextInput(TextModels.ForRect, entry, out menuElement); + + /// + /// Generate a text element for a config setting with a value + /// and a model created by the given function. + /// + public static bool GenerateTextInput( + Func> model, + ConfigEntryBase entry, + [MaybeNullWhen(false)] out MenuElement menuElement + ) + { + if (entry is not ConfigEntry typedEntry) + { + menuElement = default; + return false; + } + TextInput input = new(entry.LabelName(), model(), entry.DescriptionLine()); + input.SynchronizeWith(typedEntry); + menuElement = input; + return true; + } + private record ElementTreeNode { public readonly List<(string path, MenuElement element)> Elements = []; diff --git a/Silksong.ModMenuAnalyzers/MenuProperty.cs b/Silksong.ModMenuAnalyzers/MenuProperty.cs index b892eae..2a43fcb 100644 --- a/Silksong.ModMenuAnalyzers/MenuProperty.cs +++ b/Silksong.ModMenuAnalyzers/MenuProperty.cs @@ -44,7 +44,16 @@ private ITypeSymbol DataType "Silksong.ModMenu.Models.ModMenuNameAttribute", }; - private static bool IsRelevant(KnownTypes knownTypes, AttributeData data) + private static readonly IReadOnlyDictionary UnityTypeFactories = new Dictionary() + { + { "UnityEngine.Vector2", "Silksong.ModMenu.Models.TextModels.ForVector2" }, + { "UnityEngine.Vector3", "Silksong.ModMenu.Models.TextModels.ForVector3" }, + { "UnityEngine.Vector4", "Silksong.ModMenu.Models.TextModels.ForVector4" }, + { "UnityEngine.Quaternion", "Silksong.ModMenu.Models.TextModels.ForQuaternion" }, + { "UnityEngine.Rect", "Silksong.ModMenu.Models.TextModels.ForRect" }, + }; + + private static bool IsRelevant(KnownTypes knownTypes, AttributeData data) { if (data.AttributeClass == null) return false; @@ -223,7 +232,8 @@ out var menuRangeAttr && !InitEnumType() && !InitColorType() && !InitTextType() - ) + && !InitUnityType() + ) { Diagnostics .UnsupportedType(DataType.ToDisplayString()) @@ -378,6 +388,19 @@ private bool InitTextType() return true; } + private bool InitUnityType() + { + string typeName = DataType.ToDisplayString(); + if (UnityTypeFactories.TryGetValue(typeName, out string factory)) + { + DefaultInitializer.Add( + $@"{Name} = new Silksong.ModMenu.Elements.TextInput<{typeName}>({DisplayName.MakeLiteral()}, {factory}(), {Description.MakeLiteral()});" + ); + return true; + } + return false; + } + internal string DefineProperty() { string type; diff --git a/Silksong.ModMenuTesting/Tests/GeneratorTest.cs b/Silksong.ModMenuTesting/Tests/GeneratorTest.cs index f551257..e305a41 100644 --- a/Silksong.ModMenuTesting/Tests/GeneratorTest.cs +++ b/Silksong.ModMenuTesting/Tests/GeneratorTest.cs @@ -52,6 +52,9 @@ public class GeneratedData public Color ColorValue = Color.red; + [ElementFactory] + public Color ColorRgbValue = Color.cyan; + [ModMenuName("Custom Bool Name")] public bool BoolValue; @@ -68,7 +71,13 @@ public int IntProperty } [ModMenuOptions(2, 3, 5, 7)] - public int PrimeInt; + public int PrimeInt = 2; + + public Vector2 Vector2Value = Vector2.zero; + public Vector3 Vector3Value = Vector3.zero; + public Vector4 Vector4Value = Vector4.zero; + public Quaternion QuaternionValue = Quaternion.identity; + public Rect RectValue = Rect.zero; [SubMenu] public SubMenuData SubMenu1 = new(); diff --git a/Silksong.ModMenuTesting/Tests/ModMenuAutoTestingPlugin.cs b/Silksong.ModMenuTesting/Tests/ModMenuAutoTestingPlugin.cs index 57112a3..1cf0b74 100644 --- a/Silksong.ModMenuTesting/Tests/ModMenuAutoTestingPlugin.cs +++ b/Silksong.ModMenuTesting/Tests/ModMenuAutoTestingPlugin.cs @@ -19,24 +19,25 @@ protected override void Setup(ConfigFile config) { config.Bind("Unity Types", "KeyCode Option", KeyCode.A); config.Bind("Unity Types", "Color Option", Color.green); - config.Bind("Unity Types", "Vector2 Option", Vector2.one); // not done - config.Bind("Unity Types", "Vector3 Option", Vector3.one); // not done - config.Bind("Unity Types", "Vector4 Option", Vector4.one); // not done - config.Bind("Unity Types", "Quaternion Option", Quaternion.identity); // not done + config.Bind("Unity Types", "Vector2 Option", Vector2.one); + config.Bind("Unity Types", "Vector3 Option", Vector3.one); + config.Bind("Unity Types", "Vector4 Option", Vector4.one); + config.Bind("Unity Types", "Quaternion Option", Quaternion.identity); + config.Bind("Unity Types", "Rect Option", Rect.zero); config.Bind("Value Types", "String Option", "value"); config.Bind("Value Types", "Enum Option", TestEnum.EnumOne); config.Bind("Value Types", "Bool Option", true); - config.Bind("Value Types", "Byte Option", (byte)0); // not done - config.Bind("Value Types", "SByte Option", (sbyte)0); // not done - config.Bind("Value Types", "Short Option", (short)0); // not done - config.Bind("Value Types", "UShort Option", (ushort)0); // not done + config.Bind("Value Types", "Byte Option", (byte)0); + config.Bind("Value Types", "SByte Option", (sbyte)0); + config.Bind("Value Types", "Short Option", (short)0); + config.Bind("Value Types", "UShort Option", (ushort)0); config.Bind("Value Types", "Int Option", 0); - config.Bind("Value Types", "UInt Option", 0u); // not done - config.Bind("Value Types", "Long Option", 0L); // not done - config.Bind("Value Types", "ULong Option", 0UL); // not done + config.Bind("Value Types", "UInt Option", 0u); + config.Bind("Value Types", "Long Option", 0L); + config.Bind("Value Types", "ULong Option", 0UL); config.Bind("Value Types", "Float Option", 0.0f); - config.Bind("Value Types", "Double Option", 0.0d); // not done - config.Bind("Value Types", "Decimal Option", 0.0m); // not done + config.Bind("Value Types", "Double Option", 0.0d); + config.Bind("Value Types", "Decimal Option", 0.0m); } }