Cleanup project structure

Restructured the project somewhat and cleaned up classes so that things are where they belong. Created "Helpers" folder and put appropriate helper classes in there.

Important things:
- The "GameObject path" methods are now extension methods on UnityEngine.Transform
- Removed AccessTools (Reflection helpers) as there was no use of it. Replaced with ReflectionHelpers class.
- Some improvements to the "Object Reflection" window, should be a bit faster now. Code cleaned up significantly.
This commit is contained in:
sinaioutlander
2020-08-18 17:11:58 +10:00
parent 1ba9b2eae1
commit 153ad2268b
18 changed files with 530 additions and 547 deletions

View File

@ -2,13 +2,8 @@
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using UnityEngine; using UnityEngine;
using MelonLoader; using MelonLoader;
using UnhollowerBaseLib;
using UnhollowerRuntimeLib;
using Harmony;
using Il2CppSystem.Runtime.InteropServices;
namespace Explorer namespace Explorer
{ {
@ -17,53 +12,23 @@ namespace Explorer
// consts // consts
public const string ID = "com.sinai.cppexplorer"; public const string ID = "com.sinai.cppexplorer";
public const string VERSION = "1.3.3"; public const string VERSION = "1.3.5";
public const string AUTHOR = "Sinai"; public const string AUTHOR = "Sinai";
public const string NAME = "IL2CPP Runtime Explorer"
#if Release_Unity2018 #if Release_Unity2018
public const string NAME = "IL2CPP Runtime Explorer (Unity 2018)"; + " (Unity 2018)"
#else
public const string NAME = "IL2CPP Runtime Explorer";
#endif #endif
;
// fields // fields
public static CppExplorer Instance; public static CppExplorer Instance;
private string m_objUnderMouseName = "";
private Camera m_main;
// props // props
public static bool ShowMenu { get; set; } = false; public static bool ShowMenu { get; set; } = false;
public static int ArrayLimit { get; set; } = 20; public static int ArrayLimit { get; set; } = 20;
public bool MouseInspect { get; set; } = false;
// prop helpers
public static Il2CppSystem.Type GameObjectType => Il2CppType.Of<GameObject>();
public static Il2CppSystem.Type TransformType => Il2CppType.Of<Transform>();
public static Il2CppSystem.Type ObjectType => Il2CppType.Of<UnityEngine.Object>();
public static Il2CppSystem.Type ComponentType => Il2CppType.Of<Component>();
public static string ActiveSceneName
{
get
{
return UnityEngine.SceneManagement.SceneManager.GetActiveScene().name;
}
}
public Camera MainCamera
{
get
{
if (m_main == null)
{
m_main = Camera.main;
}
return m_main;
}
}
// methods // methods
@ -76,21 +41,15 @@ namespace Explorer
new MainMenu(); new MainMenu();
new WindowManager(); new WindowManager();
// done init
ShowMenu = true; ShowMenu = true;
} }
// On scene change
public override void OnLevelWasLoaded(int level) public override void OnLevelWasLoaded(int level)
{ {
if (ScenePage.Instance != null) ScenePage.Instance?.OnSceneChange();
{ SearchPage.Instance?.OnSceneChange();
ScenePage.Instance.OnSceneChange();
SearchPage.Instance.OnSceneChange();
}
} }
// Update
public override void OnUpdate() public override void OnUpdate()
{ {
if (Input.GetKeyDown(KeyCode.F7)) if (Input.GetKeyDown(KeyCode.F7))
@ -109,43 +68,7 @@ namespace Explorer
MainMenu.Instance.Update(); MainMenu.Instance.Update();
WindowManager.Instance.Update(); WindowManager.Instance.Update();
if (Input.GetKey(KeyCode.LeftShift) && Input.GetMouseButtonDown(1)) InspectUnderMouse.Update();
{
MouseInspect = !MouseInspect;
}
if (MouseInspect)
{
InspectUnderMouse();
}
}
else if (MouseInspect)
{
MouseInspect = false;
}
}
private void InspectUnderMouse()
{
Ray ray = MainCamera.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit hit, 1000f))
{
var obj = hit.transform.gameObject;
m_objUnderMouseName = GetGameObjectPath(obj.transform);
if (Input.GetMouseButtonDown(0))
{
MouseInspect = false;
m_objUnderMouseName = "";
WindowManager.InspectObject(obj, out _);
}
}
else
{
m_objUnderMouseName = "";
} }
} }
@ -156,79 +79,7 @@ namespace Explorer
MainMenu.Instance.OnGUI(); MainMenu.Instance.OnGUI();
WindowManager.Instance.OnGUI(); WindowManager.Instance.OnGUI();
if (MouseInspect) InspectUnderMouse.OnGUI();
{
if (m_objUnderMouseName != "")
{
var pos = Input.mousePosition;
var rect = new Rect(
pos.x - (Screen.width / 2), // x
Screen.height - pos.y - 50, // y
Screen.width, // w
50 // h
);
var origAlign = GUI.skin.label.alignment;
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
//shadow text
GUI.Label(rect, $"<color=black>{m_objUnderMouseName}</color>");
//white text
GUI.Label(new Rect(rect.x - 1, rect.y + 1, rect.width, rect.height), m_objUnderMouseName);
GUI.skin.label.alignment = origAlign;
}
}
}
// ************** public helpers **************
public static object Il2CppCast(object obj, Type castTo)
{
var method = typeof(Il2CppObjectBase).GetMethod("TryCast");
var generic = method.MakeGenericMethod(castTo);
return generic.Invoke(obj, null);
}
public static string GetGameObjectPath(Transform _transform)
{
return GetGameObjectPath(_transform, true);
}
public static string GetGameObjectPath(Transform _transform, bool _includeItemName)
{
string text = _includeItemName ? ("/" + _transform.name) : "";
GameObject gameObject = _transform.gameObject;
while (gameObject.transform.parent != null)
{
gameObject = gameObject.transform.parent.gameObject;
text = "/" + gameObject.name + text;
}
return text;
}
public static Type GetType(string _type)
{
try
{
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{
try
{
if (asm.GetType(_type) is Type type)
{
return type;
}
}
catch { }
}
return null;
}
catch
{
return null;
}
} }
} }
} }

