Compare commits

...

12 Commits

Author SHA1 Message Date
59c5b13a05 1.8.3.1 2020-10-05 20:25:51 +11:00
b8b6cc1605 1.8.0.1
* Added some internal caching for Enum Names, should vastly improve speed when inspecting certain classes (worst case scenario I found went from over 50 seconds to less than 1 second).
* ILRepack is now done as part of the build process, should simplify things if you are building the project yourself.
2020-10-05 20:25:25 +11:00
912b1b80ff using ILRepack MSBuild task, adding some base libs 2020-10-05 18:32:38 +11:00
6a9c64c2a1 Update README for new build process 2020-10-04 20:48:08 +11:00
54deecd312 Update README.md 2020-10-04 20:11:05 +11:00
403943a41f Update README.md 2020-10-04 20:09:45 +11:00
e7aa01ebc8 1.8.3
* Merging `mcs.dll` into the main `Explorer.dll` file, no longer needs to be in the Mods / Plugins folder.
2020-10-04 19:01:39 +11:00
bf6d526284 1.8.23
* Fixed an issue in Mono games when the target you are inspecting is destroyed (window would not close as it should).
* Cleaned up and refactored the Input support so it's easier to manage.
2020-10-03 20:19:44 +10:00
c991cb4b22 1.8.22
* Some performance improvements for the new InputSystem support (affects some 2019.3+ games)
* Fixed a small mistake with left/right mouse button checking.
2020-10-02 18:40:51 +10:00
3971e49ce1 Update README.md 2020-10-01 20:41:48 +10:00
6920ca1129 Update README.md 2020-10-01 20:26:25 +10:00
748e0cabcb 1.8.21
* Fixed a bug when editing a Text Field and the input string is `null`. Only affected Il2Cpp games, appeared in 1.8.0.
* Added a menu page for editing the Explorer Settings in-game, called `Options`.
* Added a new setting for default Items per Page Limit (for all "Pages" in Explorer).
2020-10-01 20:20:52 +10:00
32 changed files with 480 additions and 298 deletions

View File

