Compare commits

...

4 Commits

Author SHA1 Message Date
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
13 changed files with 216 additions and 121 deletions

View File

@ -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,13 +147,13 @@ 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, everything you need (other than MelonLoader and/or BepInEx) is included with this repository.
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.
## Credits

View File

@ -269,6 +269,7 @@ namespace Explorer
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
GUILayout.Label($"[{i}]", new GUILayoutOption[] { GUILayout.Width(30) });
GUI.skin.label.alignment = TextAnchor.MiddleLeft;
GUILayout.Label("Key:", new GUILayoutOption[] { GUILayout.Width(40) });
key.DrawValue(window, (window.width / 2) - 80f);

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

@ -243,6 +243,7 @@
<Compile Include="Extensions\ReflectionExtensions.cs" />
<Compile Include="Helpers\InputHelper.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" />

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.22";
public const string AUTHOR = "Sinai";
public const string GUID = "com.sinai.explorer";

View File

@ -9,7 +9,7 @@ namespace Explorer
/// </summary>
public static class InputHelper
{
// If Input module failed to load at all
// If no Input modules loaded at all
public static bool NO_INPUT;
// If using new InputSystem module
@ -19,129 +19,114 @@ namespace Explorer
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 TKeyboard => _keyboard ?? (_keyboard = ReflectionHelpers.GetTypeByName("UnityEngine.InputSystem.Keyboard"));
private static Type _keyboard;
private static Type TMouse => _mouseSys ?? (_mouseSys = ReflectionHelpers.GetTypeByName("UnityEngine.InputSystem.Mouse"));
private static Type _mouseSys;
private static Type TMouse => _mouse ?? (_mouse = ReflectionHelpers.GetTypeByName("UnityEngine.InputSystem.Mouse"));
private static Type _mouse;
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;
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;
// Cached member infos (legacy)
private static PropertyInfo _mousePosition;
private static MethodInfo _getKey;
private static MethodInfo _getKeyDown;
private static MethodInfo _getMouseButton;
private static MethodInfo _getMouseButtonDown;
private static PropertyInfo _mousePositionProp;
private static MethodInfo _getKeyMethod;
private static MethodInfo _getKeyDownMethod;
private static MethodInfo _getMouseButtonMethod;
private static MethodInfo _getMouseButtonDownMethod;
public static void Init()
{
if (TKeyboard != null || TryManuallyLoadNewInput())
if (TKeyboard != null || TryLoadModule("Unity.InputSystem", TKeyboard))
{
InitNewInput();
return;
}
if (TInput != null || TryManuallyLoadLegacyInput())
else if (TInput != null || TryLoadModule("UnityEngine.Input", TInput))
{
InitLegacyInput();
return;
}
ExplorerCore.LogWarning("Could not find any Input module!");
NO_INPUT = true;
else
{
ExplorerCore.LogWarning("Could not find any Input module!");
NO_INPUT = true;
}
}
private static bool TryLoadModule(string dll, Type check) => ReflectionHelpers.LoadModule(dll) && check != null;
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 });
_kbCurrentProp = TKeyboard.GetProperty("current");
_kbIndexer = TKeyboard.GetProperty("Item", new Type[] { TKey });
var btnControl = ReflectionHelpers.GetTypeByName("UnityEngine.InputSystem.Controls.ButtonControl");
_isPressed = btnControl.GetProperty("isPressed");
_wasPressedThisFrame = btnControl.GetProperty("wasPressedThisFrame");
_btnIsPressedProp = btnControl.GetProperty("isPressed");
_btnWasPressedProp = btnControl.GetProperty("wasPressedThisFrame");
_mouseCurrent = TMouse.GetProperty("current");
_leftButton = TMouse.GetProperty("leftButton");
_rightButton = TMouse.GetProperty("rightButton");
_mouseCurrentProp = TMouse.GetProperty("current");
_leftButtonProp = TMouse.GetProperty("leftButton");
_rightButtonProp = TMouse.GetProperty("rightButton");
_position = ReflectionHelpers.GetTypeByName("UnityEngine.InputSystem.Pointer")
.GetProperty("position");
_positionProp = ReflectionHelpers.GetTypeByName("UnityEngine.InputSystem.Pointer")
.GetProperty("position");
_readValueMethod = ReflectionHelpers.GetTypeByName("UnityEngine.InputSystem.InputControl`1")
.MakeGenericType(typeof(Vector2))
.GetMethod("ReadValue");
_readVector2InputMethod = 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;
}
_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) });
}
public static Vector3 MousePosition
{
get
{
if (NO_INPUT) return Vector3.zero;
if (NO_INPUT)
return Vector3.zero;
if (USING_NEW_INPUT)
{
var mouse = _mouseCurrent.GetValue(null, null);
var pos = _position.GetValue(mouse, null);
return (Vector2)_readVector2InputMethod.Invoke(MousePositionInfo, new object[0]);
return (Vector2)_readValueMethod.Invoke(pos, new object[0]);
}
return (Vector3)_mousePosition.GetValue(null, null);
return (Vector3)_mousePositionProp.GetValue(null, null);
}
}
@ -151,14 +136,13 @@ namespace Explorer
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 });
var parsedKey = Enum.Parse(TKey, key.ToString());
var actualKey = _kbIndexer.GetValue(CurrentKeyboard, new object[] { parsedKey });
return (bool)_wasPressedThisFrame.GetValue(actualKey, null);
return (bool)_btnWasPressedProp.GetValue(actualKey, null);
}
return (bool)_getKeyDown.Invoke(null, new object[] { key });
return (bool)_getKeyDownMethod.Invoke(null, new object[] { key });
}
public static bool GetKey(KeyCode key)
@ -168,55 +152,54 @@ namespace Explorer
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 });
var actualKey = _kbIndexer.GetValue(CurrentKeyboard, new object[] { parsed });
return (bool)_isPressed.GetValue(actualKey, null);
return (bool)_btnIsPressedProp.GetValue(actualKey, null);
}
return (bool)_getKey.Invoke(null, new object[] { key });
return (bool)_getKeyMethod.Invoke(null, new object[] { key });
}
/// <param name="btn">0/1 = left, 2 = middle, 3 = right, etc</param>
/// <param name="btn">0 = left, 1 = right, 2 = middle.</param>
public static bool GetMouseButtonDown(int btn)
{
if (NO_INPUT) return false;
if (USING_NEW_INPUT)
{
var mouse = _mouseCurrent.GetValue(null, null);
object actualBtn;
switch (btn)
{
case 0: actualBtn = LeftMouseButton; break;
case 1: actualBtn = RightMouseButton; break;
default: throw new NotImplementedException();
}
PropertyInfo btnProp;
if (btn < 2) btnProp = _leftButton;
else btnProp = _rightButton;
var actualBtn = btnProp.GetValue(mouse, null);
return (bool)_wasPressedThisFrame.GetValue(actualBtn, null);
return (bool)_btnWasPressedProp.GetValue(actualBtn, null);
}
return (bool)_getMouseButtonDown.Invoke(null, new object[] { btn });
return (bool)_getMouseButtonDownMethod.Invoke(null, new object[] { btn });
}
/// <param name="btn">1 = left, 2 = middle, 3 = right, etc</param>
/// <param name="btn">0 = left, 1 = right, 2 = middle.</param>
public static bool GetMouseButton(int btn)
{
if (NO_INPUT) return false;
if (USING_NEW_INPUT)
{
var mouse = _mouseCurrent.GetValue(null, null);
object actualBtn;
switch (btn)
{
case 0: actualBtn = LeftMouseButton; break;
case 1: actualBtn = RightMouseButton; break;
default: throw new NotImplementedException();
}
PropertyInfo btnProp;
if (btn < 2) btnProp = _leftButton;
else btnProp = _rightButton;
var actualBtn = btnProp.GetValue(mouse, null);
return (bool)_isPressed.GetValue(actualBtn, null);
return (bool)_btnIsPressedProp.GetValue(actualBtn, null);
}
return (bool)_getMouseButton.Invoke(null, new object[] { btn });
return (bool)_getMouseButtonMethod.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
{

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

@ -150,6 +150,7 @@ namespace Explorer
GUILayout.EndHorizontal();
#endif
GUI.skin.label.alignment = TextAnchor.MiddleLeft;
return _rect;
}

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;