mirror of
https://github.com/sinai-dev/UnityExplorer.git
synced 2025-01-03 16:13:25 +08:00
Merging the two projects into one with build configurations
Removed the "src_2018" project, since it's now 1:1 with the main project and the only difference is references. Now using build configurations and preprocessor directives to accomplish the same thing.
This commit is contained in:
parent
0c3067973e
commit
d399b6acd1
@ -16,10 +16,15 @@ namespace Explorer
|
||||
// consts
|
||||
|
||||
public const string ID = "com.sinai.cppexplorer";
|
||||
public const string NAME = "IL2CPP Runtime Explorer";
|
||||
public const string VERSION = "1.3.2";
|
||||
public const string AUTHOR = "Sinai";
|
||||
|
||||
#if Release_Unity2018
|
||||
public const string NAME = "IL2CPP Runtime Explorer (Unity 2018)";
|
||||
#else
|
||||
public const string NAME = "IL2CPP Runtime Explorer";
|
||||
#endif
|
||||
|
||||
// fields
|
||||
|
||||
public static CppExplorer Instance;
|
||||
|
@ -8,31 +8,33 @@
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Explorer</RootNamespace>
|
||||
<AssemblyName>CppExplorer</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<AssemblyName>CppExplorer</AssemblyName>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
<DebugType>none</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>..\Release\</OutputPath>
|
||||
<DefineConstants>
|
||||
</DefineConstants>
|
||||
<DefineConstants>DEBUG</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release_Unity2018|AnyCPU' ">
|
||||
<AssemblyName>CppExplorer_Unity2018</AssemblyName>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
<DebugType>none</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>..\Release\</OutputPath>
|
||||
<DefineConstants>Release_Unity2018</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
@ -66,48 +68,70 @@
|
||||
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnhollowerRuntimeLib.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Unity.TextMeshPro">
|
||||
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\Unity.TextMeshPro.dll</HintPath>
|
||||
<!-- Unity 2019 build (InputLegacyModule.dll) -->
|
||||
<Reference Include="UnityEngine" Condition="'$(Configuration)'=='Debug'">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
<Reference Include="UnityEngine.CoreModule" Condition="'$(Configuration)'=='Debug'">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.IMGUIModule">
|
||||
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.IMGUIModule.dll</HintPath>
|
||||
<Reference Include="UnityEngine.IMGUIModule" Condition="'$(Configuration)'=='Debug'">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.IMGUIModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.InputLegacyModule">
|
||||
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.InputLegacyModule.dll</HintPath>
|
||||
<Reference Include="UnityEngine.InputModule" Condition="'$(Configuration)'=='Debug'">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.InputLegacyModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.InputModule">
|
||||
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.InputModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.ParticleSystemModule">
|
||||
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.ParticleSystemModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.PhysicsModule">
|
||||
<Reference Include="UnityEngine.PhysicsModule" Condition="'$(Configuration)'=='Debug'">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.PhysicsModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.TextRenderingModule">
|
||||
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.TextRenderingModule.dll</HintPath>
|
||||
<Reference Include="UnityEngine.TextRenderingModule" Condition="'$(Configuration)'=='Debug'">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.TextRenderingModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UI">
|
||||
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.UI.dll</HintPath>
|
||||
<Reference Include="UnityEngine.UI" Condition="'$(Configuration)'=='Debug'">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.UI.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UIElementsModule">
|
||||
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.UIElementsModule.dll</HintPath>
|
||||
<Reference Include="UnityEngine.UIElementsModule" Condition="'$(Configuration)'=='Debug'">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.UIElementsModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UIModule">
|
||||
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.UIModule.dll</HintPath>
|
||||
<!-- Unity 2018 build (InputModule.dll) -->
|
||||
<Reference Include="UnityEngine" Condition="'$(Configuration)'=='Release_Unity2018'">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnityEngine.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule" Condition="'$(Configuration)'=='Release_Unity2018'">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.IMGUIModule" Condition="'$(Configuration)'=='Release_Unity2018'">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnityEngine.IMGUIModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.InputModule" Condition="'$(Configuration)'=='Release_Unity2018'">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnityEngine.InputModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.PhysicsModule" Condition="'$(Configuration)'=='Release_Unity2018'">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnityEngine.PhysicsModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.TextRenderingModule" Condition="'$(Configuration)'=='Release_Unity2018'">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnityEngine.TextRenderingModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UI" Condition="'$(Configuration)'=='Release_Unity2018'">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnityEngine.UI.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UIElementsModule" Condition="'$(Configuration)'=='Release_Unity2018'">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnityEngine.UIElementsModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
@ -8,13 +8,13 @@ EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release_Unity2018|Any CPU = Release_Unity2018|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_Unity2018|Any CPU.ActiveCfg = Release_Unity2018|Any CPU
|
||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_Unity2018|Any CPU.Build.0 = Release_Unity2018|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -70,7 +70,7 @@ namespace Explorer
|
||||
{
|
||||
foreach (var holder in this.m_FieldInfos)
|
||||
{
|
||||
if (m_search == "" || holder.fieldInfo.Name.ToLower().Contains(m_search.ToLower()))
|
||||
if (forceAll || m_search == "" || holder.fieldInfo.Name.ToLower().Contains(m_search.ToLower()))
|
||||
{
|
||||
holder.UpdateValue(m_object);
|
||||
}
|
||||
@ -81,7 +81,7 @@ namespace Explorer
|
||||
{
|
||||
foreach (var holder in this.m_PropertyInfos)
|
||||
{
|
||||
if (m_search == "" || holder.propInfo.Name.ToLower().Contains(m_search.ToLower()))
|
||||
if (forceAll || m_search == "" || holder.propInfo.Name.ToLower().Contains(m_search.ToLower()))
|
||||
{
|
||||
holder.UpdateValue(m_object);
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ namespace Explorer
|
||||
var origSkin = GUI.skin;
|
||||
GUI.skin = UIStyles.WindowSkin;
|
||||
|
||||
MainRect = GUI.Window(MainWindowID, MainRect, (GUI.WindowFunction)MainWindow, "IL2CPP Runtime Explorer");
|
||||
MainRect = GUI.Window(MainWindowID, MainRect, (GUI.WindowFunction)MainWindow, CppExplorer.NAME);
|
||||
|
||||
GUI.skin = origSkin;
|
||||
}
|
||||
|
@ -1,228 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using MelonLoader;
|
||||
using UnhollowerBaseLib;
|
||||
using UnhollowerRuntimeLib;
|
||||
using Harmony;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
public class CppExplorer : MelonMod
|
||||
{
|
||||
// consts
|
||||
|
||||
public const string ID = "com.sinai.cppexplorer";
|
||||
public const string NAME = "IL2CPP Runtime Explorer (Unity 2018)";
|
||||
public const string VERSION = "1.3.2";
|
||||
public const string AUTHOR = "Sinai";
|
||||
|
||||
// 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
|
||||
|
||||
public override void OnApplicationStart()
|
||||
{
|
||||
base.OnApplicationStart();
|
||||
|
||||
Instance = this;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
// Update
|
||||
public override void OnUpdate()
|
||||
{
|
||||
if (Input.GetKeyDown(KeyCode.F7))
|
||||
{
|
||||
ShowMenu = !ShowMenu;
|
||||
}
|
||||
|
||||
if (ShowMenu)
|
||||
{
|
||||
if (!Cursor.visible)
|
||||
{
|
||||
Cursor.visible = true;
|
||||
Cursor.lockState = CursorLockMode.None;
|
||||
}
|
||||
|
||||
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 = "";
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnGUI()
|
||||
{
|
||||
base.OnGUI();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Explorer</RootNamespace>
|
||||
<AssemblyName>CppExplorer_Unity2018</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
<DebugType>none</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>..\Release\</OutputPath>
|
||||
<DefineConstants>
|
||||
</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Il2Cppmscorlib">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\VRChat\MelonLoader\Managed\Il2Cppmscorlib.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Il2CppSystem">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\VRChat\MelonLoader\Managed\Il2CppSystem.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Il2CppSystem.Core">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\VRChat\MelonLoader\Managed\Il2CppSystem.Core.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="mcs">
|
||||
<HintPath>..\lib\mcs.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="MelonLoader.ModHandler">
|
||||
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\MelonLoader.ModHandler.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="UnhollowerBaseLib">
|
||||
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnhollowerBaseLib.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnhollowerRuntimeLib">
|
||||
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnhollowerRuntimeLib.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnityEngine.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.IMGUIModule">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnityEngine.IMGUIModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.InputModule">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnityEngine.InputModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.PhysicsModule">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnityEngine.PhysicsModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.TextRenderingModule">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnityEngine.TextRenderingModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UI">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnityEngine.UI.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UIElementsModule">
|
||||
<HintPath>..\..\..\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnityEngine.UIElementsModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</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="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="MainMenu\MainMenu.cs" />
|
||||
<Compile Include="Inspectors\GameObjectWindow.cs" />
|
||||
<Compile Include="Inspectors\ReflectionWindow.cs" />
|
||||
<Compile Include="MainMenu\Pages\ScenePage.cs" />
|
||||
<Compile Include="MainMenu\Pages\SearchPage.cs" />
|
||||
<Compile Include="UIStyles.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="utils\AccessTools.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
@ -1,25 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30128.74
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CppExplorer", "CppExplorer.csproj", "{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {DD5C0A5D-03F1-4CC3-8B4D-E10834908C5A}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@ -1,448 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using MelonLoader;
|
||||
using UnhollowerRuntimeLib;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
public class GameObjectWindow : UIWindow
|
||||
{
|
||||
public override string Name { get => "GameObject Inspector"; set => Name = value; }
|
||||
|
||||
public GameObject m_object;
|
||||
|
||||
// gui element holders
|
||||
private string m_name;
|
||||
private string m_scene;
|
||||
|
||||
private Vector2 m_transformScroll = Vector2.zero;
|
||||
private Transform[] m_children;
|
||||
|
||||
private Vector2 m_compScroll = Vector2.zero;
|
||||
//private Component[] m_components;
|
||||
|
||||
private float m_translateAmount = 0.3f;
|
||||
private float m_rotateAmount = 50f;
|
||||
private float m_scaleAmount = 0.1f;
|
||||
|
||||
List<Component> m_cachedDestroyList = new List<Component>();
|
||||
//private string m_addComponentInput = "";
|
||||
|
||||
private string m_setParentInput = "";
|
||||
|
||||
public bool GetObjectAsGameObject()
|
||||
{
|
||||
if (Target == null)
|
||||
{
|
||||
MelonLogger.Log("Target is null!");
|
||||
return false;
|
||||
}
|
||||
|
||||
var targetType = Target.GetType();
|
||||
|
||||
if (targetType == typeof(GameObject))
|
||||
{
|
||||
m_object = Target as GameObject;
|
||||
return true;
|
||||
}
|
||||
else if (targetType == typeof(Transform))
|
||||
{
|
||||
m_object = (Target as Transform).gameObject;
|
||||
return true;
|
||||
}
|
||||
|
||||
MelonLogger.Log("Error: Target is null or not a GameObject/Transform!");
|
||||
DestroyWindow();
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
if (!GetObjectAsGameObject())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_name = m_object.name;
|
||||
m_scene = m_object.scene == null ? "null" : m_object.scene.name;
|
||||
|
||||
//var listComps = new Il2CppSystem.Collections.Generic.List<Component>();
|
||||
//m_object.GetComponents(listComps);
|
||||
//m_components = listComps.ToArray();
|
||||
|
||||
var list = new List<Transform>();
|
||||
for (int i = 0; i < m_object.transform.childCount; i++)
|
||||
{
|
||||
list.Add(m_object.transform.GetChild(i));
|
||||
}
|
||||
m_children = list.ToArray();
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if (!m_object && !GetObjectAsGameObject())
|
||||
{
|
||||
MelonLogger.Log("Object is null! Destroying window...");
|
||||
DestroyWindow();
|
||||
}
|
||||
}
|
||||
|
||||
private void InspectGameObject(GameObject obj)
|
||||
{
|
||||
var window = WindowManager.InspectObject(obj, out bool created);
|
||||
|
||||
if (created)
|
||||
{
|
||||
window.m_rect = new Rect(this.m_rect.x, this.m_rect.y, this.m_rect.width, this.m_rect.height);
|
||||
DestroyWindow();
|
||||
}
|
||||
}
|
||||
|
||||
private void ReflectObject(Il2CppSystem.Object obj)
|
||||
{
|
||||
var window = WindowManager.InspectObject(obj, out bool created);
|
||||
|
||||
if (created)
|
||||
{
|
||||
if (this.m_rect.x <= (Screen.width - this.m_rect.width - 100))
|
||||
{
|
||||
window.m_rect = new Rect(
|
||||
this.m_rect.x + this.m_rect.width + 20,
|
||||
this.m_rect.y,
|
||||
550,
|
||||
700);
|
||||
}
|
||||
else
|
||||
{
|
||||
window.m_rect = new Rect(this.m_rect.x + 50, this.m_rect.y + 50, 550, 700);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void WindowFunction(int windowID)
|
||||
{
|
||||
Header();
|
||||
|
||||
GUILayout.BeginArea(new Rect(5, 25, m_rect.width - 10, m_rect.height - 35), GUI.skin.box);
|
||||
|
||||
scroll = GUILayout.BeginScrollView(scroll, GUI.skin.scrollView);
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Label("Scene: <color=cyan>" + (m_scene == "" ? "n/a" : m_scene) + "</color>", null);
|
||||
if (m_scene == CppExplorer.ActiveSceneName)
|
||||
{
|
||||
if (GUILayout.Button("<color=#00FF00>< View in Scene Explorer</color>", new GUILayoutOption[] { GUILayout.Width(230) }))
|
||||
{
|
||||
ScenePage.Instance.SetTransformTarget(m_object);
|
||||
MainMenu.SetCurrentPage(0);
|
||||
}
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Label("Path:", new GUILayoutOption[] { GUILayout.Width(50) });
|
||||
string pathlabel = CppExplorer.GetGameObjectPath(m_object.transform);
|
||||
if (m_object.transform.parent != null)
|
||||
{
|
||||
if (GUILayout.Button("<-", new GUILayoutOption[] { GUILayout.Width(35) }))
|
||||
{
|
||||
InspectGameObject(m_object.transform.parent.gameObject);
|
||||
}
|
||||
}
|
||||
GUILayout.TextArea(pathlabel, null);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Label("Name:", new GUILayoutOption[] { GUILayout.Width(50) });
|
||||
GUILayout.TextArea(m_name, null);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
// --- Horizontal Columns section ---
|
||||
GUILayout.BeginHorizontal(null);
|
||||
|
||||
GUILayout.BeginVertical(new GUILayoutOption[] { GUILayout.Width(m_rect.width / 2 - 17) });
|
||||
TransformList();
|
||||
GUILayout.EndVertical();
|
||||
|
||||
GUILayout.BeginVertical(new GUILayoutOption[] { GUILayout.Width(m_rect.width / 2 - 17) });
|
||||
ComponentList();
|
||||
GUILayout.EndVertical();
|
||||
|
||||
GUILayout.EndHorizontal(); // end horiz columns
|
||||
|
||||
GameObjectControls();
|
||||
|
||||
GUILayout.EndScrollView();
|
||||
|
||||
m_rect = WindowManager.ResizeWindow(m_rect, windowID);
|
||||
|
||||
GUILayout.EndArea();
|
||||
}
|
||||
|
||||
private void TransformList()
|
||||
{
|
||||
GUILayout.BeginVertical(GUI.skin.box, new GUILayoutOption[] { GUILayout.Height(250) });
|
||||
m_transformScroll = GUILayout.BeginScrollView(m_transformScroll, GUI.skin.scrollView);
|
||||
|
||||
GUILayout.Label("<b>Children:</b>", null);
|
||||
if (m_children != null && m_children.Length > 0)
|
||||
{
|
||||
foreach (var obj in m_children.Where(x => x.childCount > 0))
|
||||
{
|
||||
if (!obj)
|
||||
{
|
||||
GUILayout.Label("null", null);
|
||||
continue;
|
||||
}
|
||||
UIStyles.GameobjButton(obj.gameObject, InspectGameObject, false, this.m_rect.width / 2 - 60);
|
||||
}
|
||||
foreach (var obj in m_children.Where(x => x.childCount == 0))
|
||||
{
|
||||
if (!obj)
|
||||
{
|
||||
GUILayout.Label("null", null);
|
||||
continue;
|
||||
}
|
||||
UIStyles.GameobjButton(obj.gameObject, InspectGameObject, false, this.m_rect.width / 2 - 60);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GUILayout.Label("<i>None</i>", null);
|
||||
}
|
||||
|
||||
GUILayout.EndScrollView();
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
|
||||
private void ComponentList()
|
||||
{
|
||||
GUILayout.BeginVertical(GUI.skin.box, new GUILayoutOption[] { GUILayout.Height(250) });
|
||||
m_compScroll = GUILayout.BeginScrollView(m_compScroll, GUI.skin.scrollView);
|
||||
GUILayout.Label("<b><size=15>Components</size></b>", null);
|
||||
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
||||
if (m_cachedDestroyList.Count > 0)
|
||||
{
|
||||
m_cachedDestroyList.Clear();
|
||||
}
|
||||
|
||||
var m_components = new Il2CppSystem.Collections.Generic.List<Component>();
|
||||
m_object.GetComponentsInternal(Il2CppType.Of<Component>(), false, false, true, false, m_components);
|
||||
|
||||
var ilTypeOfTransform = Il2CppType.Of<Transform>();
|
||||
var ilTypeOfBehaviour = Il2CppType.Of<Behaviour>();
|
||||
foreach (var component in m_components)
|
||||
{
|
||||
var ilType = component.GetIl2CppType();
|
||||
if (ilType == ilTypeOfTransform)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
if (ilTypeOfBehaviour.IsAssignableFrom(ilType))
|
||||
{
|
||||
BehaviourEnabledBtn(component.TryCast<Behaviour>());
|
||||
}
|
||||
if (GUILayout.Button("<color=cyan>" + ilType.Name + "</color>", new GUILayoutOption[] { GUILayout.Width(m_rect.width / 2 - 90) }))
|
||||
{
|
||||
ReflectObject(component);
|
||||
}
|
||||
if (GUILayout.Button("<color=red>-</color>", new GUILayoutOption[] { GUILayout.Width(20) }))
|
||||
{
|
||||
m_cachedDestroyList.Add(component);
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleCenter;
|
||||
if (m_cachedDestroyList.Count > 0)
|
||||
{
|
||||
for (int i = m_cachedDestroyList.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var comp = m_cachedDestroyList[i];
|
||||
GameObject.Destroy(comp);
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndScrollView();
|
||||
|
||||
//GUILayout.BeginHorizontal(null);
|
||||
//m_addComponentInput = GUILayout.TextField(m_addComponentInput, new GUILayoutOption[] { GUILayout.Width(m_rect.width / 2 - 150) });
|
||||
//if (GUILayout.Button("Add Component", new GUILayoutOption[] { GUILayout.Width(120) }))
|
||||
//{
|
||||
// if (HPExplorer.GetType(m_addComponentInput) is Type type && typeof(Component).IsAssignableFrom(type))
|
||||
// {
|
||||
// var comp = m_object.AddComponent(type);
|
||||
// var list = m_components.ToList();
|
||||
// list.Add(comp);
|
||||
// m_components = list.ToArray();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// MelonLogger.LogWarning($"Could not get type '{m_addComponentInput}'. If it's not a typo, try the fully qualified name.");
|
||||
// }
|
||||
//}
|
||||
//GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
private void BehaviourEnabledBtn(Behaviour obj)
|
||||
{
|
||||
var _col = GUI.color;
|
||||
bool _enabled = obj.enabled;
|
||||
if (_enabled)
|
||||
{
|
||||
GUI.color = Color.green;
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.color = Color.red;
|
||||
}
|
||||
|
||||
// ------ toggle active button ------
|
||||
|
||||
_enabled = GUILayout.Toggle(_enabled, "", new GUILayoutOption[] { GUILayout.Width(18) });
|
||||
if (obj.enabled != _enabled)
|
||||
{
|
||||
obj.enabled = _enabled;
|
||||
}
|
||||
GUI.color = _col;
|
||||
}
|
||||
|
||||
private void GameObjectControls()
|
||||
{
|
||||
GUILayout.BeginVertical(GUI.skin.box, new GUILayoutOption[] { GUILayout.Width(530) });
|
||||
GUILayout.Label("<b><size=15>GameObject Controls</size></b>", null);
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
bool m_active = m_object.activeSelf;
|
||||
m_active = GUILayout.Toggle(m_active, (m_active ? "<color=lime>Enabled " : "<color=red>Disabled") + "</color>",
|
||||
new GUILayoutOption[] { GUILayout.Width(80) });
|
||||
if (m_object.activeSelf != m_active) { m_object.SetActive(m_active); }
|
||||
|
||||
UIStyles.InstantiateButton(m_object, 100);
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
|
||||
if (GUILayout.Button("Remove from parent", new GUILayoutOption[] { GUILayout.Width(160) }))
|
||||
{
|
||||
m_object.transform.parent = null;
|
||||
}
|
||||
m_setParentInput = GUILayout.TextField(m_setParentInput, new GUILayoutOption[] { GUILayout.Width(m_rect.width - 280) });
|
||||
if (GUILayout.Button("Set Parent", new GUILayoutOption[] { GUILayout.Width(80) }))
|
||||
{
|
||||
if (GameObject.Find(m_setParentInput) is GameObject newparent)
|
||||
{
|
||||
m_object.transform.parent = newparent.transform;
|
||||
}
|
||||
else
|
||||
{
|
||||
MelonLogger.LogWarning($"Could not find gameobject '{m_setParentInput}'");
|
||||
}
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginVertical(GUI.skin.box, null);
|
||||
|
||||
var t = m_object.transform;
|
||||
TranslateControl(t, TranslateType.Position, ref m_translateAmount, false);
|
||||
TranslateControl(t, TranslateType.Rotation, ref m_rotateAmount, true);
|
||||
TranslateControl(t, TranslateType.Scale, ref m_scaleAmount, false);
|
||||
|
||||
GUILayout.EndVertical();
|
||||
|
||||
if (GUILayout.Button("<color=red><b>Destroy</b></color>", null))
|
||||
{
|
||||
GameObject.Destroy(m_object);
|
||||
DestroyWindow();
|
||||
return;
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
public enum TranslateType
|
||||
{
|
||||
Position,
|
||||
Rotation,
|
||||
Scale
|
||||
}
|
||||
|
||||
private void TranslateControl(Transform transform, TranslateType mode, ref float amount, bool multByTime)
|
||||
{
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Label("<color=cyan><b>" + mode + "</b></color>:", new GUILayoutOption[] { GUILayout.Width(65) });
|
||||
|
||||
Vector3 vector = Vector3.zero;
|
||||
switch (mode)
|
||||
{
|
||||
case TranslateType.Position: vector = transform.localPosition; break;
|
||||
case TranslateType.Rotation: vector = transform.localRotation.eulerAngles; break;
|
||||
case TranslateType.Scale: vector = transform.localScale; break;
|
||||
}
|
||||
GUILayout.Label(vector.ToString(), new GUILayoutOption[] { GUILayout.Width(250) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleRight;
|
||||
|
||||
GUILayout.Label("<color=cyan>X:</color>", new GUILayoutOption[] { GUILayout.Width(20) });
|
||||
PlusMinusFloat(ref vector.x, amount, multByTime);
|
||||
|
||||
GUILayout.Label("<color=cyan>Y:</color>", new GUILayoutOption[] { GUILayout.Width(20) });
|
||||
PlusMinusFloat(ref vector.y, amount, multByTime);
|
||||
|
||||
GUILayout.Label("<color=cyan>Z:</color>", new GUILayoutOption[] { GUILayout.Width(20) });
|
||||
PlusMinusFloat(ref vector.z, amount, multByTime);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case TranslateType.Position: transform.localPosition = vector; break;
|
||||
case TranslateType.Rotation: transform.localRotation = Quaternion.Euler(vector); break;
|
||||
case TranslateType.Scale: transform.localScale = vector; break;
|
||||
}
|
||||
|
||||
GUILayout.Label("+/-:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
var input = amount.ToString("F3");
|
||||
input = GUILayout.TextField(input, new GUILayoutOption[] { GUILayout.Width(40) });
|
||||
if (float.TryParse(input, out float f))
|
||||
{
|
||||
amount = f;
|
||||
}
|
||||
|
||||
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
private void PlusMinusFloat(ref float f, float amount, bool multByTime)
|
||||
{
|
||||
string s = f.ToString("F3");
|
||||
s = GUILayout.TextField(s, new GUILayoutOption[] { GUILayout.Width(60) });
|
||||
if (float.TryParse(s, out float f2))
|
||||
{
|
||||
f = f2;
|
||||
}
|
||||
if (GUILayout.RepeatButton("-", new GUILayoutOption[] { GUILayout.Width(20) }))
|
||||
{
|
||||
f -= multByTime ? amount * Time.deltaTime : amount;
|
||||
}
|
||||
if (GUILayout.RepeatButton("+", new GUILayoutOption[] { GUILayout.Width(20) }))
|
||||
{
|
||||
f += multByTime ? amount * Time.deltaTime : amount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MelonLoader;
|
||||
using UnhollowerBaseLib;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
public class FieldInfoHolder : MemberInfoHolder
|
||||
{
|
||||
public FieldInfo fieldInfo;
|
||||
public object m_value;
|
||||
|
||||
public FieldInfoHolder(Type _type, FieldInfo _fieldInfo)
|
||||
{
|
||||
classType = _type;
|
||||
fieldInfo = _fieldInfo;
|
||||
}
|
||||
|
||||
public override void UpdateValue(object obj)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (obj is Il2CppSystem.Object ilObject)
|
||||
{
|
||||
var declaringType = this.fieldInfo.DeclaringType;
|
||||
|
||||
var cast = CppExplorer.Il2CppCast(obj, declaringType);
|
||||
m_value = this.fieldInfo.GetValue(fieldInfo.IsStatic ? null : cast);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_value = this.fieldInfo.GetValue(fieldInfo.IsStatic ? null : obj);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MelonLogger.Log($"Error updating FieldInfoHolder | {e.GetType()}: {e.Message}\r\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public override void SetValue(object obj)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (fieldInfo.FieldType.IsEnum)
|
||||
{
|
||||
if (Enum.Parse(fieldInfo.FieldType, m_value.ToString()) is object enumValue && enumValue != null)
|
||||
{
|
||||
m_value = enumValue;
|
||||
}
|
||||
}
|
||||
else if (fieldInfo.FieldType.IsPrimitive)
|
||||
{
|
||||
if (fieldInfo.FieldType == typeof(float))
|
||||
{
|
||||
if (float.TryParse(m_value.ToString(), out float f))
|
||||
{
|
||||
m_value = f;
|
||||
}
|
||||
else
|
||||
{
|
||||
MelonLogger.LogWarning("Cannot parse " + m_value.ToString() + " to a float!");
|
||||
}
|
||||
}
|
||||
else if (fieldInfo.FieldType == typeof(double))
|
||||
{
|
||||
if (double.TryParse(m_value.ToString(), out double d))
|
||||
{
|
||||
m_value = d;
|
||||
}
|
||||
else
|
||||
{
|
||||
MelonLogger.LogWarning("Cannot parse " + m_value.ToString() + " to a double!");
|
||||
}
|
||||
}
|
||||
else if (fieldInfo.FieldType != typeof(bool))
|
||||
{
|
||||
if (int.TryParse(m_value.ToString(), out int i))
|
||||
{
|
||||
m_value = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
MelonLogger.LogWarning("Cannot parse " + m_value.ToString() + " to an integer! type: " + fieldInfo.FieldType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MelonLogger.Log("Unsupported primitive field type: " + fieldInfo.FieldType.FullName);
|
||||
}
|
||||
}
|
||||
|
||||
if (obj is Il2CppSystem.Object ilObject)
|
||||
{
|
||||
var declaringType = this.fieldInfo.DeclaringType;
|
||||
|
||||
var cast = CppExplorer.Il2CppCast(obj, declaringType);
|
||||
fieldInfo.SetValue(fieldInfo.IsStatic ? null : cast, m_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
fieldInfo.SetValue(fieldInfo.IsStatic ? null : obj, m_value);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MelonLogger.Log($"Error setting FieldInfoHolder | {e.GetType()}: {e.Message}\r\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
public abstract class MemberInfoHolder
|
||||
{
|
||||
public Type classType;
|
||||
public bool IsExpanded = false;
|
||||
public int arrayOffset = 0;
|
||||
|
||||
public abstract void Draw(ReflectionWindow window);
|
||||
public abstract void UpdateValue(object obj);
|
||||
public abstract void SetValue(object obj);
|
||||
}
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MelonLoader;
|
||||
using UnhollowerBaseLib;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
public class PropertyInfoHolder : MemberInfoHolder
|
||||
{
|
||||
public PropertyInfo propInfo;
|
||||
public object m_value;
|
||||
|
||||
public PropertyInfoHolder(Type _type, PropertyInfo _propInfo)
|
||||
{
|
||||
classType = _type;
|
||||
propInfo = _propInfo;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public override void UpdateValue(object obj)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (obj is Il2CppSystem.Object ilObject)
|
||||
{
|
||||
var declaringType = this.propInfo.DeclaringType;
|
||||
|
||||
if (declaringType == typeof(Il2CppObjectBase))
|
||||
{
|
||||
m_value = ilObject.Pointer;
|
||||
}
|
||||
else
|
||||
{
|
||||
var cast = CppExplorer.Il2CppCast(obj, declaringType);
|
||||
m_value = this.propInfo.GetValue(this.propInfo.GetAccessors()[0].IsStatic ? null : cast, null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_value = this.propInfo.GetValue(obj, null);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
m_value = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void SetValue(object obj)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (propInfo.PropertyType.IsEnum)
|
||||
{
|
||||
if (Enum.Parse(propInfo.PropertyType, m_value.ToString()) is object enumValue && enumValue != null)
|
||||
{
|
||||
m_value = enumValue;
|
||||
}
|
||||
}
|
||||
else if (propInfo.PropertyType.IsPrimitive)
|
||||
{
|
||||
if (propInfo.PropertyType == typeof(float))
|
||||
{
|
||||
if (float.TryParse(m_value.ToString(), out float f))
|
||||
{
|
||||
m_value = f;
|
||||
}
|
||||
else
|
||||
{
|
||||
MelonLogger.LogWarning("Cannot parse " + m_value.ToString() + " to a float!");
|
||||
}
|
||||
}
|
||||
else if (propInfo.PropertyType == typeof(double))
|
||||
{
|
||||
if (double.TryParse(m_value.ToString(), out double d))
|
||||
{
|
||||
m_value = d;
|
||||
}
|
||||
else
|
||||
{
|
||||
MelonLogger.LogWarning("Cannot parse " + m_value.ToString() + " to a double!");
|
||||
}
|
||||
}
|
||||
else if (propInfo.PropertyType != typeof(bool))
|
||||
{
|
||||
if (int.TryParse(m_value.ToString(), out int i))
|
||||
{
|
||||
m_value = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
MelonLogger.LogWarning("Cannot parse " + m_value.ToString() + " to an integer! type: " + propInfo.PropertyType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var declaring = propInfo.DeclaringType;
|
||||
var cast = CppExplorer.Il2CppCast(obj, declaring);
|
||||
|
||||
propInfo.SetValue(propInfo.GetAccessors()[0].IsStatic ? null : cast, m_value, null);
|
||||
}
|
||||
catch
|
||||
{
|
||||
//MelonLogger.Log("Exception trying to set property " + this.propInfo.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,357 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using MelonLoader;
|
||||
using Mono.CSharp;
|
||||
using UnhollowerBaseLib;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
public class ReflectionWindow : UIWindow
|
||||
{
|
||||
public override string Name { get => "Object Reflection"; set => Name = value; }
|
||||
|
||||
public Type m_objectType;
|
||||
public object m_object;
|
||||
|
||||
private List<FieldInfoHolder> m_FieldInfos;
|
||||
private List<PropertyInfoHolder> m_PropertyInfos;
|
||||
|
||||
private bool m_autoUpdate = false;
|
||||
private string m_search = "";
|
||||
public MemberFilter m_filter = MemberFilter.Property;
|
||||
|
||||
public enum MemberFilter
|
||||
{
|
||||
Both,
|
||||
Property,
|
||||
Field
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
m_object = Target;
|
||||
|
||||
m_FieldInfos = new List<FieldInfoHolder>();
|
||||
m_PropertyInfos = new List<PropertyInfoHolder>();
|
||||
|
||||
var type = GetActualType(m_object);
|
||||
if (type == null)
|
||||
{
|
||||
MelonLogger.Log("could not get underlying type for object. ToString(): " + m_object.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
m_objectType = type;
|
||||
GetFields(m_object);
|
||||
GetProperties(m_object);
|
||||
}
|
||||
catch { }
|
||||
|
||||
UpdateValues(true);
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if (m_autoUpdate)
|
||||
{
|
||||
UpdateValues();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateValues(bool forceAll = false)
|
||||
{
|
||||
if (forceAll || m_filter == MemberFilter.Both || m_filter == MemberFilter.Field)
|
||||
{
|
||||
foreach (var holder in this.m_FieldInfos)
|
||||
{
|
||||
if (m_search == "" || holder.fieldInfo.Name.ToLower().Contains(m_search.ToLower()))
|
||||
{
|
||||
holder.UpdateValue(m_object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (forceAll || m_filter == MemberFilter.Both || m_filter == MemberFilter.Property)
|
||||
{
|
||||
foreach (var holder in this.m_PropertyInfos)
|
||||
{
|
||||
if (m_search == "" || holder.propInfo.Name.ToLower().Contains(m_search.ToLower()))
|
||||
{
|
||||
holder.UpdateValue(m_object);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void WindowFunction(int windowID)
|
||||
{
|
||||
try
|
||||
{
|
||||
Header();
|
||||
|
||||
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);
|
||||
|
||||
bool unityObj = m_object is UnityEngine.Object;
|
||||
|
||||
if (unityObj)
|
||||
{
|
||||
GUILayout.Label("Name: " + (m_object as UnityEngine.Object).name, null);
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
if (unityObj)
|
||||
{
|
||||
GUILayout.BeginHorizontal(null);
|
||||
|
||||
GUILayout.Label("<b>Tools:</b>", new GUILayoutOption[] { GUILayout.Width(80) });
|
||||
|
||||
UIStyles.InstantiateButton((UnityEngine.Object)m_object);
|
||||
|
||||
if (m_object is Component comp && comp.gameObject is GameObject obj)
|
||||
{
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleRight;
|
||||
GUILayout.Label("GameObject:", null);
|
||||
if (GUILayout.Button("<color=#00FF00>" + obj.name + "</color>", new GUILayoutOption[] { GUILayout.MaxWidth(m_rect.width - 350) }))
|
||||
{
|
||||
WindowManager.InspectObject(obj, out bool _);
|
||||
}
|
||||
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
UIStyles.HorizontalLine(Color.grey);
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Label("<b>Search:</b>", new GUILayoutOption[] { GUILayout.Width(75) });
|
||||
m_search = GUILayout.TextField(m_search, null);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Label("<b>Filter:</b>", new GUILayoutOption[] { GUILayout.Width(75) });
|
||||
FilterToggle(MemberFilter.Both, "Both");
|
||||
FilterToggle(MemberFilter.Property, "Properties");
|
||||
FilterToggle(MemberFilter.Field, "Fields");
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Label("<b>Values:</b>", new GUILayoutOption[] { GUILayout.Width(75) });
|
||||
if (GUILayout.Button("Update", new GUILayoutOption[] { GUILayout.Width(100) }))
|
||||
{
|
||||
UpdateValues();
|
||||
}
|
||||
GUI.color = m_autoUpdate ? Color.green : Color.red;
|
||||
m_autoUpdate = GUILayout.Toggle(m_autoUpdate, "Auto-update?", new GUILayoutOption[] { GUILayout.Width(100) });
|
||||
GUI.color = Color.white;
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(10);
|
||||
|
||||
scroll = GUILayout.BeginScrollView(scroll, GUI.skin.scrollView);
|
||||
|
||||
GUILayout.Space(10);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndScrollView();
|
||||
|
||||
m_rect = WindowManager.ResizeWindow(m_rect, windowID);
|
||||
|
||||
GUILayout.EndArea();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MelonLogger.LogWarning("Exception on window draw. Message: " + e.Message);
|
||||
DestroyWindow();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void FilterToggle(MemberFilter mode, string label)
|
||||
{
|
||||
if (m_filter == mode)
|
||||
{
|
||||
GUI.color = Color.green;
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
if (GUILayout.Button(label, new GUILayoutOption[] { GUILayout.Width(100) }))
|
||||
{
|
||||
m_filter = mode;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Harmony;
|
||||
using MelonLoader;
|
||||
using UnhollowerBaseLib;
|
||||
using UnhollowerRuntimeLib;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
public abstract class UIWindow
|
||||
{
|
||||
public abstract string Name { get; set; }
|
||||
|
||||
public object Target;
|
||||
|
||||
public int windowID;
|
||||
public Rect m_rect = new Rect(0, 0, 550, 700);
|
||||
|
||||
public Vector2 scroll = Vector2.zero;
|
||||
|
||||
public static UIWindow CreateWindow<T>(object target) where T : UIWindow
|
||||
{
|
||||
//var component = (UIWindow)AddToGameObject<T>(Instance.gameObject);
|
||||
var window = Activator.CreateInstance<T>();
|
||||
|
||||
window.Target = target;
|
||||
window.windowID = WindowManager.NextWindowID();
|
||||
window.m_rect = WindowManager.GetNewWindowRect();
|
||||
|
||||
WindowManager.Windows.Add(window);
|
||||
|
||||
window.Init();
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
public void DestroyWindow()
|
||||
{
|
||||
try
|
||||
{
|
||||
WindowManager.Windows.Remove(this);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MelonLogger.Log("Exception removing Window from WindowManager.Windows list!");
|
||||
MelonLogger.Log($"{e.GetType()} : {e.Message}\r\n{e.StackTrace}");
|
||||
}
|
||||
//Destroy(this);
|
||||
}
|
||||
|
||||
public abstract void Init();
|
||||
public abstract void WindowFunction(int windowID);
|
||||
public abstract void Update();
|
||||
|
||||
public void OnGUI()
|
||||
{
|
||||
if (CppExplorer.ShowMenu)
|
||||
{
|
||||
var origSkin = GUI.skin;
|
||||
|
||||
GUI.skin = UIStyles.WindowSkin;
|
||||
m_rect = GUI.Window(windowID, m_rect, (GUI.WindowFunction)WindowFunction, Name);
|
||||
|
||||
GUI.skin = origSkin;
|
||||
}
|
||||
}
|
||||
|
||||
public void Header()
|
||||
{
|
||||
GUI.DragWindow(new Rect(0, 0, m_rect.width - 90, 20));
|
||||
|
||||
if (GUI.Button(new Rect(m_rect.width - 90, 2, 80, 20), "<color=red><b>X</b></color>"))
|
||||
{
|
||||
DestroyWindow();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.EventSystems;
|
||||
using MelonLoader;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
public class MainMenu
|
||||
{
|
||||
public static MainMenu Instance;
|
||||
|
||||
public MainMenu()
|
||||
{
|
||||
Instance = this;
|
||||
|
||||
Pages.Add(new ScenePage());
|
||||
Pages.Add(new SearchPage());
|
||||
Pages.Add(new ConsolePage());
|
||||
|
||||
foreach (var page in Pages)
|
||||
{
|
||||
page.Init();
|
||||
}
|
||||
}
|
||||
|
||||
public const int MainWindowID = 10;
|
||||
public static Rect MainRect = new Rect(5, 5, 550, 700);
|
||||
private static readonly List<WindowPage> Pages = new List<WindowPage>();
|
||||
private static int m_currentPage = 0;
|
||||
|
||||
public static void SetCurrentPage(int index)
|
||||
{
|
||||
if (index < 0 || Pages.Count <= index)
|
||||
{
|
||||
MelonLogger.Log("cannot set page " + index);
|
||||
return;
|
||||
}
|
||||
m_currentPage = index;
|
||||
GUI.BringWindowToFront(MainWindowID);
|
||||
GUI.FocusWindow(MainWindowID);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
Pages[m_currentPage].Update();
|
||||
}
|
||||
|
||||
public void OnGUI()
|
||||
{
|
||||
if (CppExplorer.ShowMenu)
|
||||
{
|
||||
var origSkin = GUI.skin;
|
||||
GUI.skin = UIStyles.WindowSkin;
|
||||
|
||||
MainRect = GUI.Window(MainWindowID, MainRect, (GUI.WindowFunction)MainWindow, "IL2CPP Runtime Explorer");
|
||||
|
||||
GUI.skin = origSkin;
|
||||
}
|
||||
}
|
||||
|
||||
private void MainWindow(int id)
|
||||
{
|
||||
GUI.DragWindow(new Rect(0, 0, MainRect.width - 90, 20));
|
||||
|
||||
if (GUI.Button(new Rect(MainRect.width - 90, 2, 80, 20), "Hide (F7)"))
|
||||
{
|
||||
CppExplorer.ShowMenu = false;
|
||||
return;
|
||||
}
|
||||
|
||||
GUILayout.BeginArea(new Rect(5, 25, MainRect.width - 10, MainRect.height - 35), GUI.skin.box);
|
||||
|
||||
MainHeader();
|
||||
|
||||
var page = Pages[m_currentPage];
|
||||
page.scroll = GUILayout.BeginScrollView(page.scroll, GUI.skin.scrollView);
|
||||
page.DrawWindow();
|
||||
GUILayout.EndScrollView();
|
||||
|
||||
MainRect = WindowManager.ResizeWindow(MainRect, MainWindowID);
|
||||
|
||||
GUILayout.EndArea();
|
||||
}
|
||||
|
||||
private void MainHeader()
|
||||
{
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Label("<b>Options:</b>", new GUILayoutOption[] { GUILayout.Width(70) });
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleRight;
|
||||
GUILayout.Label("Array Limit:", new GUILayoutOption[] { GUILayout.Width(70) });
|
||||
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||
var _input = GUILayout.TextField(CppExplorer.ArrayLimit.ToString(), new GUILayoutOption[] { GUILayout.Width(60) });
|
||||
if (int.TryParse(_input, out int _lim))
|
||||
{
|
||||
CppExplorer.ArrayLimit = _lim;
|
||||
}
|
||||
CppExplorer.Instance.MouseInspect = GUILayout.Toggle(CppExplorer.Instance.MouseInspect, "Inspect Under Mouse (Shift + RMB)", null);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
for (int i = 0; i < Pages.Count; i++)
|
||||
{
|
||||
if (m_currentPage == i)
|
||||
GUI.color = Color.green;
|
||||
else
|
||||
GUI.color = Color.white;
|
||||
|
||||
if (GUILayout.Button(Pages[i].Name, null))
|
||||
{
|
||||
m_currentPage = i;
|
||||
}
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(10);
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,131 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Mono.CSharp;
|
||||
using UnityEngine;
|
||||
using Attribute = System.Attribute;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
public class REPL : InteractiveBase
|
||||
{
|
||||
static REPL()
|
||||
{
|
||||
var go = new GameObject("UnityREPL");
|
||||
GameObject.DontDestroyOnLoad(go);
|
||||
//go.transform.parent = HPExplorer.Instance.transform;
|
||||
MB = go.AddComponent<ReplHelper>();
|
||||
}
|
||||
|
||||
[Documentation("MB - A dummy MonoBehaviour for accessing Unity.")]
|
||||
public static ReplHelper MB { get; }
|
||||
|
||||
[Documentation("find<T>() - find a UnityEngine.Object of type T.")]
|
||||
public static T find<T>() where T : Object
|
||||
{
|
||||
return MB.Find<T>();
|
||||
}
|
||||
|
||||
[Documentation("findAll<T>() - find all UnityEngine.Object of type T.")]
|
||||
public static T[] findAll<T>() where T : Object
|
||||
{
|
||||
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("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>()
|
||||
////{
|
||||
//// return new TypeHelper(typeof(T));
|
||||
////}
|
||||
|
||||
////[Documentation("type(obj) - obtain type info about object obj. Provides some Reflection helpers.")]
|
||||
////public static TypeHelper type(object instance)
|
||||
////{
|
||||
//// return new TypeHelper(instance);
|
||||
////}
|
||||
|
||||
//[Documentation("dir(obj) - lists all available methods and fiels of a given obj.")]
|
||||
//public static string dir(object instance)
|
||||
//{
|
||||
// return type(instance).info();
|
||||
//}
|
||||
|
||||
//[Documentation("dir<T>() - lists all available methods and fields of type T.")]
|
||||
//public static string dir<T>()
|
||||
//{
|
||||
// return type<T>().info();
|
||||
//}
|
||||
|
||||
//[Documentation("findrefs(obj) - find references to the object in currently loaded components.")]
|
||||
//public static Component[] findrefs(object obj)
|
||||
//{
|
||||
// if (obj == null) throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
// var results = new List<Component>();
|
||||
// foreach (var component in Object.FindObjectsOfType<Component>())
|
||||
// {
|
||||
// var type = component.GetType();
|
||||
|
||||
// var nameBlacklist = new[] { "parent", "parentInternal", "root", "transform", "gameObject" };
|
||||
// var typeBlacklist = new[] { typeof(bool) };
|
||||
|
||||
// foreach (var prop in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
// .Where(x => x.CanRead && !nameBlacklist.Contains(x.Name) && !typeBlacklist.Contains(x.PropertyType)))
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// if (Equals(prop.GetValue(component, null), obj))
|
||||
// {
|
||||
// results.Add(component);
|
||||
// goto finish;
|
||||
// }
|
||||
// }
|
||||
// catch { }
|
||||
// }
|
||||
// foreach (var field in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
// .Where(x => !nameBlacklist.Contains(x.Name) && !typeBlacklist.Contains(x.FieldType)))
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// if (Equals(field.GetValue(component), obj))
|
||||
// {
|
||||
// results.Add(component);
|
||||
// goto finish;
|
||||
// }
|
||||
// }
|
||||
// catch { }
|
||||
// }
|
||||
// finish:;
|
||||
// }
|
||||
|
||||
// return results.ToArray();
|
||||
//}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property)]
|
||||
private class DocumentationAttribute : Attribute
|
||||
{
|
||||
public DocumentationAttribute(string doc)
|
||||
{
|
||||
Docs = doc;
|
||||
}
|
||||
|
||||
public string Docs { get; }
|
||||
}
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
using System.Collections;
|
||||
//using Il2CppSystem;
|
||||
using MelonLoader;
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
public class ReplHelper : MonoBehaviour
|
||||
{
|
||||
public ReplHelper(IntPtr intPtr) : base(intPtr) { }
|
||||
|
||||
public T Find<T>() where T : Object
|
||||
{
|
||||
return FindObjectOfType<T>();
|
||||
}
|
||||
|
||||
public T[] FindAll<T>() where T : Object
|
||||
{
|
||||
return FindObjectsOfType<T>();
|
||||
}
|
||||
|
||||
//public object RunCoroutine(IEnumerator enumerator)
|
||||
//{
|
||||
// return MelonCoroutines.Start(enumerator);
|
||||
//}
|
||||
|
||||
//public void EndCoroutine(Coroutine c)
|
||||
//{
|
||||
// StopCoroutine(c);
|
||||
//}
|
||||
}
|
||||
}
|
@ -1,227 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using System.Reflection;
|
||||
using Mono.CSharp;
|
||||
using System.IO;
|
||||
using MelonLoader;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
public class ConsolePage : WindowPage
|
||||
{
|
||||
public override string Name { get => "C# Console"; set => base.Name = value; }
|
||||
|
||||
private ScriptEvaluator _evaluator;
|
||||
private readonly StringBuilder _sb = new StringBuilder();
|
||||
|
||||
private string MethodInput = "";
|
||||
private string UsingInput = "";
|
||||
|
||||
public static List<string> UsingDirectives;
|
||||
|
||||
private static readonly string[] m_defaultUsing = new string[]
|
||||
{
|
||||
"System",
|
||||
"UnityEngine",
|
||||
"System.Linq",
|
||||
"System.Collections",
|
||||
"System.Collections.Generic",
|
||||
"System.Reflection",
|
||||
"MelonLoader"
|
||||
};
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
UnhollowerRuntimeLib.ClassInjector.RegisterTypeInIl2Cpp<ReplHelper>();
|
||||
|
||||
try
|
||||
{
|
||||
MethodInput = @"// This is a basic C# REPL console.
|
||||
// Some common using directives are added by default, you can add more below.
|
||||
// If you want to return some output, MelonLogger.Log() it.
|
||||
|
||||
MelonLogger.Log(""hello world"");";
|
||||
|
||||
ResetConsole();
|
||||
|
||||
foreach (var use in m_defaultUsing)
|
||||
{
|
||||
AddUsing(use);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MelonLogger.Log($"Error setting up console!\r\nMessage: {e.Message}\r\nStack: {e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetConsole()
|
||||
{
|
||||
if (_evaluator != null)
|
||||
{
|
||||
_evaluator.Dispose();
|
||||
}
|
||||
|
||||
_evaluator = new ScriptEvaluator(new StringWriter(_sb)) { InteractiveBaseClass = typeof(REPL) };
|
||||
|
||||
UsingDirectives = new List<string>();
|
||||
}
|
||||
|
||||
public string AsmToUsing(string asm, bool richtext = false)
|
||||
{
|
||||
if (richtext)
|
||||
{
|
||||
return $"<color=#569cd6>using</color> {asm};";
|
||||
}
|
||||
return $"using {asm};";
|
||||
}
|
||||
|
||||
public void AddUsing(string asm)
|
||||
{
|
||||
if (!UsingDirectives.Contains(asm))
|
||||
{
|
||||
UsingDirectives.Add(asm);
|
||||
Evaluate(AsmToUsing(asm));
|
||||
}
|
||||
}
|
||||
|
||||
public object Evaluate(string str)
|
||||
{
|
||||
object ret = VoidType.Value;
|
||||
|
||||
_evaluator.Compile(str, out var compiled);
|
||||
|
||||
try
|
||||
{
|
||||
compiled?.Invoke(ref ret);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MelonLogger.LogWarning(e.ToString());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
public override void DrawWindow()
|
||||
{
|
||||
GUILayout.Label("<b><size=15><color=cyan>C# REPL Console</color></size></b>", null);
|
||||
|
||||
GUILayout.Label("Method:", null);
|
||||
MethodInput = GUILayout.TextArea(MethodInput, new GUILayoutOption[] { GUILayout.Height(300) });
|
||||
|
||||
if (GUILayout.Button("<color=cyan><b>Execute</b></color>", null))
|
||||
{
|
||||
try
|
||||
{
|
||||
MethodInput = MethodInput.Trim();
|
||||
|
||||
if (!string.IsNullOrEmpty(MethodInput))
|
||||
{
|
||||
var result = Evaluate(MethodInput);
|
||||
|
||||
if (result != null && !Equals(result, VoidType.Value))
|
||||
{
|
||||
MelonLogger.Log("[Console Output]\r\n" + result.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MelonLogger.LogError("Exception compiling!\r\nMessage: " + e.Message + "\r\nStack: " + e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.Label("<b>Using directives:</b>", null);
|
||||
foreach (var asm in UsingDirectives)
|
||||
{
|
||||
GUILayout.Label(AsmToUsing(asm, true), null);
|
||||
}
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Label("Add namespace:", new GUILayoutOption[] { GUILayout.Width(110) });
|
||||
UsingInput = GUILayout.TextField(UsingInput, new GUILayoutOption[] { GUILayout.Width(150) });
|
||||
if (GUILayout.Button("Add", new GUILayoutOption[] { GUILayout.Width(50) }))
|
||||
{
|
||||
AddUsing(UsingInput);
|
||||
}
|
||||
if (GUILayout.Button("<color=red>Reset</color>", null))
|
||||
{
|
||||
ResetConsole();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public override void Update() { }
|
||||
|
||||
private class VoidType
|
||||
{
|
||||
public static readonly VoidType Value = new VoidType();
|
||||
private VoidType() { }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal class ScriptEvaluator : Evaluator, IDisposable
|
||||
{
|
||||
private static readonly HashSet<string> StdLib =
|
||||
new HashSet<string>(StringComparer.InvariantCultureIgnoreCase) { "mscorlib", "System.Core", "System", "System.Xml" };
|
||||
|
||||
private readonly TextWriter _logger;
|
||||
|
||||
public ScriptEvaluator(TextWriter logger) : base(BuildContext(logger))
|
||||
{
|
||||
_logger = logger;
|
||||
|
||||
ImportAppdomainAssemblies(ReferenceAssembly);
|
||||
AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoad;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
AppDomain.CurrentDomain.AssemblyLoad -= OnAssemblyLoad;
|
||||
_logger.Dispose();
|
||||
}
|
||||
|
||||
private void OnAssemblyLoad(object sender, AssemblyLoadEventArgs args)
|
||||
{
|
||||
string name = args.LoadedAssembly.GetName().Name;
|
||||
if (StdLib.Contains(name))
|
||||
return;
|
||||
ReferenceAssembly(args.LoadedAssembly);
|
||||
}
|
||||
|
||||
private static CompilerContext BuildContext(TextWriter tw)
|
||||
{
|
||||
var reporter = new StreamReportPrinter(tw);
|
||||
|
||||
var settings = new CompilerSettings
|
||||
{
|
||||
Version = LanguageVersion.Experimental,
|
||||
GenerateDebugInfo = false,
|
||||
StdLib = true,
|
||||
Target = Target.Library,
|
||||
WarningLevel = 0,
|
||||
EnhancedWarnings = false
|
||||
};
|
||||
|
||||
return new CompilerContext(settings, reporter);
|
||||
}
|
||||
|
||||
private static void ImportAppdomainAssemblies(Action<Assembly> import)
|
||||
{
|
||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
string name = assembly.GetName().Name;
|
||||
if (StdLib.Contains(name))
|
||||
continue;
|
||||
import(assembly);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,297 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using MelonLoader;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
public class ScenePage : WindowPage
|
||||
{
|
||||
public static ScenePage Instance;
|
||||
|
||||
public override string Name { get => "Scene Explorer"; set => base.Name = value; }
|
||||
|
||||
// ----- Holders for GUI elements ----- //
|
||||
|
||||
private string m_currentScene = "";
|
||||
|
||||
// gameobject list
|
||||
private Transform m_currentTransform;
|
||||
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<GameObjectCache> m_searchResults = new List<GameObjectCache>();
|
||||
|
||||
// ------------ Init and Update ------------ //
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
public void OnSceneChange()
|
||||
{
|
||||
m_currentScene = CppExplorer.ActiveSceneName;
|
||||
|
||||
m_currentTransform = null;
|
||||
CancelSearch();
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if (Time.time - m_timeOfLastUpdate < 0.2f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_timeOfLastUpdate = Time.time;
|
||||
|
||||
var start = Time.realtimeSinceStartup;
|
||||
|
||||
if (!m_searching)
|
||||
{
|
||||
m_objectList = new List<GameObjectCache>();
|
||||
if (m_currentTransform)
|
||||
{
|
||||
var endAppend = new List<GameObjectCache>();
|
||||
for (int i = 0; i < m_currentTransform.childCount; i++)
|
||||
{
|
||||
var child = m_currentTransform.GetChild(i);
|
||||
|
||||
if (child)
|
||||
{
|
||||
if (child.childCount > 0)
|
||||
m_objectList.Add(new GameObjectCache(child.gameObject));
|
||||
else
|
||||
endAppend.Add(new GameObjectCache(child.gameObject));
|
||||
}
|
||||
}
|
||||
m_objectList.AddRange(endAppend);
|
||||
endAppend = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var scene = SceneManager.GetSceneByName(m_currentScene);
|
||||
var rootObjects = scene.GetRootGameObjects();
|
||||
|
||||
// add objects with children first
|
||||
foreach (var obj in rootObjects.Where(x => x.transform.childCount > 0))
|
||||
{
|
||||
m_objectList.Add(new GameObjectCache(obj));
|
||||
}
|
||||
foreach (var obj in rootObjects.Where(x => x.transform.childCount == 0))
|
||||
{
|
||||
m_objectList.Add(new GameObjectCache(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------- GUI Draw Functions --------- //
|
||||
|
||||
public override void DrawWindow()
|
||||
{
|
||||
try
|
||||
{
|
||||
GUILayout.BeginHorizontal(null);
|
||||
// Current Scene label
|
||||
GUILayout.Label("Current Scene:", new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
if (SceneManager.sceneCount > 1)
|
||||
{
|
||||
int changeWanted = 0;
|
||||
if (GUILayout.Button("<", new GUILayoutOption[] { GUILayout.Width(30) }))
|
||||
{
|
||||
changeWanted = -1;
|
||||
}
|
||||
if (GUILayout.Button(">", new GUILayoutOption[] { GUILayout.Width(30) }))
|
||||
{
|
||||
changeWanted = 1;
|
||||
}
|
||||
if (changeWanted != 0)
|
||||
{
|
||||
var scenes = SceneManager.GetAllScenes();
|
||||
int index = scenes.IndexOf(SceneManager.GetSceneByName(m_currentScene));
|
||||
index += changeWanted;
|
||||
if (index >= scenes.Count - 1)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
else if (index > 0)
|
||||
{
|
||||
index = scenes.Count - 1;
|
||||
}
|
||||
m_currentScene = scenes[index].name;
|
||||
}
|
||||
}
|
||||
GUILayout.Label("<color=cyan>" + m_currentScene + "</color>", null); //new GUILayoutOption[] { GUILayout.Width(250) });
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
// ----- GameObject Search -----
|
||||
GUILayout.BeginHorizontal(GUI.skin.box, null);
|
||||
GUILayout.Label("<b>Search Scene:</b>", new GUILayoutOption[] { GUILayout.Width(100) });
|
||||
m_searchInput = GUILayout.TextField(m_searchInput, null);
|
||||
if (GUILayout.Button("Search", new GUILayoutOption[] { GUILayout.Width(80) }))
|
||||
{
|
||||
Search();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(15);
|
||||
|
||||
// ************** GameObject list ***************
|
||||
|
||||
// ----- main explorer ------
|
||||
if (!m_searching)
|
||||
{
|
||||
if (m_currentTransform != null)
|
||||
{
|
||||
GUILayout.BeginHorizontal(null);
|
||||
if (GUILayout.Button("<-", new GUILayoutOption[] { GUILayout.Width(35) }))
|
||||
{
|
||||
TraverseUp();
|
||||
}
|
||||
else
|
||||
{
|
||||
GUILayout.Label(CppExplorer.GetGameObjectPath(m_currentTransform), null);
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
else
|
||||
{
|
||||
GUILayout.Label("Scene Root GameObjects:", null);
|
||||
}
|
||||
|
||||
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.FastGameobjButton(obj.RefGameObject, obj.EnabledColor, obj.Label, obj.RefGameObject.activeSelf, SetTransformTarget, true, MainMenu.MainRect.width - 170);
|
||||
}
|
||||
var diff = Time.realtimeSinceStartup - start;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if m_currentTransform != null ...
|
||||
}
|
||||
}
|
||||
else // ------ Scene Search results ------
|
||||
{
|
||||
if (GUILayout.Button("<-", new GUILayoutOption[] { GUILayout.Width(35) }))
|
||||
{
|
||||
CancelSearch();
|
||||
}
|
||||
|
||||
GUILayout.Label("Search Results:", null);
|
||||
|
||||
if (m_searchResults.Count > 0)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GUILayout.Label("<color=red><i>No results found!</i></color>", null);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
m_currentTransform = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// -------- Actual Methods (not drawing GUI) ---------- //
|
||||
|
||||
public void SetTransformTarget(GameObject obj)
|
||||
{
|
||||
m_currentTransform = obj.transform;
|
||||
CancelSearch();
|
||||
}
|
||||
|
||||
public void TraverseUp()
|
||||
{
|
||||
if (m_currentTransform.parent != null)
|
||||
{
|
||||
m_currentTransform = m_currentTransform.parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_currentTransform = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Search()
|
||||
{
|
||||
m_searchResults = SearchSceneObjects(m_searchInput);
|
||||
m_searching = true;
|
||||
}
|
||||
|
||||
public void CancelSearch()
|
||||
{
|
||||
m_searching = false;
|
||||
}
|
||||
|
||||
public List<GameObjectCache> SearchSceneObjects(string _search)
|
||||
{
|
||||
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(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,399 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using System.Reflection;
|
||||
using UnityEngine.SceneManagement;
|
||||
using Object = UnityEngine.Object;
|
||||
using UnhollowerRuntimeLib;
|
||||
using MelonLoader;
|
||||
using UnhollowerBaseLib;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
public class SearchPage : WindowPage
|
||||
{
|
||||
public static SearchPage Instance;
|
||||
|
||||
public override string Name { get => "Object Search"; set => base.Name = value; }
|
||||
|
||||
private string m_searchInput = "";
|
||||
private string m_typeInput = "";
|
||||
private int m_limit = 20;
|
||||
private int m_pageOffset = 0;
|
||||
private List<object> m_searchResults = new List<object>();
|
||||
private Vector2 resultsScroll = Vector2.zero;
|
||||
|
||||
public SceneFilter SceneMode = SceneFilter.Any;
|
||||
public TypeFilter TypeMode = TypeFilter.Object;
|
||||
|
||||
public enum SceneFilter
|
||||
{
|
||||
Any,
|
||||
This,
|
||||
DontDestroy,
|
||||
None
|
||||
}
|
||||
|
||||
public enum TypeFilter
|
||||
{
|
||||
Object,
|
||||
GameObject,
|
||||
Component,
|
||||
Custom
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
public void OnSceneChange()
|
||||
{
|
||||
m_searchResults.Clear();
|
||||
m_pageOffset = 0;
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
}
|
||||
|
||||
public override void DrawWindow()
|
||||
{
|
||||
try
|
||||
{
|
||||
// helpers
|
||||
GUILayout.BeginHorizontal(GUI.skin.box, null);
|
||||
GUILayout.Label("<b><color=orange>Helpers</color></b>", new GUILayoutOption[] { GUILayout.Width(70) });
|
||||
if (GUILayout.Button("Find Static Instances", new GUILayoutOption[] { GUILayout.Width(180) }))
|
||||
{
|
||||
m_searchResults = GetInstanceClassScanner().ToList();
|
||||
m_pageOffset = 0;
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
// search box
|
||||
SearchBox();
|
||||
|
||||
// results
|
||||
GUILayout.BeginVertical(GUI.skin.box, null);
|
||||
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
|
||||
GUILayout.Label("<b><color=orange>Results </color></b>" + " (" + m_searchResults.Count + ")", null);
|
||||
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||
|
||||
int count = m_searchResults.Count;
|
||||
|
||||
if (count > this.m_limit)
|
||||
{
|
||||
// prev/next page buttons
|
||||
GUILayout.BeginHorizontal(null);
|
||||
int maxOffset = (int)Mathf.Ceil(count / this.m_limit);
|
||||
if (GUILayout.Button("< Prev", null))
|
||||
{
|
||||
if (m_pageOffset > 0) m_pageOffset--;
|
||||
}
|
||||
|
||||
GUILayout.Label($"Page {m_pageOffset + 1}/{maxOffset + 1}", new GUILayoutOption[] { GUILayout.Width(80) });
|
||||
|
||||
if (GUILayout.Button("Next >", null))
|
||||
{
|
||||
if (m_pageOffset < maxOffset) m_pageOffset++;
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
resultsScroll = GUILayout.BeginScrollView(resultsScroll, GUI.skin.scrollView);
|
||||
|
||||
var _temprect = new Rect(MainMenu.MainRect.x, MainMenu.MainRect.y, MainMenu.MainRect.width + 160, MainMenu.MainRect.height);
|
||||
|
||||
if (m_searchResults.Count > 0)
|
||||
{
|
||||
int offset = m_pageOffset * this.m_limit;
|
||||
int preiterated = 0;
|
||||
|
||||
if (offset >= count) m_pageOffset = 0;
|
||||
|
||||
for (int i = 0; i < m_searchResults.Count; i++)
|
||||
{
|
||||
if (offset > 0 && preiterated < offset)
|
||||
{
|
||||
preiterated++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i - offset > this.m_limit - 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var obj = m_searchResults[i];
|
||||
|
||||
bool _ = false;
|
||||
int __ = 0;
|
||||
UIStyles.DrawValue(ref obj, ref _, ref __, _temprect);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GUILayout.Label("<color=red><i>No results found!</i></color>", null);
|
||||
}
|
||||
|
||||
GUILayout.EndScrollView();
|
||||
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
catch
|
||||
{
|
||||
m_searchResults.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void SearchBox()
|
||||
{
|
||||
GUILayout.BeginVertical(GUI.skin.box, null);
|
||||
|
||||
// ----- GameObject Search -----
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
|
||||
GUILayout.Label("<b><color=orange>Search</color></b>", null);
|
||||
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
|
||||
GUILayout.Label("Name Contains:", new GUILayoutOption[] { GUILayout.Width(100) });
|
||||
m_searchInput = GUILayout.TextField(m_searchInput, new GUILayoutOption[] { GUILayout.Width(200) });
|
||||
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleRight;
|
||||
GUILayout.Label("Results per page:", new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
var resultinput = m_limit.ToString();
|
||||
resultinput = GUILayout.TextField(resultinput, new GUILayoutOption[] { GUILayout.Width(55) });
|
||||
if (int.TryParse(resultinput, out int _i) && _i > 0)
|
||||
{
|
||||
m_limit = _i;
|
||||
}
|
||||
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
|
||||
GUILayout.Label("Class Filter:", new GUILayoutOption[] { GUILayout.Width(100) });
|
||||
ClassFilterToggle(TypeFilter.Object, "Object");
|
||||
ClassFilterToggle(TypeFilter.GameObject, "GameObject");
|
||||
ClassFilterToggle(TypeFilter.Component, "Component");
|
||||
ClassFilterToggle(TypeFilter.Custom, "Custom");
|
||||
GUILayout.EndHorizontal();
|
||||
if (TypeMode == TypeFilter.Custom)
|
||||
{
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleRight;
|
||||
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) });
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
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);
|
||||
SceneFilterToggle(SceneFilter.None, "No Scene", 80);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
if (GUILayout.Button("<b><color=cyan>Search</color></b>", null))
|
||||
{
|
||||
Search();
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
private void ClassFilterToggle(TypeFilter mode, string label)
|
||||
{
|
||||
if (TypeMode == mode)
|
||||
{
|
||||
GUI.color = Color.green;
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
if (GUILayout.Button(label, new GUILayoutOption[] { GUILayout.Width(100) }))
|
||||
{
|
||||
TypeMode = mode;
|
||||
}
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
|
||||
private void SceneFilterToggle(SceneFilter mode, string label, float width)
|
||||
{
|
||||
if (SceneMode == mode)
|
||||
{
|
||||
GUI.color = Color.green;
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
if (GUILayout.Button(label, new GUILayoutOption[] { GUILayout.Width(width) }))
|
||||
{
|
||||
SceneMode = mode;
|
||||
}
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
|
||||
|
||||
// -------------- ACTUAL METHODS (not Gui draw) ----------------- //
|
||||
|
||||
// ======= search functions =======
|
||||
|
||||
private void Search()
|
||||
{
|
||||
m_pageOffset = 0;
|
||||
m_searchResults = FindAllObjectsOfType(m_searchInput, m_typeInput);
|
||||
}
|
||||
|
||||
private List<object> FindAllObjectsOfType(string _search, string _type)
|
||||
{
|
||||
Il2CppSystem.Type searchType = null;
|
||||
|
||||
if (TypeMode == TypeFilter.Custom)
|
||||
{
|
||||
try
|
||||
{
|
||||
var findType = CppExplorer.GetType(_type);
|
||||
searchType = Il2CppSystem.Type.GetType(findType.AssemblyQualifiedName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MelonLogger.Log("Exception: " + e.GetType() + ", " + e.Message + "\r\n" + e.StackTrace);
|
||||
}
|
||||
}
|
||||
else if (TypeMode == TypeFilter.Object)
|
||||
{
|
||||
searchType = CppExplorer.ObjectType;
|
||||
}
|
||||
else if (TypeMode == TypeFilter.GameObject)
|
||||
{
|
||||
searchType = CppExplorer.GameObjectType;
|
||||
}
|
||||
else if (TypeMode == TypeFilter.Component)
|
||||
{
|
||||
searchType = CppExplorer.ComponentType;
|
||||
}
|
||||
|
||||
if (!CppExplorer.ObjectType.IsAssignableFrom(searchType))
|
||||
{
|
||||
MelonLogger.LogError("Your Custom Class Type must inherit from UnityEngine.Object!");
|
||||
return new List<object>();
|
||||
}
|
||||
|
||||
var matches = new List<object>();
|
||||
|
||||
var allObjectsOfType = Resources.FindObjectsOfTypeAll(searchType);
|
||||
|
||||
foreach (var obj in allObjectsOfType)
|
||||
{
|
||||
if (_search != "" && !obj.name.ToLower().Contains(_search.ToLower()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (searchType == CppExplorer.ComponentType && CppExplorer.TransformType.IsAssignableFrom(obj.GetIl2CppType()))
|
||||
{
|
||||
// Transforms shouldn't really be counted as Components, skip them.
|
||||
// They're more akin to GameObjects.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (SceneMode != SceneFilter.Any && !FilterScene(obj, this.SceneMode))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!matches.Contains(obj))
|
||||
{
|
||||
matches.Add(obj);
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
public static bool FilterScene(object obj, SceneFilter filter)
|
||||
{
|
||||
GameObject go;
|
||||
if (obj is Il2CppSystem.Object ilObject)
|
||||
{
|
||||
go = ilObject.TryCast<GameObject>() ?? ilObject.TryCast<Component>().gameObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
go = (obj as GameObject) ?? (obj as Component).gameObject;
|
||||
}
|
||||
|
||||
if (!go)
|
||||
{
|
||||
// object is not on a GameObject, cannot perform scene filter operation.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (filter == SceneFilter.None)
|
||||
{
|
||||
return string.IsNullOrEmpty(go.scene.name);
|
||||
}
|
||||
else if (filter == SceneFilter.This)
|
||||
{
|
||||
return go.scene.name == CppExplorer.ActiveSceneName;
|
||||
}
|
||||
else if (filter == SceneFilter.DontDestroy)
|
||||
{
|
||||
return go.scene.name == "DontDestroyOnLoad";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ====== other ========
|
||||
|
||||
// credit: ManlyMarco (RuntimeUnityEditor)
|
||||
public static IEnumerable<object> GetInstanceClassScanner()
|
||||
{
|
||||
var query = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.Where(x => !x.FullName.StartsWith("Mono"))
|
||||
.SelectMany(GetTypesSafe)
|
||||
.Where(t => t.IsClass && !t.IsAbstract && !t.ContainsGenericParameters);
|
||||
|
||||
foreach (var type in query)
|
||||
{
|
||||
object obj = null;
|
||||
try
|
||||
{
|
||||
obj = type.GetProperty("Instance", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)?.GetValue(null, null);
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
obj = type.GetField("Instance", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)?.GetValue(null);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
if (obj != null && !obj.ToString().StartsWith("Mono"))
|
||||
{
|
||||
yield return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Type> GetTypesSafe(Assembly asm)
|
||||
{
|
||||
try { return asm.GetTypes(); }
|
||||
catch (ReflectionTypeLoadException e) { return e.Types.Where(x => x != null); }
|
||||
catch { return Enumerable.Empty<Type>(); }
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
public abstract class WindowPage
|
||||
{
|
||||
public virtual string Name { get; set; }
|
||||
|
||||
public Vector2 scroll = Vector2.zero;
|
||||
|
||||
public abstract void Init();
|
||||
|
||||
public abstract void DrawWindow();
|
||||
|
||||
public abstract void Update();
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Explorer;
|
||||
using MelonLoader;
|
||||
|
||||
[assembly: MelonInfo(typeof(CppExplorer), CppExplorer.NAME, CppExplorer.VERSION, CppExplorer.AUTHOR)]
|
||||
[assembly: MelonGame(null, null)]
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle(CppExplorer.NAME)]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany(CppExplorer.AUTHOR)]
|
||||
[assembly: AssemblyProduct(CppExplorer.NAME)]
|
||||
[assembly: AssemblyCopyright("")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("b21dbde3-5d6f-4726-93ab-cc3cc68bae7d")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
@ -1,505 +0,0 @@
|
||||
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 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;
|
||||
}
|
||||
|
||||
// *********************************** METHODS FOR DRAWING VALUES IN GUI ************************************
|
||||
|
||||
// helper for "Instantiate" button on UnityEngine.Objects
|
||||
public static void InstantiateButton(Object obj, float width = 100)
|
||||
{
|
||||
if (GUILayout.Button("Instantiate", new GUILayoutOption[] { GUILayout.Width(width) }))
|
||||
{
|
||||
var newobj = Object.Instantiate(obj);
|
||||
|
||||
WindowManager.InspectObject(newobj, out _);
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
// ------ toggle active button ------
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUI.skin.button.alignment = TextAnchor.UpperLeft;
|
||||
|
||||
GUI.color = activeColor;
|
||||
|
||||
enabled = GUILayout.Toggle(enabled, "", new GUILayoutOption[] { GUILayout.Width(18) });
|
||||
if (obj.activeSelf != enabled)
|
||||
{
|
||||
obj.SetActive(enabled);
|
||||
}
|
||||
|
||||
// ------- actual button ---------
|
||||
|
||||
if (GUILayout.Button(label, new GUILayoutOption[] { GUILayout.Height(22), GUILayout.Width(width) }))
|
||||
{
|
||||
if (specialInspectMethod != null)
|
||||
{
|
||||
specialInspectMethod(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
WindowManager.InspectObject(obj, out bool _);
|
||||
}
|
||||
}
|
||||
|
||||
// ------ small "Inspect" button on the right ------
|
||||
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleCenter;
|
||||
GUI.color = Color.white;
|
||||
|
||||
if (showSmallInspectBtn)
|
||||
{
|
||||
if (GUILayout.Button("Inspect", null))
|
||||
{
|
||||
WindowManager.InspectObject(obj, out bool _);
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public static void DrawMember(ref object value, ref bool isExpanded, ref int arrayOffset, MemberInfo memberInfo, Rect rect, object setTarget = null, Action<object> setAction = null, float labelWidth = 180, bool autoSet = false)
|
||||
{
|
||||
GUILayout.Label("<color=cyan>" + memberInfo.Name + ":</color>", new GUILayoutOption[] { GUILayout.Width(labelWidth) });
|
||||
|
||||
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, ref isExpanded, ref arrayOffset, rect, valueType, (canWrite ? setTarget : null), (canWrite ? setAction : null), autoSet);
|
||||
}
|
||||
|
||||
public static void DrawValue(ref object value, ref bool isExpanded, ref int arrayOffset, Rect rect, string nullValueType = null, object setTarget = null, Action<object> setAction = null, bool autoSet = false)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
GUILayout.Label("<i>null (" + nullValueType + ")</i>", null);
|
||||
return;
|
||||
}
|
||||
|
||||
var valueType = value.GetType();
|
||||
|
||||
Il2CppSystem.Type ilType = null;
|
||||
if (value is Il2CppSystem.Object ilObject)
|
||||
{
|
||||
ilType = ilObject.GetIl2CppType();
|
||||
}
|
||||
|
||||
if (valueType.IsPrimitive || value.GetType() == typeof(string))
|
||||
{
|
||||
DrawPrimitive(ref value, rect, setTarget, setAction);
|
||||
}
|
||||
else if (ilType != null && ilType == CppExplorer.GameObjectType || CppExplorer.TransformType.IsAssignableFrom(ilType))
|
||||
{
|
||||
GameObject go;
|
||||
var ilObj = value as Il2CppSystem.Object;
|
||||
if (ilType == CppExplorer.GameObjectType)
|
||||
{
|
||||
go = ilObj.TryCast<GameObject>();
|
||||
}
|
||||
else
|
||||
{
|
||||
go = ilObj.TryCast<Transform>().gameObject;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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]);
|
||||
}
|
||||
|
||||
int count = enumerable.Cast<object>().Count();
|
||||
|
||||
if (!isExpanded)
|
||||
{
|
||||
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
isExpanded = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
isExpanded = false;
|
||||
}
|
||||
}
|
||||
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
||||
string btnLabel = "<color=yellow>[" + count + "] " + 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)
|
||||
{
|
||||
if (count > CppExplorer.ArrayLimit)
|
||||
{
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Space(190);
|
||||
int maxOffset = (int)Mathf.Ceil(count / CppExplorer.ArrayLimit);
|
||||
GUILayout.Label($"Page {arrayOffset + 1}/{maxOffset + 1}", new GUILayoutOption[] { GUILayout.Width(80) });
|
||||
// prev/next page buttons
|
||||
if (GUILayout.Button("< Prev", null))
|
||||
{
|
||||
if (arrayOffset > 0) arrayOffset--;
|
||||
}
|
||||
if (GUILayout.Button("Next >", null))
|
||||
{
|
||||
if (arrayOffset < maxOffset) arrayOffset++;
|
||||
}
|
||||
}
|
||||
|
||||
int offset = arrayOffset * CppExplorer.ArrayLimit;
|
||||
|
||||
if (offset >= count) offset = 0;
|
||||
|
||||
var enumerator = enumerable.GetEnumerator();
|
||||
if (enumerator != null)
|
||||
{
|
||||
int i = 0;
|
||||
int preiterated = 0;
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
if (offset > 0 && preiterated < offset)
|
||||
{
|
||||
preiterated++;
|
||||
continue;
|
||||
}
|
||||
|
||||
var obj = enumerator.Current;
|
||||
|
||||
//collapsing the BeginHorizontal called from ReflectionWindow.WindowFunction or previous array entry
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Space(190);
|
||||
|
||||
if (i > CppExplorer.ArrayLimit - 1)
|
||||
{
|
||||
//GUILayout.Label($"<i><color=red>{count - CppExplorer.ArrayLimit} results omitted, array is too long!</color></i>", null);
|
||||
break;
|
||||
}
|
||||
|
||||
if (obj == null)
|
||||
{
|
||||
GUILayout.Label("<i><color=grey>null</color></i>", null);
|
||||
}
|
||||
else
|
||||
{
|
||||
var type = obj.GetType();
|
||||
|
||||
var lbl = (i + offset) + ": <color=cyan>" + obj.ToString() + "</color>";
|
||||
|
||||
if (type.IsPrimitive || typeof(string).IsAssignableFrom(type))
|
||||
{
|
||||
GUILayout.Label(lbl, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
||||
if (GUILayout.Button(lbl, null))
|
||||
{
|
||||
WindowManager.InspectObject(obj, out _);
|
||||
}
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleCenter;
|
||||
}
|
||||
//var type = obj.GetType();
|
||||
//DrawMember(ref obj, type.ToString(), i.ToString(), rect, setTarget, setAction, 25, true);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
string typeLabel;
|
||||
if (ilType != null)
|
||||
{
|
||||
typeLabel = ilType.FullName;
|
||||
}
|
||||
else
|
||||
{
|
||||
typeLabel = value.GetType().FullName;
|
||||
}
|
||||
if (!label.Contains(typeLabel))
|
||||
{
|
||||
label += $" ({typeLabel})";
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
bool allowSet = setAction != null;
|
||||
|
||||
if (value.GetType() == typeof(bool))
|
||||
{
|
||||
bool b = (bool)value;
|
||||
var color = "<color=" + (b ? "lime>" : "red>");
|
||||
|
||||
if (allowSet)
|
||||
{
|
||||
value = GUILayout.Toggle((bool)value, color + value.ToString() + "</color>", null);
|
||||
|
||||
if (b != (bool)value)
|
||||
{
|
||||
setAction.Invoke(setTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value.ToString().Length > 37)
|
||||
{
|
||||
value = GUILayout.TextArea(value.ToString(), new GUILayoutOption[] { GUILayout.MaxWidth(m_rect.width - 260) });
|
||||
}
|
||||
else
|
||||
{
|
||||
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) })))
|
||||
{
|
||||
setAction.Invoke(setTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper for setting an enum
|
||||
|
||||
public static void SetEnum(ref object value, int change)
|
||||
{
|
||||
var type = value.GetType();
|
||||
var names = Enum.GetNames(type).ToList();
|
||||
|
||||
int newindex = names.IndexOf(value.ToString()) + change;
|
||||
|
||||
if ((change < 0 && newindex >= 0) || (change > 0 && newindex < names.Count))
|
||||
{
|
||||
value = Enum.Parse(type, names[newindex]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,189 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Harmony;
|
||||
using MelonLoader;
|
||||
using UnhollowerBaseLib;
|
||||
using UnhollowerRuntimeLib;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
public class WindowManager
|
||||
{
|
||||
public static WindowManager Instance;
|
||||
|
||||
public static List<UIWindow> Windows = new List<UIWindow>();
|
||||
public static int CurrentWindowID { get; set; } = 500000;
|
||||
private static Rect m_lastWindowRect;
|
||||
|
||||
public WindowManager()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
foreach (var window in Windows)
|
||||
{
|
||||
window.Update();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnGUI()
|
||||
{
|
||||
foreach (var window in Windows)
|
||||
{
|
||||
window.OnGUI();
|
||||
}
|
||||
}
|
||||
|
||||
// ========= Public Helpers =========
|
||||
|
||||
public static bool IsMouseInWindow
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!CppExplorer.ShowMenu)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var window in Windows)
|
||||
{
|
||||
if (RectContainsMouse(window.m_rect))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return RectContainsMouse(MainMenu.MainRect);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool RectContainsMouse(Rect rect)
|
||||
{
|
||||
return rect.Contains(new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y));
|
||||
}
|
||||
|
||||
public static int NextWindowID()
|
||||
{
|
||||
return CurrentWindowID++;
|
||||
}
|
||||
|
||||
public static Rect GetNewWindowRect()
|
||||
{
|
||||
return GetNewWindowRect(ref m_lastWindowRect);
|
||||
}
|
||||
|
||||
public static Rect GetNewWindowRect(ref Rect lastRect)
|
||||
{
|
||||
Rect rect = new Rect(0, 0, 550, 700);
|
||||
|
||||
var mainrect = MainMenu.MainRect;
|
||||
if (mainrect.x <= (Screen.width - mainrect.width - 100))
|
||||
{
|
||||
rect = new Rect(mainrect.x + mainrect.width + 20, mainrect.y, rect.width, rect.height);
|
||||
}
|
||||
|
||||
if (lastRect.x == rect.x)
|
||||
{
|
||||
rect = new Rect(rect.x + 25, rect.y + 25, rect.width, rect.height);
|
||||
}
|
||||
|
||||
lastRect = rect;
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
public static UIWindow InspectObject(object obj, out bool createdNew)
|
||||
{
|
||||
createdNew = false;
|
||||
|
||||
foreach (var window in Windows)
|
||||
{
|
||||
if (obj == window.Target)
|
||||
{
|
||||
GUI.BringWindowToFront(window.windowID);
|
||||
GUI.FocusWindow(window.windowID);
|
||||
return window;
|
||||
}
|
||||
}
|
||||
|
||||
createdNew = true;
|
||||
if (obj is GameObject || obj is Transform)
|
||||
{
|
||||
return InspectGameObject(obj as GameObject ?? (obj as Transform).gameObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
return InspectReflection(obj);
|
||||
}
|
||||
}
|
||||
|
||||
private static UIWindow InspectGameObject(GameObject obj)
|
||||
{
|
||||
var new_window = UIWindow.CreateWindow<GameObjectWindow>(obj);
|
||||
GUI.FocusWindow(new_window.windowID);
|
||||
|
||||
return new_window;
|
||||
}
|
||||
|
||||
public static UIWindow InspectReflection(object obj)
|
||||
{
|
||||
var new_window = UIWindow.CreateWindow<ReflectionWindow>(obj);
|
||||
GUI.FocusWindow(new_window.windowID);
|
||||
|
||||
return new_window;
|
||||
}
|
||||
|
||||
// ============= Resize Window Helper ============
|
||||
|
||||
// static readonly GUIContent gcDrag = new GUIContent("<->", "drag to resize");
|
||||
private static readonly GUIContent gcDrag = new GUIContent("<->");
|
||||
private static bool isResizing = false;
|
||||
private static Rect m_currentResize;
|
||||
private static int m_currentWindow;
|
||||
|
||||
public static Rect ResizeWindow(Rect _rect, int ID)
|
||||
{
|
||||
try
|
||||
{
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Space(_rect.width - 35);
|
||||
|
||||
GUILayout.Button(gcDrag, GUI.skin.label, new GUILayoutOption[] { GUILayout.Width(25), GUILayout.Height(25) });
|
||||
|
||||
var r = GUILayoutUtility.GetLastRect();
|
||||
|
||||
Vector2 mouse = GUIUtility.ScreenToGUIPoint(new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y));
|
||||
|
||||
if (r.Contains(mouse) && Input.GetMouseButtonDown(0))
|
||||
{
|
||||
isResizing = true;
|
||||
m_currentWindow = ID;
|
||||
m_currentResize = new Rect(mouse.x, mouse.y, _rect.width, _rect.height);
|
||||
}
|
||||
else if (!Input.GetMouseButton(0))
|
||||
{
|
||||
isResizing = false;
|
||||
}
|
||||
|
||||
if (isResizing && ID == m_currentWindow)
|
||||
{
|
||||
_rect.width = Mathf.Max(100, m_currentResize.width + (mouse.x - m_currentResize.x));
|
||||
_rect.height = Mathf.Max(100, m_currentResize.height + (mouse.y - m_currentResize.y));
|
||||
_rect.xMax = Mathf.Min(Screen.width, _rect.xMax); // modifying xMax affects width, not x
|
||||
_rect.yMax = Mathf.Min(Screen.height, _rect.yMax); // modifying yMax affects height, not y
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
catch { }
|
||||
|
||||
return _rect;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user