View File

@ -137,23 +137,26 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="CppExplorer.cs" /> <Compile Include="CppExplorer.cs" />
<Compile Include="Inspectors\Reflection\FieldInfoHolder.cs" /> <Compile Include="Helpers\ReflectionHelpers.cs" />
<Compile Include="Inspectors\Reflection\MemberInfoHolder.cs" /> <Compile Include="Helpers\UIHelpers.cs" />
<Compile Include="Inspectors\Reflection\PropertyInfoHolder.cs" /> <Compile Include="Helpers\UnityHelpers.cs" />
<Compile Include="Inspectors\UIWindow.cs" /> <Compile Include="MainMenu\InspectUnderMouse.cs" />
<Compile Include="Windows\Reflection\FieldInfoHolder.cs" />
<Compile Include="Windows\Reflection\MemberInfoHolder.cs" />
<Compile Include="Windows\Reflection\PropertyInfoHolder.cs" />
<Compile Include="Windows\UIWindow.cs" />
<Compile Include="MainMenu\Pages\ConsolePage.cs" /> <Compile Include="MainMenu\Pages\ConsolePage.cs" />
<Compile Include="MainMenu\Pages\Console\REPL.cs" /> <Compile Include="MainMenu\Pages\Console\REPL.cs" />
<Compile Include="MainMenu\Pages\Console\REPLHelper.cs" /> <Compile Include="MainMenu\Pages\Console\REPLHelper.cs" />
<Compile Include="MainMenu\Pages\WindowPage.cs" /> <Compile Include="MainMenu\Pages\WindowPage.cs" />
<Compile Include="WindowManager.cs" /> <Compile Include="Windows\WindowManager.cs" />
<Compile Include="MainMenu\MainMenu.cs" /> <Compile Include="MainMenu\MainMenu.cs" />
<Compile Include="Inspectors\GameObjectWindow.cs" /> <Compile Include="Windows\GameObjectWindow.cs" />
<Compile Include="Inspectors\ReflectionWindow.cs" /> <Compile Include="Windows\ReflectionWindow.cs" />
<Compile Include="MainMenu\Pages\ScenePage.cs" /> <Compile Include="MainMenu\Pages\ScenePage.cs" />
<Compile Include="MainMenu\Pages\SearchPage.cs" /> <Compile Include="MainMenu\Pages\SearchPage.cs" />
<Compile Include="UIStyles.cs" /> <Compile Include="Helpers\UIStyles.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="utils\AccessTools.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project> </Project>

View File

@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using UnhollowerBaseLib;
using UnhollowerRuntimeLib;
using UnityEngine;
using BF = System.Reflection.BindingFlags;
using ILBF = Il2CppSystem.Reflection.BindingFlags;
namespace Explorer
{
public class ReflectionHelpers
{
public static BF CommonFlags = BF.Public | BF.Instance | BF.NonPublic | BF.Static;
public static ILBF CommonFlags_IL = ILBF.Public | ILBF.NonPublic | ILBF.Instance | ILBF.Static;
public static Il2CppSystem.Type GameObjectType => Il2CppType.Of<GameObject>();
public static Il2CppSystem.Type TransformType => Il2CppType.Of<Transform>();
public static Il2CppSystem.Type ObjectType => Il2CppType.Of<UnityEngine.Object>();
public static Il2CppSystem.Type ComponentType => Il2CppType.Of<Component>();
private static readonly MethodInfo m_tryCastMethodInfo = typeof(Il2CppObjectBase).GetMethod("TryCast");
public static object Il2CppCast(object obj, Type castTo)
{
var generic = m_tryCastMethodInfo.MakeGenericMethod(castTo);
return generic.Invoke(obj, null);
}
public static bool IsList(Type t)
{
return t.IsGenericType
&& t.GetGenericTypeDefinition() is Type typeDef
&& (typeDef.IsAssignableFrom(typeof(List<>)) || typeDef.IsAssignableFrom(typeof(Il2CppSystem.Collections.Generic.List<>)));
}
public static Type GetTypeByName(string typeName)
{
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{
try
{
if (asm.GetType(typeName) is Type type)
{
return type;
}
}
catch { }
}
return null;
}
public static Type GetActualType(object m_object)
{
if (m_object is Il2CppSystem.Object ilObject)
{
var iltype = ilObject.GetIl2CppType();
return Type.GetType(iltype.AssemblyQualifiedName);
}
else
{
return m_object.GetType();
}
}
public static Type[] GetAllBaseTypes(object m_object)
{
var list = new List<Type>();
if (m_object is Il2CppSystem.Object ilObject)
{
var ilType = ilObject.GetIl2CppType();
if (Type.GetType(ilType.AssemblyQualifiedName) is Type ilTypeToManaged)
{
list.Add(ilTypeToManaged);
while (ilType.BaseType != null)
{
ilType = ilType.BaseType;
if (Type.GetType(ilType.AssemblyQualifiedName) is Type ilBaseTypeToManaged)
{
list.Add(ilBaseTypeToManaged);
}
}
}
}
else
{
var type = m_object.GetType();
list.Add(type);
while (type.BaseType != null)
{
type = type.BaseType;
list.Add(type);
}
}
return list.ToArray();
}
}
}

