diff --git a/Source/Client/Desyncs/ClientSyncOpinion.cs b/Source/Client/Desyncs/ClientSyncOpinion.cs index 8338d671..f7414c04 100644 --- a/Source/Client/Desyncs/ClientSyncOpinion.cs +++ b/Source/Client/Desyncs/ClientSyncOpinion.cs @@ -17,6 +17,11 @@ public class ClientSyncOpinion public List worldRandomStates = new(); public List mapStates = new(); + // todo Unused for now + public List pawnCapacityHashes = new(); + public List pawnStatHashes = new(); + public List pawnNeedHashes = new(); + public List desyncStackTraces = new(); public List desyncStackTraceHashes = new(); public bool simulating; diff --git a/Source/Client/Patches/Determinism.cs b/Source/Client/Patches/Determinism.cs index 6e728494..072b611a 100644 --- a/Source/Client/Patches/Determinism.cs +++ b/Source/Client/Patches/Determinism.cs @@ -346,7 +346,8 @@ static class DontRecalculateSocialThoughtsInInterface { static bool Prefix(SituationalThoughtHandler __instance, Pawn otherPawn) { - if (!Multiplayer.InInterface) return true; + if (Multiplayer.Client == null) return true; + if (Multiplayer.Ticking || Multiplayer.ExecutingCmds) return true; // This initializer needs to always run (the method itself begins with it) if (!__instance.cachedSocialThoughts.TryGetValue(otherPawn, out var value)) @@ -359,12 +360,64 @@ static bool Prefix(SituationalThoughtHandler __instance, Pawn otherPawn) } } + [HarmonyPatch(typeof(SituationalThoughtHandler), nameof(SituationalThoughtHandler.AppendSocialThoughts))] + static class DontUpdateThoughQueryTickInInterface + { + private static FieldInfo queryTickField = AccessTools.Field(typeof(SituationalThoughtHandler.CachedSocialThoughts), nameof(SituationalThoughtHandler.CachedSocialThoughts.lastQueryTick)); + + static IEnumerable Transpiler(IEnumerable insts) + { + foreach (var inst in insts) + { + if (inst.opcode == OpCodes.Stfld && inst.operand == queryTickField) + { + yield return new CodeInstruction(OpCodes.Ldarg_0); + yield return new CodeInstruction(OpCodes.Ldarg_1); + yield return new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(DontUpdateThoughQueryTickInInterface), nameof(NewQueryTick))); + } + + yield return inst; + } + } + + private static int NewQueryTick(int ticks, SituationalThoughtHandler thoughtHandler, Pawn otherPawn) + { + return Multiplayer.Client == null || Multiplayer.Ticking || Multiplayer.ExecutingCmds ? + ticks : + thoughtHandler.cachedSocialThoughts[otherPawn].lastQueryTick; + } + } + [HarmonyPatch(typeof(SituationalThoughtHandler), nameof(SituationalThoughtHandler.CheckRecalculateMoodThoughts))] static class DontRecalculateMoodThoughtsInInterface { - static bool Prefix() + static bool Prefix(SituationalThoughtHandler __instance) + { + if (Multiplayer.Client != null && !Multiplayer.Ticking && !Multiplayer.ExecutingCmds) return false; + + // Notify_SituationalThoughtsDirty was called + if (__instance.lastMoodThoughtsRecalculationTick == -99999) + __instance.cachedThoughts.Clear(); + + return true; + } + } + + [HarmonyPatch(typeof(SituationalThoughtHandler), nameof(SituationalThoughtHandler.Notify_SituationalThoughtsDirty))] + static class NotifyThoughtsDirtyPatch + { + private static MethodInfo clearMethod = + AccessTools.Method(typeof(List), nameof(List.Clear)); + + static IEnumerable Transpiler(IEnumerable insts) { - return !Multiplayer.InInterface; + foreach (var inst in insts) + { + if (inst.operand == clearMethod) + yield return new CodeInstruction(OpCodes.Pop); + else + yield return inst; + } } } diff --git a/Source/Client/Syncing/Dict/SyncDictRimWorld.cs b/Source/Client/Syncing/Dict/SyncDictRimWorld.cs index 172990fc..75c234b7 100644 --- a/Source/Client/Syncing/Dict/SyncDictRimWorld.cs +++ b/Source/Client/Syncing/Dict/SyncDictRimWorld.cs @@ -73,8 +73,16 @@ public static class SyncDictRimWorld (ByteWriter data, PawnTable table) => WriteSync(data, Find.MainTabsRoot.OpenTab), (ByteReader data) => { - var tab = (MainTabWindow_PawnTable)ReadSync(data).TabWindow; - return tab.CreateTable(); + Rand.PushState(); + try + { + var tab = (MainTabWindow_PawnTable)ReadSync(data).TabWindow; + return tab.CreateTable(); + } + finally + { + Rand.PopState(); + } }, true }, { diff --git a/Source/Common/Version.cs b/Source/Common/Version.cs index d2bf5f8f..9997dd7f 100644 --- a/Source/Common/Version.cs +++ b/Source/Common/Version.cs @@ -2,8 +2,8 @@ namespace Multiplayer.Common { public static class MpVersion { - public const string Version = "0.9.3"; - public const int Protocol = 36; + public const string Version = "0.9.4"; + public const int Protocol = 37; public const string ApiAssemblyName = "0MultiplayerAPI";