From 8704fb4c61974d0a1cfc611868f0d216428edff8 Mon Sep 17 00:00:00 2001 From: Yuji Ueki Date: Mon, 28 Jun 2021 20:34:02 +0900 Subject: [PATCH 1/2] :recycle: Refactor PacketListener --- .../recording/packet/PacketListener.java | 297 ++++++------------ .../recording/packet/PacketRecorder.java | 130 ++++++++ 2 files changed, 225 insertions(+), 202 deletions(-) create mode 100644 src/main/java/com/replaymod/recording/packet/PacketRecorder.java diff --git a/src/main/java/com/replaymod/recording/packet/PacketListener.java b/src/main/java/com/replaymod/recording/packet/PacketListener.java index c7524bbe..9913842f 100644 --- a/src/main/java/com/replaymod/recording/packet/PacketListener.java +++ b/src/main/java/com/replaymod/recording/packet/PacketListener.java @@ -1,7 +1,5 @@ package com.replaymod.recording.packet; -import com.github.steveice10.netty.buffer.PooledByteBufAllocator; -import com.github.steveice10.packetlib.tcp.io.ByteBufNetOutput; import com.google.gson.Gson; import com.replaymod.core.ReplayMod; import com.replaymod.core.utils.Restrictions; @@ -13,13 +11,10 @@ import com.replaymod.recording.Setting; import com.replaymod.recording.gui.GuiSavingReplay; import com.replaymod.recording.handler.ConnectionEventHandler; -import com.replaymod.replaystudio.PacketData; import com.replaymod.replaystudio.data.Marker; -import com.replaymod.replaystudio.io.ReplayOutputStream; import com.replaymod.replaystudio.replay.ReplayFile; import com.replaymod.replaystudio.replay.ReplayMetaData; import com.replaymod.replaystudio.us.myles.ViaVersion.api.Pair; -import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; @@ -28,12 +23,8 @@ import net.minecraft.entity.Entity; import net.minecraft.network.IPacket; import net.minecraft.network.PacketBuffer; -import net.minecraft.network.PacketDirection; -import net.minecraft.network.ProtocolType; -import net.minecraft.network.datasync.EntityDataManager; import net.minecraft.network.login.server.SCustomPayloadLoginPacket; import net.minecraft.network.login.server.SEnableCompressionPacket; -import net.minecraft.network.login.server.SLoginSuccessPacket; import net.minecraft.network.play.server.*; import net.minecraft.util.text.StringTextComponent; import org.apache.commons.io.FilenameUtils; @@ -51,7 +42,6 @@ import java.util.concurrent.atomic.AtomicInteger; import static com.replaymod.core.versions.MCVer.getMinecraft; -import static com.replaymod.replaystudio.util.Utils.writeInt; public class PacketListener extends ChannelInboundHandlerAdapter { @@ -61,23 +51,15 @@ public class PacketListener extends ChannelInboundHandlerAdapter { private final ReplayMod core; private final Path outputPath; private final ReplayFile replayFile; + private final ReplayMetaData metaData; + private final PacketRecorder packetRecorder; private final ResourcePackRecorder resourcePackRecorder; private final ExecutorService saveService = Executors.newSingleThreadExecutor(); - private final ReplayOutputStream packetOutputStream; - - private ReplayMetaData metaData; private ChannelHandlerContext context = null; - private final long startTime; - private long lastSentPacket; - private long timePassedWhilePaused; - private volatile boolean serverWasPaused; - private ProtocolType connectionState = ProtocolType.LOGIN; - private boolean loginPhase = true; - /** * Used to keep track of the last metadata save job submitted to the save service and * as such prevents unnecessary writes. @@ -90,108 +72,14 @@ public PacketListener(ReplayMod core, Path outputPath, ReplayFile replayFile, Re this.replayFile = replayFile; this.metaData = metaData; this.resourcePackRecorder = new ResourcePackRecorder(replayFile); - this.packetOutputStream = replayFile.writePacketData(); - this.startTime = metaData.getDate(); + this.packetRecorder = new PacketRecorder(replayFile, metaData); saveMetaData(); } - private void saveMetaData() { - int id = lastSaveMetaDataId.incrementAndGet(); - saveService.submit(() -> { - if (lastSaveMetaDataId.get() != id) { - return; // Another job has been scheduled, it will do the hard work. - } - try { - synchronized (replayFile) { - if (ReplayMod.isMinimalMode()) { - metaData.setFileFormat("MCPR"); - metaData.setFileFormatVersion(ReplayMetaData.CURRENT_FILE_FORMAT_VERSION); - metaData.setProtocolVersion(MCVer.getProtocolVersion()); - metaData.setGenerator("ReplayMod in Minimal Mode"); - - try (OutputStream out = replayFile.write("metaData.json")) { - String json = (new Gson()).toJson(metaData); - out.write(json.getBytes()); - } - } else { - replayFile.writeMetaData(MCVer.getPacketTypeRegistry(true), metaData); - } - } - } catch (IOException e) { - logger.error("Writing metadata:", e); - } - }); - } - - public void save(IPacket 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 (!mc.isOnExecutionThread()) { - mc.enqueue(() -> save(packet)); - return; - } - try { - if (packet instanceof SSpawnPlayerPacket) { - UUID uuid = ((SSpawnPlayerPacket) packet).getUniqueId(); - Set uuids = new HashSet<>(Arrays.asList(metaData.getPlayers())); - uuids.add(uuid.toString()); - metaData.setPlayers(uuids.toArray(new String[uuids.size()])); - saveMetaData(); - } - - if (packet instanceof SEnableCompressionPacket) { - return; // Replay data is never compressed on the packet level - } - - long now = System.currentTimeMillis(); - if (serverWasPaused) { - timePassedWhilePaused = now - startTime - lastSentPacket; - serverWasPaused = false; - } - int timestamp = (int) (now - startTime - timePassedWhilePaused); - lastSentPacket = timestamp; - PacketData packetData = getPacketData(timestamp, packet); - saveService.submit(() -> { - try { - if (ReplayMod.isMinimalMode()) { - // Minimal mode, ReplayStudio might not know our packet ids, so we cannot use it - com.github.steveice10.netty.buffer.ByteBuf packetIdBuf = PooledByteBufAllocator.DEFAULT.buffer(); - com.github.steveice10.netty.buffer.ByteBuf packetBuf = packetData.getPacket().getBuf(); - try { - new ByteBufNetOutput(packetIdBuf).writeVarInt(packetData.getPacket().getId()); - - int packetIdLen = packetIdBuf.readableBytes(); - int packetBufLen = packetBuf.readableBytes(); - writeInt(packetOutputStream, (int) packetData.getTime()); - writeInt(packetOutputStream, packetIdLen + packetBufLen); - packetIdBuf.readBytes(packetOutputStream, packetIdLen); - packetBuf.getBytes(packetBuf.readerIndex(), packetOutputStream, packetBufLen); - } finally { - packetIdBuf.release(); - packetBuf.release(); - } - } else { - packetOutputStream.write(packetData); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - }); - - if (packet instanceof SLoginSuccessPacket) { - moveToPlayState(); - } - } catch (Exception e) { - logger.error("Writing packet:", e); - } - } - @Override public void channelInactive(ChannelHandlerContext ctx) { - metaData.setDuration((int) lastSentPacket); + metaData.setDuration((int) packetRecorder.getLastSentPacket()); saveMetaData(); core.runLater(() -> { @@ -212,52 +100,15 @@ public void channelInactive(ChannelHandlerContext ctx) { logger.error("Waiting for save service termination:", e); } try { - packetOutputStream.close(); + packetRecorder.close(); } catch (IOException e) { logger.error("Failed to close packet output stream:", e); } - List> outputPaths; - synchronized (replayFile) { - try { - if (!MarkerProcessor.producesAnyOutput(replayFile)) { - // Immediately close the saving popup, the user doesn't care about it - core.runLater(guiSavingReplay::close); - - // If we crash right here, on the next start we'll prompt the user for recovery - // but we don't really want that, so drop a marker file to skip recovery for this replay. - Files.createFile(outputPath.resolveSibling(outputPath.getFileName() + ".no_recover")); - - // We still have the replay, so we just save it (at least for a few weeks) in case they change their mind - String replayName = FilenameUtils.getBaseName(outputPath.getFileName().toString()); - Path rawFolder = ReplayMod.instance.getRawReplayFolder(); - Path rawPath = rawFolder.resolve(outputPath.getFileName()); - for (int i = 1; Files.exists(rawPath); i++) { - rawPath = rawPath.resolveSibling(replayName + "." + i + ".mcpr"); - } - Files.createDirectories(rawPath.getParent()); - replayFile.saveTo(rawPath.toFile()); - replayFile.close(); - return; - } - - replayFile.save(); - replayFile.close(); - - if (core.getSettingsRegistry().get(Setting.AUTO_POST_PROCESS) && !ReplayMod.isMinimalMode()) { - outputPaths = MarkerProcessor.apply(outputPath, guiSavingReplay.getProgressBar()::setProgress); - } else { - outputPaths = Collections.singletonList(new Pair<>(outputPath, metaData)); - } - } catch (Exception e) { - logger.error("Saving replay file:", e); - CrashReport crashReport = CrashReport.makeCrashReport(e, "Saving replay file"); - core.runLater(() -> Utils.error(logger, VanillaGuiScreen.wrap(mc.currentScreen), crashReport, guiSavingReplay::close)); - return; - } + List> outputPaths = saveReplayFile(guiSavingReplay); + if (outputPaths != null) { + core.runLater(() -> guiSavingReplay.presentRenameDialog(outputPaths)); } - - core.runLater(() -> guiSavingReplay.presentRenameDialog(outputPaths)); }).start(); } @@ -289,7 +140,6 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception return; } - if (packet instanceof SCustomPayloadLoginPacket) { PacketBuffer buffer = new PacketBuffer(Unpooled.buffer()); packet.writePacketData(buffer); @@ -322,38 +172,37 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception } catch (Exception e) { logger.error("Handling packet for recording:", e); } - } super.channelRead(ctx, msg); } - private void DataManager_set(EntityDataManager dataManager, EntityDataManager.DataEntry entry) { - dataManager.register(entry.getKey(), entry.getValue()); - } - - @SuppressWarnings("unchecked") - private PacketData getPacketData(int timestamp, IPacket packet) throws Exception { + public void save(IPacket 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 (!mc.isOnExecutionThread()) { + mc.enqueue(() -> save(packet)); + return; + } - Integer packetId = getPacketId(packet); - ByteBuf byteBuf = Unpooled.buffer(); try { - packet.writePacketData(new PacketBuffer(byteBuf)); - return new PacketData(timestamp, new com.replaymod.replaystudio.protocol.Packet( - MCVer.getPacketTypeRegistry(loginPhase), - packetId, - com.github.steveice10.netty.buffer.Unpooled.wrappedBuffer( - byteBuf.array(), - byteBuf.arrayOffset(), - byteBuf.readableBytes() - ) - )); - } finally { - byteBuf.release(); - - if (packet instanceof SCustomPayloadPlayPacket) { - ((SCustomPayloadPlayPacket) packet).getBufferData().release(); + if (packet instanceof SSpawnPlayerPacket) { + UUID uuid = ((SSpawnPlayerPacket) packet).getUniqueId(); + Set uuids = new HashSet<>(Arrays.asList(metaData.getPlayers())); + uuids.add(uuid.toString()); + metaData.setPlayers(uuids.toArray(new String[uuids.size()])); + saveMetaData(); + } + + if (packet instanceof SEnableCompressionPacket) { + return; // Replay data is never compressed on the packet level } + + packetRecorder.saveIntoReplayFile(packet); + } catch (Exception e) { + logger.error("Writing packet:", e); } } @@ -389,35 +238,79 @@ public void addMarker(String name, int timestamp) { } public long getCurrentDuration() { - return lastSentPacket; + return packetRecorder.getLastSentPacket(); } public void setServerWasPaused() { - this.serverWasPaused = true; + packetRecorder.setServerWasPaused(true); } - private Integer getPacketId(IPacket packet) throws IOException { - Integer packetId = connectionState.getPacketId(PacketDirection.CLIENTBOUND, packet); - - if (packetId == null) { - /* - Retrying as the state is PLAY - TODO: Investigate packet order and refactor to be more consistent - */ - packetId = ProtocolType.PLAY.getPacketId(PacketDirection.CLIENTBOUND, packet); + private void saveMetaData() { + int id = lastSaveMetaDataId.incrementAndGet(); + saveService.submit(() -> { + if (lastSaveMetaDataId.get() != id) { + return; // Another job has been scheduled, it will do the hard work. + } + try { + synchronized (replayFile) { + if (ReplayMod.isMinimalMode()) { + metaData.setFileFormat("MCPR"); + metaData.setFileFormatVersion(ReplayMetaData.CURRENT_FILE_FORMAT_VERSION); + metaData.setProtocolVersion(MCVer.getProtocolVersion()); + metaData.setGenerator("ReplayMod in Minimal Mode"); - if (packetId == null) { - throw new IOException("Unknown packet type:" + packet.getClass()); + try (OutputStream out = replayFile.write("metaData.json")) { + String json = (new Gson()).toJson(metaData); + out.write(json.getBytes()); + } + } else { + replayFile.writeMetaData(MCVer.getPacketTypeRegistry(true), metaData); + } + } + } catch (IOException e) { + logger.error("Writing metadata:", e); } + }); + } - moveToPlayState(); - } + private List> saveReplayFile(GuiSavingReplay guiSavingReplay) { + synchronized (replayFile) { + try { + if (!MarkerProcessor.producesAnyOutput(replayFile)) { + // Immediately close the saving popup, the user doesn't care about it + core.runLater(guiSavingReplay::close); + + // If we crash right here, on the next start we'll prompt the user for recovery + // but we don't really want that, so drop a marker file to skip recovery for this replay. + Files.createFile(outputPath.resolveSibling(outputPath.getFileName() + ".no_recover")); + + // We still have the replay, so we just save it (at least for a few weeks) in case they change their mind + String replayName = FilenameUtils.getBaseName(outputPath.getFileName().toString()); + Path rawFolder = ReplayMod.instance.getRawReplayFolder(); + Path rawPath = rawFolder.resolve(outputPath.getFileName()); + for (int i = 1; Files.exists(rawPath); i++) { + rawPath = rawPath.resolveSibling(replayName + "." + i + ".mcpr"); + } + Files.createDirectories(rawPath.getParent()); + replayFile.saveTo(rawPath.toFile()); + replayFile.close(); + return null; + } - return packetId; - } + replayFile.save(); + replayFile.close(); - private void moveToPlayState() { - connectionState = ProtocolType.PLAY; - loginPhase = false; + if (core.getSettingsRegistry().get(Setting.AUTO_POST_PROCESS) && !ReplayMod.isMinimalMode()) { + return MarkerProcessor.apply(outputPath, guiSavingReplay.getProgressBar()::setProgress); + } else { + return Collections.singletonList(new Pair<>(outputPath, metaData)); + } + } catch (Exception e) { + logger.error("Saving replay file:", e); + CrashReport crashReport = CrashReport.makeCrashReport(e, "Saving replay file"); + core.runLater(() -> Utils.error(logger, VanillaGuiScreen.wrap(mc.currentScreen), crashReport, guiSavingReplay::close)); + return null; + } + } } } diff --git a/src/main/java/com/replaymod/recording/packet/PacketRecorder.java b/src/main/java/com/replaymod/recording/packet/PacketRecorder.java new file mode 100644 index 00000000..f8abb92c --- /dev/null +++ b/src/main/java/com/replaymod/recording/packet/PacketRecorder.java @@ -0,0 +1,130 @@ +package com.replaymod.recording.packet; + +import com.github.steveice10.netty.buffer.PooledByteBufAllocator; +import com.github.steveice10.packetlib.tcp.io.ByteBufNetOutput; +import com.replaymod.core.ReplayMod; +import com.replaymod.core.versions.MCVer; +import com.replaymod.replaystudio.PacketData; +import com.replaymod.replaystudio.io.ReplayOutputStream; +import com.replaymod.replaystudio.replay.ReplayFile; +import com.replaymod.replaystudio.replay.ReplayMetaData; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import net.minecraft.network.IPacket; +import net.minecraft.network.PacketBuffer; +import net.minecraft.network.PacketDirection; +import net.minecraft.network.ProtocolType; +import net.minecraft.network.play.server.SCustomPayloadPlayPacket; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import static com.replaymod.replaystudio.util.Utils.writeInt; + +public class PacketRecorder { + private static final Logger logger = LogManager.getLogger(); + + private final ExecutorService saveService = Executors.newSingleThreadExecutor(); + private final ReplayOutputStream packetOutputStream; + + private final long startTime; + private long lastSentPacket; + private long timePassedWhilePaused; + private volatile boolean serverWasPaused; + + public PacketRecorder(ReplayFile replayFile, ReplayMetaData metaData) throws IOException { + this.packetOutputStream = replayFile.writePacketData(); + this.startTime = metaData.getDate(); + } + + public long getLastSentPacket() { + return lastSentPacket; + } + + public void setServerWasPaused(boolean serverWasPaused) { + this.serverWasPaused = serverWasPaused; + } + + public void close() throws IOException { + packetOutputStream.close(); + } + + public void saveIntoReplayFile(IPacket packet) { + try { + long now = System.currentTimeMillis(); + if (serverWasPaused) { + timePassedWhilePaused = now - startTime - lastSentPacket; + serverWasPaused = false; + } + int timestamp = (int) (now - startTime - timePassedWhilePaused); + lastSentPacket = timestamp; + PacketData packetData = getPacketData(timestamp, packet); + saveService.submit(() -> { + try { + if (ReplayMod.isMinimalMode()) { + // Minimal mode, ReplayStudio might not know our packet ids, so we cannot use it + com.github.steveice10.netty.buffer.ByteBuf packetIdBuf = PooledByteBufAllocator.DEFAULT.buffer(); + com.github.steveice10.netty.buffer.ByteBuf packetBuf = packetData.getPacket().getBuf(); + try { + new ByteBufNetOutput(packetIdBuf).writeVarInt(packetData.getPacket().getId()); + + int packetIdLen = packetIdBuf.readableBytes(); + int packetBufLen = packetBuf.readableBytes(); + writeInt(packetOutputStream, (int) packetData.getTime()); + writeInt(packetOutputStream, packetIdLen + packetBufLen); + packetIdBuf.readBytes(packetOutputStream, packetIdLen); + packetBuf.getBytes(packetBuf.readerIndex(), packetOutputStream, packetBufLen); + } finally { + packetIdBuf.release(); + packetBuf.release(); + } + } else { + packetOutputStream.write(packetData); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } catch (Exception e) { + logger.error("Writing packet:", e); + } + } + + private PacketData getPacketData(int timestamp, IPacket packet) throws Exception { + Integer packetId = ProtocolType.PLAY.getPacketId(PacketDirection.CLIENTBOUND, packet); + boolean loginPhase = false; + + if (packetId == null) { + packetId = ProtocolType.LOGIN.getPacketId(PacketDirection.CLIENTBOUND, packet); + loginPhase = true; + + if (packetId == null) { + throw new IOException("Unknown packet type:" + packet.getClass()); + } + } + + ByteBuf byteBuf = Unpooled.buffer(); + + try { + packet.writePacketData(new PacketBuffer(byteBuf)); + return new PacketData(timestamp, new com.replaymod.replaystudio.protocol.Packet( + MCVer.getPacketTypeRegistry(loginPhase), + packetId, + com.github.steveice10.netty.buffer.Unpooled.wrappedBuffer( + byteBuf.array(), + byteBuf.arrayOffset(), + byteBuf.readableBytes() + ) + )); + } finally { + byteBuf.release(); + + if (packet instanceof SCustomPayloadPlayPacket) { + ((SCustomPayloadPlayPacket) packet).getBufferData().release(); + } + } + } +} From eb3fe8ed23b1a1d9d3d8ac6d0d5cb2278fe6c263 Mon Sep 17 00:00:00 2001 From: Yuji Ueki Date: Tue, 29 Jun 2021 00:40:58 +0900 Subject: [PATCH 2/2] :bug: Fix incorrect block rendering --- .../recording/packet/PacketRecorder.java | 16 +++++++++++----- .../java/com/replaymod/replay/ReplayHandler.java | 5 +++-- .../replay/{ => sender}/FullReplaySender.java | 6 +++++- .../replay/{ => sender}/QuickReplaySender.java | 4 +++- 4 files changed, 22 insertions(+), 9 deletions(-) rename src/main/java/com/replaymod/replay/{ => sender}/FullReplaySender.java (99%) rename src/main/java/com/replaymod/replay/{ => sender}/QuickReplaySender.java (98%) diff --git a/src/main/java/com/replaymod/recording/packet/PacketRecorder.java b/src/main/java/com/replaymod/recording/packet/PacketRecorder.java index f8abb92c..d076d9fe 100644 --- a/src/main/java/com/replaymod/recording/packet/PacketRecorder.java +++ b/src/main/java/com/replaymod/recording/packet/PacketRecorder.java @@ -14,6 +14,7 @@ import net.minecraft.network.PacketBuffer; import net.minecraft.network.PacketDirection; import net.minecraft.network.ProtocolType; +import net.minecraft.network.login.server.SCustomPayloadLoginPacket; import net.minecraft.network.play.server.SCustomPayloadPlayPacket; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -106,17 +107,22 @@ private PacketData getPacketData(int timestamp, IPacket packet) throws Exception } } - ByteBuf byteBuf = Unpooled.buffer(); + ByteBuf byteBuf = Unpooled.buffer(256, 1048576); + PacketBuffer buf = new PacketBuffer(byteBuf); try { - packet.writePacketData(new PacketBuffer(byteBuf)); + if (packet instanceof SCustomPayloadLoginPacket) { + ((SCustomPayloadLoginPacket) packet).getInternalData().resetReaderIndex(); + } + + packet.writePacketData(buf); return new PacketData(timestamp, new com.replaymod.replaystudio.protocol.Packet( MCVer.getPacketTypeRegistry(loginPhase), packetId, com.github.steveice10.netty.buffer.Unpooled.wrappedBuffer( - byteBuf.array(), - byteBuf.arrayOffset(), - byteBuf.readableBytes() + buf.array(), + buf.arrayOffset(), + buf.readableBytes() ) )); } finally { diff --git a/src/main/java/com/replaymod/replay/ReplayHandler.java b/src/main/java/com/replaymod/replay/ReplayHandler.java index d163d7ab..6862b871 100644 --- a/src/main/java/com/replaymod/replay/ReplayHandler.java +++ b/src/main/java/com/replaymod/replay/ReplayHandler.java @@ -26,6 +26,8 @@ import com.replaymod.replay.events.ReplayClosingCallback; import com.replaymod.replay.events.ReplayOpenedCallback; import com.replaymod.replay.gui.overlay.GuiReplayOverlay; +import com.replaymod.replay.sender.FullReplaySender; +import com.replaymod.replay.sender.QuickReplaySender; import com.replaymod.replaystudio.data.Marker; import com.replaymod.replaystudio.replay.ReplayFile; import com.replaymod.replaystudio.util.Location; @@ -119,7 +121,7 @@ public ReplayHandler(ReplayFile replayFile, boolean asyncMode) throws IOExceptio fullReplaySender.setAsyncMode(asyncMode); } - void restartedReplay() { + public void restartedReplay() { Preconditions.checkState(mc.isOnExecutionThread(), "Must be called from Minecraft thread."); channel.close(); @@ -188,7 +190,6 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable t) { } )); - channel = new EmbeddedChannel(); channel.pipeline().addLast("ReplayModReplay_quickReplaySender", quickReplaySender); channel.pipeline().addLast("ReplayModReplay_replaySender", fullReplaySender); diff --git a/src/main/java/com/replaymod/replay/FullReplaySender.java b/src/main/java/com/replaymod/replay/sender/FullReplaySender.java similarity index 99% rename from src/main/java/com/replaymod/replay/FullReplaySender.java rename to src/main/java/com/replaymod/replay/sender/FullReplaySender.java index 63d67c97..ba72cec5 100644 --- a/src/main/java/com/replaymod/replay/FullReplaySender.java +++ b/src/main/java/com/replaymod/replay/sender/FullReplaySender.java @@ -1,4 +1,4 @@ -package com.replaymod.replay; +package com.replaymod.replay.sender; import com.github.steveice10.packetlib.io.NetOutput; import com.github.steveice10.packetlib.tcp.io.ByteBufNetOutput; @@ -11,6 +11,10 @@ import com.replaymod.gui.versions.callbacks.PreTickCallback; import com.replaymod.mixin.MinecraftAccessor; import com.replaymod.mixin.TimerAccessor; +import com.replaymod.replay.ReplayHandler; +import com.replaymod.replay.ReplayModReplay; +import com.replaymod.replay.ReplaySender; +import com.replaymod.replay.Setting; import com.replaymod.replay.camera.CameraEntity; import com.replaymod.replaystudio.io.ReplayInputStream; import com.replaymod.replaystudio.replay.ReplayFile; diff --git a/src/main/java/com/replaymod/replay/QuickReplaySender.java b/src/main/java/com/replaymod/replay/sender/QuickReplaySender.java similarity index 98% rename from src/main/java/com/replaymod/replay/QuickReplaySender.java rename to src/main/java/com/replaymod/replay/sender/QuickReplaySender.java index a5c2d8c0..a470ffe1 100644 --- a/src/main/java/com/replaymod/replay/QuickReplaySender.java +++ b/src/main/java/com/replaymod/replay/sender/QuickReplaySender.java @@ -1,4 +1,4 @@ -package com.replaymod.replay; +package com.replaymod.replay.sender; import com.github.steveice10.packetlib.io.NetInput; import com.github.steveice10.packetlib.tcp.io.ByteBufNetInput; @@ -11,6 +11,8 @@ import com.replaymod.gui.versions.callbacks.PreTickCallback; import com.replaymod.mixin.MinecraftAccessor; import com.replaymod.mixin.TimerAccessor; +import com.replaymod.replay.ReplayModReplay; +import com.replaymod.replay.ReplaySender; import com.replaymod.replaystudio.replay.ReplayFile; import com.replaymod.replaystudio.util.RandomAccessReplay; import io.netty.buffer.ByteBuf;