Compare commits

...

10 Commits
1.6.7 ... 1.7.0

Author SHA1 Message Date
de663f34b2 1.7.0
* Fix for GuiLayout.Space unstrip
* Cleanups
2020-09-12 00:59:59 +10:00
8d648fec43 1.6.9
* Fix for games where patching Cursor methods fails.
* Added backup attempt for loading Cursor module if not present.
* HashSet collections are now supported by CacheList
* try/catch for loading Mod Config
2020-09-11 18:53:17 +10:00
835a81765e Add support for Hashset, add try/catch for loading settings 2020-09-11 00:17:13 +10:00
51ed936e30 Revert PR changes 2020-09-10 22:40:23 +10:00
ac16587cdc Merge pull request #11 from PsymoNBond/master
Fixed Rect init
2020-09-10 22:38:16 +10:00
1e1eaa6c38 Fixed Rect init 2020-09-10 14:16:25 +03:00
af17ae82c6 Update README.md 2020-09-10 20:47:13 +10:00
e23341c2b1 Update README.md 2020-09-10 20:36:24 +10:00
080bde4a63 Update README.md 2020-09-10 20:35:41 +10:00
1d739a1936 1.6.8
* Added a ModConfig, allowing you to define the main menu toggle keybind and the default window size (so far).
* Made the parsing of arguments more intelligent, should now behave as expected for null or empty arguments.
2020-09-10 20:31:09 +10:00
33 changed files with 604 additions and 268 deletions

View File

@ -30,20 +30,30 @@ Requires [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) to be ins
## How to use ## How to use
* Press F7 to show or hide the menu. * Press F7 to show or hide the menu.
* Simply browse through the scene, search for objects, etc, most of it is pretty self-explanatory. * Use the Scene Explorer or the Object Search to start Exploring, or the C# Console to test some code.
* See below for more specific details.
### Features ### Mod Config
There is a simple Mod Config for the CppExplorer, which is generated the first time you run it.
This config is generated to `Mods\CppExplorer\config.xml`. Edit the config while the game is closed if you wish to change it.
`Main_Menu_Toggle` (KeyCode)
* Sets the keybinding for the Main Menu toggle (show/hide all CppExplorer 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)
* Sets the default width and height for all CppExplorer windows when created.
* `x` is width, `y` is height.
* Default: `<x>550</x> <y>700</y>`
## Features
[![](overview.png)](overview.png) [![](overview.png)](overview.png)
<i>An overview of the different CppExplorer menus.</i> <i>An overview of the different CppExplorer menus.</i>
* Scene hierarchy explorer
* Search loaded assets with filters
* Traverse and manipulate GameObjects
* Generic Reflection inspector
* C# REPL Console
* Inspect-under-mouse
### Scene Explorer ### Scene Explorer
* A simple menu which allows you to traverse the Transform heirarchy of the scene. * A simple menu which allows you to traverse the Transform heirarchy of the scene.

View File

@ -172,7 +172,7 @@ namespace Explorer
{ {
holder = new CacheDictionary(); holder = new CacheDictionary();
} }
else if (ReflectionHelpers.IsEnumerable(valueType) || ReflectionHelpers.IsCppList(valueType)) else if (ReflectionHelpers.IsEnumerable(valueType) || ReflectionHelpers.IsCppEnumerable(valueType))
{ {
holder = new CacheList(); holder = new CacheList();
} }
@ -244,30 +244,41 @@ namespace Explorer
var input = m_argumentInput[i]; var input = m_argumentInput[i];
var type = m_arguments[i].ParameterType; var type = m_arguments[i].ParameterType;
if (type == typeof(string)) // First, try parse the input and use that.
if (!string.IsNullOrEmpty(input))
{ {
parsedArgs.Add(input); // strings can obviously just be used directly
} if (type == typeof(string))
else
{
try
{ {
parsedArgs.Add(type.GetMethod("Parse", new Type[] { typeof(string) }) parsedArgs.Add(input);
.Invoke(null, new object[] { input })); continue;
} }
catch else
{ {
if (m_arguments[i].HasDefaultValue) // try to invoke the parse method and use that.
try
{ {
parsedArgs.Add(m_arguments[i].DefaultValue); parsedArgs.Add(type.GetMethod("Parse", new Type[] { typeof(string) })
.Invoke(null, new object[] { input }));
continue;
} }
else catch
{ {
// Try add a null arg I guess MelonLogger.Log($"Argument #{i} '{m_arguments[i].Name}' ({type.Name}), could not parse input '{input}'.");
parsedArgs.Add(null);
} }
} }
} }
// Didn't use input, see if there is a default value.
if (m_arguments[i].HasDefaultValue)
{
parsedArgs.Add(m_arguments[i].DefaultValue);
continue;
}
// Try add a null arg I guess
parsedArgs.Add(null);
} }
return parsedArgs.ToArray(); return parsedArgs.ToArray();
@ -373,7 +384,7 @@ namespace Explorer
} }
else else
{ {
GUILayout.Space(labelWidth); GUIUnstrip.Space(labelWidth);
} }
var cm = this as CacheMethod; var cm = this as CacheMethod;
@ -440,7 +451,7 @@ namespace Explorer
// new line and space // new line and space
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Space(labelWidth); GUIUnstrip.Space(labelWidth);
} }
else if (cm != null) else if (cm != null)
{ {
@ -454,7 +465,7 @@ namespace Explorer
// new line and space // new line and space
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Space(labelWidth); GUIUnstrip.Space(labelWidth);
} }
if (!string.IsNullOrEmpty(ReflectionException)) if (!string.IsNullOrEmpty(ReflectionException))

View File

