Compare commits

..

4 Commits
1.3.3 ... 1.3.5

Author SHA1 Message Date
153ad2268b 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.
2020-08-18 17:11:58 +10:00
1ba9b2eae1 Update README.md 2020-08-15 16:08:56 +10:00
be2da96cc0 Update README.md 2020-08-15 16:07:20 +10:00
a2405d69c5 Update README.md 2020-08-14 17:51:09 +10:00
19 changed files with 540 additions and 547 deletions

View File

@ -27,6 +27,16 @@ Requires [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) to be ins
* Press F7 to show or hide the menu.
* Simply browse through the scene, search for objects, etc, it's pretty self-explanatory.
### Help! I can't use the mouse!
It is fairly common for games to override mouse control with their own mouse behaviour. Unfortunately, it's not feasible for CppExplorer to handle this due to how differently every game will go about it.
In order to fix this problem, you can:
* Use [VRCExplorerMouseControl](https://github.com/sinaioutlander/VRCExplorerMouseControl) (for VRChat)
* Use [HPExplorerMouseControl](https://github.com/sinaioutlander/Hellpoint-Mods/tree/master/HPExplorerMouseControl/HPExplorerMouseControl) (for Hellpoint)
* In general, pressing Escape (to open a menu) will usually give you temporary control over the mouse.
* Create your own mini-plugin using one of the two plugins above as an example. Usually only 1 or 2 simple Harmony patches are needed to fix the problem.
## Images
Scene explorer, and inspection of a MonoBehaviour object:

View File

@ -2,13 +2,8 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using MelonLoader;
using UnhollowerBaseLib;
using UnhollowerRuntimeLib;
using Harmony;
using Il2CppSystem.Runtime.InteropServices;
namespace Explorer
{
@ -17,53 +12,23 @@ namespace Explorer
// consts
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 NAME = "IL2CPP Runtime Explorer"
#if Release_Unity2018
public const string NAME = "IL2CPP Runtime Explorer (Unity 2018)";
#else
public const string NAME = "IL2CPP Runtime Explorer";
+ " (Unity 2018)"
#endif
;
// fields
public static CppExplorer Instance;
private string m_objUnderMouseName = "";
private Camera m_main;
// props
public static bool ShowMenu { get; set; } = false;
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
@ -76,21 +41,15 @@ namespace Explorer
new MainMenu();
new WindowManager();
// done init
ShowMenu = true;
}
// On scene change
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()
{
if (Input.GetKeyDown(KeyCode.F7))
@ -109,43 +68,7 @@ namespace Explorer
MainMenu.Instance.Update();
WindowManager.Instance.Update();
if (Input.GetKey(KeyCode.LeftShift) && Input.GetMouseButtonDown(1))
{
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 = "";
InspectUnderMouse.Update();
}
}
@ -156,79 +79,7 @@ namespace Explorer
MainMenu.Instance.OnGUI();
WindowManager.Instance.OnGUI();
if (MouseInspect)
{
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;
}
InspectUnderMouse.OnGUI();
}
}
}

View File

