Compare commits

..

8 Commits
3.3.3 ... 3.3.6

Author SHA1 Message Date
6ca117b070 Fix strings boxed as Il2CppSystem.Objects 2021-04-04 13:44:58 +10:00
113f2fd922 3.3.5 - fix Il2Cpp Hashtable, boxed strings 2021-04-04 03:41:36 +10:00
7443f6500e Update README.md 2021-04-03 17:24:28 +11:00
92566c2729 Update README.md 2021-04-02 19:56:18 +11:00
713f87f455 Update THIRDPARTY_LICENSES.md 2021-04-02 17:45:50 +11:00
4241e7e207 Include third-party licenses 2021-04-02 17:44:49 +11:00
6d479a6703 3.3.4
* Fixed Harmony patches not working properly for games which use older BepInEx releases (ie. Risk of Rain 2)
* Fixed a couple minor issues with the config settings
2021-04-02 17:06:49 +11:00
6539f818c3 Update README.md 2021-04-01 22:04:58 +11:00
38 changed files with 1429 additions and 224 deletions

View File

@ -6,7 +6,7 @@
An in-game explorer and a suite of debugging tools for <a href="https://docs.unity3d.com/Manual/IL2CPP.html">IL2CPP</a> and <b>Mono</b> Unity games, to aid with modding development. An in-game explorer and a suite of debugging tools for <a href="https://docs.unity3d.com/Manual/IL2CPP.html">IL2CPP</a> and <b>Mono</b> Unity games, to aid with modding development.
</p> </p>
## Releases [![](https://img.shields.io/github/release/sinai-dev/Explorer.svg?label=release%20notes)](../../releases/latest) [![](https://img.shields.io/github/downloads/sinai-dev/Explorer/total.svg)]() [![](https://img.shields.io/github/downloads/sinai-dev/Explorer/latest/total.svg)]() ## Releases [![](https://img.shields.io/github/release/sinai-dev/Explorer.svg?label=release%20notes)](../../releases/latest) [![](https://img.shields.io/github/downloads/sinai-dev/Explorer/total.svg)](../../releases) [![](https://img.shields.io/github/downloads/sinai-dev/Explorer/latest/total.svg)](../../releases/latest)
| Mod Loader | IL2CPP | Mono | | Mod Loader | IL2CPP | Mono |
| ----------- | ------ | ---- | | ----------- | ------ | ---- |
@ -19,24 +19,24 @@
### BepInEx ### BepInEx
0. Install [BepInEx](https://github.com/BepInEx/BepInEx) for your game. For IL2CPP you should use [BepInEx 6 (Bleeding Edge)](https://builds.bepis.io/projects/bepinex_be), for Mono you should use [BepInEx 5](https://github.com/BepInEx/BepInEx/releases) (until Mono support stabilizes in BepInEx 6). 1. Install [BepInEx](https://github.com/BepInEx/BepInEx) for your game. For IL2CPP you should use [BepInEx 6 (Bleeding Edge)](https://builds.bepis.io/projects/bepinex_be), for Mono you should use [BepInEx 5](https://github.com/BepInEx/BepInEx/releases) (until Mono support stabilizes in BepInEx 6).
1. Download the UnityExplorer release for BepInEx IL2CPP or Mono above. 2. Download the UnityExplorer release for BepInEx IL2CPP or Mono above.
2. Take the `UnityExplorer.BIE.___.dll` file and put it in `[GameFolder]\BepInEx\plugins\` 3. Take the `UnityExplorer.BIE.___.dll` file and put it in `[GameFolder]\BepInEx\plugins\`
3. In IL2CPP, you will need to download the [Unity libs](https://github.com/LavaGang/Unity-Runtime-Libraries) for the game's Unity version and put them in the `BepInEx\unity-libs\` folder. 4. In IL2CPP, you will need to download the [Unity libs](https://github.com/LavaGang/Unity-Runtime-Libraries) for the game's Unity version and put them in the `BepInEx\unity-libs\` folder.
### MelonLoader ### MelonLoader
0. Install [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) 0.3+ for your game. Version 0.3 is currently in pre-release, so you must "Enable ALPHA Releases" in your MelonLoader Installer settings to see the option for it. 1. Install [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) 0.3+ for your game. Version 0.3 is currently in pre-release, so you must "Enable ALPHA Releases" in your MelonLoader Installer settings to see the option for it.
1. Download the UnityExplorer release for MelonLoader IL2CPP or Mono above. 2. Download the UnityExplorer release for MelonLoader IL2CPP or Mono above.
2. Take the `UnityExplorer.ML.___.dll` file and put it in the `[GameFolder]\Mods\` folder. 3. Take the `UnityExplorer.ML.___.dll` file and put it in the `[GameFolder]\Mods\` folder.
### Standalone ### Standalone
The standalone release is based on the BepInEx build, so it requires Harmony 2.0 (or HarmonyX) to function properly. The standalone release requires you to also load `0Harmony.dll` (HarmonyX, from the `lib\` folder) to function properly, and the IL2CPP also requires `UnhollowerBaseLib.dll` as well. The Mono release should be fairly easy to use with any loader, but the IL2CPP one may be tricky, I'd recommend just using BepInEx or MelonLoader for IL2CPP.
0. Load the DLL from your mod or inject it. You must also make sure `0Harmony.dll` is loaded, and `UnhollowerBaseLib.dll` for IL2CPP as well. 1. Load the UnityExplorer DLL from your mod or inject it, as well as `0Harmony.dll` and `UnhollowerBaseLib.dll` as required.
1. Create an instance of Unity Explorer with `UnityExplorer.ExplorerStandalone.CreateInstance();` 2. Create an instance of Unity Explorer with `UnityExplorer.ExplorerStandalone.CreateInstance();`
2. Optionally subscribe to the `ExplorerStandalone.OnLog` event to handle logging if you wish. 3. Optionally subscribe to the `ExplorerStandalone.OnLog` event to handle logging if you wish.
## Issues and contributions ## Issues and contributions
@ -46,7 +46,19 @@ Both issue reports and PR contributions are welcome in this repository.
To report an issue with UnityExplorer, please use the following template (as well as any other information / images you can provide). To report an issue with UnityExplorer, please use the following template (as well as any other information / images you can provide).
Please upload your Unity log file to [Pastebin](https://pastebin.com/) and provide a link to the paste. Template:
```
* Game issue occurs on:
* UnityExplorer version: (eg BIE.IL2CPP v3.3.3, etc)
* Description of issue:
* Unity log link:
* Mod Loader log link:
```
Please upload your Unity log file to [Pastebin](https://pastebin.com/) (or equivalent service) and provide a link to the paste.
* The log should be found at `%userprofile%\AppData\LocalLow\[Company]\[Game]\` unless redirected by your Mod Loader. * The log should be found at `%userprofile%\AppData\LocalLow\[Company]\[Game]\` unless redirected by your Mod Loader.
* The file will be called either `output_log.txt` or `Player.log` * The file will be called either `output_log.txt` or `Player.log`
@ -56,20 +68,6 @@ As well as the Unity log, please upload your Mod Loader's log:
* BepInEx: `BepInEx\LogOutput.log` * BepInEx: `BepInEx\LogOutput.log`
* MelonLoader: `MelonLoader\Latest.log` * MelonLoader: `MelonLoader\Latest.log`
Template:
```
* OS Platform:
* Display resolution:
* Game(s) tested on:
* UnityExplorer version(s) tested:
* Description of issue:
* Unity log pastebin link:
* Mod Loader log pastebin link:
```
## Features ## Features
<p align="center"> <p align="center">
@ -126,31 +124,6 @@ Depending on the release you are using, the config file will be found at:
* MelonLoader: `UserData\MelonPreferences.cfg` * MelonLoader: `UserData\MelonPreferences.cfg`
* Standalone `{DLL_location}\UnityExplorer\config.ini` * Standalone `{DLL_location}\UnityExplorer\config.ini`
`Main Menu Toggle` (KeyCode)
* Default: `F7`
* See [this article](https://docs.unity3d.com/ScriptReference/KeyCode.html) for a full list of all accepted KeyCodes.
`Force Unlock Mouse` (bool)
* Default: `true`
* Forces the cursor to be unlocked and visible while the UnityExplorer menu is open, and prevents anything else taking control.
`Default Page Limit` (int)
* Default: `25`
* Sets the default items per page when viewing lists or search results.
* <b>Requires a restart to take effect</b>, apart from Reflection Inspector tabs.
`Default Output Path` (string)
* Default: `Mods\UnityExplorer`
* Where output is generated to, by default (for Texture PNG saving, etc).
`Log Unity Debug` (bool)
* Default: `false`
* Listens for Unity `Debug.Log` messages and prints them to UnityExplorer's log.
`Hide on Startup` (bool)
* Default: `false`
* If true, UnityExplorer will be hidden when you start the game, you must open it via the keybind.
## Building ## Building
Building the project should be straight-forward, the references are all inside the `lib\` folder. Building the project should be straight-forward, the references are all inside the `lib\` folder.
@ -162,10 +135,10 @@ Building the project should be straight-forward, the references are all inside t
## Acknowledgments ## Acknowledgments
* [ManlyMarco](https://github.com/ManlyMarco) for [Runtime Unity Editor](https://github.com/ManlyMarco/RuntimeUnityEditor), snippets from the REPL Console were used for UnityExplorer's C# Console. * [ManlyMarco](https://github.com/ManlyMarco) for [Runtime Unity Editor](https://github.com/ManlyMarco/RuntimeUnityEditor) \[[license](THIRDPARTY_LICENSES.md#runtimeunityeditor-license)\], snippets from the REPL Console were used for UnityExplorer's C# Console.
* [denikson](https://github.com/denikson) (aka Horse) for [mcs-unity](https://github.com/denikson/mcs-unity), used as the `Mono.CSharp` reference for the C# Console. * [denikson](https://github.com/denikson) (aka Horse) for [mcs-unity](https://github.com/denikson/mcs-unity) \[no license\], used as the `Mono.CSharp` reference for the C# Console.
* [HerpDerpenstine](https://github.com/HerpDerpinstine) for [MelonCoroutines](https://github.com/LavaGang/MelonLoader/blob/master/MelonLoader.Support.Il2Cpp/MelonCoroutines.cs), they were included for standalone IL2CPP coroutine support. * [HerpDerpenstine](https://github.com/HerpDerpinstine) for [MelonCoroutines](https://github.com/LavaGang/MelonLoader/blob/6cc958ec23b5e2e8453a73bc2e0d5aa353d4f0d1/MelonLoader.Support.Il2Cpp/MelonCoroutines.cs) \[[license](THIRDPARTY_LICENSES.md#melonloader-license)\], they were included for standalone IL2CPP coroutine support.
* [InGameCodeEditor](https://assetstore.unity.com/packages/tools/gui/ingame-code-editor-144254) was used as the base for the syntax highlighting for UnityExplorer's C# console (`UnityExplorer.UI.Main.CSConsole.Lexer`). * [InGameCodeEditor](https://assetstore.unity.com/packages/tools/gui/ingame-code-editor-144254) \[[license](THIRDPARTY_LICENSES.md#ingamecodeeditor-license)\] was used as the base for the syntax highlighting for UnityExplorer's C# console (`UnityExplorer.UI.Main.CSConsole.Lexer`).
### Disclaimer ### Disclaimer

1067
THIRDPARTY_LICENSES.md Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -7,6 +7,7 @@ using System.Linq;
using UnityExplorer.Core.Runtime; using UnityExplorer.Core.Runtime;
using UnityExplorer.UI.Main.CSConsole; using UnityExplorer.UI.Main.CSConsole;
using UnityExplorer.UI.Main.Home; using UnityExplorer.UI.Main.Home;
using UnityExplorer.UI.Inspectors;
namespace UnityExplorer.Core.CSharp namespace UnityExplorer.Core.CSharp
{ {

View File

@ -46,7 +46,7 @@ namespace UnityExplorer.Core.Config
private void SetValue(T value) private void SetValue(T value)
{ {
if ((m_value == null && value == null) || m_value.Equals(value)) if ((m_value == null && value == null) || (m_value != null && m_value.Equals(value)))
return; return;
m_value = value; m_value = value;

View File

@ -46,81 +46,16 @@ namespace UnityExplorer.Core.Input
UpdateCursorControl(); UpdateCursorControl();
Unlock = true; Unlock = ConfigManager.Force_Unlock_Mouse.Value;
ConfigManager.Force_Unlock_Mouse.OnValueChanged += (bool val) => { Unlock = val; }; ConfigManager.Force_Unlock_Mouse.OnValueChanged += (bool val) => { Unlock = val; };
} }
private static void SetupPatches()
{
try
{
if (CursorType == null)
{
throw new Exception("Could not find Type 'UnityEngine.Cursor'!");
}
// Get current cursor state and enable cursor
try
{
m_lastLockMode = (CursorLockMode?)typeof(Cursor).GetProperty("lockState", BF.Public | BF.Static)?.GetValue(null, null)
?? CursorLockMode.None;
m_lastVisibleState = (bool?)typeof(Cursor).GetProperty("visible", BF.Public | BF.Static)?.GetValue(null, null)
?? false;
}
catch { }
// Setup Harmony Patches
TryPatch(typeof(Cursor),
"lockState",
new HarmonyMethod(typeof(CursorUnlocker).GetMethod(nameof(Prefix_set_lockState))),
true);
TryPatch(typeof(Cursor),
"visible",
new HarmonyMethod(typeof(CursorUnlocker).GetMethod(nameof(Prefix_set_visible))),
true);
TryPatch(typeof(EventSystem),
"current",
new HarmonyMethod(typeof(CursorUnlocker).GetMethod(nameof(Prefix_EventSystem_set_current))),
true);
}
catch (Exception e)
{
ExplorerCore.Log($"Exception on ForceUnlockCursor.Init! {e.GetType()}, {e.Message}");
}
}
private static void TryPatch(Type type, string property, HarmonyMethod patch, bool setter)
{
try
{
var harmony = ExplorerCore.Loader.HarmonyInstance;
var prop = type.GetProperty(property);
if (setter) // setter is prefix
{
harmony.Patch(prop.GetSetMethod(), prefix: patch);
}
else // getter is postfix
{
harmony.Patch(prop.GetGetMethod(), postfix: patch);
}
}
catch (Exception e)
{
string suf = setter ? "set_" : "get_";
ExplorerCore.Log($"Unable to patch {type.Name}.{suf}{property}: {e.Message}");
}
}
public static void UpdateCursorControl() public static void UpdateCursorControl()
{ {
try try
{ {
m_currentlySettingCursor = true; m_currentlySettingCursor = true;
if (ShouldActuallyUnlock) if (ShouldActuallyUnlock)
{ {
Cursor.lockState = CursorLockMode.None; Cursor.lockState = CursorLockMode.None;
@ -137,6 +72,7 @@ namespace UnityExplorer.Core.Input
if (UIManager.EventSys) if (UIManager.EventSys)
ReleaseEventSystem(); ReleaseEventSystem();
} }
m_currentlySettingCursor = false; m_currentlySettingCursor = false;
} }
catch (Exception e) catch (Exception e)
@ -163,9 +99,7 @@ namespace UnityExplorer.Core.Input
if (!m_lastEventSystem) if (!m_lastEventSystem)
m_lastEventSystem = EventSystem.current; m_lastEventSystem = EventSystem.current;
//ExplorerCore.Log("Disabling current event system...");
m_lastEventSystem.enabled = false; m_lastEventSystem.enabled = false;
//m_lastEventSystem.gameObject.SetActive(false);
} }
// Set to our current system // Set to our current system
@ -184,7 +118,6 @@ namespace UnityExplorer.Core.Input
if (m_lastEventSystem) if (m_lastEventSystem)
{ {
m_lastEventSystem.enabled = true; m_lastEventSystem.enabled = true;
//m_lastEventSystem.gameObject.SetActive(true);
m_settingEventSystem = true; m_settingEventSystem = true;
EventSystem.current = m_lastEventSystem; EventSystem.current = m_lastEventSystem;
@ -193,7 +126,30 @@ namespace UnityExplorer.Core.Input
} }
} }
[HarmonyPrefix] // Patches
private static void SetupPatches()
{
try
{
if (CursorType == null)
throw new Exception("Could not load Type 'UnityEngine.Cursor'!");
// Get current cursor state and enable cursor
m_lastLockMode = (CursorLockMode?)CursorType.GetProperty("lockState", BF.Public | BF.Static)?.GetValue(null, null)
?? CursorLockMode.None;
m_lastVisibleState = (bool?)CursorType.GetProperty("visible", BF.Public | BF.Static)?.GetValue(null, null)
?? false;
ExplorerCore.Loader.SetupPatches();
}
catch (Exception e)
{
ExplorerCore.Log($"Error on CursorUnlocker.Init! {e.GetType()}, {e.Message}");
}
}
public static void Prefix_EventSystem_set_current(ref EventSystem value) public static void Prefix_EventSystem_set_current(ref EventSystem value)
{ {
if (!m_settingEventSystem) if (!m_settingEventSystem)
@ -210,7 +166,6 @@ namespace UnityExplorer.Core.Input
// Also keep track of when anything else tries to set Cursor state, this will be the // Also keep track of when anything else tries to set Cursor state, this will be the
// value that we set back to when we close the menu or disable force-unlock. // value that we set back to when we close the menu or disable force-unlock.
[HarmonyPrefix]
public static void Prefix_set_lockState(ref CursorLockMode value) public static void Prefix_set_lockState(ref CursorLockMode value)
{ {
if (!m_currentlySettingCursor) if (!m_currentlySettingCursor)
@ -222,7 +177,6 @@ namespace UnityExplorer.Core.Input
} }
} }
[HarmonyPrefix]
public static void Prefix_set_visible(ref bool value) public static void Prefix_set_visible(ref bool value)
{ {
if (!m_currentlySettingCursor) if (!m_currentlySettingCursor)

View File

@ -7,7 +7,7 @@ using System.Reflection;
using BF = System.Reflection.BindingFlags; using BF = System.Reflection.BindingFlags;
using UnityExplorer.Core.Runtime; using UnityExplorer.Core.Runtime;
namespace UnityExplorer.Core namespace UnityExplorer
{ {
public static class ReflectionUtility public static class ReflectionUtility
{ {
@ -18,7 +18,7 @@ namespace UnityExplorer.Core
/// </summary> /// </summary>
/// <param name="obj">The object to get the true Type for.</param> /// <param name="obj">The object to get the true Type for.</param>
/// <returns>The most accurate Type of the object which could be identified.</returns> /// <returns>The most accurate Type of the object which could be identified.</returns>
public static Type GetType(this object obj) public static Type GetActualType(this object obj)
{ {
if (obj == null) if (obj == null)
return null; return null;
@ -32,7 +32,7 @@ namespace UnityExplorer.Core
/// <param name="obj">The object to cast</param> /// <param name="obj">The object to cast</param>
/// <returns>The object, cast to the underlying Type if possible, otherwise the original object.</returns> /// <returns>The object, cast to the underlying Type if possible, otherwise the original object.</returns>
public static object Cast(this object obj) public static object Cast(this object obj)
=> ReflectionProvider.Instance.Cast(obj, GetType(obj)); => ReflectionProvider.Instance.Cast(obj, GetActualType(obj));
/// <summary> /// <summary>
/// Cast an object to a Type, if possible. /// Cast an object to a Type, if possible.
@ -105,7 +105,7 @@ namespace UnityExplorer.Core
/// <summary> /// <summary>
/// Get all base types of the provided Type, including itself. /// Get all base types of the provided Type, including itself.
/// </summary> /// </summary>
public static Type[] GetAllBaseTypes(this object obj) => GetAllBaseTypes(GetType(obj)); public static Type[] GetAllBaseTypes(this object obj) => GetAllBaseTypes(GetActualType(obj));
/// <summary> /// <summary>
/// Get all base types of the provided Type, including itself. /// Get all base types of the provided Type, including itself.

View File

@ -154,21 +154,24 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp
/// <returns>The object, as the type (or a normal C# object) if successful or the input value if not.</returns> /// <returns>The object, as the type (or a normal C# object) if successful or the input value if not.</returns>
public static object Il2CppCast(object obj, Type castTo) public static object Il2CppCast(object obj, Type castTo)
{ {
if (!(obj is Il2CppSystem.Object ilObj)) if (!(obj is Il2CppSystem.Object cppObj))
return obj; return obj;
if (!Il2CppTypeNotNull(castTo, out IntPtr castToPtr)) if (!Il2CppTypeNotNull(castTo, out IntPtr castToPtr))
return obj; return obj;
IntPtr castFromPtr = il2cpp_object_get_class(ilObj.Pointer); IntPtr castFromPtr = il2cpp_object_get_class(cppObj.Pointer);
if (!il2cpp_class_is_assignable_from(castToPtr, castFromPtr)) if (!il2cpp_class_is_assignable_from(castToPtr, castFromPtr))
return obj; return null;
if (RuntimeSpecificsStore.IsInjected(castToPtr)) if (RuntimeSpecificsStore.IsInjected(castToPtr))
return UnhollowerBaseLib.Runtime.ClassInjectorBase.GetMonoObjectFromIl2CppPointer(ilObj.Pointer); return UnhollowerBaseLib.Runtime.ClassInjectorBase.GetMonoObjectFromIl2CppPointer(cppObj.Pointer);
return Activator.CreateInstance(castTo, ilObj.Pointer); if (castTo == typeof(string))
return cppObj.ToString();
return Activator.CreateInstance(castTo, cppObj.Pointer);
} }
/// <summary> /// <summary>
@ -319,6 +322,14 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp
return false; return false;
} }
public override void BoxStringToType(ref object value, Type castTo)
{
if (castTo == typeof(Il2CppSystem.String))
value = (Il2CppSystem.String)(value as string);
else
value = (Il2CppSystem.Object)(value as string);
}
// ~~~~~~~~~~ not used ~~~~~~~~~~~~ // ~~~~~~~~~~ not used ~~~~~~~~~~~~
// cached il2cpp unbox methods // cached il2cpp unbox methods

View File

@ -27,6 +27,9 @@ namespace UnityExplorer.Core.Runtime.Mono
public override string ProcessTypeNameInString(Type type, string theString, ref string typeName) public override string ProcessTypeNameInString(Type type, string theString, ref string typeName)
=> theString; => theString;
// not necessary
public override void BoxStringToType(ref object _string, Type castTo) { }
} }
} }

View File

@ -25,5 +25,7 @@ namespace UnityExplorer.Core.Runtime
public abstract string ProcessTypeNameInString(Type type, string theString, ref string typeName); public abstract string ProcessTypeNameInString(Type type, string theString, ref string typeName);
public abstract bool LoadModule(string module); public abstract bool LoadModule(string module);
public abstract void BoxStringToType(ref object _string, Type castTo);
} }
} }

27
src/Core/TestClass.cs Normal file
View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace UnityExplorer
{
public static class TestClass
{
#if CPP
public static string testStringOne = "Test";
public static Il2CppSystem.Object testStringTwo = "string boxed as cpp object";
public static Il2CppSystem.String testStringThree = "string boxed as cpp string";
public static string nullString = null;
public static Il2CppSystem.Collections.Hashtable testHashset;
static TestClass()
{
testHashset = new Il2CppSystem.Collections.Hashtable();
testHashset.Add("key1", "itemOne");
testHashset.Add("key2", "itemTwo");
testHashset.Add("key3", "itemThree");
}
#endif
}
}

View File

@ -5,6 +5,7 @@ using UnityExplorer.Core.Config;
using UnityExplorer.Core.Input; using UnityExplorer.Core.Input;
using UnityExplorer.Core.Runtime; using UnityExplorer.Core.Runtime;
using UnityExplorer.UI; using UnityExplorer.UI;
using UnityExplorer.UI.Inspectors;
using UnityExplorer.UI.Main; using UnityExplorer.UI.Main;
namespace UnityExplorer namespace UnityExplorer
@ -12,7 +13,7 @@ namespace UnityExplorer
public class ExplorerCore public class ExplorerCore
{ {
public const string NAME = "UnityExplorer"; public const string NAME = "UnityExplorer";
public const string VERSION = "3.3.3"; public const string VERSION = "3.3.6";
public const string AUTHOR = "Sinai"; public const string AUTHOR = "Sinai";
public const string GUID = "com.sinai.unityexplorer"; public const string GUID = "com.sinai.unityexplorer";
@ -46,6 +47,8 @@ namespace UnityExplorer
UIManager.Init(); UIManager.Init();
Log($"{NAME} {VERSION} initialized."); Log($"{NAME} {VERSION} initialized.");
// InspectorManager.Instance.Inspect(typeof(TestClass));
} }
public static void Update() public static void Update()

View File

@ -10,6 +10,9 @@ using System.Text;
using UnityExplorer.Core.Config; using UnityExplorer.Core.Config;
using UnityExplorer.Loader.BIE; using UnityExplorer.Loader.BIE;
using UnityEngine; using UnityEngine;
using UnityExplorer.Core;
using UnityEngine.EventSystems;
using UnityExplorer.Core.Input;
#if CPP #if CPP
using BepInEx.IL2CPP; using BepInEx.IL2CPP;
using UnhollowerRuntimeLib; using UnhollowerRuntimeLib;
@ -75,10 +78,8 @@ namespace UnityExplorer
ClassInjector.RegisterTypeInIl2Cpp<ExplorerBehaviour>(); ClassInjector.RegisterTypeInIl2Cpp<ExplorerBehaviour>();
var obj = new GameObject( var obj = new GameObject("ExplorerBehaviour");
"ExplorerBehaviour", obj.AddComponent<ExplorerBehaviour>();
new Il2CppSystem.Type[] { Il2CppType.Of<ExplorerBehaviour>() }
);
obj.hideFlags = HideFlags.HideAndDontSave; obj.hideFlags = HideFlags.HideAndDontSave;
GameObject.DontDestroyOnLoad(obj); GameObject.DontDestroyOnLoad(obj);
@ -101,6 +102,48 @@ namespace UnityExplorer
} }
} }
#endif #endif
public void SetupPatches()
{
try
{
this.HarmonyInstance.PatchAll();
}
catch (Exception ex)
{
ExplorerCore.Log($"Exception setting up Harmony patches:\r\n{ex.ReflectionExToString()}");
}
}
[HarmonyPatch(typeof(EventSystem), "current", MethodType.Setter)]
public class PATCH_EventSystem_current
{
[HarmonyPrefix]
public static void Prefix_EventSystem_set_current(ref EventSystem value)
{
CursorUnlocker.Prefix_EventSystem_set_current(ref value);
}
}
[HarmonyPatch(typeof(Cursor), "lockState", MethodType.Setter)]
public class PATCH_Cursor_lockState
{
[HarmonyPrefix]
public static void Prefix_set_lockState(ref CursorLockMode value)
{
CursorUnlocker.Prefix_set_lockState(ref value);
}
}
[HarmonyPatch(typeof(Cursor), "visible", MethodType.Setter)]
public class PATCH_Cursor_visible
{
[HarmonyPrefix]
public static void Prefix_set_visible(ref bool value)
{
CursorUnlocker.Prefix_set_visible(ref value);
}
}
} }
} }
#endif #endif

View File

@ -17,10 +17,6 @@ namespace UnityExplorer
Action<object> OnLogWarning { get; } Action<object> OnLogWarning { get; }
Action<object> OnLogError { get; } Action<object> OnLogError { get; }
#if ML void SetupPatches();
Harmony.HarmonyInstance HarmonyInstance { get; }
#else
HarmonyLib.Harmony HarmonyInstance { get; }
#endif
} }
} }

View File

@ -1,10 +1,14 @@
#if ML #if ML
using System; using System;
using System.IO; using System.IO;
using Harmony;
using MelonLoader; using MelonLoader;
using UnityEngine; using UnityEngine;
using UnityEngine.EventSystems;
using UnityExplorer; using UnityExplorer;
using UnityExplorer.Core;
using UnityExplorer.Core.Config; using UnityExplorer.Core.Config;
using UnityExplorer.Core.Input;
using UnityExplorer.Loader.ML; using UnityExplorer.Loader.ML;
[assembly: MelonInfo(typeof(ExplorerMelonMod), ExplorerCore.NAME, ExplorerCore.VERSION, ExplorerCore.AUTHOR)] [assembly: MelonInfo(typeof(ExplorerMelonMod), ExplorerCore.NAME, ExplorerCore.VERSION, ExplorerCore.AUTHOR)]
@ -40,6 +44,41 @@ namespace UnityExplorer
{ {
ExplorerCore.Update(); ExplorerCore.Update();
} }
public void SetupPatches()
{
try
{
PrefixProperty(typeof(Cursor),
"lockState",
new HarmonyMethod(typeof(CursorUnlocker).GetMethod(nameof(CursorUnlocker.Prefix_set_lockState))));
PrefixProperty(typeof(Cursor),
"visible",
new HarmonyMethod(typeof(CursorUnlocker).GetMethod(nameof(CursorUnlocker.Prefix_set_visible))));
PrefixProperty(typeof(EventSystem),
"current",
new HarmonyMethod(typeof(CursorUnlocker).GetMethod(nameof(CursorUnlocker.Prefix_EventSystem_set_current))));
}
catch (Exception ex)
{
ExplorerCore.Log($"Exception setting up Harmony patches:\r\n{ex.ReflectionExToString()}");
}
}
private void PrefixProperty(Type type, string property, HarmonyMethod prefix)
{
try
{
var prop = type.GetProperty(property);
this.Harmony.Patch(prop.GetSetMethod(), prefix: prefix);
}
catch (Exception e)
{
ExplorerCore.Log($"Unable to patch {type.Name}.set_{property}: {e.Message}");
}
}
} }
} }
#endif #endif

View File

@ -21,8 +21,12 @@ namespace UnityExplorer.Loader.ML
{ {
prefCategory = MelonPreferences.CreateCategory(CTG_NAME, $"{CTG_NAME} Settings"); prefCategory = MelonPreferences.CreateCategory(CTG_NAME, $"{CTG_NAME} Settings");
try
{
MelonPreferences.Mapper.RegisterMapper(KeycodeReader, KeycodeWriter); MelonPreferences.Mapper.RegisterMapper(KeycodeReader, KeycodeWriter);
} }
catch { }
}
public override void LoadConfig() public override void LoadConfig()
{ {

View File

@ -6,6 +6,9 @@ using System.Reflection;
using UnityEngine; using UnityEngine;
using UnityExplorer.Core.Config; using UnityExplorer.Core.Config;
using UnityExplorer.Loader.STANDALONE; using UnityExplorer.Loader.STANDALONE;
using UnityEngine.EventSystems;
using UnityExplorer.Core.Input;
using UnityExplorer.Core;
#if CPP #if CPP
using UnhollowerRuntimeLib; using UnhollowerRuntimeLib;
#endif #endif
@ -86,17 +89,9 @@ namespace UnityExplorer
#if CPP #if CPP
ClassInjector.RegisterTypeInIl2Cpp<ExplorerBehaviour>(); ClassInjector.RegisterTypeInIl2Cpp<ExplorerBehaviour>();
var obj = new GameObject(
"ExplorerBehaviour",
new Il2CppSystem.Type[] { Il2CppType.Of<ExplorerBehaviour>() }
);
#else
var obj = new GameObject(
"ExplorerBehaviour",
new Type[] { typeof(ExplorerBehaviour) }
);
#endif #endif
var obj = new GameObject("ExplorerBehaviour");
obj.AddComponent<ExplorerBehaviour>();
GameObject.DontDestroyOnLoad(obj); GameObject.DontDestroyOnLoad(obj);
obj.hideFlags = HideFlags.HideAndDontSave; obj.hideFlags = HideFlags.HideAndDontSave;
@ -114,6 +109,48 @@ namespace UnityExplorer
ExplorerCore.Update(); ExplorerCore.Update();
} }
} }
public void SetupPatches()
{
try
{
this.HarmonyInstance.PatchAll();
}
catch (Exception ex)
{
ExplorerCore.Log($"Exception setting up Harmony patches:\r\n{ex.ReflectionExToString()}");
}
}
[HarmonyPatch(typeof(EventSystem), "current", MethodType.Setter)]
public class PATCH_EventSystem_current
{
[HarmonyPrefix]
public static void Prefix_EventSystem_set_current(ref EventSystem value)
{
CursorUnlocker.Prefix_EventSystem_set_current(ref value);
}
}
[HarmonyPatch(typeof(Cursor), "lockState", MethodType.Setter)]
public class PATCH_Cursor_lockState
{
[HarmonyPrefix]
public static void Prefix_set_lockState(ref CursorLockMode value)
{
CursorUnlocker.Prefix_set_lockState(ref value);
}
}
[HarmonyPatch(typeof(Cursor), "visible", MethodType.Setter)]
public class PATCH_Cursor_visible
{
[HarmonyPrefix]
public static void Prefix_set_visible(ref bool value)
{
CursorUnlocker.Prefix_set_visible(ref value);
}
}
} }
} }
#endif #endif

View File

@ -10,7 +10,7 @@ using UnityExplorer.Core.Runtime;
using UnityExplorer.Core; using UnityExplorer.Core;
using UnityExplorer.UI.Utility; using UnityExplorer.UI.Utility;
using UnityExplorer.UI.InteractiveValues; using UnityExplorer.UI.InteractiveValues;
using UnityExplorer.UI.Main.Home.Inspectors.Reflection; using UnityExplorer.UI.Inspectors.Reflection;
namespace UnityExplorer.UI.CacheObject namespace UnityExplorer.UI.CacheObject
{ {
@ -86,7 +86,7 @@ namespace UnityExplorer.UI.CacheObject
{ {
try try
{ {
Type baseType = ReflectionUtility.GetType(IValue.Value) ?? FallbackType; Type baseType = ReflectionUtility.GetActualType(IValue.Value) ?? FallbackType;
if (!ReflectionProvider.Instance.IsReflectionSupported(baseType)) if (!ReflectionProvider.Instance.IsReflectionSupported(baseType))
throw new Exception("Type not supported with reflection"); throw new Exception("Type not supported with reflection");
@ -94,7 +94,7 @@ namespace UnityExplorer.UI.CacheObject
UpdateReflection(); UpdateReflection();
if (IValue.Value != null) if (IValue.Value != null)
IValue.Value = IValue.Value.Cast(ReflectionUtility.GetType(IValue.Value)); IValue.Value = IValue.Value.Cast(ReflectionUtility.GetActualType(IValue.Value));
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -55,7 +55,7 @@ namespace UnityExplorer.UI.CacheObject
// if the type has changed fundamentally, make a new interactivevalue for it // if the type has changed fundamentally, make a new interactivevalue for it
var type = value == null var type = value == null
? FallbackType ? FallbackType
: ReflectionUtility.GetType(value); : ReflectionUtility.GetActualType(value);
var ivalueType = InteractiveValue.GetIValueForType(type); var ivalueType = InteractiveValue.GetIValueForType(type);

View File

@ -7,7 +7,7 @@ using UnityEngine.UI;
using UnityExplorer.Core.Runtime; using UnityExplorer.Core.Runtime;
using UnityExplorer.UI.Utility; using UnityExplorer.UI.Utility;
namespace UnityExplorer.UI.Main.Home.Inspectors.GameObjects namespace UnityExplorer.UI.Inspectors.GameObjects
{ {
public class ChildList public class ChildList
{ {

View File

@ -8,7 +8,7 @@ using UnityExplorer.Core;
using UnityExplorer.Core.Runtime; using UnityExplorer.Core.Runtime;
using UnityExplorer.UI.Utility; using UnityExplorer.UI.Utility;
namespace UnityExplorer.UI.Main.Home.Inspectors.GameObjects namespace UnityExplorer.UI.Inspectors.GameObjects
{ {
public class ComponentList public class ComponentList
{ {
@ -75,7 +75,7 @@ namespace UnityExplorer.UI.Main.Home.Inspectors.GameObjects
var text = s_compListTexts[i]; var text = s_compListTexts[i];
text.text = SignatureHighlighter.ParseFullSyntax(ReflectionUtility.GetType(comp), true); text.text = SignatureHighlighter.ParseFullSyntax(ReflectionUtility.GetActualType(comp), true);
var toggle = s_compToggles[i]; var toggle = s_compToggles[i];
#if CPP #if CPP

View File

@ -8,7 +8,7 @@ using UnityExplorer.Core.Input;
using UnityExplorer.Core.Runtime; using UnityExplorer.Core.Runtime;
using UnityExplorer.Core.Unity; using UnityExplorer.Core.Unity;
namespace UnityExplorer.UI.Main.Home.Inspectors.GameObjects namespace UnityExplorer.UI.Inspectors.GameObjects
{ {
public class GameObjectControls public class GameObjectControls
{ {

View File

@ -7,7 +7,7 @@ using UnityEngine.UI;
using UnityExplorer.Core.Runtime; using UnityExplorer.Core.Runtime;
using UnityExplorer.Core.Unity; using UnityExplorer.Core.Unity;
namespace UnityExplorer.UI.Main.Home.Inspectors.GameObjects namespace UnityExplorer.UI.Inspectors.GameObjects
{ {
public class GameObjectInspector : InspectorBase public class GameObjectInspector : InspectorBase
{ {

View File

@ -11,6 +11,7 @@ using UnityExplorer.Core.Input;
using UnityExplorer.Core.Runtime; using UnityExplorer.Core.Runtime;
using UnityExplorer.UI; using UnityExplorer.UI;
using UnityExplorer.UI.Main; using UnityExplorer.UI.Main;
using UnityExplorer.UI.Inspectors;
namespace UnityExplorer.UI.Main.Home namespace UnityExplorer.UI.Main.Home
{ {

View File

@ -3,7 +3,7 @@ using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.Core.Unity; using UnityExplorer.Core.Unity;
namespace UnityExplorer.UI.Main.Home.Inspectors namespace UnityExplorer.UI.Inspectors
{ {
public abstract class InspectorBase public abstract class InspectorBase
{ {

View File

@ -9,12 +9,11 @@ using UnityEngine.SceneManagement;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.Core.Runtime; using UnityExplorer.Core.Runtime;
using UnityExplorer.UI.Main.Home; using UnityExplorer.UI.Main.Home;
using UnityExplorer.UI.Main.Home.Inspectors;
using UnityExplorer.UI.CacheObject; using UnityExplorer.UI.CacheObject;
using UnityExplorer.UI.Main.Home.Inspectors.GameObjects; using UnityExplorer.UI.Inspectors.GameObjects;
using UnityExplorer.UI.Main.Home.Inspectors.Reflection; using UnityExplorer.UI.Inspectors.Reflection;
namespace UnityExplorer.UI.Main.Home namespace UnityExplorer.UI.Inspectors
{ {
public class InspectorManager public class InspectorManager
{ {

View File

@ -9,7 +9,7 @@ using UnityExplorer.Core;
using UnityExplorer.Core.Config; using UnityExplorer.Core.Config;
using UnityExplorer.Core.Runtime; using UnityExplorer.Core.Runtime;
namespace UnityExplorer.UI.Main.Home.Inspectors.Reflection namespace UnityExplorer.UI.Inspectors.Reflection
{ {
public enum MemberScopes public enum MemberScopes
{ {

View File

@ -9,9 +9,11 @@ using UnityExplorer.Core;
using UnityExplorer.Core.Config; using UnityExplorer.Core.Config;
using UnityExplorer.Core.Runtime; using UnityExplorer.Core.Runtime;
using UnityExplorer.UI.CacheObject; using UnityExplorer.UI.CacheObject;
using UnityExplorer.UI.Main;
using UnityExplorer.UI.Main.Home;
using UnityExplorer.UI.Utility; using UnityExplorer.UI.Utility;
namespace UnityExplorer.UI.Main.Home.Inspectors.Reflection namespace UnityExplorer.UI.Inspectors.Reflection
{ {
public class ReflectionInspector : InspectorBase public class ReflectionInspector : InspectorBase
{ {
@ -78,7 +80,7 @@ namespace UnityExplorer.UI.Main.Home.Inspectors.Reflection
if (this is StaticInspector) if (this is StaticInspector)
m_targetType = target as Type; m_targetType = target as Type;
else else
m_targetType = ReflectionUtility.GetType(target); m_targetType = ReflectionUtility.GetActualType(target);
m_targetTypeShortName = SignatureHighlighter.ParseFullSyntax(m_targetType, false); m_targetTypeShortName = SignatureHighlighter.ParseFullSyntax(m_targetType, false);

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
namespace UnityExplorer.UI.Main.Home.Inspectors.Reflection namespace UnityExplorer.UI.Inspectors.Reflection
{ {
public class StaticInspector : ReflectionInspector public class StaticInspector : ReflectionInspector
{ {

View File

@ -218,32 +218,37 @@ namespace UnityExplorer.UI.InteractiveValues
private IDictionary EnumerateWithReflection() private IDictionary EnumerateWithReflection()
{ {
var valueType = ReflectionUtility.GetType(Value); var valueType = ReflectionUtility.GetActualType(Value);
// get keys and values
var keys = valueType.GetProperty("Keys").GetValue(Value, null);
var values = valueType.GetProperty("Values").GetValue(Value, null);
// create lists to hold them
var keyList = new List<object>(); var keyList = new List<object>();
var valueList = new List<object>(); var valueList = new List<object>();
// store entries with reflection var hashtable = Value.Cast(typeof(Il2CppSystem.Collections.Hashtable)) as Il2CppSystem.Collections.Hashtable;
EnumerateCollection(keys, keyList);
EnumerateCollection(values, valueList);
// make actual mono dictionary if (hashtable != null)
var dict = (IDictionary)Activator.CreateInstance(typeof(Dictionary<,>) {
.MakeGenericType(m_typeOfKeys, m_typeofValues)); EnumerateCppHashtable(hashtable, keyList, valueList);
}
else
{
var keys = valueType.GetProperty("Keys").GetValue(Value, null);
var values = valueType.GetProperty("Values").GetValue(Value, null);
EnumerateCppIDictionary(keys, keyList);
EnumerateCppIDictionary(values, valueList);
}
var dict = Activator.CreateInstance(typeof(Dictionary<,>)
.MakeGenericType(m_typeOfKeys, m_typeofValues))
as IDictionary;
// finally iterate into mono dictionary
for (int i = 0; i < keyList.Count; i++) for (int i = 0; i < keyList.Count; i++)
dict.Add(keyList[i], valueList[i]); dict.Add(keyList[i], valueList[i]);
return dict; return dict;
} }
private void EnumerateCollection(object collection, List<object> list) private void EnumerateCppIDictionary(object collection, List<object> list)
{ {
// invoke GetEnumerator // invoke GetEnumerator
var enumerator = collection.GetType().GetMethod("GetEnumerator").Invoke(collection, null); var enumerator = collection.GetType().GetMethod("GetEnumerator").Invoke(collection, null);
@ -258,11 +263,23 @@ namespace UnityExplorer.UI.InteractiveValues
list.Add(current.GetValue(enumerator, null)); list.Add(current.GetValue(enumerator, null));
} }
} }
private void EnumerateCppHashtable(Il2CppSystem.Collections.Hashtable hashtable, List<object> keys, List<object> values)
{
for (int i = 0; i < hashtable.buckets.Count; i++)
{
var bucket = hashtable.buckets[i];
if (bucket == null || bucket.key == null)
continue;
keys.Add(bucket.key);
values.Add(bucket.val);
}
}
#endif #endif
#endregion #endregion
#region UI CONSTRUCTION #region UI CONSTRUCTION
internal GameObject m_listContent; internal GameObject m_listContent;
internal LayoutElement m_listLayout; internal LayoutElement m_listLayout;

View File

@ -6,6 +6,7 @@ using System.Reflection;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.Core;
using UnityExplorer.Core.Config; using UnityExplorer.Core.Config;
using UnityExplorer.Core.Unity; using UnityExplorer.Core.Unity;
using UnityExplorer.UI; using UnityExplorer.UI;
@ -38,11 +39,11 @@ namespace UnityExplorer.UI.InteractiveValues
internal IEnumerable RefIEnumerable; internal IEnumerable RefIEnumerable;
internal IList RefIList; internal IList RefIList;
#if CPP //#if CPP
internal Il2CppSystem.Collections.ICollection CppICollection; // internal object CppICollection;
#else //#else
internal ICollection CppICollection = null; // internal object CppICollection = null;
#endif //#endif
internal readonly Type m_baseEntryType; internal readonly Type m_baseEntryType;
@ -55,13 +56,17 @@ namespace UnityExplorer.UI.InteractiveValues
RefIEnumerable = Value as IEnumerable; RefIEnumerable = Value as IEnumerable;
RefIList = Value as IList; RefIList = Value as IList;
#if CPP //#if CPP
if (Value != null && RefIList == null) // if (Value != null && RefIList == null)
{ // {
try { CppICollection = (Value as Il2CppSystem.Object).TryCast<Il2CppSystem.Collections.ICollection>(); } // try
catch { } // {
} // var type = typeof(Il2CppSystem.Collections.ICollection).MakeGenericType(this.m_baseEntryType);
#endif // CppICollection = (Value as Il2CppSystem.Object).Cast(type);
// }
// catch { }
// }
//#endif
if (m_subContentParent.activeSelf) if (m_subContentParent.activeSelf)
{ {
@ -91,8 +96,8 @@ namespace UnityExplorer.UI.InteractiveValues
if (Value != null) if (Value != null)
{ {
string count = "?"; string count = "?";
if (m_recacheWanted && (RefIList != null || CppICollection != null)) if (m_recacheWanted && RefIList != null)// || CppICollection != null))
count = RefIList?.Count.ToString() ?? CppICollection.Count.ToString(); count = RefIList.Count.ToString();// ?? CppICollection.Count.ToString();
else if (!m_recacheWanted) else if (!m_recacheWanted)
count = m_entries.Count.ToString(); count = m_entries.Count.ToString();

View File

@ -9,6 +9,7 @@ using UnityExplorer.Core.Unity;
using UnityExplorer.UI; using UnityExplorer.UI;
using UnityExplorer.UI.Utility; using UnityExplorer.UI.Utility;
using UnityExplorer.UI.CacheObject; using UnityExplorer.UI.CacheObject;
using UnityExplorer.Core.Runtime;
namespace UnityExplorer.UI.InteractiveValues namespace UnityExplorer.UI.InteractiveValues
{ {
@ -23,6 +24,14 @@ namespace UnityExplorer.UI.InteractiveValues
public override void OnValueUpdated() public override void OnValueUpdated()
{ {
#if CPP
// strings boxed as Il2CppSystem.Objects can behave weirdly.
// GetActualType will find they are a string, but if its boxed
// then we need to unbox it like this...
if (!(Value is string) && Value is Il2CppSystem.Object cppobj)
Value = cppobj.ToString();
#endif
base.OnValueUpdated(); base.OnValueUpdated();
} }
@ -88,10 +97,18 @@ namespace UnityExplorer.UI.InteractiveValues
m_labelLayout.flexibleWidth = 0; m_labelLayout.flexibleWidth = 0;
} }
internal void OnApplyClicked() internal void SetValueFromInput()
{ {
Value = m_valueInput.text; Value = m_valueInput.text;
if (!typeof(string).IsAssignableFrom(Owner.FallbackType))
ReflectionProvider.Instance.BoxStringToType(ref Value, Owner.FallbackType);
Owner.SetValue(); Owner.SetValue();
// revert back to string now
OnValueUpdated();
RefreshUIForValue(); RefreshUIForValue();
} }
@ -162,7 +179,7 @@ namespace UnityExplorer.UI.InteractiveValues
if (Owner.CanWrite) if (Owner.CanWrite)
{ {
var apply = UIFactory.CreateButton(groupObj, "ApplyButton", "Apply", OnApplyClicked, new Color(0.2f, 0.2f, 0.2f)); var apply = UIFactory.CreateButton(groupObj, "ApplyButton", "Apply", SetValueFromInput, new Color(0.2f, 0.2f, 0.2f));
UIFactory.SetLayoutElement(apply.gameObject, minWidth: 50, minHeight: 25, flexibleWidth: 0); UIFactory.SetLayoutElement(apply.gameObject, minWidth: 50, minHeight: 25, flexibleWidth: 0);
} }
else else

View File

@ -12,6 +12,7 @@ using UnityExplorer.UI;
using UnityExplorer.UI.Utility; using UnityExplorer.UI.Utility;
using UnityExplorer.UI.CacheObject; using UnityExplorer.UI.CacheObject;
using UnityExplorer.UI.Main.Home; using UnityExplorer.UI.Main.Home;
using UnityExplorer.UI.Inspectors;
namespace UnityExplorer.UI.InteractiveValues namespace UnityExplorer.UI.InteractiveValues
{ {
@ -66,7 +67,7 @@ namespace UnityExplorer.UI.InteractiveValues
public static InteractiveValue Create(object value, Type fallbackType) public static InteractiveValue Create(object value, Type fallbackType)
{ {
var type = ReflectionUtility.GetType(value) ?? fallbackType; var type = ReflectionUtility.GetActualType(value) ?? fallbackType;
var iType = GetIValueForType(type); var iType = GetIValueForType(type);
return (InteractiveValue)Activator.CreateInstance(iType, new object[] { value, type }); return (InteractiveValue)Activator.CreateInstance(iType, new object[] { value, type });

View File

@ -217,7 +217,6 @@ namespace UnityExplorer.UI.Main
{ {
LogUnity = val; LogUnity = val;
ConfigManager.Log_Unity_Debug.Value = val; ConfigManager.Log_Unity_Debug.Value = val;
ConfigManager.Handler.SaveConfig();
}); });
ConfigManager.Log_Unity_Debug.OnValueChanged += (bool val) => { unityToggle.isOn = val; }; ConfigManager.Log_Unity_Debug.OnValueChanged += (bool val) => { unityToggle.isOn = val; };

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.UI.Inspectors;
namespace UnityExplorer.UI.Main.Home namespace UnityExplorer.UI.Main.Home
{ {

View File

@ -13,6 +13,7 @@ using UnityExplorer.UI.Utility;
using UnityExplorer.UI.Main.Search; using UnityExplorer.UI.Main.Search;
using System.IO; using System.IO;
using UnityExplorer.Core; using UnityExplorer.Core;
using UnityExplorer.UI.Inspectors;
namespace UnityExplorer.UI.Main.Home namespace UnityExplorer.UI.Main.Home
{ {

View File

@ -10,6 +10,7 @@ using UnityExplorer.Core;
using UnityExplorer.UI.Utility; using UnityExplorer.UI.Utility;
using UnityExplorer.Core.Search; using UnityExplorer.Core.Search;
using UnityExplorer.UI.Main.Home; using UnityExplorer.UI.Main.Home;
using UnityExplorer.UI.Inspectors;
namespace UnityExplorer.UI.Main.Search namespace UnityExplorer.UI.Main.Search
{ {
@ -129,7 +130,7 @@ namespace UnityExplorer.UI.Main.Search
if (m_context != SearchContext.StaticClass) if (m_context != SearchContext.StaticClass)
{ {
var name = SignatureHighlighter.ParseFullSyntax(ReflectionUtility.GetType(obj), true); var name = SignatureHighlighter.ParseFullSyntax(ReflectionUtility.GetActualType(obj), true);
if (unityObj && m_context != SearchContext.Singleton) if (unityObj && m_context != SearchContext.Singleton)
{ {

View File

@ -246,6 +246,7 @@
<Compile Include="Core\Search\SceneFilter.cs" /> <Compile Include="Core\Search\SceneFilter.cs" />
<Compile Include="Core\Search\SearchContext.cs" /> <Compile Include="Core\Search\SearchContext.cs" />
<Compile Include="Core\Search\SearchProvider.cs" /> <Compile Include="Core\Search\SearchProvider.cs" />
<Compile Include="Core\TestClass.cs" />
<Compile Include="Core\Unity\UnityHelpers.cs" /> <Compile Include="Core\Unity\UnityHelpers.cs" />
<Compile Include="Loader\BIE\BepInExConfigHandler.cs" /> <Compile Include="Loader\BIE\BepInExConfigHandler.cs" />
<Compile Include="Loader\BIE\ExplorerBepInPlugin.cs" /> <Compile Include="Loader\BIE\ExplorerBepInPlugin.cs" />
@ -286,16 +287,16 @@
<Compile Include="UI\Main\CSConsole\Lexer\SymbolMatch.cs" /> <Compile Include="UI\Main\CSConsole\Lexer\SymbolMatch.cs" />
<Compile Include="UI\Main\DebugConsole.cs" /> <Compile Include="UI\Main\DebugConsole.cs" />
<Compile Include="UI\Main\Home\HomePage.cs" /> <Compile Include="UI\Main\Home\HomePage.cs" />
<Compile Include="UI\Main\Home\InspectorManager.cs" /> <Compile Include="UI\Inspectors\InspectorManager.cs" />
<Compile Include="UI\Main\Home\Inspectors\GameObjects\ChildList.cs" /> <Compile Include="UI\Inspectors\GameObjects\ChildList.cs" />
<Compile Include="UI\Main\Home\Inspectors\GameObjects\ComponentList.cs" /> <Compile Include="UI\Inspectors\GameObjects\ComponentList.cs" />
<Compile Include="UI\Main\Home\Inspectors\GameObjects\GameObjectControls.cs" /> <Compile Include="UI\Inspectors\GameObjects\GameObjectControls.cs" />
<Compile Include="UI\Main\Home\Inspectors\GameObjects\GameObjectInspector.cs" /> <Compile Include="UI\Inspectors\GameObjects\GameObjectInspector.cs" />
<Compile Include="UI\Main\Home\Inspectors\InspectorBase.cs" /> <Compile Include="UI\Inspectors\InspectorBase.cs" />
<Compile Include="UI\Main\Home\Inspectors\Reflection\InstanceInspector.cs" /> <Compile Include="UI\Inspectors\Reflection\InstanceInspector.cs" />
<Compile Include="UI\Main\Home\Inspectors\Reflection\ReflectionInspector.cs" /> <Compile Include="UI\Inspectors\Reflection\ReflectionInspector.cs" />
<Compile Include="UI\Main\Home\Inspectors\Reflection\StaticInspector.cs" /> <Compile Include="UI\Inspectors\Reflection\StaticInspector.cs" />
<Compile Include="UI\Main\Home\InspectUnderMouse.cs" /> <Compile Include="UI\Inspectors\InspectUnderMouse.cs" />
<Compile Include="UI\Main\Home\SceneExplorer.cs" /> <Compile Include="UI\Main\Home\SceneExplorer.cs" />
<Compile Include="UI\Main\MainMenu.cs" /> <Compile Include="UI\Main\MainMenu.cs" />
<Compile Include="UI\Main\Options\OptionsPage.cs" /> <Compile Include="UI\Main\Options\OptionsPage.cs" />