Skip to content
This repository was archived by the owner on May 9, 2023. It is now read-only.

Commit 6d479a6

Browse files
committed
3.3.4
* Fixed Harmony patches not working properly for games which use older BepInEx releases (ie. Risk of Rain 2) * Fixed a couple minor issues with the config settings
1 parent 6539f81 commit 6d479a6

File tree

9 files changed

+175
-131
lines changed

9 files changed

+175
-131
lines changed

README.md

Lines changed: 11 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,24 @@
1919

2020
### BepInEx
2121

22-
0. Install [BepInEx](https://github.com/BepInEx/BepInEx) for your game. For IL2CPP you should use [BepInEx 6 (Bleeding Edge)](https://builds.bepis.io/projects/bepinex_be), for Mono you should use [BepInEx 5](https://github.com/BepInEx/BepInEx/releases) (until Mono support stabilizes in BepInEx 6).
23-
1. Download the UnityExplorer release for BepInEx IL2CPP or Mono above.
24-
2. Take the `UnityExplorer.BIE.___.dll` file and put it in `[GameFolder]\BepInEx\plugins\`
25-
3. In IL2CPP, you will need to download the [Unity libs](https://github.com/LavaGang/Unity-Runtime-Libraries) for the game's Unity version and put them in the `BepInEx\unity-libs\` folder.
22+
1. Install [BepInEx](https://github.com/BepInEx/BepInEx) for your game. For IL2CPP you should use [BepInEx 6 (Bleeding Edge)](https://builds.bepis.io/projects/bepinex_be), for Mono you should use [BepInEx 5](https://github.com/BepInEx/BepInEx/releases) (until Mono support stabilizes in BepInEx 6).
23+
2. Download the UnityExplorer release for BepInEx IL2CPP or Mono above.
24+
3. Take the `UnityExplorer.BIE.___.dll` file and put it in `[GameFolder]\BepInEx\plugins\`
25+
4. In IL2CPP, you will need to download the [Unity libs](https://github.com/LavaGang/Unity-Runtime-Libraries) for the game's Unity version and put them in the `BepInEx\unity-libs\` folder.
2626

2727
### MelonLoader
2828

29-
0. Install [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) 0.3+ for your game. Version 0.3 is currently in pre-release, so you must "Enable ALPHA Releases" in your MelonLoader Installer settings to see the option for it.
30-
1. Download the UnityExplorer release for MelonLoader IL2CPP or Mono above.
31-
2. Take the `UnityExplorer.ML.___.dll` file and put it in the `[GameFolder]\Mods\` folder.
29+
1. Install [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) 0.3+ for your game. Version 0.3 is currently in pre-release, so you must "Enable ALPHA Releases" in your MelonLoader Installer settings to see the option for it.
30+
2. Download the UnityExplorer release for MelonLoader IL2CPP or Mono above.
31+
3. Take the `UnityExplorer.ML.___.dll` file and put it in the `[GameFolder]\Mods\` folder.
3232

3333
### Standalone
3434

35-
The standalone release is based on the BepInEx build, so it requires Harmony 2.0 (or HarmonyX) to function properly.
35+
The standalone release requires you to also load `0Harmony.dll` (HarmonyX, from the `lib\` folder) to function properly, and the IL2CPP also requires `UnhollowerBaseLib.dll` as well. The Mono release should be fairly easy to use with any loader, but the IL2CPP one may be tricky, I'd recommend just using BepInEx or MelonLoader for IL2CPP.
3636

37-
0. Load the DLL from your mod or inject it. You must also make sure `0Harmony.dll` is loaded, and `UnhollowerBaseLib.dll` for IL2CPP as well.
38-
1. Create an instance of Unity Explorer with `UnityExplorer.ExplorerStandalone.CreateInstance();`
39-
2. Optionally subscribe to the `ExplorerStandalone.OnLog` event to handle logging if you wish.
37+
1. Load the UnityExplorer DLL from your mod or inject it, as well as `0Harmony.dll` and `UnhollowerBaseLib.dll` as required.
38+
2. Create an instance of Unity Explorer with `UnityExplorer.ExplorerStandalone.CreateInstance();`
39+
3. Optionally subscribe to the `ExplorerStandalone.OnLog` event to handle logging if you wish.
4040

4141
## Issues and contributions
4242

@@ -124,31 +124,6 @@ Depending on the release you are using, the config file will be found at:
124124
* MelonLoader: `UserData\MelonPreferences.cfg`
125125
* Standalone `{DLL_location}\UnityExplorer\config.ini`
126126

127-
`Main Menu Toggle` (KeyCode)
128-
* Default: `F7`
129-
* See [this article](https://docs.unity3d.com/ScriptReference/KeyCode.html) for a full list of all accepted KeyCodes.
130-
131-
`Force Unlock Mouse` (bool)
132-
* Default: `true`
133-
* Forces the cursor to be unlocked and visible while the UnityExplorer menu is open, and prevents anything else taking control.
134-
135-
`Default Page Limit` (int)
136-
* Default: `25`
137-
* Sets the default items per page when viewing lists or search results.
138-
* <b>Requires a restart to take effect</b>, apart from Reflection Inspector tabs.
139-
140-
`Default Output Path` (string)
141-
* Default: `Mods\UnityExplorer`
142-
* Where output is generated to, by default (for Texture PNG saving, etc).
143-
144-
`Log Unity Debug` (bool)
145-
* Default: `false`
146-
* Listens for Unity `Debug.Log` messages and prints them to UnityExplorer's log.
147-
148-
`Hide on Startup` (bool)
149-
* Default: `false`
150-
* If true, UnityExplorer will be hidden when you start the game, you must open it via the keybind.
151-
152127
## Building
153128

154129
Building the project should be straight-forward, the references are all inside the `lib\` folder.

lib/BepInEx.dll

-3 KB
Binary file not shown.

src/Core/Config/ConfigElement.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public ConfigElement(string name, string description, T defaultValue, bool isInt
4646

4747
private void SetValue(T value)
4848
{
49-
if ((m_value == null && value == null) || m_value.Equals(value))
49+
if ((m_value == null && value == null) || (m_value != null && m_value.Equals(value)))
5050
return;
5151

5252
m_value = value;

src/Core/Input/CursorUnlocker.cs

Lines changed: 28 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -46,86 +46,21 @@ public static void Init()
4646

4747
UpdateCursorControl();
4848

49-
Unlock = true;
49+
Unlock = ConfigManager.Force_Unlock_Mouse.Value;
5050
ConfigManager.Force_Unlock_Mouse.OnValueChanged += (bool val) => { Unlock = val; };
5151
}
5252

53-
private static void SetupPatches()
54-
{
55-
try
56-
{
57-
if (CursorType == null)
58-
{
59-
throw new Exception("Could not find Type 'UnityEngine.Cursor'!");
60-
}
61-
62-
// Get current cursor state and enable cursor
63-
try
64-
{
65-
m_lastLockMode = (CursorLockMode?)typeof(Cursor).GetProperty("lockState", BF.Public | BF.Static)?.GetValue(null, null)
66-
?? CursorLockMode.None;
67-
68-
m_lastVisibleState = (bool?)typeof(Cursor).GetProperty("visible", BF.Public | BF.Static)?.GetValue(null, null)
69-
?? false;
70-
}
71-
catch { }
72-
73-
// Setup Harmony Patches
74-
TryPatch(typeof(Cursor),
75-
"lockState",
76-
new HarmonyMethod(typeof(CursorUnlocker).GetMethod(nameof(Prefix_set_lockState))),
77-
true);
78-
79-
TryPatch(typeof(Cursor),
80-
"visible",
81-
new HarmonyMethod(typeof(CursorUnlocker).GetMethod(nameof(Prefix_set_visible))),
82-
true);
83-
84-
TryPatch(typeof(EventSystem),
85-
"current",
86-
new HarmonyMethod(typeof(CursorUnlocker).GetMethod(nameof(Prefix_EventSystem_set_current))),
87-
true);
88-
}
89-
catch (Exception e)
90-
{
91-
ExplorerCore.Log($"Exception on ForceUnlockCursor.Init! {e.GetType()}, {e.Message}");
92-
}
93-
}
94-
95-
private static void TryPatch(Type type, string property, HarmonyMethod patch, bool setter)
96-
{
97-
try
98-
{
99-
var harmony = ExplorerCore.Loader.HarmonyInstance;
100-
101-
var prop = type.GetProperty(property);
102-
103-
if (setter) // setter is prefix
104-
{
105-
harmony.Patch(prop.GetSetMethod(), prefix: patch);
106-
}
107-
else // getter is postfix
108-
{
109-
harmony.Patch(prop.GetGetMethod(), postfix: patch);
110-
}
111-
}
112-
catch (Exception e)
113-
{
114-
string suf = setter ? "set_" : "get_";
115-
ExplorerCore.Log($"Unable to patch {type.Name}.{suf}{property}: {e.Message}");
116-
}
117-
}
118-
11953
public static void UpdateCursorControl()
12054
{
12155
try
12256
{
12357
m_currentlySettingCursor = true;
58+
12459
if (ShouldActuallyUnlock)
12560
{
12661
Cursor.lockState = CursorLockMode.None;
12762
Cursor.visible = true;
128-
63+
12964
if (UIManager.EventSys)
13065
SetEventSystem();
13166
}
@@ -137,6 +72,7 @@ public static void UpdateCursorControl()
13772
if (UIManager.EventSys)
13873
ReleaseEventSystem();
13974
}
75+
14076
m_currentlySettingCursor = false;
14177
}
14278
catch (Exception e)
@@ -163,9 +99,7 @@ public static void SetEventSystem()
16399
if (!m_lastEventSystem)
164100
m_lastEventSystem = EventSystem.current;
165101

166-
//ExplorerCore.Log("Disabling current event system...");
167102
m_lastEventSystem.enabled = false;
168-
//m_lastEventSystem.gameObject.SetActive(false);
169103
}
170104

171105
// Set to our current system
@@ -184,7 +118,6 @@ public static void ReleaseEventSystem()
184118
if (m_lastEventSystem)
185119
{
186120
m_lastEventSystem.enabled = true;
187-
//m_lastEventSystem.gameObject.SetActive(true);
188121

189122
m_settingEventSystem = true;
190123
EventSystem.current = m_lastEventSystem;
@@ -193,7 +126,30 @@ public static void ReleaseEventSystem()
193126
}
194127
}
195128

196-
[HarmonyPrefix]
129+
// Patches
130+
131+
private static void SetupPatches()
132+
{
133+
try
134+
{
135+
if (CursorType == null)
136+
throw new Exception("Could not load Type 'UnityEngine.Cursor'!");
137+
138+
// Get current cursor state and enable cursor
139+
m_lastLockMode = (CursorLockMode?)CursorType.GetProperty("lockState", BF.Public | BF.Static)?.GetValue(null, null)
140+
?? CursorLockMode.None;
141+
142+
m_lastVisibleState = (bool?)CursorType.GetProperty("visible", BF.Public | BF.Static)?.GetValue(null, null)
143+
?? false;
144+
145+
ExplorerCore.Loader.SetupPatches();
146+
}
147+
catch (Exception e)
148+
{
149+
ExplorerCore.Log($"Error on CursorUnlocker.Init! {e.GetType()}, {e.Message}");
150+
}
151+
}
152+
197153
public static void Prefix_EventSystem_set_current(ref EventSystem value)
198154
{
199155
if (!m_settingEventSystem)
@@ -210,7 +166,6 @@ public static void Prefix_EventSystem_set_current(ref EventSystem value)
210166
// Also keep track of when anything else tries to set Cursor state, this will be the
211167
// value that we set back to when we close the menu or disable force-unlock.
212168

213-
[HarmonyPrefix]
214169
public static void Prefix_set_lockState(ref CursorLockMode value)
215170
{
216171
if (!m_currentlySettingCursor)
@@ -222,7 +177,6 @@ public static void Prefix_set_lockState(ref CursorLockMode value)
222177
}
223178
}
224179

225-
[HarmonyPrefix]
226180
public static void Prefix_set_visible(ref bool value)
227181
{
228182
if (!m_currentlySettingCursor)

src/ExplorerCore.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace UnityExplorer
1212
public class ExplorerCore
1313
{
1414
public const string NAME = "UnityExplorer";
15-
public const string VERSION = "3.3.3";
15+
public const string VERSION = "3.3.4";
1616
public const string AUTHOR = "Sinai";
1717
public const string GUID = "com.sinai.unityexplorer";
1818

src/Loader/BIE/ExplorerBepInPlugin.cs

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
using UnityExplorer.Core.Config;
1111
using UnityExplorer.Loader.BIE;
1212
using UnityEngine;
13+
using UnityExplorer.Core;
14+
using UnityEngine.EventSystems;
15+
using UnityExplorer.Core.Input;
1316
#if CPP
1417
using BepInEx.IL2CPP;
1518
using UnhollowerRuntimeLib;
@@ -75,10 +78,8 @@ public override void Load()
7578

7679
ClassInjector.RegisterTypeInIl2Cpp<ExplorerBehaviour>();
7780

78-
var obj = new GameObject(
79-
"ExplorerBehaviour",
80-
new Il2CppSystem.Type[] { Il2CppType.Of<ExplorerBehaviour>() }
81-
);
81+
var obj = new GameObject("ExplorerBehaviour");
82+
obj.AddComponent<ExplorerBehaviour>();
8283
obj.hideFlags = HideFlags.HideAndDontSave;
8384
GameObject.DontDestroyOnLoad(obj);
8485

@@ -101,6 +102,48 @@ internal void Update()
101102
}
102103
}
103104
#endif
105+
106+
public void SetupPatches()
107+
{
108+
try
109+
{
110+
this.HarmonyInstance.PatchAll();
111+
}
112+
catch (Exception ex)
113+
{
114+
ExplorerCore.Log($"Exception setting up Harmony patches:\r\n{ex.ReflectionExToString()}");
115+
}
116+
}
117+
118+
[HarmonyPatch(typeof(EventSystem), "current", MethodType.Setter)]
119+
public class PATCH_EventSystem_current
120+
{
121+
[HarmonyPrefix]
122+
public static void Prefix_EventSystem_set_current(ref EventSystem value)
123+
{
124+
CursorUnlocker.Prefix_EventSystem_set_current(ref value);
125+
}
126+
}
127+
128+
[HarmonyPatch(typeof(Cursor), "lockState", MethodType.Setter)]
129+
public class PATCH_Cursor_lockState
130+
{
131+
[HarmonyPrefix]
132+
public static void Prefix_set_lockState(ref CursorLockMode value)
133+
{
134+
CursorUnlocker.Prefix_set_lockState(ref value);
135+
}
136+
}
137+
138+
[HarmonyPatch(typeof(Cursor), "visible", MethodType.Setter)]
139+
public class PATCH_Cursor_visible
140+
{
141+
[HarmonyPrefix]
142+
public static void Prefix_set_visible(ref bool value)
143+
{
144+
CursorUnlocker.Prefix_set_visible(ref value);
145+
}
146+
}
104147
}
105148
}
106149
#endif

src/Loader/IExplorerLoader.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,6 @@ public interface IExplorerLoader
1717
Action<object> OnLogWarning { get; }
1818
Action<object> OnLogError { get; }
1919

20-
#if ML
21-
Harmony.HarmonyInstance HarmonyInstance { get; }
22-
#else
23-
HarmonyLib.Harmony HarmonyInstance { get; }
24-
#endif
20+
void SetupPatches();
2521
}
2622
}

src/Loader/ML/ExplorerMelonMod.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
#if ML
22
using System;
33
using System.IO;
4+
using Harmony;
45
using MelonLoader;
56
using UnityEngine;
7+
using UnityEngine.EventSystems;
68
using UnityExplorer;
9+
using UnityExplorer.Core;
710
using UnityExplorer.Core.Config;
11+
using UnityExplorer.Core.Input;
812
using UnityExplorer.Loader.ML;
913

1014
[assembly: MelonInfo(typeof(ExplorerMelonMod), ExplorerCore.NAME, ExplorerCore.VERSION, ExplorerCore.AUTHOR)]
@@ -40,6 +44,41 @@ public override void OnUpdate()
4044
{
4145
ExplorerCore.Update();
4246
}
47+
48+
public void SetupPatches()
49+
{
50+
try
51+
{
52+
PrefixProperty(typeof(Cursor),
53+
"lockState",
54+
new HarmonyMethod(typeof(CursorUnlocker).GetMethod(nameof(CursorUnlocker.Prefix_set_lockState))));
55+
56+
PrefixProperty(typeof(Cursor),
57+
"visible",
58+
new HarmonyMethod(typeof(CursorUnlocker).GetMethod(nameof(CursorUnlocker.Prefix_set_visible))));
59+
60+
PrefixProperty(typeof(EventSystem),
61+
"current",
62+
new HarmonyMethod(typeof(CursorUnlocker).GetMethod(nameof(CursorUnlocker.Prefix_EventSystem_set_current))));
63+
}
64+
catch (Exception ex)
65+
{
66+
ExplorerCore.Log($"Exception setting up Harmony patches:\r\n{ex.ReflectionExToString()}");
67+
}
68+
}
69+
70+
private void PrefixProperty(Type type, string property, HarmonyMethod prefix)
71+
{
72+
try
73+
{
74+
var prop = type.GetProperty(property);
75+
this.Harmony.Patch(prop.GetSetMethod(), prefix: prefix);
76+
}
77+
catch (Exception e)
78+
{
79+
ExplorerCore.Log($"Unable to patch {type.Name}.set_{property}: {e.Message}");
80+
}
81+
}
4382
}
4483
}
4584
#endif

0 commit comments

Comments
 (0)