@ -137,23 +137,26 @@
</ItemGroup>
<ItemGroup>
<Compile Include="CppExplorer.cs" />
<Compile Include="Inspectors\Reflection\FieldInfoHolder.cs" />
<Compile Include="Inspectors\Reflection\MemberInfoHolder.cs" />
<Compile Include="Inspectors\Reflection\PropertyInfoHolder.cs" />
<Compile Include="Inspectors\UIWindow.cs" />
<Compile Include="Helpers\ReflectionHelpers.cs" />
<Compile Include="Helpers\UIHelpers.cs" />
<Compile Include="Helpers\UnityHelpers.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\Console\REPL.cs" />
<Compile Include="MainMenu\Pages\Console\REPLHelper.cs" />
<Compile Include="MainMenu\Pages\WindowPage.cs" />
<Compile Include="WindowManager.cs" />
<Compile Include="Windows\WindowManager.cs" />
<Compile Include="MainMenu\MainMenu.cs" />
<Compile Include="Inspectors\GameObjectWindow.cs" />
<Compile Include="Inspectors\ReflectionWindow.cs" />
<Compile Include="Windows\GameObjectWindow.cs" />
<Compile Include="Windows\ReflectionWindow.cs" />
<Compile Include="MainMenu\Pages\ScenePage.cs" />
<Compile Include="MainMenu\Pages\SearchPage.cs" />
<Compile Include="UIStyles.cs" />
<Compile Include="Helpers\UIStyles.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="utils\AccessTools.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</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.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Il2CppSystem.Collections;
//using Il2CppSystem.Reflection;
using MelonLoader;
using UnhollowerBaseLib;
using System.Threading.Tasks;
using UnityEngine;
using Object = UnityEngine.Object;
using System.Reflection;
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
public static void InstantiateButton(Object obj, float width = 100)
{
@ -134,7 +42,7 @@ namespace Explorer
}
else
{
color = LightGreen;
color = UIStyles.LightGreen;
}
}
else
@ -144,7 +52,7 @@ namespace Explorer
FastGameobjButton(obj, color, label, obj.activeSelf, specialInspectMethod, showSmallInspectBtn, width);
}
public static void FastGameobjButton(GameObject obj, Color activeColor, string label, bool enabled, Action<GameObject> specialInspectMethod = null, bool showSmallInspectBtn = true, float width = 380)
{
if (!obj)
@ -236,11 +144,11 @@ namespace Explorer
{
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;
var ilObj = value as Il2CppSystem.Object;
if (ilType == CppExplorer.GameObjectType)
if (ilType == ReflectionHelpers.GameObjectType)
{
go = ilObj.TryCast<GameObject>();
}
@ -269,7 +177,7 @@ namespace Explorer
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;

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.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.BeginHorizontal(null);

View File

@ -36,7 +36,7 @@ namespace Explorer
public void OnSceneChange()
{
m_currentScene = CppExplorer.ActiveSceneName;
m_currentScene = UnityHelpers.ActiveSceneName;
m_currentTransform = null;
CancelSearch();
@ -155,7 +155,7 @@ namespace Explorer
}
else
{
GUILayout.Label(CppExplorer.GetGameObjectPath(m_currentTransform), null);
GUILayout.Label(m_currentTransform.GetGameObjectPath(), null);
}
GUILayout.EndHorizontal();
}
@ -169,7 +169,7 @@ namespace Explorer
foreach (var obj in m_objectList)
{
//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)
{
//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

View File

@ -132,7 +132,7 @@ namespace Explorer
bool _ = false;
int __ = 0;
UIStyles.DrawValue(ref obj, ref _, ref __, _temprect);
UIHelpers.DrawValue(ref obj, ref _, ref __, _temprect);
}
}
else
@ -263,7 +263,7 @@ namespace Explorer
{
try
{
var findType = CppExplorer.GetType(_type);
var findType = ReflectionHelpers.GetTypeByName(_type);
searchType = Il2CppSystem.Type.GetType(findType.AssemblyQualifiedName);
}
catch (Exception e)
@ -273,18 +273,18 @@ namespace Explorer
}
else if (TypeMode == TypeFilter.Object)
{
searchType = CppExplorer.ObjectType;
searchType = ReflectionHelpers.ObjectType;
}
else if (TypeMode == TypeFilter.GameObject)
{
searchType = CppExplorer.GameObjectType;
searchType = ReflectionHelpers.GameObjectType;
}
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!");
return new List<object>();
@ -301,7 +301,7 @@ namespace Explorer
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.
// They're more akin to GameObjects.
@ -346,7 +346,7 @@ namespace Explorer
}
else if (filter == SceneFilter.This)
{
return go.scene.name == CppExplorer.ActiveSceneName;
return go.scene.name == UnityHelpers.ActiveSceneName;
}
else if (filter == SceneFilter.DontDestroy)
{

View File

@ -133,7 +133,7 @@ namespace Explorer
GUILayout.BeginHorizontal(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) }))
{
@ -145,7 +145,7 @@ namespace Explorer
GUILayout.BeginHorizontal(null);
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 (GUILayout.Button("<-", new GUILayoutOption[] { GUILayout.Width(35) }))
@ -198,7 +198,7 @@ namespace Explorer
GUILayout.Label("null", null);
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))
{
@ -207,7 +207,7 @@ namespace Explorer
GUILayout.Label("null", null);
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
@ -329,7 +329,7 @@ namespace Explorer
new GUILayoutOption[] { GUILayout.Width(80) });
if (m_object.activeSelf != m_active) { m_object.SetActive(m_active); }
UIStyles.InstantiateButton(m_object, 100);
UIHelpers.InstantiateButton(m_object, 100);
GUILayout.EndHorizontal();

