diff --git a/src/Core/Config/InternalConfigHandler.cs b/src/Core/Config/InternalConfigHandler.cs index 331e533..e3ebdf0 100644 --- a/src/Core/Config/InternalConfigHandler.cs +++ b/src/Core/Config/InternalConfigHandler.cs @@ -52,8 +52,6 @@ namespace UnityExplorer.Core.Config { try { - ExplorerCore.Log("Loading internal data"); - if (!File.Exists(INI_PATH)) return false; @@ -67,8 +65,6 @@ namespace UnityExplorer.Core.Config configElement.BoxedValue = StringToConfigValue(config.Value, configElement.ElementType); } - ExplorerCore.Log("Loaded"); - return true; } catch (Exception ex) diff --git a/src/Core/Input/CursorUnlocker.cs b/src/Core/Input/CursorUnlocker.cs index c1e8f95..a76f82b 100644 --- a/src/Core/Input/CursorUnlocker.cs +++ b/src/Core/Input/CursorUnlocker.cs @@ -78,13 +78,6 @@ namespace UnityExplorer.Core.Input } } - public static void UpdateIfNeeded() - { - if ((!ShouldActuallyUnlock && (Cursor.visible || Cursor.lockState == CursorLockMode.None)) - || (ShouldActuallyUnlock && (!Cursor.visible || Cursor.lockState != CursorLockMode.None))) - UpdateCursorControl(); - } - public static void UpdateCursorControl() { try @@ -143,9 +136,6 @@ namespace UnityExplorer.Core.Input public static void ReleaseEventSystem() { - if (EventSystem.current != UIManager.EventSys) - return; - if (InputManager.CurrentType == InputType.InputSystem) return; @@ -225,4 +215,198 @@ namespace UnityExplorer.Core.Input } } } -} \ No newline at end of file +} + +// Was rewriting but something broke, not looking into it right now. + +//using System; +//using UnityEngine; +//using UnityEngine.EventSystems; +//using UnityExplorer.Core.Input; +//using BF = System.Reflection.BindingFlags; +//using UnityExplorer.Core.Config; +//using UnityExplorer.Core; +//using UnityExplorer.UI; +//using System.Collections; +//#if ML +//using Harmony; +//#else +//using HarmonyLib; +//#endif + +//namespace UnityExplorer.Core.Input +//{ +// public class CursorUnlocker +// { +// public static bool Unlock +// { +// get => unlock; +// set +// { +// unlock = value; +// UpdateCursorControl(); +// } +// } +// private static bool unlock; + +// public static bool ShouldActuallyUnlock => UIManager.ShowMenu && Unlock; + +// private static CursorLockMode lastLockMode; +// private static bool lastVisibleState; + +// private static bool currentlySetting = false; + +// private static Type CursorType +// => cursorType +// ?? (cursorType = ReflectionUtility.GetTypeByName("UnityEngine.Cursor")); +// private static Type cursorType; + +// public static void Init() +// { +// SetupPatches(); + +// UpdateCursorControl(); + +// Unlock = ConfigManager.Force_Unlock_Mouse.Value; +// ConfigManager.Force_Unlock_Mouse.OnValueChanged += (bool val) => { Unlock = val; }; + +// if (ConfigManager.Aggressive_Force_Unlock.Value) +// RuntimeProvider.Instance.StartCoroutine(ForceUnlockCoroutine()); +// } + +// private static readonly WaitForEndOfFrame _waitForEndOfFrame = new WaitForEndOfFrame(); + +// private static IEnumerator ForceUnlockCoroutine() +// { +// while (true) +// { +// yield return _waitForEndOfFrame; + +// UpdateCursorControl(); +// } +// } + +// public static void UpdateCursorControl() +// { +// currentlySetting = true; + +// if (ShouldActuallyUnlock) +// { +// if (Cursor.lockState != CursorLockMode.None) +// Cursor.lockState = CursorLockMode.None; +// if (!Cursor.visible) +// Cursor.visible = true; + +// SetEventSystem(); +// } +// else +// { +// if (Cursor.lockState != lastLockMode) +// Cursor.lockState = lastLockMode; +// if (Cursor.visible != lastVisibleState) +// Cursor.visible = lastVisibleState; + +// ReleaseEventSystem(); +// } + +// currentlySetting = false; +// } + +// // Event system overrides + +// private static bool m_settingEventSystem; +// private static EventSystem m_lastEventSystem; +// private static BaseInputModule m_lastInputModule; + +// public static void SetEventSystem() +// { +// if (InputManager.CurrentType == InputType.InputSystem +// || !UIManager.EventSys +// || EventSystem.current == UIManager.EventSys) +// return; + +// if (EventSystem.current && EventSystem.current != UIManager.EventSys) +// { +// m_lastEventSystem = EventSystem.current; +// m_lastEventSystem.enabled = false; +// } + +// // Set to our current system +// m_settingEventSystem = true; +// UIManager.EventSys.enabled = true; +// EventSystem.current = UIManager.EventSys; +// InputManager.ActivateUIModule(); +// m_settingEventSystem = false; +// } + +// public static void ReleaseEventSystem() +// { +// if (InputManager.CurrentType == InputType.InputSystem +// || !UIManager.EventSys +// || EventSystem.current != UIManager.EventSys +// || !m_lastEventSystem) +// return; + +// if (m_lastEventSystem.gameObject.activeInHierarchy) +// { +// m_lastEventSystem.enabled = true; + +// m_settingEventSystem = true; +// EventSystem.current = m_lastEventSystem; +// m_lastInputModule?.ActivateModule(); +// m_settingEventSystem = false; +// } +// } + +// // Patches + +// private static void SetupPatches() +// { +// if (CursorType == null) +// throw new Exception("Could not load Type 'UnityEngine.Cursor'!"); + +// lastLockMode = Cursor.lockState; +// lastVisibleState = Cursor.visible; + +// // Let mod loader handle actual patching (only necessary until ML 0.3.1) +// ExplorerCore.Loader.SetupCursorPatches(); +// } + +// public static void Prefix_EventSystem_set_current(ref EventSystem value) +// { +// if (!m_settingEventSystem && value != UIManager.EventSys) +// { +// m_lastEventSystem = value; +// m_lastInputModule = value?.currentInputModule; + +// if (ShouldActuallyUnlock) +// { +// value = UIManager.EventSys; +// value.enabled = true; +// } +// } +// } + +// public static void Prefix_set_lockState(ref CursorLockMode value) +// { +// if (!currentlySetting) +// { +// lastLockMode = value; + +// if (ShouldActuallyUnlock) +// value = CursorLockMode.None; +// } +// } + +// public static void Prefix_set_visible(ref bool value) +// { +// if (!currentlySetting) +// { +// lastVisibleState = value; + +// if (ShouldActuallyUnlock) +// value = true; +// } +// } +// } +//} \ No newline at end of file diff --git a/src/Core/ReflectionUtility.cs b/src/Core/ReflectionUtility.cs index 208b701..150aaab 100644 --- a/src/Core/ReflectionUtility.cs +++ b/src/Core/ReflectionUtility.cs @@ -57,7 +57,13 @@ namespace UnityExplorer /// The object to cast /// The object, cast to the underlying Type if possible, otherwise the original object. public static object TryCast(this object obj) - => ReflectionProvider.Instance.Cast(obj, GetActualType(obj)); + { + var type = GetActualType(obj); + + if (type.IsValueType) + return obj; + return ReflectionProvider.Instance.Cast(obj, type); + } /// /// Cast an object to a Type, if possible. @@ -66,10 +72,19 @@ namespace UnityExplorer /// The Type to cast to /// The object, cast to the Type provided if possible, otherwise the original object. public static object TryCast(this object obj, Type castTo) - => ReflectionProvider.Instance.Cast(obj, castTo); + { + if (castTo.IsValueType) + return obj; + return ReflectionProvider.Instance.Cast(obj, castTo); + } public static T TryCast(this object obj) - => ReflectionProvider.Instance.TryCast(obj); + { + var type = typeof(T); + if (type.IsValueType) + return (T)obj; + return ReflectionProvider.Instance.TryCast(obj); + } /// /// Check if the provided Type is assignable to IEnumerable. diff --git a/src/Core/Runtime/Il2Cpp/AssetBundle.cs b/src/Core/Runtime/Il2Cpp/AssetBundle.cs index 9ad4301..52dbb0f 100644 --- a/src/Core/Runtime/Il2Cpp/AssetBundle.cs +++ b/src/Core/Runtime/Il2Cpp/AssetBundle.cs @@ -19,9 +19,7 @@ namespace UnityExplorer public static AssetBundle LoadFromFile(string path) { var iCall = ICallManager.GetICall("UnityEngine.AssetBundle::LoadFromFile_Internal"); - var ptr = iCall.Invoke(IL2CPP.ManagedStringToIl2Cpp(path), 0u, 0UL); - return new AssetBundle(ptr); } @@ -30,12 +28,20 @@ namespace UnityExplorer public static AssetBundle LoadFromMemory(byte[] binary, uint crc = 0) { var iCall = ICallManager.GetICall("UnityEngine.AssetBundle::LoadFromMemory_Internal"); - var ptr = iCall(((Il2CppStructArray) binary).Pointer, crc); - return new AssetBundle(ptr); } + // static void UnloadAllAssetBundles(bool unloadAllObjects); + + internal delegate void d_UnloadAllAssetBundles(bool unloadAllObjects); + + public static void UnloadAllAssetBundles(bool unloadAllObjects) + { + var iCall = ICallManager.GetICall("UnityEngine.AssetBundle::UnloadAllAssetBundles"); + iCall.Invoke(unloadAllObjects); + } + // ~~~~~~~~~~~~ Instance ~~~~~~~~~~~~ private readonly IntPtr m_bundlePtr = IntPtr.Zero; @@ -71,6 +77,15 @@ namespace UnityExplorer return new UnityEngine.Object(ptr).TryCast(); } + + // public extern void Unload(bool unloadAllLoadedObjects); + internal delegate void d_Unload(IntPtr _this, bool unloadAllLoadedObjects); + + public void Unload(bool unloadAssets = true) + { + var iCall = ICallManager.GetICall("UnityEngine.AssetBundle::Unload"); + iCall.Invoke(this.m_bundlePtr, unloadAssets); + } } } #endif \ No newline at end of file diff --git a/src/Core/Runtime/Il2Cpp/Il2CppReflection.cs b/src/Core/Runtime/Il2Cpp/Il2CppReflection.cs index 8eb479c..c96e58e 100644 --- a/src/Core/Runtime/Il2Cpp/Il2CppReflection.cs +++ b/src/Core/Runtime/Il2Cpp/Il2CppReflection.cs @@ -133,35 +133,37 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp var type = obj.GetType(); - if (obj is Il2CppSystem.Object cppObject) + try { - // weird specific case - if the object is an Il2CppSystem.Type, then return so manually. - if (cppObject is CppType) - return typeof(CppType); - - if (!string.IsNullOrEmpty(type.Namespace)) + if ((Il2CppSystem.Object)obj is Il2CppSystem.Object cppObject) { - // Il2CppSystem-namespace objects should just return GetType, - // because using GetIl2CppType returns the System namespace type instead. - if (type.Namespace.StartsWith("System.") || type.Namespace.StartsWith("Il2CppSystem.")) - return cppObject.GetType(); + // weird specific case - if the object is an Il2CppSystem.Type, then return so manually. + if (cppObject is CppType) + return typeof(CppType); + + if (type.FullName.StartsWith("System.") || type.FullName.StartsWith("Il2CppSystem.")) + return type; + + var cppType = cppObject.GetIl2CppType(); + + // check if type is injected + IntPtr classPtr = il2cpp_object_get_class(cppObject.Pointer); + if (RuntimeSpecificsStore.IsInjected(classPtr)) + { + var typeByName = ReflectionUtility.GetTypeByName(cppType.FullName); + if (typeByName != null) + return typeByName; + } + + // this should be fine for all other il2cpp objects + var getType = GetMonoType(cppType); + if (getType != null) + return getType; } - - var cppType = cppObject.GetIl2CppType(); - - // check if type is injected - IntPtr classPtr = il2cpp_object_get_class(cppObject.Pointer); - if (RuntimeSpecificsStore.IsInjected(classPtr)) - { - var typeByName = ReflectionUtility.GetTypeByName(cppType.FullName); - if (typeByName != null) - return typeByName; - } - - // this should be fine for all other il2cpp objects - var getType = GetMonoType(cppType); - if (getType != null) - return getType; + } + catch // (Exception ex) + { + // ExplorerCore.LogWarning("Exception in GetActualType: " + ex); } return type; diff --git a/src/Core/Tests/TestClass.cs b/src/Core/Tests/TestClass.cs index c44a08c..2c95315 100644 --- a/src/Core/Tests/TestClass.cs +++ b/src/Core/Tests/TestClass.cs @@ -103,6 +103,11 @@ namespace UnityExplorer.Tests public static Il2CppSystem.Collections.Hashtable testHashset; public static Il2CppSystem.Collections.Generic.List testList; + + + //public static Il2CppSystem.Nullable NullableQuaternion; + //public static Il2CppSystem.Nullable NullableInt = new Il2CppSystem.Nullable(5); + //public static Il2CppSystem.Nullable NullableBool = new Il2CppSystem.Nullable(false); #endif static TestClass() @@ -111,6 +116,9 @@ namespace UnityExplorer.Tests BigList.Add(i.ToString()); #if CPP + //NullableQuaternion = new Il2CppSystem.Nullable(); + //NullableQuaternion.value = Quaternion.identity; + testHashset = new Il2CppSystem.Collections.Hashtable(); testHashset.Add("key1", "itemOne"); testHashset.Add("key2", "itemTwo"); diff --git a/src/UI/Inspectors/CacheObject/CacheField.cs b/src/UI/Inspectors/CacheObject/CacheField.cs index 9de77a3..267345e 100644 --- a/src/UI/Inspectors/CacheObject/CacheField.cs +++ b/src/UI/Inspectors/CacheObject/CacheField.cs @@ -20,16 +20,20 @@ namespace UnityExplorer.UI.Inspectors.CacheObject base.SetInspectorOwner(inspector, member); } - protected override void TryEvaluate() + protected override object TryEvaluate() { try { - Value = FieldInfo.GetValue(this.Owner.Target.TryCast(this.DeclaringType)); + var ret = FieldInfo.GetValue(this.Owner.Target.TryCast(this.DeclaringType)); + HadException = false; + LastException = null; + return ret; } catch (Exception ex) { HadException = true; LastException = ex; + return null; } } @@ -37,7 +41,7 @@ namespace UnityExplorer.UI.Inspectors.CacheObject { try { - FieldInfo.SetValue(FieldInfo.IsStatic ? null : Owner.Target, value); + FieldInfo.SetValue(FieldInfo.IsStatic ? null : Owner.Target.TryCast(this.DeclaringType), value); } catch (Exception ex) { diff --git a/src/UI/Inspectors/CacheObject/CacheKeyValuePair.cs b/src/UI/Inspectors/CacheObject/CacheKeyValuePair.cs index e7641b8..349cb3a 100644 --- a/src/UI/Inspectors/CacheObject/CacheKeyValuePair.cs +++ b/src/UI/Inspectors/CacheObject/CacheKeyValuePair.cs @@ -42,7 +42,7 @@ namespace UnityExplorer.UI.Inspectors.CacheObject { KeyInputWanted = true; KeyInputText = key.ToString(); - KeyInputTypeText = SignatureHighlighter.ParseFullType(type, false); + KeyInputTypeText = SignatureHighlighter.ParseType(type, false); } else { diff --git a/src/UI/Inspectors/CacheObject/CacheMember.cs b/src/UI/Inspectors/CacheObject/CacheMember.cs index b5a83a8..4e61c1c 100644 --- a/src/UI/Inspectors/CacheObject/CacheMember.cs +++ b/src/UI/Inspectors/CacheObject/CacheMember.cs @@ -5,6 +5,7 @@ using System.Reflection; using System.Text; using UnityEngine; using UnityExplorer.UI.Inspectors.CacheObject.Views; +using UnityExplorer.UI.ObjectPool; using UnityExplorer.UI.Utility; namespace UnityExplorer.UI.Inspectors.CacheObject @@ -17,9 +18,11 @@ namespace UnityExplorer.UI.Inspectors.CacheObject public abstract Type DeclaringType { get; } public string NameForFiltering { get; protected set; } - public override bool HasArguments => Arguments?.Length > 0; - public ParameterInfo[] Arguments { get; protected set; } - public bool Evaluating { get; protected set; } + 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 EvaluateWidget Evaluator { get; protected set; } + public bool Evaluating => Evaluator != null && Evaluator.UIRoot.activeSelf; public virtual void SetInspectorOwner(ReflectionInspector inspector, MemberInfo member) { @@ -28,17 +31,43 @@ namespace UnityExplorer.UI.Inspectors.CacheObject this.NameForFiltering = $"{member.DeclaringType.Name}.{member.Name}"; } - protected abstract void TryEvaluate(); + public override void ReleasePooledObjects() + { + base.ReleasePooledObjects(); + + if (this.Evaluator != null) + { + this.Evaluator.OnReturnToPool(); + Pool.Return(this.Evaluator); + this.Evaluator = null; + } + } + + internal override void HidePooledObjects() + { + base.HidePooledObjects(); + + if (this.Evaluator != null) + this.Evaluator.UIRoot.transform.SetParent(Pool.Instance.InactiveHolder.transform, false); + } + + protected abstract object TryEvaluate(); protected abstract void TrySetValue(object value); + public void EvaluateAndSetCell() + { + Evaluate(); + if (CellView != null) + SetCell(CellView); + } + /// /// Evaluate when first shown (if ShouldAutoEvaluate), or else when Evaluate button is clicked, or auto-updated. /// public void Evaluate() { - TryEvaluate(); - SetValueFromSource(Value); + SetValueFromSource(TryEvaluate()); } public override void SetUserValue(object value) @@ -58,6 +87,9 @@ namespace UnityExplorer.UI.Inspectors.CacheObject //memCell.UpdateToggle.gameObject.SetActive(ShouldAutoEvaluate); } + private static readonly Color evalEnabledColor = new Color(0.15f, 0.25f, 0.15f); + private static readonly Color evalDisabledColor = new Color(0.15f, 0.15f, 0.15f); + protected override bool SetCellEvaluateState(CacheObjectCell objectcell) { var cell = objectcell as CacheMemberCell; @@ -68,15 +100,27 @@ namespace UnityExplorer.UI.Inspectors.CacheObject //cell.UpdateToggle.gameObject.SetActive(false); cell.EvaluateButton.Button.gameObject.SetActive(true); if (HasArguments) - cell.EvaluateButton.ButtonText.text = $"Evaluate ({Arguments.Length})"; + { + if (!Evaluating) + cell.EvaluateButton.ButtonText.text = $"Evaluate ({Arguments.Length + GenericArguments.Length})"; + else + { + cell.EvaluateButton.ButtonText.text = "Hide"; + Evaluator.UIRoot.transform.SetParent(cell.EvaluateHolder.transform, false); + RuntimeProvider.Instance.SetColorBlock(cell.EvaluateButton.Button, evalEnabledColor, evalEnabledColor * 1.3f); + } + } else cell.EvaluateButton.ButtonText.text = "Evaluate"; + + if (!Evaluating) + RuntimeProvider.Instance.SetColorBlock(cell.EvaluateButton.Button, evalDisabledColor, evalDisabledColor * 1.3f); } - else - { - //cell.UpdateToggle.gameObject.SetActive(true); - //cell.UpdateToggle.isOn = AutoUpdateWanted; - } + //else + //{ + // cell.UpdateToggle.gameObject.SetActive(true); + // cell.UpdateToggle.isOn = AutoUpdateWanted; + //} if (State == ValueState.NotEvaluated && !ShouldAutoEvaluate) { @@ -93,6 +137,35 @@ namespace UnityExplorer.UI.Inspectors.CacheObject return false; } + + public void OnEvaluateClicked() + { + if (!HasArguments) + { + EvaluateAndSetCell(); + } + else + { + if (Evaluator == null) + { + this.Evaluator = Pool.Borrow(); + Evaluator.OnBorrowedFromPool(this); + Evaluator.UIRoot.transform.SetParent((CellView as CacheMemberCell).EvaluateHolder.transform, false); + SetCellEvaluateState(CellView); + } + else + { + if (Evaluator.UIRoot.activeSelf) + Evaluator.UIRoot.SetActive(false); + else + Evaluator.UIRoot.SetActive(true); + + SetCellEvaluateState(CellView); + } + } + } + + #region Cache Member Util public static bool CanProcessArgs(ParameterInfo[] parameters) diff --git a/src/UI/Inspectors/CacheObject/CacheMethod.cs b/src/UI/Inspectors/CacheObject/CacheMethod.cs index 3985466..23d4625 100644 --- a/src/UI/Inspectors/CacheObject/CacheMethod.cs +++ b/src/UI/Inspectors/CacheObject/CacheMethod.cs @@ -19,18 +19,35 @@ namespace UnityExplorer.UI.Inspectors.CacheObject base.SetInspectorOwner(inspector, member); Arguments = MethodInfo.GetParameters(); + if (MethodInfo.IsGenericMethod) + GenericArguments = MethodInfo.GetGenericArguments(); } - protected override void TryEvaluate() + protected override object TryEvaluate() { try { - throw new NotImplementedException("TODO"); + var methodInfo = MethodInfo; + + if (methodInfo.IsGenericMethod) + methodInfo = MethodInfo.MakeGenericMethod(Evaluator.TryParseGenericArguments()); + + var target = MethodInfo.IsStatic ? null : Owner.Target.TryCast(DeclaringType); + + if (Arguments.Length > 0) + return methodInfo.Invoke(target, Evaluator.TryParseArguments()); + + var ret = methodInfo.Invoke(target, new object[0]); + + HadException = false; + LastException = null; + return ret; } catch (Exception ex) { HadException = true; LastException = ex; + return null; } } diff --git a/src/UI/Inspectors/CacheObject/CacheObjectBase.cs b/src/UI/Inspectors/CacheObject/CacheObjectBase.cs index 1e979ed..e9dfefe 100644 --- a/src/UI/Inspectors/CacheObject/CacheObjectBase.cs +++ b/src/UI/Inspectors/CacheObject/CacheObjectBase.cs @@ -128,7 +128,6 @@ namespace UnityExplorer.UI.Inspectors.CacheObject /// protected virtual void ProcessOnEvaluate() { - if (HadException) State = ValueState.Exception; else if (Value.IsNullOrDestroyed()) @@ -166,7 +165,7 @@ namespace UnityExplorer.UI.Inspectors.CacheObject switch (State) { case ValueState.NotEvaluated: - label = $"{NOT_YET_EVAL} ({SignatureHighlighter.ParseFullType(FallbackType, true)})"; break; + label = $"{NOT_YET_EVAL} ({SignatureHighlighter.ParseType(FallbackType, true)})"; break; case ValueState.Exception: label = $"{ReflectionUtility.ReflectionExToString(LastException)}"; break; case ValueState.Boolean: @@ -228,7 +227,7 @@ namespace UnityExplorer.UI.Inspectors.CacheObject break; case ValueState.Enum: SetIValueState(); - SetValueState(cell, new ValueStateArgs(true, subContentButtonActive: true)); + SetValueState(cell, new ValueStateArgs(true, subContentButtonActive: CanWrite)); break; case ValueState.Collection: case ValueState.Dictionary: @@ -258,11 +257,12 @@ namespace UnityExplorer.UI.Inspectors.CacheObject cell.TypeLabel.gameObject.SetActive(args.typeLabelActive); if (args.typeLabelActive) - cell.TypeLabel.text = SignatureHighlighter.ParseFullType(Value.GetActualType(), false); + cell.TypeLabel.text = SignatureHighlighter.ParseType(Value.GetActualType(), false); cell.Toggle.gameObject.SetActive(args.toggleActive); if (args.toggleActive) { + cell.Toggle.interactable = CanWrite; cell.Toggle.isOn = (bool)Value; cell.ToggleText.text = Value.ToString(); } @@ -329,7 +329,7 @@ namespace UnityExplorer.UI.Inspectors.CacheObject IValue = null; } - internal void HideIValue() + internal virtual void HidePooledObjects() { if (this.IValue == null) return; diff --git a/src/UI/Inspectors/CacheObject/CacheProperty.cs b/src/UI/Inspectors/CacheObject/CacheProperty.cs index 1981a09..104372a 100644 --- a/src/UI/Inspectors/CacheObject/CacheProperty.cs +++ b/src/UI/Inspectors/CacheObject/CacheProperty.cs @@ -21,16 +21,26 @@ namespace UnityExplorer.UI.Inspectors.CacheObject Arguments = PropertyInfo.GetIndexParameters(); } - protected override void TryEvaluate() + protected override object TryEvaluate() { try { - Value = PropertyInfo.GetValue(Owner.Target.TryCast(DeclaringType), null); + bool _static = PropertyInfo.GetAccessors(true)[0].IsStatic; + var target = _static ? null : Owner.Target.TryCast(DeclaringType); + + if (HasArguments) + return PropertyInfo.GetValue(target, this.Evaluator.TryParseArguments()); + + var ret = PropertyInfo.GetValue(target, null); + HadException = false; + LastException = null; + return ret; } catch (Exception ex) { HadException = true; LastException = ex; + return null; } } @@ -41,9 +51,13 @@ namespace UnityExplorer.UI.Inspectors.CacheObject try { - // TODO property indexers + bool _static = PropertyInfo.GetAccessors(true)[0].IsStatic; + var target = _static ? null : Owner.Target.TryCast(DeclaringType); - PropertyInfo.SetValue(PropertyInfo.GetSetMethod().IsStatic ? null : Owner.Target, value, null); + if (HasArguments) + PropertyInfo.SetValue(target, value, Evaluator.TryParseArguments()); + else + PropertyInfo.SetValue(target, value, null); } catch (Exception ex) { diff --git a/src/UI/Inspectors/CacheObject/Views/CacheMemberCell.cs b/src/UI/Inspectors/CacheObject/Views/CacheMemberCell.cs index 599e0f0..5afde1d 100644 --- a/src/UI/Inspectors/CacheObject/Views/CacheMemberCell.cs +++ b/src/UI/Inspectors/CacheObject/Views/CacheMemberCell.cs @@ -21,7 +21,7 @@ namespace UnityExplorer.UI.Inspectors.CacheObject.Views protected virtual void EvaluateClicked() { - // TODO + this.MemberOccupant.OnEvaluateClicked(); } protected override void ConstructEvaluateHolder(GameObject parent) diff --git a/src/UI/Inspectors/CacheObject/Views/EvaluateWidget.cs b/src/UI/Inspectors/CacheObject/Views/EvaluateWidget.cs new file mode 100644 index 0000000..e54bc35 --- /dev/null +++ b/src/UI/Inspectors/CacheObject/Views/EvaluateWidget.cs @@ -0,0 +1,257 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using UnityEngine; +using UnityEngine.UI; +using UnityExplorer.UI.ObjectPool; +using UnityExplorer.UI.Utility; + +namespace UnityExplorer.UI.Inspectors.CacheObject.Views +{ + public class EvaluateWidget : IPooledObject + { + public CacheMember Owner { get; set; } + + public GameObject UIRoot { get; set; } + public float DefaultHeight => -1f; + + private ParameterInfo[] arguments; + private string[] argumentInput; + + private GameObject argHolder; + private readonly List argRows = new List(); + private readonly List argLabels = new List(); + + private Type[] genericArguments; + private string[] genericInput; + + private GameObject genericArgHolder; + private readonly List genericArgRows = new List(); + private readonly List genericArgLabels = new List(); + + private readonly List inputFieldCache = new List(); + + public void OnBorrowedFromPool(CacheMember owner) + { + this.Owner = owner; + + arguments = owner.Arguments; + argumentInput = new string[arguments.Length]; + + genericArguments = owner.GenericArguments; + genericInput = new string[genericArguments.Length]; + + SetArgRows(); + + this.UIRoot.SetActive(true); + } + + public void OnReturnToPool() + { + foreach (var input in inputFieldCache) + input.text = ""; + + this.Owner = null; + } + + public Type[] TryParseGenericArguments() + { + Type[] outArgs = new Type[genericArguments.Length]; + + for (int i = 0; i < genericArguments.Length; i++) + { + outArgs[i] = ReflectionUtility.GetTypeByName(genericInput[i]) + ?? throw new Exception($"Could not find any type by name '{genericInput[i]}'!"); + } + + return outArgs; + } + + public object[] TryParseArguments() + { + object[] outArgs = new object[arguments.Length]; + + for (int i = 0; i < arguments.Length; i++) + { + var arg = arguments[i]; + var input = argumentInput[i]; + + var type = arg.ParameterType; + if (type.IsByRef) + type = type.GetElementType(); + + if (type == typeof(string)) + { + outArgs[i] = input; + continue; + } + + if (string.IsNullOrEmpty(input)) + { + if (arg.IsOptional) + outArgs[i] = arg.DefaultValue; + else + outArgs[i] = null; + continue; + } + + try + { + var parse = ReflectionUtility.GetMethodInfo(type, "Parse", new Type[] { typeof(string) }); + 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; + } + } + + return outArgs; + } + + private void SetArgRows() + { + if (genericArguments.Any()) + { + genericArgHolder.SetActive(true); + SetupGenericArgs(); + } + else + genericArgHolder.SetActive(false); + + if (arguments.Any()) + { + argHolder.SetActive(true); + SetupArgs(); + } + else + argHolder.SetActive(false); + } + + private void SetupGenericArgs() + { + for (int i = 0; i < genericArguments.Length || i < genericArgRows.Count; i++) + { + if (i >= genericArguments.Length) + { + if (i >= genericArgRows.Count) + break; + else + // exceeded actual args, but still iterating so there must be views left, disable them + genericArgRows[i].SetActive(false); + continue; + } + + var arg = genericArguments[i]; + + if (i >= genericArgRows.Count) + AddArgRow(i, true); + + genericArgRows[i].SetActive(true); + + var sb = new StringBuilder($"{arg.Name}"); + + var constraints = arg.GetGenericParameterConstraints(); + for (int j = 0; j < constraints.Length; j++) + { + if (j == 0) sb.Append(' ').Append('('); + else sb.Append(',').Append(' '); + + sb.Append(SignatureHighlighter.ParseType(constraints[i])); + + if (j + 1 == constraints.Length) + sb.Append(')'); + } + + genericArgLabels[i].text = sb.ToString(); + } + } + + private void SetupArgs() + { + for (int i = 0; i < arguments.Length || i < argRows.Count; i++) + { + if (i >= arguments.Length) + { + if (i >= argRows.Count) + break; + else + // exceeded actual args, but still iterating so there must be views left, disable them + argRows[i].SetActive(false); + continue; + } + + var arg = arguments[i]; + + if (i >= argRows.Count) + AddArgRow(i, false); + + argRows[i].SetActive(true); + argLabels[i].text = $"{SignatureHighlighter.ParseType(arg.ParameterType)} {arg.Name}"; + } + } + + private void AddArgRow(int index, bool generic) + { + if (!generic) + AddArgRow(index, argHolder, argRows, argLabels, argumentInput); + else + AddArgRow(index, genericArgHolder, genericArgRows, genericArgLabels, genericInput); + } + + private void AddArgRow(int index, GameObject parent, List objectList, List labelList, string[] inputArray) + { + var horiGroup = UIFactory.CreateUIObject("ArgRow_" + index, parent); + UIFactory.SetLayoutElement(horiGroup, minHeight: 25, flexibleHeight: 50, minWidth: 50, flexibleWidth: 9999); + UIFactory.SetLayoutGroup(horiGroup, false, false, true, true, 5); + objectList.Add(horiGroup); + + var label = UIFactory.CreateLabel(horiGroup, "ArgLabel", "not set", TextAnchor.MiddleLeft); + UIFactory.SetLayoutElement(label.gameObject, minWidth: 40, flexibleWidth: 90, minHeight: 25, flexibleHeight: 50); + labelList.Add(label); + label.horizontalOverflow = HorizontalWrapMode.Wrap; + + var inputObj = UIFactory.CreateInputField(horiGroup, "InputField", "...", out InputField inputField); + UIFactory.SetLayoutElement(inputObj, minHeight: 25, flexibleHeight: 0, minWidth: 100, flexibleWidth: 1000); + inputField.lineType = InputField.LineType.MultiLineNewline; + inputField.onValueChanged.AddListener((string val) => { inputArray[index] = val; }); + inputFieldCache.Add(inputField); + } + + public GameObject CreateContent(GameObject parent) + { + UIRoot = UIFactory.CreateVerticalGroup(parent, "EvaluateWidget", false, false, true, true, 3, new Vector4(2, 2, 2, 2), + new Color(0.15f, 0.15f, 0.15f)); + UIFactory.SetLayoutElement(UIRoot, minWidth: 50, flexibleWidth: 9999, minHeight: 50, flexibleHeight: 800); + + // generic args + this.genericArgHolder = UIFactory.CreateUIObject("GenericHolder", UIRoot); + UIFactory.SetLayoutElement(genericArgHolder, flexibleWidth: 1000); + var genericsTitle = UIFactory.CreateLabel(genericArgHolder, "GenericsTitle", "Generic Arguments", TextAnchor.MiddleLeft); + UIFactory.SetLayoutElement(genericsTitle.gameObject, minHeight: 25, flexibleWidth: 1000); + UIFactory.SetLayoutGroup(genericArgHolder, false, false, true, true, 3); + UIFactory.SetLayoutElement(genericArgHolder, minHeight: 25, flexibleHeight: 750, minWidth: 50, flexibleWidth: 9999); + + // args + this.argHolder = UIFactory.CreateUIObject("ArgHolder", UIRoot); + UIFactory.SetLayoutElement(argHolder, flexibleWidth: 1000); + var argsTitle = UIFactory.CreateLabel(argHolder, "ArgsTitle", "Arguments", TextAnchor.MiddleLeft); + UIFactory.SetLayoutElement(argsTitle.gameObject, minHeight: 25, flexibleWidth: 1000); + UIFactory.SetLayoutGroup(argHolder, false, false, true, true, 3); + UIFactory.SetLayoutElement(argHolder, minHeight: 25, flexibleHeight: 750, minWidth: 50, flexibleWidth: 9999); + + // evaluate button + var evalButton = UIFactory.CreateButton(UIRoot, "EvaluateButton", "Evaluate", new Color(0.2f, 0.2f, 0.2f)); + UIFactory.SetLayoutElement(evalButton.Button.gameObject, minHeight: 25, minWidth: 150, flexibleWidth: 0); + evalButton.OnClick += () => + { + Owner.EvaluateAndSetCell(); + }; + + return UIRoot; + } + } +} diff --git a/src/UI/Inspectors/GameObjectInspector.cs b/src/UI/Inspectors/GameObjectInspector.cs index 5c23cbd..5a81d75 100644 --- a/src/UI/Inspectors/GameObjectInspector.cs +++ b/src/UI/Inspectors/GameObjectInspector.cs @@ -121,7 +121,7 @@ namespace UnityExplorer.UI.Inspectors if (!compToStringCache.ContainsKey(type.AssemblyQualifiedName)) { - compToStringCache.Add(type.AssemblyQualifiedName, SignatureHighlighter.ParseFullType(type, true)); + compToStringCache.Add(type.AssemblyQualifiedName, SignatureHighlighter.ParseType(type, true)); } cell.Button.ButtonText.text = compToStringCache[type.AssemblyQualifiedName]; diff --git a/src/UI/Inspectors/ICacheObjectController.cs b/src/UI/Inspectors/ICacheObjectController.cs index 383e075..fa33141 100644 --- a/src/UI/Inspectors/ICacheObjectController.cs +++ b/src/UI/Inspectors/ICacheObjectController.cs @@ -8,7 +8,7 @@ namespace UnityExplorer.UI.Inspectors { public interface ICacheObjectController { - CacheObjectBase ParentCacheObject { get; } // TODO + CacheObjectBase ParentCacheObject { get; } object Target { get; } Type TargetType { get; } diff --git a/src/UI/Inspectors/IValues/InteractiveDictionary.cs b/src/UI/Inspectors/IValues/InteractiveDictionary.cs index 46f6aa2..84ae0e5 100644 --- a/src/UI/Inspectors/IValues/InteractiveDictionary.cs +++ b/src/UI/Inspectors/IValues/InteractiveDictionary.cs @@ -39,6 +39,8 @@ namespace UnityExplorer.UI.Inspectors.IValues public override void OnBorrowed(CacheObjectBase owner) { base.OnBorrowed(owner); + + DictScrollPool.Refresh(true, true); } public override void ReleaseFromOwner() @@ -83,7 +85,7 @@ namespace UnityExplorer.UI.Inspectors.IValues CacheEntries(value); - TopLabel.text = $"[{cachedEntries.Count}] {SignatureHighlighter.ParseFullType(type, false)}"; + TopLabel.text = $"[{cachedEntries.Count}] {SignatureHighlighter.ParseType(type, false)}"; } @@ -172,7 +174,7 @@ namespace UnityExplorer.UI.Inspectors.IValues { if (cell.Occupant != null) { - cell.Occupant.HideIValue(); + cell.Occupant.HidePooledObjects(); cell.Occupant.CellView = null; cell.Occupant = null; } diff --git a/src/UI/Inspectors/IValues/InteractiveList.cs b/src/UI/Inspectors/IValues/InteractiveList.cs index 1eb44ed..3354f55 100644 --- a/src/UI/Inspectors/IValues/InteractiveList.cs +++ b/src/UI/Inspectors/IValues/InteractiveList.cs @@ -35,6 +35,8 @@ namespace UnityExplorer.UI.Inspectors.IValues public override void OnBorrowed(CacheObjectBase owner) { base.OnBorrowed(owner); + + ListScrollPool.Refresh(true, true); } public override void ReleaseFromOwner() @@ -72,7 +74,7 @@ namespace UnityExplorer.UI.Inspectors.IValues CacheEntries(value); - TopLabel.text = $"[{cachedEntries.Count}] {SignatureHighlighter.ParseFullType(type, false)}"; + TopLabel.text = $"[{cachedEntries.Count}] {SignatureHighlighter.ParseType(type, false)}"; } //this.ScrollPoolLayout.minHeight = Math.Min(400f, 35f * values.Count); @@ -169,7 +171,7 @@ namespace UnityExplorer.UI.Inspectors.IValues { if (cell.Occupant != null) { - cell.Occupant.HideIValue(); + cell.Occupant.HidePooledObjects(); cell.Occupant.CellView = null; cell.Occupant = null; } diff --git a/src/UI/Inspectors/ReflectionInspector.cs b/src/UI/Inspectors/ReflectionInspector.cs index e53dbc1..1e14a24 100644 --- a/src/UI/Inspectors/ReflectionInspector.cs +++ b/src/UI/Inspectors/ReflectionInspector.cs @@ -30,7 +30,7 @@ namespace UnityExplorer.UI.Inspectors private List members = new List(); private readonly List filteredMembers = new List(); - private readonly HashSet displayedMembers = new HashSet(); + // private readonly HashSet displayedMembers = new HashSet(); public Text NameText; public Text AssemblyText; @@ -65,7 +65,6 @@ namespace UnityExplorer.UI.Inspectors members.Clear(); filteredMembers.Clear(); - displayedMembers.Clear(); autoUpdateToggle.isOn = false; AutoUpdateWanted = false; @@ -88,7 +87,7 @@ namespace UnityExplorer.UI.Inspectors prefix = "[R]"; } - Tab.TabText.text = $"{prefix} {SignatureHighlighter.ParseFullType(TargetType)}"; + Tab.TabText.text = $"{prefix} {SignatureHighlighter.ParseType(TargetType)}"; NameText.text = SignatureHighlighter.ParseFullSyntax(TargetType, true); @@ -156,8 +155,11 @@ namespace UnityExplorer.UI.Inspectors private void UpdateDisplayedMembers()// bool onlyAutoUpdate) { bool shouldRefresh = false; - foreach (var member in displayedMembers) + foreach (var cell in MemberScrollPool.CellPool) { + if (!cell.Enabled || cell.Occupant == null) + continue; + var member = cell.MemberOccupant; if (member.ShouldAutoEvaluate) // && (!onlyAutoUpdate || member.AutoUpdateWanted)) { shouldRefresh = true; @@ -185,9 +187,6 @@ namespace UnityExplorer.UI.Inspectors { if (cell.Occupant != null) { - if (displayedMembers.Contains(cell.MemberOccupant)) - displayedMembers.Remove(cell.MemberOccupant); - cell.Occupant.CellView = null; cell.Occupant = null; } @@ -202,15 +201,13 @@ namespace UnityExplorer.UI.Inspectors { if (cell.Occupant != null) { - cell.Occupant.HideIValue(); - displayedMembers.Remove(cell.MemberOccupant); + cell.Occupant.HidePooledObjects(); cell.Occupant.CellView = null; cell.Occupant = null; } cell.Occupant = member; member.CellView = cell; - displayedMembers.Add(member); } member.SetCell(cell); diff --git a/src/UI/ObjectExplorer/ObjectSearch.cs b/src/UI/ObjectExplorer/ObjectSearch.cs index 8d0006f..69c6f5a 100644 --- a/src/UI/ObjectExplorer/ObjectSearch.cs +++ b/src/UI/ObjectExplorer/ObjectSearch.cs @@ -97,7 +97,7 @@ namespace UnityExplorer.UI.Panels { string text; if (m_context == SearchContext.StaticClass) - text = SignatureHighlighter.ParseFullType(currentResults[index] as Type, true, true); + text = SignatureHighlighter.ParseType(currentResults[index] as Type, true, true); else text = ToStringUtility.ToStringWithType(currentResults[index], currentResults[index]?.GetActualType()); diff --git a/src/UI/ObjectExplorer/SceneExplorer.cs b/src/UI/ObjectExplorer/SceneExplorer.cs index 8d8e8e3..c72fe33 100644 --- a/src/UI/ObjectExplorer/SceneExplorer.cs +++ b/src/UI/ObjectExplorer/SceneExplorer.cs @@ -41,10 +41,10 @@ namespace UnityExplorer.UI.Panels private readonly Dictionary sceneToDropdownOption = new Dictionary(); private IEnumerable GetRootEntries() => SceneHandler.CurrentRootObjects; - + public void Update() { - if (AutoUpdate && Time.realtimeSinceStartup - timeOfLastUpdate >= 1f) + if ((AutoUpdate || !SceneHandler.InspectingAssetScene) && Time.realtimeSinceStartup - timeOfLastUpdate >= 1f) { timeOfLastUpdate = Time.realtimeSinceStartup; UpdateTree(); @@ -65,7 +65,7 @@ namespace UnityExplorer.UI.Panels SceneHandler.SelectedScene = SceneHandler.LoadedScenes[value]; SceneHandler.Update(); Tree.RefreshData(true); - //OnSelectedSceneChanged(SceneHandler.SelectedScene.Value); + OnSelectedSceneChanged(SceneHandler.SelectedScene.Value); } private void SceneHandler_OnInspectedSceneChanged(Scene scene) @@ -83,14 +83,14 @@ namespace UnityExplorer.UI.Panels sceneDropdown.captionText.text = opt.text; } - //OnSelectedSceneChanged(scene); + OnSelectedSceneChanged(scene); } - //private void OnSelectedSceneChanged(Scene scene) - //{ - // if (refreshRow) - // refreshRow.SetActive(!scene.IsValid()); - //} + private void OnSelectedSceneChanged(Scene scene) + { + if (refreshRow) + refreshRow.SetActive(!scene.IsValid()); + } private void SceneHandler_OnLoadedScenesChanged(ReadOnlyCollection loadedScenes) { diff --git a/src/UI/Panels/ObjectExplorer.cs b/src/UI/Panels/ObjectExplorer.cs index b6efd3d..88b6096 100644 --- a/src/UI/Panels/ObjectExplorer.cs +++ b/src/UI/Panels/ObjectExplorer.cs @@ -40,7 +40,7 @@ namespace UnityExplorer.UI.Panels content.SetActive(true); var button = tabButtons[tabIndex]; - RuntimeProvider.Instance.SetColorBlock(button.Button, UIManager.navButtonEnabledColor, UIManager.navButtonEnabledColor * 1.2f); + RuntimeProvider.Instance.SetColorBlock(button.Button, UIManager.enabledButtonColor, UIManager.enabledButtonColor * 1.2f); SelectedTab = tabIndex; SaveToConfigManager(); @@ -49,7 +49,7 @@ namespace UnityExplorer.UI.Panels private void DisableTab(int tabIndex) { tabPages[tabIndex].SetActive(false); - RuntimeProvider.Instance.SetColorBlock(tabButtons[tabIndex].Button, UIManager.navButtonDisabledColor, UIManager.navButtonDisabledColor * 1.2f); + RuntimeProvider.Instance.SetColorBlock(tabButtons[tabIndex].Button, UIManager.disabledButtonColor, UIManager.disabledButtonColor * 1.2f); } public override void Update() @@ -97,10 +97,11 @@ namespace UnityExplorer.UI.Panels public override void SetDefaultPosAndAnchors() { + // todo proper default size mainPanelRect.localPosition = Vector2.zero; mainPanelRect.pivot = new Vector2(0f, 1f); - mainPanelRect.anchorMin = new Vector2(0.1f, 0.2f); - mainPanelRect.anchorMax = new Vector2(0.25f, 0.9f); + mainPanelRect.anchorMin = new Vector2(0.1f, 0.25f); + mainPanelRect.anchorMax = new Vector2(0.25f, 0.8f); //mainPanelRect.anchorMin = Vector3.zero; diff --git a/src/UI/Panels/PanelDragger.cs b/src/UI/Panels/PanelDragger.cs index 0bc6437..be1ed0b 100644 --- a/src/UI/Panels/PanelDragger.cs +++ b/src/UI/Panels/PanelDragger.cs @@ -227,19 +227,6 @@ namespace UnityExplorer.UI.Panels Vector3 pos = Panel.localPosition; pos += (Vector3)diff; Panel.localPosition = pos; - - // TODO prevent dragging the navbar outside the window completely. - // this was not that, but should do that. - - //var halfHeight = Panel.rect.height * 0.5f; - //var halfWidth = Panel.rect.width * 0.5f; - //if (Panel.MinY() - halfHeight + 25 < 0 - // || Panel.MinX() - halfWidth + 25 < 0 - // || Panel.MaxY() + halfWidth - 25 > Screen.height - // || Panel.MinX() + halfWidth - 25 > Screen.width) - //{ - // Panel.localPosition -= (Vector3)diff; - //} } public void OnEndDrag() diff --git a/src/UI/Panels/UIPanel.cs b/src/UI/Panels/UIPanel.cs index 649f32b..6193323 100644 --- a/src/UI/Panels/UIPanel.cs +++ b/src/UI/Panels/UIPanel.cs @@ -114,9 +114,9 @@ namespace UnityExplorer.UI.Panels if (NavButtonWanted) { if (active) - RuntimeProvider.Instance.SetColorBlock(NavButton.Button, UIManager.navButtonEnabledColor, UIManager.navButtonEnabledColor * 1.2f); + RuntimeProvider.Instance.SetColorBlock(NavButton.Button, UIManager.enabledButtonColor, UIManager.enabledButtonColor * 1.2f); else - RuntimeProvider.Instance.SetColorBlock(NavButton.Button, UIManager.navButtonDisabledColor, UIManager.navButtonDisabledColor * 1.2f); + RuntimeProvider.Instance.SetColorBlock(NavButton.Button, UIManager.disabledButtonColor, UIManager.disabledButtonColor * 1.2f); } } @@ -136,7 +136,7 @@ namespace UnityExplorer.UI.Panels NavButton = UIFactory.CreateButton(UIManager.NavbarButtonHolder, $"Button_{PanelType}", Name); UIFactory.SetLayoutElement(NavButton.Button.gameObject, minWidth: 118, flexibleWidth: 0); - RuntimeProvider.Instance.SetColorBlock(NavButton.Button, UIManager.navButtonDisabledColor, UIManager.navButtonDisabledColor * 1.2f); + RuntimeProvider.Instance.SetColorBlock(NavButton.Button, UIManager.disabledButtonColor, UIManager.disabledButtonColor * 1.2f); NavButton.OnClick += () => { UIManager.TogglePanel(PanelType); diff --git a/src/UI/UIFactory.cs b/src/UI/UIFactory.cs index dddb91c..db51a7a 100644 --- a/src/UI/UIFactory.cs +++ b/src/UI/UIFactory.cs @@ -729,9 +729,7 @@ namespace UnityExplorer.UI contentRect.pivot = new Vector2(0.5f, 1f); contentRect.sizeDelta = new Vector2(0f, 0f); contentRect.offsetMax = new Vector2(0f, 0f); - SetLayoutGroup(content, true, false, true, true, 0, 2, 2, 2, 2, TextAnchor.UpperCenter); - content.AddComponent().verticalFit = ContentSizeFitter.FitMode.PreferredSize; var scrollRect = mainObj.AddComponent(); diff --git a/src/UI/UIManager.cs b/src/UI/UIManager.cs index 920cab8..0cfd857 100644 --- a/src/UI/UIManager.cs +++ b/src/UI/UIManager.cs @@ -53,8 +53,8 @@ namespace UnityExplorer.UI public static RectTransform NavBarRect; public static GameObject NavbarButtonHolder; - internal static readonly Color navButtonEnabledColor = new Color(0.2f, 0.4f, 0.28f); - internal static readonly Color navButtonDisabledColor = new Color(0.25f, 0.25f, 0.25f); + internal static readonly Color enabledButtonColor = new Color(0.2f, 0.4f, 0.28f); + internal static readonly Color disabledButtonColor = new Color(0.25f, 0.25f, 0.25f); public const int MAX_INPUTFIELD_CHARS = 16000; diff --git a/src/UI/Utility/SignatureHighlighter.cs b/src/UI/Utility/SignatureHighlighter.cs index 2b73d0d..458276b 100644 --- a/src/UI/Utility/SignatureHighlighter.cs +++ b/src/UI/Utility/SignatureHighlighter.cs @@ -35,6 +35,12 @@ namespace UnityExplorer.UI.Utility public const string LOCAL_ARG = "#a6e9e9"; + internal const string ARRAY_TOKEN = "[]"; + internal const string OPEN_COLOR = "{ns}."); - - // Declaring type - - var declaring = type.DeclaringType; - while (declaring != null) + if (!isGeneric) { - syntaxBuilder.Append(HighlightType(declaring)); - syntaxBuilder.Append('.'); - declaring = declaring.DeclaringType; + if (includeNamespace && GetNamespace(type, out string ns)) + syntaxBuilder.Append(OPEN_COLOR).Append(NAMESPACE).Append('>').Append(ns).Append(CLOSE_COLOR).Append('.'); + + // Declaring type + + var declaring = type.DeclaringType; + while (declaring != null) + { + syntaxBuilder.Append(HighlightType(declaring)); + syntaxBuilder.Append('.'); + declaring = declaring.DeclaringType; + } } // Highlight the type name @@ -96,68 +105,101 @@ namespace UnityExplorer.UI.Utility { syntaxBuilder.Append('.'); - string memColor = GetMemberInfoColor(memberInfo, out bool isStatic); + //string memColor = GetMemberInfoColor(memberInfo, out bool isStatic); + + //if (isStatic) + // syntaxBuilder.Append(OPEN_ITALIC); + + //syntaxBuilder.Append($"{memberInfo.Name}{CLOSE_COLOR}"); + int start = syntaxBuilder.Length - 1; + syntaxBuilder.Append(OPEN_COLOR) + .Append(GetMemberInfoColor(memberInfo, out bool isStatic)) + .Append('>') + .Append(memberInfo.Name) + .Append(CLOSE_COLOR); if (isStatic) - syntaxBuilder.Append(""); - - syntaxBuilder.Append($"{memberInfo.Name}"); - - if (isStatic) - syntaxBuilder.Append(""); + { + syntaxBuilder.Insert(start, OPEN_ITALIC); + syntaxBuilder.Append(CLOSE_ITALIC); + } if (memberInfo is MethodInfo method) { var args = method.GetGenericArguments(); if (args.Length > 0) - syntaxBuilder.Append($"<{ParseGenericArgs(args, true)}>"); + //syntaxBuilder.Append($"<{ParseGenericArgs(args, true)}>"); + syntaxBuilder.Append('<').Append(ParseGenericArgs(args, true)).Append('>'); } } return syntaxBuilder.ToString(); } - public static string ParseFullType(Type type, bool includeNamespace = false, bool includeDllName = false) + public static string ParseType(Type type, bool includeNamespace = false, bool includeDllName = false) { - string ret = HighlightType(type); + var sb = new StringBuilder(); bool isGeneric = type.IsGenericParameter || (type.HasElementType && type.GetElementType().IsGenericParameter); if (!isGeneric && includeNamespace && GetNamespace(type, out string ns)) - ret = $"{ns}.{ret}"; + //sb.Append($"{ns}{CLOSE_COLOR}."); + sb.Append(OPEN_COLOR).Append(NAMESPACE).Append('>').Append(ns).Append(CLOSE_COLOR).Append('.'); + + sb.Append(HighlightType(type)); if (includeDllName) { if (!string.IsNullOrEmpty(type.Assembly.Location)) - ret = $"{ret} ({Path.GetFileName(type.Assembly.Location)})"; + //sb.Append($" ({Path.GetFileName(type.Assembly.Location)})"); + sb.Append(' ').Append('(').Append(Path.GetFileName(type.Assembly.Location)).Append(')'); else - ret = $"{ret} ({type.Assembly.GetName().Name})"; + //sb.Append($" ({type.Assembly.GetName().Name})"); + sb.Append(' ').Append('(').Append(type.Assembly.GetName().Name).Append(')'); } - return ret; + return sb.ToString(); } private static readonly Dictionary typeToRichType = new Dictionary(); + private static bool EndsWith(this StringBuilder sb, string _string) + { + int len = _string.Length; + + if (sb.Length < len) + return false; + + int stringpos = 0; + for (int i = sb.Length - len; i < sb.Length; i++, stringpos++) + { + if (sb[i] != _string[stringpos]) + return false; + } + return true; + } + private static string HighlightType(Type type) { string key = type.ToString(); if (typeToRichType.ContainsKey(key)) return typeToRichType[key]; - - var typeName = type.Name; + + var sb = new StringBuilder(type.Name); bool isArray = false; - if (typeName.EndsWith("[]")) + if (sb.EndsWith(ARRAY_TOKEN)) { isArray = true; - typeName = typeName.Substring(0, typeName.Length - 2); + sb.Remove(sb.Length - 2, 2); type = type.GetElementType(); } if (type.IsGenericParameter || (type.HasElementType && type.GetElementType().IsGenericParameter)) { - typeName = $"{typeName}"; + //typeName = $"{typeName}"; + sb.Insert(0, $""); + sb.Append(CLOSE_COLOR); } else { @@ -172,27 +214,33 @@ namespace UnityExplorer.UI.Utility int suffixLen = 1 + args.Length.ToString().Length; // make sure the typename actually has expected "`N" format. - if (typeName[typeName.Length - suffixLen] == '`') - typeName = typeName.Substring(0, typeName.Length - suffixLen); + if (sb[sb.Length - suffixLen] == '`') + //typeName = typeName.Substring(0, typeName.Length - suffixLen); + sb.Remove(sb.Length - suffixLen, suffixLen); } // highlight the base name itself // do this after removing the `N suffix, so only the name itself is in the color tags. - typeName = $"{typeName}"; + //typeName = $"{typeName}"; + sb.Insert(0, $"{OPEN_COLOR}{GetClassColor(type)}>"); + sb.Append(CLOSE_COLOR); // parse the generic args, if any if (args.Length > 0) { - typeName += $"<{ParseGenericArgs(args)}>"; + //typeName += $"<{ParseGenericArgs(args)}>"; + sb.Append('<').Append(ParseGenericArgs(args)).Append('>'); } } if (isArray) - typeName += "[]"; + //typeName += "[]"; + sb.Append('[').Append(']'); - typeToRichType.Add(key, typeName); + var ret = sb.ToString(); + typeToRichType.Add(key, ret); - return typeName; + return ret; } public static string ParseGenericArgs(Type[] args, bool isGenericParams = false) @@ -200,24 +248,27 @@ namespace UnityExplorer.UI.Utility if (args.Length < 1) return string.Empty; - string ret = ""; + //string ret = ""; + var sb = new StringBuilder(); for (int i = 0; i < args.Length; i++) { if (i > 0) - ret += ", "; + //ret += ", "; + sb.Append(',').Append(' '); if (isGenericParams) { - ret += $"{args[i].Name}"; + //ret += $"{args[i].Name}"; + sb.Append(OPEN_COLOR).Append(CONST).Append('>').Append(args[i].Name).Append(CLOSE_COLOR); continue; } - // using HighlightTypeName makes it recursive, so we can parse nested generic args. - ret += ParseFullType(args[i]); + //ret += ParseType(args[i]); + sb.Append(ParseType(args[i])); } - return ret; + return sb.ToString(); } public static string GetMemberInfoColor(MemberInfo memberInfo, out bool isStatic) diff --git a/src/UI/Utility/ToStringUtility.cs b/src/UI/Utility/ToStringUtility.cs index 433c481..4577a11 100644 --- a/src/UI/Utility/ToStringUtility.cs +++ b/src/UI/Utility/ToStringUtility.cs @@ -30,9 +30,6 @@ namespace UnityExplorer.UI.Utility string richType = SignatureHighlighter.ParseFullSyntax(type, includeNamespace); - //if (!includeName) - // return richType; - _stringBuilder.Clear(); if (value.IsNullOrDestroyed()) @@ -142,10 +139,20 @@ namespace UnityExplorer.UI.Utility value = value.TryCast(type); string toString; - 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]); + try + { + 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]); + } + catch (Exception ex) + { + toString = ex.ReflectionExToString(); + } + + string _ = null; + toString = ReflectionProvider.Instance.ProcessTypeFullNameInString(type, toString, ref _); return toString; } diff --git a/src/UI/Widgets/ScrollPool/UIExtensions.cs b/src/UI/Widgets/ScrollPool/UIExtensions.cs index bac135e..364fd7a 100644 --- a/src/UI/Widgets/ScrollPool/UIExtensions.cs +++ b/src/UI/Widgets/ScrollPool/UIExtensions.cs @@ -24,7 +24,7 @@ namespace UnityExplorer.UI public static float MinY(this RectTransform rect) => rect.position.y; - public static float MaxX(this RectTransform rect) => rect.position.x - rect.rect.width; + public static float MaxX(this RectTransform rect) => rect.position.x + rect.rect.width; public static float MinX(this RectTransform rect) => rect.position.x; } diff --git a/src/UnityExplorer.csproj b/src/UnityExplorer.csproj index 82e5f8d..b47ef84 100644 --- a/src/UnityExplorer.csproj +++ b/src/UnityExplorer.csproj @@ -246,6 +246,7 @@ +