From 7514be6ba5cf50f178316055fad97ec3e4cf5fe9 Mon Sep 17 00:00:00 2001 From: SokyranTheDragon Date: Mon, 29 Apr 2024 19:38:37 +0200 Subject: [PATCH] Fix GameConditionManager.MapBrightnessTracker (Unnatural Darkness) desyncs GameConditionManager.MapBrightnessTracker:Tick uses Time.deltaTime, the value of which will be different between the players. With similar FPS they'll be very close to one another, but if there's a big change between FPS values (for example, 60 and 144) the issue will be much bigger. The issue with MapBrightnessTracker is the map will get darker at a different rate for each player - in one of my tests, the client finished the transition 10 ticks faster than the host. The fix here is rather simple - replace `deltaTime` with a constant value of `1 / 60` or `0.166666...` to ensure each 60 ticks in-game will be treated as a second, no matter the game speed. --- Source/Client/Patches/Determinism.cs | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/Source/Client/Patches/Determinism.cs b/Source/Client/Patches/Determinism.cs index 849171dd..f514c0cc 100644 --- a/Source/Client/Patches/Determinism.cs +++ b/Source/Client/Patches/Determinism.cs @@ -491,4 +491,37 @@ private static int NewCacheStatus(int gameTick) } } + [HarmonyPatch(typeof(GameConditionManager.MapBrightnessTracker), nameof(GameConditionManager.MapBrightnessTracker.Tick))] + static class MapBrightnessLerpPatch + { + static IEnumerable Transpiler(IEnumerable instr) + { + var patchCount = 0; + + // The method is using delta time for darkness changes, + // which is not good for MP since it's tied to the FPS. + var target = AccessTools.DeclaredPropertyGetter(typeof(Time), nameof(Time.deltaTime)); + + foreach (var ci in instr) + { + if (ci.Calls(target)) + { + // Replace deltaTime with a constant value. + // We use 1/60 since 1 second at speed 1 the deltaTime + // should (in perfect situation) be 60 ticks. + ci.opcode = OpCodes.Ldc_R4; + ci.operand = 1f / 60f; + + patchCount++; + } + + yield return ci; + } + + const int expectedPatches = 1; + if (patchCount != expectedPatches) + Log.Error($"Replaced an incorrect amount of Time.deltaTime calls for GameConditionManager.MapBrightnessTracker:Tick (expected: {expectedPatches}, patched: {patchCount}). Was the original method changed?"); + } + } + }