View File

@ -28,7 +28,7 @@ namespace Explorer
{
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);
}
else
@ -44,7 +44,7 @@ namespace Explorer
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)
@ -103,7 +103,7 @@ namespace Explorer
{
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);
}
else

View File

@ -23,7 +23,7 @@ namespace Explorer
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)
@ -40,7 +40,7 @@ namespace Explorer
}
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);
}
}
@ -114,7 +114,7 @@ namespace Explorer
}
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);
}

View File

@ -1,4 +1,5 @@
using System;
using System.CodeDom;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
@ -14,11 +15,11 @@ namespace Explorer
{
public override string Name { get => "Object Reflection"; set => Name = value; }
public Type m_objectType;
public object m_object;
public Type ObjectType;
//public object Target;
private List<FieldInfoHolder> m_FieldInfos;
private List<PropertyInfoHolder> m_PropertyInfos;
private FieldInfoHolder[] m_FieldInfos;
private PropertyInfoHolder[] m_PropertyInfos;
private bool m_autoUpdate = false;
private string m_search = "";
@ -33,25 +34,21 @@ namespace Explorer
public override void Init()
{
m_object = Target;
m_FieldInfos = new List<FieldInfoHolder>();
m_PropertyInfos = new List<PropertyInfoHolder>();
var type = GetActualType(m_object);
var type = ReflectionHelpers.GetActualType(Target);
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;
}
try
{
m_objectType = type;
GetFields(m_object);
GetProperties(m_object);
}
catch { }
ObjectType = type;
var types = ReflectionHelpers.GetAllBaseTypes(Target);
CacheFields(types);
CacheProperties(types);
MelonLogger.Log("Cached properties: " + m_PropertyInfos.Length);
UpdateValues(true);
}
@ -66,29 +63,106 @@ namespace Explorer
private void UpdateValues(bool forceAll = false)
{
if (forceAll || m_filter == MemberFilter.Both || m_filter == MemberFilter.Field)
{
foreach (var holder in this.m_FieldInfos)
{
if (forceAll || m_search == "" || holder.fieldInfo.Name.ToLower().Contains(m_search.ToLower()))
{
holder.UpdateValue(m_object);
}
}
}
UpdateMemberList(forceAll, this.m_FieldInfos, MemberFilter.Field);
UpdateMemberList(forceAll, this.m_PropertyInfos, MemberFilter.Property);
}
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)
{
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.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)
{
GUILayout.Label("Name: " + (m_object as UnityEngine.Object).name, null);
GUILayout.Label("Name: " + (Target as UnityEngine.Object).name, null);
}
GUILayout.EndHorizontal();
@ -114,9 +188,9 @@ namespace Explorer
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;
GUILayout.Label("GameObject:", null);
@ -163,40 +237,12 @@ namespace Explorer
if (m_filter == MemberFilter.Both || m_filter == MemberFilter.Field)
{
UIStyles.HorizontalLine(Color.grey);
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();
}
DrawMembers(this.m_FieldInfos, "Fields");
}
if (m_filter == MemberFilter.Both || m_filter == MemberFilter.Property)
{
UIStyles.HorizontalLine(Color.grey);
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();
}
DrawMembers(this.m_PropertyInfos, "Properties");
}
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)
{
if (m_filter == mode)
@ -229,129 +296,5 @@ namespace Explorer
}
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;
}
}
}