Prevent pausing in the middle of a bundle packet

Because certain actions (e.g. switching to Quick Mode) will fail in this
state.
This commit is contained in:
Jonas Herzig
2024-06-18 14:52:34 +02:00
parent 5218feb6b6
commit 76a68b7867

View File

@@ -11,6 +11,7 @@ import com.replaymod.core.utils.Restrictions;
import com.replaymod.replay.camera.CameraEntity; import com.replaymod.replay.camera.CameraEntity;
import com.replaymod.replaystudio.io.ReplayInputStream; import com.replaymod.replaystudio.io.ReplayInputStream;
import com.replaymod.replaystudio.lib.viaversion.api.protocol.packet.State; import com.replaymod.replaystudio.lib.viaversion.api.protocol.packet.State;
import com.replaymod.replaystudio.protocol.PacketType;
import com.replaymod.replaystudio.protocol.PacketTypeRegistry; import com.replaymod.replaystudio.protocol.PacketTypeRegistry;
import com.replaymod.replaystudio.replay.ReplayFile; import com.replaymod.replaystudio.replay.ReplayFile;
import de.johni0702.minecraft.gui.utils.EventRegistrations; import de.johni0702.minecraft.gui.utils.EventRegistrations;
@@ -267,6 +268,11 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re
*/ */
protected boolean hasWorldLoaded; protected boolean hasWorldLoaded;
/**
* Whether we are currently in the middle of a bundle packet.
*/
protected boolean inBundle;
/** /**
* The minecraft instance. * The minecraft instance.
*/ */
@@ -1025,7 +1031,7 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re
while (true) { while (true) {
try { try {
// When playback is paused and the world has loaded (we don't want any dirt-screens) we sleep // When playback is paused and the world has loaded (we don't want any dirt-screens) we sleep
while (paused() && hasWorldLoaded) { while (paused() && hasWorldLoaded && !inBundle) {
// Unless we are going to terminate, restart or jump // Unless we are going to terminate, restart or jump
if (terminate || startFromBeginning || desiredTimeStamp != -1) { if (terminate || startFromBeginning || desiredTimeStamp != -1) {
break; break;
@@ -1033,7 +1039,7 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re
Thread.sleep(10); Thread.sleep(10);
} }
if (terminate) { if (terminate && !inBundle) {
break REPLAY_LOOP; break REPLAY_LOOP;
} }
@@ -1053,7 +1059,7 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re
// If we aren't jumping and the world has already been loaded (no dirt-screens) then wait // If we aren't jumping and the world has already been loaded (no dirt-screens) then wait
// the required amount to get proper packet timing // the required amount to get proper packet timing
if (!isHurrying() && hasWorldLoaded) { if (!isHurrying() && hasWorldLoaded && !inBundle) {
// Timestamp of when the next packet should be sent // Timestamp of when the next packet should be sent
long expectedTime = realTimeStart + (long) (nextTimeStamp / replaySpeed); long expectedTime = realTimeStart + (long) (nextTimeStamp / replaySpeed);
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
@@ -1064,6 +1070,7 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re
} }
// Process packet // Process packet
if (nextPacket.type == PacketType.Bundle) inBundle = !inBundle;
channel.pipeline().fireChannelRead(Unpooled.wrappedBuffer(nextPacket.bytes)); channel.pipeline().fireChannelRead(Unpooled.wrappedBuffer(nextPacket.bytes));
nextPacket = null; nextPacket = null;
@@ -1111,6 +1118,7 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re
// Restart the replay. // Restart the replay.
hasWorldLoaded = false; hasWorldLoaded = false;
inBundle = false;
lastTimeStamp = 0; lastTimeStamp = 0;
registry = getPacketTypeRegistry(State.LOGIN); registry = getPacketTypeRegistry(State.LOGIN);
startFromBeginning = false; startFromBeginning = false;
@@ -1243,6 +1251,7 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re
} }
if (timestamp < lastTimeStamp) { // Restart the replay if we need to go backwards in time if (timestamp < lastTimeStamp) { // Restart the replay if we need to go backwards in time
hasWorldLoaded = false; hasWorldLoaded = false;
inBundle = false;
lastTimeStamp = 0; lastTimeStamp = 0;
if (replayIn != null) { if (replayIn != null) {
replayIn.close(); replayIn.close();
@@ -1271,13 +1280,14 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re
} }
int nextTimeStamp = pd.timestamp; int nextTimeStamp = pd.timestamp;
if (nextTimeStamp > timestamp) { if (nextTimeStamp > timestamp && !inBundle) {
// We are done sending all packets // We are done sending all packets
nextPacket = pd; nextPacket = pd;
break; break;
} }
// Process packet // Process packet
if (pd.type == PacketType.Bundle) inBundle = !inBundle;
channel.pipeline().fireChannelRead(Unpooled.wrappedBuffer(pd.bytes)); channel.pipeline().fireChannelRead(Unpooled.wrappedBuffer(pd.bytes));
// MC as of 1.20.2 relies on autoRead, so it can update the connection state on the main // MC as of 1.20.2 relies on autoRead, so it can update the connection state on the main
@@ -1497,6 +1507,7 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re
private final int timestamp; private final int timestamp;
private final byte[] bytes; private final byte[] bytes;
private final PacketType type;
PacketData(ReplayInputStream in) throws IOException { PacketData(ReplayInputStream in) throws IOException {
if (ReplayMod.isMinimalMode()) { if (ReplayMod.isMinimalMode()) {
@@ -1508,6 +1519,7 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re
} }
bytes = new byte[length]; bytes = new byte[length];
IOUtils.readFully(in, bytes); IOUtils.readFully(in, bytes);
type = PacketType.UnknownLogin;
} else { } else {
com.replaymod.replaystudio.PacketData data = in.readPacket(); com.replaymod.replaystudio.PacketData data = in.readPacket();
if (data == null) { if (data == null) {
@@ -1515,6 +1527,7 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re
} }
timestamp = (int) data.getTime(); timestamp = (int) data.getTime();
com.replaymod.replaystudio.protocol.Packet packet = data.getPacket(); com.replaymod.replaystudio.protocol.Packet packet = data.getPacket();
type = packet.getType();
// We need to re-encode ReplayStudio packets, so we can later decode them as NMS packets // We need to re-encode ReplayStudio packets, so we can later decode them as NMS packets
// The main reason we aren't reading them as NMS packets is that we want ReplayStudio to be able // The main reason we aren't reading them as NMS packets is that we want ReplayStudio to be able
// to apply ViaVersion (and potentially other magic) to it. // to apply ViaVersion (and potentially other magic) to it.