@ -228,14 +228,14 @@ namespace Explorer
var negativeWhitespace = window.width - (whitespace + 100f); var negativeWhitespace = window.width - (whitespace + 100f);
GUI.skin.button.alignment = TextAnchor.MiddleLeft; GUI.skin.button.alignment = TextAnchor.MiddleLeft;
string btnLabel = $"<color=#2df7b2>[{count}] Dictionary<{TypeOfKeys.FullName}, {TypeOfValues.FullName}></color>"; string btnLabel = $"[{count}] <color=#2df7b2>Dictionary<{TypeOfKeys.FullName}, {TypeOfValues.FullName}></color>";
if (GUILayout.Button(btnLabel, new GUILayoutOption[] { GUILayout.Width(negativeWhitespace) })) if (GUILayout.Button(btnLabel, new GUILayoutOption[] { GUILayout.Width(negativeWhitespace) }))
{ {
WindowManager.InspectObject(Value, out bool _); WindowManager.InspectObject(Value, out bool _);
} }
GUI.skin.button.alignment = TextAnchor.MiddleCenter; GUI.skin.button.alignment = TextAnchor.MiddleCenter;
GUILayout.Space(5); GUIUnstrip.Space(5);
if (IsExpanded) if (IsExpanded)
{ {
@ -246,7 +246,7 @@ namespace Explorer
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Space(whitespace); GUIUnstrip.Space(whitespace);
Pages.CurrentPageLabel(); Pages.CurrentPageLabel();
@ -262,7 +262,7 @@ namespace Explorer
Pages.DrawLimitInputArea(); Pages.DrawLimitInputArea();
GUILayout.Space(5); GUIUnstrip.Space(5);
} }
int offset = Pages.CalculateOffsetIndex(); int offset = Pages.CalculateOffsetIndex();
@ -276,7 +276,7 @@ namespace Explorer
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
//GUILayout.Space(whitespace); //GUIUnstrip.Space(whitespace);
if (key == null || val == null) if (key == null || val == null)
{ {

View File

@ -40,7 +40,7 @@ namespace Explorer
private Type m_genericTypeDef; private Type m_genericTypeDef;
// Cached ToArray method for Lists // Cached ToArray method for Lists
public MethodInfo GenericToArrayMethod public MethodInfo CppListToArrayMethod
{ {
get => GetGenericToArrayMethod(); get => GetGenericToArrayMethod();
} }
@ -60,7 +60,7 @@ namespace Explorer
{ {
if (m_enumerable == null && Value != null) if (m_enumerable == null && Value != null)
{ {
m_enumerable = Value as IEnumerable ?? GetEnumerableFromIl2CppList(); m_enumerable = Value as IEnumerable ?? EnumerateWithReflection();
} }
return m_enumerable; return m_enumerable;
} }
@ -100,21 +100,45 @@ namespace Explorer
return m_itemProperty; return m_itemProperty;
} }
private IEnumerable GetEnumerableFromIl2CppList() private IEnumerable EnumerateWithReflection()
{ {
if (Value == null) return null; if (Value == null) return null;
if (GenericTypeDef == typeof(Il2CppSystem.Collections.Generic.List<>)) if (GenericTypeDef == typeof(Il2CppSystem.Collections.Generic.List<>))
{ {
return (IEnumerable)GenericToArrayMethod?.Invoke(Value, new object[0]); return (IEnumerable)CppListToArrayMethod?.Invoke(Value, new object[0]);
}
else if (GenericTypeDef == typeof(Il2CppSystem.Collections.Generic.HashSet<>))
{
return CppHashSetToMono();
} }
else else
{ {
return ConvertIListToMono(); return CppIListToMono();
} }
} }
private IList ConvertIListToMono() private IEnumerable CppHashSetToMono()
{
var set = new HashSet<object>();
// invoke GetEnumerator
var enumerator = Value.GetType().GetMethod("GetEnumerator").Invoke(Value, null);
// get the type of it
var enumeratorType = enumerator.GetType();
// reflect MoveNext and Current
var moveNext = enumeratorType.GetMethod("MoveNext");
var current = enumeratorType.GetProperty("Current");
// iterate
while ((bool)moveNext.Invoke(enumerator, null))
{
set.Add(current.GetValue(enumerator));
}
return set;
}
private IList CppIListToMono()
{ {
try try
{ {
@ -273,7 +297,7 @@ namespace Explorer
} }
GUI.skin.button.alignment = TextAnchor.MiddleCenter; GUI.skin.button.alignment = TextAnchor.MiddleCenter;
GUILayout.Space(5); GUIUnstrip.Space(5);
if (IsExpanded) if (IsExpanded)
{ {
@ -284,7 +308,7 @@ namespace Explorer
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Space(whitespace); GUIUnstrip.Space(whitespace);
Pages.CurrentPageLabel(); Pages.CurrentPageLabel();
@ -300,7 +324,7 @@ namespace Explorer
Pages.DrawLimitInputArea(); Pages.DrawLimitInputArea();
GUILayout.Space(5); GUIUnstrip.Space(5);
} }
int offset = Pages.CalculateOffsetIndex(); int offset = Pages.CalculateOffsetIndex();
@ -313,7 +337,7 @@ namespace Explorer
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Space(whitespace); GUIUnstrip.Space(whitespace);
if (entry == null || entry.Value == null) if (entry == null || entry.Value == null)
{ {

View File

@ -49,10 +49,10 @@ namespace Explorer
} }
} }
var c = (Color)Value; //var c = (Color)Value;
GUI.color = c; //GUI.color = c;
GUILayout.Label($"<color=#2df7b2>Color:</color> {c.ToString()}", null); GUILayout.Label($"<color=#2df7b2>Color:</color> {((Color)Value).ToString()}", null);
GUI.color = Color.white; //GUI.color = Color.white;
if (CanWrite && IsExpanded) if (CanWrite && IsExpanded)
{ {
@ -61,32 +61,32 @@ namespace Explorer
var whitespace = CalcWhitespace(window); var whitespace = CalcWhitespace(window);
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Space(whitespace); GUIUnstrip.Space(whitespace);
GUILayout.Label("R:", new GUILayoutOption[] { GUILayout.Width(30) }); GUILayout.Label("R:", new GUILayoutOption[] { GUILayout.Width(30) });
r = GUILayout.TextField(r, new GUILayoutOption[] { GUILayout.Width(120) }); r = GUILayout.TextField(r, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Space(whitespace); GUIUnstrip.Space(whitespace);
GUILayout.Label("G:", new GUILayoutOption[] { GUILayout.Width(30) }); GUILayout.Label("G:", new GUILayoutOption[] { GUILayout.Width(30) });
g = GUILayout.TextField(g, new GUILayoutOption[] { GUILayout.Width(120) }); g = GUILayout.TextField(g, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Space(whitespace); GUIUnstrip.Space(whitespace);
GUILayout.Label("B:", new GUILayoutOption[] { GUILayout.Width(30) }); GUILayout.Label("B:", new GUILayoutOption[] { GUILayout.Width(30) });
b = GUILayout.TextField(b, new GUILayoutOption[] { GUILayout.Width(120) }); b = GUILayout.TextField(b, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Space(whitespace); GUIUnstrip.Space(whitespace);
GUILayout.Label("A:", new GUILayoutOption[] { GUILayout.Width(30) }); GUILayout.Label("A:", new GUILayoutOption[] { GUILayout.Width(30) });
a = GUILayout.TextField(a, new GUILayoutOption[] { GUILayout.Width(120) }); a = GUILayout.TextField(a, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
// draw set value button // draw set value button
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Space(whitespace); GUIUnstrip.Space(whitespace);
if (GUILayout.Button("<color=lime>Apply</color>", new GUILayoutOption[] { GUILayout.Width(155) })) if (GUILayout.Button("<color=lime>Apply</color>", new GUILayoutOption[] { GUILayout.Width(155) }))
{ {
SetValueFromInput(); SetValueFromInput();

View File

@ -92,7 +92,7 @@ namespace Explorer
} }
} }
GUILayout.Space(10); GUIUnstrip.Space(10);
} }
} }

View File