View File

@ -1,108 +1,16 @@
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.Text; using System.Text;
using Il2CppSystem.Collections; using System.Threading.Tasks;
//using Il2CppSystem.Reflection;
using MelonLoader;
using UnhollowerBaseLib;
using UnityEngine; using UnityEngine;
using Object = UnityEngine.Object; using Object = UnityEngine.Object;
using System.Reflection;
namespace Explorer namespace Explorer
{ {
public class UIStyles public class UIHelpers
{ {
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
{
if (_customSkin == null)
{
try
{
_customSkin = CreateWindowSkin();
}
catch
{
_customSkin = GUI.skin;
}
}
return _customSkin;
}
}
public static void HorizontalLine(Color color)
{
var c = GUI.color;
GUI.color = color;
GUILayout.Box(GUIContent.none, HorizontalBar, null);
GUI.color = c;
}
private static GUISkin _customSkin;
public static Texture2D m_nofocusTex;
public static Texture2D m_focusTex;
private static GUIStyle _horizBarStyle;
private static GUIStyle HorizontalBar
{
get
{
if (_horizBarStyle == null)
{
_horizBarStyle = new GUIStyle();
_horizBarStyle.normal.background = Texture2D.whiteTexture;
_horizBarStyle.margin = new RectOffset(0, 0, 4, 4);
_horizBarStyle.fixedHeight = 2;
}
return _horizBarStyle;
}
}
private static GUISkin CreateWindowSkin()
{
var newSkin = Object.Instantiate(GUI.skin);
Object.DontDestroyOnLoad(newSkin);
m_nofocusTex = MakeTex(550, 700, new Color(0.1f, 0.1f, 0.1f, 0.7f));
m_focusTex = MakeTex(550, 700, new Color(0.3f, 0.3f, 0.3f, 1f));
newSkin.window.normal.background = m_nofocusTex;
newSkin.window.onNormal.background = m_focusTex;
newSkin.box.normal.textColor = Color.white;
newSkin.window.normal.textColor = Color.white;
newSkin.button.normal.textColor = Color.white;
newSkin.textField.normal.textColor = Color.white;
newSkin.label.normal.textColor = Color.white;
return newSkin;
}
public static Texture2D MakeTex(int width, int height, Color col)
{
Color[] pix = new Color[width * height];
for (int i = 0; i < pix.Length; ++i)
{
pix[i] = col;
}
Texture2D result = new Texture2D(width, height);
result.SetPixels(pix);
result.Apply();
return result;
}
// *********************************** METHODS FOR DRAWING VALUES IN GUI ************************************
// helper for "Instantiate" button on UnityEngine.Objects // helper for "Instantiate" button on UnityEngine.Objects
public static void InstantiateButton(Object obj, float width = 100) public static void InstantiateButton(Object obj, float width = 100)
{ {
@ -134,7 +42,7 @@ namespace Explorer
} }
else else
{ {
color = LightGreen; color = UIStyles.LightGreen;
} }
} }
else else
@ -144,7 +52,7 @@ namespace Explorer
FastGameobjButton(obj, color, label, obj.activeSelf, specialInspectMethod, showSmallInspectBtn, width); 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) public static void FastGameobjButton(GameObject obj, Color activeColor, string label, bool enabled, Action<GameObject> specialInspectMethod = null, bool showSmallInspectBtn = true, float width = 380)
{ {
if (!obj) if (!obj)
@ -236,11 +144,11 @@ namespace Explorer
{ {
DrawPrimitive(ref value, rect, setTarget, setAction); DrawPrimitive(ref value, rect, setTarget, setAction);
} }
else if (ilType != null && ilType == CppExplorer.GameObjectType || CppExplorer.TransformType.IsAssignableFrom(ilType)) else if (ilType != null && ilType == ReflectionHelpers.GameObjectType || ReflectionHelpers.TransformType.IsAssignableFrom(ilType))
{ {
GameObject go; GameObject go;
var ilObj = value as Il2CppSystem.Object; var ilObj = value as Il2CppSystem.Object;
if (ilType == CppExplorer.GameObjectType) if (ilType == ReflectionHelpers.GameObjectType)
{ {
go = ilObj.TryCast<GameObject>(); go = ilObj.TryCast<GameObject>();
} }
@ -269,7 +177,7 @@ namespace Explorer
GUILayout.Label(value.ToString(), null); GUILayout.Label(value.ToString(), null);
} }
else if (value is System.Collections.IEnumerable || ReflectionWindow.IsList(valueType)) else if (value is System.Collections.IEnumerable || ReflectionHelpers.IsList(valueType))
{ {
System.Collections.IEnumerable enumerable; System.Collections.IEnumerable enumerable;

100
src/Helpers/UIStyles.cs Normal file
View File

@ -0,0 +1,100 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
using Object = UnityEngine.Object;
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
{
if (_customSkin == null)
{
try
{
_customSkin = CreateWindowSkin();
}
catch
{
_customSkin = GUI.skin;
}
}
return _customSkin;
}
}
public static void HorizontalLine(Color color)
{
var c = GUI.color;
GUI.color = color;
GUILayout.Box(GUIContent.none, HorizontalBar, null);
GUI.color = c;
}
private static GUISkin _customSkin;
public static Texture2D m_nofocusTex;
public static Texture2D m_focusTex;
private static GUIStyle _horizBarStyle;
private static GUIStyle HorizontalBar
{
get
{
if (_horizBarStyle == null)
{
_horizBarStyle = new GUIStyle();
_horizBarStyle.normal.background = Texture2D.whiteTexture;
_horizBarStyle.margin = new RectOffset(0, 0, 4, 4);
_horizBarStyle.fixedHeight = 2;
}
return _horizBarStyle;
}
}
private static GUISkin CreateWindowSkin()
{
var newSkin = Object.Instantiate(GUI.skin);
Object.DontDestroyOnLoad(newSkin);
m_nofocusTex = MakeTex(550, 700, new Color(0.1f, 0.1f, 0.1f, 0.7f));
m_focusTex = MakeTex(550, 700, new Color(0.3f, 0.3f, 0.3f, 1f));
newSkin.window.normal.background = m_nofocusTex;
newSkin.window.onNormal.background = m_focusTex;
newSkin.box.normal.textColor = Color.white;
newSkin.window.normal.textColor = Color.white;
newSkin.button.normal.textColor = Color.white;
newSkin.textField.normal.textColor = Color.white;
newSkin.label.normal.textColor = Color.white;
return newSkin;
}
public static Texture2D MakeTex(int width, int height, Color col)
{
Color[] pix = new Color[width * height];
for (int i = 0; i < pix.Length; ++i)
{
pix[i] = col;
}
Texture2D result = new Texture2D(width, height);
result.SetPixels(pix);
result.Apply();
return result;
}
}
}

View File

@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace Explorer
{
public static class UnityHelpers
{
private static Camera m_mainCamera;
public static Camera MainCamera
{
get
{
if (m_mainCamera == null)
{
m_mainCamera = Camera.main;
}
return m_mainCamera;
}
}
public static string ActiveSceneName
{
get
{
return UnityEngine.SceneManagement.SceneManager.GetActiveScene().name;
}
}
public static string GetGameObjectPath(this Transform _transform)
{
return GetGameObjectPath(_transform, true);
}
public static string GetGameObjectPath(this Transform _transform, bool _includeThisName)
{
string path = _includeThisName ? ("/" + _transform.name) : "";
GameObject gameObject = _transform.gameObject;
while (gameObject.transform.parent != null)
{
gameObject = gameObject.transform.parent.gameObject;
path = "/" + gameObject.name + path;
}
return path;
}
}
}

View File

@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace Explorer
{
public class InspectUnderMouse
{
public static bool EnableInspect { get; set; } = false;
private static string m_objUnderMouseName = "";
public static void Update()
{
if (CppExplorer.ShowMenu)
{
if (Input.GetKey(KeyCode.LeftShift) && Input.GetMouseButtonDown(1))
{
EnableInspect = !EnableInspect;
}
if (EnableInspect)
{
InspectRaycast();
}
}
else if (EnableInspect)
{
EnableInspect = false;
}
}
public static void InspectRaycast()
{
Ray ray = UnityHelpers.MainCamera.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit hit, 1000f))
{
var obj = hit.transform.gameObject;
m_objUnderMouseName = obj.transform.GetGameObjectPath();
if (Input.GetMouseButtonDown(0))
{
EnableInspect = false;
m_objUnderMouseName = "";
WindowManager.InspectObject(obj, out _);
}
}
else
{
m_objUnderMouseName = "";
}
}
public static void OnGUI()
{
if (EnableInspect)
{
if (m_objUnderMouseName != "")
{
var pos = Input.mousePosition;
var rect = new Rect(
pos.x - (Screen.width / 2), // x
Screen.height - pos.y - 50, // y
Screen.width, // w
50 // h
);
var origAlign = GUI.skin.label.alignment;
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
//shadow text
GUI.Label(rect, $"<color=black>{m_objUnderMouseName}</color>");
//white text
GUI.Label(new Rect(rect.x - 1, rect.y + 1, rect.width, rect.height), m_objUnderMouseName);
GUI.skin.label.alignment = origAlign;
}
}
}
}
}

