From c828d9b6424f624e33993ef005f50c8698221d70 Mon Sep 17 00:00:00 2001 From: Sinai Date: Sat, 8 May 2021 20:54:16 +1000 Subject: [PATCH] InteractiveValueStruct, and a few cleanups --- src/Core/Input/InputSystem.cs | 8 +- src/Core/Reflection/Il2CppReflection.cs | 9 +- src/Core/Reflection/ReflectionUtility.cs | 87 ++++----- src/Core/Runtime/Il2Cpp/Il2CppProvider.cs | 4 +- src/Core/Runtime/Mono/MonoTextureUtil.cs | 2 +- src/Core/Utility/ArgumentUtility.cs | 16 ++ src/Core/Utility/MiscUtility.cs | 4 +- src/UI/CacheObject/CacheMember.cs | 2 +- src/UI/CacheObject/CacheMethod.cs | 2 +- src/UI/CacheObject/CacheObjectBase.cs | 26 +-- src/UI/CacheObject/Views/EvaluateWidget.cs | 2 +- src/UI/IValues/InteractiveColor.cs | 19 +- src/UI/IValues/InteractiveList.cs | 2 + src/UI/IValues/InteractiveValue.cs | 4 +- src/UI/IValues/InteractiveValueStruct.cs | 213 +++++++++++++++++++++ src/UI/Utility/ToStringUtility.cs | 6 +- src/UnityExplorer.csproj | 2 + 17 files changed, 316 insertions(+), 92 deletions(-) create mode 100644 src/Core/Utility/ArgumentUtility.cs create mode 100644 src/UI/IValues/InteractiveValueStruct.cs diff --git a/src/Core/Input/InputSystem.cs b/src/Core/Input/InputSystem.cs index f961edb..aa9e99f 100644 --- a/src/Core/Input/InputSystem.cs +++ b/src/Core/Input/InputSystem.cs @@ -81,7 +81,7 @@ namespace UnityExplorer.Core.Input { try { - return (Vector2)ReadV2ControlMethod.Invoke(MousePositionInfo, new object[0]); + return (Vector2)ReadV2ControlMethod.Invoke(MousePositionInfo, ArgumentUtility.EmptyArgs); } catch { return Vector2.zero; } } @@ -93,7 +93,7 @@ namespace UnityExplorer.Core.Input { try { - return (Vector2)ReadV2ControlMethod.Invoke(MouseScrollInfo, new object[0]); + return (Vector2)ReadV2ControlMethod.Invoke(MouseScrollInfo, ArgumentUtility.EmptyArgs); } catch { return Vector2.zero; } } @@ -193,7 +193,7 @@ namespace UnityExplorer.Core.Input CreateAction(map, "scrollWheel", new[] { "/scroll" }, "scrollWheel"); UI_Enable = map.GetType().GetMethod("Enable"); - UI_Enable.Invoke(map, new object[0]); + UI_Enable.Invoke(map, ArgumentUtility.EmptyArgs); UI_ActionMap = map; } @@ -227,7 +227,7 @@ namespace UnityExplorer.Core.Input public void ActivateModule() { m_newInputModule.ActivateModule(); - UI_Enable.Invoke(UI_ActionMap, new object[0]); + UI_Enable.Invoke(UI_ActionMap, ArgumentUtility.EmptyArgs); } } } \ No newline at end of file diff --git a/src/Core/Reflection/Il2CppReflection.cs b/src/Core/Reflection/Il2CppReflection.cs index 808ed40..f5ceaf6 100644 --- a/src/Core/Reflection/Il2CppReflection.cs +++ b/src/Core/Reflection/Il2CppReflection.cs @@ -282,7 +282,7 @@ namespace UnityExplorer .MakeGenericMethod(toType)); } - return unboxMethods[name].Invoke(cppObj, new object[0]); + return unboxMethods[name].Invoke(cppObj, ArgumentUtility.EmptyArgs); } catch (Exception ex) { @@ -291,13 +291,10 @@ namespace UnityExplorer } } - private static readonly Type[] emptyTypes = new Type[0]; - private static readonly object[] emptyArgs = new object[0]; - private static Il2CppSystem.Object BoxIl2CppObject(object cppStruct, Type structType) { - return GetMethodInfo(structType, "BoxIl2CppObject", emptyTypes) - .Invoke(cppStruct, emptyArgs) + return GetMethodInfo(structType, "BoxIl2CppObject", ArgumentUtility.EmptyTypes) + .Invoke(cppStruct, ArgumentUtility.EmptyArgs) as Il2CppSystem.Object; } diff --git a/src/Core/Reflection/ReflectionUtility.cs b/src/Core/Reflection/ReflectionUtility.cs index 1696430..8fa336c 100644 --- a/src/Core/Reflection/ReflectionUtility.cs +++ b/src/Core/Reflection/ReflectionUtility.cs @@ -67,13 +67,13 @@ namespace UnityExplorer allTypeNames.Add(type.FullName); } - foreach (var key in s_cachedTypeInheritance.Keys) + foreach (var key in typeInheritance.Keys) { try { var baseType = AllTypes[key]; - if (baseType.IsAssignableFrom(type) && !s_cachedTypeInheritance[key].Contains(type)) - s_cachedTypeInheritance[key].Add(type); + if (baseType.IsAssignableFrom(type) && !typeInheritance[key].Contains(type)) + typeInheritance[key].Add(type); } catch { } } @@ -145,7 +145,7 @@ namespace UnityExplorer #region Type inheritance cache // cache for GetBaseTypes - internal static readonly Dictionary s_cachedBaseTypes = new Dictionary(); + internal static readonly Dictionary baseTypes = new Dictionary(); /// /// Get all base types of the provided Type, including itself. @@ -162,7 +162,7 @@ namespace UnityExplorer var name = type.AssemblyQualifiedName; - if (s_cachedBaseTypes.TryGetValue(name, out Type[] ret)) + if (baseTypes.TryGetValue(name, out Type[] ret)) return ret; List list = new List(); @@ -175,7 +175,7 @@ namespace UnityExplorer ret = list.ToArray(); - s_cachedBaseTypes.Add(name, ret); + baseTypes.Add(name, ret); return ret; } @@ -186,8 +186,8 @@ namespace UnityExplorer #region Type and Generic Parameter implementation cache // cache for GetImplementationsOf - internal static readonly Dictionary> s_cachedTypeInheritance = new Dictionary>(); - internal static readonly Dictionary> s_cachedGenericParameterInheritance = new Dictionary>(); + internal static readonly Dictionary> typeInheritance = new Dictionary>(); + internal static readonly Dictionary> genericParameterInheritance = new Dictionary>(); public static string GetImplementationKey(Type type) { @@ -222,7 +222,7 @@ namespace UnityExplorer private static HashSet GetImplementations(string key, Type baseType, bool allowAbstract, bool allowGeneric) { - if (!s_cachedTypeInheritance.ContainsKey(key)) + if (!typeInheritance.ContainsKey(key)) { var set = new HashSet(); for (int i = 0; i < allTypeNames.Count; i++) @@ -250,15 +250,15 @@ namespace UnityExplorer //set. - s_cachedTypeInheritance.Add(key, set); + typeInheritance.Add(key, set); } - return s_cachedTypeInheritance[key]; + return typeInheritance[key]; } private static HashSet GetGenericParameterImplementations(string key, Type baseType, bool allowAbstract, bool allowGeneric) { - if (!s_cachedGenericParameterInheritance.ContainsKey(key)) + if (!genericParameterInheritance.ContainsKey(key)) { var set = new HashSet(); @@ -294,10 +294,10 @@ namespace UnityExplorer catch { } } - s_cachedGenericParameterInheritance.Add(key, set); + genericParameterInheritance.Add(key, set); } - return s_cachedGenericParameterInheritance[key]; + return genericParameterInheritance[key]; } #endregion @@ -305,64 +305,65 @@ namespace UnityExplorer #region Internal MemberInfo Cache - internal static Dictionary> s_cachedFieldInfos = new Dictionary>(); + internal static Dictionary> fieldInfos = new Dictionary>(); public static FieldInfo GetFieldInfo(Type type, string fieldName) { - if (!s_cachedFieldInfos.ContainsKey(type)) - s_cachedFieldInfos.Add(type, new Dictionary()); + if (!fieldInfos.ContainsKey(type)) + fieldInfos.Add(type, new Dictionary()); - if (!s_cachedFieldInfos[type].ContainsKey(fieldName)) - s_cachedFieldInfos[type].Add(fieldName, type.GetField(fieldName, FLAGS)); + if (!fieldInfos[type].ContainsKey(fieldName)) + fieldInfos[type].Add(fieldName, type.GetField(fieldName, FLAGS)); - return s_cachedFieldInfos[type][fieldName]; + return fieldInfos[type][fieldName]; } - internal static Dictionary> s_cachedPropInfos = new Dictionary>(); + internal static Dictionary> propertyInfos = new Dictionary>(); public static PropertyInfo GetPropertyInfo(Type type, string propertyName) { - if (!s_cachedPropInfos.ContainsKey(type)) - s_cachedPropInfos.Add(type, new Dictionary()); + if (!propertyInfos.ContainsKey(type)) + propertyInfos.Add(type, new Dictionary()); - if (!s_cachedPropInfos[type].ContainsKey(propertyName)) - s_cachedPropInfos[type].Add(propertyName, type.GetProperty(propertyName, FLAGS)); + if (!propertyInfos[type].ContainsKey(propertyName)) + propertyInfos[type].Add(propertyName, type.GetProperty(propertyName, FLAGS)); - return s_cachedPropInfos[type][propertyName]; + return propertyInfos[type][propertyName]; } - internal static Dictionary> s_cachedMethodInfos = new Dictionary>(); + internal static Dictionary> methodInfos = new Dictionary>(); - public static MethodInfo GetMethodInfo(Type type, string methodName, Type[] argumentTypes) + public static MethodInfo GetMethodInfo(Type type, string methodName) + => GetMethodInfo(type, methodName, ArgumentUtility.EmptyTypes, false); + + public static MethodInfo GetMethodInfo(Type type, string methodName, Type[] argumentTypes, bool cacheAmbiguous = false) { - if (!s_cachedMethodInfos.ContainsKey(type)) - s_cachedMethodInfos.Add(type, new Dictionary()); + if (!methodInfos.ContainsKey(type)) + methodInfos.Add(type, new Dictionary()); var sig = methodName; - if (argumentTypes != null) + // If the signature could be ambiguous (internally, within UnityExplorer's own use) + // then append the arguments to the key. + // Currently not needed and not used, but just in case I need it one day. + if (cacheAmbiguous) { - sig += "("; - for (int i = 0; i < argumentTypes.Length; i++) - { - if (i > 0) - sig += ","; - sig += argumentTypes[i].FullName; - } - sig += ")"; + sig += "|"; + foreach (var arg in argumentTypes) + sig += arg.FullName + ","; } try { - if (!s_cachedMethodInfos[type].ContainsKey(sig)) + if (!methodInfos[type].ContainsKey(sig)) { if (argumentTypes != null) - s_cachedMethodInfos[type].Add(sig, type.GetMethod(methodName, FLAGS, null, argumentTypes, null)); + methodInfos[type].Add(sig, type.GetMethod(methodName, FLAGS, null, argumentTypes, null)); else - s_cachedMethodInfos[type].Add(sig, type.GetMethod(methodName, FLAGS)); + methodInfos[type].Add(sig, type.GetMethod(methodName, FLAGS)); } - return s_cachedMethodInfos[type][sig]; + return methodInfos[type][sig]; } catch (AmbiguousMatchException) { diff --git a/src/Core/Runtime/Il2Cpp/Il2CppProvider.cs b/src/Core/Runtime/Il2Cpp/Il2CppProvider.cs index e2d6df3..34f88bc 100644 --- a/src/Core/Runtime/Il2Cpp/Il2CppProvider.cs +++ b/src/Core/Runtime/Il2Cpp/Il2CppProvider.cs @@ -233,8 +233,8 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp ReflectionUtility.GetPropertyInfo(typeof(Selectable), "m_Colors") .SetValue(selectable, _colorBlock, null); - ReflectionUtility.GetMethodInfo(typeof(Selectable), "OnSetProperty", new Type[0]) - .Invoke(selectable, new object[0]); + ReflectionUtility.GetMethodInfo(typeof(Selectable), "OnSetProperty") + .Invoke(selectable, ArgumentUtility.EmptyArgs); } catch (Exception ex) { diff --git a/src/Core/Runtime/Mono/MonoTextureUtil.cs b/src/Core/Runtime/Mono/MonoTextureUtil.cs index 3a0a5a7..f04da58 100644 --- a/src/Core/Runtime/Mono/MonoTextureUtil.cs +++ b/src/Core/Runtime/Mono/MonoTextureUtil.cs @@ -46,7 +46,7 @@ namespace UnityExplorer.Core.Runtime.Mono if (method.IsStatic) return (byte[])method.Invoke(null, new object[] { tex }); else - return (byte[])method.Invoke(tex, new object[0]); + return (byte[])method.Invoke(tex, ArgumentUtility.EmptyArgs); } private static MethodInfo GetEncodeToPNGMethod() diff --git a/src/Core/Utility/ArgumentUtility.cs b/src/Core/Utility/ArgumentUtility.cs new file mode 100644 index 0000000..da85a5e --- /dev/null +++ b/src/Core/Utility/ArgumentUtility.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace UnityExplorer +{ + public static class ArgumentUtility + { + public static readonly Type[] EmptyTypes = new Type[0]; + public static readonly object[] EmptyArgs = new object[0]; + + public static readonly Type[] ParseArgs = new Type[] { typeof(string) }; + } +} diff --git a/src/Core/Utility/MiscUtility.cs b/src/Core/Utility/MiscUtility.cs index 7d021b4..4a939fc 100644 --- a/src/Core/Utility/MiscUtility.cs +++ b/src/Core/Utility/MiscUtility.cs @@ -23,8 +23,8 @@ namespace UnityExplorer /// public static bool HasFlag(this Enum flags, Enum value) { - ulong num = Convert.ToUInt64(value); - return (Convert.ToUInt64(flags) & num) == num; + ulong flag = Convert.ToUInt64(value); + return (Convert.ToUInt64(flags) & flag) == flag; } } } diff --git a/src/UI/CacheObject/CacheMember.cs b/src/UI/CacheObject/CacheMember.cs index 605b86e..aadccf7 100644 --- a/src/UI/CacheObject/CacheMember.cs +++ b/src/UI/CacheObject/CacheMember.cs @@ -25,7 +25,7 @@ namespace UnityExplorer.UI.CacheObject public abstract bool IsStatic { get; } public override bool HasArguments => Arguments?.Length > 0 || GenericArguments.Length > 0; public ParameterInfo[] Arguments { get; protected set; } = new ParameterInfo[0]; - public Type[] GenericArguments { get; protected set; } = new Type[0]; + public Type[] GenericArguments { get; protected set; } = ArgumentUtility.EmptyTypes; public EvaluateWidget Evaluator { get; protected set; } public bool Evaluating => Evaluator != null && Evaluator.UIRoot.activeSelf; diff --git a/src/UI/CacheObject/CacheMethod.cs b/src/UI/CacheObject/CacheMethod.cs index 0d29c33..28771dd 100644 --- a/src/UI/CacheObject/CacheMethod.cs +++ b/src/UI/CacheObject/CacheMethod.cs @@ -37,7 +37,7 @@ namespace UnityExplorer.UI.CacheObject if (Arguments.Length > 0) return methodInfo.Invoke(DeclaringInstance, Evaluator.TryParseArguments()); - var ret = methodInfo.Invoke(DeclaringInstance, new object[0]); + var ret = methodInfo.Invoke(DeclaringInstance, ArgumentUtility.EmptyArgs); HadException = false; LastException = null; diff --git a/src/UI/CacheObject/CacheObjectBase.cs b/src/UI/CacheObject/CacheObjectBase.cs index beca89b..fecfc5a 100644 --- a/src/UI/CacheObject/CacheObjectBase.cs +++ b/src/UI/CacheObject/CacheObjectBase.cs @@ -60,7 +60,7 @@ namespace UnityExplorer.UI.CacheObject // internals - private static readonly Dictionary numberParseMethods = new Dictionary(); + // private static readonly Dictionary numberParseMethods = new Dictionary(); public ValueState State = ValueState.NotEvaluated; @@ -160,25 +160,18 @@ namespace UnityExplorer.UI.CacheObject { if (type == typeof(bool)) return ValueState.Boolean; - else if (type.IsPrimitive || type == typeof(decimal)) return ValueState.Number; - else if (type == typeof(string)) return ValueState.String; - else if (type.IsEnum) return ValueState.Enum; - else if (type == typeof(Color) || type == typeof(Color32)) return ValueState.Color; - - // else if (InteractiveValueStruct.SupportsType(type)) - // return ValueState.ValueStruct; - + else if (InteractiveValueStruct.SupportsType(type)) + return ValueState.ValueStruct; else if (typeof(IDictionary).IsAssignableFrom(type)) return ValueState.Dictionary; - else if (typeof(IEnumerable).IsAssignableFrom(type)) return ValueState.Collection; else @@ -341,6 +334,8 @@ namespace UnityExplorer.UI.CacheObject // CacheObjectCell Apply + // todo make this a reusable utility method + public virtual void OnCellApplyClicked() { if (State == ValueState.Boolean) @@ -349,14 +344,9 @@ namespace UnityExplorer.UI.CacheObject { try { - var type = Value.GetActualType(); - if (!numberParseMethods.ContainsKey(type.AssemblyQualifiedName)) - { - var method = type.GetMethod("Parse", new Type[] { typeof(string) }); - numberParseMethods.Add(type.AssemblyQualifiedName, method); - } - - var val = numberParseMethods[type.AssemblyQualifiedName] + var type = Value.GetType(); + + var val = ReflectionUtility.GetMethodInfo(type, "Parse", ArgumentUtility.ParseArgs) .Invoke(null, new object[] { CellView.InputField.Text }); SetUserValue(val); diff --git a/src/UI/CacheObject/Views/EvaluateWidget.cs b/src/UI/CacheObject/Views/EvaluateWidget.cs index 307591c..3e73b58 100644 --- a/src/UI/CacheObject/Views/EvaluateWidget.cs +++ b/src/UI/CacheObject/Views/EvaluateWidget.cs @@ -101,7 +101,7 @@ namespace UnityExplorer.UI.CacheObject.Views try { - var parse = ReflectionUtility.GetMethodInfo(type, "Parse", new Type[] { typeof(string) }); + var parse = ReflectionUtility.GetMethodInfo(type, "Parse", ArgumentUtility.ParseArgs); outArgs[i] = parse.Invoke(null, new object[] { input }); } catch (Exception ex) diff --git a/src/UI/IValues/InteractiveColor.cs b/src/UI/IValues/InteractiveColor.cs index 6b4b543..f6932fa 100644 --- a/src/UI/IValues/InteractiveColor.cs +++ b/src/UI/IValues/InteractiveColor.cs @@ -35,19 +35,12 @@ namespace UnityExplorer.UI.IValues input.InputField.readOnly = !owner.CanWrite; } + // owner setting value to this public override void SetValue(object value) { OnOwnerSetValue(value); } - public void SetValueToOwner() - { - if (IsValueColor32) - CurrentOwner.SetUserValue((Color32)EditedColor); - else - CurrentOwner.SetUserValue(EditedColor); - } - private void OnOwnerSetValue(object value) { if (value is Color32 c32) @@ -77,6 +70,16 @@ namespace UnityExplorer.UI.IValues m_colorImage.color = EditedColor; } + // setting value to owner + + public void SetValueToOwner() + { + if (IsValueColor32) + CurrentOwner.SetUserValue((Color32)EditedColor); + else + CurrentOwner.SetUserValue(EditedColor); + } + private void SetColorField(float val, int fieldIndex) { switch (fieldIndex) diff --git a/src/UI/IValues/InteractiveList.cs b/src/UI/IValues/InteractiveList.cs index b7c050e..a95a194 100644 --- a/src/UI/IValues/InteractiveList.cs +++ b/src/UI/IValues/InteractiveList.cs @@ -74,6 +74,8 @@ namespace UnityExplorer.UI.IValues var type = value.GetActualType(); if (type.IsGenericType) EntryType = type.GetGenericArguments()[0]; + else if (type.HasElementType) + EntryType = type.GetElementType(); else EntryType = typeof(object); diff --git a/src/UI/IValues/InteractiveValue.cs b/src/UI/IValues/InteractiveValue.cs index 61bd7c4..9891ba6 100644 --- a/src/UI/IValues/InteractiveValue.cs +++ b/src/UI/IValues/InteractiveValue.cs @@ -23,8 +23,8 @@ namespace UnityExplorer.UI.IValues return typeof(InteractiveList); case ValueState.Dictionary: return typeof(InteractiveDictionary); - //case ValueState.ValueStruct: - // return typeof(InteractiveValueStruct); + case ValueState.ValueStruct: + return typeof(InteractiveValueStruct); case ValueState.Color: return typeof(InteractiveColor); default: return null; diff --git a/src/UI/IValues/InteractiveValueStruct.cs b/src/UI/IValues/InteractiveValueStruct.cs new file mode 100644 index 0000000..555a27e --- /dev/null +++ b/src/UI/IValues/InteractiveValueStruct.cs @@ -0,0 +1,213 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using UnityEngine.UI; +using UnityExplorer.UI.CacheObject; +using UnityExplorer.UI.Utility; + +namespace UnityExplorer.UI.IValues +{ + public class InteractiveValueStruct : InteractiveValue + { + #region Struct cache / wrapper + + public class StructInfo + { + public bool IsSupported; + public FieldInfo[] Fields; + + public StructInfo(bool isSupported, FieldInfo[] fields) + { + IsSupported = isSupported; + Fields = fields; + } + + public void SetValue(object instance, string value, int fieldIndex) + { + try + { + var field = Fields[fieldIndex]; + + object val; + if (field.FieldType == typeof(string)) + val = value; + else + val = ReflectionUtility.GetMethodInfo(field.FieldType, "Parse", ArgumentUtility.ParseArgs) + .Invoke(null, new object[] { value }); + + field.SetValue(instance, val); + } + catch (FormatException) { ExplorerCore.LogWarning($"Invalid argument '{value}'!"); } + catch (ArgumentException) { ExplorerCore.LogWarning($"Invalid argument '{value}'!"); } + catch (OverflowException) { ExplorerCore.LogWarning($"Invalid argument '{value}'!"); } + catch (Exception ex) + { + ExplorerCore.Log("Excepting setting value '" + value + "'! " + ex); + } + } + + public string GetValue(object instance, int fieldIndex) + { + return Fields[fieldIndex].GetValue(instance)?.ToString() ?? ""; + } + } + + private static readonly Dictionary typeSupportCache = new Dictionary(); + + private const BindingFlags INSTANCE_FLAGS = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public; + private const string SYSTEM_VOID = "System.Void"; + + public static bool SupportsType(Type type) + { + if (!type.IsValueType || string.IsNullOrEmpty(type.AssemblyQualifiedName) || type.FullName == SYSTEM_VOID) + return false; + + if (typeSupportCache.TryGetValue(type.AssemblyQualifiedName, out var info)) + return info.IsSupported; + + var supported = true; + + var fields = type.GetFields(INSTANCE_FLAGS); + + if (fields.Any(it => !it.FieldType.IsPrimitive && it.FieldType != typeof(string))) + { + supported = false; + info = new StructInfo(supported, null); + } + else + { + supported = true; + info = new StructInfo(supported, fields); + } + + typeSupportCache.Add(type.AssemblyQualifiedName, info); + + return supported; + } + + #endregion + + public object RefInstance; + + public StructInfo CurrentInfo; + private Type lastStructType; + + private ButtonRef applyButton; + private readonly List fieldRows = new List(); + private readonly List inputFields = new List(); + private readonly List labels = new List(); + + public override void OnBorrowed(CacheObjectBase owner) + { + base.OnBorrowed(owner); + + applyButton.Button.gameObject.SetActive(owner.CanWrite); + } + + // Setting value from owner to this + + public override void SetValue(object value) + { + RefInstance = value; + + var type = RefInstance.GetType(); + + if (type != lastStructType) + { + CurrentInfo = typeSupportCache[type.AssemblyQualifiedName]; + SetupUIForType(); + lastStructType = type; + } + + for (int i = 0; i < CurrentInfo.Fields.Length; i++) + { + inputFields[i].Text = CurrentInfo.GetValue(RefInstance, i); + } + } + + private void OnApplyClicked() + { + try + { + for (int i = 0; i < CurrentInfo.Fields.Length; i++) + { + CurrentInfo.SetValue(RefInstance, inputFields[i].Text, i); + } + + CurrentOwner.SetUserValue(RefInstance); + } + catch (Exception ex) + { + ExplorerCore.LogWarning("Exception setting value: " + ex); + } + } + + // UI Setup for type + + private void SetupUIForType() + { + for (int i = 0; i < CurrentInfo.Fields.Length || i <= inputFields.Count; i++) + { + if (i >= CurrentInfo.Fields.Length) + { + if (i >= inputFields.Count) + break; + + fieldRows[i].SetActive(false); + continue; + } + + if (i >= inputFields.Count) + AddEditorRow(); + + fieldRows[i].SetActive(true); + + string label = SignatureHighlighter.Parse(CurrentInfo.Fields[i].FieldType, false); + label += $" {CurrentInfo.Fields[i].Name}:"; + labels[i].text = label; + } + } + + private void AddEditorRow() + { + var row = UIFactory.CreateUIObject("HoriGroup", UIRoot); + //row.AddComponent().horizontalFit = ContentSizeFitter.FitMode.PreferredSize; + UIFactory.SetLayoutElement(row, minHeight: 25, flexibleWidth: 9999); + UIFactory.SetLayoutGroup(row, false, false, true, true, 8, childAlignment: TextAnchor.MiddleLeft); + + fieldRows.Add(row); + + var label = UIFactory.CreateLabel(row, "Label", "notset", TextAnchor.MiddleRight); + UIFactory.SetLayoutElement(label.gameObject, minHeight: 25, minWidth: 150, flexibleWidth: 0); + label.horizontalOverflow = HorizontalWrapMode.Wrap; + labels.Add(label); + + var input = UIFactory.CreateInputField(row, "InputField", "..."); + UIFactory.SetLayoutElement(input.UIRoot, minHeight: 25, minWidth: 100); + var fitter = input.UIRoot.AddComponent(); + fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; + fitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize; + input.InputField.lineType = InputField.LineType.MultiLineNewline; + inputFields.Add(input); + } + + // UI Construction + + public override GameObject CreateContent(GameObject parent) + { + UIRoot = UIFactory.CreateVerticalGroup(parent, "InteractiveValueStruct", false, false, true, true, 3, new Vector4(4, 4, 4, 4), + new Color(0.06f, 0.06f, 0.06f), TextAnchor.MiddleLeft); + UIFactory.SetLayoutElement(UIRoot, minHeight: 25, flexibleWidth: 9999); + + applyButton = UIFactory.CreateButton(UIRoot, "ApplyButton", "Apply", new Color(0.2f, 0.27f, 0.2f)); + UIFactory.SetLayoutElement(applyButton.Button.gameObject, minHeight: 25, minWidth: 100); + applyButton.OnClick += OnApplyClicked; + + return UIRoot; + } + } +} diff --git a/src/UI/Utility/ToStringUtility.cs b/src/UI/Utility/ToStringUtility.cs index 99b8e44..8e4066c 100644 --- a/src/UI/Utility/ToStringUtility.cs +++ b/src/UI/Utility/ToStringUtility.cs @@ -119,14 +119,14 @@ namespace UnityExplorer.UI.Utility { try { - var formatMethod = type.GetMethod("ToString", new Type[] { typeof(string) }); + var formatMethod = type.GetMethod("ToString", ArgumentUtility.ParseArgs); formatMethod.Invoke(value, new object[] { "F3" }); toStringFormattedMethods.Add(type.AssemblyQualifiedName, formatMethod); toStringMethods.Add(type.AssemblyQualifiedName, null); } catch { - var toStringMethod = type.GetMethod("ToString", new Type[0]); + var toStringMethod = type.GetMethod("ToString", ArgumentUtility.EmptyTypes); toStringMethods.Add(type.AssemblyQualifiedName, toStringMethod); } } @@ -141,7 +141,7 @@ namespace UnityExplorer.UI.Utility if (toStringFormattedMethods.TryGetValue(type.AssemblyQualifiedName, out MethodInfo f3method)) toString = (string)f3method.Invoke(value, new object[] { "F3" }); else - toString = (string)toStringMethods[type.AssemblyQualifiedName].Invoke(value, new object[0]); + toString = (string)toStringMethods[type.AssemblyQualifiedName].Invoke(value, ArgumentUtility.EmptyArgs); } catch (Exception ex) { diff --git a/src/UnityExplorer.csproj b/src/UnityExplorer.csproj index 66397df..037856a 100644 --- a/src/UnityExplorer.csproj +++ b/src/UnityExplorer.csproj @@ -224,6 +224,7 @@ + @@ -251,6 +252,7 @@ +