1.4.5 (pre-release)

* Added support for MethodInfos with only primitive arguments on reflection window
* Added backup resize mode incase resizing experiences an exception
This commit is contained in:
sinaioutlander 2020-08-30 07:01:13 +10:00
parent 68eeee353e
commit 7dc58ea02c
8 changed files with 326 additions and 205 deletions

View File

@ -16,6 +16,10 @@ namespace Explorer
private bool m_evaluated = false; private bool m_evaluated = false;
private CacheObjectBase m_cachedReturnValue; private CacheObjectBase m_cachedReturnValue;
private bool m_isEvaluating;
private ParameterInfo[] m_arguments;
private string[] m_argumentInput;
public bool HasParameters public bool HasParameters
{ {
get get
@ -29,13 +33,6 @@ namespace Explorer
} }
private bool? m_hasParams; private bool? m_hasParams;
// ======= TODO =======
private bool m_isEvaluating;
private string[] m_argumentNames;
private Type[] m_argumentTypes;
private string[] m_argumentInput;
// =====================
public static bool CanEvaluate(MethodInfo mi) public static bool CanEvaluate(MethodInfo mi)
{ {
// generic type args not supported yet // generic type args not supported yet
@ -44,20 +41,14 @@ namespace Explorer
return false; return false;
} }
// TODO primitive params (commented out impl below) // only primitive and string args supported
if (mi.GetParameters().Length > 0) foreach (var param in mi.GetParameters())
{
if (!param.ParameterType.IsPrimitive && param.ParameterType != typeof(string))
{ {
return false; return false;
} }
}
//// only primitive and string args supported
//foreach (var param in mi.GetParameters())
//{
// if (!param.ParameterType.IsPrimitive && param.ParameterType != typeof(string))
// {
// return false;
// }
//}
return true; return true;
} }
@ -66,69 +57,68 @@ namespace Explorer
{ {
base.Init(); base.Init();
// TODO cache params var mi = MemberInfo as MethodInfo;
m_arguments = mi.GetParameters();
m_argumentInput = new string[m_arguments.Length];
} }
public override void UpdateValue() public override void UpdateValue()
{ {
base.UpdateValue(); base.UpdateValue();
// TODO update params (?)
}
private void Evaluate()
{
m_evaluated = true;
var mi = MemberInfo as MethodInfo;
object ret;
if (!HasParameters)
{
ret = mi.Invoke(mi.IsStatic ? null : DeclaringInstance, new object[0]);
}
else
{
// TODO parse params, invoke if valid
throw new NotImplementedException("TODO");
}
if (ret != null)
{
m_cachedReturnValue = GetCacheObject(ret);
if (m_cachedReturnValue is CacheList cacheList)
{
cacheList.WhiteSpace = 0f;
cacheList.ButtonWidthOffset += 70f;
}
m_cachedReturnValue.UpdateValue();
}
else
{
m_cachedReturnValue = null;
}
} }
public override void DrawValue(Rect window, float width) public override void DrawValue(Rect window, float width)
{ {
GUILayout.BeginVertical(null); GUILayout.BeginVertical(null);
GUILayout.BeginHorizontal(null); string evaluateLabel = "<color=lime>Evaluate</color>";
if (GUILayout.Button("Evaluate", new GUILayoutOption[] { GUILayout.Width(70) }))
{
if (HasParameters) if (HasParameters)
{ {
throw new NotImplementedException("TODO"); if (m_isEvaluating)
{
for (int i = 0; i < m_arguments.Length; i++)
{
var name = m_arguments[i].Name;
var input = m_argumentInput[i];
var type = m_arguments[i].ParameterType.Name;
GUILayout.BeginHorizontal(null);
m_argumentInput[i] = GUILayout.TextField(input, new GUILayoutOption[] { GUILayout.Width(150) });
GUILayout.Label(i + ": <color=cyan>" + name + "</color> <color=yellow>(" + type + ")</color>", null);
GUILayout.EndHorizontal();
}
GUILayout.BeginHorizontal(null);
if (GUILayout.Button(evaluateLabel, new GUILayoutOption[] { GUILayout.Width(70) }))
{
Evaluate();
m_isEvaluating = false;
}
if (GUILayout.Button("Cancel", new GUILayoutOption[] { GUILayout.Width(70) }))
{
m_isEvaluating = false;
}
} }
else else
{
GUILayout.BeginHorizontal(null);
if (GUILayout.Button($"Evaluate ({m_arguments.Length} params)", new GUILayoutOption[] { GUILayout.Width(150) }))
{
m_isEvaluating = true;
}
}
}
else
{
GUILayout.BeginHorizontal(null);
if (GUILayout.Button(evaluateLabel, new GUILayoutOption[] { GUILayout.Width(70) }))
{ {
Evaluate(); Evaluate();
} }
} }
GUI.skin.label.wordWrap = false;
GUILayout.Label($"<color=yellow>{ValueType}</color>", null);
GUI.skin.label.wordWrap = true;
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
@ -148,16 +138,88 @@ namespace Explorer
} }
else else
{ {
GUILayout.Label($"null", null); GUILayout.Label($"null (<color=yellow>{ValueType}</color>)", null);
} }
} }
else else
{ {
GUILayout.Label($"<color=grey><i>Not yet evaluated</i></color>", null); GUILayout.Label($"<color=grey><i>Not yet evaluated</i></color> (<color=yellow>{ValueType}</color>)", null);
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.EndVertical(); GUILayout.EndVertical();
} }
private void Evaluate()
{
m_evaluated = true;
var mi = MemberInfo as MethodInfo;
object ret = null;
if (!HasParameters)
{
ret = mi.Invoke(mi.IsStatic ? null : DeclaringInstance, new object[0]);
}
else
{
var arguments = new List<object>();
for (int i = 0; i < m_arguments.Length; i++)
{
var input = m_argumentInput[i];
var type = m_arguments[i].ParameterType;
if (type == typeof(string))
{
arguments.Add(input);
}
else
{
try
{
if (type.GetMethod("Parse", new Type[] { typeof(string) }).Invoke(null, new object[] { input }) is object parsed)
{
arguments.Add(parsed);
}
else
{
throw new Exception();
}
}
catch
{
MelonLogger.Log($"Unable to parse '{input}' to type '{type.Name}'");
break;
}
}
}
if (arguments.Count == m_arguments.Length)
{
ret = mi.Invoke(mi.IsStatic ? null : DeclaringInstance, arguments.ToArray());
}
else
{
MelonLogger.Log($"Did not invoke because {m_arguments.Length - arguments.Count} arguments could not be parsed!");
}
}
if (ret != null)
{
m_cachedReturnValue = GetCacheObject(ret);
if (m_cachedReturnValue is CacheList cacheList)
{
cacheList.WhiteSpace = 0f;
cacheList.ButtonWidthOffset += 70f;
}
m_cachedReturnValue.UpdateValue();
}
else
{
m_cachedReturnValue = null;
}
}
} }
} }