View File

@ -98,7 +98,7 @@ namespace Explorer
{ {
CppExplorer.ArrayLimit = _lim; CppExplorer.ArrayLimit = _lim;
} }
CppExplorer.Instance.MouseInspect = GUILayout.Toggle(CppExplorer.Instance.MouseInspect, "Inspect Under Mouse (Shift + RMB)", null); InspectUnderMouse.EnableInspect = GUILayout.Toggle(InspectUnderMouse.EnableInspect, "Inspect Under Mouse (Shift + RMB)", null);
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);

View File

@ -36,7 +36,7 @@ namespace Explorer
public void OnSceneChange() public void OnSceneChange()
{ {
m_currentScene = CppExplorer.ActiveSceneName; m_currentScene = UnityHelpers.ActiveSceneName;
m_currentTransform = null; m_currentTransform = null;
CancelSearch(); CancelSearch();
@ -155,7 +155,7 @@ namespace Explorer
} }
else else
{ {
GUILayout.Label(CppExplorer.GetGameObjectPath(m_currentTransform), null); GUILayout.Label(m_currentTransform.GetGameObjectPath(), null);
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
@ -169,7 +169,7 @@ namespace Explorer
foreach (var obj in m_objectList) 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); UIHelpers.FastGameobjButton(obj.RefGameObject, obj.EnabledColor, obj.Label, obj.RefGameObject.activeSelf, SetTransformTarget, true, MainMenu.MainRect.width - 170);
} }
} }
} }
@ -187,7 +187,7 @@ namespace Explorer
foreach (var obj in m_searchResults) 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); UIHelpers.FastGameobjButton(obj.RefGameObject, obj.EnabledColor, obj.Label, obj.RefGameObject.activeSelf, SetTransformTarget, true, MainMenu.MainRect.width - 170);
} }
} }
else else

