mirror of
https://github.com/sinai-dev/UnityExplorer.git
synced 2025-06-15 22:07:48 +08:00
InteractiveValueStruct, and a few cleanups
This commit is contained in:
parent
26052621e5
commit
c828d9b642
@ -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[] { "<Mouse>/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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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<string, Type[]> s_cachedBaseTypes = new Dictionary<string, Type[]>();
|
||||
internal static readonly Dictionary<string, Type[]> baseTypes = new Dictionary<string, Type[]>();
|
||||
|
||||
/// <summary>
|
||||
/// 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<Type> list = new List<Type>();
|
||||
@ -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<string, HashSet<Type>> s_cachedTypeInheritance = new Dictionary<string, HashSet<Type>>();
|
||||
internal static readonly Dictionary<string, HashSet<Type>> s_cachedGenericParameterInheritance = new Dictionary<string, HashSet<Type>>();
|
||||
internal static readonly Dictionary<string, HashSet<Type>> typeInheritance = new Dictionary<string, HashSet<Type>>();
|
||||
internal static readonly Dictionary<string, HashSet<Type>> genericParameterInheritance = new Dictionary<string, HashSet<Type>>();
|
||||
|
||||
public static string GetImplementationKey(Type type)
|
||||
{
|
||||
@ -222,7 +222,7 @@ namespace UnityExplorer
|
||||
|
||||
private static HashSet<Type> GetImplementations(string key, Type baseType, bool allowAbstract, bool allowGeneric)
|
||||
{
|
||||
if (!s_cachedTypeInheritance.ContainsKey(key))
|
||||
if (!typeInheritance.ContainsKey(key))
|
||||
{
|
||||
var set = new HashSet<Type>();
|
||||
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<Type> GetGenericParameterImplementations(string key, Type baseType, bool allowAbstract, bool allowGeneric)
|
||||
{
|
||||
if (!s_cachedGenericParameterInheritance.ContainsKey(key))
|
||||
if (!genericParameterInheritance.ContainsKey(key))
|
||||
{
|
||||
var set = new HashSet<Type>();
|
||||
|
||||
@ -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<Type, Dictionary<string, FieldInfo>> s_cachedFieldInfos = new Dictionary<Type, Dictionary<string, FieldInfo>>();
|
||||
internal static Dictionary<Type, Dictionary<string, FieldInfo>> fieldInfos = new Dictionary<Type, Dictionary<string, FieldInfo>>();
|
||||
|
||||
public static FieldInfo GetFieldInfo(Type type, string fieldName)
|
||||
{
|
||||
if (!s_cachedFieldInfos.ContainsKey(type))
|
||||
s_cachedFieldInfos.Add(type, new Dictionary<string, FieldInfo>());
|
||||
if (!fieldInfos.ContainsKey(type))
|
||||
fieldInfos.Add(type, new Dictionary<string, FieldInfo>());
|
||||
|
||||
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<Type, Dictionary<string, PropertyInfo>> s_cachedPropInfos = new Dictionary<Type, Dictionary<string, PropertyInfo>>();
|
||||
internal static Dictionary<Type, Dictionary<string, PropertyInfo>> propertyInfos = new Dictionary<Type, Dictionary<string, PropertyInfo>>();
|
||||
|
||||
public static PropertyInfo GetPropertyInfo(Type type, string propertyName)
|
||||
{
|
||||
if (!s_cachedPropInfos.ContainsKey(type))
|
||||
s_cachedPropInfos.Add(type, new Dictionary<string, PropertyInfo>());
|
||||
if (!propertyInfos.ContainsKey(type))
|
||||
propertyInfos.Add(type, new Dictionary<string, PropertyInfo>());
|
||||
|
||||
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<Type, Dictionary<string, MethodInfo>> s_cachedMethodInfos = new Dictionary<Type, Dictionary<string, MethodInfo>>();
|
||||
internal static Dictionary<Type, Dictionary<string, MethodInfo>> methodInfos = new Dictionary<Type, Dictionary<string, MethodInfo>>();
|
||||
|
||||
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<string, MethodInfo>());
|
||||
if (!methodInfos.ContainsKey(type))
|
||||
methodInfos.Add(type, new Dictionary<string, MethodInfo>());
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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()
|
||||
|
16
src/Core/Utility/ArgumentUtility.cs
Normal file
16
src/Core/Utility/ArgumentUtility.cs
Normal file
@ -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) };
|
||||
}
|
||||
}
|
@ -23,8 +23,8 @@ namespace UnityExplorer
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -60,7 +60,7 @@ namespace UnityExplorer.UI.CacheObject
|
||||
|
||||
// internals
|
||||
|
||||
private static readonly Dictionary<string, MethodInfo> numberParseMethods = new Dictionary<string, MethodInfo>();
|
||||
// private static readonly Dictionary<string, MethodInfo> numberParseMethods = new Dictionary<string, MethodInfo>();
|
||||
|
||||
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);
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
213
src/UI/IValues/InteractiveValueStruct.cs
Normal file
213
src/UI/IValues/InteractiveValueStruct.cs
Normal file
@ -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<string, StructInfo> typeSupportCache = new Dictionary<string, StructInfo>();
|
||||
|
||||
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<GameObject> fieldRows = new List<GameObject>();
|
||||
private readonly List<InputFieldRef> inputFields = new List<InputFieldRef>();
|
||||
private readonly List<Text> labels = new List<Text>();
|
||||
|
||||
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 += $" <color={SignatureHighlighter.FIELD_INSTANCE}>{CurrentInfo.Fields[i].Name}</color>:";
|
||||
labels[i].text = label;
|
||||
}
|
||||
}
|
||||
|
||||
private void AddEditorRow()
|
||||
{
|
||||
var row = UIFactory.CreateUIObject("HoriGroup", UIRoot);
|
||||
//row.AddComponent<ContentSizeFitter>().horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
UIFactory.SetLayoutElement(row, minHeight: 25, flexibleWidth: 9999);
|
||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(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<ContentSizeFitter>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
{
|
||||
|
@ -224,6 +224,7 @@
|
||||
<Compile Include="Core\ExplorerBehaviour.cs" />
|
||||
<Compile Include="Core\Reflection\Extensions.cs" />
|
||||
<Compile Include="Core\Reflection\Il2CppReflection.cs" />
|
||||
<Compile Include="Core\Utility\ArgumentUtility.cs" />
|
||||
<Compile Include="Core\Utility\MiscUtility.cs" />
|
||||
<Compile Include="UI\Inspectors\TODO_InspectUnderMouse.cs" />
|
||||
<Compile Include="UI\CSConsole\CSConsoleManager.cs" />
|
||||
@ -251,6 +252,7 @@
|
||||
<Compile Include="UI\IValues\InteractiveString.cs" />
|
||||
<Compile Include="UI\IValues\InteractiveValue.cs" />
|
||||
<Compile Include="UI\Inspectors\ReflectionInspector.cs" />
|
||||
<Compile Include="UI\IValues\InteractiveValueStruct.cs" />
|
||||
<Compile Include="UI\Models\InputFieldRef.cs" />
|
||||
<Compile Include="UI\ObjectPool\IPooledObject.cs" />
|
||||
<Compile Include="UI\ObjectPool\Pool.cs" />
|
||||
|
Loading…
x
Reference in New Issue
Block a user