View File

@ -69,8 +69,8 @@ namespace Explorer
var newSkin = Object.Instantiate(GUI.skin); var newSkin = Object.Instantiate(GUI.skin);
Object.DontDestroyOnLoad(newSkin); Object.DontDestroyOnLoad(newSkin);
m_nofocusTex = MakeTex(550, 700, new Color(0.1f, 0.1f, 0.1f, 0.7f)); m_nofocusTex = MakeTex(1, 1, new Color(0.1f, 0.1f, 0.1f, 0.7f));
m_focusTex = MakeTex(550, 700, new Color(0.3f, 0.3f, 0.3f, 1f)); m_focusTex = MakeTex(1, 1, new Color(0.3f, 0.3f, 0.3f, 1f));
newSkin.window.normal.background = m_nofocusTex; newSkin.window.normal.background = m_nofocusTex;
newSkin.window.onNormal.background = m_focusTex; newSkin.window.onNormal.background = m_focusTex;

View File

@ -12,7 +12,7 @@ namespace Explorer
public class GameObjectWindow : UIWindow public class GameObjectWindow : UIWindow
{ {
public override string Title => WindowManager.TabView public override string Title => WindowManager.TabView
? m_object.name ? $"<color=cyan>[G]</color> {m_object.name}"
: $"GameObject Inspector ({m_object.name})"; : $"GameObject Inspector ({m_object.name})";
public GameObject m_object; public GameObject m_object;

View File

@ -13,13 +13,13 @@ namespace Explorer
public class ReflectionWindow : UIWindow public class ReflectionWindow : UIWindow
{ {
public override string Title => WindowManager.TabView public override string Title => WindowManager.TabView
? ObjectType.Name ? $"<color=cyan>[R]</color> {ObjectType.Name}"
: $"Reflection Inspector ({ObjectType.Name})"; : $"Reflection Inspector ({ObjectType.Name})";
public Type ObjectType; public Type ObjectType;
private CacheObjectBase[] m_cachedMembers; private CacheObjectBase[] m_allCachedMembers;
private CacheObjectBase[] m_cachedMemberFiltered; private CacheObjectBase[] m_cachedMembersFiltered;
private int m_pageOffset; private int m_pageOffset;
private int m_limitPerPage = 20; private int m_limitPerPage = 20;
@ -72,7 +72,7 @@ namespace Explorer
public override void Update() public override void Update()
{ {
m_cachedMemberFiltered = m_cachedMembers.Where(x => ShouldProcessMember(x)).ToArray(); m_cachedMembersFiltered = m_allCachedMembers.Where(x => ShouldProcessMember(x)).ToArray();
if (m_autoUpdate) if (m_autoUpdate)
{ {
@ -82,7 +82,7 @@ namespace Explorer
private void UpdateValues() private void UpdateValues()
{ {
foreach (var member in m_cachedMemberFiltered) foreach (var member in m_cachedMembersFiltered)
{ {
member.UpdateValue(); member.UpdateValue();
} }
@ -140,7 +140,7 @@ namespace Explorer
{ {
if (member.MemberType == MemberTypes.Field || member.MemberType == MemberTypes.Property || member.MemberType == MemberTypes.Method) if (member.MemberType == MemberTypes.Field || member.MemberType == MemberTypes.Property || member.MemberType == MemberTypes.Method)
{ {
if (member.Name.Contains("Il2CppType") || member.Name.StartsWith("get_")) if (member.Name.Contains("Il2CppType") || member.Name.StartsWith("get_") || member.Name.StartsWith("set_"))
continue; continue;
try try
@ -165,7 +165,7 @@ namespace Explorer
} }
} }
m_cachedMembers = list.ToArray(); m_allCachedMembers = list.ToArray();
} }
// =========== GUI DRAW =========== // // =========== GUI DRAW =========== //
@ -174,6 +174,8 @@ namespace Explorer
{ {
try try
{ {
// ====== HEADER ======
var rect = WindowManager.TabView ? TabViewWindow.Instance.m_rect : this.m_rect; var rect = WindowManager.TabView ? TabViewWindow.Instance.m_rect : this.m_rect;
if (!WindowManager.TabView) if (!WindowManager.TabView)
@ -241,18 +243,17 @@ namespace Explorer
GUILayout.Space(10); GUILayout.Space(10);
// prev/next page buttons // prev/next page buttons
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Label("<b>Limit per page:</b>", new GUILayoutOption[] { GUILayout.Width(125) }); GUILayout.Label("<b>Limit per page:</b>", new GUILayoutOption[] { GUILayout.Width(125) });
var limitString = m_limitPerPage.ToString(); var limitString = m_limitPerPage.ToString();
limitString = GUILayout.TextField(limitString, new GUILayoutOption[] { GUILayout.Width(60) }); limitString = GUILayout.TextField(limitString, new GUILayoutOption[] { GUILayout.Width(60) });
if (int.TryParse(limitString, out int i)) if (int.TryParse(limitString, out int lim))
{ {
m_limitPerPage = i; m_limitPerPage = lim;
} }
int count = m_cachedMemberFiltered.Length; int count = m_cachedMembersFiltered.Length;
if (count > m_limitPerPage) if (count > m_limitPerPage)
{ {
int maxOffset = (int)Mathf.Ceil((float)(count / (decimal)m_limitPerPage)) - 1; int maxOffset = (int)Mathf.Ceil((float)(count / (decimal)m_limitPerPage)) - 1;
@ -274,12 +275,47 @@ namespace Explorer
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
// ====== BODY ======
scroll = GUILayout.BeginScrollView(scroll, GUI.skin.scrollView); scroll = GUILayout.BeginScrollView(scroll, GUI.skin.scrollView);
GUILayout.Space(10); GUILayout.Space(10);
DrawMembers(this.m_cachedMemberFiltered); UIStyles.HorizontalLine(Color.grey);
GUILayout.BeginVertical(GUI.skin.box, null);
int index = 0;
var members = this.m_cachedMembersFiltered;
int offsetIndex = (m_pageOffset * m_limitPerPage) + index;
if (offsetIndex >= count)
{
int maxOffset = (int)Mathf.Ceil((float)(m_cachedMembersFiltered.Length / (decimal)m_limitPerPage)) - 1;
if (m_pageOffset > maxOffset)
{
m_pageOffset = 0;
}
}
for (int j = offsetIndex; (j < offsetIndex + m_limitPerPage && j < members.Length); j++)
{
var holder = members[j];
GUILayout.BeginHorizontal(new GUILayoutOption[] { GUILayout.Height(25) });
try
{
holder.Draw(rect, 180f);
}
catch { }
GUILayout.EndHorizontal();
index++;
}
GUILayout.EndVertical();
GUILayout.EndScrollView(); GUILayout.EndScrollView();
if (!WindowManager.TabView) if (!WindowManager.TabView)
@ -289,69 +325,21 @@ namespace Explorer
GUILayout.EndArea(); GUILayout.EndArea();
} }
} }
catch (Il2CppException e)
{
if (!e.Message.Contains("in a group with only"))
{
throw;
}
}
catch (Exception e) catch (Exception e)
{ {
MelonLogger.LogWarning("Exception on window draw. Message: " + e.Message); MelonLogger.LogWarning("Exception drawing ReflectionWindow: " + e.GetType() + ", " + e.Message);
DestroyWindow(); DestroyWindow();
return; return;
} }
} }
private void DrawMembers(CacheObjectBase[] members)
{
// todo pre-cache list based on current search, otherwise this doesnt work.
int i = 0;
DrawMembersInternal("Properties", MemberTypes.Property, members, ref i);
DrawMembersInternal("Fields", MemberTypes.Field, members, ref i);
DrawMembersInternal("Methods", MemberTypes.Method, members, ref i);
}
private void DrawMembersInternal(string title, MemberTypes filter, CacheObjectBase[] members, ref int index)
{
if (m_filter != filter && m_filter != MemberTypes.All)
{
return;
}
var rect = WindowManager.TabView ? TabViewWindow.Instance.m_rect : this.m_rect;
UIStyles.HorizontalLine(Color.grey);
GUILayout.Label($"<size=18><b><color=gold>{title}</color></b></size>", null);
int offset = (m_pageOffset * m_limitPerPage) + index;
if (offset >= m_cachedMemberFiltered.Length)
{
m_pageOffset = 0;
offset = 0;
}
for (int j = offset; j < offset + m_limitPerPage && j < members.Length; j++)
{
var holder = members[j];
if (holder.MemberInfoType != filter || !ShouldProcessMember(holder)) continue;
GUILayout.BeginHorizontal(new GUILayoutOption[] { GUILayout.Height(25) });
try
{
holder.Draw(rect, 180f);
}
catch // (Exception e)
{
//MelonLogger.Log("Exception drawing member " + holder.MemberInfo.Name);
//MelonLogger.Log(e.GetType() + ", " + e.Message);
//MelonLogger.Log(e.StackTrace);
}
GUILayout.EndHorizontal();
index++;
if (index >= m_limitPerPage) break;
}
}
private void FilterToggle(MemberTypes mode, string label) private void FilterToggle(MemberTypes mode, string label)
{ {
if (m_filter == mode) if (m_filter == mode)
@ -365,6 +353,7 @@ namespace Explorer
if (GUILayout.Button(label, new GUILayoutOption[] { GUILayout.Width(100) })) if (GUILayout.Button(label, new GUILayoutOption[] { GUILayout.Width(100) }))
{ {
m_filter = mode; m_filter = mode;
m_pageOffset = 0;
} }
GUI.color = Color.white; GUI.color = Color.white;
} }

View File

@ -20,8 +20,8 @@ namespace Explorer
public static Rect ResizeWindow(Rect _rect, int ID) public static Rect ResizeWindow(Rect _rect, int ID)
{ {
if (RESIZE_FAILED) return _rect; if (!RESIZE_FAILED)
{
var origRect = _rect; var origRect = _rect;
try try
@ -69,6 +69,36 @@ namespace Explorer
} }
GUI.skin.label.alignment = TextAnchor.UpperLeft; GUI.skin.label.alignment = TextAnchor.UpperLeft;
}
else
{
GUILayout.BeginHorizontal(GUI.skin.box, null);
GUILayout.Label("Resize window:", new GUILayoutOption[] { GUILayout.Width(100) });
GUI.skin.label.alignment = TextAnchor.MiddleRight;
GUILayout.Label("<color=cyan>Width:</color>", new GUILayoutOption[] { GUILayout.Width(60) });
if (GUILayout.RepeatButton("-", new GUILayoutOption[] { GUILayout.Width(20) }))
{
_rect.width -= 5f;
}
if (GUILayout.RepeatButton("+", new GUILayoutOption[] { GUILayout.Width(20) }))
{
_rect.width += 5f;
}
GUILayout.Label("<color=cyan>Height:</color>", new GUILayoutOption[] { GUILayout.Width(60) });
if (GUILayout.RepeatButton("-", new GUILayoutOption[] { GUILayout.Width(20) }))
{
_rect.height -= 5f;
}
if (GUILayout.RepeatButton("+", new GUILayoutOption[] { GUILayout.Width(20) }))
{
_rect.height += 5f;
}
GUILayout.EndHorizontal();
GUI.skin.label.alignment = TextAnchor.UpperLeft;
}
return _rect; return _rect;
} }

View File

@ -3,17 +3,19 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using MelonLoader;
using UnityEngine; using UnityEngine;
namespace Explorer namespace Explorer
{ {
public class TabViewWindow : UIWindow public class TabViewWindow : UIWindow
{ {
public override string Title => "Tab View"; public override string Title => $"Tabs ({WindowManager.Windows.Count})";
public static TabViewWindow Instance => m_instance ?? (m_instance = new TabViewWindow()); public static TabViewWindow Instance => m_instance ?? (m_instance = new TabViewWindow());
private static TabViewWindow m_instance; private static TabViewWindow m_instance;
private UIWindow m_targetWindow;
public int TargetTabID = 0; public int TargetTabID = 0;
public override bool IsTabViewWindow => true; public override bool IsTabViewWindow => true;
@ -24,13 +26,43 @@ namespace Explorer
} }
public override void Init() { } public override void Init() { }
public override void Update() { } public override void Update()
{
while (TargetTabID >= WindowManager.Windows.Count)
{
TargetTabID--;
}
if (TargetTabID == -1 && WindowManager.Windows.Count > 0)
{
TargetTabID = 0;
}
if (TargetTabID >= 0)
{
m_targetWindow = WindowManager.Windows[TargetTabID];
}
else
{
m_targetWindow = null;
}
m_targetWindow?.Update();
}
public override void WindowFunction(int windowID) public override void WindowFunction(int windowID)
{ {
try try
{ {
Header(); GUI.DragWindow(new Rect(0, 0, m_rect.width - 90, 20));
if (GUI.Button(new Rect(m_rect.width - 90, 2, 80, 20), "<color=red>Close All</color>"))
{
foreach (var window in WindowManager.Windows)
{
window.DestroyWindow();
}
return;
}
GUILayout.BeginArea(new Rect(5, 25, m_rect.width - 10, m_rect.height - 35), GUI.skin.box); GUILayout.BeginArea(new Rect(5, 25, m_rect.width - 10, m_rect.height - 35), GUI.skin.box);
@ -51,6 +83,7 @@ namespace Explorer
bool focused = i == TargetTabID; bool focused = i == TargetTabID;
string color = focused ? "<color=lime>" : "<color=orange>"; string color = focused ? "<color=lime>" : "<color=orange>";
GUI.color = focused ? Color.green : Color.white;
var window = WindowManager.Windows[i]; var window = WindowManager.Windows[i];
if (GUILayout.Button(color + window.Title + "</color>", new GUILayoutOption[] { GUILayout.Width(200) })) if (GUILayout.Button(color + window.Title + "</color>", new GUILayoutOption[] { GUILayout.Width(200) }))
@ -62,20 +95,12 @@ namespace Explorer
window.DestroyWindow(); window.DestroyWindow();
} }
} }
GUI.color = Color.white;
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.EndVertical(); GUILayout.EndVertical();
GUI.skin.button.alignment = TextAnchor.MiddleCenter; GUI.skin.button.alignment = TextAnchor.MiddleCenter;
while (TargetTabID >= WindowManager.Windows.Count) m_targetWindow.WindowFunction(m_targetWindow.windowID);
{
TargetTabID--;
}
if (TargetTabID >= 0)
{
var window = WindowManager.Windows[TargetTabID];
window.WindowFunction(window.windowID);
}
try try
{ {

View File

@ -7,8 +7,6 @@ using MelonLoader;
using UnhollowerBaseLib; using UnhollowerBaseLib;
using UnhollowerRuntimeLib; using UnhollowerRuntimeLib;
using UnityEngine; using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
namespace Explorer namespace Explorer
{ {
@ -46,15 +44,7 @@ namespace Explorer
public void DestroyWindow() public void DestroyWindow()
{ {
try WindowManager.DestroyWindow(this);
{
WindowManager.Windows.Remove(this);
}
catch (Exception e)
{
MelonLogger.Log("Exception removing Window from WindowManager.Windows list!");
MelonLogger.Log($"{e.GetType()} : {e.Message}\r\n{e.StackTrace}");
}
} }
public void OnGUI() public void OnGUI()
@ -72,12 +62,10 @@ namespace Explorer
public void Header() public void Header()
{ {
if (!WindowManager.TabView || IsTabViewWindow)
{
GUI.DragWindow(new Rect(0, 0, m_rect.width - 90, 20));
}
if (!WindowManager.TabView) if (!WindowManager.TabView)
{ {
GUI.DragWindow(new Rect(0, 0, m_rect.width - 90, 20));
if (GUI.Button(new Rect(m_rect.width - 90, 2, 80, 20), "<color=red><b>X</b></color>")) if (GUI.Button(new Rect(m_rect.width - 90, 2, 80, 20), "<color=red><b>X</b></color>"))
{ {
DestroyWindow(); DestroyWindow();

View File

@ -22,12 +22,38 @@ namespace Explorer
public static int CurrentWindowID { get; set; } = 500000; public static int CurrentWindowID { get; set; } = 500000;
private static Rect m_lastWindowRect; private static Rect m_lastWindowRect;
private static readonly List<UIWindow> m_windowsToDestroy = new List<UIWindow>();
public WindowManager() public WindowManager()
{ {
Instance = this; Instance = this;
} }
public static void DestroyWindow(UIWindow window)
{
m_windowsToDestroy.Add(window);
}
public void Update() public void Update()
{
if (m_windowsToDestroy.Count > 0)
{
foreach (var window in m_windowsToDestroy)
{
if (Windows.Contains(window))
{
Windows.Remove(window);
}
}
m_windowsToDestroy.Clear();
}
if (TabView)
{
TabViewWindow.Instance.Update();
}
else
{ {
for (int i = 0; i < Windows.Count; i++) for (int i = 0; i < Windows.Count; i++)
{ {
@ -38,6 +64,7 @@ namespace Explorer
} }
} }
} }
}
public void OnGUI() public void OnGUI()
{ {