View File

@ -132,7 +132,7 @@ namespace Explorer
bool _ = false; bool _ = false;
int __ = 0; int __ = 0;
UIStyles.DrawValue(ref obj, ref _, ref __, _temprect); UIHelpers.DrawValue(ref obj, ref _, ref __, _temprect);
} }
} }
else else
@ -263,7 +263,7 @@ namespace Explorer
{ {
try try
{ {
var findType = CppExplorer.GetType(_type); var findType = ReflectionHelpers.GetTypeByName(_type);
searchType = Il2CppSystem.Type.GetType(findType.AssemblyQualifiedName); searchType = Il2CppSystem.Type.GetType(findType.AssemblyQualifiedName);
} }
catch (Exception e) catch (Exception e)
@ -273,18 +273,18 @@ namespace Explorer
} }
else if (TypeMode == TypeFilter.Object) else if (TypeMode == TypeFilter.Object)
{ {
searchType = CppExplorer.ObjectType; searchType = ReflectionHelpers.ObjectType;
} }
else if (TypeMode == TypeFilter.GameObject) else if (TypeMode == TypeFilter.GameObject)
{ {
searchType = CppExplorer.GameObjectType; searchType = ReflectionHelpers.GameObjectType;
} }
else if (TypeMode == TypeFilter.Component) else if (TypeMode == TypeFilter.Component)
{ {
searchType = CppExplorer.ComponentType; searchType = ReflectionHelpers.ComponentType;
} }
if (!CppExplorer.ObjectType.IsAssignableFrom(searchType)) if (!ReflectionHelpers.ObjectType.IsAssignableFrom(searchType))
{ {
MelonLogger.LogError("Your Custom Class Type must inherit from UnityEngine.Object!"); MelonLogger.LogError("Your Custom Class Type must inherit from UnityEngine.Object!");
return new List<object>(); return new List<object>();
@ -301,7 +301,7 @@ namespace Explorer
continue; continue;
} }
if (searchType == CppExplorer.ComponentType && CppExplorer.TransformType.IsAssignableFrom(obj.GetIl2CppType())) if (searchType == ReflectionHelpers.ComponentType && ReflectionHelpers.TransformType.IsAssignableFrom(obj.GetIl2CppType()))
{ {
// Transforms shouldn't really be counted as Components, skip them. // Transforms shouldn't really be counted as Components, skip them.
// They're more akin to GameObjects. // They're more akin to GameObjects.
@ -346,7 +346,7 @@ namespace Explorer
} }
else if (filter == SceneFilter.This) else if (filter == SceneFilter.This)
{ {
return go.scene.name == CppExplorer.ActiveSceneName; return go.scene.name == UnityHelpers.ActiveSceneName;
} }
else if (filter == SceneFilter.DontDestroy) else if (filter == SceneFilter.DontDestroy)
{ {

View File

@ -133,7 +133,7 @@ namespace Explorer
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Label("Scene: <color=cyan>" + (m_scene == "" ? "n/a" : m_scene) + "</color>", null); GUILayout.Label("Scene: <color=cyan>" + (m_scene == "" ? "n/a" : m_scene) + "</color>", null);
if (m_scene == CppExplorer.ActiveSceneName) if (m_scene == UnityHelpers.ActiveSceneName)
{ {
if (GUILayout.Button("<color=#00FF00>< View in Scene Explorer</color>", new GUILayoutOption[] { GUILayout.Width(230) })) if (GUILayout.Button("<color=#00FF00>< View in Scene Explorer</color>", new GUILayoutOption[] { GUILayout.Width(230) }))
{ {
@ -145,7 +145,7 @@ namespace Explorer
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Label("Path:", new GUILayoutOption[] { GUILayout.Width(50) }); GUILayout.Label("Path:", new GUILayoutOption[] { GUILayout.Width(50) });
string pathlabel = CppExplorer.GetGameObjectPath(m_object.transform); string pathlabel = m_object.transform.GetGameObjectPath();
if (m_object.transform.parent != null) if (m_object.transform.parent != null)
{ {
if (GUILayout.Button("<-", new GUILayoutOption[] { GUILayout.Width(35) })) if (GUILayout.Button("<-", new GUILayoutOption[] { GUILayout.Width(35) }))
@ -198,7 +198,7 @@ namespace Explorer
GUILayout.Label("null", null); GUILayout.Label("null", null);
continue; continue;
} }
UIStyles.GameobjButton(obj.gameObject, InspectGameObject, false, this.m_rect.width / 2 - 60); UIHelpers.GameobjButton(obj.gameObject, InspectGameObject, false, this.m_rect.width / 2 - 60);
} }
foreach (var obj in m_children.Where(x => x.childCount == 0)) foreach (var obj in m_children.Where(x => x.childCount == 0))
{ {
@ -207,7 +207,7 @@ namespace Explorer
GUILayout.Label("null", null); GUILayout.Label("null", null);
continue; continue;
} }
UIStyles.GameobjButton(obj.gameObject, InspectGameObject, false, this.m_rect.width / 2 - 60); UIHelpers.GameobjButton(obj.gameObject, InspectGameObject, false, this.m_rect.width / 2 - 60);
} }
} }
else else
@ -329,7 +329,7 @@ namespace Explorer
new GUILayoutOption[] { GUILayout.Width(80) }); new GUILayoutOption[] { GUILayout.Width(80) });
if (m_object.activeSelf != m_active) { m_object.SetActive(m_active); } if (m_object.activeSelf != m_active) { m_object.SetActive(m_active); }
UIStyles.InstantiateButton(m_object, 100); UIHelpers.InstantiateButton(m_object, 100);
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();

