Compare commits

..

5 Commits
1.6.4 ... 1.6.5

Author SHA1 Message Date
0769b7ef23 1.6.5
* Add expander to Unity struct inspectors, collapsed by default
* `UnityEngine.Color` labels in Reflection Inspector are now the same color as the value for convenience
* Cleaned up InputHelper
2020-09-08 23:47:17 +10:00
5086dcc82b Update README.md 2020-09-08 20:21:34 +10:00
56abd38e92 Add build instructions to Readme 2020-09-08 20:18:37 +10:00
a7e6ae87df Update README.md 2020-09-08 19:47:07 +10:00
b5c584bb02 Update README.md 2020-09-08 19:46:54 +10:00
9 changed files with 173 additions and 64 deletions

View File

@ -16,6 +16,7 @@
### Known issues ### Known issues
* CppExplorer may experience a `MissingMethodException` when trying to use certain UnityEngine methods. If you experience this, please open an issue and I will do my best to fix it. * CppExplorer may experience a `MissingMethodException` when trying to use certain UnityEngine methods. If you experience this, please open an issue and I will do my best to fix it.
* Reflection may fail with certain types (eg. `Nullable<T>`, some Dictionary types, etc). Please see [Il2CppAssemblyUnhollower](https://github.com/knah/Il2CppAssemblyUnhollower#known-issues) for more details.
* Scrolling with mouse wheel in the CppExplorer menu may not work on all games at the moment. * Scrolling with mouse wheel in the CppExplorer menu may not work on all games at the moment.
## How to install ## How to install
@ -91,6 +92,18 @@ CppExplorer can force the mouse to be visible and unlocked when the menu is open
* For Hellpoint, use [HPExplorerMouseControl](https://github.com/sinai-dev/Hellpoint-Mods/tree/master/HPExplorerMouseControl/HPExplorerMouseControl) * For Hellpoint, use [HPExplorerMouseControl](https://github.com/sinai-dev/Hellpoint-Mods/tree/master/HPExplorerMouseControl/HPExplorerMouseControl)
* You can create your own plugin using one of the two plugins above as an example. Usually only a few simple Harmony patches are needed to fix the problem. * You can create your own plugin using one of the two plugins above as an example. Usually only a few simple Harmony patches are needed to fix the problem.
## 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.
1. Install MelonLoader for your game.
2. Download this repository and open the `CppExplorer.sln` file in the `src` folder.
3. In Visual Studio, right-click the CppExplorer C# Project in the solution browser and click "Unload Project".
4. Right-click the "CppExplorer (unloaded)" and select "Edit Project File".
5. Scroll down until you see the `<ItemGroup>` containing the References.
6. Fix all of the paths in the `..\Steam\` directory for your game (use the full path if you need to).
7. Reload the project and everything should be working, you can now build and run it.
## Credits ## Credits
Written by Sinai. Written by Sinai.

View File

@ -9,6 +9,8 @@ namespace Explorer
{ {
public class CacheColor : CacheObjectBase public class CacheColor : CacheObjectBase
{ {
private bool IsExpanded;
private string r = "0"; private string r = "0";
private string g = "0"; private string g = "0";
private string b = "0"; private string b = "0";
@ -28,9 +30,30 @@ namespace Explorer
public override void DrawValue(Rect window, float width) public override void DrawValue(Rect window, float width)
{ {
GUILayout.Label($"<color=yellow>Color</color>: {((Color)Value).ToString()}", null);
if (CanWrite) if (CanWrite)
{
if (!IsExpanded)
{
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
{
IsExpanded = true;
}
}
else
{
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) }))
{
IsExpanded = false;
}
}
}
var c = (Color)Value;
GUI.color = c;
GUILayout.Label($"<color=yellow>Color:</color> {c.ToString()}", null);
GUI.color = Color.white;
if (CanWrite && IsExpanded)
{ {
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
var whitespace = window.width - width - 90; var whitespace = window.width - width - 90;

View File

@ -9,6 +9,8 @@ namespace Explorer
{ {
public class CacheQuaternion : CacheObjectBase public class CacheQuaternion : CacheObjectBase
{ {
private bool IsExpanded;
private string x = "0"; private string x = "0";
private string y = "0"; private string y = "0";
private string z = "0"; private string z = "0";
@ -26,9 +28,27 @@ namespace Explorer
public override void DrawValue(Rect window, float width) public override void DrawValue(Rect window, float width)
{ {
if (CanWrite)
{
if (!IsExpanded)
{
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
{
IsExpanded = true;
}
}
else
{
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) }))
{
IsExpanded = false;
}
}
}
GUILayout.Label($"<color=yellow>Quaternion</color>: {((Quaternion)Value).eulerAngles.ToString()}", null); GUILayout.Label($"<color=yellow>Quaternion</color>: {((Quaternion)Value).eulerAngles.ToString()}", null);
if (CanWrite) if (CanWrite && IsExpanded)
{ {
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
var whitespace = window.width - width - 90; var whitespace = window.width - width - 90;

View File

@ -9,6 +9,8 @@ namespace Explorer
{ {
public class CacheRect : CacheObjectBase public class CacheRect : CacheObjectBase
{ {
private bool IsExpanded;
private string x = "0"; private string x = "0";
private string y = "0"; private string y = "0";
private string w = "0"; private string w = "0";
@ -28,9 +30,27 @@ namespace Explorer
public override void DrawValue(Rect window, float width) public override void DrawValue(Rect window, float width)
{ {
if (CanWrite)
{
if (!IsExpanded)
{
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
{
IsExpanded = true;
}
}
else
{
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) }))
{
IsExpanded = false;
}
}
}
GUILayout.Label($"<color=yellow>Rect</color>: {((Rect)Value).ToString()}", null); GUILayout.Label($"<color=yellow>Rect</color>: {((Rect)Value).ToString()}", null);
if (CanWrite) if (CanWrite && IsExpanded)
{ {
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
var whitespace = window.width - width - 90; var whitespace = window.width - width - 90;

View File

@ -10,6 +10,8 @@ namespace Explorer
{ {
public class CacheVector : CacheObjectBase public class CacheVector : CacheObjectBase
{ {
private bool IsExpanded;
public int VectorSize = 2; public int VectorSize = 2;
private string x = "0"; private string x = "0";
@ -63,9 +65,27 @@ namespace Explorer
public override void DrawValue(Rect window, float width) public override void DrawValue(Rect window, float width)
{ {
if (CanWrite)
{
if (!IsExpanded)
{
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
{
IsExpanded = true;
}
}
else
{
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) }))
{
IsExpanded = false;
}
}
}
GUILayout.Label($"<color=yellow>Vector{VectorSize}</color>: {(string)m_toStringMethod.Invoke(Value, new object[0])}", null); GUILayout.Label($"<color=yellow>Vector{VectorSize}</color>: {(string)m_toStringMethod.Invoke(Value, new object[0])}", null);
if (CanWrite) if (CanWrite && IsExpanded)
{ {
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
var whitespace = window.width - width - 90; var whitespace = window.width - width - 90;

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.4"; public const string VERSION = "1.6.5";
public const string AUTHOR = "Sinai"; public const string AUTHOR = "Sinai";
public const string GUID = "com.sinai.cppexplorer"; public const string GUID = "com.sinai.cppexplorer";
@ -50,7 +50,7 @@ namespace Explorer
{ {
Instance = this; Instance = this;
InputHelper.CheckInput(); InputHelper.Init();
new MainMenu(); new MainMenu();
new WindowManager(); new WindowManager();

View File

@ -2,7 +2,7 @@
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}</ProjectGuid> <ProjectGuid>{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}</ProjectGuid>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
@ -24,6 +24,7 @@
<Prefer32Bit>false</Prefer32Bit> <Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<!-- Replace the '..\Steam\..` references with ones from your game (make sure to use the 'MelonLoader\' folder) -->
<Reference Include="Il2Cppmscorlib"> <Reference Include="Il2Cppmscorlib">
<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>
@ -46,7 +47,6 @@
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnhollowerBaseLib.dll</HintPath> <HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnhollowerBaseLib.dll</HintPath>
<Private>False</Private> <Private>False</Private>
</Reference> </Reference>
<!-- Replace these references with ones from your game (..\MelonLoader\ folder) -->
<Reference Include="UnityEngine"> <Reference Include="UnityEngine">
<HintPath>..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.dll</HintPath> <HintPath>..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.dll</HintPath>
<Private>False</Private> <Private>False</Private>

View File

@ -10,8 +10,8 @@ Global
Release|Any CPU = Release|Any CPU Release|Any CPU = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release|Any CPU.ActiveCfg = Release|Any CPU {B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release|Any CPU.ActiveCfg = Debug|Any CPU
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release|Any CPU.Build.0 = Release|Any CPU {B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release|Any CPU.Build.0 = Debug|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -15,93 +15,106 @@ namespace Explorer
/// </summary> /// </summary>
public static class InputHelper public static class InputHelper
{ {
public static void CheckInput() // If Input module failed to load at all
{ public static bool NO_INPUT;
if (Input == null)
{
MelonLogger.Log("UnityEngine.Input is null, trying to load manually....");
if ((TryLoad("UnityEngine.InputLegacyModule.dll") || TryLoad("UnityEngine.CoreModule.dll")) && Input != null) // Base UnityEngine.Input class
{ private static Type Input => _input ?? (_input = ReflectionHelpers.GetTypeByName("UnityEngine.Input"));
MelonLogger.Log("Ok!");
}
else
{
MelonLogger.Log("Could not load Input module!");
}
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;
}
}
}
}
public static Type Input => _input ?? (_input = ReflectionHelpers.GetTypeByName("UnityEngine.Input"));
private static Type _input; private static Type _input;
private static PropertyInfo MousePosInfo => _mousePosition ?? (_mousePosition = Input?.GetProperty("mousePosition")); // Cached member infos
private static PropertyInfo _mousePosition; private static PropertyInfo _mousePosition;
private static MethodInfo GetKeyInfo => _getKey ?? (_getKey = Input?.GetMethod("GetKey", new Type[] { typeof(KeyCode) }));
private static MethodInfo _getKey; private static MethodInfo _getKey;
private static MethodInfo GetKeyDownInfo => _getKeyDown ?? (_getKeyDown = Input?.GetMethod("GetKeyDown", new Type[] { typeof(KeyCode) }));
private static MethodInfo _getKeyDown; private static MethodInfo _getKeyDown;
private static MethodInfo GetMouseButtonInfo => _getMouseButton ?? (_getMouseButton = Input?.GetMethod("GetMouseButton", new Type[] { typeof(int) }));
private static MethodInfo _getMouseButton; private static MethodInfo _getMouseButton;
private static MethodInfo GetMouseButtonDownInfo => _getMouseButtonDown ?? (_getMouseButtonDown = Input?.GetMethod("GetMouseButtonDown", new Type[] { typeof(int) }));
private static MethodInfo _getMouseButtonDown; private static MethodInfo _getMouseButtonDown;
public static void Init()
{
if (Input == null && !TryManuallyLoadInput())
{
NO_INPUT = true;
return;
}
// Cache reflection now that we know Input is loaded
_mousePosition = Input.GetProperty("mousePosition");
_getKey = Input.GetMethod("GetKey", new Type[] { typeof(KeyCode) });
_getKeyDown = Input.GetMethod("GetKeyDown", new Type[] { typeof(KeyCode) });
_getMouseButton = Input.GetMethod("GetMouseButton", new Type[] { typeof(int) });
_getMouseButtonDown = Input.GetMethod("GetMouseButtonDown", new Type[] { typeof(int) });
}
#pragma warning disable IDE1006 // Camel-case property (Unity style) #pragma warning disable IDE1006 // Camel-case property (Unity style)
public static Vector3 mousePosition public static Vector3 mousePosition
{ {
get get
{ {
if (Input == null) return Vector3.zero; if (NO_INPUT) return Vector3.zero;
return (Vector3)MousePosInfo.GetValue(null); return (Vector3)_mousePosition.GetValue(null);
} }
} }
#pragma warning restore IDE1006 #pragma warning restore IDE1006
public static bool GetKeyDown(KeyCode key) public static bool GetKeyDown(KeyCode key)
{ {
if (Input == null) return false; if (NO_INPUT) return false;
return (bool)GetKeyDownInfo.Invoke(null, new object[] { key }); return (bool)_getKeyDown.Invoke(null, new object[] { key });
} }
public static bool GetKey(KeyCode key) public static bool GetKey(KeyCode key)
{ {
if (Input == null) return false; if (NO_INPUT) return false;
return (bool)GetKeyInfo.Invoke(null, new object[] { key }); return (bool)_getKey.Invoke(null, new object[] { key });
} }
/// <param name="btn">1 = left, 2 = middle, 3 = right, etc</param> /// <param name="btn">1 = left, 2 = middle, 3 = right, etc</param>
public static bool GetMouseButtonDown(int btn) public static bool GetMouseButtonDown(int btn)
{ {
if (Input == null) return false; if (NO_INPUT) return false;
return (bool)GetMouseButtonDownInfo.Invoke(null, new object[] { btn }); return (bool)_getMouseButtonDown.Invoke(null, new object[] { btn });
} }
/// <param name="btn">1 = left, 2 = middle, 3 = right, etc</param> /// <param name="btn">1 = left, 2 = middle, 3 = right, etc</param>
public static bool GetMouseButton(int btn) public static bool GetMouseButton(int btn)
{ {
if (Input == null) return false; if (NO_INPUT) return false;
return (bool)GetMouseButtonInfo.Invoke(null, new object[] { btn }); return (bool)_getMouseButton.Invoke(null, new object[] { btn });
}
private static bool TryManuallyLoadInput()
{
MelonLogger.Log("UnityEngine.Input is null, trying to load manually....");
if ((TryLoad("UnityEngine.InputLegacyModule.dll") || TryLoad("UnityEngine.CoreModule.dll")) && Input != null)
{
MelonLogger.Log("Ok!");
return true;
}
else
{
MelonLogger.Log("Could not load Input module!");
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;
}
}
} }
} }
} }