mirror of
https://github.com/sinai-dev/UnityExplorer.git
synced 2024-12-23 01:59:40 +08:00
parent
e58cf45e07
commit
2f3bb80eeb
@ -16,7 +16,7 @@ namespace Explorer
|
||||
|
||||
public const string ID = "com.sinai.cppexplorer";
|
||||
public const string NAME = "IL2CPP Runtime Explorer";
|
||||
public const string VERSION = "1.3.0";
|
||||
public const string VERSION = "1.3.1";
|
||||
public const string AUTHOR = "Sinai";
|
||||
|
||||
// fields
|
||||
|
@ -112,7 +112,6 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ILBehaviour.cs" />
|
||||
<Compile Include="CppExplorer.cs" />
|
||||
<Compile Include="MainMenu\Pages\ConsolePage.cs" />
|
||||
<Compile Include="MainMenu\Pages\Console\REPL.cs" />
|
||||
|
@ -1,33 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using MelonLoader;
|
||||
using UnhollowerRuntimeLib;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
//public class ILBehaviour : MonoBehaviour
|
||||
//{
|
||||
// public ILBehaviour(IntPtr intPtr) : base(intPtr) { }
|
||||
|
||||
// public static T AddToGameObject<T>(GameObject _go) where T : ILBehaviour
|
||||
// {
|
||||
// Il2CppSystem.Type ilType = UnhollowerRuntimeLib.Il2CppType.Of<T>();
|
||||
|
||||
// if (ilType == null)
|
||||
// {
|
||||
// MelonLogger.Log("Error - could not get MB as ilType");
|
||||
// return null;
|
||||
// }
|
||||
|
||||
// var obj = typeof(T)
|
||||
// .GetConstructor(new Type[] { typeof(IntPtr) })
|
||||
// .Invoke(new object[] { _go.AddComponent(UnhollowerRuntimeLib.Il2CppType.Of<T>()).Pointer });
|
||||
|
||||
// return (T)obj;
|
||||
// }
|
||||
//}
|
||||
}
|
@ -93,9 +93,13 @@ namespace Explorer
|
||||
return;
|
||||
}
|
||||
|
||||
m_objectType = type;
|
||||
GetFields(m_object);
|
||||
GetProperties(m_object);
|
||||
try
|
||||
{
|
||||
m_objectType = type;
|
||||
GetFields(m_object);
|
||||
GetProperties(m_object);
|
||||
}
|
||||
catch { }
|
||||
|
||||
UpdateValues();
|
||||
}
|
||||
@ -276,7 +280,7 @@ namespace Explorer
|
||||
|
||||
public static bool IsList(Type t)
|
||||
{
|
||||
return t.IsGenericType
|
||||
return t.IsGenericType
|
||||
&& t.GetGenericTypeDefinition() is Type typeDef
|
||||
&& (typeDef.IsAssignableFrom(typeof(List<>)) || typeDef.IsAssignableFrom(typeof(Il2CppSystem.Collections.Generic.List<>)));
|
||||
}
|
||||
@ -292,8 +296,20 @@ namespace Explorer
|
||||
|
||||
foreach (var type in types)
|
||||
{
|
||||
foreach (var pi in type.GetProperties(At.flags))
|
||||
PropertyInfo[] propInfos = new PropertyInfo[0];
|
||||
|
||||
try
|
||||
{
|
||||
propInfos = type.GetProperties(At.flags);
|
||||
}
|
||||
catch (TypeLoadException)
|
||||
{
|
||||
MelonLogger.Log($"Couldn't get Properties for Type '{type.Name}', it may not support Il2Cpp Reflection at the moment.");
|
||||
}
|
||||
|
||||
foreach (var pi in propInfos)
|
||||
{
|
||||
// this member causes a crash when inspected, so just skipping it for now.
|
||||
if (pi.Name == "Il2CppType")
|
||||
{
|
||||
continue;
|
||||
@ -335,7 +351,7 @@ namespace Explorer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* *********************
|
||||
* PROPERTYINFO HOLDER
|
||||
@ -346,6 +362,7 @@ namespace Explorer
|
||||
public Type classType;
|
||||
public PropertyInfo propInfo;
|
||||
public object m_value;
|
||||
public bool IsExpanded;
|
||||
|
||||
public PropertyInfoHolder(Type _type, PropertyInfo _propInfo)
|
||||
{
|
||||
@ -355,14 +372,7 @@ namespace Explorer
|
||||
|
||||
public void Draw(ReflectionWindow window)
|
||||
{
|
||||
if (propInfo.CanWrite)
|
||||
{
|
||||
UIStyles.DrawMember(ref m_value, propInfo.PropertyType.Name, propInfo.Name, window.m_rect, window.m_object, SetValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
UIStyles.DrawMember(ref m_value, propInfo.PropertyType.Name, propInfo.Name, window.m_rect, window.m_object);
|
||||
}
|
||||
UIStyles.DrawMember(ref m_value, ref this.IsExpanded, this.propInfo, window.m_rect, window.m_object, SetValue);
|
||||
}
|
||||
|
||||
public void UpdateValue(object obj)
|
||||
@ -389,15 +399,15 @@ namespace Explorer
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//MelonLogger.Log("Exception on PropertyInfoHolder.UpdateValue, Name: " + this.propInfo.Name);
|
||||
//MelonLogger.Log(e.GetType() + ", " + e.Message);
|
||||
MelonLogger.Log("Exception on PropertyInfoHolder.UpdateValue, Name: " + this.propInfo.Name);
|
||||
MelonLogger.Log(e.GetType() + ", " + e.Message);
|
||||
|
||||
//var inner = e.InnerException;
|
||||
//while (inner != null)
|
||||
//{
|
||||
// MelonLogger.Log("inner: " + inner.GetType() + ", " + inner.Message);
|
||||
// inner = inner.InnerException;
|
||||
//}
|
||||
var inner = e.InnerException;
|
||||
while (inner != null)
|
||||
{
|
||||
MelonLogger.Log("inner: " + inner.GetType() + ", " + inner.Message);
|
||||
inner = inner.InnerException;
|
||||
}
|
||||
|
||||
m_value = null;
|
||||
}
|
||||
@ -473,6 +483,7 @@ namespace Explorer
|
||||
public Type classType;
|
||||
public FieldInfo fieldInfo;
|
||||
public object m_value;
|
||||
public bool IsExpanded;
|
||||
|
||||
public FieldInfoHolder(Type _type, FieldInfo _fieldInfo)
|
||||
{
|
||||
@ -487,16 +498,7 @@ namespace Explorer
|
||||
|
||||
public void Draw(ReflectionWindow window)
|
||||
{
|
||||
bool canSet = !(fieldInfo.IsLiteral && !fieldInfo.IsInitOnly);
|
||||
|
||||
if (canSet)
|
||||
{
|
||||
UIStyles.DrawMember(ref m_value, fieldInfo.FieldType.Name, fieldInfo.Name, window.m_rect, window.m_object, SetValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
UIStyles.DrawMember(ref m_value, fieldInfo.FieldType.Name, fieldInfo.Name, window.m_rect, window.m_object);
|
||||
}
|
||||
UIStyles.DrawMember(ref m_value, ref this.IsExpanded, this.fieldInfo, window.m_rect, window.m_object, SetValue);
|
||||
}
|
||||
|
||||
public void SetValue(object obj)
|
||||
|
@ -36,17 +36,17 @@ namespace Explorer
|
||||
return MB.FindAll<T>();
|
||||
}
|
||||
|
||||
[Documentation("runCoroutine(enumerator) - runs an IEnumerator as a Unity coroutine.")]
|
||||
public static object runCoroutine(IEnumerator i)
|
||||
{
|
||||
return MB.RunCoroutine(i);
|
||||
}
|
||||
//[Documentation("runCoroutine(enumerator) - runs an IEnumerator as a Unity coroutine.")]
|
||||
//public static object runCoroutine(IEnumerator i)
|
||||
//{
|
||||
// return MB.RunCoroutine(i);
|
||||
//}
|
||||
|
||||
[Documentation("endCoroutine(co) - ends a Unity coroutine.")]
|
||||
public static void endCoroutine(Coroutine c)
|
||||
{
|
||||
MB.EndCoroutine(c);
|
||||
}
|
||||
//[Documentation("endCoroutine(co) - ends a Unity coroutine.")]
|
||||
//public static void endCoroutine(Coroutine c)
|
||||
//{
|
||||
// MB.EndCoroutine(c);
|
||||
//}
|
||||
|
||||
////[Documentation("type<T>() - obtain type info about a type T. Provides some Reflection helpers.")]
|
||||
////public static TypeHelper type<T>()
|
||||
|
@ -21,14 +21,14 @@ namespace Explorer
|
||||
return FindObjectsOfType<T>();
|
||||
}
|
||||
|
||||
public object RunCoroutine(IEnumerator enumerator)
|
||||
{
|
||||
return MelonCoroutines.Start(enumerator);
|
||||
}
|
||||
//public object RunCoroutine(IEnumerator enumerator)
|
||||
//{
|
||||
// return MelonCoroutines.Start(enumerator);
|
||||
//}
|
||||
|
||||
public void EndCoroutine(Coroutine c)
|
||||
{
|
||||
StopCoroutine(c);
|
||||
}
|
||||
//public void EndCoroutine(Coroutine c)
|
||||
//{
|
||||
// StopCoroutine(c);
|
||||
//}
|
||||
}
|
||||
}
|
@ -20,12 +20,13 @@ namespace Explorer
|
||||
|
||||
// gameobject list
|
||||
private Transform m_currentTransform;
|
||||
private List<GameObject> m_objectList = new List<GameObject>();
|
||||
private List<GameObjectCache> m_objectList = new List<GameObjectCache>();
|
||||
private float m_timeOfLastUpdate = -1f;
|
||||
|
||||
// search bar
|
||||
private bool m_searching = false;
|
||||
private string m_searchInput = "";
|
||||
private List<GameObject> m_searchResults = new List<GameObject>();
|
||||
private List<GameObjectCache> m_searchResults = new List<GameObjectCache>();
|
||||
|
||||
// ------------ Init and Update ------------ //
|
||||
|
||||
@ -40,17 +41,24 @@ namespace Explorer
|
||||
|
||||
m_currentTransform = null;
|
||||
CancelSearch();
|
||||
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if (Time.time - m_timeOfLastUpdate < 1f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_timeOfLastUpdate = Time.time;
|
||||
|
||||
var start = Time.realtimeSinceStartup;
|
||||
|
||||
if (!m_searching)
|
||||
{
|
||||
m_objectList = new List<GameObject>();
|
||||
m_objectList = new List<GameObjectCache>();
|
||||
if (m_currentTransform)
|
||||
{
|
||||
var noChildren = new List<GameObject>();
|
||||
var endAppend = new List<GameObjectCache>();
|
||||
for (int i = 0; i < m_currentTransform.childCount; i++)
|
||||
{
|
||||
var child = m_currentTransform.GetChild(i);
|
||||
@ -58,13 +66,13 @@ namespace Explorer
|
||||
if (child)
|
||||
{
|
||||
if (child.childCount > 0)
|
||||
m_objectList.Add(child.gameObject);
|
||||
m_objectList.Add(new GameObjectCache(child.gameObject));
|
||||
else
|
||||
noChildren.Add(child.gameObject);
|
||||
endAppend.Add(new GameObjectCache(child.gameObject));
|
||||
}
|
||||
}
|
||||
m_objectList.AddRange(noChildren);
|
||||
noChildren = null;
|
||||
m_objectList.AddRange(endAppend);
|
||||
endAppend = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -74,11 +82,11 @@ namespace Explorer
|
||||
// add objects with children first
|
||||
foreach (var obj in rootObjects.Where(x => x.transform.childCount > 0))
|
||||
{
|
||||
m_objectList.Add(obj);
|
||||
m_objectList.Add(new GameObjectCache(obj));
|
||||
}
|
||||
foreach (var obj in rootObjects.Where(x => x.transform.childCount == 0))
|
||||
{
|
||||
m_objectList.Add(obj);
|
||||
m_objectList.Add(new GameObjectCache(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -161,10 +169,13 @@ namespace Explorer
|
||||
|
||||
if (m_objectList.Count > 0)
|
||||
{
|
||||
var start = Time.realtimeSinceStartup;
|
||||
foreach (var obj in m_objectList)
|
||||
{
|
||||
UIStyles.GameobjButton(obj, SetTransformTarget, true, MainMenu.MainRect.width - 170);
|
||||
//UIStyles.GameobjButton(obj, SetTransformTarget, true, MainMenu.MainRect.width - 170);
|
||||
UIStyles.FastGameobjButton(obj.RefGameObject, obj.EnabledColor, obj.Label, obj.RefGameObject.activeSelf, SetTransformTarget, true, MainMenu.MainRect.width - 170);
|
||||
}
|
||||
var diff = Time.realtimeSinceStartup - start;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -184,7 +195,8 @@ namespace Explorer
|
||||
{
|
||||
foreach (var obj in m_searchResults)
|
||||
{
|
||||
UIStyles.GameobjButton(obj, SetTransformTarget, true, MainMenu.MainRect.width - 170);
|
||||
//UIStyles.GameobjButton(obj, SetTransformTarget, true, MainMenu.MainRect.width - 170);
|
||||
UIStyles.FastGameobjButton(obj.RefGameObject, obj.EnabledColor, obj.Label, obj.RefGameObject.activeSelf, SetTransformTarget, true, MainMenu.MainRect.width - 170);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -232,19 +244,54 @@ namespace Explorer
|
||||
m_searching = false;
|
||||
}
|
||||
|
||||
public List<GameObject> SearchSceneObjects(string _search)
|
||||
public List<GameObjectCache> SearchSceneObjects(string _search)
|
||||
{
|
||||
var matches = new List<GameObject>();
|
||||
var matches = new List<GameObjectCache>();
|
||||
|
||||
foreach (var obj in Resources.FindObjectsOfTypeAll<GameObject>())
|
||||
{
|
||||
if (obj.name.ToLower().Contains(_search.ToLower()) && obj.scene.name == m_currentScene)
|
||||
{
|
||||
matches.Add(obj);
|
||||
matches.Add(new GameObjectCache(obj));
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
public class GameObjectCache
|
||||
{
|
||||
public GameObject RefGameObject;
|
||||
public string Label;
|
||||
public Color EnabledColor;
|
||||
public int ChildCount;
|
||||
|
||||
public GameObjectCache(GameObject obj)
|
||||
{
|
||||
RefGameObject = obj;
|
||||
ChildCount = obj.transform.childCount;
|
||||
|
||||
Label = (ChildCount > 0) ? "[" + obj.transform.childCount + " children] " : "";
|
||||
Label += obj.name;
|
||||
|
||||
bool enabled = obj.activeSelf;
|
||||
int childCount = obj.transform.childCount;
|
||||
if (enabled)
|
||||
{
|
||||
if (childCount > 0)
|
||||
{
|
||||
EnabledColor = Color.green;
|
||||
}
|
||||
else
|
||||
{
|
||||
EnabledColor = UIStyles.LightGreen;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EnabledColor = Color.red;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -91,7 +91,8 @@ namespace Explorer
|
||||
{
|
||||
var obj = m_searchResults[i];
|
||||
|
||||
UIStyles.DrawValue(ref obj, _temprect);
|
||||
bool _ = false;
|
||||
UIStyles.DrawValue(ref obj, _temprect, ref _);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -262,7 +263,6 @@ namespace Explorer
|
||||
{
|
||||
var findType = CppExplorer.GetType(_type);
|
||||
type = Il2CppSystem.Type.GetType(findType.AssemblyQualifiedName);
|
||||
MelonLogger.Log("Got type: " + type.AssemblyQualifiedName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
301
src/UIStyles.cs
301
src/UIStyles.cs
@ -5,7 +5,7 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Il2CppSystem.Collections;
|
||||
using Il2CppSystem.Reflection;
|
||||
//using Il2CppSystem.Reflection;
|
||||
using MelonLoader;
|
||||
using UnhollowerBaseLib;
|
||||
using UnityEngine;
|
||||
@ -15,6 +15,8 @@ namespace Explorer
|
||||
{
|
||||
public class UIStyles
|
||||
{
|
||||
public static Color LightGreen = new Color(Color.green.r - 0.3f, Color.green.g - 0.3f, Color.green.b - 0.3f);
|
||||
|
||||
public static GUISkin WindowSkin
|
||||
{
|
||||
get
|
||||
@ -115,42 +117,48 @@ namespace Explorer
|
||||
// helper for drawing a styled button for a GameObject or Transform
|
||||
public static void GameobjButton(GameObject obj, Action<GameObject> specialInspectMethod = null, bool showSmallInspectBtn = true, float width = 380)
|
||||
{
|
||||
if (obj == null)
|
||||
bool children = obj.transform.childCount > 0;
|
||||
|
||||
string label = children ? "[" + obj.transform.childCount + " children] " : "";
|
||||
label += obj.name;
|
||||
|
||||
bool enabled = obj.activeSelf;
|
||||
int childCount = obj.transform.childCount;
|
||||
Color color;
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
if (childCount > 0)
|
||||
{
|
||||
color = Color.green;
|
||||
}
|
||||
else
|
||||
{
|
||||
color = LightGreen;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
color = Color.red;
|
||||
}
|
||||
|
||||
FastGameobjButton(obj, color, label, obj.activeSelf, specialInspectMethod, showSmallInspectBtn, width);
|
||||
}
|
||||
|
||||
public static void FastGameobjButton(GameObject obj, Color activeColor, string label, bool enabled, Action<GameObject> specialInspectMethod = null, bool showSmallInspectBtn = true, float width = 380)
|
||||
{
|
||||
if (!obj)
|
||||
{
|
||||
GUILayout.Label("<i><color=red>null</color></i>", null);
|
||||
return;
|
||||
}
|
||||
|
||||
bool enabled = obj.activeSelf;
|
||||
bool children = obj.transform.childCount > 0;
|
||||
// ------ toggle active button ------
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUI.skin.button.alignment = TextAnchor.UpperLeft;
|
||||
|
||||
// ------ build name ------
|
||||
|
||||
string label = children ? "[" + obj.transform.childCount + " children] " : "";
|
||||
label += obj.name;
|
||||
|
||||
// ------ Color -------
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
if (children)
|
||||
{
|
||||
GUI.color = Color.green;
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.color = new Color(Color.green.r - 0.3f, Color.green.g - 0.3f, Color.green.b - 0.3f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.color = Color.red;
|
||||
}
|
||||
|
||||
// ------ toggle active button ------
|
||||
GUI.color = activeColor;
|
||||
|
||||
enabled = GUILayout.Toggle(enabled, "", new GUILayoutOption[] { GUILayout.Width(18) });
|
||||
if (obj.activeSelf != enabled)
|
||||
@ -188,84 +196,114 @@ namespace Explorer
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public static void DrawMember(ref object value, string valueType, string memberName, Rect rect, object setTarget = null, Action<object> setAction = null, float labelWidth = 180, bool autoSet = false)
|
||||
public static void DrawMember(ref object value, ref bool isExpanded, MemberInfo memberInfo, Rect rect, object setTarget = null, Action<object> setAction = null, float labelWidth = 180, bool autoSet = false)
|
||||
{
|
||||
GUILayout.Label("<color=cyan>" + memberName + ":</color>", new GUILayoutOption[] { GUILayout.Width(labelWidth) });
|
||||
GUILayout.Label("<color=cyan>" + memberInfo.Name + ":</color>", new GUILayoutOption[] { GUILayout.Width(labelWidth) });
|
||||
|
||||
DrawValue(ref value, rect, valueType, memberName, setTarget, setAction, autoSet);
|
||||
string valueType = "";
|
||||
bool canWrite = true;
|
||||
if (memberInfo is FieldInfo fi)
|
||||
{
|
||||
valueType = fi.FieldType.Name;
|
||||
canWrite = !(fi.IsLiteral && !fi.IsInitOnly);
|
||||
}
|
||||
else if (memberInfo is PropertyInfo pi)
|
||||
{
|
||||
valueType = pi.PropertyType.Name;
|
||||
canWrite = pi.CanWrite;
|
||||
}
|
||||
|
||||
DrawValue(ref value, rect, ref isExpanded, valueType, (canWrite ? setTarget : null), (canWrite ? setAction : null), autoSet);
|
||||
}
|
||||
|
||||
public static void DrawValue(ref object value, Rect rect, string nullValueType = null, string memberName = null, object setTarget = null, Action<object> setAction = null, bool autoSet = false)
|
||||
public static void DrawValue(ref object value, Rect rect, ref bool isExpanded, string nullValueType = null, object setTarget = null, Action<object> setAction = null, bool autoSet = false)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
GUILayout.Label("<i>null (" + nullValueType + ")</i>", null);
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
var valueType = value.GetType();
|
||||
if (valueType.IsPrimitive || value.GetType() == typeof(string))
|
||||
{
|
||||
var valueType = value.GetType();
|
||||
if (valueType.IsPrimitive || value.GetType() == typeof(string))
|
||||
DrawPrimitive(ref value, rect, setTarget, setAction);
|
||||
}
|
||||
else if (valueType == typeof(GameObject) || valueType == typeof(Transform))
|
||||
{
|
||||
GameObject go;
|
||||
if (value.GetType() == typeof(Transform))
|
||||
{
|
||||
DrawPrimitive(ref value, rect, setTarget, setAction);
|
||||
go = (value as Transform).gameObject;
|
||||
}
|
||||
else if (valueType == typeof(GameObject) || valueType == typeof(Transform))
|
||||
else
|
||||
{
|
||||
GameObject go;
|
||||
if (value.GetType() == typeof(Transform))
|
||||
{
|
||||
go = (value as Transform).gameObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
go = (value as GameObject);
|
||||
}
|
||||
|
||||
UIStyles.GameobjButton(go, null, false, rect.width - 250);
|
||||
go = (value as GameObject);
|
||||
}
|
||||
else if (valueType.IsEnum)
|
||||
{
|
||||
if (setAction != null)
|
||||
{
|
||||
if (GUILayout.Button("<", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
SetEnum(ref value, -1);
|
||||
setAction.Invoke(setTarget);
|
||||
}
|
||||
if (GUILayout.Button(">", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
SetEnum(ref value, 1);
|
||||
setAction.Invoke(setTarget);
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.Label(value.ToString(), null);
|
||||
GameobjButton(go, null, false, rect.width - 250);
|
||||
}
|
||||
else if (valueType.IsEnum)
|
||||
{
|
||||
if (setAction != null)
|
||||
{
|
||||
if (GUILayout.Button("<", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
SetEnum(ref value, -1);
|
||||
setAction.Invoke(setTarget);
|
||||
}
|
||||
if (GUILayout.Button(">", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
SetEnum(ref value, 1);
|
||||
setAction.Invoke(setTarget);
|
||||
}
|
||||
}
|
||||
else if (value is System.Collections.IEnumerable || ReflectionWindow.IsList(valueType))
|
||||
|
||||
GUILayout.Label(value.ToString(), null);
|
||||
}
|
||||
else if (value is System.Collections.IEnumerable || ReflectionWindow.IsList(valueType))
|
||||
{
|
||||
System.Collections.IEnumerable enumerable;
|
||||
|
||||
if (value is System.Collections.IEnumerable isEnumerable)
|
||||
{
|
||||
System.Collections.IEnumerable enumerable;
|
||||
enumerable = isEnumerable;
|
||||
}
|
||||
else
|
||||
{
|
||||
var listValueType = value.GetType().GetGenericArguments()[0];
|
||||
var listType = typeof(Il2CppSystem.Collections.Generic.List<>).MakeGenericType(new Type[] { listValueType });
|
||||
var method = listType.GetMethod("ToArray");
|
||||
enumerable = (System.Collections.IEnumerable)method.Invoke(value, new object[0]);
|
||||
}
|
||||
|
||||
if (value is System.Collections.IEnumerable isEnumerable)
|
||||
int count = enumerable.Cast<object>().Count();
|
||||
|
||||
if (!isExpanded)
|
||||
{
|
||||
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
enumerable = isEnumerable;
|
||||
isExpanded = true;
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
var listValueType = value.GetType().GetGenericArguments()[0];
|
||||
var listType = typeof(Il2CppSystem.Collections.Generic.List<>).MakeGenericType(new Type[] { listValueType });
|
||||
var method = listType.GetMethod("ToArray");
|
||||
enumerable = (System.Collections.IEnumerable)method.Invoke(value, new object[0]);
|
||||
isExpanded = false;
|
||||
}
|
||||
}
|
||||
|
||||
int count = enumerable.Cast<object>().Count();
|
||||
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
||||
string btnLabel = "<color=yellow>[" + count + "] " + valueType + "</color>";
|
||||
if (GUILayout.Button(btnLabel, new GUILayoutOption[] { GUILayout.MaxWidth(rect.width - 230) }))
|
||||
{
|
||||
WindowManager.InspectObject(value, out bool _);
|
||||
}
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleCenter;
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
||||
string btnLabel = "<color=yellow>[" + count + "] " + valueType + "</color>";
|
||||
if (GUILayout.Button(btnLabel, new GUILayoutOption[] { GUILayout.MaxWidth(rect.width - 260) }))
|
||||
{
|
||||
WindowManager.InspectObject(value, out bool _);
|
||||
}
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleCenter;
|
||||
|
||||
if (isExpanded)
|
||||
{
|
||||
var enumerator = enumerable.GetEnumerator();
|
||||
if (enumerator != null)
|
||||
{
|
||||
@ -315,49 +353,68 @@ namespace Explorer
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
var label = value.ToString();
|
||||
|
||||
if (valueType == typeof(Object))
|
||||
{
|
||||
var label = value.ToString();
|
||||
|
||||
if (valueType == typeof(Object))
|
||||
{
|
||||
label = (value as Object).name;
|
||||
}
|
||||
else if (value is Vector4 vec4)
|
||||
{
|
||||
label = vec4.ToString();
|
||||
}
|
||||
else if (value is Vector3 vec3)
|
||||
{
|
||||
label = vec3.ToString();
|
||||
}
|
||||
else if (value is Vector2 vec2)
|
||||
{
|
||||
label = vec2.ToString();
|
||||
}
|
||||
else if (value is Rect rec)
|
||||
{
|
||||
label = rec.ToString();
|
||||
}
|
||||
else if (value is Matrix4x4 matrix)
|
||||
{
|
||||
label = matrix.ToString();
|
||||
}
|
||||
else if (value is Color col)
|
||||
{
|
||||
label = col.ToString();
|
||||
}
|
||||
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
||||
if (GUILayout.Button("<color=yellow>" + label + "</color>", new GUILayoutOption[] { GUILayout.MaxWidth(rect.width - 230) }))
|
||||
{
|
||||
WindowManager.InspectObject(value, out bool _);
|
||||
}
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleCenter;
|
||||
label = (value as Object).name;
|
||||
}
|
||||
else if (value is Vector4 vec4)
|
||||
{
|
||||
label = vec4.ToString();
|
||||
}
|
||||
else if (value is Vector3 vec3)
|
||||
{
|
||||
label = vec3.ToString();
|
||||
}
|
||||
else if (value is Vector2 vec2)
|
||||
{
|
||||
label = vec2.ToString();
|
||||
}
|
||||
else if (value is Rect rec)
|
||||
{
|
||||
label = rec.ToString();
|
||||
}
|
||||
else if (value is Matrix4x4 matrix)
|
||||
{
|
||||
label = matrix.ToString();
|
||||
}
|
||||
else if (value is Color col)
|
||||
{
|
||||
label = col.ToString();
|
||||
}
|
||||
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
||||
if (GUILayout.Button("<color=yellow>" + label + "</color>", new GUILayoutOption[] { GUILayout.MaxWidth(rect.width - 230) }))
|
||||
{
|
||||
WindowManager.InspectObject(value, out bool _);
|
||||
}
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleCenter;
|
||||
}
|
||||
}
|
||||
|
||||
//public static void DrawMember(ref object value, string valueType, string memberName, Rect rect, object setTarget = null, Action<object> setAction = null, float labelWidth = 180, bool autoSet = false)
|
||||
//{
|
||||
// GUILayout.Label("<color=cyan>" + memberName + ":</color>", new GUILayoutOption[] { GUILayout.Width(labelWidth) });
|
||||
|
||||
// DrawValue(ref value, rect, valueType, memberName, setTarget, setAction, autoSet);
|
||||
//}
|
||||
|
||||
//public static void DrawValue(ref object value, Rect rect, string nullValueType = null, string memberName = null, object setTarget = null, Action<object> setAction = null, bool autoSet = false)
|
||||
//{
|
||||
// if (value == null)
|
||||
// {
|
||||
// GUILayout.Label("<i>null (" + nullValueType + ")</i>", null);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
|
||||
// }
|
||||
//}
|
||||
|
||||
// Helper for drawing primitive values (with Apply button)
|
||||
|
||||
public static void DrawPrimitive(ref object value, Rect m_rect, object setTarget = null, Action<object> setAction = null, bool autoSet = false)
|
||||
@ -387,10 +444,10 @@ namespace Explorer
|
||||
}
|
||||
else
|
||||
{
|
||||
value = GUILayout.TextField(value.ToString(), new GUILayoutOption[] { GUILayout.MaxWidth(m_rect.width - 260) });
|
||||
value = GUILayout.TextField(value.ToString(), new GUILayoutOption[] { GUILayout.MaxWidth(m_rect.width - 260) });
|
||||
}
|
||||
|
||||
if (autoSet || (allowSet && GUILayout.Button("<color=#00FF00>Apply</color>", new GUILayoutOption[] { GUILayout.Width(60) })))
|
||||
if (autoSet || (allowSet && GUILayout.Button("<color=#00FF00>Apply</color>", new GUILayoutOption[] { GUILayout.Width(60) })))
|
||||
{
|
||||
setAction.Invoke(setTarget);
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ namespace Explorer
|
||||
|
||||
public const string ID = "com.sinai.cppexplorer";
|
||||
public const string NAME = "IL2CPP Runtime Explorer";
|
||||
public const string VERSION = "1.3.0";
|
||||
public const string VERSION = "1.3.1";
|
||||
public const string AUTHOR = "Sinai";
|
||||
|
||||
// fields
|
||||
|
@ -104,7 +104,6 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ILBehaviour.cs" />
|
||||
<Compile Include="CppExplorer.cs" />
|
||||
<Compile Include="MainMenu\Pages\ConsolePage.cs" />
|
||||
<Compile Include="MainMenu\Pages\Console\REPL.cs" />
|
||||
|
@ -1,33 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using MelonLoader;
|
||||
using UnhollowerRuntimeLib;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
//public class ILBehaviour : MonoBehaviour
|
||||
//{
|
||||
// public ILBehaviour(IntPtr intPtr) : base(intPtr) { }
|
||||
|
||||
// public static T AddToGameObject<T>(GameObject _go) where T : ILBehaviour
|
||||
// {
|
||||
// Il2CppSystem.Type ilType = UnhollowerRuntimeLib.Il2CppType.Of<T>();
|
||||
|
||||
// if (ilType == null)
|
||||
// {
|
||||
// MelonLogger.Log("Error - could not get MB as ilType");
|
||||
// return null;
|
||||
// }
|
||||
|
||||
// var obj = typeof(T)
|
||||
// .GetConstructor(new Type[] { typeof(IntPtr) })
|
||||
// .Invoke(new object[] { _go.AddComponent(UnhollowerRuntimeLib.Il2CppType.Of<T>()).Pointer });
|
||||
|
||||
// return (T)obj;
|
||||
// }
|
||||
//}
|
||||
}
|
@ -93,9 +93,13 @@ namespace Explorer
|
||||
return;
|
||||
}
|
||||
|
||||
m_objectType = type;
|
||||
GetFields(m_object);
|
||||
GetProperties(m_object);
|
||||
try
|
||||
{
|
||||
m_objectType = type;
|
||||
GetFields(m_object);
|
||||
GetProperties(m_object);
|
||||
}
|
||||
catch { }
|
||||
|
||||
UpdateValues();
|
||||
}
|
||||
@ -276,7 +280,7 @@ namespace Explorer
|
||||
|
||||
public static bool IsList(Type t)
|
||||
{
|
||||
return t.IsGenericType
|
||||
return t.IsGenericType
|
||||
&& t.GetGenericTypeDefinition() is Type typeDef
|
||||
&& (typeDef.IsAssignableFrom(typeof(List<>)) || typeDef.IsAssignableFrom(typeof(Il2CppSystem.Collections.Generic.List<>)));
|
||||
}
|
||||
@ -292,8 +296,20 @@ namespace Explorer
|
||||
|
||||
foreach (var type in types)
|
||||
{
|
||||
foreach (var pi in type.GetProperties(At.flags))
|
||||
PropertyInfo[] propInfos = new PropertyInfo[0];
|
||||
|
||||
try
|
||||
{
|
||||
propInfos = type.GetProperties(At.flags);
|
||||
}
|
||||
catch (TypeLoadException)
|
||||
{
|
||||
MelonLogger.Log($"Couldn't get Properties for Type '{type.Name}', it may not support Il2Cpp Reflection at the moment.");
|
||||
}
|
||||
|
||||
foreach (var pi in propInfos)
|
||||
{
|
||||
// this member causes a crash when inspected, so just skipping it for now.
|
||||
if (pi.Name == "Il2CppType")
|
||||
{
|
||||
continue;
|
||||
@ -335,7 +351,7 @@ namespace Explorer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* *********************
|
||||
* PROPERTYINFO HOLDER
|
||||
@ -346,6 +362,7 @@ namespace Explorer
|
||||
public Type classType;
|
||||
public PropertyInfo propInfo;
|
||||
public object m_value;
|
||||
public bool IsExpanded;
|
||||
|
||||
public PropertyInfoHolder(Type _type, PropertyInfo _propInfo)
|
||||
{
|
||||
@ -355,14 +372,7 @@ namespace Explorer
|
||||
|
||||
public void Draw(ReflectionWindow window)
|
||||
{
|
||||
if (propInfo.CanWrite)
|
||||
{
|
||||
UIStyles.DrawMember(ref m_value, propInfo.PropertyType.Name, propInfo.Name, window.m_rect, window.m_object, SetValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
UIStyles.DrawMember(ref m_value, propInfo.PropertyType.Name, propInfo.Name, window.m_rect, window.m_object);
|
||||
}
|
||||
UIStyles.DrawMember(ref m_value, ref this.IsExpanded, this.propInfo, window.m_rect, window.m_object, SetValue);
|
||||
}
|
||||
|
||||
public void UpdateValue(object obj)
|
||||
@ -389,15 +399,15 @@ namespace Explorer
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//MelonLogger.Log("Exception on PropertyInfoHolder.UpdateValue, Name: " + this.propInfo.Name);
|
||||
//MelonLogger.Log(e.GetType() + ", " + e.Message);
|
||||
MelonLogger.Log("Exception on PropertyInfoHolder.UpdateValue, Name: " + this.propInfo.Name);
|
||||
MelonLogger.Log(e.GetType() + ", " + e.Message);
|
||||
|
||||
//var inner = e.InnerException;
|
||||
//while (inner != null)
|
||||
//{
|
||||
// MelonLogger.Log("inner: " + inner.GetType() + ", " + inner.Message);
|
||||
// inner = inner.InnerException;
|
||||
//}
|
||||
var inner = e.InnerException;
|
||||
while (inner != null)
|
||||
{
|
||||
MelonLogger.Log("inner: " + inner.GetType() + ", " + inner.Message);
|
||||
inner = inner.InnerException;
|
||||
}
|
||||
|
||||
m_value = null;
|
||||
}
|
||||
@ -473,6 +483,7 @@ namespace Explorer
|
||||
public Type classType;
|
||||
public FieldInfo fieldInfo;
|
||||
public object m_value;
|
||||
public bool IsExpanded;
|
||||
|
||||
public FieldInfoHolder(Type _type, FieldInfo _fieldInfo)
|
||||
{
|
||||
@ -487,16 +498,7 @@ namespace Explorer
|
||||
|
||||
public void Draw(ReflectionWindow window)
|
||||
{
|
||||
bool canSet = !(fieldInfo.IsLiteral && !fieldInfo.IsInitOnly);
|
||||
|
||||
if (canSet)
|
||||
{
|
||||
UIStyles.DrawMember(ref m_value, fieldInfo.FieldType.Name, fieldInfo.Name, window.m_rect, window.m_object, SetValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
UIStyles.DrawMember(ref m_value, fieldInfo.FieldType.Name, fieldInfo.Name, window.m_rect, window.m_object);
|
||||
}
|
||||
UIStyles.DrawMember(ref m_value, ref this.IsExpanded, this.fieldInfo, window.m_rect, window.m_object, SetValue);
|
||||
}
|
||||
|
||||
public void SetValue(object obj)
|
||||
|
@ -36,17 +36,17 @@ namespace Explorer
|
||||
return MB.FindAll<T>();
|
||||
}
|
||||
|
||||
[Documentation("runCoroutine(enumerator) - runs an IEnumerator as a Unity coroutine.")]
|
||||
public static object runCoroutine(IEnumerator i)
|
||||
{
|
||||
return MB.RunCoroutine(i);
|
||||
}
|
||||
//[Documentation("runCoroutine(enumerator) - runs an IEnumerator as a Unity coroutine.")]
|
||||
//public static object runCoroutine(IEnumerator i)
|
||||
//{
|
||||
// return MB.RunCoroutine(i);
|
||||
//}
|
||||
|
||||
[Documentation("endCoroutine(co) - ends a Unity coroutine.")]
|
||||
public static void endCoroutine(Coroutine c)
|
||||
{
|
||||
MB.EndCoroutine(c);
|
||||
}
|
||||
//[Documentation("endCoroutine(co) - ends a Unity coroutine.")]
|
||||
//public static void endCoroutine(Coroutine c)
|
||||
//{
|
||||
// MB.EndCoroutine(c);
|
||||
//}
|
||||
|
||||
////[Documentation("type<T>() - obtain type info about a type T. Provides some Reflection helpers.")]
|
||||
////public static TypeHelper type<T>()
|
||||
|
@ -21,14 +21,14 @@ namespace Explorer
|
||||
return FindObjectsOfType<T>();
|
||||
}
|
||||
|
||||
public object RunCoroutine(IEnumerator enumerator)
|
||||
{
|
||||
return MelonCoroutines.Start(enumerator);
|
||||
}
|
||||
//public object RunCoroutine(IEnumerator enumerator)
|
||||
//{
|
||||
// return MelonCoroutines.Start(enumerator);
|
||||
//}
|
||||
|
||||
public void EndCoroutine(Coroutine c)
|
||||
{
|
||||
StopCoroutine(c);
|
||||
}
|
||||
//public void EndCoroutine(Coroutine c)
|
||||
//{
|
||||
// StopCoroutine(c);
|
||||
//}
|
||||
}
|
||||
}
|
@ -20,12 +20,13 @@ namespace Explorer
|
||||
|
||||
// gameobject list
|
||||
private Transform m_currentTransform;
|
||||
private List<GameObject> m_objectList = new List<GameObject>();
|
||||
private List<GameObjectCache> m_objectList = new List<GameObjectCache>();
|
||||
private float m_timeOfLastUpdate = -1f;
|
||||
|
||||
// search bar
|
||||
private bool m_searching = false;
|
||||
private string m_searchInput = "";
|
||||
private List<GameObject> m_searchResults = new List<GameObject>();
|
||||
private List<GameObjectCache> m_searchResults = new List<GameObjectCache>();
|
||||
|
||||
// ------------ Init and Update ------------ //
|
||||
|
||||
@ -40,17 +41,24 @@ namespace Explorer
|
||||
|
||||
m_currentTransform = null;
|
||||
CancelSearch();
|
||||
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if (Time.time - m_timeOfLastUpdate < 1f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_timeOfLastUpdate = Time.time;
|
||||
|
||||
var start = Time.realtimeSinceStartup;
|
||||
|
||||
if (!m_searching)
|
||||
{
|
||||
m_objectList = new List<GameObject>();
|
||||
m_objectList = new List<GameObjectCache>();
|
||||
if (m_currentTransform)
|
||||
{
|
||||
var noChildren = new List<GameObject>();
|
||||
var endAppend = new List<GameObjectCache>();
|
||||
for (int i = 0; i < m_currentTransform.childCount; i++)
|
||||
{
|
||||
var child = m_currentTransform.GetChild(i);
|
||||
@ -58,13 +66,13 @@ namespace Explorer
|
||||
if (child)
|
||||
{
|
||||
if (child.childCount > 0)
|
||||
m_objectList.Add(child.gameObject);
|
||||
m_objectList.Add(new GameObjectCache(child.gameObject));
|
||||
else
|
||||
noChildren.Add(child.gameObject);
|
||||
endAppend.Add(new GameObjectCache(child.gameObject));
|
||||
}
|
||||
}
|
||||
m_objectList.AddRange(noChildren);
|
||||
noChildren = null;
|
||||
m_objectList.AddRange(endAppend);
|
||||
endAppend = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -74,11 +82,11 @@ namespace Explorer
|
||||
// add objects with children first
|
||||
foreach (var obj in rootObjects.Where(x => x.transform.childCount > 0))
|
||||
{
|
||||
m_objectList.Add(obj);
|
||||
m_objectList.Add(new GameObjectCache(obj));
|
||||
}
|
||||
foreach (var obj in rootObjects.Where(x => x.transform.childCount == 0))
|
||||
{
|
||||
m_objectList.Add(obj);
|
||||
m_objectList.Add(new GameObjectCache(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -120,7 +128,8 @@ namespace Explorer
|
||||
m_currentScene = scenes[index].name;
|
||||
}
|
||||
}
|
||||
GUILayout.Label("<color=cyan>" + m_currentScene + "</color>", null);
|
||||
GUILayout.Label("<color=cyan>" + m_currentScene + "</color>", null); //new GUILayoutOption[] { GUILayout.Width(250) });
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
// ----- GameObject Search -----
|
||||
@ -160,10 +169,13 @@ namespace Explorer
|
||||
|
||||
if (m_objectList.Count > 0)
|
||||
{
|
||||
var start = Time.realtimeSinceStartup;
|
||||
foreach (var obj in m_objectList)
|
||||
{
|
||||
UIStyles.GameobjButton(obj, SetTransformTarget, true, MainMenu.MainRect.width - 170);
|
||||
//UIStyles.GameobjButton(obj, SetTransformTarget, true, MainMenu.MainRect.width - 170);
|
||||
UIStyles.FastGameobjButton(obj.RefGameObject, obj.EnabledColor, obj.Label, obj.RefGameObject.activeSelf, SetTransformTarget, true, MainMenu.MainRect.width - 170);
|
||||
}
|
||||
var diff = Time.realtimeSinceStartup - start;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -183,7 +195,8 @@ namespace Explorer
|
||||
{
|
||||
foreach (var obj in m_searchResults)
|
||||
{
|
||||
UIStyles.GameobjButton(obj, SetTransformTarget, true, MainMenu.MainRect.width - 170);
|
||||
//UIStyles.GameobjButton(obj, SetTransformTarget, true, MainMenu.MainRect.width - 170);
|
||||
UIStyles.FastGameobjButton(obj.RefGameObject, obj.EnabledColor, obj.Label, obj.RefGameObject.activeSelf, SetTransformTarget, true, MainMenu.MainRect.width - 170);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -231,19 +244,54 @@ namespace Explorer
|
||||
m_searching = false;
|
||||
}
|
||||
|
||||
public List<GameObject> SearchSceneObjects(string _search)
|
||||
public List<GameObjectCache> SearchSceneObjects(string _search)
|
||||
{
|
||||
var matches = new List<GameObject>();
|
||||
var matches = new List<GameObjectCache>();
|
||||
|
||||
foreach (var obj in Resources.FindObjectsOfTypeAll<GameObject>())
|
||||
{
|
||||
if (obj.name.ToLower().Contains(_search.ToLower()) && obj.scene.name == m_currentScene)
|
||||
{
|
||||
matches.Add(obj);
|
||||
matches.Add(new GameObjectCache(obj));
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
public class GameObjectCache
|
||||
{
|
||||
public GameObject RefGameObject;
|
||||
public string Label;
|
||||
public Color EnabledColor;
|
||||
public int ChildCount;
|
||||
|
||||
public GameObjectCache(GameObject obj)
|
||||
{
|
||||
RefGameObject = obj;
|
||||
ChildCount = obj.transform.childCount;
|
||||
|
||||
Label = (ChildCount > 0) ? "[" + obj.transform.childCount + " children] " : "";
|
||||
Label += obj.name;
|
||||
|
||||
bool enabled = obj.activeSelf;
|
||||
int childCount = obj.transform.childCount;
|
||||
if (enabled)
|
||||
{
|
||||
if (childCount > 0)
|
||||
{
|
||||
EnabledColor = Color.green;
|
||||
}
|
||||
else
|
||||
{
|
||||
EnabledColor = UIStyles.LightGreen;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EnabledColor = Color.red;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ namespace Explorer
|
||||
private List<object> m_searchResults = new List<object>();
|
||||
private Vector2 resultsScroll = Vector2.zero;
|
||||
|
||||
public override void Init()
|
||||
public override void Init()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
@ -54,7 +54,7 @@ namespace Explorer
|
||||
m_searchResults.Clear();
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
public override void Update()
|
||||
{
|
||||
}
|
||||
|
||||
@ -91,7 +91,8 @@ namespace Explorer
|
||||
{
|
||||
var obj = m_searchResults[i];
|
||||
|
||||
UIStyles.DrawValue(ref obj, _temprect);
|
||||
bool _ = false;
|
||||
UIStyles.DrawValue(ref obj, _temprect, ref _);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -147,14 +148,14 @@ namespace Explorer
|
||||
{
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleRight;
|
||||
GUILayout.Label("Custom Class:", new GUILayoutOption[] { GUILayout.Width(250) });
|
||||
GUILayout.Label("Custom Class:", new GUILayoutOption[] { GUILayout.Width(250) });
|
||||
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||
m_typeInput = GUILayout.TextField(m_typeInput, new GUILayoutOption[] { GUILayout.Width(250) });
|
||||
m_typeInput = GUILayout.TextField(m_typeInput, new GUILayoutOption[] { GUILayout.Width(250) });
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Label("Scene Filter:", new GUILayoutOption[] { GUILayout.Width(100) });
|
||||
GUILayout.Label("Scene Filter:", new GUILayoutOption[] { GUILayout.Width(100) });
|
||||
SceneFilterToggle(SceneFilter.Any, "Any", 60);
|
||||
SceneFilterToggle(SceneFilter.This, "This Scene", 100);
|
||||
SceneFilterToggle(SceneFilter.DontDestroy, "DontDestroyOnLoad", 140);
|
||||
@ -262,7 +263,6 @@ namespace Explorer
|
||||
{
|
||||
var findType = CppExplorer.GetType(_type);
|
||||
type = Il2CppSystem.Type.GetType(findType.AssemblyQualifiedName);
|
||||
MelonLogger.Log("Got type: " + type.AssemblyQualifiedName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -372,7 +372,7 @@ namespace Explorer
|
||||
if (type == typeof(GameObject) || typeof(Component).IsAssignableFrom(type))
|
||||
{
|
||||
var go = obj as GameObject ?? (obj as Component).gameObject;
|
||||
|
||||
|
||||
if (go != null && go.scene.name == CppExplorer.ActiveSceneName && go.scene.name != "DontDestroyOnLoad")
|
||||
{
|
||||
return true;
|
||||
|
@ -5,7 +5,7 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Il2CppSystem.Collections;
|
||||
using Il2CppSystem.Reflection;
|
||||
//using Il2CppSystem.Reflection;
|
||||
using MelonLoader;
|
||||
using UnhollowerBaseLib;
|
||||
using UnityEngine;
|
||||
@ -15,6 +15,8 @@ namespace Explorer
|
||||
{
|
||||
public class UIStyles
|
||||
{
|
||||
public static Color LightGreen = new Color(Color.green.r - 0.3f, Color.green.g - 0.3f, Color.green.b - 0.3f);
|
||||
|
||||
public static GUISkin WindowSkin
|
||||
{
|
||||
get
|
||||
@ -115,42 +117,48 @@ namespace Explorer
|
||||
// helper for drawing a styled button for a GameObject or Transform
|
||||
public static void GameobjButton(GameObject obj, Action<GameObject> specialInspectMethod = null, bool showSmallInspectBtn = true, float width = 380)
|
||||
{
|
||||
if (obj == null)
|
||||
bool children = obj.transform.childCount > 0;
|
||||
|
||||
string label = children ? "[" + obj.transform.childCount + " children] " : "";
|
||||
label += obj.name;
|
||||
|
||||
bool enabled = obj.activeSelf;
|
||||
int childCount = obj.transform.childCount;
|
||||
Color color;
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
if (childCount > 0)
|
||||
{
|
||||
color = Color.green;
|
||||
}
|
||||
else
|
||||
{
|
||||
color = LightGreen;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
color = Color.red;
|
||||
}
|
||||
|
||||
FastGameobjButton(obj, color, label, obj.activeSelf, specialInspectMethod, showSmallInspectBtn, width);
|
||||
}
|
||||
|
||||
public static void FastGameobjButton(GameObject obj, Color activeColor, string label, bool enabled, Action<GameObject> specialInspectMethod = null, bool showSmallInspectBtn = true, float width = 380)
|
||||
{
|
||||
if (!obj)
|
||||
{
|
||||
GUILayout.Label("<i><color=red>null</color></i>", null);
|
||||
return;
|
||||
}
|
||||
|
||||
bool enabled = obj.activeSelf;
|
||||
bool children = obj.transform.childCount > 0;
|
||||
// ------ toggle active button ------
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUI.skin.button.alignment = TextAnchor.UpperLeft;
|
||||
|
||||
// ------ build name ------
|
||||
|
||||
string label = children ? "[" + obj.transform.childCount + " children] " : "";
|
||||
label += obj.name;
|
||||
|
||||
// ------ Color -------
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
if (children)
|
||||
{
|
||||
GUI.color = Color.green;
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.color = new Color(Color.green.r - 0.3f, Color.green.g - 0.3f, Color.green.b - 0.3f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.color = Color.red;
|
||||
}
|
||||
|
||||
// ------ toggle active button ------
|
||||
GUI.color = activeColor;
|
||||
|
||||
enabled = GUILayout.Toggle(enabled, "", new GUILayoutOption[] { GUILayout.Width(18) });
|
||||
if (obj.activeSelf != enabled)
|
||||
@ -188,84 +196,114 @@ namespace Explorer
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public static void DrawMember(ref object value, string valueType, string memberName, Rect rect, object setTarget = null, Action<object> setAction = null, float labelWidth = 180, bool autoSet = false)
|
||||
public static void DrawMember(ref object value, ref bool isExpanded, MemberInfo memberInfo, Rect rect, object setTarget = null, Action<object> setAction = null, float labelWidth = 180, bool autoSet = false)
|
||||
{
|
||||
GUILayout.Label("<color=cyan>" + memberName + ":</color>", new GUILayoutOption[] { GUILayout.Width(labelWidth) });
|
||||
GUILayout.Label("<color=cyan>" + memberInfo.Name + ":</color>", new GUILayoutOption[] { GUILayout.Width(labelWidth) });
|
||||
|
||||
DrawValue(ref value, rect, valueType, memberName, setTarget, setAction, autoSet);
|
||||
string valueType = "";
|
||||
bool canWrite = true;
|
||||
if (memberInfo is FieldInfo fi)
|
||||
{
|
||||
valueType = fi.FieldType.Name;
|
||||
canWrite = !(fi.IsLiteral && !fi.IsInitOnly);
|
||||
}
|
||||
else if (memberInfo is PropertyInfo pi)
|
||||
{
|
||||
valueType = pi.PropertyType.Name;
|
||||
canWrite = pi.CanWrite;
|
||||
}
|
||||
|
||||
DrawValue(ref value, rect, ref isExpanded, valueType, (canWrite ? setTarget : null), (canWrite ? setAction : null), autoSet);
|
||||
}
|
||||
|
||||
public static void DrawValue(ref object value, Rect rect, string nullValueType = null, string memberName = null, object setTarget = null, Action<object> setAction = null, bool autoSet = false)
|
||||
public static void DrawValue(ref object value, Rect rect, ref bool isExpanded, string nullValueType = null, object setTarget = null, Action<object> setAction = null, bool autoSet = false)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
GUILayout.Label("<i>null (" + nullValueType + ")</i>", null);
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
var valueType = value.GetType();
|
||||
if (valueType.IsPrimitive || value.GetType() == typeof(string))
|
||||
{
|
||||
var valueType = value.GetType();
|
||||
if (valueType.IsPrimitive || value.GetType() == typeof(string))
|
||||
DrawPrimitive(ref value, rect, setTarget, setAction);
|
||||
}
|
||||
else if (valueType == typeof(GameObject) || valueType == typeof(Transform))
|
||||
{
|
||||
GameObject go;
|
||||
if (value.GetType() == typeof(Transform))
|
||||
{
|
||||
DrawPrimitive(ref value, rect, setTarget, setAction);
|
||||
go = (value as Transform).gameObject;
|
||||
}
|
||||
else if (valueType == typeof(GameObject) || valueType == typeof(Transform))
|
||||
else
|
||||
{
|
||||
GameObject go;
|
||||
if (value.GetType() == typeof(Transform))
|
||||
{
|
||||
go = (value as Transform).gameObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
go = (value as GameObject);
|
||||
}
|
||||
|
||||
UIStyles.GameobjButton(go, null, false, rect.width - 250);
|
||||
go = (value as GameObject);
|
||||
}
|
||||
else if (valueType.IsEnum)
|
||||
{
|
||||
if (setAction != null)
|
||||
{
|
||||
if (GUILayout.Button("<", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
SetEnum(ref value, -1);
|
||||
setAction.Invoke(setTarget);
|
||||
}
|
||||
if (GUILayout.Button(">", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
SetEnum(ref value, 1);
|
||||
setAction.Invoke(setTarget);
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.Label(value.ToString(), null);
|
||||
GameobjButton(go, null, false, rect.width - 250);
|
||||
}
|
||||
else if (valueType.IsEnum)
|
||||
{
|
||||
if (setAction != null)
|
||||
{
|
||||
if (GUILayout.Button("<", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
SetEnum(ref value, -1);
|
||||
setAction.Invoke(setTarget);
|
||||
}
|
||||
if (GUILayout.Button(">", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
SetEnum(ref value, 1);
|
||||
setAction.Invoke(setTarget);
|
||||
}
|
||||
}
|
||||
else if (value is System.Collections.IEnumerable || ReflectionWindow.IsList(valueType))
|
||||
|
||||
GUILayout.Label(value.ToString(), null);
|
||||
}
|
||||
else if (value is System.Collections.IEnumerable || ReflectionWindow.IsList(valueType))
|
||||
{
|
||||
System.Collections.IEnumerable enumerable;
|
||||
|
||||
if (value is System.Collections.IEnumerable isEnumerable)
|
||||
{
|
||||
System.Collections.IEnumerable enumerable;
|
||||
enumerable = isEnumerable;
|
||||
}
|
||||
else
|
||||
{
|
||||
var listValueType = value.GetType().GetGenericArguments()[0];
|
||||
var listType = typeof(Il2CppSystem.Collections.Generic.List<>).MakeGenericType(new Type[] { listValueType });
|
||||
var method = listType.GetMethod("ToArray");
|
||||
enumerable = (System.Collections.IEnumerable)method.Invoke(value, new object[0]);
|
||||
}
|
||||
|
||||
if (value is System.Collections.IEnumerable isEnumerable)
|
||||
int count = enumerable.Cast<object>().Count();
|
||||
|
||||
if (!isExpanded)
|
||||
{
|
||||
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
enumerable = isEnumerable;
|
||||
isExpanded = true;
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
var listValueType = value.GetType().GetGenericArguments()[0];
|
||||
var listType = typeof(Il2CppSystem.Collections.Generic.List<>).MakeGenericType(new Type[] { listValueType });
|
||||
var method = listType.GetMethod("ToArray");
|
||||
enumerable = (System.Collections.IEnumerable)method.Invoke(value, new object[0]);
|
||||
isExpanded = false;
|
||||
}
|
||||
}
|
||||
|
||||
int count = enumerable.Cast<object>().Count();
|
||||
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
||||
string btnLabel = "<color=yellow>[" + count + "] " + valueType + "</color>";
|
||||
if (GUILayout.Button(btnLabel, new GUILayoutOption[] { GUILayout.MaxWidth(rect.width - 230) }))
|
||||
{
|
||||
WindowManager.InspectObject(value, out bool _);
|
||||
}
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleCenter;
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
||||
string btnLabel = "<color=yellow>[" + count + "] " + valueType + "</color>";
|
||||
if (GUILayout.Button(btnLabel, new GUILayoutOption[] { GUILayout.MaxWidth(rect.width - 260) }))
|
||||
{
|
||||
WindowManager.InspectObject(value, out bool _);
|
||||
}
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleCenter;
|
||||
|
||||
if (isExpanded)
|
||||
{
|
||||
var enumerator = enumerable.GetEnumerator();
|
||||
if (enumerator != null)
|
||||
{
|
||||
@ -315,49 +353,68 @@ namespace Explorer
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
var label = value.ToString();
|
||||
|
||||
if (valueType == typeof(Object))
|
||||
{
|
||||
var label = value.ToString();
|
||||
|
||||
if (valueType == typeof(Object))
|
||||
{
|
||||
label = (value as Object).name;
|
||||
}
|
||||
else if (value is Vector4 vec4)
|
||||
{
|
||||
label = vec4.ToString();
|
||||
}
|
||||
else if (value is Vector3 vec3)
|
||||
{
|
||||
label = vec3.ToString();
|
||||
}
|
||||
else if (value is Vector2 vec2)
|
||||
{
|
||||
label = vec2.ToString();
|
||||
}
|
||||
else if (value is Rect rec)
|
||||
{
|
||||
label = rec.ToString();
|
||||
}
|
||||
else if (value is Matrix4x4 matrix)
|
||||
{
|
||||
label = matrix.ToString();
|
||||
}
|
||||
else if (value is Color col)
|
||||
{
|
||||
label = col.ToString();
|
||||
}
|
||||
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
||||
if (GUILayout.Button("<color=yellow>" + label + "</color>", new GUILayoutOption[] { GUILayout.MaxWidth(rect.width - 230) }))
|
||||
{
|
||||
WindowManager.InspectObject(value, out bool _);
|
||||
}
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleCenter;
|
||||
label = (value as Object).name;
|
||||
}
|
||||
else if (value is Vector4 vec4)
|
||||
{
|
||||
label = vec4.ToString();
|
||||
}
|
||||
else if (value is Vector3 vec3)
|
||||
{
|
||||
label = vec3.ToString();
|
||||
}
|
||||
else if (value is Vector2 vec2)
|
||||
{
|
||||
label = vec2.ToString();
|
||||
}
|
||||
else if (value is Rect rec)
|
||||
{
|
||||
label = rec.ToString();
|
||||
}
|
||||
else if (value is Matrix4x4 matrix)
|
||||
{
|
||||
label = matrix.ToString();
|
||||
}
|
||||
else if (value is Color col)
|
||||
{
|
||||
label = col.ToString();
|
||||
}
|
||||
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
||||
if (GUILayout.Button("<color=yellow>" + label + "</color>", new GUILayoutOption[] { GUILayout.MaxWidth(rect.width - 230) }))
|
||||
{
|
||||
WindowManager.InspectObject(value, out bool _);
|
||||
}
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleCenter;
|
||||
}
|
||||
}
|
||||
|
||||
//public static void DrawMember(ref object value, string valueType, string memberName, Rect rect, object setTarget = null, Action<object> setAction = null, float labelWidth = 180, bool autoSet = false)
|
||||
//{
|
||||
// GUILayout.Label("<color=cyan>" + memberName + ":</color>", new GUILayoutOption[] { GUILayout.Width(labelWidth) });
|
||||
|
||||
// DrawValue(ref value, rect, valueType, memberName, setTarget, setAction, autoSet);
|
||||
//}
|
||||
|
||||
//public static void DrawValue(ref object value, Rect rect, string nullValueType = null, string memberName = null, object setTarget = null, Action<object> setAction = null, bool autoSet = false)
|
||||
//{
|
||||
// if (value == null)
|
||||
// {
|
||||
// GUILayout.Label("<i>null (" + nullValueType + ")</i>", null);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
|
||||
// }
|
||||
//}
|
||||
|
||||
// Helper for drawing primitive values (with Apply button)
|
||||
|
||||
public static void DrawPrimitive(ref object value, Rect m_rect, object setTarget = null, Action<object> setAction = null, bool autoSet = false)
|
||||
@ -387,10 +444,10 @@ namespace Explorer
|
||||
}
|
||||
else
|
||||
{
|
||||
value = GUILayout.TextField(value.ToString(), new GUILayoutOption[] { GUILayout.MaxWidth(m_rect.width - 260) });
|
||||
value = GUILayout.TextField(value.ToString(), new GUILayoutOption[] { GUILayout.MaxWidth(m_rect.width - 260) });
|
||||
}
|
||||
|
||||
if (autoSet || (allowSet && GUILayout.Button("<color=#00FF00>Apply</color>", new GUILayoutOption[] { GUILayout.Width(60) })))
|
||||
if (autoSet || (allowSet && GUILayout.Button("<color=#00FF00>Apply</color>", new GUILayoutOption[] { GUILayout.Width(60) })))
|
||||
{
|
||||
setAction.Invoke(setTarget);
|
||||
}
|
||||
|
@ -142,11 +142,11 @@ namespace Explorer
|
||||
|
||||
// ============= Resize Window Helper ============
|
||||
|
||||
static readonly GUIContent gcDrag = new GUIContent("<->");
|
||||
//static readonly GUIContent gcDrag = new GUIContent("<->");
|
||||
|
||||
private static bool isResizing = false;
|
||||
private static Rect m_currentResize;
|
||||
private static int m_currentWindow;
|
||||
//private static bool isResizing = false;
|
||||
//private static Rect m_currentResize;
|
||||
//private static int m_currentWindow;
|
||||
|
||||
public static Rect ResizeWindow(Rect _rect, int ID)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user