View File

@ -28,7 +28,7 @@ namespace Explorer
{ {
var declaringType = this.fieldInfo.DeclaringType; var declaringType = this.fieldInfo.DeclaringType;
var cast = CppExplorer.Il2CppCast(obj, declaringType); var cast = ReflectionHelpers.Il2CppCast(obj, declaringType);
m_value = this.fieldInfo.GetValue(fieldInfo.IsStatic ? null : cast); m_value = this.fieldInfo.GetValue(fieldInfo.IsStatic ? null : cast);
} }
else else
@ -44,7 +44,7 @@ namespace Explorer
public override void Draw(ReflectionWindow window) public override void Draw(ReflectionWindow window)
{ {
UIStyles.DrawMember(ref m_value, ref this.IsExpanded, ref this.arrayOffset, this.fieldInfo, window.m_rect, window.m_object, SetValue); UIHelpers.DrawMember(ref m_value, ref this.IsExpanded, ref this.arrayOffset, this.fieldInfo, window.m_rect, window.Target, SetValue);
} }
public override void SetValue(object obj) public override void SetValue(object obj)
@ -103,7 +103,7 @@ namespace Explorer
{ {
var declaringType = this.fieldInfo.DeclaringType; var declaringType = this.fieldInfo.DeclaringType;
var cast = CppExplorer.Il2CppCast(obj, declaringType); var cast = ReflectionHelpers.Il2CppCast(obj, declaringType);
fieldInfo.SetValue(fieldInfo.IsStatic ? null : cast, m_value); fieldInfo.SetValue(fieldInfo.IsStatic ? null : cast, m_value);
} }
else else

View File

@ -23,7 +23,7 @@ namespace Explorer
public override void Draw(ReflectionWindow window) public override void Draw(ReflectionWindow window)
{ {
UIStyles.DrawMember(ref m_value, ref this.IsExpanded, ref this.arrayOffset, this.propInfo, window.m_rect, window.m_object, SetValue); UIHelpers.DrawMember(ref m_value, ref this.IsExpanded, ref this.arrayOffset, this.propInfo, window.m_rect, window.Target, SetValue);
} }
public override void UpdateValue(object obj) public override void UpdateValue(object obj)
@ -40,7 +40,7 @@ namespace Explorer
} }
else else
{ {
var cast = CppExplorer.Il2CppCast(obj, declaringType); var cast = ReflectionHelpers.Il2CppCast(obj, declaringType);
m_value = this.propInfo.GetValue(this.propInfo.GetAccessors()[0].IsStatic ? null : cast, null); m_value = this.propInfo.GetValue(this.propInfo.GetAccessors()[0].IsStatic ? null : cast, null);
} }
} }
@ -114,7 +114,7 @@ namespace Explorer
} }
var declaring = propInfo.DeclaringType; var declaring = propInfo.DeclaringType;
var cast = CppExplorer.Il2CppCast(obj, declaring); var cast = ReflectionHelpers.Il2CppCast(obj, declaring);
propInfo.SetValue(propInfo.GetAccessors()[0].IsStatic ? null : cast, m_value, null); propInfo.SetValue(propInfo.GetAccessors()[0].IsStatic ? null : cast, m_value, null);
} }

View File

