From b4a2c1b2661cd25ffa08950409042fd9f0e8a492 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Mon, 6 Apr 2020 15:10:32 +0200 Subject: [PATCH] Fix race condition between inbound and injected packets (fixes #118) In the case of #118, this was resulting in the EntityTrackerUpdate packet (which contains info on which skin layers should be visible) sometimes ending up before the SpawnPlayer packet, hence the players outer skin layers being invisible at the start of the recording. --- src/main/java/com/replaymod/core/versions/MCVer.java | 8 ++++++++ .../recording/mixin/MixinNetHandlerPlayClient.java | 1 + .../com/replaymod/recording/packet/PacketListener.java | 8 ++++++++ 3 files changed, 17 insertions(+) diff --git a/src/main/java/com/replaymod/core/versions/MCVer.java b/src/main/java/com/replaymod/core/versions/MCVer.java index 80c165f5..d62db95d 100644 --- a/src/main/java/com/replaymod/core/versions/MCVer.java +++ b/src/main/java/com/replaymod/core/versions/MCVer.java @@ -394,6 +394,14 @@ public class MCVer { //#endif } + public static void scheduleOnMainThread(Runnable runnable) { + //#if MC>=11400 + getMinecraft().send(runnable); + //#else + //$$ getMinecraft().addScheduledTask(runnable); + //#endif + } + //#if MC>=11400 public static Window getWindow(MinecraftClient mc) { //#if MC>=11500 diff --git a/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerPlayClient.java b/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerPlayClient.java index 997bdb11..497a18ec 100644 --- a/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerPlayClient.java +++ b/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerPlayClient.java @@ -57,6 +57,7 @@ public abstract class MixinNetHandlerPlayClient { //$$ @Inject(method = "handlePlayerListItem", at=@At("HEAD")) //#endif public void recordOwnJoin(PlayerListS2CPacket packet, CallbackInfo ci) { + if (!MCVer.isOnMainThread()) return; if (mcStatic.player == null) return; RecordingEventHandler handler = getRecordingEventHandler(); diff --git a/src/main/java/com/replaymod/recording/packet/PacketListener.java b/src/main/java/com/replaymod/recording/packet/PacketListener.java index 2fb03ed8..9bcd7d17 100644 --- a/src/main/java/com/replaymod/recording/packet/PacketListener.java +++ b/src/main/java/com/replaymod/recording/packet/PacketListener.java @@ -149,6 +149,14 @@ public class PacketListener extends ChannelInboundHandlerAdapter { } public void save(Packet packet) { + // If we're not on the main thread (i.e. we're on the netty thread), then we need to schedule the saving + // to happen on the main thread so we can guarantee correct ordering of inbound and inject packets. + // Otherwise, injected packets may end up further down the packet stream than they were supposed to and other + // inbound packets which may rely on the injected packet would behave incorrectly when played back. + if (!MCVer.isOnMainThread()) { + MCVer.scheduleOnMainThread(() -> save(packet)); + return; + } try { if(packet instanceof PlayerSpawnS2CPacket) { //#if MC>=10800