mirror of
https://github.com/sinai-dev/UnityExplorer.git
synced 2025-06-16 14:17:51 +08:00
1.4.5 (pre-release)
* Added MethodInfo support for basic methods with no arguments. * Added support for missing primitive types (char, short, byte) * Added CacheDictionary class (currently unsupported) * Cleaned up some stuff, using System.Reflection.MemberType instead of a custom enum.
This commit is contained in:
parent
6e644b4f50
commit
92fe1dc704
@ -45,7 +45,6 @@ Requires [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) to be ins
|
|||||||
CppExplorer can force the mouse to be visible and unlocked when the menu is open, if you have enabled "Force Unlock Mouse" (Left-Alt toggle). However, you may also want to prevent the mouse clicking-through onto the game behind CppExplorer, this is possible but it requires specific patches for that game.
|
CppExplorer can force the mouse to be visible and unlocked when the menu is open, if you have enabled "Force Unlock Mouse" (Left-Alt toggle). However, you may also want to prevent the mouse clicking-through onto the game behind CppExplorer, this is possible but it requires specific patches for that game.
|
||||||
|
|
||||||
* For VRChat, use [VRCExplorerMouseControl](https://github.com/sinaioutlander/VRCExplorerMouseControl)
|
* For VRChat, use [VRCExplorerMouseControl](https://github.com/sinaioutlander/VRCExplorerMouseControl)
|
||||||
* For Hellpoint, use [HPExplorerMouseControl](https://github.com/sinaioutlander/Hellpoint-Mods/tree/master/HPExplorerMouseControl/HPExplorerMouseControl)
|
|
||||||
* You can create your own mini-plugin using one of the two plugins above as an example. Usually only 1 or 2 simple Harmony patches are needed to fix the problem (if you want to submit that here, feel free to make a PR to this Readme).
|
* You can create your own mini-plugin using one of the two plugins above as an example. Usually only 1 or 2 simple Harmony patches are needed to fix the problem (if you want to submit that here, feel free to make a PR to this Readme).
|
||||||
|
|
||||||
## Images
|
## Images
|
||||||
|
34
src/CachedObjects/CacheDictionary.cs
Normal file
34
src/CachedObjects/CacheDictionary.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MelonLoader;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Explorer
|
||||||
|
{
|
||||||
|
public class CacheDictionary : CacheObjectBase
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
public override void Init()
|
||||||
|
{
|
||||||
|
//base.Init();
|
||||||
|
|
||||||
|
Value = "Unsupported";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateValue()
|
||||||
|
{
|
||||||
|
//base.UpdateValue();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void DrawValue(Rect window, float width)
|
||||||
|
{
|
||||||
|
GUILayout.Label("<color=red>Dictionary (unsupported)</color>", null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,7 @@ using UnityEngine;
|
|||||||
|
|
||||||
namespace Explorer
|
namespace Explorer
|
||||||
{
|
{
|
||||||
public class CacheEnum : CacheObject
|
public class CacheEnum : CacheObjectBase
|
||||||
{
|
{
|
||||||
public Type EnumType;
|
public Type EnumType;
|
||||||
public string[] EnumNames;
|
public string[] EnumNames;
|
||||||
|
@ -8,7 +8,7 @@ using UnityEngine;
|
|||||||
|
|
||||||
namespace Explorer
|
namespace Explorer
|
||||||
{
|
{
|
||||||
public class CacheGameObject : CacheObject
|
public class CacheGameObject : CacheObjectBase
|
||||||
{
|
{
|
||||||
private GameObject GameObj
|
private GameObject GameObj
|
||||||
{
|
{
|
||||||
|
@ -3,34 +3,40 @@ using System.Collections;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using MelonLoader;
|
|
||||||
using Mono.CSharp;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Explorer
|
namespace Explorer
|
||||||
{
|
{
|
||||||
public partial class CacheList : CacheObject
|
public partial class CacheList : CacheObjectBase
|
||||||
{
|
{
|
||||||
public bool IsExpanded { get; set; }
|
public bool IsExpanded { get; set; }
|
||||||
public int ArrayOffset { get; set; }
|
public int ArrayOffset { get; set; }
|
||||||
public int ArrayLimit { get; set; } = 20;
|
public int ArrayLimit { get; set; } = 20;
|
||||||
|
|
||||||
|
public float WhiteSpace = 215f;
|
||||||
|
public float ButtonWidthOffset = 290f;
|
||||||
|
|
||||||
public Type EntryType
|
public Type EntryType
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (m_entryType == null)
|
if (m_entryType == null)
|
||||||
{
|
{
|
||||||
switch (this.MemberInfoType)
|
if (this.MemberInfo != null)
|
||||||
{
|
{
|
||||||
case ReflectionWindow.MemberInfoType.Field:
|
switch (this.MemberInfoType)
|
||||||
m_entryType = (MemberInfo as FieldInfo).FieldType.GetGenericArguments()[0];
|
{
|
||||||
break;
|
case MemberTypes.Field:
|
||||||
case ReflectionWindow.MemberInfoType.Property:
|
m_entryType = (MemberInfo as FieldInfo).FieldType.GetGenericArguments()[0];
|
||||||
m_entryType = (MemberInfo as PropertyInfo).PropertyType.GetGenericArguments()[0];
|
break;
|
||||||
break;
|
case MemberTypes.Property:
|
||||||
|
m_entryType = (MemberInfo as PropertyInfo).PropertyType.GetGenericArguments()[0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Value != null)
|
||||||
|
{
|
||||||
|
m_entryType = Value.GetType().GetGenericArguments()[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m_entryType;
|
return m_entryType;
|
||||||
@ -55,7 +61,7 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable m_enumerable;
|
private IEnumerable m_enumerable;
|
||||||
private CacheObject[] m_cachedEntries;
|
private CacheObjectBase[] m_cachedEntries;
|
||||||
|
|
||||||
public MethodInfo GenericToArrayMethod
|
public MethodInfo GenericToArrayMethod
|
||||||
{
|
{
|
||||||
@ -97,7 +103,7 @@ namespace Explorer
|
|||||||
|
|
||||||
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
||||||
string btnLabel = "<color=yellow>[" + count + "] " + EntryType + "</color>";
|
string btnLabel = "<color=yellow>[" + count + "] " + EntryType + "</color>";
|
||||||
if (GUILayout.Button(btnLabel, new GUILayoutOption[] { GUILayout.MaxWidth(window.width - 260) }))
|
if (GUILayout.Button(btnLabel, new GUILayoutOption[] { GUILayout.MaxWidth(window.width - ButtonWidthOffset) }))
|
||||||
{
|
{
|
||||||
WindowManager.InspectObject(Value, out bool _);
|
WindowManager.InspectObject(Value, out bool _);
|
||||||
}
|
}
|
||||||
@ -107,8 +113,12 @@ namespace Explorer
|
|||||||
|
|
||||||
if (IsExpanded)
|
if (IsExpanded)
|
||||||
{
|
{
|
||||||
float whitespace = 215;
|
float whitespace = WhiteSpace;
|
||||||
ClampLabelWidth(window, ref whitespace);
|
|
||||||
|
if (whitespace > 0)
|
||||||
|
{
|
||||||
|
ClampLabelWidth(window, ref whitespace);
|
||||||
|
}
|
||||||
|
|
||||||
if (count > ArrayLimit)
|
if (count > ArrayLimit)
|
||||||
{
|
{
|
||||||
@ -120,11 +130,11 @@ namespace Explorer
|
|||||||
int maxOffset = (int)Mathf.Ceil((float)(count / (decimal)ArrayLimit)) - 1;
|
int maxOffset = (int)Mathf.Ceil((float)(count / (decimal)ArrayLimit)) - 1;
|
||||||
GUILayout.Label($"Page {ArrayOffset + 1}/{maxOffset + 1}", new GUILayoutOption[] { GUILayout.Width(80) });
|
GUILayout.Label($"Page {ArrayOffset + 1}/{maxOffset + 1}", new GUILayoutOption[] { GUILayout.Width(80) });
|
||||||
// prev/next page buttons
|
// prev/next page buttons
|
||||||
if (GUILayout.Button("< Prev", null))
|
if (GUILayout.Button("< Prev", new GUILayoutOption[] { GUILayout.Width(60) }))
|
||||||
{
|
{
|
||||||
if (ArrayOffset > 0) ArrayOffset--;
|
if (ArrayOffset > 0) ArrayOffset--;
|
||||||
}
|
}
|
||||||
if (GUILayout.Button("Next >", null))
|
if (GUILayout.Button("Next >", new GUILayoutOption[] { GUILayout.Width(60) }))
|
||||||
{
|
{
|
||||||
if (ArrayOffset < maxOffset) ArrayOffset++;
|
if (ArrayOffset < maxOffset) ArrayOffset++;
|
||||||
}
|
}
|
||||||
@ -186,7 +196,7 @@ namespace Explorer
|
|||||||
|
|
||||||
if (enumerator == null) return;
|
if (enumerator == null) return;
|
||||||
|
|
||||||
var list = new List<CacheObject>();
|
var list = new List<CacheObjectBase>();
|
||||||
while (enumerator.MoveNext())
|
while (enumerator.MoveNext())
|
||||||
{
|
{
|
||||||
list.Add(GetCacheObject(enumerator.Current, null, null, this.EntryType));
|
list.Add(GetCacheObject(enumerator.Current, null, null, this.EntryType));
|
||||||
|
104
src/CachedObjects/CacheMethod.cs
Normal file
104
src/CachedObjects/CacheMethod.cs
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Reflection;
|
||||||
|
using UnityEngine;
|
||||||
|
using MelonLoader;
|
||||||
|
|
||||||
|
namespace Explorer
|
||||||
|
{
|
||||||
|
public class CacheMethod : CacheObjectBase
|
||||||
|
{
|
||||||
|
private bool m_evaluated = false;
|
||||||
|
private CacheObjectBase m_cachedReturnValue;
|
||||||
|
|
||||||
|
public static bool CanEvaluate(MethodInfo mi)
|
||||||
|
{
|
||||||
|
if (mi.GetParameters().Length > 0 || mi.GetGenericArguments().Length > 0)
|
||||||
|
{
|
||||||
|
// Currently methods with arguments are not supported (no good way to input them).
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Init()
|
||||||
|
{
|
||||||
|
base.Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateValue()
|
||||||
|
{
|
||||||
|
base.UpdateValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Evaluate()
|
||||||
|
{
|
||||||
|
m_evaluated = true;
|
||||||
|
|
||||||
|
var mi = MemberInfo as MethodInfo;
|
||||||
|
var ret = mi.Invoke(mi.IsStatic ? null : DeclaringInstance, new object[0]);
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
GUILayout.BeginVertical(null);
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
if (GUILayout.Button("Evaluate", new GUILayoutOption[] { GUILayout.Width(70) }))
|
||||||
|
{
|
||||||
|
Evaluate();
|
||||||
|
}
|
||||||
|
GUI.skin.label.wordWrap = false;
|
||||||
|
GUILayout.Label($"<color=yellow>{ValueType}</color>", null);
|
||||||
|
GUI.skin.label.wordWrap = true;
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
if (m_evaluated)
|
||||||
|
{
|
||||||
|
if (m_cachedReturnValue != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_cachedReturnValue.DrawValue(window, width);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MelonLogger.Log("Exception drawing m_cachedReturnValue!");
|
||||||
|
MelonLogger.Log(e.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GUILayout.Label($"null", null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GUILayout.Label($"<color=grey><i>Not yet evaluated</i></color>", null);
|
||||||
|
}
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
GUILayout.EndVertical();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,14 +10,13 @@ using UnityEngine;
|
|||||||
|
|
||||||
namespace Explorer
|
namespace Explorer
|
||||||
{
|
{
|
||||||
public abstract class CacheObject
|
public abstract class CacheObjectBase
|
||||||
{
|
{
|
||||||
public object Value;
|
public object Value;
|
||||||
public string ValueType;
|
public string ValueType;
|
||||||
|
|
||||||
// Reflection window only
|
// Reflection window only
|
||||||
public MemberInfo MemberInfo { get; set; }
|
public MemberInfo MemberInfo { get; set; }
|
||||||
// public ReflectionWindow.MemberInfoType MemberInfoType { get; set; }
|
|
||||||
public Type DeclaringType { get; set; }
|
public Type DeclaringType { get; set; }
|
||||||
public object DeclaringInstance { get; set; }
|
public object DeclaringInstance { get; set; }
|
||||||
public string FullName => $"{MemberInfo.DeclaringType.Name}.{MemberInfo.Name}";
|
public string FullName => $"{MemberInfo.DeclaringType.Name}.{MemberInfo.Name}";
|
||||||
@ -42,14 +41,14 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReflectionWindow.MemberInfoType MemberInfoType
|
public MemberTypes MemberInfoType
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (MemberInfo is FieldInfo) return ReflectionWindow.MemberInfoType.Field;
|
if (MemberInfo is FieldInfo) return MemberTypes.Field;
|
||||||
if (MemberInfo is PropertyInfo) return ReflectionWindow.MemberInfoType.Property;
|
if (MemberInfo is PropertyInfo) return MemberTypes.Property;
|
||||||
if (MemberInfo is MethodInfo) return ReflectionWindow.MemberInfoType.Method;
|
if (MemberInfo is MethodInfo) return MemberTypes.Method;
|
||||||
return ReflectionWindow.MemberInfoType.All;
|
return MemberTypes.All;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +56,7 @@ namespace Explorer
|
|||||||
public virtual void Init() { }
|
public virtual void Init() { }
|
||||||
public abstract void DrawValue(Rect window, float width);
|
public abstract void DrawValue(Rect window, float width);
|
||||||
|
|
||||||
public static CacheObject GetCacheObject(object obj)
|
public static CacheObjectBase GetCacheObject(object obj)
|
||||||
{
|
{
|
||||||
return GetCacheObject(obj, null, null);
|
return GetCacheObject(obj, null, null);
|
||||||
}
|
}
|
||||||
@ -69,13 +68,39 @@ namespace Explorer
|
|||||||
/// <param name="memberInfo">The MemberInfo (can be null if obj is not null)</param>
|
/// <param name="memberInfo">The MemberInfo (can be null if obj is not null)</param>
|
||||||
/// <param name="declaringInstance">If MemberInfo is not null, the declaring class instance. Can be null if static.</param>
|
/// <param name="declaringInstance">If MemberInfo is not null, the declaring class instance. Can be null if static.</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static CacheObject GetCacheObject(object obj, MemberInfo memberInfo, object declaringInstance)
|
public static CacheObjectBase GetCacheObject(object obj, MemberInfo memberInfo, object declaringInstance)
|
||||||
{
|
{
|
||||||
var type = ReflectionHelpers.GetActualType(obj) ?? (memberInfo as FieldInfo)?.FieldType ?? (memberInfo as PropertyInfo)?.PropertyType;
|
//var type = ReflectionHelpers.GetActualType(obj) ?? (memberInfo as FieldInfo)?.FieldType ?? (memberInfo as PropertyInfo)?.PropertyType;
|
||||||
|
|
||||||
|
Type type = null;
|
||||||
|
|
||||||
|
if (obj != null)
|
||||||
|
{
|
||||||
|
type = ReflectionHelpers.GetActualType(obj);
|
||||||
|
}
|
||||||
|
else if (memberInfo != null)
|
||||||
|
{
|
||||||
|
if (memberInfo is FieldInfo fi)
|
||||||
|
{
|
||||||
|
type = fi.FieldType;
|
||||||
|
}
|
||||||
|
else if (memberInfo is PropertyInfo pi)
|
||||||
|
{
|
||||||
|
type = pi.PropertyType;
|
||||||
|
}
|
||||||
|
else if (memberInfo is MethodInfo mi)
|
||||||
|
{
|
||||||
|
type = mi.ReturnType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (type == null)
|
if (type == null)
|
||||||
{
|
{
|
||||||
MelonLogger.Log("Could not get type for object or memberinfo!");
|
MelonLogger.Log("Could not get type for object or memberinfo!");
|
||||||
|
if (memberInfo is MethodInfo)
|
||||||
|
{
|
||||||
|
MelonLogger.Log("is it void?");
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,12 +115,22 @@ namespace Explorer
|
|||||||
/// <param name="declaringInstance">If MemberInfo is not null, the declaring class instance. Can be null if static.</param>
|
/// <param name="declaringInstance">If MemberInfo is not null, the declaring class instance. Can be null if static.</param>
|
||||||
/// <param name="valueType">The type of the object or MemberInfo value.</param>
|
/// <param name="valueType">The type of the object or MemberInfo value.</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static CacheObject GetCacheObject(object obj, MemberInfo memberInfo, object declaringInstance, Type valueType)
|
public static CacheObjectBase GetCacheObject(object obj, MemberInfo memberInfo, object declaringInstance, Type valueType)
|
||||||
{
|
{
|
||||||
CacheObject holder;
|
CacheObjectBase holder;
|
||||||
|
|
||||||
if ((obj is Il2CppSystem.Object || typeof(Il2CppSystem.Object).IsAssignableFrom(valueType))
|
if (memberInfo is MethodInfo mi)
|
||||||
&& (valueType.FullName.Contains("UnityEngine.GameObject") || valueType.FullName.Contains("UnityEngine.Transform")))
|
{
|
||||||
|
if (CacheMethod.CanEvaluate(mi))
|
||||||
|
{
|
||||||
|
holder = new CacheMethod();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (valueType == typeof(GameObject) || valueType == typeof(Transform))
|
||||||
{
|
{
|
||||||
holder = new CacheGameObject();
|
holder = new CacheGameObject();
|
||||||
}
|
}
|
||||||
@ -107,10 +142,14 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
holder = new CacheEnum();
|
holder = new CacheEnum();
|
||||||
}
|
}
|
||||||
else if (typeof(System.Collections.IEnumerable).IsAssignableFrom(valueType) || ReflectionHelpers.IsList(valueType))
|
else if (ReflectionHelpers.IsArray(valueType) || ReflectionHelpers.IsList(valueType))
|
||||||
{
|
{
|
||||||
holder = new CacheList();
|
holder = new CacheList();
|
||||||
}
|
}
|
||||||
|
else if (ReflectionHelpers.IsDictionary(valueType))
|
||||||
|
{
|
||||||
|
holder = new CacheDictionary();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
holder = new CacheOther();
|
holder = new CacheOther();
|
||||||
@ -163,7 +202,7 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
GUILayout.Label("<color=red>Reflection failed!</color> (" + ReflectionException + ")", null);
|
GUILayout.Label("<color=red>Reflection failed!</color> (" + ReflectionException + ")", null);
|
||||||
}
|
}
|
||||||
else if (Value == null)
|
else if (Value == null && MemberInfoType != MemberTypes.Method)
|
||||||
{
|
{
|
||||||
GUILayout.Label("<i>null (" + ValueType + ")</i>", null);
|
GUILayout.Label("<i>null (" + ValueType + ")</i>", null);
|
||||||
}
|
}
|
@ -9,7 +9,7 @@ using UnityEngine;
|
|||||||
|
|
||||||
namespace Explorer
|
namespace Explorer
|
||||||
{
|
{
|
||||||
public class CacheOther : CacheObject
|
public class CacheOther : CacheObjectBase
|
||||||
{
|
{
|
||||||
private MethodInfo m_toStringMethod;
|
private MethodInfo m_toStringMethod;
|
||||||
private bool m_triedToGetMethod;
|
private bool m_triedToGetMethod;
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using MelonLoader;
|
using MelonLoader;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Explorer
|
namespace Explorer
|
||||||
{
|
{
|
||||||
public class CachePrimitive : CacheObject
|
public class CachePrimitive : CacheObjectBase
|
||||||
{
|
{
|
||||||
public enum PrimitiveTypes
|
public enum PrimitiveTypes
|
||||||
{
|
{
|
||||||
@ -13,7 +14,8 @@ namespace Explorer
|
|||||||
Double,
|
Double,
|
||||||
Float,
|
Float,
|
||||||
Int,
|
Int,
|
||||||
String
|
String,
|
||||||
|
Char
|
||||||
}
|
}
|
||||||
|
|
||||||
private string m_valueToString;
|
private string m_valueToString;
|
||||||
@ -37,10 +39,10 @@ namespace Explorer
|
|||||||
t = typeof(float); break;
|
t = typeof(float); break;
|
||||||
case PrimitiveTypes.Int:
|
case PrimitiveTypes.Int:
|
||||||
t = typeof(int); break;
|
t = typeof(int); break;
|
||||||
case PrimitiveTypes.String:
|
case PrimitiveTypes.Char:
|
||||||
t = typeof(string); break;
|
t = typeof(char); break;
|
||||||
}
|
}
|
||||||
m_parseMethod = t.GetMethod("Parse", new Type[] { typeof(string) });
|
m_parseMethod = t?.GetMethod("Parse", new Type[] { typeof(string) });
|
||||||
}
|
}
|
||||||
return m_parseMethod;
|
return m_parseMethod;
|
||||||
}
|
}
|
||||||
@ -52,7 +54,7 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
if (Value == null)
|
if (Value == null)
|
||||||
{
|
{
|
||||||
// this must mean it is a string? no other primitive type should be nullable
|
// this must mean it is a string. No other primitive type should be nullable.
|
||||||
PrimitiveType = PrimitiveTypes.String;
|
PrimitiveType = PrimitiveTypes.String;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -72,21 +74,39 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
PrimitiveType = PrimitiveTypes.Float;
|
PrimitiveType = PrimitiveTypes.Float;
|
||||||
}
|
}
|
||||||
else if (type == typeof(int) || type == typeof(long) || type == typeof(uint) || type == typeof(ulong) || type == typeof(IntPtr))
|
else if (IsInteger(type))
|
||||||
{
|
{
|
||||||
PrimitiveType = PrimitiveTypes.Int;
|
PrimitiveType = PrimitiveTypes.Int;
|
||||||
}
|
}
|
||||||
|
else if (type == typeof(char))
|
||||||
|
{
|
||||||
|
PrimitiveType = PrimitiveTypes.Char;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (type != typeof(string))
|
|
||||||
{
|
|
||||||
MelonLogger.Log("Unsupported primitive: " + type);
|
|
||||||
}
|
|
||||||
|
|
||||||
PrimitiveType = PrimitiveTypes.String;
|
PrimitiveType = PrimitiveTypes.String;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsInteger(Type type)
|
||||||
|
{
|
||||||
|
// For our purposes, all types of int can be treated the same, including IntPtr.
|
||||||
|
return _integerTypes.Contains(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly HashSet<Type> _integerTypes = new HashSet<Type>
|
||||||
|
{
|
||||||
|
typeof(int),
|
||||||
|
typeof(uint),
|
||||||
|
typeof(short),
|
||||||
|
typeof(ushort),
|
||||||
|
typeof(long),
|
||||||
|
typeof(ulong),
|
||||||
|
typeof(byte),
|
||||||
|
typeof(sbyte),
|
||||||
|
typeof(IntPtr)
|
||||||
|
};
|
||||||
|
|
||||||
public override void UpdateValue()
|
public override void UpdateValue()
|
||||||
{
|
{
|
||||||
base.UpdateValue();
|
base.UpdateValue();
|
||||||
@ -99,21 +119,26 @@ namespace Explorer
|
|||||||
if (PrimitiveType == PrimitiveTypes.Bool)
|
if (PrimitiveType == PrimitiveTypes.Bool)
|
||||||
{
|
{
|
||||||
var b = (bool)Value;
|
var b = (bool)Value;
|
||||||
var color = "<color=" + (b ? "lime>" : "red>");
|
var color = $"<color={(b ? "lime>" : "red>")}";
|
||||||
b = GUILayout.Toggle(b, color + b.ToString() + "</color>", null);
|
var label = $"{color}{b}</color>";
|
||||||
|
|
||||||
if (b != (bool)Value)
|
if (CanWrite)
|
||||||
{
|
{
|
||||||
SetValue(m_valueToString);
|
b = GUILayout.Toggle(b, label, null);
|
||||||
|
if (b != (bool)Value)
|
||||||
|
{
|
||||||
|
SetValue(m_valueToString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GUILayout.Label(label, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GUILayout.Label("<color=yellow><i>" + PrimitiveType + "</i></color>", new GUILayoutOption[] { GUILayout.Width(50) });
|
GUILayout.Label("<color=yellow><i>" + PrimitiveType + "</i></color>", new GUILayoutOption[] { GUILayout.Width(50) });
|
||||||
|
|
||||||
//var content = new GUIContent(m_valueToString);
|
|
||||||
//var contentSize = GUI.skin.textField.CalcSize(content);
|
|
||||||
|
|
||||||
int dynSize = 25 + (m_valueToString.Length * 15);
|
int dynSize = 25 + (m_valueToString.Length * 15);
|
||||||
var maxwidth = window.width - 300f;
|
var maxwidth = window.width - 300f;
|
||||||
if (CanWrite) maxwidth -= 60;
|
if (CanWrite) maxwidth -= 60;
|
||||||
|
@ -170,32 +170,34 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make it appear as though UnlockMouse is disabled to the rest of the application.
|
// Temporarily disabled this because I don't think it's actually useful, and may in fact cause problems instead
|
||||||
|
|
||||||
[HarmonyPatch(typeof(Cursor), nameof(Cursor.visible), MethodType.Getter)]
|
//// Make it appear as though UnlockMouse is disabled to the rest of the application.
|
||||||
public class Cursor_get_visible
|
|
||||||
{
|
|
||||||
[HarmonyPostfix]
|
|
||||||
public static void Postfix(ref bool __result)
|
|
||||||
{
|
|
||||||
if (ShouldForceMouse)
|
|
||||||
{
|
|
||||||
__result = m_lastVisibleState;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPatch(typeof(Cursor), nameof(Cursor.lockState), MethodType.Getter)]
|
//[HarmonyPatch(typeof(Cursor), nameof(Cursor.visible), MethodType.Getter)]
|
||||||
public class Cursor_get_lockState
|
//public class Cursor_get_visible
|
||||||
{
|
//{
|
||||||
[HarmonyPostfix]
|
// [HarmonyPostfix]
|
||||||
public static void Postfix(ref CursorLockMode __result)
|
// public static void Postfix(ref bool __result)
|
||||||
{
|
// {
|
||||||
if (ShouldForceMouse)
|
// if (ShouldForceMouse)
|
||||||
{
|
// {
|
||||||
__result = m_lastLockMode;
|
// __result = m_lastVisibleState;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
|
//[HarmonyPatch(typeof(Cursor), nameof(Cursor.lockState), MethodType.Getter)]
|
||||||
|
//public class Cursor_get_lockState
|
||||||
|
//{
|
||||||
|
// [HarmonyPostfix]
|
||||||
|
// public static void Postfix(ref CursorLockMode __result)
|
||||||
|
// {
|
||||||
|
// if (ShouldForceMouse)
|
||||||
|
// {
|
||||||
|
// __result = m_lastLockMode;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,11 +120,13 @@
|
|||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="CachedObjects\CacheDictionary.cs" />
|
||||||
<Compile Include="CachedObjects\CacheEnum.cs" />
|
<Compile Include="CachedObjects\CacheEnum.cs" />
|
||||||
<Compile Include="CachedObjects\CacheGameObject.cs" />
|
<Compile Include="CachedObjects\CacheGameObject.cs" />
|
||||||
<Compile Include="CachedObjects\CacheList.cs" />
|
<Compile Include="CachedObjects\CacheList.cs" />
|
||||||
<Compile Include="CachedObjects\CachePrimitive.cs" />
|
<Compile Include="CachedObjects\CachePrimitive.cs" />
|
||||||
<Compile Include="CachedObjects\CacheOther.cs" />
|
<Compile Include="CachedObjects\CacheOther.cs" />
|
||||||
|
<Compile Include="CachedObjects\CacheMethod.cs" />
|
||||||
<Compile Include="CppExplorer.cs" />
|
<Compile Include="CppExplorer.cs" />
|
||||||
<Compile Include="Extensions\ReflectionExtensions.cs" />
|
<Compile Include="Extensions\ReflectionExtensions.cs" />
|
||||||
<Compile Include="Extensions\UnityExtensions.cs" />
|
<Compile Include="Extensions\UnityExtensions.cs" />
|
||||||
@ -132,7 +134,7 @@
|
|||||||
<Compile Include="Helpers\UIHelpers.cs" />
|
<Compile Include="Helpers\UIHelpers.cs" />
|
||||||
<Compile Include="Helpers\UnityHelpers.cs" />
|
<Compile Include="Helpers\UnityHelpers.cs" />
|
||||||
<Compile Include="MainMenu\InspectUnderMouse.cs" />
|
<Compile Include="MainMenu\InspectUnderMouse.cs" />
|
||||||
<Compile Include="CachedObjects\CacheObject.cs" />
|
<Compile Include="CachedObjects\CacheObjectBase.cs" />
|
||||||
<Compile Include="Windows\ResizeDrag.cs" />
|
<Compile Include="Windows\ResizeDrag.cs" />
|
||||||
<Compile Include="Windows\UIWindow.cs" />
|
<Compile Include="Windows\UIWindow.cs" />
|
||||||
<Compile Include="MainMenu\Pages\ConsolePage.cs" />
|
<Compile Include="MainMenu\Pages\ConsolePage.cs" />
|
||||||
|
@ -72,6 +72,11 @@ namespace Explorer
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsArray(Type t)
|
||||||
|
{
|
||||||
|
return typeof(System.Collections.IEnumerable).IsAssignableFrom(t);
|
||||||
|
}
|
||||||
|
|
||||||
public static bool IsList(Type t)
|
public static bool IsList(Type t)
|
||||||
{
|
{
|
||||||
return t.IsGenericType
|
return t.IsGenericType
|
||||||
@ -79,6 +84,13 @@ namespace Explorer
|
|||||||
&& (typeDef.IsAssignableFrom(typeof(List<>)) || typeDef.IsAssignableFrom(typeof(Il2CppSystem.Collections.Generic.List<>)));
|
&& (typeDef.IsAssignableFrom(typeof(List<>)) || typeDef.IsAssignableFrom(typeof(Il2CppSystem.Collections.Generic.List<>)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsDictionary(Type t)
|
||||||
|
{
|
||||||
|
return t.IsGenericType
|
||||||
|
&& t.GetGenericTypeDefinition() is Type typeDef
|
||||||
|
&& typeDef.IsAssignableFrom(typeof(Il2CppSystem.Collections.Generic.Dictionary<,>));
|
||||||
|
}
|
||||||
|
|
||||||
public static Type GetTypeByName(string typeName)
|
public static Type GetTypeByName(string typeName)
|
||||||
{
|
{
|
||||||
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
|
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
|
||||||
|
@ -121,7 +121,9 @@ MelonLogger.Log(""hello world"");";
|
|||||||
{
|
{
|
||||||
GUILayout.Label("<b><size=15><color=cyan>C# REPL Console</color></size></b>", null);
|
GUILayout.Label("<b><size=15><color=cyan>C# REPL Console</color></size></b>", null);
|
||||||
|
|
||||||
GUILayout.Label("Method:", null);
|
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||||
|
|
||||||
|
GUILayout.Label("Enter code here as though it is a method body:", null);
|
||||||
MethodInput = GUILayout.TextArea(MethodInput, new GUILayoutOption[] { GUILayout.Height(250) });
|
MethodInput = GUILayout.TextArea(MethodInput, new GUILayoutOption[] { GUILayout.Height(250) });
|
||||||
|
|
||||||
if (GUILayout.Button("<color=cyan><b>Execute</b></color>", null))
|
if (GUILayout.Button("<color=cyan><b>Execute</b></color>", null))
|
||||||
@ -147,10 +149,7 @@ MelonLogger.Log(""hello world"");";
|
|||||||
}
|
}
|
||||||
|
|
||||||
GUILayout.Label("<b>Using directives:</b>", null);
|
GUILayout.Label("<b>Using directives:</b>", null);
|
||||||
foreach (var asm in UsingDirectives)
|
|
||||||
{
|
|
||||||
GUILayout.Label(AsmToUsing(asm, true), null);
|
|
||||||
}
|
|
||||||
GUILayout.BeginHorizontal(null);
|
GUILayout.BeginHorizontal(null);
|
||||||
GUILayout.Label("Add namespace:", new GUILayoutOption[] { GUILayout.Width(105) });
|
GUILayout.Label("Add namespace:", new GUILayoutOption[] { GUILayout.Width(105) });
|
||||||
UsingInput = GUILayout.TextField(UsingInput, new GUILayoutOption[] { GUILayout.Width(150) });
|
UsingInput = GUILayout.TextField(UsingInput, new GUILayoutOption[] { GUILayout.Width(150) });
|
||||||
@ -163,6 +162,11 @@ MelonLogger.Log(""hello world"");";
|
|||||||
ResetConsole();
|
ResetConsole();
|
||||||
}
|
}
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
foreach (var asm in UsingDirectives)
|
||||||
|
{
|
||||||
|
GUILayout.Label(AsmToUsing(asm, true), null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update() { }
|
public override void Update() { }
|
||||||
|
@ -26,7 +26,7 @@ namespace Explorer
|
|||||||
//private List<object> m_searchResults = new List<object>();
|
//private List<object> m_searchResults = new List<object>();
|
||||||
private Vector2 resultsScroll = Vector2.zero;
|
private Vector2 resultsScroll = Vector2.zero;
|
||||||
|
|
||||||
private List<CacheObject> m_searchResults = new List<CacheObject>();
|
private List<CacheObjectBase> m_searchResults = new List<CacheObjectBase>();
|
||||||
|
|
||||||
public SceneFilter SceneMode = SceneFilter.Any;
|
public SceneFilter SceneMode = SceneFilter.Any;
|
||||||
public TypeFilter TypeMode = TypeFilter.Object;
|
public TypeFilter TypeMode = TypeFilter.Object;
|
||||||
@ -64,7 +64,7 @@ namespace Explorer
|
|||||||
|
|
||||||
private void CacheResults(IEnumerable results)
|
private void CacheResults(IEnumerable results)
|
||||||
{
|
{
|
||||||
m_searchResults = new List<CacheObject>();
|
m_searchResults = new List<CacheObjectBase>();
|
||||||
|
|
||||||
foreach (var obj in results)
|
foreach (var obj in results)
|
||||||
{
|
{
|
||||||
@ -75,7 +75,7 @@ namespace Explorer
|
|||||||
toCache = ilObject.TryCast<GameObject>() ?? ilObject.TryCast<Transform>()?.gameObject ?? ilObject;
|
toCache = ilObject.TryCast<GameObject>() ?? ilObject.TryCast<Transform>()?.gameObject ?? ilObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
var cache = CacheObject.GetCacheObject(toCache);
|
var cache = CacheObjectBase.GetCacheObject(toCache);
|
||||||
m_searchResults.Add(cache);
|
m_searchResults.Add(cache);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ using MelonLoader;
|
|||||||
using UnhollowerRuntimeLib;
|
using UnhollowerRuntimeLib;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.SceneManagement;
|
using UnityEngine.SceneManagement;
|
||||||
using ComponentList = Il2CppSystem.Collections.Generic.List<UnityEngine.Component>;
|
|
||||||
|
|
||||||
namespace Explorer
|
namespace Explorer
|
||||||
{
|
{
|
||||||
@ -22,7 +21,7 @@ namespace Explorer
|
|||||||
|
|
||||||
private Vector2 m_transformScroll = Vector2.zero;
|
private Vector2 m_transformScroll = Vector2.zero;
|
||||||
private Transform[] m_children;
|
private Transform[] m_children;
|
||||||
private ComponentList m_components;
|
private Component[] m_components;
|
||||||
|
|
||||||
private Vector2 m_compScroll = Vector2.zero;
|
private Vector2 m_compScroll = Vector2.zero;
|
||||||
|
|
||||||
@ -69,11 +68,9 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_name = m_object.name;
|
m_name = m_object.name;
|
||||||
m_scene = m_object.scene == null ? "null" : m_object.scene.name;
|
m_scene = string.IsNullOrEmpty(m_object.scene.name)
|
||||||
|
? "None"
|
||||||
//var listComps = new Il2CppSystem.Collections.Generic.List<Component>();
|
: m_object.scene.name;
|
||||||
//m_object.GetComponents(listComps);
|
|
||||||
//m_components = listComps.ToArray();
|
|
||||||
|
|
||||||
var list = new List<Transform>();
|
var list = new List<Transform>();
|
||||||
for (int i = 0; i < m_object.transform.childCount; i++)
|
for (int i = 0; i < m_object.transform.childCount; i++)
|
||||||
@ -92,8 +89,12 @@ namespace Explorer
|
|||||||
throw new Exception("Object is null!");
|
throw new Exception("Object is null!");
|
||||||
}
|
}
|
||||||
|
|
||||||
m_components = new Il2CppSystem.Collections.Generic.List<Component>();
|
var list = new List<Component>();
|
||||||
m_object.GetComponentsInternal(ReflectionHelpers.ComponentType, false, false, true, false, m_components);
|
foreach (var comp in m_object.GetComponents(ReflectionHelpers.ComponentType))
|
||||||
|
{
|
||||||
|
list.Add(comp);
|
||||||
|
}
|
||||||
|
m_components = list.ToArray();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@ -255,34 +256,37 @@ namespace Explorer
|
|||||||
m_cachedDestroyList.Clear();
|
m_cachedDestroyList.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var component in m_components)
|
if (m_components != null)
|
||||||
{
|
{
|
||||||
if (!component) continue;
|
foreach (var component in m_components)
|
||||||
|
{
|
||||||
|
if (!component) continue;
|
||||||
|
|
||||||
var ilType = component.GetIl2CppType();
|
var ilType = component.GetIl2CppType();
|
||||||
if (ilType == ReflectionHelpers.TransformType)
|
if (ilType == ReflectionHelpers.TransformType)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
GUILayout.BeginHorizontal(null);
|
GUILayout.BeginHorizontal(null);
|
||||||
if (ReflectionHelpers.BehaviourType.IsAssignableFrom(ilType))
|
if (ReflectionHelpers.BehaviourType.IsAssignableFrom(ilType))
|
||||||
{
|
{
|
||||||
BehaviourEnabledBtn(component.TryCast<Behaviour>());
|
BehaviourEnabledBtn(component.TryCast<Behaviour>());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GUILayout.Space(26);
|
||||||
|
}
|
||||||
|
if (GUILayout.Button("<color=cyan>" + ilType.Name + "</color>", new GUILayoutOption[] { GUILayout.Width(m_rect.width / 2 - 90) }))
|
||||||
|
{
|
||||||
|
ReflectObject(component);
|
||||||
|
}
|
||||||
|
if (GUILayout.Button("<color=red>-</color>", new GUILayoutOption[] { GUILayout.Width(20) }))
|
||||||
|
{
|
||||||
|
m_cachedDestroyList.Add(component);
|
||||||
|
}
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
GUILayout.Space(26);
|
|
||||||
}
|
|
||||||
if (GUILayout.Button("<color=cyan>" + ilType.Name + "</color>", new GUILayoutOption[] { GUILayout.Width(m_rect.width / 2 - 90) }))
|
|
||||||
{
|
|
||||||
ReflectObject(component);
|
|
||||||
}
|
|
||||||
if (GUILayout.Button("<color=red>-</color>", new GUILayoutOption[] { GUILayout.Width(20) }))
|
|
||||||
{
|
|
||||||
m_cachedDestroyList.Add(component);
|
|
||||||
}
|
|
||||||
GUILayout.EndHorizontal();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GUI.skin.button.alignment = TextAnchor.MiddleCenter;
|
GUI.skin.button.alignment = TextAnchor.MiddleCenter;
|
||||||
|
@ -16,30 +16,27 @@ namespace Explorer
|
|||||||
|
|
||||||
public Type ObjectType;
|
public Type ObjectType;
|
||||||
|
|
||||||
private CacheObject[] m_cachedMembers;
|
private CacheObjectBase[] m_cachedMembers;
|
||||||
private CacheObject[] m_cachedMemberFiltered;
|
private CacheObjectBase[] m_cachedMemberFiltered;
|
||||||
private int m_pageOffset;
|
private int m_pageOffset;
|
||||||
private int m_limitPerPage = 20;
|
private int m_limitPerPage = 20;
|
||||||
|
|
||||||
private bool m_autoUpdate = false;
|
private bool m_autoUpdate = false;
|
||||||
private string m_search = "";
|
private string m_search = "";
|
||||||
public MemberInfoType m_filter = MemberInfoType.Property;
|
public MemberTypes m_filter = MemberTypes.Property;
|
||||||
private bool m_hideFailedReflection = false;
|
private bool m_hideFailedReflection = false;
|
||||||
|
|
||||||
public enum MemberInfoType
|
// some extra caching
|
||||||
{
|
private UnityEngine.Object m_uObj;
|
||||||
Field,
|
private Component m_component;
|
||||||
Property,
|
|
||||||
Method,
|
|
||||||
All
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Init()
|
public override void Init()
|
||||||
{
|
{
|
||||||
var type = ReflectionHelpers.GetActualType(Target);
|
var type = ReflectionHelpers.GetActualType(Target);
|
||||||
if (type == null)
|
if (type == null)
|
||||||
{
|
{
|
||||||
MelonLogger.Log("Could not get underlying type for object. ToString(): " + Target.ToString());
|
MelonLogger.Log($"Could not get underlying type for object..? Type: {Target?.GetType().Name}, ToString: {Target?.ToString()}");
|
||||||
|
DestroyWindow();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,10 +45,27 @@ namespace Explorer
|
|||||||
var types = ReflectionHelpers.GetAllBaseTypes(Target);
|
var types = ReflectionHelpers.GetAllBaseTypes(Target);
|
||||||
CacheMembers(types);
|
CacheMembers(types);
|
||||||
|
|
||||||
m_filter = MemberInfoType.All;
|
if (Target is Il2CppSystem.Object ilObject)
|
||||||
m_cachedMemberFiltered = m_cachedMembers.Where(x => ShouldProcessMember(x)).ToArray();
|
{
|
||||||
UpdateValues();
|
var unityObj = ilObject.TryCast<UnityEngine.Object>();
|
||||||
m_filter = MemberInfoType.Property;
|
if (unityObj)
|
||||||
|
{
|
||||||
|
m_uObj = unityObj;
|
||||||
|
|
||||||
|
var component = ilObject.TryCast<Component>();
|
||||||
|
if (component)
|
||||||
|
{
|
||||||
|
m_component = component;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_filter = MemberTypes.All;
|
||||||
|
m_autoUpdate = true;
|
||||||
|
Update();
|
||||||
|
|
||||||
|
m_autoUpdate = false;
|
||||||
|
m_filter = MemberTypes.Property;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update()
|
public override void Update()
|
||||||
@ -65,11 +79,6 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateValues()
|
private void UpdateValues()
|
||||||
{
|
|
||||||
UpdateMembers();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateMembers()
|
|
||||||
{
|
{
|
||||||
foreach (var member in m_cachedMemberFiltered)
|
foreach (var member in m_cachedMemberFiltered)
|
||||||
{
|
{
|
||||||
@ -77,9 +86,9 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ShouldProcessMember(CacheObject holder)
|
private bool ShouldProcessMember(CacheObjectBase holder)
|
||||||
{
|
{
|
||||||
if (m_filter != MemberInfoType.All && m_filter != holder.MemberInfoType) return false;
|
if (m_filter != MemberTypes.All && m_filter != holder.MemberInfoType) return false;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(holder.ReflectionException) && m_hideFailedReflection) return false;
|
if (!string.IsNullOrEmpty(holder.ReflectionException) && m_hideFailedReflection) return false;
|
||||||
|
|
||||||
@ -92,16 +101,13 @@ namespace Explorer
|
|||||||
|
|
||||||
private void CacheMembers(Type[] types)
|
private void CacheMembers(Type[] types)
|
||||||
{
|
{
|
||||||
var list = new List<CacheObject>();
|
var list = new List<CacheObjectBase>();
|
||||||
|
|
||||||
var names = new List<string>();
|
var names = new List<string>();
|
||||||
|
|
||||||
foreach (var declaringType in types)
|
foreach (var declaringType in types)
|
||||||
{
|
{
|
||||||
if (declaringType == typeof(Il2CppObjectBase)) continue;
|
|
||||||
|
|
||||||
MemberInfo[] infos;
|
MemberInfo[] infos;
|
||||||
|
|
||||||
string exception = null;
|
string exception = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -114,8 +120,8 @@ namespace Explorer
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//object value = null;
|
|
||||||
object target = Target;
|
object target = Target;
|
||||||
|
|
||||||
if (target is Il2CppSystem.Object ilObject)
|
if (target is Il2CppSystem.Object ilObject)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -130,9 +136,10 @@ namespace Explorer
|
|||||||
|
|
||||||
foreach (var member in infos)
|
foreach (var member in infos)
|
||||||
{
|
{
|
||||||
if (member.MemberType == MemberTypes.Field || member.MemberType == MemberTypes.Property)
|
if (member.MemberType == MemberTypes.Field || member.MemberType == MemberTypes.Property || member.MemberType == MemberTypes.Method)
|
||||||
{
|
{
|
||||||
if (member.Name == "Il2CppType") continue;
|
if (member.Name.Contains("Il2CppType") || member.Name.StartsWith("get_"))
|
||||||
|
continue;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -140,7 +147,7 @@ namespace Explorer
|
|||||||
if (names.Contains(name)) continue;
|
if (names.Contains(name)) continue;
|
||||||
names.Add(name);
|
names.Add(name);
|
||||||
|
|
||||||
var cached = CacheObject.GetCacheObject(null, member, target);
|
var cached = CacheObjectBase.GetCacheObject(null, member, target);
|
||||||
if (cached != null)
|
if (cached != null)
|
||||||
{
|
{
|
||||||
list.Add(cached);
|
list.Add(cached);
|
||||||
@ -149,9 +156,8 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
MelonLogger.Log("Exception caching member!");
|
MelonLogger.LogWarning($"Exception caching member {declaringType.Name}.{member.Name}!");
|
||||||
MelonLogger.Log(e.GetType() + ", " + e.Message);
|
MelonLogger.Log(e.ToString());
|
||||||
MelonLogger.Log(e.StackTrace);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -172,26 +178,18 @@ namespace Explorer
|
|||||||
|
|
||||||
GUILayout.BeginHorizontal(null);
|
GUILayout.BeginHorizontal(null);
|
||||||
GUILayout.Label("<b>Type:</b> <color=cyan>" + ObjectType.FullName + "</color>", null);
|
GUILayout.Label("<b>Type:</b> <color=cyan>" + ObjectType.FullName + "</color>", null);
|
||||||
|
if (m_uObj)
|
||||||
bool unityObj = Target is UnityEngine.Object;
|
|
||||||
|
|
||||||
if (unityObj)
|
|
||||||
{
|
{
|
||||||
GUILayout.Label("Name: " + (Target as UnityEngine.Object).name, null);
|
GUILayout.Label("Name: " + m_uObj.name, null);
|
||||||
}
|
}
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
if (unityObj)
|
if (m_uObj)
|
||||||
{
|
{
|
||||||
GUILayout.BeginHorizontal(null);
|
GUILayout.BeginHorizontal(null);
|
||||||
|
|
||||||
GUILayout.Label("<b>Tools:</b>", new GUILayoutOption[] { GUILayout.Width(80) });
|
GUILayout.Label("<b>Tools:</b>", new GUILayoutOption[] { GUILayout.Width(80) });
|
||||||
|
UIHelpers.InstantiateButton(m_uObj);
|
||||||
UIHelpers.InstantiateButton((UnityEngine.Object)Target);
|
if (m_component && m_component.gameObject is GameObject obj)
|
||||||
|
|
||||||
var comp = (Target as Il2CppSystem.Object).TryCast<Component>();
|
|
||||||
|
|
||||||
if (comp && comp.gameObject is GameObject obj)
|
|
||||||
{
|
{
|
||||||
GUI.skin.label.alignment = TextAnchor.MiddleRight;
|
GUI.skin.label.alignment = TextAnchor.MiddleRight;
|
||||||
GUILayout.Label("GameObject:", null);
|
GUILayout.Label("GameObject:", null);
|
||||||
@ -201,7 +199,6 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,9 +218,10 @@ namespace Explorer
|
|||||||
|
|
||||||
GUILayout.BeginHorizontal(null);
|
GUILayout.BeginHorizontal(null);
|
||||||
GUILayout.Label("<b>Filter:</b>", new GUILayoutOption[] { GUILayout.Width(75) });
|
GUILayout.Label("<b>Filter:</b>", new GUILayoutOption[] { GUILayout.Width(75) });
|
||||||
FilterToggle(MemberInfoType.All, "All");
|
FilterToggle(MemberTypes.All, "All");
|
||||||
FilterToggle(MemberInfoType.Property, "Properties");
|
FilterToggle(MemberTypes.Property, "Properties");
|
||||||
FilterToggle(MemberInfoType.Field, "Fields");
|
FilterToggle(MemberTypes.Field, "Fields");
|
||||||
|
FilterToggle(MemberTypes.Method, "Methods");
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
GUILayout.BeginHorizontal(null);
|
GUILayout.BeginHorizontal(null);
|
||||||
@ -284,18 +282,19 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawMembers(CacheObject[] members)
|
private void DrawMembers(CacheObjectBase[] members)
|
||||||
{
|
{
|
||||||
// todo pre-cache list based on current search, otherwise this doesnt work.
|
// todo pre-cache list based on current search, otherwise this doesnt work.
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
DrawMembersInternal("Properties", MemberInfoType.Property, members, ref i);
|
DrawMembersInternal("Properties", MemberTypes.Property, members, ref i);
|
||||||
DrawMembersInternal("Fields", MemberInfoType.Field, members, ref i);
|
DrawMembersInternal("Fields", MemberTypes.Field, members, ref i);
|
||||||
|
DrawMembersInternal("Methods", MemberTypes.Method, members, ref i);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawMembersInternal(string title, MemberInfoType filter, CacheObject[] members, ref int index)
|
private void DrawMembersInternal(string title, MemberTypes filter, CacheObjectBase[] members, ref int index)
|
||||||
{
|
{
|
||||||
if (m_filter != filter && m_filter != MemberInfoType.All)
|
if (m_filter != filter && m_filter != MemberTypes.All)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -336,7 +335,7 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FilterToggle(MemberInfoType mode, string label)
|
private void FilterToggle(MemberTypes mode, string label)
|
||||||
{
|
{
|
||||||
if (m_filter == mode)
|
if (m_filter == mode)
|
||||||
{
|
{
|
||||||
|
@ -59,6 +59,8 @@ namespace Explorer
|
|||||||
MelonLogger.Log("Exception on GuiResize: " + e.GetType() + ", " + e.Message);
|
MelonLogger.Log("Exception on GuiResize: " + e.GetType() + ", " + e.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||||
|
|
||||||
return _rect;
|
return _rect;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user