@ -1,4 +1,5 @@
using System; using System;
using System.CodeDom;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -14,11 +15,11 @@ namespace Explorer
{ {
public override string Name { get => "Object Reflection"; set => Name = value; } public override string Name { get => "Object Reflection"; set => Name = value; }
public Type m_objectType; public Type ObjectType;
public object m_object; //public object Target;
private List<FieldInfoHolder> m_FieldInfos; private FieldInfoHolder[] m_FieldInfos;
private List<PropertyInfoHolder> m_PropertyInfos; private PropertyInfoHolder[] m_PropertyInfos;
private bool m_autoUpdate = false; private bool m_autoUpdate = false;
private string m_search = ""; private string m_search = "";
@ -33,25 +34,21 @@ namespace Explorer
public override void Init() public override void Init()
{ {
m_object = Target; var type = ReflectionHelpers.GetActualType(Target);
m_FieldInfos = new List<FieldInfoHolder>();
m_PropertyInfos = new List<PropertyInfoHolder>();
var type = GetActualType(m_object);
if (type == null) if (type == null)
{ {
MelonLogger.Log("could not get underlying type for object. ToString(): " + m_object.ToString()); MelonLogger.Log("Could not get underlying type for object. ToString(): " + Target.ToString());
return; return;
} }
try ObjectType = type;
{
m_objectType = type; var types = ReflectionHelpers.GetAllBaseTypes(Target);
GetFields(m_object);
GetProperties(m_object); CacheFields(types);
} CacheProperties(types);
catch { }
MelonLogger.Log("Cached properties: " + m_PropertyInfos.Length);
UpdateValues(true); UpdateValues(true);
} }
@ -66,29 +63,106 @@ namespace Explorer
private void UpdateValues(bool forceAll = false) private void UpdateValues(bool forceAll = false)
{ {
if (forceAll || m_filter == MemberFilter.Both || m_filter == MemberFilter.Field) UpdateMemberList(forceAll, this.m_FieldInfos, MemberFilter.Field);
{ UpdateMemberList(forceAll, this.m_PropertyInfos, MemberFilter.Property);
foreach (var holder in this.m_FieldInfos) }
{
if (forceAll || m_search == "" || holder.fieldInfo.Name.ToLower().Contains(m_search.ToLower()))
{
holder.UpdateValue(m_object);
}
}
}
if (forceAll || m_filter == MemberFilter.Both || m_filter == MemberFilter.Property) private void UpdateMemberList(bool forceAll, MemberInfoHolder[] list, MemberFilter filter)
{
if (forceAll || m_filter == MemberFilter.Both || m_filter == filter)
{ {
foreach (var holder in this.m_PropertyInfos) foreach (var holder in list)
{ {
if (forceAll || m_search == "" || holder.propInfo.Name.ToLower().Contains(m_search.ToLower())) if (forceAll || ShouldUpdateMemberInfo(holder))
{ {
holder.UpdateValue(m_object); holder.UpdateValue(Target);
} }
} }
} }
} }
private bool ShouldUpdateMemberInfo(MemberInfoHolder holder)
{
var memberName = holder is FieldInfoHolder ?
(holder as FieldInfoHolder).fieldInfo.Name :
(holder as PropertyInfoHolder).propInfo.Name;
return m_search == "" || memberName.ToLower().Contains(m_search.ToLower());
}
private void CacheProperties(Type[] types, List<string> names = null)
{
if (names == null)
{
names = new List<string>();
}
var list = new List<PropertyInfoHolder>();
foreach (var type in types)
{
PropertyInfo[] propInfos = new PropertyInfo[0];
try
{
propInfos = type.GetProperties(ReflectionHelpers.CommonFlags);
}
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;
}
if (names.Contains(pi.Name))
{
continue;
}
names.Add(pi.Name);
var piHolder = new PropertyInfoHolder(type, pi);
list.Add(piHolder);
}
}
m_PropertyInfos = list.ToArray();
}
private void CacheFields(Type[] types, List<string> names = null)
{
if (names == null)
{
names = new List<string>();
}
var list = new List<FieldInfoHolder>();
foreach (var type in types)
{
foreach (var fi in type.GetFields(ReflectionHelpers.CommonFlags))
{
if (names.Contains(fi.Name))
{
continue;
}
names.Add(fi.Name);
var fiHolder = new FieldInfoHolder(type, fi);
list.Add(fiHolder);
}
}
m_FieldInfos = list.ToArray();
}
// =========== GUI DRAW =========== //
public override void WindowFunction(int windowID) public override void WindowFunction(int windowID)
{ {
try try
@ -98,13 +172,13 @@ namespace Explorer
GUILayout.BeginArea(new Rect(5, 25, m_rect.width - 10, m_rect.height - 35), GUI.skin.box); GUILayout.BeginArea(new Rect(5, 25, m_rect.width - 10, m_rect.height - 35), GUI.skin.box);
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Label("<b>Type:</b> <color=cyan>" + m_objectType.Name + "</color>", null); GUILayout.Label("<b>Type:</b> <color=cyan>" + ObjectType.Name + "</color>", null);
bool unityObj = m_object is UnityEngine.Object; bool unityObj = Target is UnityEngine.Object;
if (unityObj) if (unityObj)
{ {
GUILayout.Label("Name: " + (m_object as UnityEngine.Object).name, null); GUILayout.Label("Name: " + (Target as UnityEngine.Object).name, null);
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
@ -114,9 +188,9 @@ namespace Explorer
GUILayout.Label("<b>Tools:</b>", new GUILayoutOption[] { GUILayout.Width(80) }); GUILayout.Label("<b>Tools:</b>", new GUILayoutOption[] { GUILayout.Width(80) });
UIStyles.InstantiateButton((UnityEngine.Object)m_object); UIHelpers.InstantiateButton((UnityEngine.Object)Target);
if (m_object is Component comp && comp.gameObject is GameObject obj) if (Target is Component comp && comp.gameObject is GameObject obj)
{ {
GUI.skin.label.alignment = TextAnchor.MiddleRight; GUI.skin.label.alignment = TextAnchor.MiddleRight;
GUILayout.Label("GameObject:", null); GUILayout.Label("GameObject:", null);
@ -163,40 +237,12 @@ namespace Explorer
if (m_filter == MemberFilter.Both || m_filter == MemberFilter.Field) if (m_filter == MemberFilter.Both || m_filter == MemberFilter.Field)
{ {
UIStyles.HorizontalLine(Color.grey); DrawMembers(this.m_FieldInfos, "Fields");
GUILayout.Label("<size=18><b><color=gold>Fields</color></b></size>", null);
foreach (var holder in this.m_FieldInfos)
{
if (m_search != "" && !holder.fieldInfo.Name.ToLower().Contains(m_search.ToLower()))
{
continue;
}
GUILayout.BeginHorizontal(new GUILayoutOption[] { GUILayout.Height(25) });
holder.Draw(this);
GUILayout.EndHorizontal();
}
} }
if (m_filter == MemberFilter.Both || m_filter == MemberFilter.Property) if (m_filter == MemberFilter.Both || m_filter == MemberFilter.Property)
{ {
UIStyles.HorizontalLine(Color.grey); DrawMembers(this.m_PropertyInfos, "Properties");
GUILayout.Label("<size=18><b><color=gold>Properties</color></b></size>", null);
foreach (var holder in this.m_PropertyInfos)
{
if (m_search != "" && !holder.propInfo.Name.ToLower().Contains(m_search.ToLower()))
{
continue;
}
GUILayout.BeginHorizontal(new GUILayoutOption[] { GUILayout.Height(25) });
holder.Draw(this);
GUILayout.EndHorizontal();
}
} }
GUILayout.EndScrollView(); GUILayout.EndScrollView();
@ -213,6 +259,27 @@ namespace Explorer
} }
} }
private void DrawMembers(MemberInfoHolder[] members, string title)
{
UIStyles.HorizontalLine(Color.grey);
GUILayout.Label($"<size=18><b><color=gold>{title}</color></b></size>", null);
foreach (var holder in members)
{
var memberName = (holder as FieldInfoHolder)?.fieldInfo.Name ?? (holder as PropertyInfoHolder)?.propInfo.Name;
if (m_search != "" && !memberName.ToLower().Contains(m_search.ToLower()))
{
continue;
}
GUILayout.BeginHorizontal(new GUILayoutOption[] { GUILayout.Height(25) });
holder.Draw(this);
GUILayout.EndHorizontal();
}
}
private void FilterToggle(MemberFilter mode, string label) private void FilterToggle(MemberFilter mode, string label)
{ {
if (m_filter == mode) if (m_filter == mode)
@ -229,129 +296,5 @@ namespace Explorer
} }
GUI.color = Color.white; GUI.color = Color.white;
} }
// ============ HELPERS ===============
public Type GetActualType(object m_object)
{
if (m_object is Il2CppSystem.Object ilObject)
{
var iltype = ilObject.GetIl2CppType();
return Type.GetType(iltype.AssemblyQualifiedName);
}
else
{
return m_object.GetType();
}
}
public Type[] GetAllBaseTypes(object m_object)
{
var list = new List<Type>();
if (m_object is Il2CppSystem.Object ilObject)
{
var ilType = ilObject.GetIl2CppType();
if (Type.GetType(ilType.AssemblyQualifiedName) is Type ilTypeToManaged)
{
list.Add(ilTypeToManaged);
while (ilType.BaseType != null)
{
ilType = ilType.BaseType;
if (Type.GetType(ilType.AssemblyQualifiedName) is Type ilBaseTypeToManaged)
{
list.Add(ilBaseTypeToManaged);
}
}
}
}
else
{
var type = m_object.GetType();
list.Add(type);
while (type.BaseType != null)
{
type = type.BaseType;
list.Add(type);
}
}
return list.ToArray();
}
public static bool IsList(Type t)
{
return t.IsGenericType
&& t.GetGenericTypeDefinition() is Type typeDef
&& (typeDef.IsAssignableFrom(typeof(List<>)) || typeDef.IsAssignableFrom(typeof(Il2CppSystem.Collections.Generic.List<>)));
}
private void GetProperties(object m_object, List<string> names = null)
{
if (names == null)
{
names = new List<string>();
}
var types = GetAllBaseTypes(m_object);
foreach (var type in types)
{
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;
}
if (names.Contains(pi.Name))
{
continue;
}
names.Add(pi.Name);
var piHolder = new PropertyInfoHolder(type, pi);
m_PropertyInfos.Add(piHolder);
}
}
}
private void GetFields(object m_object, List<string> names = null)
{
if (names == null)
{
names = new List<string>();
}
var types = GetAllBaseTypes(m_object);
foreach (var type in types)
{
foreach (var fi in type.GetFields(At.flags))
{
if (names.Contains(fi.Name))
{
continue;
}
names.Add(fi.Name);
var fiHolder = new FieldInfoHolder(type, fi);
m_FieldInfos.Add(fiHolder);
}
}
}
} }
} }

