mirror of
https://github.com/GrahamKracker/UnityExplorer.git
synced 2025-07-04 20:42:22 +08:00
Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
c228d29707 | |||
56d1507aff | |||
72d31eaa64 | |||
4e8b84b67e | |||
5b94e31a12 | |||
692a37635e | |||
9cb1cea025 |
@ -1,4 +1,4 @@
|
|||||||
# CppExplorer []()
|
# CppExplorer [](https://github.com/HerpDerpinstine/MelonLoader)
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img align="center" src="https://sinai-dev.github.io/images/thumbs/02.png">
|
<img align="center" src="https://sinai-dev.github.io/images/thumbs/02.png">
|
||||||
|
@ -16,15 +16,14 @@ namespace Explorer
|
|||||||
public string ValueTypeName;
|
public string ValueTypeName;
|
||||||
public Type ValueType;
|
public Type ValueType;
|
||||||
|
|
||||||
// Reflection Inspector only
|
|
||||||
public MemberInfo MemInfo { get; set; }
|
public MemberInfo MemInfo { get; set; }
|
||||||
public Type DeclaringType { get; set; }
|
public Type DeclaringType { get; set; }
|
||||||
public object DeclaringInstance { get; set; }
|
public object DeclaringInstance { get; set; }
|
||||||
public string ReflectionException { get; set; }
|
|
||||||
|
|
||||||
public int PropertyIndex { get; private set; }
|
public int PropertyIndex { get; private set; }
|
||||||
private string m_propertyIndexInput = "0";
|
private string m_propertyIndexInput = "0";
|
||||||
|
|
||||||
|
public string ReflectionException { get; set; }
|
||||||
|
|
||||||
public string RichTextName => m_richTextName ?? GetRichTextName();
|
public string RichTextName => m_richTextName ?? GetRichTextName();
|
||||||
private string m_richTextName;
|
private string m_richTextName;
|
||||||
|
|
||||||
@ -115,6 +114,11 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
CacheObjectBase holder;
|
CacheObjectBase holder;
|
||||||
|
|
||||||
|
// This is pretty ugly, could probably make a cleaner implementation.
|
||||||
|
// However, the only cleaner ways I can think of are slower and probably not worth it.
|
||||||
|
|
||||||
|
// Note: the order is somewhat important.
|
||||||
|
|
||||||
if (memberInfo is MethodInfo mi)
|
if (memberInfo is MethodInfo mi)
|
||||||
{
|
{
|
||||||
if (CacheMethod.CanEvaluate(mi))
|
if (CacheMethod.CanEvaluate(mi))
|
||||||
@ -154,14 +158,15 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
holder = new CacheRect();
|
holder = new CacheRect();
|
||||||
}
|
}
|
||||||
else if (ReflectionHelpers.IsArray(valueType) || ReflectionHelpers.IsList(valueType))
|
// must check this before IsEnumerable
|
||||||
{
|
|
||||||
holder = new CacheList();
|
|
||||||
}
|
|
||||||
else if (ReflectionHelpers.IsDictionary(valueType))
|
else if (ReflectionHelpers.IsDictionary(valueType))
|
||||||
{
|
{
|
||||||
holder = new CacheDictionary();
|
holder = new CacheDictionary();
|
||||||
}
|
}
|
||||||
|
else if (ReflectionHelpers.IsEnumerable(valueType) || ReflectionHelpers.IsCppList(valueType))
|
||||||
|
{
|
||||||
|
holder = new CacheList();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
holder = new CacheOther();
|
holder = new CacheOther();
|
||||||
|
@ -1,34 +1,357 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
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 MelonLoader;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using System.Reflection;
|
||||||
|
using UnhollowerBaseLib;
|
||||||
|
|
||||||
namespace Explorer
|
namespace Explorer
|
||||||
{
|
{
|
||||||
public class CacheDictionary : CacheObjectBase
|
public class CacheDictionary : CacheObjectBase, IExpandHeight
|
||||||
{
|
{
|
||||||
|
public bool IsExpanded { get; set; }
|
||||||
|
public float WhiteSpace { get; set; } = 215f;
|
||||||
|
public float ButtonWidthOffset { get; set; } = 290f;
|
||||||
|
|
||||||
|
public PageHelper Pages = new PageHelper();
|
||||||
|
|
||||||
public override void Init()
|
private CacheObjectBase[] m_cachedKeys;
|
||||||
|
private CacheObjectBase[] m_cachedValues;
|
||||||
|
|
||||||
|
public Type TypeOfKeys
|
||||||
{
|
{
|
||||||
//base.Init();
|
get
|
||||||
|
{
|
||||||
|
if (m_keysType == null) GetGenericArguments();
|
||||||
|
return m_keysType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private Type m_keysType;
|
||||||
|
|
||||||
Value = "Unsupported";
|
public Type TypeOfValues
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (m_valuesType == null) GetGenericArguments();
|
||||||
|
return m_valuesType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private Type m_valuesType;
|
||||||
|
|
||||||
|
public IDictionary IDict
|
||||||
|
{
|
||||||
|
get => m_iDictionary ?? (m_iDictionary = Value as IDictionary) ?? Il2CppDictionaryToMono();
|
||||||
|
set => m_iDictionary = value;
|
||||||
|
}
|
||||||
|
private IDictionary m_iDictionary;
|
||||||
|
|
||||||
|
// ========== Methods ==========
|
||||||
|
|
||||||
|
// This is a bit janky due to Il2Cpp Dictionary not implementing IDictionary.
|
||||||
|
private IDictionary Il2CppDictionaryToMono()
|
||||||
|
{
|
||||||
|
// note: "ValueType" is the Dictionary itself, TypeOfValues is the 'Dictionary.Values' type.
|
||||||
|
|
||||||
|
// make generic dictionary from key and value type
|
||||||
|
var dict = (IDictionary)Activator.CreateInstance(typeof(Dictionary<,>)
|
||||||
|
.MakeGenericType(TypeOfKeys, TypeOfValues));
|
||||||
|
|
||||||
|
// get keys and values
|
||||||
|
var keys = ValueType.GetProperty("Keys") .GetValue(Value);
|
||||||
|
var values = ValueType.GetProperty("Values").GetValue(Value);
|
||||||
|
|
||||||
|
// create lists to hold them
|
||||||
|
var keyList = new List<object>();
|
||||||
|
var valueList = new List<object>();
|
||||||
|
|
||||||
|
// get keys enumerator and store keys
|
||||||
|
var keyEnumerator = keys.GetType().GetMethod("GetEnumerator").Invoke(keys, null);
|
||||||
|
var keyCollectionType = keyEnumerator.GetType();
|
||||||
|
var keyMoveNext = keyCollectionType.GetMethod("MoveNext");
|
||||||
|
var keyCurrent = keyCollectionType.GetProperty("Current");
|
||||||
|
while ((bool)keyMoveNext.Invoke(keyEnumerator, null))
|
||||||
|
{
|
||||||
|
keyList.Add(keyCurrent.GetValue(keyEnumerator));
|
||||||
|
}
|
||||||
|
|
||||||
|
// get values enumerator and store values
|
||||||
|
var valueEnumerator = values.GetType().GetMethod("GetEnumerator").Invoke(values, null);
|
||||||
|
var valueCollectionType = valueEnumerator.GetType();
|
||||||
|
var valueMoveNext = valueCollectionType.GetMethod("MoveNext");
|
||||||
|
var valueCurrent = valueCollectionType.GetProperty("Current");
|
||||||
|
while ((bool)valueMoveNext.Invoke(valueEnumerator, null))
|
||||||
|
{
|
||||||
|
valueList.Add(valueCurrent.GetValue(valueEnumerator));
|
||||||
|
}
|
||||||
|
|
||||||
|
// finally iterate into actual dictionary
|
||||||
|
for (int i = 0; i < keyList.Count; i++)
|
||||||
|
{
|
||||||
|
dict.Add(keyList[i], valueList[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GetGenericArguments()
|
||||||
|
{
|
||||||
|
if (this.MemInfo != null)
|
||||||
|
{
|
||||||
|
Type memberType = null;
|
||||||
|
switch (this.MemInfo.MemberType)
|
||||||
|
{
|
||||||
|
case MemberTypes.Field:
|
||||||
|
memberType = (MemInfo as FieldInfo).FieldType;
|
||||||
|
break;
|
||||||
|
case MemberTypes.Property:
|
||||||
|
memberType = (MemInfo as PropertyInfo).PropertyType;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memberType != null && memberType.IsGenericType)
|
||||||
|
{
|
||||||
|
m_keysType = memberType.GetGenericArguments()[0];
|
||||||
|
m_valuesType = memberType.GetGenericArguments()[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Value != null)
|
||||||
|
{
|
||||||
|
var type = Value.GetType();
|
||||||
|
if (type.IsGenericType)
|
||||||
|
{
|
||||||
|
m_keysType = type.GetGenericArguments()[0];
|
||||||
|
m_valuesType = type.GetGenericArguments()[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateValue()
|
public override void UpdateValue()
|
||||||
{
|
{
|
||||||
//base.UpdateValue();
|
// first make sure we won't run into a TypeInitializationException.
|
||||||
|
if (!EnsureDictionaryIsSupported())
|
||||||
|
{
|
||||||
|
ReflectionException = "Dictionary Type not supported with Reflection!";
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base.UpdateValue();
|
||||||
|
|
||||||
|
// reset
|
||||||
|
IDict = null;
|
||||||
|
|
||||||
|
if (Value == null || IDict == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var keys = new List<CacheObjectBase>();
|
||||||
|
foreach (var key in IDict.Keys)
|
||||||
|
{
|
||||||
|
var cache = GetCacheObject(key, TypeOfKeys);
|
||||||
|
cache.UpdateValue();
|
||||||
|
keys.Add(cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
var values = new List<CacheObjectBase>();
|
||||||
|
foreach (var val in IDict.Values)
|
||||||
|
{
|
||||||
|
var cache = GetCacheObject(val, TypeOfValues);
|
||||||
|
cache.UpdateValue();
|
||||||
|
values.Add(cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_cachedKeys = keys.ToArray();
|
||||||
|
m_cachedValues = values.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool EnsureDictionaryIsSupported()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//var ilTypes = new List<Il2CppSystem.Type>();
|
||||||
|
var monoTypes = new Type[] { TypeOfKeys, TypeOfValues };
|
||||||
|
|
||||||
|
foreach (var type in monoTypes)
|
||||||
|
{
|
||||||
|
var generic = typeof(Il2CppClassPointerStore<>).MakeGenericType(type);
|
||||||
|
if (generic == null) return false;
|
||||||
|
|
||||||
|
var genericPtr = (IntPtr)generic.GetField("NativeClassPtr").GetValue(null);
|
||||||
|
if (genericPtr == null) return false;
|
||||||
|
|
||||||
|
var classPtr = IL2CPP.il2cpp_class_get_type(genericPtr);
|
||||||
|
if (classPtr == null) return false;
|
||||||
|
|
||||||
|
var internalType = Il2CppSystem.Type.internal_from_handle(classPtr);
|
||||||
|
if (internalType == null) return false;
|
||||||
|
|
||||||
|
//ilTypes.Add(internalType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should be fine if we got this far, but I'll leave the rest below commented out just in case.
|
||||||
|
return true;
|
||||||
|
|
||||||
|
//MelonLogger.Log("Got both generic types, continuing...");
|
||||||
|
|
||||||
|
//var dictIlClass = IL2CPP.GetIl2CppClass("mscorlib.dll", "System.Collections.Generic", "Dictionary`2");
|
||||||
|
//if (dictIlClass == null) return;
|
||||||
|
|
||||||
|
//MelonLogger.Log("Got base dictionary Il2Cpp type");
|
||||||
|
|
||||||
|
//var ilClassFromType = IL2CPP.il2cpp_class_get_type(dictIlClass);
|
||||||
|
//if (ilClassFromType == null) return;
|
||||||
|
|
||||||
|
//MelonLogger.Log("got IntPtr from base dictionary type");
|
||||||
|
|
||||||
|
//var internalHandle = Il2CppSystem.Type.internal_from_handle(ilClassFromType);
|
||||||
|
//if (internalHandle == null) return;
|
||||||
|
|
||||||
|
//var generic = internalHandle.MakeGenericType(new Il2CppReferenceArray<Il2CppSystem.Type>(new Il2CppSystem.Type[]
|
||||||
|
//{
|
||||||
|
// ilTypes[0], ilTypes[1]
|
||||||
|
//}));
|
||||||
|
//if (generic == null) return;
|
||||||
|
|
||||||
|
//MelonLogger.Log("Made generic handle for our entry types");
|
||||||
|
|
||||||
|
//var nativeClassPtr = generic.TypeHandle.value;
|
||||||
|
//if (nativeClassPtr == null) return;
|
||||||
|
|
||||||
|
//MelonLogger.Log("Got the actual nativeClassPtr for the handle");
|
||||||
|
|
||||||
|
//var dictType = typeof(Il2CppSystem.Collections.Generic.Dictionary<,>).MakeGenericType(TypeOfKeys, TypeOfValues);
|
||||||
|
//if (dictType == null) return;
|
||||||
|
|
||||||
|
//MelonLogger.Log("Made the generic type for the dictionary");
|
||||||
|
|
||||||
|
//var pointerStoreType = typeof(Il2CppClassPointerStore<>).MakeGenericType(dictType);
|
||||||
|
//if (pointerStoreType == null) return;
|
||||||
|
|
||||||
|
//MelonLogger.Log("Made the generic PointerStoreType for our dict");
|
||||||
|
|
||||||
|
//var ptrToSet = IL2CPP.il2cpp_class_from_type(nativeClassPtr);
|
||||||
|
//if (ptrToSet == null) return;
|
||||||
|
|
||||||
|
//MelonLogger.Log("Got class from nativeClassPtr, setting value...");
|
||||||
|
|
||||||
|
//pointerStoreType.GetField("NativeClassPtr").SetValue(null, ptrToSet);
|
||||||
|
|
||||||
|
//MelonLogger.Log("Ok");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============= GUI Draw =============
|
||||||
|
|
||||||
public override void DrawValue(Rect window, float width)
|
public override void DrawValue(Rect window, float width)
|
||||||
{
|
{
|
||||||
GUILayout.Label("<color=red>Dictionary (unsupported)</color>", null);
|
if (m_cachedKeys == null || m_cachedValues == null)
|
||||||
|
{
|
||||||
|
GUILayout.Label("Cached keys or values is null!", null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = m_cachedKeys.Length;
|
||||||
|
|
||||||
|
if (!IsExpanded)
|
||||||
|
{
|
||||||
|
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||||
|
{
|
||||||
|
IsExpanded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||||
|
{
|
||||||
|
IsExpanded = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
||||||
|
string btnLabel = $"<color=yellow>[{count}] Dictionary<{TypeOfKeys.FullName}, {TypeOfValues.FullName}></color>";
|
||||||
|
if (GUILayout.Button(btnLabel, new GUILayoutOption[] { GUILayout.MaxWidth(window.width - ButtonWidthOffset) }))
|
||||||
|
{
|
||||||
|
WindowManager.InspectObject(Value, out bool _);
|
||||||
|
}
|
||||||
|
GUI.skin.button.alignment = TextAnchor.MiddleCenter;
|
||||||
|
|
||||||
|
GUILayout.Space(5);
|
||||||
|
|
||||||
|
if (IsExpanded)
|
||||||
|
{
|
||||||
|
float whitespace = WhiteSpace;
|
||||||
|
if (whitespace > 0)
|
||||||
|
{
|
||||||
|
ClampLabelWidth(window, ref whitespace);
|
||||||
|
}
|
||||||
|
|
||||||
|
Pages.ItemCount = count;
|
||||||
|
|
||||||
|
if (count > Pages.ItemsPerPage)
|
||||||
|
{
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
|
||||||
|
GUILayout.Space(whitespace);
|
||||||
|
|
||||||
|
Pages.CurrentPageLabel();
|
||||||
|
|
||||||
|
// prev/next page buttons
|
||||||
|
if (GUILayout.Button("< Prev", new GUILayoutOption[] { GUILayout.Width(60) }))
|
||||||
|
{
|
||||||
|
Pages.TurnPage(Turn.Left);
|
||||||
|
}
|
||||||
|
if (GUILayout.Button("Next >", new GUILayoutOption[] { GUILayout.Width(60) }))
|
||||||
|
{
|
||||||
|
Pages.TurnPage(Turn.Right);
|
||||||
|
}
|
||||||
|
|
||||||
|
Pages.DrawLimitInputArea();
|
||||||
|
|
||||||
|
GUILayout.Space(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
int offset = Pages.CalculateOffsetIndex();
|
||||||
|
|
||||||
|
for (int i = offset; i < offset + Pages.ItemsPerPage && i < count; i++)
|
||||||
|
{
|
||||||
|
var key = m_cachedKeys[i];
|
||||||
|
var val = m_cachedValues[i];
|
||||||
|
|
||||||
|
//collapsing the BeginHorizontal called from ReflectionWindow.WindowFunction or previous array entry
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
|
||||||
|
//GUILayout.Space(whitespace);
|
||||||
|
|
||||||
|
if (key == null || val == null)
|
||||||
|
{
|
||||||
|
GUILayout.Label($"[{i}] <i><color=grey>(null)</color></i>", null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
|
||||||
|
GUILayout.Label($"[{i}]", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||||
|
|
||||||
|
GUILayout.Label("Key:", new GUILayoutOption[] { GUILayout.Width(40) });
|
||||||
|
key.DrawValue(window, (window.width / 2) - 30f);
|
||||||
|
|
||||||
|
GUILayout.Label("Value:", new GUILayoutOption[] { GUILayout.Width(40) });
|
||||||
|
val.DrawValue(window, (window.width / 2) - 30f);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,13 +8,13 @@ using UnityEngine;
|
|||||||
|
|
||||||
namespace Explorer
|
namespace Explorer
|
||||||
{
|
{
|
||||||
public class CacheList : CacheObjectBase
|
public class CacheList : CacheObjectBase, IExpandHeight
|
||||||
{
|
{
|
||||||
public bool IsExpanded { get; set; }
|
public bool IsExpanded { get; set; }
|
||||||
public PageHelper Pages = new PageHelper();
|
public float WhiteSpace { get; set; } = 215f;
|
||||||
|
public float ButtonWidthOffset { get; set; } = 290f;
|
||||||
|
|
||||||
public float WhiteSpace = 215f;
|
public PageHelper Pages = new PageHelper();
|
||||||
public float ButtonWidthOffset = 290f;
|
|
||||||
|
|
||||||
private CacheObjectBase[] m_cachedEntries;
|
private CacheObjectBase[] m_cachedEntries;
|
||||||
|
|
||||||
@ -52,6 +52,7 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
get => GetItemProperty();
|
get => GetItemProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private PropertyInfo m_itemProperty;
|
private PropertyInfo m_itemProperty;
|
||||||
|
|
||||||
// ========== Methods ==========
|
// ========== Methods ==========
|
||||||
@ -218,6 +219,7 @@ namespace Explorer
|
|||||||
|
|
||||||
if (GetCacheObject(obj, t) is CacheObjectBase cached)
|
if (GetCacheObject(obj, t) is CacheObjectBase cached)
|
||||||
{
|
{
|
||||||
|
cached.UpdateValue();
|
||||||
list.Add(cached);
|
list.Add(cached);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -262,7 +264,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.FullName + "</color>";
|
||||||
if (GUILayout.Button(btnLabel, new GUILayoutOption[] { GUILayout.MaxWidth(window.width - ButtonWidthOffset) }))
|
if (GUILayout.Button(btnLabel, new GUILayoutOption[] { GUILayout.MaxWidth(window.width - ButtonWidthOffset) }))
|
||||||
{
|
{
|
||||||
WindowManager.InspectObject(Value, out bool _);
|
WindowManager.InspectObject(Value, out bool _);
|
||||||
@ -305,12 +307,6 @@ namespace Explorer
|
|||||||
GUILayout.Space(5);
|
GUILayout.Space(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
//int offset = ArrayOffset * ArrayLimit;
|
|
||||||
//if (offset >= count)
|
|
||||||
//{
|
|
||||||
// offset = 0;
|
|
||||||
// ArrayOffset = 0;
|
|
||||||
//}
|
|
||||||
int offset = Pages.CalculateOffsetIndex();
|
int offset = Pages.CalculateOffsetIndex();
|
||||||
|
|
||||||
for (int i = offset; i < offset + Pages.ItemsPerPage && i < count; i++)
|
for (int i = offset; i < offset + Pages.ItemsPerPage && i < count; i++)
|
||||||
|
@ -18,28 +18,17 @@ namespace Explorer
|
|||||||
private ParameterInfo[] m_arguments;
|
private ParameterInfo[] m_arguments;
|
||||||
private string[] m_argumentInput;
|
private string[] m_argumentInput;
|
||||||
|
|
||||||
public bool HasParameters
|
public bool HasParameters => m_arguments != null && m_arguments.Length > 0;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (m_hasParams == null)
|
|
||||||
{
|
|
||||||
m_hasParams = (MemInfo as MethodInfo).GetParameters().Length > 0;
|
|
||||||
}
|
|
||||||
return (bool)m_hasParams;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private bool? m_hasParams;
|
|
||||||
|
|
||||||
public static bool CanEvaluate(MethodInfo mi)
|
public static bool CanEvaluate(MethodInfo mi)
|
||||||
{
|
{
|
||||||
// generic type args not supported yet
|
// TODO generic args
|
||||||
if (mi.GetGenericArguments().Length > 0)
|
if (mi.GetGenericArguments().Length > 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// only primitive and string args supported
|
// primitive and string args supported
|
||||||
foreach (var param in mi.GetParameters())
|
foreach (var param in mi.GetParameters())
|
||||||
{
|
{
|
||||||
if (!param.ParameterType.IsPrimitive && param.ParameterType != typeof(string))
|
if (!param.ParameterType.IsPrimitive && param.ParameterType != typeof(string))
|
||||||
@ -66,6 +55,83 @@ namespace Explorer
|
|||||||
//base.UpdateValue();
|
//base.UpdateValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Evaluate()
|
||||||
|
{
|
||||||
|
var mi = MemInfo as MethodInfo;
|
||||||
|
|
||||||
|
object ret = null;
|
||||||
|
|
||||||
|
if (!HasParameters)
|
||||||
|
{
|
||||||
|
ret = mi.Invoke(mi.IsStatic ? null : DeclaringInstance, new object[0]);
|
||||||
|
m_evaluated = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var parsedArgs = 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))
|
||||||
|
{
|
||||||
|
parsedArgs.Add(input);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (type.GetMethod("Parse", new Type[] { typeof(string) }).Invoke(null, new object[] { input }) is object parsed)
|
||||||
|
{
|
||||||
|
parsedArgs.Add(parsed);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// try add a null arg i guess
|
||||||
|
parsedArgs.Add(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
MelonLogger.Log($"Unable to parse '{input}' to type '{type.Name}'");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ret = mi.Invoke(mi.IsStatic ? null : DeclaringInstance, parsedArgs.ToArray());
|
||||||
|
m_evaluated = true;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MelonLogger.Log($"Exception evaluating: {e.GetType()}, {e.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret != null)
|
||||||
|
{
|
||||||
|
m_cachedReturnValue = GetCacheObject(ret);
|
||||||
|
|
||||||
|
if (m_cachedReturnValue is IExpandHeight expander)
|
||||||
|
{
|
||||||
|
expander.WhiteSpace = 0f;
|
||||||
|
expander.ButtonWidthOffset += 70f;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_cachedReturnValue.UpdateValue();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_cachedReturnValue = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==== GUI DRAW ====
|
||||||
|
|
||||||
public override void DrawValue(Rect window, float width)
|
public override void DrawValue(Rect window, float width)
|
||||||
{
|
{
|
||||||
GUILayout.BeginVertical(null);
|
GUILayout.BeginVertical(null);
|
||||||
@ -123,17 +189,9 @@ namespace Explorer
|
|||||||
if (m_evaluated)
|
if (m_evaluated)
|
||||||
{
|
{
|
||||||
if (m_cachedReturnValue != null)
|
if (m_cachedReturnValue != null)
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
m_cachedReturnValue.DrawValue(window, width);
|
m_cachedReturnValue.DrawValue(window, width);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
MelonLogger.Log("Exception drawing m_cachedReturnValue!");
|
|
||||||
MelonLogger.Log(e.ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GUILayout.Label($"null (<color=yellow>{ValueTypeName}</color>)", null);
|
GUILayout.Label($"null (<color=yellow>{ValueTypeName}</color>)", null);
|
||||||
@ -147,77 +205,5 @@ namespace Explorer
|
|||||||
|
|
||||||
GUILayout.EndVertical();
|
GUILayout.EndVertical();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Evaluate()
|
|
||||||
{
|
|
||||||
var mi = MemInfo as MethodInfo;
|
|
||||||
|
|
||||||
object ret = null;
|
|
||||||
|
|
||||||
if (!HasParameters)
|
|
||||||
{
|
|
||||||
ret = mi.Invoke(mi.IsStatic ? null : DeclaringInstance, new object[0]);
|
|
||||||
m_evaluated = true;
|
|
||||||
}
|
|
||||||
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());
|
|
||||||
m_evaluated = true;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
@ -12,7 +13,7 @@ namespace Explorer
|
|||||||
public class CppExplorer : MelonMod
|
public class CppExplorer : MelonMod
|
||||||
{
|
{
|
||||||
public const string GUID = "com.sinai.cppexplorer";
|
public const string GUID = "com.sinai.cppexplorer";
|
||||||
public const string VERSION = "1.5.8";
|
public const string VERSION = "1.6.2";
|
||||||
public const string AUTHOR = "Sinai";
|
public const string AUTHOR = "Sinai";
|
||||||
|
|
||||||
public const string NAME = "CppExplorer"
|
public const string NAME = "CppExplorer"
|
||||||
|
@ -120,6 +120,7 @@
|
|||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="Helpers\IExpandHeight.cs" />
|
||||||
<Compile Include="CachedObjects\Struct\CacheColor.cs" />
|
<Compile Include="CachedObjects\Struct\CacheColor.cs" />
|
||||||
<Compile Include="CachedObjects\Object\CacheDictionary.cs" />
|
<Compile Include="CachedObjects\Object\CacheDictionary.cs" />
|
||||||
<Compile Include="CachedObjects\Struct\CacheEnum.cs" />
|
<Compile Include="CachedObjects\Struct\CacheEnum.cs" />
|
||||||
|
16
src/Helpers/IExpandHeight.cs
Normal file
16
src/Helpers/IExpandHeight.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Explorer
|
||||||
|
{
|
||||||
|
interface IExpandHeight
|
||||||
|
{
|
||||||
|
bool IsExpanded { get; set; }
|
||||||
|
|
||||||
|
float WhiteSpace { get; set; }
|
||||||
|
float ButtonWidthOffset { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,8 @@ using UnhollowerRuntimeLib;
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using BF = System.Reflection.BindingFlags;
|
using BF = System.Reflection.BindingFlags;
|
||||||
using MelonLoader;
|
using MelonLoader;
|
||||||
|
using System.Collections;
|
||||||
|
using Mono.CSharp;
|
||||||
|
|
||||||
namespace Explorer
|
namespace Explorer
|
||||||
{
|
{
|
||||||
@ -74,45 +76,54 @@ namespace Explorer
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsArray(Type t)
|
public static bool IsEnumerable(Type t)
|
||||||
{
|
{
|
||||||
return typeof(System.Collections.IEnumerable).IsAssignableFrom(t);
|
return typeof(IEnumerable).IsAssignableFrom(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsList(Type t)
|
// Only Il2Cpp List needs this check. C# List is IEnumerable.
|
||||||
|
public static bool IsCppList(Type t)
|
||||||
{
|
{
|
||||||
if (t.IsGenericType)
|
if (t.IsGenericType && t.GetGenericTypeDefinition() is Type g)
|
||||||
{
|
{
|
||||||
var generic = t.GetGenericTypeDefinition();
|
return typeof(Il2CppSystem.Collections.Generic.List<>).IsAssignableFrom(g)
|
||||||
|
|| typeof(Il2CppSystem.Collections.Generic.IList<>).IsAssignableFrom(g);
|
||||||
return generic.IsAssignableFrom(typeof(Il2CppSystem.Collections.Generic.List<>))
|
|
||||||
|| generic.IsAssignableFrom(typeof(Il2CppSystem.Collections.Generic.IList<>));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return t.IsAssignableFrom(typeof(Il2CppSystem.Collections.IList));
|
return typeof(Il2CppSystem.Collections.IList).IsAssignableFrom(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsDictionary(Type t)
|
public static bool IsDictionary(Type t)
|
||||||
{
|
{
|
||||||
return t.IsGenericType
|
if (typeof(IDictionary).IsAssignableFrom(t))
|
||||||
&& t.GetGenericTypeDefinition() is Type typeDef
|
{
|
||||||
&& typeDef.IsAssignableFrom(typeof(Il2CppSystem.Collections.Generic.Dictionary<,>));
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t.IsGenericType && t.GetGenericTypeDefinition() is Type g)
|
||||||
|
{
|
||||||
|
return typeof(Il2CppSystem.Collections.Generic.Dictionary<,>).IsAssignableFrom(g)
|
||||||
|
|| typeof(Il2CppSystem.Collections.Generic.IDictionary<,>).IsAssignableFrom(g);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return typeof(Il2CppSystem.Collections.IDictionary).IsAssignableFrom(t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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())
|
||||||
{
|
{
|
||||||
try
|
foreach (var type in GetTypesSafe(asm))
|
||||||
{
|
{
|
||||||
if (asm.GetType(typeName) is Type type)
|
if (type.FullName == typeName)
|
||||||
{
|
{
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch { }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -137,6 +148,13 @@ namespace Explorer
|
|||||||
return obj.GetType();
|
return obj.GetType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<Type> GetTypesSafe(Assembly asm)
|
||||||
|
{
|
||||||
|
try { return asm.GetTypes(); }
|
||||||
|
catch (ReflectionTypeLoadException e) { return e.Types.Where(x => x != null); }
|
||||||
|
catch { return Enumerable.Empty<Type>(); }
|
||||||
|
}
|
||||||
|
|
||||||
public static Type[] GetAllBaseTypes(object obj)
|
public static Type[] GetAllBaseTypes(object obj)
|
||||||
{
|
{
|
||||||
var list = new List<Type>();
|
var list = new List<Type>();
|
||||||
|
@ -56,7 +56,10 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
_horizBarStyle = new GUIStyle();
|
_horizBarStyle = new GUIStyle();
|
||||||
_horizBarStyle.normal.background = Texture2D.whiteTexture;
|
_horizBarStyle.normal.background = Texture2D.whiteTexture;
|
||||||
_horizBarStyle.margin = new RectOffset(0, 0, 4, 4);
|
var rectOffset = new RectOffset();
|
||||||
|
rectOffset.top = 4;
|
||||||
|
rectOffset.bottom = 4;
|
||||||
|
_horizBarStyle.margin = rectOffset;
|
||||||
_horizBarStyle.fixedHeight = 2;
|
_horizBarStyle.fixedHeight = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +76,10 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
_horizBarSmallStyle = new GUIStyle();
|
_horizBarSmallStyle = new GUIStyle();
|
||||||
_horizBarSmallStyle.normal.background = Texture2D.whiteTexture;
|
_horizBarSmallStyle.normal.background = Texture2D.whiteTexture;
|
||||||
_horizBarSmallStyle.margin = new RectOffset(0, 0, 2, 2);
|
var rectOffset = new RectOffset();
|
||||||
|
rectOffset.top = 2;
|
||||||
|
rectOffset.bottom = 2;
|
||||||
|
_horizBarSmallStyle.margin = rectOffset;
|
||||||
_horizBarSmallStyle.fixedHeight = 1;
|
_horizBarSmallStyle.fixedHeight = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,8 @@ namespace Explorer
|
|||||||
private ScriptEvaluator _evaluator;
|
private ScriptEvaluator _evaluator;
|
||||||
private readonly StringBuilder _sb = new StringBuilder();
|
private readonly StringBuilder _sb = new StringBuilder();
|
||||||
|
|
||||||
|
private Vector2 inputAreaScroll;
|
||||||
|
|
||||||
private string MethodInput = "";
|
private string MethodInput = "";
|
||||||
private string UsingInput = "";
|
private string UsingInput = "";
|
||||||
|
|
||||||
@ -124,7 +126,12 @@ MelonLogger.Log(""hello world"");";
|
|||||||
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||||
|
|
||||||
GUILayout.Label("Enter code here as though it is a method body:", null);
|
GUILayout.Label("Enter code here as though it is a method body:", null);
|
||||||
MethodInput = GUILayout.TextArea(MethodInput, new GUILayoutOption[] { GUILayout.Height(250) });
|
|
||||||
|
inputAreaScroll = GUIUnstrip.BeginScrollView(inputAreaScroll, new GUILayoutOption[] { GUILayout.Height(250) });
|
||||||
|
|
||||||
|
MethodInput = GUILayout.TextArea(MethodInput, new GUILayoutOption[] { GUILayout.ExpandHeight(true) });
|
||||||
|
|
||||||
|
GUIUnstrip.EndScrollView();
|
||||||
|
|
||||||
if (GUILayout.Button("<color=cyan><b>Execute</b></color>", null))
|
if (GUILayout.Button("<color=cyan><b>Execute</b></color>", null))
|
||||||
{
|
{
|
||||||
|
@ -172,16 +172,6 @@ namespace Explorer
|
|||||||
GUILayout.Label("Name Contains:", new GUILayoutOption[] { GUILayout.Width(100) });
|
GUILayout.Label("Name Contains:", new GUILayoutOption[] { GUILayout.Width(100) });
|
||||||
m_searchInput = GUILayout.TextField(m_searchInput, new GUILayoutOption[] { GUILayout.Width(200) });
|
m_searchInput = GUILayout.TextField(m_searchInput, new GUILayoutOption[] { GUILayout.Width(200) });
|
||||||
|
|
||||||
//GUI.skin.label.alignment = TextAnchor.MiddleRight;
|
|
||||||
//GUILayout.Label("Results per page:", new GUILayoutOption[] { GUILayout.Width(120) });
|
|
||||||
//var resultinput = m_limit.ToString();
|
|
||||||
//resultinput = GUILayout.TextField(resultinput, new GUILayoutOption[] { GUILayout.Width(55) });
|
|
||||||
//if (int.TryParse(resultinput, out int _i) && _i > 0)
|
|
||||||
//{
|
|
||||||
// m_limit = _i;
|
|
||||||
//}
|
|
||||||
//GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
|
||||||
|
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
GUILayout.BeginHorizontal(null);
|
GUILayout.BeginHorizontal(null);
|
||||||
@ -263,7 +253,7 @@ namespace Explorer
|
|||||||
CacheResults(FindAllObjectsOfType(m_searchInput, m_typeInput));
|
CacheResults(FindAllObjectsOfType(m_searchInput, m_typeInput));
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<object> FindAllObjectsOfType(string _search, string _type)
|
private List<object> FindAllObjectsOfType(string searchQuery, string typeName)
|
||||||
{
|
{
|
||||||
Il2CppSystem.Type searchType = null;
|
Il2CppSystem.Type searchType = null;
|
||||||
|
|
||||||
@ -271,13 +261,18 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var findType = ReflectionHelpers.GetTypeByName(_type);
|
if (ReflectionHelpers.GetTypeByName(typeName) is Type t)
|
||||||
searchType = Il2CppSystem.Type.GetType(findType.AssemblyQualifiedName);
|
{
|
||||||
//MelonLogger.Log("Search type: " + findType.AssemblyQualifiedName);
|
searchType = Il2CppSystem.Type.GetType(t.AssemblyQualifiedName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception($"Could not find a Type by the name of '{typeName}'!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
MelonLogger.Log("Exception: " + e.GetType() + ", " + e.Message + "\r\n" + e.StackTrace);
|
MelonLogger.Log("Exception getting Search Type: " + e.GetType() + ", " + e.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (TypeMode == TypeFilter.Object)
|
else if (TypeMode == TypeFilter.Object)
|
||||||
@ -295,7 +290,10 @@ namespace Explorer
|
|||||||
|
|
||||||
if (!ReflectionHelpers.ObjectType.IsAssignableFrom(searchType))
|
if (!ReflectionHelpers.ObjectType.IsAssignableFrom(searchType))
|
||||||
{
|
{
|
||||||
MelonLogger.LogError("Your Custom Class Type must inherit from UnityEngine.Object!");
|
if (searchType != null)
|
||||||
|
{
|
||||||
|
MelonLogger.LogWarning("Your Custom Class Type must inherit from UnityEngine.Object!");
|
||||||
|
}
|
||||||
return new List<object>();
|
return new List<object>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,7 +308,7 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
if (i >= 2000) break;
|
if (i >= 2000) break;
|
||||||
|
|
||||||
if (_search != "" && !obj.name.ToLower().Contains(_search.ToLower()))
|
if (searchQuery != "" && !obj.name.ToLower().Contains(searchQuery.ToLower()))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -387,7 +385,7 @@ namespace Explorer
|
|||||||
public static IEnumerable<object> GetInstanceClassScanner()
|
public static IEnumerable<object> GetInstanceClassScanner()
|
||||||
{
|
{
|
||||||
var query = AppDomain.CurrentDomain.GetAssemblies()
|
var query = AppDomain.CurrentDomain.GetAssemblies()
|
||||||
.SelectMany(GetTypesSafe)
|
.SelectMany(ReflectionHelpers.GetTypesSafe)
|
||||||
.Where(t => t.IsClass && !t.IsAbstract && !t.ContainsGenericParameters);
|
.Where(t => t.IsClass && !t.IsAbstract && !t.ContainsGenericParameters);
|
||||||
|
|
||||||
var flags = BindingFlags.Public | BindingFlags.Static;
|
var flags = BindingFlags.Public | BindingFlags.Static;
|
||||||
@ -430,7 +428,7 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
var t = ReflectionHelpers.GetActualType(obj);
|
var t = ReflectionHelpers.GetActualType(obj);
|
||||||
|
|
||||||
if (!FilterName(t.FullName) || ReflectionHelpers.IsArray(t) || ReflectionHelpers.IsList(t))
|
if (!FilterName(t.FullName) || ReflectionHelpers.IsEnumerable(t) || ReflectionHelpers.IsCppList(t))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -439,12 +437,5 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<Type> GetTypesSafe(Assembly asm)
|
|
||||||
{
|
|
||||||
try { return asm.GetTypes(); }
|
|
||||||
catch (ReflectionTypeLoadException e) { return e.Types.Where(x => x != null); }
|
|
||||||
catch { return Enumerable.Empty<Type>(); }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,12 +48,6 @@ namespace Explorer
|
|||||||
|
|
||||||
public bool GetObjectAsGameObject()
|
public bool GetObjectAsGameObject()
|
||||||
{
|
{
|
||||||
if (Target == null)
|
|
||||||
{
|
|
||||||
MelonLogger.Log("Target is null!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var targetType = Target.GetType();
|
var targetType = Target.GetType();
|
||||||
|
|
||||||
if (targetType == typeof(GameObject))
|
if (targetType == typeof(GameObject))
|
||||||
@ -108,6 +102,22 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (Target == null)
|
||||||
|
{
|
||||||
|
MelonLogger.Log("Target is null!");
|
||||||
|
DestroyWindow();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (Target is UnityEngine.Object uObj)
|
||||||
|
{
|
||||||
|
if (!uObj)
|
||||||
|
{
|
||||||
|
MelonLogger.Log("Target was destroyed!");
|
||||||
|
DestroyWindow();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_object && !GetObjectAsGameObject())
|
if (!m_object && !GetObjectAsGameObject())
|
||||||
{
|
{
|
||||||
throw new Exception("Object is null!");
|
throw new Exception("Object is null!");
|
||||||
|
@ -22,8 +22,6 @@ namespace Explorer
|
|||||||
private CacheObjectBase[] m_cachedMembersFiltered;
|
private CacheObjectBase[] m_cachedMembersFiltered;
|
||||||
|
|
||||||
public PageHelper Pages = new PageHelper();
|
public PageHelper Pages = new PageHelper();
|
||||||
//private int m_pageOffset;
|
|
||||||
//private int m_limitPerPage = 20;
|
|
||||||
|
|
||||||
private bool m_autoUpdate = false;
|
private bool m_autoUpdate = false;
|
||||||
private string m_search = "";
|
private string m_search = "";
|
||||||
@ -69,6 +67,20 @@ namespace Explorer
|
|||||||
|
|
||||||
public override void Update()
|
public override void Update()
|
||||||
{
|
{
|
||||||
|
if (Target == null)
|
||||||
|
{
|
||||||
|
DestroyWindow();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (Target is UnityEngine.Object uObj)
|
||||||
|
{
|
||||||
|
if (!uObj)
|
||||||
|
{
|
||||||
|
DestroyWindow();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_cachedMembersFiltered = m_allCachedMembers.Where(x => ShouldProcessMember(x)).ToArray();
|
m_cachedMembersFiltered = m_allCachedMembers.Where(x => ShouldProcessMember(x)).ToArray();
|
||||||
|
|
||||||
if (m_autoUpdate)
|
if (m_autoUpdate)
|
||||||
|
Reference in New Issue
Block a user