Skip to content

Commit

Permalink
Fix desyncs related to pawn mood thoughts
Browse files Browse the repository at this point in the history
Fix the wildlife tab desyncing in the mod Numbers
  • Loading branch information
Zetrith committed Nov 20, 2023
1 parent 3ec9c4c commit 3cf6b22
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 7 deletions.
5 changes: 5 additions & 0 deletions Source/Client/Desyncs/ClientSyncOpinion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ public class ClientSyncOpinion
public List<uint> worldRandomStates = new();
public List<MapRandomStateData> mapStates = new();

// todo Unused for now
public List<int> pawnCapacityHashes = new();
public List<int> pawnStatHashes = new();
public List<int> pawnNeedHashes = new();

public List<StackTraceLogItem> desyncStackTraces = new();
public List<int> desyncStackTraceHashes = new();
public bool simulating;
Expand Down
59 changes: 56 additions & 3 deletions Source/Client/Patches/Determinism.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> 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<Thought_Situational>), nameof(List<Thought_Situational>.Clear));

static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> insts)
{
return !Multiplayer.InInterface;
foreach (var inst in insts)
{
if (inst.operand == clearMethod)
yield return new CodeInstruction(OpCodes.Pop);
else
yield return inst;
}
}
}

Expand Down
12 changes: 10 additions & 2 deletions Source/Client/Syncing/Dict/SyncDictRimWorld.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,16 @@ public static class SyncDictRimWorld
(ByteWriter data, PawnTable table) => WriteSync(data, Find.MainTabsRoot.OpenTab),
(ByteReader data) =>
{
var tab = (MainTabWindow_PawnTable)ReadSync<MainButtonDef>(data).TabWindow;
return tab.CreateTable();
Rand.PushState();
try
{
var tab = (MainTabWindow_PawnTable)ReadSync<MainButtonDef>(data).TabWindow;
return tab.CreateTable();
}
finally
{
Rand.PopState();
}
}, true
},
{
Expand Down
4 changes: 2 additions & 2 deletions Source/Common/Version.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down

0 comments on commit 3cf6b22

Please sign in to comment.