diff --git a/src/CachedObjects/CacheEnum.cs b/src/CachedObjects/CacheEnum.cs
index 90fdae3..d8a182b 100644
--- a/src/CachedObjects/CacheEnum.cs
+++ b/src/CachedObjects/CacheEnum.cs
@@ -10,21 +10,18 @@ namespace Explorer
{
public class CacheEnum : CacheObject
{
- private readonly Type m_enumType;
- private readonly string[] m_names;
+ public Type EnumType;
+ public string[] EnumNames;
- public CacheEnum(object obj)
+ public override void Init()
{
- if (obj != null)
- {
- m_enumType = obj.GetType();
- m_names = Enum.GetNames(m_enumType);
- }
+ EnumType = Value.GetType();
+ EnumNames = Enum.GetNames(EnumType);
}
public override void DrawValue(Rect window, float width)
{
- if (MemberInfo != null)
+ if (CanWrite)
{
if (GUILayout.Button("<", new GUILayoutOption[] { GUILayout.Width(25) }))
{
@@ -38,34 +35,18 @@ namespace Explorer
}
}
- GUILayout.Label(Value.ToString(), null);
- }
-
- public override void SetValue()
- {
- if (MemberInfo == null)
- {
- MelonLogger.Log("Trying to SetValue but the MemberInfo is null!");
- return;
- }
-
- if (Enum.Parse(m_enumType, Value.ToString()) is object enumValue && enumValue != null)
- {
- Value = enumValue;
- }
-
- SetValue(Value, MemberInfo, DeclaringInstance);
+ GUILayout.Label(Value.ToString(), null);// + " (" + ValueType + ")", null);
}
public void SetEnum(ref object value, int change)
{
- var names = m_names.ToList();
+ var names = EnumNames.ToList();
int newindex = names.IndexOf(value.ToString()) + change;
if ((change < 0 && newindex >= 0) || (change > 0 && newindex < names.Count))
{
- value = Enum.Parse(m_enumType, names[newindex]);
+ value = Enum.Parse(EnumType, names[newindex]);
}
}
}
diff --git a/src/CachedObjects/CacheGameObject.cs b/src/CachedObjects/CacheGameObject.cs
index 7025531..417093b 100644
--- a/src/CachedObjects/CacheGameObject.cs
+++ b/src/CachedObjects/CacheGameObject.cs
@@ -10,44 +10,37 @@ namespace Explorer
{
public class CacheGameObject : CacheObject
{
- private GameObject m_gameObject;
-
- public CacheGameObject(object obj)
+ private GameObject GameObj
{
- if (obj != null)
- m_gameObject = GetGameObject(obj);
- }
-
- private GameObject GetGameObject(object obj)
- {
- if (obj is Il2CppSystem.Object ilObj)
+ get
{
- var ilType = ilObj.GetIl2CppType();
-
- if (ilType == ReflectionHelpers.GameObjectType || ilType == ReflectionHelpers.TransformType)
+ if (m_gameObject == null)
{
- return ilObj.TryCast() ?? ilObj.TryCast()?.gameObject;
- }
- }
+ if (Value is Il2CppSystem.Object ilObj)
+ {
+ var ilType = ilObj.GetIl2CppType();
- return null;
+ if (ilType == ReflectionHelpers.GameObjectType || ilType == ReflectionHelpers.TransformType)
+ {
+ m_gameObject = ilObj.TryCast() ?? ilObj.TryCast()?.gameObject;
+ }
+ }
+ }
+
+ return m_gameObject;
+ }
}
+ private GameObject m_gameObject;
+
public override void DrawValue(Rect window, float width)
{
- UIHelpers.GameobjButton(m_gameObject, null, false, width);
- }
-
- public override void SetValue()
- {
- throw new NotImplementedException("TODO");
+ UIHelpers.GameobjButton(GameObj, null, false, width);
}
public override void UpdateValue()
{
base.UpdateValue();
-
- m_gameObject = GetGameObject(Value);
}
}
}
diff --git a/src/CachedObjects/CacheList.cs b/src/CachedObjects/CacheList.cs
index 5a0f82a..7dfd644 100644
--- a/src/CachedObjects/CacheList.cs
+++ b/src/CachedObjects/CacheList.cs
@@ -14,6 +14,7 @@ namespace Explorer
{
public bool IsExpanded { get; set; }
public int ArrayOffset { get; set; }
+ public int ArrayLimit { get; set; } = 20;
public Type EntryType
{
@@ -47,15 +48,6 @@ namespace Explorer
private IEnumerable m_enumerable;
private CacheObject[] m_cachedEntries;
- public CacheList(object obj)
- {
- if (obj != null)
- {
- Value = obj;
- EntryType = obj.GetType().GetGenericArguments()[0];
- }
- }
-
private IEnumerable CppListToEnumerable(object list)
{
if (EntryType == null) return null;
@@ -95,12 +87,12 @@ namespace Explorer
if (IsExpanded)
{
- if (count > CppExplorer.ArrayLimit)
+ if (count > ArrayLimit)
{
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal(null);
GUILayout.Space(190);
- int maxOffset = (int)Mathf.Ceil((float)(count / (decimal)CppExplorer.ArrayLimit)) - 1;
+ int maxOffset = (int)Mathf.Ceil((float)(count / (decimal)ArrayLimit)) - 1;
GUILayout.Label($"Page {ArrayOffset + 1}/{maxOffset + 1}", new GUILayoutOption[] { GUILayout.Width(80) });
// prev/next page buttons
if (GUILayout.Button("< Prev", null))
@@ -111,13 +103,20 @@ namespace Explorer
{
if (ArrayOffset < maxOffset) ArrayOffset++;
}
+ GUILayout.Label("Limit: ", new GUILayoutOption[] { GUILayout.Width(50) });
+ var limit = this.ArrayLimit.ToString();
+ limit = GUILayout.TextField(limit, new GUILayoutOption[] { GUILayout.Width(50) });
+ if (limit != ArrayLimit.ToString() && int.TryParse(limit, out int i))
+ {
+ ArrayLimit = i;
+ }
}
- int offset = ArrayOffset * CppExplorer.ArrayLimit;
+ int offset = ArrayOffset * ArrayLimit;
if (offset >= count) offset = 0;
- for (int i = offset; i < offset + CppExplorer.ArrayLimit && i < count; i++)
+ for (int i = offset; i < offset + ArrayLimit && i < count; i++)
{
var entry = m_cachedEntries[i];
@@ -140,11 +139,6 @@ namespace Explorer
}
}
- public override void SetValue()
- {
- throw new NotImplementedException("TODO");
- }
-
///
/// Called when the user presses the "Update" button, or if AutoUpdate is on.
///
@@ -161,7 +155,7 @@ namespace Explorer
var list = new List();
while (enumerator.MoveNext())
{
- list.Add(GetCacheObject(enumerator.Current));
+ list.Add(GetCacheObject(enumerator.Current, null, null, this.EntryType));
}
m_cachedEntries = list.ToArray();
diff --git a/src/CachedObjects/CacheObject.cs b/src/CachedObjects/CacheObject.cs
index 505a0c2..2240025 100644
--- a/src/CachedObjects/CacheObject.cs
+++ b/src/CachedObjects/CacheObject.cs
@@ -17,15 +17,45 @@ namespace Explorer
// Reflection window only
public MemberInfo MemberInfo { get; set; }
- public ReflectionWindow.MemberInfoType MemberInfoType { get; set; }
+ // public ReflectionWindow.MemberInfoType MemberInfoType { get; set; }
public Type DeclaringType { get; set; }
public object DeclaringInstance { get; set; }
public string FullName => $"{MemberInfo.DeclaringType.Name}.{MemberInfo.Name}";
public string ReflectionException;
+ public bool CanWrite
+ {
+ get
+ {
+ if (MemberInfo is FieldInfo fi)
+ {
+ return !(fi.IsLiteral && !fi.IsInitOnly);
+ }
+ else if (MemberInfo is PropertyInfo pi)
+ {
+ return pi.CanWrite;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ public ReflectionWindow.MemberInfoType MemberInfoType
+ {
+ get
+ {
+ if (MemberInfo is FieldInfo) return ReflectionWindow.MemberInfoType.Field;
+ if (MemberInfo is PropertyInfo) return ReflectionWindow.MemberInfoType.Property;
+ if (MemberInfo is MethodInfo) return ReflectionWindow.MemberInfoType.Method;
+ return ReflectionWindow.MemberInfoType.All;
+ }
+ }
+
// methods
+ public virtual void Init() { }
public abstract void DrawValue(Rect window, float width);
- public abstract void SetValue();
public static CacheObject GetCacheObject(object obj)
{
@@ -41,63 +71,72 @@ namespace Explorer
///
public static CacheObject GetCacheObject(object obj, MemberInfo memberInfo, object declaringInstance)
{
- CacheObject holder;
-
var type = ReflectionHelpers.GetActualType(obj) ?? (memberInfo as FieldInfo)?.FieldType ?? (memberInfo as PropertyInfo)?.PropertyType;
+ if (type == null)
+ {
+ MelonLogger.Log("Could not get type for object or memberinfo!");
+ return null;
+ }
+
+ return GetCacheObject(obj, memberInfo, declaringInstance, type);
+ }
+
+ ///
+ /// Gets the CacheObject subclass for an object or MemberInfo
+ ///
+ /// The current value (can be null if memberInfo is not null)
+ /// The MemberInfo (can be null if obj is not null)
+ /// If MemberInfo is not null, the declaring class instance. Can be null if static.
+ /// The type of the object or MemberInfo value.
+ ///
+ public static CacheObject GetCacheObject(object obj, MemberInfo memberInfo, object declaringInstance, Type type)
+ {
+ CacheObject holder;
+
if ((obj is Il2CppSystem.Object || typeof(Il2CppSystem.Object).IsAssignableFrom(type))
&& (type.FullName.Contains("UnityEngine.GameObject") || type.FullName.Contains("UnityEngine.Transform")))
{
- holder = new CacheGameObject(obj);
+ holder = new CacheGameObject();
}
else if (type.IsPrimitive || type == typeof(string))
{
- holder = new CachePrimitive(obj);
+ holder = new CachePrimitive();
}
else if (type.IsEnum)
{
- holder = new CacheEnum(obj);
+ holder = new CacheEnum();
}
else if (typeof(System.Collections.IEnumerable).IsAssignableFrom(type) || ReflectionHelpers.IsList(type))
{
- holder = new CacheList(obj);
+ holder = new CacheList();
}
else
{
holder = new CacheOther();
}
- if (memberInfo != null)
- {
- holder.MemberInfo = memberInfo;
- holder.DeclaringType = memberInfo.DeclaringType;
- holder.DeclaringInstance = declaringInstance;
-
- if (memberInfo.MemberType == MemberTypes.Field)
- {
- holder.MemberInfoType = ReflectionWindow.MemberInfoType.Field;
- }
- else if (memberInfo.MemberType == MemberTypes.Property)
- {
- holder.MemberInfoType = ReflectionWindow.MemberInfoType.Property;
- }
- else if (memberInfo.MemberType == MemberTypes.Method)
- {
- holder.MemberInfoType = ReflectionWindow.MemberInfoType.Method;
- }
- }
-
holder.Value = obj;
holder.ValueType = type.FullName;
+ if (memberInfo != null)
+ {
+ holder.MemberInfo = memberInfo;
+ holder.DeclaringType = memberInfo.DeclaringType;
+ holder.DeclaringInstance = declaringInstance;
+ }
+
+ holder.UpdateValue();
+ holder.Init();
+
return holder;
}
- public void Draw(Rect window, float labelWidth = 180f)
+ public void Draw(Rect window, float labelWidth = 215f)
{
if (MemberInfo != null)
{
- GUILayout.Label("" + FullName + ":", new GUILayoutOption[] { GUILayout.Width(labelWidth) });
+ GUILayout.Label("" + FullName + "", new GUILayoutOption[] { GUILayout.Width(labelWidth) });
}
else
{
@@ -110,7 +149,7 @@ namespace Explorer
}
else if (Value == null)
{
- GUILayout.Label("null (" + this.ValueType + ")", null);
+ GUILayout.Label("null (" + ValueType + ")", null);
}
else
{
@@ -147,25 +186,19 @@ namespace Explorer
}
}
- public void SetValue(object value, MemberInfo memberInfo, object declaringInstance)
+ public void SetValue()
{
try
{
- if (memberInfo.MemberType == MemberTypes.Field)
+ if (MemberInfo.MemberType == MemberTypes.Field)
{
- var fi = memberInfo as FieldInfo;
- if (!(fi.IsLiteral && !fi.IsInitOnly))
- {
- fi.SetValue(fi.IsStatic ? null : declaringInstance, value);
- }
+ var fi = MemberInfo as FieldInfo;
+ fi.SetValue(fi.IsStatic ? null : DeclaringInstance, Value);
}
- else if (memberInfo.MemberType == MemberTypes.Property)
+ else if (MemberInfo.MemberType == MemberTypes.Property)
{
- var pi = memberInfo as PropertyInfo;
- if (pi.CanWrite)
- {
- pi.SetValue(pi.GetAccessors()[0].IsStatic ? null : declaringInstance, value);
- }
+ var pi = MemberInfo as PropertyInfo;
+ pi.SetValue(pi.GetAccessors()[0].IsStatic ? null : DeclaringInstance, Value);
}
}
catch (Exception e)
diff --git a/src/CachedObjects/CacheOther.cs b/src/CachedObjects/CacheOther.cs
index d2adf85..f101b96 100644
--- a/src/CachedObjects/CacheOther.cs
+++ b/src/CachedObjects/CacheOther.cs
@@ -58,21 +58,11 @@ namespace Explorer
}
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
- if (GUILayout.Button("" + label + "", new GUILayoutOption[] { GUILayout.MaxWidth(width) }))
+ if (GUILayout.Button("" + label + "", new GUILayoutOption[] { GUILayout.MaxWidth(width + 40) }))
{
WindowManager.InspectObject(Value, out bool _);
}
GUI.skin.button.alignment = TextAnchor.MiddleCenter;
}
-
- public override void SetValue()
- {
- throw new NotImplementedException("TODO");
- }
-
- //public override void UpdateValue(object obj)
- //{
-
- //}
}
}
diff --git a/src/CachedObjects/CachePrimitive.cs b/src/CachedObjects/CachePrimitive.cs
index 26be983..0c7fbfa 100644
--- a/src/CachedObjects/CachePrimitive.cs
+++ b/src/CachedObjects/CachePrimitive.cs
@@ -1,8 +1,5 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using System.Reflection;
using MelonLoader;
using UnityEngine;
@@ -10,7 +7,7 @@ namespace Explorer
{
public class CachePrimitive : CacheObject
{
- public enum PrimitiveType
+ public enum PrimitiveTypes
{
Bool,
Double,
@@ -19,69 +16,122 @@ namespace Explorer
String
}
- private readonly PrimitiveType m_primitiveType;
+ private string m_valueToString;
- public CachePrimitive(object obj)
+ public PrimitiveTypes PrimitiveType;
+
+ public MethodInfo ParseMethod
{
- if (obj == null) return;
+ get
+ {
+ if (m_parseMethod == null)
+ {
+ Type t = null;
+ switch (PrimitiveType)
+ {
+ case PrimitiveTypes.Bool:
+ t = typeof(bool); break;
+ case PrimitiveTypes.Double:
+ t = typeof(double); break;
+ case PrimitiveTypes.Float:
+ t = typeof(float); break;
+ case PrimitiveTypes.Int:
+ t = typeof(int); break;
+ case PrimitiveTypes.String:
+ t = typeof(string); break;
+ }
+ m_parseMethod = t.GetMethod("Parse", new Type[] { typeof(string) });
+ }
+ return m_parseMethod;
+ }
+ }
- if (obj is bool)
+ private MethodInfo m_parseMethod;
+
+ public override void Init()
+ {
+ if (Value == null)
{
- m_primitiveType = PrimitiveType.Bool;
+ // this must mean it is a string? no other primitive type should be nullable
+ PrimitiveType = PrimitiveTypes.String;
+ return;
}
- else if (obj is double)
+
+ m_valueToString = Value.ToString();
+ var type = Value.GetType();
+
+ if (type == typeof(bool))
{
- m_primitiveType = PrimitiveType.Double;
+ PrimitiveType = PrimitiveTypes.Bool;
}
- else if (obj is float)
+ else if (type == typeof(double))
{
- m_primitiveType = PrimitiveType.Float;
+ PrimitiveType = PrimitiveTypes.Double;
}
- else if (obj is int || obj is IntPtr || obj is uint)
+ else if (type == typeof(float))
{
- m_primitiveType = PrimitiveType.Int;
+ PrimitiveType = PrimitiveTypes.Float;
}
- else if (obj is string)
+ else if (type == typeof(int) || type == typeof(long) || type == typeof(uint) || type == typeof(ulong) || type == typeof(IntPtr))
{
- m_primitiveType = PrimitiveType.String;
+ PrimitiveType = PrimitiveTypes.Int;
}
+ else
+ {
+ if (type != typeof(string))
+ {
+ MelonLogger.Log("Unsupported primitive: " + type);
+ }
+
+ PrimitiveType = PrimitiveTypes.String;
+ }
+ }
+
+ public override void UpdateValue()
+ {
+ base.UpdateValue();
+
+ m_valueToString = Value?.ToString();
}
public override void DrawValue(Rect window, float width)
{
- if (m_primitiveType == PrimitiveType.Bool && Value is bool b)
+ if (PrimitiveType == PrimitiveTypes.Bool)
{
+ var b = (bool)Value;
var color = "" : "red>");
- Value = GUILayout.Toggle((bool)Value, color + Value.ToString() + "", null);
+ b = GUILayout.Toggle(b, color + b.ToString() + "", null);
if (b != (bool)Value)
{
- SetValue();
+ SetValue(m_valueToString);
}
}
else
{
- var toString = Value.ToString();
- if (toString.Length > 37)
+ GUILayout.Label("" + PrimitiveType + "", new GUILayoutOption[] { GUILayout.Width(50) });
+
+ var _width = window.width - 200;
+ if (m_valueToString.Length > 37)
{
- Value = GUILayout.TextArea(toString, new GUILayoutOption[] { GUILayout.MaxWidth(window.width - 260) });
+ m_valueToString = GUILayout.TextArea(m_valueToString, new GUILayoutOption[] { GUILayout.MaxWidth(_width) });
}
else
{
- Value = GUILayout.TextField(toString, new GUILayoutOption[] { GUILayout.MaxWidth(window.width - 260) });
+ m_valueToString = GUILayout.TextField(m_valueToString, new GUILayoutOption[] { GUILayout.MaxWidth(_width) });
}
-
- if (MemberInfo != null)
+
+ if (CanWrite)
{
if (GUILayout.Button("Apply", new GUILayoutOption[] { GUILayout.Width(60) }))
{
- SetValue();
+ SetValue(m_valueToString);
}
}
}
}
- public override void SetValue()
+ public void SetValue(string value)
{
if (MemberInfo == null)
{
@@ -89,19 +139,24 @@ namespace Explorer
return;
}
- switch (m_primitiveType)
+ if (PrimitiveType == PrimitiveTypes.String)
{
- case PrimitiveType.Bool:
- SetValue(bool.Parse(Value.ToString()), MemberInfo, DeclaringInstance); return;
- case PrimitiveType.Double:
- SetValue(double.Parse(Value.ToString()), MemberInfo, DeclaringInstance); return;
- case PrimitiveType.Float:
- SetValue(float.Parse(Value.ToString()), MemberInfo, DeclaringInstance); return;
- case PrimitiveType.Int:
- SetValue(int.Parse(Value.ToString()), MemberInfo, DeclaringInstance); return;
- case PrimitiveType.String:
- SetValue(Value.ToString(), MemberInfo, DeclaringInstance); return;
+ Value = value;
}
+ else
+ {
+ try
+ {
+ var val = ParseMethod.Invoke(null, new object[] { value });
+ Value = val;
+ }
+ catch (Exception e)
+ {
+ MelonLogger.Log("Exception parsing value: " + e.GetType() + ", " + e.Message);
+ }
+ }
+
+ SetValue();
}
}
}
diff --git a/src/CppExplorer.cs b/src/CppExplorer.cs
index afcb79d..b99b2ad 100644
--- a/src/CppExplorer.cs
+++ b/src/CppExplorer.cs
@@ -13,7 +13,7 @@ namespace Explorer
// consts
public const string ID = "com.sinai.cppexplorer";
- public const string VERSION = "1.4.1";
+ public const string VERSION = "1.4.2";
public const string AUTHOR = "Sinai";
public const string NAME = "CppExplorer"
@@ -29,7 +29,6 @@ namespace Explorer
// props
public static bool ShowMenu { get; set; } = false;
- public static int ArrayLimit { get; set; } = 20;
// methods
diff --git a/src/Helpers/ReflectionHelpers.cs b/src/Helpers/ReflectionHelpers.cs
index 0868a20..25e5e8e 100644
--- a/src/Helpers/ReflectionHelpers.cs
+++ b/src/Helpers/ReflectionHelpers.cs
@@ -22,6 +22,7 @@ namespace Explorer
public static Il2CppSystem.Type TransformType => Il2CppType.Of();
public static Il2CppSystem.Type ObjectType => Il2CppType.Of();
public static Il2CppSystem.Type ComponentType => Il2CppType.Of();
+ public static Il2CppSystem.Type BehaviourType => Il2CppType.Of();
private static readonly MethodInfo m_tryCastMethodInfo = typeof(Il2CppObjectBase).GetMethod("TryCast");
diff --git a/src/Helpers/UIHelpers.cs b/src/Helpers/UIHelpers.cs
index d72d479..cbf4bd9 100644
--- a/src/Helpers/UIHelpers.cs
+++ b/src/Helpers/UIHelpers.cs
@@ -22,7 +22,7 @@ namespace Explorer
}
// helper for drawing a styled button for a GameObject or Transform
- public static void GameobjButton(GameObject obj, Action specialInspectMethod = null, bool showSmallInspectBtn = true, float width = 380)
+ public static void GameobjButton(GameObject obj, Action specialInspectMethod = null, bool showSmallInspectBtn = true, float width = 380)
{
bool children = obj.transform.childCount > 0;
@@ -52,7 +52,7 @@ namespace Explorer
FastGameobjButton(obj, color, label, obj.activeSelf, specialInspectMethod, showSmallInspectBtn, width);
}
- public static void FastGameobjButton(GameObject obj, Color activeColor, string label, bool enabled, Action specialInspectMethod = null, bool showSmallInspectBtn = true, float width = 380)
+ public static void FastGameobjButton(GameObject obj, Color activeColor, string label, bool enabled, Action specialInspectMethod = null, bool showSmallInspectBtn = true, float width = 380)
{
if (!obj)
{
@@ -79,7 +79,7 @@ namespace Explorer
{
if (specialInspectMethod != null)
{
- specialInspectMethod(obj);
+ specialInspectMethod(obj.transform);
}
else
{
@@ -94,13 +94,18 @@ namespace Explorer
if (showSmallInspectBtn)
{
- if (GUILayout.Button("Inspect", null))
- {
- WindowManager.InspectObject(obj, out bool _);
- }
+ SmallInspectButton(obj);
}
GUILayout.EndHorizontal();
}
+
+ public static void SmallInspectButton(object obj)
+ {
+ if (GUILayout.Button("Inspect", null))
+ {
+ WindowManager.InspectObject(obj, out bool _);
+ }
+ }
}
}
diff --git a/src/MainMenu/MainMenu.cs b/src/MainMenu/MainMenu.cs
index 640a7a3..512fca8 100644
--- a/src/MainMenu/MainMenu.cs
+++ b/src/MainMenu/MainMenu.cs
@@ -88,19 +88,6 @@ namespace Explorer
private void MainHeader()
{
- GUILayout.BeginHorizontal(null);
- GUILayout.Label("Options:", new GUILayoutOption[] { GUILayout.Width(70) });
- GUI.skin.label.alignment = TextAnchor.MiddleRight;
- GUILayout.Label("Array Limit:", new GUILayoutOption[] { GUILayout.Width(70) });
- GUI.skin.label.alignment = TextAnchor.UpperLeft;
- var _input = GUILayout.TextField(CppExplorer.ArrayLimit.ToString(), new GUILayoutOption[] { GUILayout.Width(60) });
- if (int.TryParse(_input, out int _lim))
- {
- CppExplorer.ArrayLimit = _lim;
- }
- InspectUnderMouse.EnableInspect = GUILayout.Toggle(InspectUnderMouse.EnableInspect, "Inspect Under Mouse (Shift + RMB)", null);
- GUILayout.EndHorizontal();
-
GUILayout.BeginHorizontal(null);
for (int i = 0; i < Pages.Count; i++)
{
@@ -116,6 +103,9 @@ namespace Explorer
}
GUILayout.EndHorizontal();
+ GUI.color = Color.white;
+ InspectUnderMouse.EnableInspect = GUILayout.Toggle(InspectUnderMouse.EnableInspect, "Inspect Under Mouse (Shift + RMB)", null);
+
GUILayout.Space(10);
GUI.color = Color.white;
}
diff --git a/src/MainMenu/Pages/ScenePage.cs b/src/MainMenu/Pages/ScenePage.cs
index c5e61da..8166b4c 100644
--- a/src/MainMenu/Pages/ScenePage.cs
+++ b/src/MainMenu/Pages/ScenePage.cs
@@ -14,9 +14,15 @@ namespace Explorer
public override string Name { get => "Scene Explorer"; set => base.Name = value; }
- // ----- Holders for GUI elements ----- //
+ private int m_pageOffset = 0;
+ private int m_limit = 20;
+ private int m_currentTotalCount = 0;
- private string m_currentScene = "";
+ private float m_timeOfLastUpdate = -1f;
+
+ // ----- Holders for GUI elements ----- //
+
+ private string m_currentScene = "";
// gameobject list
private Transform m_currentTransform;
@@ -37,190 +43,84 @@ namespace Explorer
public void OnSceneChange()
{
m_currentScene = UnityHelpers.ActiveSceneName;
+ SetTransformTarget(null);
+ }
- m_currentTransform = null;
- CancelSearch();
+ public void CheckOffset(ref int offset, int childCount)
+ {
+ if (offset >= childCount)
+ {
+ offset = 0;
+ m_pageOffset = 0;
+ }
}
public override void Update()
{
- if (!m_searching)
+ if (m_searching) return;
+
+ if (Time.time - m_timeOfLastUpdate < 1f) return;
+ m_timeOfLastUpdate = Time.time;
+
+ m_objectList = new List();
+ int offset = m_pageOffset * m_limit;
+
+ var allTransforms = new List();
+
+ // get current list of all transforms (either scene root or our current transform children)
+ if (m_currentTransform)
{
- m_objectList = new List();
- if (m_currentTransform)
+ for (int i = 0; i < m_currentTransform.childCount; i++)
{
- var endAppend = new List();
- for (int i = 0; i < m_currentTransform.childCount; i++)
- {
- var child = m_currentTransform.GetChild(i);
-
- if (child)
- {
- if (child.childCount > 0)
- m_objectList.Add(new GameObjectCache(child.gameObject));
- else
- endAppend.Add(new GameObjectCache(child.gameObject));
- }
- }
- m_objectList.AddRange(endAppend);
- endAppend = null;
+ allTransforms.Add(m_currentTransform.GetChild(i));
}
- else
+ }
+ else
+ {
+ var scene = SceneManager.GetSceneByName(m_currentScene);
+ var rootObjects = scene.GetRootGameObjects();
+
+ foreach (var obj in rootObjects)
{
- var scene = SceneManager.GetSceneByName(m_currentScene);
- var rootObjects = scene.GetRootGameObjects();
-
- // add objects with children first
- foreach (var obj in rootObjects.Where(x => x.transform.childCount > 0))
- {
- m_objectList.Add(new GameObjectCache(obj));
- }
- foreach (var obj in rootObjects.Where(x => x.transform.childCount == 0))
- {
- m_objectList.Add(new GameObjectCache(obj));
- }
+ allTransforms.Add(obj.transform);
}
}
+
+ m_currentTotalCount = allTransforms.Count;
+
+ // make sure offset doesn't exceed count
+ CheckOffset(ref offset, m_currentTotalCount);
+
+ // sort by childcount
+ allTransforms.Sort((a, b) => b.childCount.CompareTo(a.childCount));
+
+ for (int i = offset; i < offset + m_limit && i < m_currentTotalCount; i++)
+ {
+ var child = allTransforms[i];
+ m_objectList.Add(new GameObjectCache(child.gameObject));
+ }
}
- // --------- GUI Draw Functions --------- //
-
- public override void DrawWindow()
+ public void SetTransformTarget(Transform t)
{
- try
- {
- GUILayout.BeginHorizontal(null);
- // Current Scene label
- GUILayout.Label("Current Scene:", new GUILayoutOption[] { GUILayout.Width(120) });
- try
- {
- // Need to do 'ToList()' so the object isn't cleaned up by Il2Cpp GC.
- var scenes = SceneManager.GetAllScenes().ToList();
+ m_currentTransform = t;
- if (scenes.Count > 1)
- {
- int changeWanted = 0;
- if (GUILayout.Button("<", new GUILayoutOption[] { GUILayout.Width(30) }))
- {
- changeWanted = -1;
- }
- if (GUILayout.Button(">", new GUILayoutOption[] { GUILayout.Width(30) }))
- {
- changeWanted = 1;
- }
- if (changeWanted != 0)
- {
- int index = scenes.IndexOf(SceneManager.GetSceneByName(m_currentScene));
- index += changeWanted;
- if (index > scenes.Count - 1)
- {
- index = 0;
- }
- else if (index < 0)
- {
- index = scenes.Count - 1;
- }
- m_currentScene = scenes[index].name;
- }
- }
- }
- catch { }
- GUILayout.Label("" + m_currentScene + "", null); //new GUILayoutOption[] { GUILayout.Width(250) });
+ if (m_searching)
+ CancelSearch();
- GUILayout.EndHorizontal();
-
- // ----- GameObject Search -----
- GUILayout.BeginHorizontal(GUI.skin.box, null);
- GUILayout.Label("Search Scene:", new GUILayoutOption[] { GUILayout.Width(100) });
- m_searchInput = GUILayout.TextField(m_searchInput, null);
- if (GUILayout.Button("Search", new GUILayoutOption[] { GUILayout.Width(80) }))
- {
- Search();
- }
- GUILayout.EndHorizontal();
-
- GUILayout.Space(15);
-
- // ************** GameObject list ***************
-
- // ----- main explorer ------
- if (!m_searching)
- {
- if (m_currentTransform != null)
- {
- GUILayout.BeginHorizontal(null);
- if (GUILayout.Button("<-", new GUILayoutOption[] { GUILayout.Width(35) }))
- {
- TraverseUp();
- }
- else
- {
- GUILayout.Label(m_currentTransform.GetGameObjectPath(), null);
- }
- GUILayout.EndHorizontal();
- }
- else
- {
- GUILayout.Label("Scene Root GameObjects:", null);
- }
-
- if (m_objectList.Count > 0)
- {
- foreach (var obj in m_objectList)
- {
- //UIStyles.GameobjButton(obj, SetTransformTarget, true, MainMenu.MainRect.width - 170);
- UIHelpers.FastGameobjButton(obj.RefGameObject, obj.EnabledColor, obj.Label, obj.RefGameObject.activeSelf, SetTransformTarget, true, MainMenu.MainRect.width - 170);
- }
- }
- }
- else // ------ Scene Search results ------
- {
- if (GUILayout.Button("<-", new GUILayoutOption[] { GUILayout.Width(35) }))
- {
- CancelSearch();
- }
-
- GUILayout.Label("Search Results:", null);
-
- if (m_searchResults.Count > 0)
- {
- foreach (var obj in m_searchResults)
- {
- //UIStyles.GameobjButton(obj, SetTransformTarget, true, MainMenu.MainRect.width - 170);
- UIHelpers.FastGameobjButton(obj.RefGameObject, obj.EnabledColor, obj.Label, obj.RefGameObject.activeSelf, SetTransformTarget, true, MainMenu.MainRect.width - 170);
- }
- }
- else
- {
- GUILayout.Label("No results found!", null);
- }
- }
- }
- catch
- {
- m_currentTransform = null;
- }
- }
-
-
-
- // -------- Actual Methods (not drawing GUI) ---------- //
-
- public void SetTransformTarget(GameObject obj)
- {
- m_currentTransform = obj.transform;
- CancelSearch();
+ m_timeOfLastUpdate = -1f;
+ Update();
}
public void TraverseUp()
{
if (m_currentTransform.parent != null)
{
- m_currentTransform = m_currentTransform.parent;
+ SetTransformTarget(m_currentTransform.parent);
}
else
{
- m_currentTransform = null;
+ SetTransformTarget(null);
}
}
@@ -228,6 +128,7 @@ namespace Explorer
{
m_searchResults = SearchSceneObjects(m_searchInput);
m_searching = true;
+ m_currentTotalCount = m_searchResults.Count;
}
public void CancelSearch()
@@ -249,6 +150,220 @@ namespace Explorer
return matches;
}
+
+ // --------- GUI Draw Function --------- //
+
+ public override void DrawWindow()
+ {
+ try
+ {
+ DrawHeaderArea();
+
+ GUILayout.BeginVertical(GUI.skin.box, null);
+
+ DrawPageButtons();
+
+ if (!m_searching)
+ {
+ DrawGameObjectList();
+ }
+ else
+ {
+ DrawSearchResultsList();
+ }
+
+ GUILayout.EndVertical();
+ }
+ catch (Exception e)
+ {
+ MelonLogger.Log("Exception drawing ScenePage! " + e.GetType() + ", " + e.Message);
+ MelonLogger.Log(e.StackTrace);
+ m_currentTransform = null;
+ }
+ }
+
+ private void DrawHeaderArea()
+ {
+ GUILayout.BeginHorizontal(null);
+
+ // Current Scene label
+ GUILayout.Label("Current Scene:", new GUILayoutOption[] { GUILayout.Width(120) });
+ try
+ {
+ // Need to do 'ToList()' so the object isn't cleaned up by Il2Cpp GC.
+ var scenes = SceneManager.GetAllScenes().ToList();
+
+ if (scenes.Count > 1)
+ {
+ int changeWanted = 0;
+ if (GUILayout.Button("<", new GUILayoutOption[] { GUILayout.Width(30) }))
+ {
+ changeWanted = -1;
+ }
+ if (GUILayout.Button(">", new GUILayoutOption[] { GUILayout.Width(30) }))
+ {
+ changeWanted = 1;
+ }
+ if (changeWanted != 0)
+ {
+ int index = scenes.IndexOf(SceneManager.GetSceneByName(m_currentScene));
+ index += changeWanted;
+ if (index > scenes.Count - 1)
+ {
+ index = 0;
+ }
+ else if (index < 0)
+ {
+ index = scenes.Count - 1;
+ }
+ m_currentScene = scenes[index].name;
+ }
+ }
+ }
+ catch { }
+ GUILayout.Label("" + m_currentScene + "", null); //new GUILayoutOption[] { GUILayout.Width(250) });
+
+ GUILayout.EndHorizontal();
+
+ // ----- GameObject Search -----
+ GUILayout.BeginHorizontal(GUI.skin.box, null);
+ GUILayout.Label("Search Scene:", new GUILayoutOption[] { GUILayout.Width(100) });
+ m_searchInput = GUILayout.TextField(m_searchInput, null);
+ if (GUILayout.Button("Search", new GUILayoutOption[] { GUILayout.Width(80) }))
+ {
+ Search();
+ }
+ GUILayout.EndHorizontal();
+
+ GUILayout.Space(5);
+ }
+
+ private void DrawPageButtons()
+ {
+ GUILayout.BeginHorizontal(null);
+
+ GUILayout.Label("Limit per page: ", new GUILayoutOption[] { GUILayout.Width(100) });
+ var limit = m_limit.ToString();
+ limit = GUILayout.TextField(limit, new GUILayoutOption[] { GUILayout.Width(30) });
+ if (int.TryParse(limit, out int lim))
+ {
+ m_limit = lim;
+ }
+
+ // prev/next page buttons
+ if (m_currentTotalCount > m_limit)
+ {
+ int count = m_currentTotalCount;
+ int maxOffset = (int)Mathf.Ceil((float)(count / (decimal)m_limit)) - 1;
+ if (GUILayout.Button("< Prev", null))
+ {
+ if (m_pageOffset > 0) m_pageOffset--;
+ m_timeOfLastUpdate = -1f;
+ Update();
+ }
+
+ GUI.skin.label.alignment = TextAnchor.MiddleCenter;
+ GUILayout.Label($"Page {m_pageOffset + 1}/{maxOffset + 1}", new GUILayoutOption[] { GUILayout.Width(80) });
+
+ if (GUILayout.Button("Next >", null))
+ {
+ if (m_pageOffset < maxOffset) m_pageOffset++;
+ m_timeOfLastUpdate = -1f;
+ Update();
+ }
+ }
+
+ GUILayout.EndHorizontal();
+ GUI.skin.label.alignment = TextAnchor.UpperLeft;
+ }
+
+ private void DrawGameObjectList()
+ {
+ if (m_currentTransform != null)
+ {
+ GUILayout.BeginHorizontal(null);
+ if (GUILayout.Button("<-", new GUILayoutOption[] { GUILayout.Width(35) }))
+ {
+ TraverseUp();
+ }
+ else
+ {
+ GUILayout.Label("" + m_currentTransform.GetGameObjectPath() + "",
+ new GUILayoutOption[] { GUILayout.Width(MainMenu.MainRect.width - 187f) });
+ }
+
+ UIHelpers.SmallInspectButton(m_currentTransform);
+
+ GUILayout.EndHorizontal();
+ }
+ else
+ {
+ GUILayout.Label("Scene Root GameObjects:", null);
+ }
+
+ if (m_objectList.Count > 0)
+ {
+ foreach (var obj in m_objectList)
+ {
+ if (!obj.RefGameObject)
+ {
+ string label = "null";
+
+ if (obj.RefGameObject != null)
+ {
+ label += " (Destroyed)";
+ }
+
+ label += "";
+ GUILayout.Label(label, null);
+ }
+ else
+ {
+ UIHelpers.FastGameobjButton(obj.RefGameObject,
+ obj.EnabledColor,
+ obj.Label,
+ obj.RefGameObject.activeSelf,
+ SetTransformTarget,
+ true,
+ MainMenu.MainRect.width - 170);
+ }
+ }
+ }
+ }
+
+ private void DrawSearchResultsList()
+ {
+ if (GUILayout.Button("<- Cancel Search", new GUILayoutOption[] { GUILayout.Width(150) }))
+ {
+ CancelSearch();
+ }
+
+ GUILayout.Label("Search Results:", null);
+
+ if (m_searchResults.Count > 0)
+ {
+ int offset = m_pageOffset * m_limit;
+
+ if (offset >= m_searchResults.Count)
+ {
+ offset = 0;
+ m_pageOffset = 0;
+ }
+
+ for (int i = offset; i < offset + m_limit && offset < m_searchResults.Count; i++)
+ {
+ var obj = m_searchResults[i];
+
+ UIHelpers.FastGameobjButton(obj.RefGameObject, obj.EnabledColor, obj.Label, obj.RefGameObject.activeSelf, SetTransformTarget, true, MainMenu.MainRect.width - 170);
+ }
+ }
+ else
+ {
+ GUILayout.Label("No results found!", null);
+ }
+ }
+
+ // -------- Mini GameObjectCache class ---------- //
public class GameObjectCache
{
diff --git a/src/MainMenu/Pages/SearchPage.cs b/src/MainMenu/Pages/SearchPage.cs
index 4de7292..e978a20 100644
--- a/src/MainMenu/Pages/SearchPage.cs
+++ b/src/MainMenu/Pages/SearchPage.cs
@@ -135,7 +135,7 @@ namespace Explorer
int offset = m_pageOffset * this.m_limit;
if (offset >= count) m_pageOffset = 0;
- for (int i = offset; i < offset + CppExplorer.ArrayLimit && i < count; i++)
+ for (int i = offset; i < offset + m_limit && i < count; i++)
{
m_searchResults[i].Draw(MainMenu.MainRect, 0f);
//m_searchResults[i].DrawValue(MainMenu.MainRect);
diff --git a/src/Windows/GameObjectWindow.cs b/src/Windows/GameObjectWindow.cs
index c66fb30..bcf5ba4 100644
--- a/src/Windows/GameObjectWindow.cs
+++ b/src/Windows/GameObjectWindow.cs
@@ -29,7 +29,7 @@ namespace Explorer
private float m_rotateAmount = 50f;
private float m_scaleAmount = 0.1f;
- List m_cachedDestroyList = new List();
+ private List m_cachedDestroyList = new List();
//private string m_addComponentInput = "";
private string m_setParentInput = "";
@@ -91,7 +91,7 @@ namespace Explorer
}
}
- private void InspectGameObject(GameObject obj)
+ private void InspectGameObject(Transform obj)
{
var window = WindowManager.InspectObject(obj, out bool created);
@@ -137,7 +137,7 @@ namespace Explorer
{
if (GUILayout.Button("< View in Scene Explorer", new GUILayoutOption[] { GUILayout.Width(230) }))
{
- ScenePage.Instance.SetTransformTarget(m_object);
+ ScenePage.Instance.SetTransformTarget(m_object.transform);
MainMenu.SetCurrentPage(0);
}
}
@@ -150,7 +150,7 @@ namespace Explorer
{
if (GUILayout.Button("<-", new GUILayoutOption[] { GUILayout.Width(35) }))
{
- InspectGameObject(m_object.transform.parent.gameObject);
+ InspectGameObject(m_object.transform.parent);
}
}
GUILayout.TextArea(pathlabel, null);
@@ -235,18 +235,16 @@ namespace Explorer
var m_components = new Il2CppSystem.Collections.Generic.List();
m_object.GetComponentsInternal(Il2CppType.Of(), false, false, true, false, m_components);
- var ilTypeOfTransform = Il2CppType.Of();
- var ilTypeOfBehaviour = Il2CppType.Of();
foreach (var component in m_components)
{
var ilType = component.GetIl2CppType();
- if (ilType == ilTypeOfTransform)
+ if (ilType == ReflectionHelpers.TransformType)
{
continue;
}
GUILayout.BeginHorizontal(null);
- if (ilTypeOfBehaviour.IsAssignableFrom(ilType))
+ if (ReflectionHelpers.BehaviourType.IsAssignableFrom(ilType))
{
BehaviourEnabledBtn(component.TryCast());
}
@@ -274,24 +272,6 @@ namespace Explorer
GUILayout.EndScrollView();
- //GUILayout.BeginHorizontal(null);
- //m_addComponentInput = GUILayout.TextField(m_addComponentInput, new GUILayoutOption[] { GUILayout.Width(m_rect.width / 2 - 150) });
- //if (GUILayout.Button("Add Component", new GUILayoutOption[] { GUILayout.Width(120) }))
- //{
- // if (HPExplorer.GetType(m_addComponentInput) is Type type && typeof(Component).IsAssignableFrom(type))
- // {
- // var comp = m_object.AddComponent(type);
- // var list = m_components.ToList();
- // list.Add(comp);
- // m_components = list.ToArray();
- // }
- // else
- // {
- // MelonLogger.LogWarning($"Could not get type '{m_addComponentInput}'. If it's not a typo, try the fully qualified name.");
- // }
- //}
- //GUILayout.EndHorizontal();
-
GUILayout.EndVertical();
}
diff --git a/src/Windows/ReflectionWindow.cs b/src/Windows/ReflectionWindow.cs
index ad734b5..1b1a649 100644
--- a/src/Windows/ReflectionWindow.cs
+++ b/src/Windows/ReflectionWindow.cs
@@ -25,7 +25,7 @@ namespace Explorer
private bool m_autoUpdate = false;
private string m_search = "";
public MemberInfoType m_filter = MemberInfoType.Property;
- private bool m_hideFailedReflection = true;
+ private bool m_hideFailedReflection = false;
public enum MemberInfoType
{
@@ -135,13 +135,25 @@ namespace Explorer
{
if (member.Name == "Il2CppType") continue;
- var name = member.DeclaringType.Name + "." + member.Name;
- if (names.Contains(name)) continue;
- names.Add(name);
+ try
+ {
+ var name = member.DeclaringType.Name + "." + member.Name;
+ if (names.Contains(name)) continue;
+ names.Add(name);
- var cached = CacheObject.GetCacheObject(null, member, target);
- list.Add(cached);
- cached.ReflectionException = exception;
+ var cached = CacheObject.GetCacheObject(null, member, target);
+ if (cached != null)
+ {
+ list.Add(cached);
+ cached.ReflectionException = exception;
+ }
+ }
+ catch (Exception e)
+ {
+ MelonLogger.Log("Exception caching member!");
+ MelonLogger.Log(e.GetType() + ", " + e.Message);
+ MelonLogger.Log(e.StackTrace);
+ }
}
}
}
@@ -160,7 +172,7 @@ namespace Explorer
GUILayout.BeginArea(new Rect(5, 25, m_rect.width - 10, m_rect.height - 35), GUI.skin.box);
GUILayout.BeginHorizontal(null);
- GUILayout.Label("Type: " + ObjectType.Name + "", null);
+ GUILayout.Label("Type: " + ObjectType.FullName + "", null);
bool unityObj = Target is UnityEngine.Object;
@@ -238,6 +250,7 @@ namespace Explorer
if (GUILayout.Button("< Prev", null))
{
if (m_pageOffset > 0) m_pageOffset--;
+ scroll = Vector2.zero;
}
GUILayout.Label($"Page {m_pageOffset + 1}/{maxOffset + 1}", new GUILayoutOption[] { GUILayout.Width(80) });
@@ -245,6 +258,7 @@ namespace Explorer
if (GUILayout.Button("Next >", null))
{
if (m_pageOffset < maxOffset) m_pageOffset++;
+ scroll = Vector2.zero;
}
GUILayout.EndHorizontal();
}
diff --git a/src/Windows/WindowManager.cs b/src/Windows/WindowManager.cs
index 49d3fd8..02a4352 100644
--- a/src/Windows/WindowManager.cs
+++ b/src/Windows/WindowManager.cs
@@ -104,7 +104,7 @@ namespace Explorer
foreach (var window in Windows)
{
- if (obj == window.Target)
+ if (ReferenceEquals(obj, window.Target))
{
GUI.BringWindowToFront(window.windowID);
GUI.FocusWindow(window.windowID);