From bca105a0cad9d79e7ddb3ee7a4cc887936b18937 Mon Sep 17 00:00:00 2001 From: Sakura-TA Date: Mon, 20 Apr 2026 15:34:19 +0800 Subject: [PATCH] fix(Determinism): force single-batch FastTileFinder.Query in MP to prevent quest site tile divergence --- Source/Client/Patches/Determinism.cs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Source/Client/Patches/Determinism.cs b/Source/Client/Patches/Determinism.cs index a56bf353b..9bdf674e2 100644 --- a/Source/Client/Patches/Determinism.cs +++ b/Source/Client/Patches/Determinism.cs @@ -725,4 +725,30 @@ static IEnumerable Transpiler(IEnumerable inst } } + // FastTileFinder.ComputeQueryJob uses Interlocked.Increment to race-fill a 50-slot result array + // across parallel Unity Job batches. Thread scheduling differs between machines, so clients get + // different candidate tile sets. Force single-batch execution in MP so tiles are processed in + // tileId order, making the first 50 valid tiles consistent across all clients. + [HarmonyPatch(typeof(FastTileFinder), nameof(FastTileFinder.Query))] + static class FastTileFinderQueryDeterminismPatch + { + static IEnumerable Transpiler(IEnumerable instructions) + { + var getIdealBatchCount = AccessTools.Method(typeof(UnityData), nameof(UnityData.GetIdealBatchCount)); + var getBatchCount = AccessTools.Method(typeof(FastTileFinderQueryDeterminismPatch), nameof(GetBatchCount)); + + foreach (var instr in instructions) + { + if (instr.Calls(getIdealBatchCount)) + yield return new CodeInstruction(OpCodes.Call, getBatchCount); + else + yield return instr; + } + } + + static int GetBatchCount(int length) => + Multiplayer.Client != null ? length : UnityData.GetIdealBatchCount(length); + } + + }