From 4e3fd80d80d0a1ceb5098ad2cb81365ad8f1f594 Mon Sep 17 00:00:00 2001
From: SokyranTheDragon <36712560+SokyranTheDragon@users.noreply.github.com>
Date: Sun, 9 Jun 2024 02:04:41 +0200
Subject: [PATCH] Fix issues caused by HugsLib long events (#450)
I've moved the long event patch from Perspective: Ores to `PatchingUtilities` and applied it to HugsLib as well.
---
Source/Mods/HugsLib.cs | 16 +++++++++
Source/Mods/PerspectiveOres.cs | 13 ++-----
Source/PatchingUtilities.cs | 64 ++++++++++++++++++++++++++++++++++
3 files changed, 82 insertions(+), 11 deletions(-)
create mode 100644 Source/Mods/HugsLib.cs
diff --git a/Source/Mods/HugsLib.cs b/Source/Mods/HugsLib.cs
new file mode 100644
index 00000000..b67959f0
--- /dev/null
+++ b/Source/Mods/HugsLib.cs
@@ -0,0 +1,16 @@
+using Verse;
+
+namespace Multiplayer.Compat;
+
+/// HugsLib by UnlimitedHugs
+///
+///
+[MpCompatFor("UnlimitedHugs.HugsLib")]
+public class HugsLib
+{
+ public HugsLib(ModContentPack mod)
+ {
+ // Stop the long event from running when it could break stuff.
+ PatchingUtilities.CancelCallIfLongEventsAreUnsafe("HugsLib.HugsLibController:OnMapInitFinalized");
+ }
+}
\ No newline at end of file
diff --git a/Source/Mods/PerspectiveOres.cs b/Source/Mods/PerspectiveOres.cs
index 9d46e1f3..bbe61db8 100644
--- a/Source/Mods/PerspectiveOres.cs
+++ b/Source/Mods/PerspectiveOres.cs
@@ -10,28 +10,19 @@ namespace Multiplayer.Compat
[MpCompatFor("Owlchemist.PerspectiveOres")]
public class PerspectiveOres
{
- private static bool allowedToRun = true;
-
public PerspectiveOres(ModContentPack mod)
{
- // Patch to MP to mark when to stop long events Perspective: Ores
- MpCompat.harmony.Patch(AccessTools.DeclaredMethod("Multiplayer.Client.SaveLoad:LoadInMainThread"),
- prefix: new HarmonyMethod(typeof(PerspectiveOres), nameof(SetDisallowedToRun)),
- finalizer: new HarmonyMethod(typeof(PerspectiveOres), nameof(SetAllowedToRun)));
+ PatchingUtilities.PatchLongEventMarkers();
// Stop the "ProcessMap" from running when it could break stuff.
MpCompat.harmony.Patch(AccessTools.DeclaredMethod("PerspectiveOres.PerspectiveOresSetup:ProcessMap"),
prefix: new HarmonyMethod(typeof(PerspectiveOres), nameof(StopSecondHostCall)));
}
- private static void SetDisallowedToRun() => allowedToRun = false;
-
- private static void SetAllowedToRun() => allowedToRun = true;
-
private static bool StopSecondHostCall(bool reset)
{
// Stop the host from running it for the second time. It messes stuff up due to the place it's called from.
- if (!allowedToRun)
+ if (!PatchingUtilities.AllowedToRunLongEvents)
return false;
// Prevent it from being called due to settings change, could mess stuff up.
if (reset && MP.IsInMultiplayer)
diff --git a/Source/PatchingUtilities.cs b/Source/PatchingUtilities.cs
index a547220e..736c3675 100644
--- a/Source/PatchingUtilities.cs
+++ b/Source/PatchingUtilities.cs
@@ -917,5 +917,69 @@ public static void InitializeTimestampFixer()
}
#endregion
+
+ #region Unsafe long event cancelling
+
+ public static bool AllowedToRunLongEvents { get; private set; } = true;
+ private static bool longEventMarkerPatchActive = false;
+
+ /// Patches the methods to cancel the call if it's unsafe to start long events
+ /// Names (type colon name) of the methods to patch
+ public static void CancelCallIfLongEventsAreUnsafe(params string[] methodNames) => CancelCallIfLongEventsAreUnsafe(methodNames as IEnumerable);
+
+ /// Patches the methods to cancel the call if it's unsafe to start long events
+ /// Names (type colon name) of the methods to patch
+ public static void CancelCallIfLongEventsAreUnsafe(IEnumerable methodNames)
+ => CancelCallIfLongEventsAreUnsafe(methodNames
+ .Select(m =>
+ {
+ var method = AccessTools.DeclaredMethod(m) ?? AccessTools.Method(m);
+ if (method == null)
+ Log.Error($"({nameof(PatchingUtilities)}) Could not find method {m}");
+ return method;
+ })
+ .Where(m => m != null));
+
+ /// Patches the methods to cancel the call if it's unsafe to start long events
+ /// Methods to patch
+ public static void CancelCallIfLongEventsAreUnsafe(params MethodBase[] methods) => CancelCallIfLongEventsAreUnsafe(methods as IEnumerable);
+
+ /// Patches the methods to cancel the call if it's unsafe to start long events
+ /// Methods to patch
+ public static void CancelCallIfLongEventsAreUnsafe(IEnumerable methods)
+ {
+ PatchLongEventMarkers();
+
+ var patch = new HarmonyMethod(typeof(PatchingUtilities), nameof(StopSecondHostCall));
+ foreach (var method in methods)
+ MpCompat.harmony.Patch(method, prefix: patch);
+ }
+
+ public static void PatchLongEventMarkers()
+ {
+ if (longEventMarkerPatchActive)
+ return;
+
+ longEventMarkerPatchActive = true;
+
+ // Patch to MP to mark when to stop long events Perspective: Ores
+ MpCompat.harmony.Patch(AccessTools.DeclaredMethod("Multiplayer.Client.SaveLoad:LoadInMainThread"),
+ prefix: new HarmonyMethod(typeof(PatchingUtilities), nameof(SetDisallowedToRun)),
+ finalizer: new HarmonyMethod(typeof(PatchingUtilities), nameof(SetAllowedToRun)));
+ }
+
+ private static void SetDisallowedToRun() => AllowedToRunLongEvents = false;
+
+ private static void SetAllowedToRun() => AllowedToRunLongEvents = true;
+
+ private static bool StopSecondHostCall()
+ {
+ // Stop the host from running it for the second time. It messes stuff up due to the place it's called from.
+ // It can cause the host to start generating non-local IDs when they should generate local ones. This causes
+ // the host to assign higher IDs than all the connected clients.
+ return AllowedToRunLongEvents;
+ }
+
+ #endregion
}
}
\ No newline at end of file