From 0adb8607dd75e754710e431d26da48fca0e75491 Mon Sep 17 00:00:00 2001 From: SokyranTheDragon Date: Sun, 16 Nov 2025 18:32:06 +0100 Subject: [PATCH] Fix mechanoid raids arriving from water causing desyncs The mechanoid "emerge from water" raids use the current map for spawning pawns, rathehr than the actually raided map. This is a bug/oversight in RimWorld itself, and may get fixed in the future. Currently, this causes issues since checking for currently active map is non-deterministic, thus potentially spawning the mechanoids on different maps for each player. --- Source/Client/Patches/Determinism.cs | 41 ++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/Source/Client/Patches/Determinism.cs b/Source/Client/Patches/Determinism.cs index 016569b5..a56bf353 100644 --- a/Source/Client/Patches/Determinism.cs +++ b/Source/Client/Patches/Determinism.cs @@ -684,4 +684,45 @@ static void Prefix(MainTabWindow_PawnTable __instance) } } + [HarmonyPatch(typeof(PawnsArrivalModeWorker_EmergeFromWater), nameof(PawnsArrivalModeWorker_EmergeFromWater.Arrive))] + static class PawnsArrivalModeWorker_EmergeFromWater_FixCurrentMapUsage + { + static IEnumerable Transpiler(IEnumerable instr) + { + // Due to an oversight, the vanilla method is using Find.CurrentMap rather than using (Map)parms.target. + // This causes bugs in the game, like mechanoids emerging from void/sand/random locations rather than water. + // For us, it currently causes desyncs with multiple maps active, so we need to fix it. + + var currentMapMethod = typeof(Find).DeclaredPropertyGetter(nameof(Find.CurrentMap)); + var targetField = typeof(IncidentParms).DeclaredField(nameof(IncidentParms.target)); + + var patched = 0; + + foreach (var ci in instr) + { + yield return ci; + + // Replace the Find.CurrentMap calls with (Map)parms.target + if (ci.Calls(currentMapMethod)) + { + // Change the current instruction to load the 2nd argument (IncidentParms) + ci.opcode = OpCodes.Ldarg_2; + ci.operand = null; + + // Load the IncidentParms.target field + yield return new CodeInstruction(OpCodes.Ldfld, targetField); + + // Cast the field's value to Map + yield return new CodeInstruction(OpCodes.Castclass, typeof(Map)); + + patched++; + } + } + + const int expectedPatches = 2; + if (patched != expectedPatches) + Log.Error($"Patching emerge from water arrival mode failed. Expected patches: {expectedPatches}, actual patches: {patched}. There was either an issue or the bug was fixed in RimWorld itself."); + } + } + }