@ -45,14 +45,14 @@ Requires [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) to be ins
1. Download the relevant <b>Explorer_MelonLoader_.zip</b> from above.
2. Unzip the file into the `Mods` folder in your game's installation directory, created by MelonLoader.
3. Make sure it's not in a sub-folder, `Explorer.dll` and `mcs.dll` should be directly in the `Mods\` folder.
3. Make sure it's not in a sub-folder, `Explorer.dll` should be directly in the `Mods\` folder.
### BepInEx
Requires [BepInEx](https://github.com/BepInEx/BepInEx) to be installed for your game.
1. Download the relevant <b>Explorer_BepInEx_.zip</b> from above.
2. Unzip the file into the `BepInEx\plugins\` folder in your game's installation directory, created by BepInEx.
3. Make sure it's not in a sub-folder, `Explorer.dll` and `mcs.dll` should be directly in the `plugins\` folder.
3. Make sure it's not in a sub-folder, `Explorer.dll` should be directly in the `plugins\` folder.
## How to use
@ -62,20 +62,22 @@ Requires [BepInEx](https://github.com/BepInEx/BepInEx) to be installed for your
### Mod Config
There is a simple Mod Config for the Explorer, which is generated the first time you run it.
There is a simple Mod Config for the Explorer. You can access the settings via the "Options" page of the main menu.
This config is generated to `[Game_Directory]\Mods\Explorer\config.xml`. Edit the config while the game is closed if you wish to change it.
`Main_Menu_Toggle` (KeyCode)
`Main Menu Toggle` (KeyCode)
* Sets the keybinding for the Main Menu toggle (show/hide all Explorer windows)
* See [this article](https://docs.unity3d.com/ScriptReference/KeyCode.html) for a full list of all accepted KeyCodes.
* Default: `F7`
`Default_Window_Size` (Vector2)
`Default Window Size` (Vector2)
* Sets the default width and height for all Explorer windows when created.
* `x` is width, `y` is height.
* Default: `<x>550</x> <y>700</y>`
`Default Items per Page` (Int)
* Sets the default items per page when viewing lists or search results.
* Default: `20`
## Features
### Scene Explorer
@ -145,14 +147,15 @@ public class MenuClass_CursorUpdate
## Building
If you'd like to build this yourself, everything you need (other than MelonLoader) is included with this repository, there is no need for recursive cloning etc.
If you'd like to build this yourself, you will need to have installed BepInEx and/or MelonLoader for at least one Unity game. If you want to build all 6 versions, you will need at least one Il2Cpp and one Mono game, with BepInEx and MelonLoader installed for both.
1. Install MelonLoader for your game.
1. Install MelonLoader or BepInEx for your game.
2. Open the `src\Explorer.csproj` file in a text editor.
3. Set the relevant `GameFolder` value(s) for the version(s) you want to build, eg. set `MLCppGameFolder` if you want to build for a MelonLoader Il2Cpp game.
3. Set the relevant `GameFolder` values for the versions you want to build, eg. set `MLCppGameFolder` if you want to build for a MelonLoader Il2Cpp game.
4. Open the `src\Explorer.sln` project.
5. Select `Solution 'Explorer' (1 of 1 project)` in the Solution Explorer panel, and set the <b>Active config</b> to the version you want to build, then build it.
5. Select `Solution 'Explorer' (1 of 1 project)` in the Solution Explorer panel, and set the <b>Active config</b> property to the version you want to build, then build it.
5. The DLLs are built to the `Release\` folder in the root of the repository.
6. If ILRepack fails or is missing, use the NuGet package manager to re-install `ILRepack.Lib.MSBuild.Task`, then re-build.
## Credits

BIN
lib/0Harmony.dll Normal file

Binary file not shown.

BIN
lib/BepInEx.Core.dll Normal file

Binary file not shown.

BIN
lib/BepInEx.IL2CPP.dll Normal file

Binary file not shown.

BIN
lib/BepInEx.dll Normal file

Binary file not shown.

Binary file not shown.

View File

@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
#if CPP
using UnhollowerBaseLib;
@ -15,8 +16,8 @@ namespace Explorer
public PageHelper Pages = new PageHelper();
private CacheObjectBase[] m_cachedKeys;
private CacheObjectBase[] m_cachedValues;
private CacheObjectBase[] m_cachedKeys = new CacheObjectBase[0];
private CacheObjectBase[] m_cachedValues = new CacheObjectBase[0];
public Type TypeOfKeys
{
@ -119,6 +120,11 @@ namespace Explorer
base.UpdateValue();
CacheEntries();
}
public void CacheEntries()
{
// reset
IDict = null;
@ -190,8 +196,6 @@ namespace Explorer
var whitespace = CalcWhitespace(window);
int count = m_cachedKeys.Length;
if (!IsExpanded)
{
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
@ -209,6 +213,8 @@ namespace Explorer
var negativeWhitespace = window.width - (whitespace + 100f);
int count = m_cachedKeys.Length;
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
string btnLabel = $"[{count}] <color=#2df7b2>Dictionary<{TypeOfKeys.FullName}, {TypeOfValues.FullName}></color>";
if (GUILayout.Button(btnLabel, new GUILayoutOption[] { GUILayout.Width(negativeWhitespace) }))
@ -260,20 +266,27 @@ namespace Explorer
//GUIUnstrip.Space(whitespace);
if (key == null || val == null)
if (key == null && val == null)
{
GUILayout.Label($"[{i}] <i><color=grey>(null)</color></i>", new GUILayoutOption[0]);
}
else
{
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
GUILayout.Label($"[{i}]", new GUILayoutOption[] { GUILayout.Width(30) });
GUILayout.Label($"[{i}]", new GUILayoutOption[] { GUILayout.Width(40) });
GUI.skin.label.alignment = TextAnchor.MiddleLeft;
GUILayout.Label("Key:", new GUILayoutOption[] { GUILayout.Width(40) });
key.DrawValue(window, (window.width / 2) - 80f);
if (key != null)
key.DrawValue(window, (window.width / 2) - 80f);
else
GUILayout.Label("<i>null</i>", new GUILayoutOption[0]);
GUILayout.Label("Value:", new GUILayoutOption[] { GUILayout.Width(40) });
val.DrawValue(window, (window.width / 2) - 80f);
if (Value != null)
val.DrawValue(window, (window.width / 2) - 80f);
else
GUILayout.Label("<i>null</i>", new GUILayoutOption[0]);
}
}

View File

@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Reflection;
using UnityEngine;
@ -13,7 +14,7 @@ namespace Explorer
public PageHelper Pages = new PageHelper();
private CacheObjectBase[] m_cachedEntries;
private CacheObjectBase[] m_cachedEntries = new CacheObjectBase[0];
// Type of Entries in the Array
public Type EntryType
@ -218,6 +219,11 @@ namespace Explorer
return;
}
CacheEntries();
}
public void CacheEntries()
{
var enumerator = Enumerable.GetEnumerator();
if (enumerator == null)
{
@ -276,8 +282,6 @@ namespace Explorer
var whitespace = CalcWhitespace(window);
int count = m_cachedEntries.Length;
if (!IsExpanded)
{
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
@ -295,6 +299,8 @@ namespace Explorer
var negativeWhitespace = window.width - (whitespace + 100f);
int count = m_cachedEntries.Length;
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
string btnLabel = $"[{count}] <color=#2df7b2>{EntryType.FullName}</color>";
if (GUILayout.Button(btnLabel, new GUILayoutOption[] { GUILayout.Width(negativeWhitespace) }))

View File

@ -9,6 +9,8 @@ namespace Explorer
{
public class CacheEnum : CacheObjectBase
{
internal static Dictionary<Type, string[]> EnumNamesInternalCache = new Dictionary<Type, string[]>();
// public Type EnumType;
public string[] EnumNames = new string[0];
@ -21,18 +23,7 @@ namespace Explorer
if (ValueType != null)
{
// using GetValues not GetNames, to catch instances of weird enums (eg CameraClearFlags)
var values = Enum.GetValues(ValueType);
var list = new List<string>();
foreach (var value in values)
{
var v = value.ToString();
if (list.Contains(v)) continue;
list.Add(v);
}
EnumNames = list.ToArray();
GetNames();
}
else
{
@ -40,6 +31,27 @@ namespace Explorer
}
}
internal void GetNames()
{
if (!EnumNamesInternalCache.ContainsKey(ValueType))
{
// using GetValues not GetNames, to catch instances of weird enums (eg CameraClearFlags)
var values = Enum.GetValues(ValueType);
var set = new HashSet<string>();
foreach (var value in values)
{
var v = value.ToString();
if (set.Contains(v)) continue;
set.Add(v);
}
EnumNamesInternalCache.Add(ValueType, set.ToArray());
}
EnumNames = EnumNamesInternalCache[ValueType];
}
public override void DrawValue(Rect window, float width)
{
if (CanWrite)

View File

@ -15,6 +15,7 @@ namespace Explorer
public KeyCode Main_Menu_Toggle = KeyCode.F7;
public Vector2 Default_Window_Size = new Vector2(550, 700);
public int Default_Page_Limit = 20;
public static void OnLoad()
{

View File

@ -27,14 +27,14 @@
<AssemblyName>Explorer</AssemblyName>
<!-- Set this to the MelonLoader Il2Cpp Game folder, without the ending '\' character. -->
<MLCppGameFolder>D:\Steam\steamapps\common\Hellpoint</MLCppGameFolder>
<!--<MLCppGameFolder>D:\source\Unity Projects\Test\_BUILD</MLCppGameFolder>-->
<!-- Set this to the MelonLoader Mono Game folder, without the ending '\' character. -->
<MLMonoGameFolder>D:\Steam\steamapps\common\Outward</MLMonoGameFolder>
<!-- Set this to the BepInEx Il2Cpp Game folder, without the ending '\' character. -->
<BIECppGameFolder>D:\Steam\steamapps\common\Outward - Il2Cpp</BIECppGameFolder>
<BIECppGameFolder>D:\Steam\steamapps\common\Outward_Il2Cpp</BIECppGameFolder>
<!-- Set this to the BepInEx Mono Game folder, without the ending '\' character. -->
<BIEMonoGameFolder>D:\Steam\steamapps\common\Outward</BIEMonoGameFolder>
<!-- <BIEMonoGameFolder>D:\source\Unity Projects\! My Unity Games\NewInputSystemTest\_BUILD</BIEMonoGameFolder> -->
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release_ML_Cpp|AnyCPU' ">
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
@ -95,11 +95,11 @@
<!-- MCS ref -->
<Reference Include="mcs" Condition="'$(IsNet35)'=='false'">
<HintPath>..\lib\mcs.dll</HintPath>
<Private>True</Private>
<Private>False</Private>
</Reference>
<Reference Include="mcs" Condition="'$(IsNet35)'=='true'">
<HintPath>..\lib\mcs.NET35.dll</HintPath>
<Private>True</Private>
<Private>False</Private>
</Reference>
</ItemGroup>
<!-- Universal Mono UnityEngine.dll ref (v5.3) -->
@ -241,8 +241,12 @@
<Compile Include="ExplorerBepInPlugin.cs" />
<Compile Include="ExplorerMelonMod.cs" />
<Compile Include="Extensions\ReflectionExtensions.cs" />
<Compile Include="Helpers\InputHelper.cs" />
<Compile Include="Input\AbstractInput.cs" />
<Compile Include="Input\InputManager.cs" />
<Compile Include="Input\InputSystem.cs" />
<Compile Include="Input\LegacyInput.cs" />
<Compile Include="Menu\CursorControl.cs" />
<Compile Include="Menu\MainMenu\Pages\OptionsPage.cs" />
<Compile Include="Tests\TestClass.cs" />
<Compile Include="UnstripFixes\GUIUnstrip.cs" />
<Compile Include="UnstripFixes\Internal_LayoutUtility.cs" />
@ -273,5 +277,16 @@
<Compile Include="UnstripFixes\Internal.cs" />
<Compile Include="UnstripFixes\Internal_SliderState.cs" />
</ItemGroup>
<ItemGroup>
<None Include="ILRepack.targets" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="packages\ILRepack.Lib.MSBuild.Task.2.0.18.1\build\ILRepack.Lib.MSBuild.Task.targets" Condition="Exists('packages\ILRepack.Lib.MSBuild.Task.2.0.18.1\build\ILRepack.Lib.MSBuild.Task.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('packages\ILRepack.Lib.MSBuild.Task.2.0.18.1\build\ILRepack.Lib.MSBuild.Task.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\ILRepack.Lib.MSBuild.Task.2.0.18.1\build\ILRepack.Lib.MSBuild.Task.targets'))" />
</Target>
</Project>

View File

@ -62,24 +62,11 @@ namespace Explorer
SceneManager.activeSceneChanged += DoSceneChange;
#endif
LoadMCS();
new ExplorerCore();
//HarmonyInstance.PatchAll();
}
void LoadMCS()
{
#if NET35
var path = @"BepInEx\plugins\mcs.NET35.dll";
#else
var path = @"BepInEx\plugins\mcs.dll";
#endif
Assembly.Load(File.ReadAllBytes(path));
ExplorerCore.Log("Loaded mcs!");
}
internal static void DoSceneChange(Scene arg0, Scene arg1)
{
ExplorerCore.OnSceneChange();

View File

@ -5,7 +5,7 @@ namespace Explorer
public class ExplorerCore
{
public const string NAME = "Explorer (" + PLATFORM + ", " + MODLOADER + ")";
public const string VERSION = "1.8.2";
public const string VERSION = "1.8.3.1";
public const string AUTHOR = "Sinai";
public const string GUID = "com.sinai.explorer";
@ -33,7 +33,7 @@ namespace Explorer
new MainMenu();
new WindowManager();
InputHelper.Init();
InputManager.Init();
CursorControl.Init();
Log($"{NAME} {VERSION} initialized.");
@ -54,7 +54,7 @@ namespace Explorer
public static void Update()
{
if (InputHelper.GetKeyDown(ModConfig.Instance.Main_Menu_Toggle))
if (InputManager.GetKeyDown(ModConfig.Instance.Main_Menu_Toggle))
{
ShowMenu = !ShowMenu;
}

View File

@ -1,222 +0,0 @@
using System;
using System.Reflection;
using UnityEngine;
namespace Explorer
{
/// <summary>
/// Version-agnostic Input module using Reflection.
/// </summary>
public static class InputHelper
{
// If Input module failed to load at all
public static bool NO_INPUT;
// If using new InputSystem module
public static bool USING_NEW_INPUT;
// Cached Types
private static Type TInput => _input ?? (_input = ReflectionHelpers.GetTypeByName("UnityEngine.Input"));
private static Type _input;
private static Type TKeyboard => _keyboardSys ?? (_keyboardSys = ReflectionHelpers.GetTypeByName("UnityEngine.InputSystem.Keyboard"));
private static Type _keyboardSys;
private static Type TMouse => _mouseSys ?? (_mouseSys = ReflectionHelpers.GetTypeByName("UnityEngine.InputSystem.Mouse"));
private static Type _mouseSys;
private static Type TKey => _key ?? (_key = ReflectionHelpers.GetTypeByName("UnityEngine.InputSystem.Key"));
private static Type _key;
// Cached member infos (new system)
private static PropertyInfo _keyboardCurrent;
private static PropertyInfo _kbItemProp;
private static PropertyInfo _isPressed;
private static PropertyInfo _wasPressedThisFrame;
private static PropertyInfo _mouseCurrent;
private static PropertyInfo _leftButton;
private static PropertyInfo _rightButton;
private static PropertyInfo _position;
private static MethodInfo _readValueMethod;
// Cached member infos (legacy)
private static PropertyInfo _mousePosition;
private static MethodInfo _getKey;
private static MethodInfo _getKeyDown;
private static MethodInfo _getMouseButton;
private static MethodInfo _getMouseButtonDown;
public static void Init()
{
if (TKeyboard != null || TryManuallyLoadNewInput())
{
InitNewInput();
return;
}
if (TInput != null || TryManuallyLoadLegacyInput())
{
InitLegacyInput();
return;
}
ExplorerCore.LogWarning("Could not find any Input module!");
NO_INPUT = true;
}
private static void InitNewInput()
{
ExplorerCore.Log("Initializing new InputSystem support...");
USING_NEW_INPUT = true;
_keyboardCurrent = TKeyboard.GetProperty("current");
_kbItemProp = TKeyboard.GetProperty("Item", new Type[] { TKey });
var btnControl = ReflectionHelpers.GetTypeByName("UnityEngine.InputSystem.Controls.ButtonControl");
_isPressed = btnControl.GetProperty("isPressed");
_wasPressedThisFrame = btnControl.GetProperty("wasPressedThisFrame");
_mouseCurrent = TMouse.GetProperty("current");
_leftButton = TMouse.GetProperty("leftButton");
_rightButton = TMouse.GetProperty("rightButton");
_position = ReflectionHelpers.GetTypeByName("UnityEngine.InputSystem.Pointer")
.GetProperty("position");
_readValueMethod = ReflectionHelpers.GetTypeByName("UnityEngine.InputSystem.InputControl`1")
.MakeGenericType(typeof(Vector2))
.GetMethod("ReadValue");
}
private static void InitLegacyInput()
{
ExplorerCore.Log("Initializing Legacy Input support...");
_mousePosition = TInput.GetProperty("mousePosition");
_getKey = TInput.GetMethod("GetKey", new Type[] { typeof(KeyCode) });
_getKeyDown = TInput.GetMethod("GetKeyDown", new Type[] { typeof(KeyCode) });
_getMouseButton = TInput.GetMethod("GetMouseButton", new Type[] { typeof(int) });
_getMouseButtonDown = TInput.GetMethod("GetMouseButtonDown", new Type[] { typeof(int) });
}
private static bool TryManuallyLoadNewInput()
{
if (ReflectionHelpers.LoadModule("Unity.InputSystem") && TKeyboard != null)
{
ExplorerCore.Log("Loaded new InputSystem module!");
return true;
}
else
{
return false;
}
}
private static bool TryManuallyLoadLegacyInput()
{
if ((ReflectionHelpers.LoadModule("UnityEngine.InputLegacyModule") || ReflectionHelpers.LoadModule("UnityEngine.CoreModule"))
&& TInput != null)
{
ExplorerCore.Log("Loaded legacy InputModule!");
return true;
}
else
{
return false;
}
}
public static Vector3 MousePosition
{
get
{
if (NO_INPUT) return Vector3.zero;
if (USING_NEW_INPUT)
{
var mouse = _mouseCurrent.GetValue(null, null);
var pos = _position.GetValue(mouse, null);
return (Vector2)_readValueMethod.Invoke(pos, new object[0]);
}
return (Vector3)_mousePosition.GetValue(null, null);
}
}
public static bool GetKeyDown(KeyCode key)
{
if (NO_INPUT) return false;
if (USING_NEW_INPUT)
{
var parsed = Enum.Parse(TKey, key.ToString());
var currentKB = _keyboardCurrent.GetValue(null, null);
var actualKey = _kbItemProp.GetValue(currentKB, new object[] { parsed });
return (bool)_wasPressedThisFrame.GetValue(actualKey, null);
}
return (bool)_getKeyDown.Invoke(null, new object[] { key });
}
public static bool GetKey(KeyCode key)
{
if (NO_INPUT) return false;
if (USING_NEW_INPUT)
{
var parsed = Enum.Parse(TKey, key.ToString());
var currentKB = _keyboardCurrent.GetValue(null, null);
var actualKey = _kbItemProp.GetValue(currentKB, new object[] { parsed });
return (bool)_isPressed.GetValue(actualKey, null);
}
return (bool)_getKey.Invoke(null, new object[] { key });
}
/// <param name="btn">0/1 = left, 2 = middle, 3 = right, etc</param>
public static bool GetMouseButtonDown(int btn)
{
if (NO_INPUT) return false;
if (USING_NEW_INPUT)
{
var mouse = _mouseCurrent.GetValue(null, null);
PropertyInfo btnProp;
if (btn < 2) btnProp = _leftButton;
else btnProp = _rightButton;
var actualBtn = btnProp.GetValue(mouse, null);
return (bool)_wasPressedThisFrame.GetValue(actualBtn, null);
}
return (bool)_getMouseButtonDown.Invoke(null, new object[] { btn });
}
/// <param name="btn">1 = left, 2 = middle, 3 = right, etc</param>
public static bool GetMouseButton(int btn)
{
if (NO_INPUT) return false;
if (USING_NEW_INPUT)
{
var mouse = _mouseCurrent.GetValue(null, null);
PropertyInfo btnProp;
if (btn < 2) btnProp = _leftButton;
else btnProp = _rightButton;
var actualBtn = btnProp.GetValue(mouse, null);
return (bool)_isPressed.GetValue(actualBtn, null);
}
return (bool)_getMouseButton.Invoke(null, new object[] { btn });
}
}
}

