mirror of
https://github.com/sinai-dev/UnityExplorer.git
synced 2025-06-16 22:27:45 +08:00
Made ParseUtility helper to simplify and improve parsing of various input types
This commit is contained in:
parent
c828d9b642
commit
c04a864b74
@ -92,17 +92,23 @@ namespace UnityExplorer
|
||||
public static string ReflectionExToString(this Exception e, bool innerMost = true)
|
||||
{
|
||||
if (innerMost)
|
||||
{
|
||||
while (e.InnerException != null)
|
||||
{
|
||||
if (e.InnerException is System.Runtime.CompilerServices.RuntimeWrappedException)
|
||||
break;
|
||||
|
||||
e = e.InnerException;
|
||||
}
|
||||
}
|
||||
e.GetInnerMostException();
|
||||
|
||||
return $"{e.GetType()}: {e.Message}";
|
||||
}
|
||||
|
||||
public static Exception GetInnerMostException(this Exception e)
|
||||
{
|
||||
while (e.InnerException != null)
|
||||
{
|
||||
#if CPP
|
||||
if (e.InnerException is System.Runtime.CompilerServices.RuntimeWrappedException)
|
||||
break;
|
||||
#endif
|
||||
e = e.InnerException;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -275,7 +275,7 @@ namespace UnityExplorer
|
||||
|
||||
var name = toType.AssemblyQualifiedName;
|
||||
|
||||
if (!unboxMethods.ContainsKey(toType.AssemblyQualifiedName))
|
||||
if (!unboxMethods.ContainsKey(name))
|
||||
{
|
||||
unboxMethods.Add(name, typeof(Il2CppObjectBase)
|
||||
.GetMethod("Unbox")
|
||||
|
@ -182,7 +182,6 @@ namespace UnityExplorer
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Type and Generic Parameter implementation cache
|
||||
|
||||
// cache for GetImplementationsOf
|
||||
@ -302,7 +301,6 @@ namespace UnityExplorer
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Internal MemberInfo Cache
|
||||
|
||||
internal static Dictionary<Type, Dictionary<string, FieldInfo>> fieldInfos = new Dictionary<Type, Dictionary<string, FieldInfo>>();
|
||||
|
@ -8,14 +8,12 @@ namespace UnityExplorer
|
||||
{
|
||||
public static class MiscUtility
|
||||
{
|
||||
private static CultureInfo _enCulture = new CultureInfo("en-US");
|
||||
|
||||
/// <summary>
|
||||
/// Check if a string contains another string, case-insensitive.
|
||||
/// </summary>
|
||||
public static bool ContainsIgnoreCase(this string _this, string s)
|
||||
{
|
||||
return _enCulture.CompareInfo.IndexOf(_this, s, CompareOptions.IgnoreCase) >= 0;
|
||||
return ParseUtility.en_US.CompareInfo.IndexOf(_this, s, CompareOptions.IgnoreCase) >= 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
390
src/Core/Utility/ParseUtility.cs
Normal file
390
src/Core/Utility/ParseUtility.cs
Normal file
@ -0,0 +1,390 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityExplorer
|
||||
{
|
||||
public static class ParseUtility
|
||||
{
|
||||
public static CultureInfo en_US = new CultureInfo("en-US");
|
||||
|
||||
private static readonly HashSet<Type> nonPrimitiveTypes = new HashSet<Type>
|
||||
{
|
||||
typeof(string),
|
||||
typeof(decimal),
|
||||
typeof(DateTime),
|
||||
};
|
||||
|
||||
public static bool CanParse(Type type)
|
||||
{
|
||||
if (string.IsNullOrEmpty(type.FullName))
|
||||
return false;
|
||||
return type.IsPrimitive || nonPrimitiveTypes.Contains(type) || customTypes.ContainsKey(type.FullName);
|
||||
}
|
||||
|
||||
public static bool TryParse(string input, Type type, out object obj, out Exception parseException)
|
||||
{
|
||||
obj = null;
|
||||
parseException = null;
|
||||
|
||||
if (type == null)
|
||||
return false;
|
||||
|
||||
if (type == typeof(string))
|
||||
{
|
||||
obj = input;
|
||||
return true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (customTypes.ContainsKey(type.FullName))
|
||||
{
|
||||
obj = customTypes[type.FullName].Invoke(input);
|
||||
}
|
||||
else
|
||||
{
|
||||
obj = ReflectionUtility.GetMethodInfo(type, "Parse", ArgumentUtility.ParseArgs)
|
||||
.Invoke(null, new object[] { input });
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex = ex.GetInnerMostException();
|
||||
parseException = ex;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static string ToStringForInput(object obj, Type type)
|
||||
{
|
||||
if (type == null || obj == null)
|
||||
return null;
|
||||
|
||||
if (type == typeof(string))
|
||||
return obj as string;
|
||||
|
||||
try
|
||||
{
|
||||
if (customTypes.ContainsKey(type.FullName))
|
||||
{
|
||||
return customTypesToString[type.FullName].Invoke(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (obj is IntPtr ptr)
|
||||
return ptr.ToString();
|
||||
else if (obj is UIntPtr uPtr)
|
||||
return uPtr.ToString();
|
||||
else
|
||||
return ReflectionUtility.GetMethodInfo(type, "ToString", new Type[] { typeof(IFormatProvider) })
|
||||
.Invoke(obj, new object[] { en_US })
|
||||
as string;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExplorerCore.LogWarning($"Exception formatting object for input: {ex}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Dictionary<string, string> typeInputExamples = new Dictionary<string, string>();
|
||||
|
||||
public static string GetExampleInput(Type type)
|
||||
{
|
||||
if (!typeInputExamples.ContainsKey(type.AssemblyQualifiedName))
|
||||
{
|
||||
try
|
||||
{
|
||||
var instance = Activator.CreateInstance(type);
|
||||
typeInputExamples.Add(type.AssemblyQualifiedName, ToStringForInput(instance, type));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExplorerCore.LogWarning("Exception generating default instance for example input for '" + type.FullName + "'");
|
||||
ExplorerCore.Log(ex);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
return typeInputExamples[type.AssemblyQualifiedName];
|
||||
}
|
||||
|
||||
#region Custom parse methods
|
||||
|
||||
internal delegate object ParseMethod(string input);
|
||||
|
||||
private static readonly Dictionary<string, ParseMethod> customTypes = new Dictionary<string, ParseMethod>
|
||||
{
|
||||
{ typeof(Vector2).FullName, TryParseVector2 },
|
||||
{ typeof(Vector3).FullName, TryParseVector3 },
|
||||
{ typeof(Vector4).FullName, TryParseVector4 },
|
||||
{ typeof(Quaternion).FullName, TryParseQuaternion },
|
||||
{ typeof(Rect).FullName, TryParseRect },
|
||||
{ typeof(Color).FullName, TryParseColor },
|
||||
{ typeof(Color32).FullName, TryParseColor32 },
|
||||
{ typeof(LayerMask).FullName, TryParseLayerMask },
|
||||
};
|
||||
|
||||
internal delegate string ToStringMethod(object obj);
|
||||
|
||||
private static readonly Dictionary<string, ToStringMethod> customTypesToString = new Dictionary<string, ToStringMethod>
|
||||
{
|
||||
{ typeof(Vector2).FullName, Vector2ToString },
|
||||
{ typeof(Vector3).FullName, Vector3ToString },
|
||||
{ typeof(Vector4).FullName, Vector4ToString },
|
||||
{ typeof(Quaternion).FullName, QuaternionToString },
|
||||
{ typeof(Rect).FullName, RectToString },
|
||||
{ typeof(Color).FullName, ColorToString },
|
||||
{ typeof(Color32).FullName, Color32ToString },
|
||||
{ typeof(LayerMask).FullName, LayerMaskToString },
|
||||
};
|
||||
|
||||
// Vector2
|
||||
|
||||
public static object TryParseVector2(string input)
|
||||
{
|
||||
Vector2 vector = default;
|
||||
|
||||
var split = input.Split(',');
|
||||
|
||||
vector.x = float.Parse(split[0].Trim(), en_US);
|
||||
vector.y = float.Parse(split[1].Trim(), en_US);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
public static string Vector2ToString(object obj)
|
||||
{
|
||||
if (!(obj is Vector2 vector))
|
||||
return null;
|
||||
|
||||
return string.Format(en_US, "{0}, {1}", new object[]
|
||||
{
|
||||
vector.x,
|
||||
vector.y
|
||||
});
|
||||
}
|
||||
|
||||
// Vector3
|
||||
|
||||
public static object TryParseVector3(string input)
|
||||
{
|
||||
Vector3 vector = default;
|
||||
|
||||
var split = input.Split(',');
|
||||
|
||||
vector.x = float.Parse(split[0].Trim(), en_US);
|
||||
vector.y = float.Parse(split[1].Trim(), en_US);
|
||||
vector.z = float.Parse(split[2].Trim(), en_US);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
public static string Vector3ToString(object obj)
|
||||
{
|
||||
if (!(obj is Vector3 vector))
|
||||
return null;
|
||||
|
||||
return string.Format(en_US, "{0}, {1}, {2}", new object[]
|
||||
{
|
||||
vector.x,
|
||||
vector.y,
|
||||
vector.z
|
||||
});
|
||||
}
|
||||
|
||||
// Vector4
|
||||
|
||||
public static object TryParseVector4(string input)
|
||||
{
|
||||
Vector4 vector = default;
|
||||
|
||||
var split = input.Split(',');
|
||||
|
||||
vector.x = float.Parse(split[0].Trim(), en_US);
|
||||
vector.y = float.Parse(split[1].Trim(), en_US);
|
||||
vector.z = float.Parse(split[2].Trim(), en_US);
|
||||
vector.w = float.Parse(split[3].Trim(), en_US);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
public static string Vector4ToString(object obj)
|
||||
{
|
||||
if (!(obj is Vector4 vector))
|
||||
return null;
|
||||
|
||||
return string.Format(en_US, "{0}, {1}, {2}, {3}", new object[]
|
||||
{
|
||||
vector.x,
|
||||
vector.y,
|
||||
vector.z,
|
||||
vector.w
|
||||
});
|
||||
}
|
||||
|
||||
// Quaternion
|
||||
|
||||
public static object TryParseQuaternion(string input)
|
||||
{
|
||||
Vector3 vector = default;
|
||||
|
||||
var split = input.Split(',');
|
||||
|
||||
if (split.Length == 4)
|
||||
{
|
||||
Quaternion quat = default;
|
||||
quat.x = float.Parse(split[0].Trim(), en_US);
|
||||
quat.y = float.Parse(split[1].Trim(), en_US);
|
||||
quat.z = float.Parse(split[2].Trim(), en_US);
|
||||
quat.w = float.Parse(split[3].Trim(), en_US);
|
||||
return quat;
|
||||
}
|
||||
else
|
||||
{
|
||||
vector.x = float.Parse(split[0].Trim(), en_US);
|
||||
vector.y = float.Parse(split[1].Trim(), en_US);
|
||||
vector.z = float.Parse(split[2].Trim(), en_US);
|
||||
return Quaternion.Euler(vector);
|
||||
}
|
||||
}
|
||||
|
||||
public static string QuaternionToString(object obj)
|
||||
{
|
||||
if (!(obj is Quaternion quaternion))
|
||||
return null;
|
||||
|
||||
Vector3 vector = Quaternion.ToEulerAngles(quaternion);
|
||||
|
||||
return string.Format(en_US, "{0}, {1}, {2}", new object[]
|
||||
{
|
||||
vector.x,
|
||||
vector.y,
|
||||
vector.z,
|
||||
});
|
||||
}
|
||||
|
||||
// Rect
|
||||
|
||||
public static object TryParseRect(string input)
|
||||
{
|
||||
Rect rect = default;
|
||||
|
||||
var split = input.Split(',');
|
||||
|
||||
rect.x = float.Parse(split[0].Trim(), en_US);
|
||||
rect.y = float.Parse(split[1].Trim(), en_US);
|
||||
rect.width = float.Parse(split[2].Trim(), en_US);
|
||||
rect.height = float.Parse(split[3].Trim(), en_US);
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
public static string RectToString(object obj)
|
||||
{
|
||||
if (!(obj is Rect rect))
|
||||
return null;
|
||||
|
||||
return string.Format(en_US, "{0}, {1}, {2}, {3}", new object[]
|
||||
{
|
||||
rect.x,
|
||||
rect.y,
|
||||
rect.width,
|
||||
rect.height
|
||||
});
|
||||
}
|
||||
|
||||
// Color
|
||||
|
||||
public static object TryParseColor(string input)
|
||||
{
|
||||
Color color = default;
|
||||
|
||||
var split = input.Split(',');
|
||||
|
||||
color.r = float.Parse(split[0].Trim(), en_US);
|
||||
color.g = float.Parse(split[1].Trim(), en_US);
|
||||
color.b = float.Parse(split[2].Trim(), en_US);
|
||||
if (split.Length > 3)
|
||||
color.a = float.Parse(split[3].Trim(), en_US);
|
||||
else
|
||||
color.a = 1;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
public static string ColorToString(object obj)
|
||||
{
|
||||
if (!(obj is Color color))
|
||||
return null;
|
||||
|
||||
return string.Format(en_US, "{0}, {1}, {2}, {3}", new object[]
|
||||
{
|
||||
color.r,
|
||||
color.g,
|
||||
color.b,
|
||||
color.a
|
||||
});
|
||||
}
|
||||
|
||||
// Color32
|
||||
|
||||
public static object TryParseColor32(string input)
|
||||
{
|
||||
Color32 color = default;
|
||||
|
||||
var split = input.Split(',');
|
||||
|
||||
color.r = byte.Parse(split[0].Trim(), en_US);
|
||||
color.g = byte.Parse(split[1].Trim(), en_US);
|
||||
color.b = byte.Parse(split[2].Trim(), en_US);
|
||||
if (split.Length > 3)
|
||||
color.a = byte.Parse(split[3].Trim(), en_US);
|
||||
else
|
||||
color.a = 255;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
public static string Color32ToString(object obj)
|
||||
{
|
||||
if (!(obj is Color32 color))
|
||||
return null;
|
||||
|
||||
return string.Format(en_US, "{0}, {1}, {2}, {3}", new object[]
|
||||
{
|
||||
color.r,
|
||||
color.g,
|
||||
color.b,
|
||||
color.a
|
||||
});
|
||||
}
|
||||
|
||||
// Layermask (Int32)
|
||||
|
||||
public static object TryParseLayerMask(string input)
|
||||
{
|
||||
return (LayerMask)int.Parse(input);
|
||||
}
|
||||
|
||||
public static string LayerMaskToString(object obj)
|
||||
{
|
||||
if (!(obj is LayerMask mask))
|
||||
return null;
|
||||
|
||||
return mask.ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -171,7 +171,7 @@ namespace UnityExplorer.UI.CacheObject
|
||||
|
||||
#region Cache Member Util
|
||||
|
||||
public static bool CanProcessArgs(ParameterInfo[] parameters)
|
||||
public static bool CanParseArgs(ParameterInfo[] parameters)
|
||||
{
|
||||
foreach (var param in parameters)
|
||||
{
|
||||
@ -180,7 +180,7 @@ namespace UnityExplorer.UI.CacheObject
|
||||
if (pType.IsByRef && pType.HasElementType)
|
||||
pType = pType.GetElementType();
|
||||
|
||||
if (pType != null && (pType.IsPrimitive || pType == typeof(string)))
|
||||
if (pType != null && ParseUtility.CanParse(pType))
|
||||
continue;
|
||||
else
|
||||
return false;
|
||||
@ -260,7 +260,7 @@ namespace UnityExplorer.UI.CacheObject
|
||||
return;
|
||||
|
||||
var args = mi.GetParameters();
|
||||
if (!CanProcessArgs(args))
|
||||
if (!CanParseArgs(args))
|
||||
return;
|
||||
|
||||
sig += AppendArgsToSig(args);
|
||||
@ -277,7 +277,7 @@ namespace UnityExplorer.UI.CacheObject
|
||||
var pi = member as PropertyInfo;
|
||||
|
||||
var args = pi.GetIndexParameters();
|
||||
if (!CanProcessArgs(args))
|
||||
if (!CanParseArgs(args))
|
||||
return;
|
||||
|
||||
if (!pi.CanRead && pi.CanWrite)
|
||||
|
@ -39,6 +39,9 @@ namespace UnityExplorer.UI.CacheObject
|
||||
public Type FallbackType { get; protected set; }
|
||||
public bool LastValueWasNull { get; private set; }
|
||||
|
||||
public ValueState State = ValueState.NotEvaluated;
|
||||
public Type LastValueType;
|
||||
|
||||
public InteractiveValue IValue { get; private set; }
|
||||
public Type CurrentIValueType { get; private set; }
|
||||
public bool SubContentShowWanted { get; private set; }
|
||||
@ -58,12 +61,6 @@ namespace UnityExplorer.UI.CacheObject
|
||||
this.ValueLabelText = GetValueLabel();
|
||||
}
|
||||
|
||||
// internals
|
||||
|
||||
// private static readonly Dictionary<string, MethodInfo> numberParseMethods = new Dictionary<string, MethodInfo>();
|
||||
|
||||
public ValueState State = ValueState.NotEvaluated;
|
||||
|
||||
protected const string NOT_YET_EVAL = "<color=grey>Not yet evaluated</color>";
|
||||
|
||||
public virtual void ReleasePooledObjects()
|
||||
@ -127,6 +124,7 @@ namespace UnityExplorer.UI.CacheObject
|
||||
if (HadException)
|
||||
{
|
||||
LastValueWasNull = true;
|
||||
LastValueType = FallbackType;
|
||||
State = ValueState.Exception;
|
||||
}
|
||||
else if (Value.IsNullOrDestroyed())
|
||||
@ -158,6 +156,10 @@ namespace UnityExplorer.UI.CacheObject
|
||||
|
||||
public ValueState GetStateForType(Type type)
|
||||
{
|
||||
if (LastValueType == type)
|
||||
return State;
|
||||
|
||||
LastValueType = type;
|
||||
if (type == typeof(bool))
|
||||
return ValueState.Boolean;
|
||||
else if (type.IsPrimitive || type == typeof(decimal))
|
||||
@ -184,17 +186,24 @@ namespace UnityExplorer.UI.CacheObject
|
||||
|
||||
switch (State)
|
||||
{
|
||||
case ValueState.NotEvaluated:
|
||||
return $"<i>{NOT_YET_EVAL} ({SignatureHighlighter.Parse(FallbackType, true)})</i>";
|
||||
|
||||
case ValueState.Exception:
|
||||
return $"<i><color=red>{LastException.ReflectionExToString()}</color></i>";
|
||||
|
||||
// bool and number dont want the label for the value at all
|
||||
case ValueState.Boolean:
|
||||
case ValueState.Number:
|
||||
return null;
|
||||
|
||||
case ValueState.NotEvaluated:
|
||||
return $"<i>{NOT_YET_EVAL} ({SignatureHighlighter.Parse(FallbackType, true)})</i>";
|
||||
|
||||
case ValueState.Exception:
|
||||
return $"<i><color=red>{LastException.ReflectionExToString()}</color></i>";
|
||||
// and valuestruct also doesnt want it if we can parse it
|
||||
case ValueState.ValueStruct:
|
||||
if (ParseUtility.CanParse(LastValueType))
|
||||
return null;
|
||||
break;
|
||||
|
||||
// string wants it trimmed to max 200 chars
|
||||
case ValueState.String:
|
||||
if (!LastValueWasNull)
|
||||
{
|
||||
@ -204,7 +213,8 @@ namespace UnityExplorer.UI.CacheObject
|
||||
return $"\"{s}\"";
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
// try to prefix the count of the collection for lists and dicts
|
||||
case ValueState.Collection:
|
||||
if (!LastValueWasNull)
|
||||
{
|
||||
@ -256,7 +266,6 @@ namespace UnityExplorer.UI.CacheObject
|
||||
switch (State)
|
||||
{
|
||||
case ValueState.Exception:
|
||||
//case ValueState.NullValue:
|
||||
SetValueState(cell, ValueStateArgs.Default);
|
||||
break;
|
||||
case ValueState.Boolean:
|
||||
@ -274,10 +283,15 @@ namespace UnityExplorer.UI.CacheObject
|
||||
case ValueState.Enum:
|
||||
SetValueState(cell, new ValueStateArgs(true, subContentButtonActive: CanWrite));
|
||||
break;
|
||||
case ValueState.Color:
|
||||
case ValueState.ValueStruct:
|
||||
if (ParseUtility.CanParse(LastValueType))
|
||||
SetValueState(cell, new ValueStateArgs(false, false, null, true, false, true, CanWrite, true, true));
|
||||
else
|
||||
SetValueState(cell, new ValueStateArgs(true, inspectActive: true, subContentButtonActive: true));
|
||||
break;
|
||||
case ValueState.Collection:
|
||||
case ValueState.Dictionary:
|
||||
case ValueState.ValueStruct:
|
||||
case ValueState.Color:
|
||||
SetValueState(cell, new ValueStateArgs(true, inspectActive: !LastValueWasNull, subContentButtonActive: !LastValueWasNull));
|
||||
break;
|
||||
case ValueState.Unsupported:
|
||||
@ -303,7 +317,7 @@ namespace UnityExplorer.UI.CacheObject
|
||||
// Type label (for primitives)
|
||||
cell.TypeLabel.gameObject.SetActive(args.typeLabelActive);
|
||||
if (args.typeLabelActive)
|
||||
cell.TypeLabel.text = SignatureHighlighter.Parse(Value.GetActualType(), false);
|
||||
cell.TypeLabel.text = SignatureHighlighter.Parse(LastValueType, false);
|
||||
|
||||
// toggle for bools
|
||||
cell.Toggle.gameObject.SetActive(args.toggleActive);
|
||||
@ -318,7 +332,7 @@ namespace UnityExplorer.UI.CacheObject
|
||||
cell.InputField.UIRoot.SetActive(args.inputActive);
|
||||
if (args.inputActive)
|
||||
{
|
||||
cell.InputField.Text = Value.ToString();
|
||||
cell.InputField.Text = ParseUtility.ToStringForInput(Value, LastValueType);
|
||||
cell.InputField.InputField.readOnly = !CanWrite;
|
||||
}
|
||||
|
||||
@ -342,21 +356,15 @@ namespace UnityExplorer.UI.CacheObject
|
||||
SetUserValue(this.CellView.Toggle.isOn);
|
||||
else
|
||||
{
|
||||
try
|
||||
if (ParseUtility.TryParse(CellView.InputField.Text, LastValueType, out object value, out Exception ex))
|
||||
{
|
||||
var type = Value.GetType();
|
||||
|
||||
var val = ReflectionUtility.GetMethodInfo(type, "Parse", ArgumentUtility.ParseArgs)
|
||||
.Invoke(null, new object[] { CellView.InputField.Text });
|
||||
|
||||
SetUserValue(val);
|
||||
SetUserValue(value);
|
||||
}
|
||||
catch (ArgumentException) { } // ignore bad user input
|
||||
catch (FormatException) { }
|
||||
catch (OverflowException) { }
|
||||
catch (Exception ex)
|
||||
else
|
||||
{
|
||||
ExplorerCore.LogWarning("CacheObjectBase OnCellApplyClicked (number): " + ex.ToString());
|
||||
ExplorerCore.LogWarning("Unable to parse input!");
|
||||
if (ex != null)
|
||||
ExplorerCore.Log(ex.ReflectionExToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,16 +155,18 @@ namespace UnityExplorer.UI.CacheObject.Views
|
||||
InputField = UIFactory.CreateInputField(rightHoriGroup, "InputField", "...");
|
||||
UIFactory.SetLayoutElement(InputField.UIRoot, minWidth: 150, flexibleWidth: 0, minHeight: 25, flexibleHeight: 0);
|
||||
|
||||
// Inspect and apply buttons
|
||||
// Apply
|
||||
|
||||
InspectButton = UIFactory.CreateButton(rightHoriGroup, "InspectButton", "Inspect", new Color(0.15f, 0.15f, 0.15f));
|
||||
UIFactory.SetLayoutElement(InspectButton.Button.gameObject, minWidth: 60, flexibleWidth: 0, minHeight: 25);
|
||||
InspectButton.OnClick += InspectClicked;
|
||||
|
||||
ApplyButton = UIFactory.CreateButton(rightHoriGroup, "ApplyButton", "Apply", new Color(0.15f, 0.15f, 0.15f));
|
||||
ApplyButton = UIFactory.CreateButton(rightHoriGroup, "ApplyButton", "Apply", new Color(0.15f, 0.19f, 0.15f));
|
||||
UIFactory.SetLayoutElement(ApplyButton.Button.gameObject, minWidth: 70, minHeight: 25, flexibleWidth: 0, flexibleHeight: 0);
|
||||
ApplyButton.OnClick += ApplyClicked;
|
||||
|
||||
// Inspect
|
||||
|
||||
InspectButton = UIFactory.CreateButton(rightHoriGroup, "InspectButton", "Inspect", new Color(0.15f, 0.15f, 0.15f));
|
||||
UIFactory.SetLayoutElement(InspectButton.Button.gameObject, minWidth: 70, flexibleWidth: 0, minHeight: 25);
|
||||
InspectButton.OnClick += InspectClicked;
|
||||
|
||||
// Main value label
|
||||
|
||||
ValueLabel = UIFactory.CreateLabel(rightHoriGroup, "ValueLabel", "Value goes here", TextAnchor.MiddleLeft);
|
||||
|
@ -33,7 +33,7 @@ namespace UnityExplorer.UI.CacheObject.Views
|
||||
private readonly List<Text> genericArgLabels = new List<Text>();
|
||||
private readonly List<TypeCompleter> genericAutocompleters = new List<TypeCompleter>();
|
||||
|
||||
private readonly List<InputFieldRef> inputFieldCache = new List<InputFieldRef>();
|
||||
private readonly List<InputFieldRef> inputFields = new List<InputFieldRef>();
|
||||
|
||||
public void OnBorrowedFromPool(CacheMember owner)
|
||||
{
|
||||
@ -52,7 +52,7 @@ namespace UnityExplorer.UI.CacheObject.Views
|
||||
|
||||
public void OnReturnToPool()
|
||||
{
|
||||
foreach (var input in inputFieldCache)
|
||||
foreach (var input in inputFields)
|
||||
input.Text = "";
|
||||
|
||||
this.Owner = null;
|
||||
@ -99,15 +99,11 @@ namespace UnityExplorer.UI.CacheObject.Views
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
if (!ParseUtility.TryParse(input, type, out outArgs[i], out Exception ex))
|
||||
{
|
||||
var parse = ReflectionUtility.GetMethodInfo(type, "Parse", ArgumentUtility.ParseArgs);
|
||||
outArgs[i] = parse.Invoke(null, new object[] { input });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExplorerCore.LogWarning($"Cannot parse argument '{arg.Name}' ({arg.ParameterType.Name}), {ex.GetType().Name}: {ex.Message}");
|
||||
outArgs[i] = null;
|
||||
ExplorerCore.LogWarning($"Cannot parse argument '{arg.Name}' ({arg.ParameterType.Name})" +
|
||||
$"{(ex == null ? "" : $", {ex.GetType().Name}: {ex.Message}")}");
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,6 +195,15 @@ namespace UnityExplorer.UI.CacheObject.Views
|
||||
|
||||
argRows[i].SetActive(true);
|
||||
argLabels[i].text = $"{SignatureHighlighter.Parse(arg.ParameterType, false)} <color={SignatureHighlighter.LOCAL_ARG}>{arg.Name}</color>";
|
||||
if (arg.ParameterType == typeof(string))
|
||||
inputFields[i].PlaceholderText.text = "";
|
||||
else
|
||||
{
|
||||
var elemType = arg.ParameterType;
|
||||
if (elemType.IsByRef)
|
||||
elemType = elemType.GetElementType();
|
||||
inputFields[i].PlaceholderText.text = $"eg. {ParseUtility.GetExampleInput(elemType)}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,7 +233,7 @@ namespace UnityExplorer.UI.CacheObject.Views
|
||||
inputField.InputField.lineType = InputField.LineType.MultiLineNewline;
|
||||
inputField.UIRoot.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
inputField.OnValueChanged += (string val) => { inputArray[index] = val; };
|
||||
inputFieldCache.Add(inputField);
|
||||
inputFields.Add(inputField);
|
||||
|
||||
if (autocomplete)
|
||||
genericAutocompleters.Add(new TypeCompleter(null, inputField));
|
||||
|
@ -26,33 +26,31 @@ namespace UnityExplorer.UI.IValues
|
||||
Fields = fields;
|
||||
}
|
||||
|
||||
public void SetValue(object instance, string value, int fieldIndex)
|
||||
public void SetValue(object instance, string input, int fieldIndex)
|
||||
{
|
||||
try
|
||||
{
|
||||
var field = Fields[fieldIndex];
|
||||
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)
|
||||
object val;
|
||||
if (field.FieldType == typeof(string))
|
||||
val = input;
|
||||
else
|
||||
{
|
||||
ExplorerCore.Log("Excepting setting value '" + value + "'! " + ex);
|
||||
if (!ParseUtility.TryParse(input, field.FieldType, out val, out Exception ex))
|
||||
{
|
||||
ExplorerCore.LogWarning("Unable to parse input!");
|
||||
if (ex != null) ExplorerCore.Log(ex.ReflectionExToString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
field.SetValue(instance, val);
|
||||
}
|
||||
|
||||
public string GetValue(object instance, int fieldIndex)
|
||||
{
|
||||
return Fields[fieldIndex].GetValue(instance)?.ToString() ?? "";
|
||||
var field = Fields[fieldIndex];
|
||||
var value = field.GetValue(instance);
|
||||
return ParseUtility.ToStringForInput(value, field.FieldType);
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,19 +67,21 @@ namespace UnityExplorer.UI.IValues
|
||||
if (typeSupportCache.TryGetValue(type.AssemblyQualifiedName, out var info))
|
||||
return info.IsSupported;
|
||||
|
||||
var supported = true;
|
||||
var supported = false;
|
||||
|
||||
var fields = type.GetFields(INSTANCE_FLAGS);
|
||||
|
||||
if (fields.Any(it => !it.FieldType.IsPrimitive && it.FieldType != typeof(string)))
|
||||
if (fields.Length > 0)
|
||||
{
|
||||
supported = false;
|
||||
info = new StructInfo(supported, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
supported = true;
|
||||
info = new StructInfo(supported, fields);
|
||||
if (fields.Any(it => !ParseUtility.CanParse(it.FieldType)))
|
||||
{
|
||||
supported = false;
|
||||
info = new StructInfo(supported, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
supported = true;
|
||||
info = new StructInfo(supported, fields);
|
||||
}
|
||||
}
|
||||
|
||||
typeSupportCache.Add(type.AssemblyQualifiedName, info);
|
||||
@ -182,12 +182,12 @@ namespace UnityExplorer.UI.IValues
|
||||
fieldRows.Add(row);
|
||||
|
||||
var label = UIFactory.CreateLabel(row, "Label", "notset", TextAnchor.MiddleRight);
|
||||
UIFactory.SetLayoutElement(label.gameObject, minHeight: 25, minWidth: 150, flexibleWidth: 0);
|
||||
UIFactory.SetLayoutElement(label.gameObject, minHeight: 25, minWidth: 175, flexibleWidth: 0);
|
||||
label.horizontalOverflow = HorizontalWrapMode.Wrap;
|
||||
labels.Add(label);
|
||||
|
||||
var input = UIFactory.CreateInputField(row, "InputField", "...");
|
||||
UIFactory.SetLayoutElement(input.UIRoot, minHeight: 25, minWidth: 100);
|
||||
UIFactory.SetLayoutElement(input.UIRoot, minHeight: 25, minWidth: 200);
|
||||
var fitter = input.UIRoot.AddComponent<ContentSizeFitter>();
|
||||
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
fitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
@ -204,7 +204,7 @@ namespace UnityExplorer.UI.IValues
|
||||
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);
|
||||
UIFactory.SetLayoutElement(applyButton.Button.gameObject, minHeight: 25, minWidth: 175);
|
||||
applyButton.OnClick += OnApplyClicked;
|
||||
|
||||
return UIRoot;
|
||||
|
@ -295,14 +295,12 @@ namespace UnityExplorer.UI.Panels
|
||||
{
|
||||
// Window Anchors helpers
|
||||
|
||||
internal static CultureInfo _enCulture = new CultureInfo("en-US");
|
||||
|
||||
internal static string RectAnchorsToString(this RectTransform rect)
|
||||
{
|
||||
if (!rect)
|
||||
throw new ArgumentNullException("rect");
|
||||
|
||||
return string.Format(_enCulture, "{0},{1},{2},{3}", new object[]
|
||||
return string.Format(ParseUtility.en_US, "{0},{1},{2},{3}", new object[]
|
||||
{
|
||||
rect.anchorMin.x,
|
||||
rect.anchorMin.y,
|
||||
@ -322,10 +320,10 @@ namespace UnityExplorer.UI.Panels
|
||||
throw new Exception($"stringAnchors split is unexpected length: {split.Length}");
|
||||
|
||||
Vector4 anchors;
|
||||
anchors.x = float.Parse(split[0], _enCulture);
|
||||
anchors.y = float.Parse(split[1], _enCulture);
|
||||
anchors.z = float.Parse(split[2], _enCulture);
|
||||
anchors.w = float.Parse(split[3], _enCulture);
|
||||
anchors.x = float.Parse(split[0], ParseUtility.en_US);
|
||||
anchors.y = float.Parse(split[1], ParseUtility.en_US);
|
||||
anchors.z = float.Parse(split[2], ParseUtility.en_US);
|
||||
anchors.w = float.Parse(split[3], ParseUtility.en_US);
|
||||
|
||||
panel.anchorMin = new Vector2(anchors.x, anchors.y);
|
||||
panel.anchorMax = new Vector2(anchors.z, anchors.w);
|
||||
@ -336,7 +334,7 @@ namespace UnityExplorer.UI.Panels
|
||||
if (!rect)
|
||||
throw new ArgumentNullException("rect");
|
||||
|
||||
return string.Format(_enCulture, "{0},{1}", new object[]
|
||||
return string.Format(ParseUtility.en_US, "{0},{1}", new object[]
|
||||
{
|
||||
rect.localPosition.x, rect.localPosition.y
|
||||
});
|
||||
@ -350,8 +348,8 @@ namespace UnityExplorer.UI.Panels
|
||||
throw new Exception($"stringPosition split is unexpected length: {split.Length}");
|
||||
|
||||
Vector3 vector = rect.localPosition;
|
||||
vector.x = float.Parse(split[0], _enCulture);
|
||||
vector.y = float.Parse(split[1], _enCulture);
|
||||
vector.x = float.Parse(split[0], ParseUtility.en_US);
|
||||
vector.y = float.Parse(split[1], ParseUtility.en_US);
|
||||
rect.localPosition = vector;
|
||||
}
|
||||
}
|
||||
|
@ -226,6 +226,7 @@
|
||||
<Compile Include="Core\Reflection\Il2CppReflection.cs" />
|
||||
<Compile Include="Core\Utility\ArgumentUtility.cs" />
|
||||
<Compile Include="Core\Utility\MiscUtility.cs" />
|
||||
<Compile Include="Core\Utility\ParseUtility.cs" />
|
||||
<Compile Include="UI\Inspectors\TODO_InspectUnderMouse.cs" />
|
||||
<Compile Include="UI\CSConsole\CSConsoleManager.cs" />
|
||||
<Compile Include="UI\CacheObject\CacheField.cs" />
|
||||
|
Loading…
x
Reference in New Issue
Block a user