Move to hooking for mono extension

This commit is contained in:
D1GQ committed 2026-07-11 04:56:39 -05:00
1 parent 61e355f103
commit 72a7864622
4 files changed
+45 -47

No files matched your search

+3 -3
View File
@@ -16,7 +16,7 @@ using BetterAmongUs.Modules.Support;
using BetterAmongUs.Network; using BetterAmongUs.Network;
using BetterAmongUs.Patches.Client; using BetterAmongUs.Patches.Client;
using BetterAmongUs.Patches.Gameplay.UI.Settings; using BetterAmongUs.Patches.Gameplay.UI.Settings;
using BetterAmongUs.Patches.Unity; using BetterAmongUs.Patches.Hooks;
using BetterAmongUs.Utilities; using BetterAmongUs.Utilities;
using HarmonyLib; using HarmonyLib;
using UnityEngine; using UnityEngine;
@@ -159,7 +159,7 @@ internal class BAUPlugin : BasePlugin
AudioOverrideManager.Initialize(); AudioOverrideManager.Initialize();
Translator.Initialize(); Translator.Initialize();
Harmony.PatchAll(); Harmony.PatchAll();
MonoExtensionPatch.Patch(Harmony); MonoExtensionHook.Install();
GameSettingsPatch.SetupSettings(true); GameSettingsPatch.SetupSettings(true);
BAUModdedSupportEvents.OnBAUOptionsLoadedEvent.InvokeAll([.. OptionItem.AllOptions.Cast<object>()]); BAUModdedSupportEvents.OnBAUOptionsLoadedEvent.InvokeAll([.. OptionItem.AllOptions.Cast<object>()]);
AutoRegisterAttribute.Initialize(); AutoRegisterAttribute.Initialize();
@@ -186,7 +186,7 @@ internal class BAUPlugin : BasePlugin
BetterNotificationManager.Detach(); BetterNotificationManager.Detach();
ClientPatch.Unpatch(); ClientPatch.Unpatch();
Harmony.UnpatchAll(); Harmony.UnpatchAll();
MonoExtensionPatch.Unpatch(Harmony); MonoExtensionHook.Uninstall();
ModManager.Instance.ModStamp.gameObject.SetActive(false); ModManager.Instance.ModStamp.gameObject.SetActive(false);
SceneChanger.ChangeScene("MainMenu"); SceneChanger.ChangeScene("MainMenu");
} }
+1
View File
@@ -3,6 +3,7 @@
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<LangVersion>preview</LangVersion> <LangVersion>preview</LangVersion>
</PropertyGroup> </PropertyGroup>
@@ -1,89 +1,76 @@
using BetterAmongUs.Interfaces; using BetterAmongUs.Interfaces;
using BetterAmongUs.Modules; using BetterAmongUs.Modules;
using HarmonyLib; using HarmonyLib;
using MonoMod.RuntimeDetour;
using UnityEngine; using UnityEngine;
namespace BetterAmongUs.Patches.Unity; namespace BetterAmongUs.Patches.Hooks;
[HarmonyPatch] internal static class MonoExtensionHook
internal static class MonoExtensionPatch
{ {
private static bool _patched = false; private static bool _patched = false;
private static readonly HashSet<Type> PatchedTypes = []; private static readonly HashSet<Type> PatchedTypes = [];
private static readonly List<IDetour> _detours = [];
internal static void Patch(Harmony harmony) internal static void Install()
{ {
if (_patched) return; if (_patched) return;
_patched = true; _patched = true;
try try
{ {
// Find all types that implement IMonoExtension
var extensionTypes = FindAllExtensionTypes(); var extensionTypes = FindAllExtensionTypes();
foreach (var extType in extensionTypes) foreach (var extType in extensionTypes)
{ {
// Get the target MonoBehaviour type from IAutoMonoExtension<T>
var targetType = GetTargetMonoBehaviourType(extType); var targetType = GetTargetMonoBehaviourType(extType);
if (targetType == null) continue; if (targetType == null) continue;
// Only patch each target type once
if (!PatchedTypes.Add(targetType)) continue; if (!PatchedTypes.Add(targetType)) continue;
// Patch the constructor of the target type // Hook the IntPtr constructor
var constructor = AccessTools.Constructor(targetType, [typeof(IntPtr)]); var constructor = AccessTools.Constructor(targetType, [typeof(IntPtr)]);
if (constructor != null) if (constructor != null)
{ {
harmony.Patch(constructor, var hook = new MonoMod.RuntimeDetour.Hook(
postfix: new HarmonyMethod(typeof(MonoExtensionPatch), constructor,
nameof(MonoBehaviour_Constructor_Postfix))); new Action<Action<MonoBehaviour, IntPtr>, MonoBehaviour, IntPtr>(MonoBehaviour_Constructor_Hook)
);
_detours.Add(hook);
} }
// Patch OnDestroy method if it exists on the extension type // Hook OnDestroy
var destroyMethod = AccessTools.Method(extType, nameof(IMonoExtension.OnDestroy)); var destroyMethod = AccessTools.Method(extType, nameof(IMonoExtension.OnDestroy));
if (destroyMethod != null) if (destroyMethod != null)
{ {
harmony.Patch(destroyMethod, var hook = new MonoMod.RuntimeDetour.Hook(
postfix: new HarmonyMethod(typeof(MonoExtensionPatch), destroyMethod,
nameof(IMonoExtension_OnDestroy_Postfix))); new Action<Action<IMonoExtension>, IMonoExtension>(IMonoExtension_OnDestroy_Hook)
);
_detours.Add(hook);
} }
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
_patched = false; _patched = false;
Logger_.Error($"Failed to patch MonoExtension methods: {ex.Message}"); Logger_.Error($"Failed to hook MonoExtension methods: {ex.Message}");
throw; throw;
} }
} }
internal static void Unpatch(Harmony harmony) internal static void Uninstall()
{ {
if (!_patched) return; if (!_patched) return;
try try
{ {
var extensionTypes = FindAllExtensionTypes(); foreach (var detour in _detours)
foreach (var extType in extensionTypes)
{ {
var targetType = GetTargetMonoBehaviourType(extType); detour.Dispose();
if (targetType == null) continue;
// Unpatch constructor
var constructor = AccessTools.Constructor(targetType, [typeof(IntPtr)]);
if (constructor != null)
{
harmony.Unpatch(constructor, HarmonyPatchType.Postfix, harmony.Id);
}
// Unpatch OnDestroy
var destroyMethod = AccessTools.Method(extType, nameof(IMonoExtension.OnDestroy));
if (destroyMethod != null)
{
harmony.Unpatch(destroyMethod, HarmonyPatchType.Postfix, harmony.Id);
}
} }
_detours.Clear();
_patched = false;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -123,21 +110,31 @@ internal static class MonoExtensionPatch
return types; return types;
} }
private static void MonoBehaviour_Constructor_Postfix(MonoBehaviour __instance) private static void MonoBehaviour_Constructor_Hook(Action<MonoBehaviour, IntPtr> orig, MonoBehaviour instance, IntPtr ptr)
{ {
orig(instance, ptr);
try try
{ {
if (__instance == null) return; IMonoExtension.TryAddAutoExtension(instance);
IMonoExtension.TryAddAutoExtension(__instance);
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger_.Error($"Error in MonoExtension constructor patch: {ex.Message}"); Logger_.Error($"Error in constructor hook: {ex.Message}");
} }
} }
private static void IMonoExtension_OnDestroy_Postfix(IMonoExtension __instance) private static void IMonoExtension_OnDestroy_Hook(Action<IMonoExtension> orig, IMonoExtension instance)
{ {
IMonoExtension.TryRemoveExtension(__instance); orig(instance);
try
{
IMonoExtension.TryRemoveExtension(instance);
}
catch (Exception ex)
{
Logger_.Error($"Error in OnDestroy hook: {ex.Message}");
}
} }
} }
+2 -2
View File
@@ -1,9 +1,9 @@
using BetterAmongUs.Modules.Support; using BetterAmongUs.Modules;
using BetterAmongUs.Modules.Support;
using HarmonyLib; using HarmonyLib;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.Networking; using UnityEngine.Networking;
using BetterAmongUs.Modules;
namespace BetterAmongUs.Patches.Unity; namespace BetterAmongUs.Patches.Unity;