View File

@ -21,7 +21,7 @@ namespace Explorer
CalculateMaxOffset();
}
}
private int m_itemsPerPage = 20;
private int m_itemsPerPage = ModConfig.Instance.Default_Page_Limit;
public int ItemCount
{

27
src/ILRepack.targets Normal file
View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="ILRepacker" AfterTargets="Build">
<!-- Merging DLLs -->
<ItemGroup>
<InputAssemblies Include="$(OutputPath)$(AssemblyName).dll" />
</ItemGroup>
<ItemGroup Condition="'$(IsNet35)'=='false'">
<InputAssemblies Include="..\lib\mcs.dll" />
</ItemGroup>
<ItemGroup Condition="'$(IsNet35)'=='true'">
<InputAssemblies Include="..\lib\mcs.NET35.dll" />
</ItemGroup>
<ILRepack
Parallel="true"
Internalize="true"
DebugInfo="false"
LibraryPath="..\lib\"
InputAssemblies="@(InputAssemblies)"
TargetKind="Dll"
OutputFile="$(OutputPath)$(AssemblyName).dll"
/>
</Target>
</Project>

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace Explorer.Input
{
public abstract class AbstractInput
{
public abstract void Init();
public abstract Vector2 MousePosition { get; }
public abstract bool GetKeyDown(KeyCode key);
public abstract bool GetKey(KeyCode key);
public abstract bool GetMouseButtonDown(int btn);
public abstract bool GetMouseButton(int btn);
}
}

55
src/Input/InputManager.cs Normal file
View File

@ -0,0 +1,55 @@
using System;
using System.Reflection;
using UnityEngine;
using Explorer.Input;
namespace Explorer
{
public static class InputManager
{
// If no Input modules loaded at all
public static bool NO_INPUT { get; private set; }
// If using new InputSystem module
public static bool USING_NEW_INPUT { get; private set; }
private static AbstractInput inputModule;
public static void Init()
{
if (InputSystem.TKeyboard != null || TryLoadModule("Unity.InputSystem", InputSystem.TKeyboard))
{
USING_NEW_INPUT = true;
inputModule = new InputSystem();
}
else if (LegacyInput.TInput != null || TryLoadModule("UnityEngine.Input", LegacyInput.TInput))
{
inputModule = new LegacyInput();
}
if (inputModule == null)
{
ExplorerCore.LogWarning("Could not find any Input module!");
NO_INPUT = true;
}
else
{
inputModule.Init();
}
bool TryLoadModule(string dll, Type check) => ReflectionHelpers.LoadModule(dll) && check != null;
}
public static Vector3 MousePosition => inputModule?.MousePosition ?? Vector3.zero;
public static bool GetKeyDown(KeyCode key) => inputModule?.GetKeyDown(key) ?? false;
public static bool GetKey(KeyCode key) => inputModule?.GetKey(key) ?? false;
/// <param name="btn">0 = left, 1 = right, 2 = middle.</param>
public static bool GetMouseButtonDown(int btn) => inputModule?.GetMouseButtonDown(btn) ?? false;
/// <param name="btn">0 = left, 1 = right, 2 = middle.</param>
public static bool GetMouseButton(int btn) => inputModule?.GetMouseButton(btn) ?? false;
}
}

109
src/Input/InputSystem.cs Normal file
View File

@ -0,0 +1,109 @@
using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace Explorer.Input
{
public class InputSystem : AbstractInput
{
public static Type TKeyboard => _keyboard ?? (_keyboard = ReflectionHelpers.GetTypeByName("UnityEngine.InputSystem.Keyboard"));
private static Type _keyboard;
public static Type TMouse => _mouse ?? (_mouse = ReflectionHelpers.GetTypeByName("UnityEngine.InputSystem.Mouse"));
private static Type _mouse;
public static Type TKey => _key ?? (_key = ReflectionHelpers.GetTypeByName("UnityEngine.InputSystem.Key"));
private static Type _key;
private static PropertyInfo _btnIsPressedProp;
private static PropertyInfo _btnWasPressedProp;
private static object CurrentKeyboard => _currentKeyboard ?? (_currentKeyboard = _kbCurrentProp.GetValue(null, null));
private static object _currentKeyboard;
private static PropertyInfo _kbCurrentProp;
private static PropertyInfo _kbIndexer;
private static object CurrentMouse => _currentMouse ?? (_currentMouse = _mouseCurrentProp.GetValue(null, null));
private static object _currentMouse;
private static PropertyInfo _mouseCurrentProp;
private static object LeftMouseButton => _lmb ?? (_lmb = _leftButtonProp.GetValue(CurrentMouse, null));
private static object _lmb;
private static PropertyInfo _leftButtonProp;
private static object RightMouseButton => _rmb ?? (_rmb = _rightButtonProp.GetValue(CurrentMouse, null));
private static object _rmb;
private static PropertyInfo _rightButtonProp;
private static object MousePositionInfo => _pos ?? (_pos = _positionProp.GetValue(CurrentMouse, null));
private static object _pos;
private static PropertyInfo _positionProp;
private static MethodInfo _readVector2InputMethod;
public override Vector2 MousePosition => (Vector2)_readVector2InputMethod.Invoke(MousePositionInfo, new object[0]);
public override bool GetKeyDown(KeyCode key)
{
var parsedKey = Enum.Parse(TKey, key.ToString());
var actualKey = _kbIndexer.GetValue(CurrentKeyboard, new object[] { parsedKey });
return (bool)_btnWasPressedProp.GetValue(actualKey, null);
}
public override bool GetKey(KeyCode key)
{
var parsed = Enum.Parse(TKey, key.ToString());
var actualKey = _kbIndexer.GetValue(CurrentKeyboard, new object[] { parsed });
return (bool)_btnIsPressedProp.GetValue(actualKey, null);
}
public override bool GetMouseButtonDown(int btn)
{
switch (btn)
{
case 0: return (bool)_btnWasPressedProp.GetValue(LeftMouseButton, null);
case 1: return (bool)_btnWasPressedProp.GetValue(RightMouseButton, null);
// case 2: return (bool)_btnWasPressedProp.GetValue(MiddleMouseButton, null);
default: throw new NotImplementedException();
}
}
public override bool GetMouseButton(int btn)
{
switch (btn)
{
case 0: return (bool)_btnIsPressedProp.GetValue(LeftMouseButton, null);
case 1: return (bool)_btnIsPressedProp.GetValue(RightMouseButton, null);
// case 2: return (bool)_btnIsPressedProp.GetValue(MiddleMouseButton, null);
default: throw new NotImplementedException();
}
}
public override void Init()
{
ExplorerCore.Log("Initializing new InputSystem support...");
_kbCurrentProp = TKeyboard.GetProperty("current");
_kbIndexer = TKeyboard.GetProperty("Item", new Type[] { TKey });
var btnControl = ReflectionHelpers.GetTypeByName("UnityEngine.InputSystem.Controls.ButtonControl");
_btnIsPressedProp = btnControl.GetProperty("isPressed");
_btnWasPressedProp = btnControl.GetProperty("wasPressedThisFrame");
_mouseCurrentProp = TMouse.GetProperty("current");
_leftButtonProp = TMouse.GetProperty("leftButton");
_rightButtonProp = TMouse.GetProperty("rightButton");
_positionProp = ReflectionHelpers.GetTypeByName("UnityEngine.InputSystem.Pointer")
.GetProperty("position");
_readVector2InputMethod = ReflectionHelpers.GetTypeByName("UnityEngine.InputSystem.InputControl`1")
.MakeGenericType(typeof(Vector2))
.GetMethod("ReadValue");
}
}
}

42
src/Input/LegacyInput.cs Normal file
View File

@ -0,0 +1,42 @@
using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace Explorer.Input
{
public class LegacyInput : AbstractInput
{
public static Type TInput => _input ?? (_input = ReflectionHelpers.GetTypeByName("UnityEngine.Input"));
private static Type _input;
private static PropertyInfo _mousePositionProp;
private static MethodInfo _getKeyMethod;
private static MethodInfo _getKeyDownMethod;
private static MethodInfo _getMouseButtonMethod;
private static MethodInfo _getMouseButtonDownMethod;
public override Vector2 MousePosition => (Vector3)_mousePositionProp.GetValue(null, null);
public override bool GetKey(KeyCode key) => (bool)_getKeyMethod.Invoke(null, new object[] { key });
public override bool GetKeyDown(KeyCode key) => (bool)_getKeyDownMethod.Invoke(null, new object[] { key });
public override bool GetMouseButton(int btn) => (bool)_getMouseButtonMethod.Invoke(null, new object[] { btn });
public override bool GetMouseButtonDown(int btn) => (bool)_getMouseButtonDownMethod.Invoke(null, new object[] { btn });
public override void Init()
{
ExplorerCore.Log("Initializing Legacy Input support...");
_mousePositionProp = TInput.GetProperty("mousePosition");
_getKeyMethod = TInput.GetMethod("GetKey", new Type[] { typeof(KeyCode) });
_getKeyDownMethod = TInput.GetMethod("GetKeyDown", new Type[] { typeof(KeyCode) });
_getMouseButtonMethod = TInput.GetMethod("GetMouseButton", new Type[] { typeof(int) });
_getMouseButtonDownMethod = TInput.GetMethod("GetMouseButtonDown", new Type[] { typeof(int) });
}
}
}

View File

@ -108,7 +108,7 @@ namespace Explorer
public static void Update()
{
// Check Force-Unlock input
if (InputHelper.GetKeyDown(KeyCode.LeftAlt))
if (InputManager.GetKeyDown(KeyCode.LeftAlt))
{
ForceUnlockMouse = !ForceUnlockMouse;
}

View File

@ -12,7 +12,7 @@ namespace Explorer
{
if (ExplorerCore.ShowMenu)
{
if (InputHelper.GetKey(KeyCode.LeftShift) && InputHelper.GetMouseButtonDown(1))
if (InputManager.GetKey(KeyCode.LeftShift) && InputManager.GetMouseButtonDown(1))
{
EnableInspect = !EnableInspect;
}
@ -33,7 +33,7 @@ namespace Explorer
if (!UnityHelpers.MainCamera)
return;
var ray = UnityHelpers.MainCamera.ScreenPointToRay(InputHelper.MousePosition);
var ray = UnityHelpers.MainCamera.ScreenPointToRay(InputManager.MousePosition);
if (Physics.Raycast(ray, out RaycastHit hit, 1000f))
{
@ -41,7 +41,7 @@ namespace Explorer
m_objUnderMouseName = obj.transform.GetGameObjectPath();
if (InputHelper.GetMouseButtonDown(0))
if (InputManager.GetMouseButtonDown(0))
{
EnableInspect = false;
m_objUnderMouseName = "";
@ -61,7 +61,7 @@ namespace Explorer
{
if (m_objUnderMouseName != "")
{
var pos = InputHelper.MousePosition;
var pos = InputManager.MousePosition;
var rect = new Rect(
pos.x - (Screen.width / 2), // x
Screen.height - pos.y - 50, // y

View File

@ -17,16 +17,20 @@ namespace Explorer
Pages.Add(new ScenePage());
Pages.Add(new SearchPage());
Pages.Add(new ConsolePage());
Pages.Add(new OptionsPage());
for (int i = 0; i < Pages.Count; i++)
{
var page = Pages[i];
page.Init();
// If page failed to init, it will remove itself from the list. Lower the iterate counter.
if (!Pages.Contains(page)) i--;
}
}
public const int MainWindowID = 5000;
public static Rect MainRect = new Rect(5,5, ModConfig.Instance.Default_Window_Size.x,ModConfig.Instance.Default_Window_Size.y);
public static Rect MainRect = new Rect(5, 5, ModConfig.Instance.Default_Window_Size.x, ModConfig.Instance.Default_Window_Size.y);
public static readonly List<WindowPage> Pages = new List<WindowPage>();
private static int m_currentPage = 0;

View File

@ -45,6 +45,7 @@ namespace Explorer
MethodInput = @"// This is a basic C# console.
// Some common using directives are added by default, you can add more below.
// If you want to return some output, Debug.Log() or MelonLogger.Log() it.
"
#if ML
+ @"MelonLogger.Log(""hello world"");";

View File

@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Explorer.Tests;
using UnityEngine;
namespace Explorer
{
public class OptionsPage : WindowPage
{
public override string Name => "Options";
public string toggleKeyInputString = "";
public Vector2 defaultSizeInputVector;
public int defaultPageLimit;
private CacheObjectBase toggleKeyInput;
private CacheObjectBase defaultSizeInput;
private CacheObjectBase defaultPageLimitInput;
public override void Init()
{
toggleKeyInputString = ModConfig.Instance.Main_Menu_Toggle.ToString();
toggleKeyInput = CacheFactory.GetTypeAndCacheObject(typeof(OptionsPage).GetField("toggleKeyInputString"), this);
defaultSizeInputVector = ModConfig.Instance.Default_Window_Size;
defaultSizeInput = CacheFactory.GetTypeAndCacheObject(typeof(OptionsPage).GetField("defaultSizeInputVector"), this);
defaultPageLimit = ModConfig.Instance.Default_Page_Limit;
defaultPageLimitInput = CacheFactory.GetTypeAndCacheObject(typeof(OptionsPage).GetField("defaultPageLimit"), this);
}
public override void Update() { }
public override void DrawWindow()
{
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
GUILayout.Label("<color=orange><size=16><b>Settings</b></size></color>", new GUILayoutOption[0]);
GUI.skin.label.alignment = TextAnchor.MiddleLeft;
GUILayout.BeginVertical(GUIContent.none, GUI.skin.box, new GUILayoutOption[0]);
GUILayout.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label($"Menu Toggle Key:", new GUILayoutOption[] { GUILayout.Width(215f) });
toggleKeyInput.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f);
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label($"Default Window Size:", new GUILayoutOption[] { GUILayout.Width(215f) });
defaultSizeInput.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f);
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label($"Default Items per Page:", new GUILayoutOption[] { GUILayout.Width(215f) });
defaultPageLimitInput.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f);
GUILayout.EndHorizontal();
if (GUILayout.Button("<color=lime><b>Apply and Save</b></color>", new GUILayoutOption[0]))
{
ApplyAndSave();
}
GUILayout.EndVertical();
//GUIUnstrip.Space(10f);
//GUI.skin.label.alignment = TextAnchor.MiddleCenter;
//GUILayout.Label("<color=orange><size=16><b>Other</b></size></color>", new GUILayoutOption[0]);
//GUI.skin.label.alignment = TextAnchor.MiddleLeft;
//GUILayout.BeginVertical(GUIContent.none, GUI.skin.box, new GUILayoutOption[0]);
//if (GUILayout.Button("Inspect Test Class", new GUILayoutOption[0]))
//{
// WindowManager.InspectObject(TestClass.Instance, out bool _);
//}
//GUILayout.EndVertical();
}
private void ApplyAndSave()
{
if (Enum.Parse(typeof(KeyCode), toggleKeyInputString) is KeyCode key)
{
ModConfig.Instance.Main_Menu_Toggle = key;
}
else
{
ExplorerCore.LogWarning($"Could not parse '{toggleKeyInputString}' to KeyCode!");
}
ModConfig.Instance.Default_Window_Size = defaultSizeInputVector;
ModConfig.Instance.Default_Page_Limit = defaultPageLimit;
ModConfig.SaveSettings();
}
}
}

View File

@ -10,7 +10,7 @@ namespace Explorer
{
public static ScenePage Instance;
public override string Name { get => "Scene Explorer"; }
public override string Name { get => "Scenes"; }
public PageHelper Pages = new PageHelper();

View File

@ -32,24 +32,24 @@ namespace Explorer
#if ML
GUILayout.Button(gcDrag, GUI.skin.label, new GUILayoutOption[] { GUILayout.Height(15) });
#else
GUILayout.Button(gcDrag.ToString(), new GUILayoutOption[] { GUILayout.Height(15) });
GUILayout.Button("<-- Drag to resize -->", new GUILayoutOption[] { GUILayout.Height(15) });
#endif
//var r = GUILayoutUtility.GetLastRect();
var r = Internal_LayoutUtility.GetLastRect();
var mousePos = InputHelper.MousePosition;
var mousePos = InputManager.MousePosition;
try
{
var mouse = GUIUnstrip.ScreenToGUIPoint(new Vector2(mousePos.x, Screen.height - mousePos.y));
if (r.Contains(mouse) && InputHelper.GetMouseButtonDown(0))
if (r.Contains(mouse) && InputManager.GetMouseButtonDown(0))
{
isResizing = true;
m_currentWindow = ID;
m_currentResize = new Rect(mouse.x, mouse.y, _rect.width, _rect.height);
}
else if (!InputHelper.GetMouseButton(0))
else if (!InputManager.GetMouseButton(0))
{
isResizing = false;
}
@ -125,16 +125,16 @@ namespace Explorer
//var r = GUILayoutUtility.GetLastRect();
var r = GUILayoutUtility.GetLastRect();
var mousePos = InputHelper.MousePosition;
var mousePos = InputManager.MousePosition;
var mouse = GUIUnstrip.ScreenToGUIPoint(new Vector2(mousePos.x, Screen.height - mousePos.y));
if (r.Contains(mouse) && InputHelper.GetMouseButtonDown(0))
if (r.Contains(mouse) && InputManager.GetMouseButtonDown(0))
{
isResizing = true;
m_currentWindow = ID;
m_currentResize = new Rect(mouse.x, mouse.y, _rect.width, _rect.height);
}
else if (!InputHelper.GetMouseButton(0))
else if (!InputManager.GetMouseButton(0))
{
isResizing = false;
}
@ -150,6 +150,7 @@ namespace Explorer
GUILayout.EndHorizontal();
#endif
GUI.skin.label.alignment = TextAnchor.MiddleLeft;
return _rect;
}

View File

@ -109,7 +109,7 @@ namespace Explorer
DestroyWindow();
return;
}
else if (Target is UnityEngine.Object uObj)
if (Target is UnityEngine.Object uObj)
{
if (!uObj)
{

View File

@ -78,13 +78,15 @@ namespace Explorer
{
if (Target == null)
{
ExplorerCore.Log("Target is null!");
DestroyWindow();
return;
}
else if (Target is UnityEngine.Object uObj)
if (Target is UnityEngine.Object uObj)
{
if (!uObj)
{
ExplorerCore.Log("Target was destroyed!");
DestroyWindow();
return;
}
@ -200,7 +202,7 @@ namespace Explorer
continue;
}
// ExplorerCore.Log($"Trying to cache member {signature}...");
//ExplorerCore.Log($"Trying to cache member {sig}...");
try
{

View File

@ -81,7 +81,7 @@ namespace Explorer
{
createdNew = false;
if (InputHelper.GetKey(KeyCode.LeftShift))
if (InputManager.GetKey(KeyCode.LeftShift))
{
forceReflection = true;
}
@ -189,7 +189,7 @@ namespace Explorer
private static bool RectContainsMouse(Rect rect)
{
var mousePos = InputHelper.MousePosition;
var mousePos = InputManager.MousePosition;
return rect.Contains(new Vector2(mousePos.x, Screen.height - mousePos.y));
}

View File

@ -109,6 +109,8 @@ namespace Explorer.UnstripInternals
public static string TextField(string text, GUILayoutOption[] options)
{
text = text ?? "";
int controlID = GUIUtility.GetControlID(FocusType.Keyboard);
GUIContent guicontent = GUIContent.Temp(text);
bool flag = GUIUtility.keyboardControl != controlID;

4
src/packages.config Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="ILRepack.Lib.MSBuild.Task" version="2.0.18.1" targetFramework="net472" />
</packages>