@ -56,26 +56,26 @@ namespace Explorer
var whitespace = CalcWhitespace(window); var whitespace = CalcWhitespace(window);
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Space(whitespace); GUIUnstrip.Space(whitespace);
GUILayout.Label("X:", new GUILayoutOption[] { GUILayout.Width(30) }); GUILayout.Label("X:", new GUILayoutOption[] { GUILayout.Width(30) });
x = GUILayout.TextField(x, new GUILayoutOption[] { GUILayout.Width(120) }); x = GUILayout.TextField(x, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Space(whitespace); GUIUnstrip.Space(whitespace);
GUILayout.Label("Y:", new GUILayoutOption[] { GUILayout.Width(30) }); GUILayout.Label("Y:", new GUILayoutOption[] { GUILayout.Width(30) });
y = GUILayout.TextField(y, new GUILayoutOption[] { GUILayout.Width(120) }); y = GUILayout.TextField(y, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Space(whitespace); GUIUnstrip.Space(whitespace);
GUILayout.Label("Z:", new GUILayoutOption[] { GUILayout.Width(30) }); GUILayout.Label("Z:", new GUILayoutOption[] { GUILayout.Width(30) });
z = GUILayout.TextField(z, new GUILayoutOption[] { GUILayout.Width(120) }); z = GUILayout.TextField(z, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
// draw set value button // draw set value button
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Space(whitespace); GUIUnstrip.Space(whitespace);
if (GUILayout.Button("<color=lime>Apply</color>", new GUILayoutOption[] { GUILayout.Width(155) })) if (GUILayout.Button("<color=lime>Apply</color>", new GUILayoutOption[] { GUILayout.Width(155) }))
{ {
SetValueFromInput(); SetValueFromInput();

View File

@ -58,32 +58,32 @@ namespace Explorer
var whitespace = CalcWhitespace(window); var whitespace = CalcWhitespace(window);
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Space(whitespace); GUIUnstrip.Space(whitespace);
GUILayout.Label("X:", new GUILayoutOption[] { GUILayout.Width(30) }); GUILayout.Label("X:", new GUILayoutOption[] { GUILayout.Width(30) });
x = GUILayout.TextField(x, new GUILayoutOption[] { GUILayout.Width(120) }); x = GUILayout.TextField(x, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Space(whitespace); GUIUnstrip.Space(whitespace);
GUILayout.Label("Y:", new GUILayoutOption[] { GUILayout.Width(30) }); GUILayout.Label("Y:", new GUILayoutOption[] { GUILayout.Width(30) });
y = GUILayout.TextField(y, new GUILayoutOption[] { GUILayout.Width(120) }); y = GUILayout.TextField(y, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Space(whitespace); GUIUnstrip.Space(whitespace);
GUILayout.Label("W:", new GUILayoutOption[] { GUILayout.Width(30) }); GUILayout.Label("W:", new GUILayoutOption[] { GUILayout.Width(30) });
w = GUILayout.TextField(w, new GUILayoutOption[] { GUILayout.Width(120) }); w = GUILayout.TextField(w, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Space(whitespace); GUIUnstrip.Space(whitespace);
GUILayout.Label("H:", new GUILayoutOption[] { GUILayout.Width(30) }); GUILayout.Label("H:", new GUILayoutOption[] { GUILayout.Width(30) });
h = GUILayout.TextField(h, new GUILayoutOption[] { GUILayout.Width(120) }); h = GUILayout.TextField(h, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
// draw set value button // draw set value button
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Space(whitespace); GUIUnstrip.Space(whitespace);
if (GUILayout.Button("<color=lime>Apply</color>", new GUILayoutOption[] { GUILayout.Width(155) })) if (GUILayout.Button("<color=lime>Apply</color>", new GUILayoutOption[] { GUILayout.Width(155) }))
{ {
SetValueFromInput(); SetValueFromInput();

View File

@ -94,13 +94,13 @@ namespace Explorer
// always draw x and y // always draw x and y
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Space(whitespace); GUIUnstrip.Space(whitespace);
GUILayout.Label("X:", new GUILayoutOption[] { GUILayout.Width(30) }); GUILayout.Label("X:", new GUILayoutOption[] { GUILayout.Width(30) });
x = GUILayout.TextField(x, new GUILayoutOption[] { GUILayout.Width(120) }); x = GUILayout.TextField(x, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Space(whitespace); GUIUnstrip.Space(whitespace);
GUILayout.Label("Y:", new GUILayoutOption[] { GUILayout.Width(30) }); GUILayout.Label("Y:", new GUILayoutOption[] { GUILayout.Width(30) });
y = GUILayout.TextField(y, new GUILayoutOption[] { GUILayout.Width(120) }); y = GUILayout.TextField(y, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
@ -109,7 +109,7 @@ namespace Explorer
{ {
// draw z // draw z
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Space(whitespace); GUIUnstrip.Space(whitespace);
GUILayout.Label("Z:", new GUILayoutOption[] { GUILayout.Width(30) }); GUILayout.Label("Z:", new GUILayoutOption[] { GUILayout.Width(30) });
z = GUILayout.TextField(z, new GUILayoutOption[] { GUILayout.Width(120) }); z = GUILayout.TextField(z, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
@ -118,7 +118,7 @@ namespace Explorer
{ {
// draw w // draw w
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Space(whitespace); GUIUnstrip.Space(whitespace);
GUILayout.Label("W:", new GUILayoutOption[] { GUILayout.Width(30) }); GUILayout.Label("W:", new GUILayoutOption[] { GUILayout.Width(30) });
w = GUILayout.TextField(w, new GUILayoutOption[] { GUILayout.Width(120) }); w = GUILayout.TextField(w, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
@ -126,7 +126,7 @@ namespace Explorer
// draw set value button // draw set value button
GUILayout.BeginHorizontal(null); GUILayout.BeginHorizontal(null);
GUILayout.Space(whitespace); GUIUnstrip.Space(whitespace);
if (GUILayout.Button("<color=lime>Apply</color>", new GUILayoutOption[] { GUILayout.Width(155) })) if (GUILayout.Button("<color=lime>Apply</color>", new GUILayoutOption[] { GUILayout.Width(155) }))
{ {
SetValueFromInput(); SetValueFromInput();

69
src/Config/ModConfig.cs Normal file
View File

@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using UnityEngine;
namespace Explorer
{
public class ModConfig
{
[XmlIgnore] public static readonly XmlSerializer Serializer = new XmlSerializer(typeof(ModConfig));
[XmlIgnore] private const string EXPLORER_FOLDER = @"Mods\CppExplorer";
[XmlIgnore] private const string SETTINGS_PATH = EXPLORER_FOLDER + @"\config.xml";
[XmlIgnore] public static ModConfig Instance;
public KeyCode Main_Menu_Toggle = KeyCode.F7;
public Vector2 Default_Window_Size = new Vector2(550, 700);
public static void OnLoad()
{
if (!Directory.Exists(EXPLORER_FOLDER))
{
Directory.CreateDirectory(EXPLORER_FOLDER);
}
if (LoadSettings()) return;
Instance = new ModConfig();
SaveSettings();
}
// returns true if settings successfully loaded
public static bool LoadSettings(bool checkExist = true)
{
if (checkExist && !File.Exists(SETTINGS_PATH))
return false;
try
{
using (var file = File.OpenRead(SETTINGS_PATH))
{
Instance = (ModConfig)Serializer.Deserialize(file);
}
}
catch
{
return false;
}
return Instance != null;
}
public static void SaveSettings(bool checkExist = true)
{
if (checkExist && File.Exists(SETTINGS_PATH))
File.Delete(SETTINGS_PATH);
using (var file = File.Create(SETTINGS_PATH))
{
Serializer.Serialize(file, Instance);
}
}
}
}

View File

@ -13,7 +13,7 @@ namespace Explorer
public class CppExplorer : MelonMod public class CppExplorer : MelonMod
{ {
public const string NAME = "CppExplorer"; public const string NAME = "CppExplorer";
public const string VERSION = "1.6.7"; public const string VERSION = "1.7.0";
public const string AUTHOR = "Sinai"; public const string AUTHOR = "Sinai";
public const string GUID = "com.sinai.cppexplorer"; public const string GUID = "com.sinai.cppexplorer";
@ -24,49 +24,30 @@ namespace Explorer
get => m_showMenu; get => m_showMenu;
set => SetShowMenu(value); set => SetShowMenu(value);
} }
private static bool m_showMenu; public static bool m_showMenu;
public static bool ForceUnlockMouse
{
get => m_forceUnlock;
set => SetForceUnlock(value);
}
private static bool m_forceUnlock;
private static CursorLockMode m_lastLockMode;
private static bool m_lastVisibleState;
private static bool m_currentlySettingCursor = false;
public static bool ShouldForceMouse => ShowMenu && ForceUnlockMouse;
private static void SetShowMenu(bool show) private static void SetShowMenu(bool show)
{ {
m_showMenu = show; m_showMenu = show;
UpdateCursorControl(); CursorControl.UpdateCursorControl();
}
private static void SetForceUnlock(bool unlock)
{
m_forceUnlock = unlock;
UpdateCursorControl();
} }
public override void OnApplicationStart() public override void OnApplicationStart()
{ {
Instance = this; Instance = this;
// First, load config
ModConfig.OnLoad();
// Setup InputHelper class (UnityEngine.Input)
InputHelper.Init(); InputHelper.Init();
// Create CppExplorer modules
new MainMenu(); new MainMenu();
new WindowManager(); new WindowManager();
// Get current cursor state and enable cursor // Init cursor control
m_lastLockMode = Cursor.lockState; CursorControl.Init();
m_lastVisibleState = Cursor.visible;
// Enable ShowMenu and ForceUnlockMouse
// (set m_showMenu directly to not call UpdateCursorState twice)
m_showMenu = true;
ForceUnlockMouse = true;
MelonLogger.Log($"CppExplorer {VERSION} initialized."); MelonLogger.Log($"CppExplorer {VERSION} initialized.");
} }
@ -80,22 +61,18 @@ namespace Explorer
public override void OnUpdate() public override void OnUpdate()
{ {
// Check main toggle key input // Check main toggle key input
if (InputHelper.GetKeyDown(KeyCode.F7)) if (InputHelper.GetKeyDown(ModConfig.Instance.Main_Menu_Toggle))
{ {
ShowMenu = !ShowMenu; ShowMenu = !ShowMenu;
} }
if (ShowMenu) if (ShowMenu)
{ {
// Check Force-Unlock input CursorControl.Update();
if (InputHelper.GetKeyDown(KeyCode.LeftAlt)) InspectUnderMouse.Update();
{
ForceUnlockMouse = !ForceUnlockMouse;
}
MainMenu.Instance.Update(); MainMenu.Instance.Update();
WindowManager.Instance.Update(); WindowManager.Instance.Update();
InspectUnderMouse.Update();
} }
} }
@ -103,93 +80,14 @@ namespace Explorer
{ {
if (!ShowMenu) return; if (!ShowMenu) return;
var origSkin = GUI.skin;
GUI.skin = UIStyles.WindowSkin;
MainMenu.Instance.OnGUI(); MainMenu.Instance.OnGUI();
WindowManager.Instance.OnGUI(); WindowManager.Instance.OnGUI();
InspectUnderMouse.OnGUI(); InspectUnderMouse.OnGUI();
}
private static void UpdateCursorControl() GUI.skin = origSkin;
{
m_currentlySettingCursor = true;
if (ShouldForceMouse)
{
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
}
else
{
Cursor.lockState = m_lastLockMode;
Cursor.visible = m_lastVisibleState;
}
m_currentlySettingCursor = false;
}
// Force mouse to stay unlocked and visible while UnlockMouse and ShowMenu are true.
// 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.
[HarmonyPatch(typeof(Cursor), nameof(Cursor.lockState), MethodType.Setter)]
public class Cursor_set_lockState
{
[HarmonyPrefix]
public static void Prefix(ref CursorLockMode value)
{
if (!m_currentlySettingCursor)
{
m_lastLockMode = value;
if (ShouldForceMouse)
{
value = CursorLockMode.None;
}
}
}
}
[HarmonyPatch(typeof(Cursor), nameof(Cursor.visible), MethodType.Setter)]
public class Cursor_set_visible
{
[HarmonyPrefix]
public static void Prefix(ref bool value)
{
if (!m_currentlySettingCursor)
{
m_lastVisibleState = value;
if (ShouldForceMouse)
{
value = true;
}
}
}
}
// Make it appear as though UnlockMouse is disabled to the rest of the application.
[HarmonyPatch(typeof(Cursor), nameof(Cursor.lockState), MethodType.Getter)]
public class Cursor_get_lockState
{
[HarmonyPostfix]
public static void Postfix(ref CursorLockMode __result)
{
if (ShouldForceMouse)
{
__result = m_lastLockMode;
}
}
}
[HarmonyPatch(typeof(Cursor), nameof(Cursor.visible), MethodType.Getter)]
public class Cursor_get_visible
{
[HarmonyPostfix]
public static void Postfix(ref bool __result)
{
if (ShouldForceMouse)
{
__result = m_lastVisibleState;
}
}
} }
} }
} }

View File

@ -29,6 +29,10 @@
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\Il2Cppmscorlib.dll</HintPath> <HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\Il2Cppmscorlib.dll</HintPath>
<Private>False</Private> <Private>False</Private>
</Reference> </Reference>
<Reference Include="Il2CppSystem.Core">
<HintPath>..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\Il2CppSystem.Core.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="mcs"> <Reference Include="mcs">
<HintPath>..\lib\mcs.dll</HintPath> <HintPath>..\lib\mcs.dll</HintPath>
<Private>True</Private> <Private>True</Private>
@ -85,35 +89,38 @@
<Compile Include="CachedObjects\Struct\CacheQuaternion.cs" /> <Compile Include="CachedObjects\Struct\CacheQuaternion.cs" />
<Compile Include="CachedObjects\Struct\CacheVector.cs" /> <Compile Include="CachedObjects\Struct\CacheVector.cs" />
<Compile Include="CachedObjects\Struct\CacheRect.cs" /> <Compile Include="CachedObjects\Struct\CacheRect.cs" />
<Compile Include="Config\ModConfig.cs" />
<Compile Include="CppExplorer.cs" /> <Compile Include="CppExplorer.cs" />
<Compile Include="Extensions\ReflectionExtensions.cs" /> <Compile Include="Extensions\ReflectionExtensions.cs" />
<Compile Include="Helpers\InputHelper.cs" /> <Compile Include="Helpers\InputHelper.cs" />
<Compile Include="Menu\CursorControl.cs" />
<Compile Include="Tests\TestClass.cs" /> <Compile Include="Tests\TestClass.cs" />
<Compile Include="UnstripFixes\GUIUnstrip.cs" /> <Compile Include="UnstripFixes\GUIUnstrip.cs" />
<Compile Include="UnstripFixes\LayoutUtilityUnstrip.cs" />
<Compile Include="UnstripFixes\ScrollViewStateUnstrip.cs" /> <Compile Include="UnstripFixes\ScrollViewStateUnstrip.cs" />
<Compile Include="Extensions\UnityExtensions.cs" /> <Compile Include="Extensions\UnityExtensions.cs" />
<Compile Include="Helpers\PageHelper.cs" /> <Compile Include="Helpers\PageHelper.cs" />
<Compile Include="Helpers\ReflectionHelpers.cs" /> <Compile Include="Helpers\ReflectionHelpers.cs" />
<Compile Include="Helpers\UIHelpers.cs" /> <Compile Include="Helpers\UIHelpers.cs" />
<Compile Include="Helpers\UnityHelpers.cs" /> <Compile Include="Helpers\UnityHelpers.cs" />
<Compile Include="MainMenu\InspectUnderMouse.cs" /> <Compile Include="Menu\InspectUnderMouse.cs" />
<Compile Include="CachedObjects\CacheObjectBase.cs" /> <Compile Include="CachedObjects\CacheObjectBase.cs" />
<Compile Include="UnstripFixes\SliderHandlerUnstrip.cs" /> <Compile Include="UnstripFixes\SliderHandlerUnstrip.cs" />
<Compile Include="UnstripFixes\UnstripExtensions.cs" /> <Compile Include="UnstripFixes\UnstripExtensions.cs" />
<Compile Include="Windows\ResizeDrag.cs" /> <Compile Include="Menu\Windows\ResizeDrag.cs" />
<Compile Include="Windows\TabViewWindow.cs" /> <Compile Include="Menu\Windows\TabViewWindow.cs" />
<Compile Include="Windows\UIWindow.cs" /> <Compile Include="Menu\Windows\UIWindow.cs" />
<Compile Include="MainMenu\Pages\ConsolePage.cs" /> <Compile Include="Menu\MainMenu\Pages\ConsolePage.cs" />
<Compile Include="MainMenu\Pages\Console\REPL.cs" /> <Compile Include="Menu\MainMenu\Pages\Console\REPL.cs" />
<Compile Include="MainMenu\Pages\Console\REPLHelper.cs" /> <Compile Include="Menu\MainMenu\Pages\Console\REPLHelper.cs" />
<Compile Include="MainMenu\Pages\WindowPage.cs" /> <Compile Include="Menu\MainMenu\Pages\WindowPage.cs" />
<Compile Include="Windows\WindowManager.cs" /> <Compile Include="Menu\Windows\WindowManager.cs" />
<Compile Include="MainMenu\MainMenu.cs" /> <Compile Include="Menu\MainMenu\MainMenu.cs" />
<Compile Include="Windows\GameObjectWindow.cs" /> <Compile Include="Menu\Windows\GameObjectWindow.cs" />
<Compile Include="Windows\ReflectionWindow.cs" /> <Compile Include="Menu\Windows\ReflectionWindow.cs" />
<Compile Include="MainMenu\Pages\ScenePage.cs" /> <Compile Include="Menu\MainMenu\Pages\ScenePage.cs" />
<Compile Include="MainMenu\Pages\SearchPage.cs" /> <Compile Include="Menu\MainMenu\Pages\SearchPage.cs" />
<Compile Include="Helpers\UIStyles.cs" /> <Compile Include="Menu\UIStyles.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

View File

@ -88,7 +88,8 @@ namespace Explorer
{ {
MelonLogger.Log("UnityEngine.Input is null, trying to load manually...."); MelonLogger.Log("UnityEngine.Input is null, trying to load manually....");
if ((TryLoad("UnityEngine.InputLegacyModule.dll") || TryLoad("UnityEngine.CoreModule.dll")) && Input != null) if ((ReflectionHelpers.LoadModule("UnityEngine.InputLegacyModule.dll") || ReflectionHelpers.LoadModule("UnityEngine.CoreModule.dll"))
&& Input != null)
{ {
MelonLogger.Log("Ok!"); MelonLogger.Log("Ok!");
return true; return true;
@ -98,23 +99,6 @@ namespace Explorer
MelonLogger.Log("Could not load Input module!"); MelonLogger.Log("Could not load Input module!");
return false; return false;
} }
bool TryLoad(string module)
{
var path = $@"MelonLoader\Managed\{module}";
if (!File.Exists(path)) return false;
try
{
Assembly.Load(File.ReadAllBytes(path));
return true;
}
catch (Exception e)
{
MelonLogger.Log(e.GetType() + ", " + e.Message);
return false;
}
}
} }
} }
} }

View File

@ -3,6 +3,8 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.IO;
using MelonLoader;
using UnhollowerBaseLib; using UnhollowerBaseLib;
using UnhollowerRuntimeLib; using UnhollowerRuntimeLib;
using UnityEngine; using UnityEngine;
@ -37,13 +39,14 @@ namespace Explorer
return typeof(IEnumerable).IsAssignableFrom(t); return typeof(IEnumerable).IsAssignableFrom(t);
} }
// Only Il2Cpp List needs this check. C# List is IEnumerable. // Checks for Il2Cpp List or HashSet.
public static bool IsCppList(Type t) public static bool IsCppEnumerable(Type t)
{ {
if (t.IsGenericType && t.GetGenericTypeDefinition() is Type g) if (t.IsGenericType && t.GetGenericTypeDefinition() is Type g)
{ {
return typeof(Il2CppSystem.Collections.Generic.List<>).IsAssignableFrom(g) return typeof(Il2CppSystem.Collections.Generic.List<>).IsAssignableFrom(g)
|| typeof(Il2CppSystem.Collections.Generic.IList<>).IsAssignableFrom(g); || typeof(Il2CppSystem.Collections.Generic.IList<>).IsAssignableFrom(g)
|| typeof(Il2CppSystem.Collections.Generic.HashSet<>).IsAssignableFrom(g);
} }
else else
{ {
@ -89,18 +92,20 @@ namespace Explorer
{ {
if (obj == null) return null; if (obj == null) return null;
// Need to use GetIl2CppType for Il2CppSystem Objects
if (obj is Il2CppSystem.Object ilObject) if (obj is Il2CppSystem.Object ilObject)
{ {
var ilTypeName = ilObject.GetIl2CppType().AssemblyQualifiedName; // Prevent weird behaviour when inspecting an Il2CppSystem.Type object.
if (ilObject is ILType)
if (Type.GetType(ilTypeName) is Type t && !t.FullName.Contains("System.RuntimeType"))
{ {
return t; return typeof(ILType);
} }
return ilObject.GetType(); // Get the System.Type using the qualified name, or fallback to GetType.
return Type.GetType(ilObject.GetIl2CppType().AssemblyQualifiedName) ?? obj.GetType();
} }
// It's a normal object, this is fine
return obj.GetType(); return obj.GetType();
} }
@ -109,17 +114,33 @@ namespace Explorer
var list = new List<Type>(); var list = new List<Type>();
var type = GetActualType(obj); var type = GetActualType(obj);
list.Add(type);
while (type.BaseType != null) while (type != null)
{ {
type = type.BaseType;
list.Add(type); list.Add(type);
type = type.BaseType;
} }
return list.ToArray(); return list.ToArray();
} }
public static bool LoadModule(string module)
{
var path = $@"MelonLoader\Managed\{module}";
if (!File.Exists(path)) return false;
try
{
Assembly.Load(File.ReadAllBytes(path));
return true;
}
catch (Exception e)
{
MelonLogger.Log(e.GetType() + ", " + e.Message);
return false;
}
}
public static string ExceptionToString(Exception e) public static string ExceptionToString(Exception e)
{ {
if (IsFailedGeneric(e)) if (IsFailedGeneric(e))

183
src/Menu/CursorControl.cs Normal file
View File

@ -0,0 +1,183 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using Harmony;
using MelonLoader;
using System.Reflection;
namespace Explorer
{
public class CursorControl
{
public static bool ForceUnlockMouse
{
get => m_forceUnlock;
set => SetForceUnlock(value);
}
private static bool m_forceUnlock;
private static CursorLockMode m_lastLockMode;
private static bool m_lastVisibleState;
private static bool m_currentlySettingCursor = false;
public static bool ShouldForceMouse => CppExplorer.ShowMenu && ForceUnlockMouse;
private static Type CursorType => m_cursorType ?? (m_cursorType = ReflectionHelpers.GetTypeByName("UnityEngine.Cursor"));
private static Type m_cursorType;
public static void Init()
{
try
{
// Check if Cursor class is loaded
if (CursorType == null)
{
MelonLogger.Log("Trying to manually load Cursor module...");
if (ReflectionHelpers.LoadModule("UnityEngine.CoreModule") && CursorType != null)
{
MelonLogger.Log("Ok!");
}
else
{
throw new Exception("Could not load UnityEngine.Cursor module!");
}
}
// Get current cursor state and enable cursor
m_lastLockMode = Cursor.lockState;
m_lastVisibleState = Cursor.visible;
// Setup Harmony Patches
TryPatch("lockState", new HarmonyMethod(typeof(CursorControl).GetMethod(nameof(Prefix_set_lockState))), true);
TryPatch("lockState", new HarmonyMethod(typeof(CursorControl).GetMethod(nameof(Postfix_get_lockState))), false);
TryPatch("visible", new HarmonyMethod(typeof(CursorControl).GetMethod(nameof(Prefix_set_visible))), true);
TryPatch("visible", new HarmonyMethod(typeof(CursorControl).GetMethod(nameof(Postfix_get_visible))), false);
}
catch (Exception e)
{
MelonLogger.Log($"Exception on CursorControl.Init! {e.GetType()}, {e.Message}");
}
// Enable ShowMenu and ForceUnlockMouse
// (set m_showMenu directly to not call UpdateCursorState twice)
CppExplorer.m_showMenu = true;
ForceUnlockMouse = true;
}
private static void TryPatch(string property, HarmonyMethod patch, bool setter)
{
try
{
var harmony = CppExplorer.Instance.harmonyInstance;
var prop = typeof(Cursor).GetProperty(property);
if (setter)
{
// setter is prefix
harmony.Patch(prop.GetSetMethod(), patch);
}
else
{
// getter is postfix
harmony.Patch(prop.GetGetMethod(), null, patch);
}
}
catch (Exception e)
{
MelonLogger.Log($"[NON-FATAL] Couldn't patch a method: {e.Message}");
}
}
private static void SetForceUnlock(bool unlock)
{
m_forceUnlock = unlock;
UpdateCursorControl();
}
public static void Update()
{
// Check Force-Unlock input
if (InputHelper.GetKeyDown(KeyCode.LeftAlt))
{
ForceUnlockMouse = !ForceUnlockMouse;
}
}
public static void UpdateCursorControl()
{
try
{
m_currentlySettingCursor = true;
if (ShouldForceMouse)
{
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
}
else
{
Cursor.lockState = m_lastLockMode;
Cursor.visible = m_lastVisibleState;
}
m_currentlySettingCursor = false;
}
catch (Exception e)
{
MelonLogger.Log($"Exception setting Cursor state: {e.GetType()}, {e.Message}");
}
}
// Force mouse to stay unlocked and visible while UnlockMouse and ShowMenu are true.
// 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.
[HarmonyPrefix]
public static void Prefix_set_lockState(ref CursorLockMode value)
{
if (!m_currentlySettingCursor)
{
m_lastLockMode = value;
if (ShouldForceMouse)
{
value = CursorLockMode.None;
}
}
}
[HarmonyPrefix]
public static void Prefix_set_visible(ref bool value)
{
if (!m_currentlySettingCursor)
{
m_lastVisibleState = value;
if (ShouldForceMouse)
{
value = true;
}
}
}
[HarmonyPrefix]
public static void Postfix_get_lockState(ref CursorLockMode __result)
{
if (ShouldForceMouse)
{
__result = m_lastLockMode;
}
}
[HarmonyPrefix]
public static void Postfix_get_visible(ref bool __result)
{
if (ShouldForceMouse)
{
__result = m_lastVisibleState;
}
}
}
}

View File

@ -27,8 +27,9 @@ namespace Explorer
} }
} }
public const int MainWindowID = 10; public const int MainWindowID = 5000;
public static Rect MainRect = new Rect(5, 5, 550, 700); public static Rect MainRect = new Rect(5,5, ModConfig.Instance.Default_Window_Size.x,ModConfig.Instance.Default_Window_Size.y);
private static readonly List<WindowPage> Pages = new List<WindowPage>(); private static readonly List<WindowPage> Pages = new List<WindowPage>();
private static int m_currentPage = 0; private static int m_currentPage = 0;
@ -51,19 +52,14 @@ namespace Explorer
public void OnGUI() public void OnGUI()
{ {
var origSkin = GUI.skin;
GUI.skin = UIStyles.WindowSkin;
MainRect = GUI.Window(MainWindowID, MainRect, (GUI.WindowFunction)MainWindow, CppExplorer.NAME); MainRect = GUI.Window(MainWindowID, MainRect, (GUI.WindowFunction)MainWindow, CppExplorer.NAME);
GUI.skin = origSkin;
} }
private void MainWindow(int id) private void MainWindow(int id)
{ {
GUI.DragWindow(new Rect(0, 0, MainRect.width - 90, 20)); GUI.DragWindow(new Rect(0, 0, MainRect.width - 90, 20));
if (GUI.Button(new Rect(MainRect.width - 90, 2, 80, 20), "Hide (F7)")) if (GUI.Button(new Rect(MainRect.width - 90, 2, 80, 20), $"Hide ({ModConfig.Instance.Main_Menu_Toggle})"))
{ {
CppExplorer.ShowMenu = false; CppExplorer.ShowMenu = false;
return; return;
@ -107,14 +103,16 @@ namespace Explorer
GUI.color = Color.white; GUI.color = Color.white;
InspectUnderMouse.EnableInspect = GUILayout.Toggle(InspectUnderMouse.EnableInspect, "Inspect Under Mouse (Shift + RMB)", null); InspectUnderMouse.EnableInspect = GUILayout.Toggle(InspectUnderMouse.EnableInspect, "Inspect Under Mouse (Shift + RMB)", null);
bool mouseState = CppExplorer.ForceUnlockMouse; bool mouseState = CursorControl.ForceUnlockMouse;
bool setMouse = GUILayout.Toggle(mouseState, "Force Unlock Mouse (Left Alt)", null); bool setMouse = GUILayout.Toggle(mouseState, "Force Unlock Mouse (Left Alt)", null);
if (setMouse != mouseState) CppExplorer.ForceUnlockMouse = setMouse; if (setMouse != mouseState) CursorControl.ForceUnlockMouse = setMouse;
WindowManager.TabView = GUILayout.Toggle(WindowManager.TabView, "Tab View", null); WindowManager.TabView = GUILayout.Toggle(WindowManager.TabView, "Tab View", null);
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.Space(10); //GUIUnstrip.Space(10);
GUIUnstrip.Space(10);
GUI.color = Color.white; GUI.color = Color.white;
} }
} }

View File

@ -244,7 +244,7 @@ namespace Explorer
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.Space(5); GUIUnstrip.Space(5);
} }
private void SceneChangeButtons() private void SceneChangeButtons()

View File

@ -428,7 +428,7 @@ namespace Explorer
{ {
var t = ReflectionHelpers.GetActualType(obj); var t = ReflectionHelpers.GetActualType(obj);
if (!FilterName(t.FullName) || ReflectionHelpers.IsEnumerable(t) || ReflectionHelpers.IsCppList(t)) if (!FilterName(t.FullName) || ReflectionHelpers.IsEnumerable(t) || ReflectionHelpers.IsCppEnumerable(t))
{ {
continue; continue;
} }

View File

@ -385,7 +385,7 @@ namespace Explorer
} }
else else
{ {
GUILayout.Space(26); GUIUnstrip.Space(26);
} }
if (GUILayout.Button("<color=cyan>" + ilType.Name + "</color>", new GUILayoutOption[] { GUILayout.Width(m_rect.width / 2 - 100) })) if (GUILayout.Button("<color=cyan>" + ilType.Name + "</color>", new GUILayoutOption[] { GUILayout.Width(m_rect.width / 2 - 100) }))
{ {

View File

@ -32,10 +32,14 @@ namespace Explorer
private UnityEngine.Object m_uObj; private UnityEngine.Object m_uObj;
private Component m_component; private Component m_component;
private static readonly HashSet<string> _memberBlacklist = new HashSet<string> private static readonly HashSet<string> _typeAndMemberBlacklist = new HashSet<string>
{ {
// Causes a crash // Causes a crash
"Type.DeclaringMethod", "Type.DeclaringMethod",
};
private static readonly HashSet<string> _methodStartsWithBlacklist = new HashSet<string>
{
// Pointless (handled by Properties) // Pointless (handled by Properties)
"get_", "get_",
"set_" "set_"
@ -157,7 +161,11 @@ namespace Explorer
continue; continue;
// check blacklisted members // check blacklisted members
if (_memberBlacklist.Any(it => member.Name.StartsWith(it))) var name = member.DeclaringType.Name + "." + member.Name;
if (_typeAndMemberBlacklist.Any(it => it == name))
continue;
if (_methodStartsWithBlacklist.Any(it => member.Name.StartsWith(it)))
continue; continue;
// compare signature to already cached members // compare signature to already cached members
@ -280,7 +288,7 @@ namespace Explorer
GUI.color = Color.white; GUI.color = Color.white;
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.Space(10); GUIUnstrip.Space(10);
Pages.ItemCount = m_cachedMembersFiltered.Length; Pages.ItemCount = m_cachedMembersFiltered.Length;
@ -309,7 +317,7 @@ namespace Explorer
scroll = GUIUnstrip.BeginScrollView(scroll); scroll = GUIUnstrip.BeginScrollView(scroll);
GUILayout.Space(10); GUIUnstrip.Space(10);
UIStyles.HorizontalLine(Color.grey); UIStyles.HorizontalLine(Color.grey);

View File

@ -32,7 +32,7 @@ namespace Explorer
GUILayout.Button(gcDrag, GUI.skin.label, new GUILayoutOption[] { GUILayout.Height(15) }); GUILayout.Button(gcDrag, GUI.skin.label, new GUILayoutOption[] { GUILayout.Height(15) });
//var r = GUILayoutUtility.GetLastRect(); //var r = GUILayoutUtility.GetLastRect();
var r = GUIUnstrip.GetLastRect(); var r = LayoutUtilityUnstrip.GetLastRect();
var mousePos = InputHelper.mousePosition; var mousePos = InputHelper.mousePosition;

View File

@ -17,7 +17,7 @@ namespace Explorer
public object Target; public object Target;
public int windowID; public int windowID;
public Rect m_rect = new Rect(0, 0, 550, 700); public Rect m_rect = new Rect(0,0, ModConfig.Instance.Default_Window_Size.x,ModConfig.Instance.Default_Window_Size.y);
public Vector2 scroll = Vector2.zero; public Vector2 scroll = Vector2.zero;
@ -49,15 +49,7 @@ namespace Explorer
public void OnGUI() public void OnGUI()
{ {
if (CppExplorer.ShowMenu) m_rect = GUI.Window(windowID, m_rect, (GUI.WindowFunction)WindowFunction, Title);
{
var origSkin = GUI.skin;
GUI.skin = UIStyles.WindowSkin;
m_rect = GUI.Window(windowID, m_rect, (GUI.WindowFunction)WindowFunction, Title);
GUI.skin = origSkin;
}
} }
public void Header() public void Header()

View File

@ -14,6 +14,25 @@ namespace Explorer.Tests
public static TestClass Instance => m_instance ?? (m_instance = new TestClass()); public static TestClass Instance => m_instance ?? (m_instance = new TestClass());
private static TestClass m_instance; private static TestClass m_instance;
public TestClass()
{
ILHashSetTest = new Il2CppSystem.Collections.Generic.HashSet<string>();
ILHashSetTest.Add("1");
ILHashSetTest.Add("2");
ILHashSetTest.Add("3");
}
// test HashSets
public static HashSet<string> HashSetTest = new HashSet<string>
{
"One",
"Two",
"Three"
};
public static Il2CppSystem.Collections.Generic.HashSet<string> ILHashSetTest;
// Test indexed parameter // Test indexed parameter
public string this[int arg0, string arg1] public string this[int arg0, string arg1]

View File

@ -42,20 +42,20 @@ namespace Explorer
} }
private static PropertyInfo m_scrollViewStatesInfo; private static PropertyInfo m_scrollViewStatesInfo;
public static void Space(float pixels)
public static Rect GetLastRect()
{ {
EventType type = Event.current.type; GUIUtility.CheckOnGUI();
Rect last;
if (type != EventType.Layout && type != EventType.Used) if (GUILayoutUtility.current.topLevel.isVertical)
{
last = GUILayoutUtility.current.topLevel.GetLastUnstripped(); LayoutUtilityUnstrip.GetRect(0, pixels, GUILayoutUtility.spaceStyle, new GUILayoutOption[] { GUILayout.Height(pixels) });
}
else else
LayoutUtilityUnstrip.GetRect(pixels, 0, GUILayoutUtility.spaceStyle, new GUILayoutOption[] { GUILayout.Width(pixels) });
if (Event.current.type == EventType.Layout)
{ {
last = GUILayoutUtility.kDummyRect; GUILayoutUtility.current.topLevel.entries[GUILayoutUtility.current.topLevel.entries.Count - 1].consideredForMargin = false;
} }
return last;
} }
// Fix for BeginScrollView. // Fix for BeginScrollView.

View File

@ -0,0 +1,112 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace Explorer
{
public class LayoutUtilityUnstrip
{
public static Rect GetRect(float width, float height) { return DoGetRect(width, width, height, height, GUIStyle.none, null); }
public static Rect GetRect(float width, float height, GUIStyle style) { return DoGetRect(width, width, height, height, style, null); }
public static Rect GetRect(float width, float height, params GUILayoutOption[] options) { return DoGetRect(width, width, height, height, GUIStyle.none, options); }
// Reserve layout space for a rectangle with a fixed content area.
public static Rect GetRect(float width, float height, GUIStyle style, params GUILayoutOption[] options)
{ return DoGetRect(width, width, height, height, style, options); }
public static Rect GetRect(float minWidth, float maxWidth, float minHeight, float maxHeight)
{ return DoGetRect(minWidth, maxWidth, minHeight, maxHeight, GUIStyle.none, null); }
public static Rect GetRect(float minWidth, float maxWidth, float minHeight, float maxHeight, GUIStyle style)
{ return DoGetRect(minWidth, maxWidth, minHeight, maxHeight, style, null); }
public static Rect GetRect(float minWidth, float maxWidth, float minHeight, float maxHeight, params GUILayoutOption[] options)
{ return DoGetRect(minWidth, maxWidth, minHeight, maxHeight, GUIStyle.none, options); }
// Reserve layout space for a flexible rect.
public static Rect GetRect(float minWidth, float maxWidth, float minHeight, float maxHeight, GUIStyle style, params GUILayoutOption[] options)
{ return DoGetRect(minWidth, maxWidth, minHeight, maxHeight, style, options); }
static Rect DoGetRect(float minWidth, float maxWidth, float minHeight, float maxHeight, GUIStyle style, GUILayoutOption[] options)
{
switch (Event.current.type)
{
case EventType.Layout:
GUILayoutUtility.current.topLevel.Add(new GUILayoutEntry(minWidth, maxWidth, minHeight, maxHeight, style, options));
return GUILayoutUtility.kDummyRect;
case EventType.Used:
return GUILayoutUtility.kDummyRect;
default:
return GUILayoutUtility.current.topLevel.GetNext().rect;
}
}
public static Rect GetRect(GUIContent content, GUIStyle style) { return DoGetRect(content, style, null); }
// Reserve layout space for a rectangle for displaying some contents with a specific style.
public static Rect GetRect(GUIContent content, GUIStyle style, params GUILayoutOption[] options) { return DoGetRect(content, style, options); }
static Rect DoGetRect(GUIContent content, GUIStyle style, GUILayoutOption[] options)
{
GUIUtility.CheckOnGUI();
switch (Event.current.type)
{
case EventType.Layout:
if (style.isHeightDependantOnWidth)
{
GUILayoutUtility.current.topLevel.Add(new GUIWordWrapSizer(style, content, options));
}
else
{
Vector2 sizeConstraints = new Vector2(0, 0);
if (options != null)
{
foreach (var option in options)
{
if (float.TryParse(option.value.ToString(), out float f))
{
switch (option.type)
{
case GUILayoutOption.Type.maxHeight:
sizeConstraints.y = f;
break;
case GUILayoutOption.Type.maxWidth:
sizeConstraints.x = f;
break;
}
}
}
}
Vector2 size = style.CalcSizeWithConstraints(content, sizeConstraints);
// This is needed on non-integer scale ratios to avoid errors to accumulate in further layout calculations
size.x = Mathf.Ceil(size.x);
size.y = Mathf.Ceil(size.y);
GUILayoutUtility.current.topLevel.Add(new GUILayoutEntry(size.x, size.x, size.y, size.y, style, options));
}
return GUILayoutUtility.kDummyRect;
case EventType.Used:
return GUILayoutUtility.kDummyRect;
default:
var entry = GUILayoutUtility.current.topLevel.GetNext();
//GUIDebugger.LogLayoutEntry(entry.rect, entry.marginLeft, entry.marginRight, entry.marginTop, entry.marginBottom, entry.style);
return entry.rect;
}
}
public static Rect GetLastRect()
{
EventType type = Event.current.type;
Rect last;
if (type != EventType.Layout && type != EventType.Used)
{
last = GUILayoutUtility.current.topLevel.GetLastUnstripped();
}
else
{
last = GUILayoutUtility.kDummyRect;
}
return last;
}
}
}