From 1cfbc5cee7445b03e8259baebb7c3aafc8b63c9b Mon Sep 17 00:00:00 2001 From: Christopher Galpin <52485+CodeOptimist@users.noreply.github.com> Date: Wed, 17 Apr 2024 18:39:05 -0600 Subject: [PATCH 1/2] fix for v1.5 UnnaturalCorpse event --- Source/Client/Patches/Determinism.cs | 29 +++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/Source/Client/Patches/Determinism.cs b/Source/Client/Patches/Determinism.cs index 849171dd..e6c6df24 100644 --- a/Source/Client/Patches/Determinism.cs +++ b/Source/Client/Patches/Determinism.cs @@ -123,7 +123,34 @@ static void Postfix(ref FloodUnfogResult __result) __result.allOnScreen = false; } } - + + [HarmonyPatch] + static class UnnaturalCorpsePatch // v1.5 + { + static IEnumerable TargetMethods() + { + yield return AccessTools.DeclaredMethod(typeof(AnomalyUtility), nameof(AnomalyUtility.IsValidUnseenCell)); + yield return AccessTools.DeclaredMethod(typeof(UnnaturalCorpse), nameof(UnnaturalCorpse.IsOutsideView)); + } + + static MethodInfo CellRectContains = AccessTools.Method(typeof(CellRect), nameof(CellRect.Contains)); + + static IEnumerable Transpiler(IEnumerable insts) + { + foreach (var inst in insts) + { + yield return inst; + + // consider it always outside view (not contained in CurrentViewRect) + if (inst.operand == CellRectContains) + { + yield return new CodeInstruction(OpCodes.Ldc_I4_0); + yield return new CodeInstruction(OpCodes.And); + } + } + } + } + [HarmonyPatch(typeof(Pawn), nameof(Pawn.ProcessPostTickVisuals))] static class DrawTrackerTickPatch { From b617f9cafd83478a0fdcc3537c48c86955c119ec Mon Sep 17 00:00:00 2001 From: Christopher Galpin <52485+CodeOptimist@users.noreply.github.com> Date: Sat, 4 May 2024 19:10:53 -0600 Subject: [PATCH 2/2] handle `Find.CurrentMap` --- Source/Client/Patches/Determinism.cs | 41 ++++++++++++++++------------ 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/Source/Client/Patches/Determinism.cs b/Source/Client/Patches/Determinism.cs index e6c6df24..1ed91384 100644 --- a/Source/Client/Patches/Determinism.cs +++ b/Source/Client/Patches/Determinism.cs @@ -123,31 +123,38 @@ static void Postfix(ref FloodUnfogResult __result) __result.allOnScreen = false; } } - + [HarmonyPatch] - static class UnnaturalCorpsePatch // v1.5 + static class UnnaturalCorpsePatch { static IEnumerable TargetMethods() { + // both of these actually combine "is valid" semantics with "is unseen" yield return AccessTools.DeclaredMethod(typeof(AnomalyUtility), nameof(AnomalyUtility.IsValidUnseenCell)); yield return AccessTools.DeclaredMethod(typeof(UnnaturalCorpse), nameof(UnnaturalCorpse.IsOutsideView)); } - static MethodInfo CellRectContains = AccessTools.Method(typeof(CellRect), nameof(CellRect.Contains)); - - static IEnumerable Transpiler(IEnumerable insts) - { - foreach (var inst in insts) - { - yield return inst; - - // consider it always outside view (not contained in CurrentViewRect) - if (inst.operand == CellRectContains) - { - yield return new CodeInstruction(OpCodes.Ldc_I4_0); - yield return new CodeInstruction(OpCodes.And); - } - } + // primarily for `IsValidUnseenCell()` but works fine for `IsOutsideView()` as well (maybe others) + static IEnumerable Transpiler(IEnumerable insts, ILGenerator gen) + { + var cm = new CodeMatcher(insts, gen); + + cm.MatchStartForward(Code.Call[AccessTools.DeclaredPropertyGetter(typeof(Find), nameof(Find.CurrentMap))]); + cm.SearchForward(inst => inst.Branches(out _)); + // consider it always on current map, so we can proceed (with finding a nice walkable cell etc.) + // keeping `Beq` and `Bne` avoids needing `Code.Pop, Code.Pop` + if (cm.Opcode == OpCodes.Beq_S) + cm.Advance(1).Insert(Code.Br_S[cm.InstructionAt(-1).operand]); // force jump as if equal + else if (cm.Opcode == OpCodes.Bne_Un_S) + cm.CreateLabelWithOffsets(1, out var label).Operand = label; // not-equal jump goes nowhere + else + cm.ThrowIfFalse("Couldn't find equality branch opcode following `Find.CurrentMap`", _ => false); + + cm.MatchStartForward(Code.Call[AccessTools.DeclaredMethod(typeof(CellRect), nameof(CellRect.Contains))]); + // consider it always outside view (not contained in `CurrentViewRect`) so we can proceed + cm.Advance(1).Insert(Code.Ldc_I4_0, Code.And); + + return cm.Instructions(); } }