View File

@ -1,65 +0,0 @@
using System;
using System.Reflection;
namespace Explorer
{
/// <summary>
/// AccessTools
/// Some helpers for Reflection (GetValue, SetValue, Call, InheritBaseValues)
/// </summary>
public static class At
{
public static Il2CppSystem.Reflection.BindingFlags ilFlags = Il2CppSystem.Reflection.BindingFlags.Public
| Il2CppSystem.Reflection.BindingFlags.NonPublic
| Il2CppSystem.Reflection.BindingFlags.Instance
| Il2CppSystem.Reflection.BindingFlags.Static;
public static BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static;
//reflection call
public static object Call(object obj, string method, params object[] args)
{
var methodInfo = obj.GetType().GetMethod(method, flags);
if (methodInfo != null)
{
return methodInfo.Invoke(obj, args);
}
return null;
}
// set value
public static void SetValue<T>(T value, Type type, object obj, string field)
{
FieldInfo fieldInfo = type.GetField(field, flags);
if (fieldInfo != null)
{
fieldInfo.SetValue(obj, value);
}
}
// get value
public static object GetValue(Type type, object obj, string value)
{
FieldInfo fieldInfo = type.GetField(value, flags);
if (fieldInfo != null)
{
return fieldInfo.GetValue(obj);
}
else
{
return null;
}
}
// inherit base values
public static void InheritBaseValues(object _derived, object _base)
{
foreach (FieldInfo fi in _base.GetType().GetFields(flags))
{
try { _derived.GetType().GetField(fi.Name).SetValue(_derived, fi.GetValue(_base)); } catch { }
}
return;
}
}
}