From f8fc3462e860f2f959c769655f0f1497d49e3388 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 10 Mar 2019 12:53:03 +0100 Subject: [PATCH] Get recording and replay working --- .../java/com/replaymod/core/ReplayMod.java | 16 +- .../replaymod/core/utils/Restrictions.java | 8 +- .../AdvancedScreenshots.java | 59 +-- .../handler/RecordingEventHandler.java | 6 + .../mixin/MixinKeyboardListener.java | 45 +++ .../recording/mixin/MixinMouseHelper.java | 41 ++ .../mixin/MixinNetHandlerLoginClient.java | 26 +- .../mixin/MixinNetHandlerPlayClient.java | 8 +- .../mixin/MixinNetworkDispatcher.java | 135 ++++--- .../recording/mixin/MixinRenderGlobal.java | 9 +- .../recording/packet/PacketListener.java | 19 +- .../replaymod/replay/FullReplaySender.java | 56 ++- .../replaymod/replay/InputReplayTimer.java | 365 +++++++++--------- .../replaymod/replay/QuickReplaySender.java | 9 +- .../com/replaymod/replay/ReplayHandler.java | 26 +- .../com/replaymod/replay/ReplayModReplay.java | 2 +- .../replay/gui/screen/GuiReplayViewer.java | 2 +- .../replaymod/replay/handler/GuiHandler.java | 19 +- .../MixinTileEntityEndPortalRenderer.java | 2 +- src/main/resources/META-INF/replaymod_at.cfg | 6 + .../resources/mixins.recording.replaymod.json | 8 +- versions/common.gradle | 2 +- 22 files changed, 538 insertions(+), 331 deletions(-) create mode 100644 src/main/java/com/replaymod/recording/mixin/MixinKeyboardListener.java create mode 100644 src/main/java/com/replaymod/recording/mixin/MixinMouseHelper.java diff --git a/src/main/java/com/replaymod/core/ReplayMod.java b/src/main/java/com/replaymod/core/ReplayMod.java index 5ee952f2..b57c5260 100755 --- a/src/main/java/com/replaymod/core/ReplayMod.java +++ b/src/main/java/com/replaymod/core/ReplayMod.java @@ -25,7 +25,8 @@ import org.apache.commons.io.FileUtils; //#if MC>=11300 import com.replaymod.core.versions.LangResourcePack; import net.minecraft.resources.FolderPack; -import net.minecraft.resources.IResourcePack; +import net.minecraft.resources.IPackFinder; +import net.minecraft.resources.ResourcePackInfo; import net.minecraftforge.fml.DeferredWorkQueue; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; @@ -87,6 +88,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Queue; import java.util.concurrent.FutureTask; @@ -211,7 +213,6 @@ public class ReplayMod implements Module { static { // Note: even preInit is too late and we'd have to issue another resource reload @SuppressWarnings("unchecked") //#if MC>=11300 - List defaultResourcePacks = new ArrayList<>(); // FIXME: probably replaced with DownloadingPackFinder FolderPack jGuiResourcePack = new FolderPack(new File("../jGui/src/main/resources")) { @Override protected InputStream getInputStream(String resourceName) throws IOException { @@ -233,7 +234,16 @@ public class ReplayMod implements Module { } } }; - defaultResourcePacks.add(jGuiResourcePack); + //#if MC>=11300 + mc.resourcePackRepository.addPackFinder(new IPackFinder() { + @Override + public void addPackInfosToMap(Map map, ResourcePackInfo.IFactory factory) { + map.put("jgui", ResourcePackInfo.func_195793_a("jgui", true, () -> jGuiResourcePack, factory, ResourcePackInfo.Priority.BOTTOM)); + } + }); + //#else + //$$ defaultResourcePacks.add(jGuiResourcePack); + //#endif //#if MC<=10710 //$$ FolderResourcePack mainResourcePack = new FolderResourcePack(new File("../src/main/resources")) { //$$ @Override diff --git a/src/main/java/com/replaymod/core/utils/Restrictions.java b/src/main/java/com/replaymod/core/utils/Restrictions.java index 2a5f870f..1deccf7f 100644 --- a/src/main/java/com/replaymod/core/utils/Restrictions.java +++ b/src/main/java/com/replaymod/core/utils/Restrictions.java @@ -3,6 +3,7 @@ package com.replaymod.core.utils; import net.minecraft.network.PacketBuffer; //#if MC>=10904 import net.minecraft.network.play.server.SPacketCustomPayload; +import net.minecraft.util.ResourceLocation; //#else //$$ import net.minecraft.network.play.server.S3FPacketCustomPayload; //#endif @@ -18,8 +19,11 @@ import static com.replaymod.core.versions.MCVer.readString; * @see Replay Restrictions Gist */ public class Restrictions { - // FIXME these should be ResourceLocations now - public static final String PLUGIN_CHANNEL = "Replay|Restrict"; + //#if MC>=11300 + public static final ResourceLocation PLUGIN_CHANNEL = new ResourceLocation("replaymod", "restrict"); + //#else + //$$ public static final String PLUGIN_CHANNEL = "Replay|Restrict"; + //#endif private boolean noXray; private boolean noNoclip; private boolean onlyFirstPerson; diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/AdvancedScreenshots.java b/src/main/java/com/replaymod/extras/advancedscreenshots/AdvancedScreenshots.java index 8cefee8c..49d7e2c8 100644 --- a/src/main/java/com/replaymod/extras/advancedscreenshots/AdvancedScreenshots.java +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/AdvancedScreenshots.java @@ -1,23 +1,20 @@ package com.replaymod.extras.advancedscreenshots; import com.replaymod.core.ReplayMod; -import com.replaymod.core.versions.MCVer; import com.replaymod.extras.Extra; -import com.replaymod.replay.events.ReplayDispatchKeypressesEvent; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiControls; import net.minecraftforge.common.MinecraftForge; -//#if MC>=11300 -import com.replaymod.core.versions.MCVer.Keyboard; -import net.minecraftforge.client.event.GuiScreenEvent; -//#else +//#if MC<11300 +//$$ import com.replaymod.core.versions.MCVer; +//$$ import com.replaymod.replay.events.ReplayDispatchKeypressesEvent; +//$$ import net.minecraft.client.Minecraft; +//$$ import net.minecraft.client.gui.GuiControls; +//$$ import net.minecraftforge.client.event.GuiScreenEvent; //$$ import org.lwjgl.input.Keyboard; //#endif //#if MC>=10800 //#if MC>=11300 -import net.minecraftforge.eventbus.api.SubscribeEvent; //#else //$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; //#endif @@ -29,30 +26,36 @@ public class AdvancedScreenshots implements Extra { private ReplayMod mod; - private final Minecraft mc = MCVer.getMinecraft(); - @Override - public void register(ReplayMod mod) throws Exception { + public void register(ReplayMod mod) { this.mod = mod; MinecraftForge.EVENT_BUS.register(this); } - @SubscribeEvent - public void onDispatchKeypresses(ReplayDispatchKeypressesEvent.Pre event) { - if (mc.currentScreen instanceof GuiControls) return; - //#if MC>=11300 - // FIXME - //#else - //$$ if (!Keyboard.getEventKeyState()) return; - //$$ if (Keyboard.isRepeatEvent()) return; - //$$ int keyCode = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() : Keyboard.getEventKey(); - //$$ if (keyCode == 0 || keyCode != mc.gameSettings.keyBindScreenshot.getKeyCode()) return; - //#endif + //#if MC>=11300 + private static AdvancedScreenshots instance; { instance = this; } + public static void take() { + if (instance != null) { + instance.takeScreenshot(); + } + } + //#else + //$$ @SubscribeEvent + //$$ public void onDispatchKeypresses(ReplayDispatchKeypressesEvent.Pre event) { + //$$ Minecraft mc = MCVer.getMinecraft(); + //$$ if (mc.currentScreen instanceof GuiControls) return; + //$$ if (!Keyboard.getEventKeyState()) return; + //$$ if (Keyboard.isRepeatEvent()) return; + //$$ int keyCode = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() : Keyboard.getEventKey(); + //$$ if (keyCode == 0 || keyCode != mc.gameSettings.keyBindScreenshot.getKeyCode()) return; + //$$ + //$$ takeScreenshot(); + //$$ + //$$ event.setCanceled(true); + //$$ } + //#endif - ReplayMod.instance.runLater(() -> { - new GuiCreateScreenshot(mod).display(); - }); - - event.setCanceled(true); + private void takeScreenshot() { + ReplayMod.instance.runLater(() -> new GuiCreateScreenshot(mod).display()); } } diff --git a/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java b/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java index cfa35138..a3313842 100755 --- a/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java +++ b/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java @@ -83,6 +83,12 @@ public class RecordingEventHandler { } } + //#if MC>=11300 + public void onPacket(Packet packet) { + packetListener.save(packet); + } + //#endif + public void onPlayerJoin() { try { //#if MC>=10904 diff --git a/src/main/java/com/replaymod/recording/mixin/MixinKeyboardListener.java b/src/main/java/com/replaymod/recording/mixin/MixinKeyboardListener.java new file mode 100644 index 00000000..c52c209d --- /dev/null +++ b/src/main/java/com/replaymod/recording/mixin/MixinKeyboardListener.java @@ -0,0 +1,45 @@ +//#if MC>=11300 +package com.replaymod.recording.mixin; + +import com.replaymod.core.versions.MCVer; +import com.replaymod.extras.advancedscreenshots.AdvancedScreenshots; +import com.replaymod.replay.ReplayModReplay; +import net.minecraft.client.KeyboardListener; +import net.minecraft.client.settings.KeyBinding; +import net.minecraft.client.shader.Framebuffer; +import net.minecraft.util.ScreenShotHelper; +import net.minecraft.util.text.ITextComponent; +import net.minecraftforge.fml.hooks.BasicEventHooks; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.io.File; +import java.util.function.Consumer; + +@Mixin(KeyboardListener.class) +public abstract class MixinKeyboardListener { + @Inject(method = "onKeyEvent", at = @At("HEAD"), cancellable = true) + private void dispatchKeyEvent(long windowPointer, int key, int scanCode, int action, int modifiers, CallbackInfo ci) { + // FIXME this is a hack and will hopefully be done properly by forge before its release (MinecraftForge#5481) + // (and therefore before RM's release), this code will have to be removed then and handling code updated + KeyBinding keyBindChat = MCVer.getMinecraft().gameSettings.keyBindChat; + if (action == 1 && keyBindChat.matchesKey(key, scanCode)) { + keyBindChat.pressTime++; + BasicEventHooks.fireKeyInput(); + ci.cancel(); + } + } + + @Redirect(method = "onKeyEvent", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/ScreenShotHelper;saveScreenshot(Ljava/io/File;IILnet/minecraft/client/shader/Framebuffer;Ljava/util/function/Consumer;)V")) + private void takeScreenshot(File p_148260_0_, int p_148260_1_, int p_148260_2_, Framebuffer p_148260_3_, Consumer p_148260_4_) { + if (ReplayModReplay.instance.getReplayHandler() != null) { + AdvancedScreenshots.take(); + } else { + ScreenShotHelper.saveScreenshot(p_148260_0_, p_148260_1_, p_148260_2_, p_148260_3_, p_148260_4_); + } + } +} +//#endif diff --git a/src/main/java/com/replaymod/recording/mixin/MixinMouseHelper.java b/src/main/java/com/replaymod/recording/mixin/MixinMouseHelper.java new file mode 100644 index 00000000..4dba3a3f --- /dev/null +++ b/src/main/java/com/replaymod/recording/mixin/MixinMouseHelper.java @@ -0,0 +1,41 @@ +//#if MC>=11300 +package com.replaymod.recording.mixin; + +import com.replaymod.replay.InputReplayTimer; +import com.replaymod.replay.ReplayModReplay; +import net.minecraft.client.MouseHelper; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +@Mixin(MouseHelper.class) +public abstract class MixinMouseHelper { + //#ifdef DEV_ENV + @Shadow + private boolean mouseGrabbed; + + @Inject(method = "grabMouse", at = @At("HEAD"), cancellable = true) + private void noGrab(CallbackInfo ci) { + // Used to be provided by Forge for 1.12.2 and below + if (Boolean.valueOf(System.getProperty("fml.noGrab", "false"))) { + mouseGrabbed = true; + ci.cancel(); + } + } + //#endif + + @Inject(method = "scrollCallback", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/entity/EntityPlayerSP;isSpectator()Z"), + locals = LocalCapture.CAPTURE_FAILHARD, + cancellable = true) + private void handleReplayModScroll(long _p0, double _p1, double _p2, CallbackInfo ci, double _l1, double yOffsetAccumulated) { + if (ReplayModReplay.instance.getReplayHandler() != null) { + InputReplayTimer.handleScroll((int) yOffsetAccumulated); + ci.cancel(); + } + } +} +//#endif diff --git a/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerLoginClient.java b/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerLoginClient.java index a09681ef..e3df345e 100644 --- a/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerLoginClient.java +++ b/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerLoginClient.java @@ -9,11 +9,17 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +//#if MC>=11300 +import com.replaymod.core.versions.MCVer; +import com.replaymod.recording.handler.RecordingEventHandler.RecordingEventSender; +import net.minecraft.network.login.server.SPacketCustomPayloadLogin; +//#else //#if MC>=10800 -// FIXME event not (yet?) in 1.13 import net.minecraftforge.fml.common.network.FMLNetworkEvent; +//$$ import net.minecraftforge.fml.common.network.FMLNetworkEvent; //#else //$$ import cpw.mods.fml.common.network.FMLNetworkEvent; //#endif +//#endif @Mixin(NetHandlerLoginClient.class) public abstract class MixinNetHandlerLoginClient { @@ -27,6 +33,16 @@ public abstract class MixinNetHandlerLoginClient { //#if MC>=11300 @Inject(method = "func_209521_a", at=@At("HEAD")) + private void replayModRecording_initiateRecording(SPacketCustomPayloadLogin packet, CallbackInfo ci) { + RecordingEventSender eventSender = (RecordingEventSender) MCVer.getMinecraft().renderGlobal; + if (eventSender.getRecordingEventHandler() != null) { + return; // already recording + } + ReplayModRecording.instance.initiateRecording(networkManager); + if (eventSender.getRecordingEventHandler() != null) { + eventSender.getRecordingEventHandler().onPacket(packet); + } + } //#else //$$ /** //$$ * Starts the recording right before switching into PLAY state. @@ -34,14 +50,14 @@ public abstract class MixinNetHandlerLoginClient { //$$ * as it only fires after the forge handshake. //$$ */ //$$ @Inject(method = "handleLoginSuccess", at=@At("HEAD")) - //#endif - public void replayModRecording_initiateRecording(CallbackInfo cb) { + //$$ public void replayModRecording_initiateRecording(CallbackInfo cb) { //#if MC>=10800 - ReplayModRecording.instance.initiateRecording(networkManager); + //$$ ReplayModRecording.instance.initiateRecording(networkManager); //#else //$$ ReplayModRecording.instance.initiateRecording(field_147393_d); //#endif - } + //$$ } + //#endif //#if MC>=11200 @Inject(method = "handleLoginSuccess", at=@At("RETURN")) diff --git a/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerPlayClient.java b/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerPlayClient.java index a065f643..6af64ea5 100644 --- a/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerPlayClient.java +++ b/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerPlayClient.java @@ -1,5 +1,6 @@ package com.replaymod.recording.mixin; +import com.replaymod.core.versions.MCVer; import com.replaymod.recording.handler.RecordingEventHandler; import net.minecraft.client.Minecraft; import net.minecraft.client.network.NetHandlerPlayClient; @@ -13,7 +14,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; //#if MC>=10800 //#if MC>=10904 import net.minecraft.network.play.server.SPacketPlayerListItem.Action; -// FIXME requires RuntimeInvisParam workaround import net.minecraft.network.play.server.SPacketPlayerListItem.AddPlayerData; +import net.minecraft.network.play.server.SPacketPlayerListItem.AddPlayerData; //#else //$$ import net.minecraft.network.play.server.S38PacketPlayerListItem.Action; //$$ import net.minecraft.network.play.server.S38PacketPlayerListItem.AddPlayerData; @@ -30,8 +31,7 @@ import static com.replaymod.core.versions.MCVer.*; @Mixin(NetHandlerPlayClient.class) public abstract class MixinNetHandlerPlayClient { - @Shadow - private Minecraft gameController; + private static Minecraft gameController = MCVer.getMinecraft(); //#if MC>=10800 @Shadow @@ -61,7 +61,6 @@ public abstract class MixinNetHandlerPlayClient { RecordingEventHandler handler = getRecordingEventHandler(); if (handler != null && packet.getAction() == Action.ADD_PLAYER) { - /* FIXME see import for (AddPlayerData data : packet.getEntries()) { if (data.getProfile() == null || data.getProfile().getId() == null) continue; // Only add spawn packet for our own player and only if he isn't known yet @@ -70,7 +69,6 @@ public abstract class MixinNetHandlerPlayClient { handler.onPlayerJoin(); } } - */ } } //#else diff --git a/src/main/java/com/replaymod/recording/mixin/MixinNetworkDispatcher.java b/src/main/java/com/replaymod/recording/mixin/MixinNetworkDispatcher.java index 1355c31c..7f91df30 100644 --- a/src/main/java/com/replaymod/recording/mixin/MixinNetworkDispatcher.java +++ b/src/main/java/com/replaymod/recording/mixin/MixinNetworkDispatcher.java @@ -1,78 +1,77 @@ -/* FIXME -package com.replaymod.recording.mixin; - -import com.replaymod.recording.handler.FMLHandshakeFilter; -import io.netty.channel.ChannelPipeline; -import io.netty.channel.embedded.EmbeddedChannel; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - +//#if MC<11300 +//$$ package com.replaymod.recording.mixin; +//$$ +//$$ import com.replaymod.recording.handler.FMLHandshakeFilter; +//$$ import io.netty.channel.ChannelPipeline; +//$$ import io.netty.channel.embedded.EmbeddedChannel; +//$$ import org.spongepowered.asm.mixin.Mixin; +//$$ import org.spongepowered.asm.mixin.Shadow; +//$$ import org.spongepowered.asm.mixin.injection.At; +//$$ import org.spongepowered.asm.mixin.injection.Inject; +//$$ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +//$$ //#if MC>=11200 -import io.netty.channel.ChannelConfig; -import net.minecraft.network.EnumConnectionState; -import net.minecraft.network.NetworkManager; -import org.spongepowered.asm.mixin.injection.Redirect; +//$$ import io.netty.channel.ChannelConfig; +//$$ import net.minecraft.network.EnumConnectionState; +//$$ import net.minecraft.network.NetworkManager; +//$$ import org.spongepowered.asm.mixin.injection.Redirect; //#endif - +//$$ //#if MC>=10800 -import net.minecraftforge.fml.common.network.handshake.FMLHandshakeCodec; -import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher; -import net.minecraftforge.fml.relauncher.Side; +//$$ import net.minecraftforge.fml.common.network.handshake.FMLHandshakeCodec; +//$$ import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher; +//$$ import net.minecraftforge.fml.relauncher.Side; //#else //$$ import cpw.mods.fml.common.network.handshake.FMLHandshakeCodec; //$$ import cpw.mods.fml.common.network.handshake.NetworkDispatcher; //$$ import cpw.mods.fml.relauncher.Side; //#endif - -@Mixin(value = NetworkDispatcher.class, remap = false) -public abstract class MixinNetworkDispatcher { - - @Shadow - private Side side; - - @Shadow - private EmbeddedChannel handshakeChannel; - - /** - * Always sets fml:isLocal to false on the server side. - * This effectively removes the difference in the FML handshake between SP and MP - * and forces the block/item ids, etc. to always be send. - * Injects a {@link FMLHandshakeFilter} on the client side to filter out - * those extra, unexpected packets. - */ -/* - @Inject(method = "insertIntoChannel", at=@At("HEAD")) - public void replayModRecording_setupForLocalRecording(CallbackInfo cb) { - // If we're in multiplayer, everything is fine as is - if (!handshakeChannel.attr(NetworkDispatcher.IS_LOCAL).get()) return; - - if (side == Side.SERVER) { - // On the server side, force all packets to be sent - handshakeChannel.attr(NetworkDispatcher.IS_LOCAL).set(false); - } else { - // On the client side, discard additional packets - ChannelPipeline pipeline = handshakeChannel.pipeline(); - pipeline.addAfter(pipeline.context(FMLHandshakeCodec.class).name(), - "replaymod_filter", new FMLHandshakeFilter()); - } - } - +//$$ +//$$ @Mixin(value = NetworkDispatcher.class, remap = false) +//$$ public abstract class MixinNetworkDispatcher { +//$$ +//$$ @Shadow +//$$ private Side side; +//$$ +//$$ @Shadow +//$$ private EmbeddedChannel handshakeChannel; +//$$ +//$$ /** +//$$ * Always sets fml:isLocal to false on the server side. +//$$ * This effectively removes the difference in the FML handshake between SP and MP +//$$ * and forces the block/item ids, etc. to always be send. +//$$ * Injects a {@link FMLHandshakeFilter} on the client side to filter out +//$$ * those extra, unexpected packets. +//$$ */ +//$$ @Inject(method = "insertIntoChannel", at=@At("HEAD")) +//$$ public void replayModRecording_setupForLocalRecording(CallbackInfo cb) { +//$$ // If we're in multiplayer, everything is fine as is +//$$ if (!handshakeChannel.attr(NetworkDispatcher.IS_LOCAL).get()) return; +//$$ +//$$ if (side == Side.SERVER) { +//$$ // On the server side, force all packets to be sent +//$$ handshakeChannel.attr(NetworkDispatcher.IS_LOCAL).set(false); +//$$ } else { +//$$ // On the client side, discard additional packets +//$$ ChannelPipeline pipeline = handshakeChannel.pipeline(); +//$$ pipeline.addAfter(pipeline.context(FMLHandshakeCodec.class).name(), +//$$ "replaymod_filter", new FMLHandshakeFilter()); +//$$ } +//$$ } +//$$ //#if MC>=11200 - @Redirect(method = "clientListenForServerHandshake", at = @At(value = "INVOKE", remap = true, target = - "Lnet/minecraft/network/NetworkManager;setConnectionState(Lnet/minecraft/network/EnumConnectionState;)V")) - public void replayModRecording_raceConditionWorkAround1(NetworkManager self, EnumConnectionState ignored) { } - - @Redirect(method = "insertIntoChannel", at = @At(value = "INVOKE", target = - "Lio/netty/channel/ChannelConfig;setAutoRead(Z)Lio/netty/channel/ChannelConfig;")) - public ChannelConfig replayModRecording_raceConditionWorkAround2(ChannelConfig self, boolean autoRead) { - if (side == Side.CLIENT) { - autoRead = false; - } - return self.setAutoRead(autoRead); - } + //$$ @Redirect(method = "clientListenForServerHandshake", at = @At(value = "INVOKE", remap = true, target = + //$$ "Lnet/minecraft/network/NetworkManager;setConnectionState(Lnet/minecraft/network/EnumConnectionState;)V")) + //$$ public void replayModRecording_raceConditionWorkAround1(NetworkManager self, EnumConnectionState ignored) { } + //$$ + //$$ @Redirect(method = "insertIntoChannel", at = @At(value = "INVOKE", target = + //$$ "Lio/netty/channel/ChannelConfig;setAutoRead(Z)Lio/netty/channel/ChannelConfig;")) + //$$ public ChannelConfig replayModRecording_raceConditionWorkAround2(ChannelConfig self, boolean autoRead) { + //$$ if (side == Side.CLIENT) { + //$$ autoRead = false; + //$$ } + //$$ return self.setAutoRead(autoRead); + //$$ } //#endif -} -*/ +//$$ } +//#endif diff --git a/src/main/java/com/replaymod/recording/mixin/MixinRenderGlobal.java b/src/main/java/com/replaymod/recording/mixin/MixinRenderGlobal.java index 0c11e4ed..637ba04a 100644 --- a/src/main/java/com/replaymod/recording/mixin/MixinRenderGlobal.java +++ b/src/main/java/com/replaymod/recording/mixin/MixinRenderGlobal.java @@ -7,6 +7,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; //#if MC>=11300 +import net.minecraft.client.renderer.WorldRenderer; //#else //$$ import net.minecraft.client.renderer.RenderGlobal; //#endif @@ -19,8 +20,11 @@ import net.minecraft.util.math.BlockPos; //#endif //#endif -/* FIXME runtimeinvisparameter -@Mixin(RenderGlobal.class) +//#if MC>=11300 +@Mixin(WorldRenderer.class) +//#else +//$$ @Mixin(RenderGlobal.class) +//#endif public abstract class MixinRenderGlobal implements RecordingEventHandler.RecordingEventSender { private RecordingEventHandler recordingEventHandler; @@ -58,4 +62,3 @@ public abstract class MixinRenderGlobal implements RecordingEventHandler.Recordi } } } -*/ diff --git a/src/main/java/com/replaymod/recording/packet/PacketListener.java b/src/main/java/com/replaymod/recording/packet/PacketListener.java index e7e6be68..c33e5ff3 100755 --- a/src/main/java/com/replaymod/recording/packet/PacketListener.java +++ b/src/main/java/com/replaymod/recording/packet/PacketListener.java @@ -17,6 +17,10 @@ import net.minecraft.network.play.server.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +//#if MC>=11300 +import net.minecraft.network.login.server.SPacketLoginSuccess; +//#endif + //#if MC>=10904 import net.minecraft.network.datasync.EntityDataManager; import net.minecraft.util.text.TextComponentString; @@ -67,6 +71,11 @@ public class PacketListener extends ChannelInboundHandlerAdapter { private long lastSentPacket; private long timePassedWhilePaused; private volatile boolean serverWasPaused; + //#if MC>=11300 + private EnumConnectionState connectionState = EnumConnectionState.LOGIN; + //#else + //$$ private EnumConnectionState connectionState = EnumConnectionState.PLAY; + //#endif /** * Used to keep track of the last metadata save job submitted to the save service and @@ -147,6 +156,12 @@ public class PacketListener extends ChannelInboundHandlerAdapter { throw new RuntimeException(e); } }); + + //#if MC>=11300 + if (packet instanceof SPacketLoginSuccess) { + connectionState = EnumConnectionState.PLAY; + } + //#endif } catch(Exception e) { logger.error("Writing packet:", e); } @@ -339,9 +354,9 @@ public class PacketListener extends ChannelInboundHandlerAdapter { //#endif //#if MC>=10800 - Integer packetId = EnumConnectionState.PLAY.getPacketId(EnumPacketDirection.CLIENTBOUND, packet); + Integer packetId = connectionState.getPacketId(EnumPacketDirection.CLIENTBOUND, packet); //#else - //$$ Integer packetId = (Integer) EnumConnectionState.PLAY.func_150755_b().inverse().get(packet.getClass()); + //$$ Integer packetId = (Integer) connectionState.func_150755_b().inverse().get(packet.getClass()); //#endif if (packetId == null) { throw new IOException("Unknown packet type:" + packet.getClass()); diff --git a/src/main/java/com/replaymod/replay/FullReplaySender.java b/src/main/java/com/replaymod/replay/FullReplaySender.java index cab8b6f3..b56d2f5a 100755 --- a/src/main/java/com/replaymod/replay/FullReplaySender.java +++ b/src/main/java/com/replaymod/replay/FullReplaySender.java @@ -48,8 +48,10 @@ import net.minecraft.world.GameType; //$$ import net.minecraft.world.WorldSettings.GameType; //#endif //#if MC>=10904 +import net.minecraft.network.login.server.SPacketLoginSuccess; import net.minecraft.util.text.ITextComponent; //#else +//$$ import net.minecraft.network.login.server.S02PacketLoginSuccess; //$$ import net.minecraft.util.IChatComponent; //#endif @@ -123,6 +125,9 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend private static int TP_DISTANCE_LIMIT = 128; + private static final ByteBuf byteBuf = Unpooled.buffer(); + private static final ByteBufOutputStream byteBufOut = new ByteBufOutputStream(byteBuf); + /** * The replay handler responsible for the current replay. */ @@ -165,12 +170,22 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend */ protected ReplayInputStream replayIn; + /** + * @see PacketData#PacketData(ReplayInputStream, ReplayOutputStream) + */ + private ReplayOutputStream encoder; + /** * The next packet that should be sent. * This is required as some actions such as jumping to a specified timestamp have to peek at the next packet. */ protected PacketData nextPacket; + /** + * Whether we're currently reading packets from the login phase. + */ + private boolean loginPhase; + /** * Whether we need to restart the current replay. E.g. when jumping backwards in time */ @@ -317,7 +332,11 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend if (world(mc) != null) { for (EntityPlayer playerEntity : playerEntities(world(mc))) { if (!playerEntity.addedToChunk && playerEntity instanceof EntityOtherPlayerMP) { - // FIXME playerEntity.onLivingUpdate(); + //#if MC>=11300 + playerEntity.livingTick(); + //#else + //$$ playerEntity.onLivingUpdate(); + //#endif } } } @@ -416,10 +435,11 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend int i = readVarInt(pb); + EnumConnectionState state = loginPhase ? EnumConnectionState.LOGIN : EnumConnectionState.PLAY; //#if MC>=10800 - Packet p = EnumConnectionState.PLAY.getPacket(EnumPacketDirection.CLIENTBOUND, i); + Packet p = state.getPacket(EnumPacketDirection.CLIENTBOUND, i); //#else - //$$ Packet p = Packet.generatePacket(EnumConnectionState.PLAY.func_150755_b(), i); + //$$ Packet p = Packet.generatePacket(state.func_150755_b(), i); //#endif p.readPacketData(pb); @@ -432,6 +452,15 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend * @return The processed packet or {@code null} if no packet shall be sent */ protected Packet processPacket(Packet p) throws Exception { + //#if MC>=10904 + if (p instanceof SPacketLoginSuccess) { + //#else + //$$ if (p instanceof S02PacketLoginSuccess) { + //#endif + loginPhase = false; + return p; + } + //#if MC>=10904 if (p instanceof SPacketCustomPayload) { SPacketCustomPayload packet = (SPacketCustomPayload) p; @@ -584,7 +613,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend //#endif EnumDifficulty difficulty = packet.getDifficulty(); //#if MC>=11300 - int maxPlayers = 0;// FIXME needs AT packet.maxPlayers; + int maxPlayers = packet.maxPlayers; //#else //$$ int maxPlayers = packet.getMaxPlayers(); //#endif @@ -832,7 +861,8 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend while (!terminate) { synchronized (FullReplaySender.this) { if (replayIn == null) { - replayIn = replayFile.getPacketData(); + replayIn = replayFile.getPacketData(new ReplayStudio(), true); + encoder = new ReplayOutputStream(new ReplayStudio(), byteBufOut, true); } // Packet loop while (true) { @@ -859,7 +889,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend // Read the next packet if we don't already have one if (nextPacket == null) { - nextPacket = new PacketData(replayIn); + nextPacket = new PacketData(replayIn, encoder); } int nextTimeStamp = nextPacket.timestamp; @@ -912,6 +942,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend // Restart the replay. hasWorldLoaded = false; lastTimeStamp = 0; + loginPhase = true; startFromBeginning = false; nextPacket = null; lastPacketSent = System.currentTimeMillis(); @@ -1025,13 +1056,15 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend replayIn.close(); replayIn = null; } + loginPhase = true; startFromBeginning = false; nextPacket = null; replayHandler.restartedReplay(); } if (replayIn == null) { - replayIn = replayFile.getPacketData(); + replayIn = replayFile.getPacketData(new ReplayStudio(), true); + encoder = new ReplayOutputStream(new ReplayStudio(), byteBufOut, true); } while (true) { // Send packets @@ -1043,7 +1076,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend nextPacket = null; } else { // Otherwise read one from the input stream - pd = new PacketData(replayIn); + pd = new PacketData(replayIn, encoder); } int nextTimeStamp = pd.timestamp; @@ -1176,19 +1209,16 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend } private static final class PacketData { - private static final ByteBuf byteBuf = Unpooled.buffer(); - private static final ByteBufOutputStream byteBufOut = new ByteBufOutputStream(byteBuf); - private static final ReplayOutputStream encoder = new ReplayOutputStream(new ReplayStudio(), byteBufOut); private final int timestamp; private final byte[] bytes; - public PacketData(ReplayInputStream in) throws IOException { + PacketData(ReplayInputStream in, ReplayOutputStream encoder) throws IOException { com.replaymod.replaystudio.PacketData data = in.readPacket(); timestamp = (int) data.getTime(); // We need to re-encode MCProtocolLib 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 // to apply ViaVersion (and potentially other magic) to it. - synchronized (encoder) { + synchronized (byteBuf) { byteBuf.markReaderIndex(); // Mark the current reader and writer index (should be at start) byteBuf.markWriterIndex(); diff --git a/src/main/java/com/replaymod/replay/InputReplayTimer.java b/src/main/java/com/replaymod/replay/InputReplayTimer.java index 0a9e1efb..4359da74 100644 --- a/src/main/java/com/replaymod/replay/InputReplayTimer.java +++ b/src/main/java/com/replaymod/replay/InputReplayTimer.java @@ -3,18 +3,19 @@ package com.replaymod.replay; import com.replaymod.core.utils.WrappedTimer; import com.replaymod.replay.camera.CameraController; import com.replaymod.replay.camera.CameraEntity; -import com.replaymod.replay.events.ReplayDispatchKeypressesEvent; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiScreen; -import net.minecraft.client.settings.KeyBinding; -import net.minecraft.crash.CrashReport; import net.minecraft.util.Timer; -import net.minecraftforge.client.ForgeHooksClient; -import net.minecraftforge.common.MinecraftForge; //#if MC>=11300 +import org.lwjgl.glfw.GLFW; //#else +//$$ import com.replaymod.replay.events.ReplayDispatchKeypressesEvent; +//$$ import net.minecraft.client.gui.GuiScreen; //$$ import net.minecraft.client.settings.GameSettings; +//$$ import net.minecraft.client.settings.KeyBinding; +//$$ import net.minecraft.crash.CrashReport; +//$$ import net.minecraftforge.client.ForgeHooksClient; +//$$ import net.minecraftforge.common.MinecraftForge; //$$ import org.lwjgl.input.Keyboard; //$$ import org.lwjgl.input.Mouse; //#if MC>=10800 @@ -28,6 +29,7 @@ import net.minecraftforge.common.MinecraftForge; //$$ //$$ import static com.replaymod.core.versions.MCVer.FML_BUS; //#endif +//$$ import static com.replaymod.core.versions.MCVer.newReportedException; //#endif public class InputReplayTimer extends WrappedTimer { @@ -40,10 +42,14 @@ public class InputReplayTimer extends WrappedTimer { this.mc = mod.getCore().getMinecraft(); } - /* FIXME @Override - public void updateTimer() { - super.updateTimer(); + //#if MC>=11300 + public void updateTimer(long sysClock) { + super.updateTimer(sysClock); + //#else + //$$ public void updateTimer() { + //$$ super.updateTimer(); + //#endif // 1.7.10: We have to run the scheduled executables (ours only) because MC would only run them every tick //#if MC<=10710 @@ -53,43 +59,41 @@ public class InputReplayTimer extends WrappedTimer { // If we are in a replay, we have to manually process key and mouse events as the // tick speed may vary or there may not be any ticks at all (when the replay is paused) if (mod.getReplayHandler() != null) { + //#if MC>=11300 if (mc.currentScreen == null || mc.currentScreen.allowUserInput) { - while (Mouse.next()) { - handleMouseEvent(); - } - - while (Keyboard.next()) { - handleKeyEvent(); - } - } else { + GLFW.glfwPollEvents(); + mc.processKeyBinds(); + } + mc.keyboardListener.tick(); + //#else + //$$ if (mc.currentScreen == null || mc.currentScreen.allowUserInput) { + //$$ while (Mouse.next()) { + //$$ handleMouseEvent(); + //$$ } + //$$ + //$$ while (Keyboard.next()) { + //$$ handleKeyEvent(); + //$$ } + //$$ } else { + //#if MC<11300 //#if MC>=10800 - try { - mc.currentScreen.handleInput(); - } catch (IOException e) { // *SIGH* - e.printStackTrace(); - } + //$$ try { + //$$ mc.currentScreen.handleInput(); + //$$ } catch (IOException e) { // *SIGH* + //$$ e.printStackTrace(); + //$$ } //#else //$$ mc.currentScreen.handleInput(); //#endif - } + //#endif + //$$ } + //#endif } } - protected void handleMouseEvent() { - if (ForgeHooksClient.postMouseEvent()) return; - - int button = Mouse.getEventButton() - 100; - boolean pressed = Mouse.getEventButtonState(); - - // Update key binding states - KeyBinding.setKeyBindState(button, pressed); - if (pressed) { - KeyBinding.onTick(button); - } - - int wheel = Mouse.getEventDWheel(); + public static void handleScroll(int wheel) { if (wheel != 0) { - ReplayHandler replayHandler = mod.getReplayHandler(); + ReplayHandler replayHandler = ReplayModReplay.instance.getReplayHandler(); if (replayHandler != null) { CameraEntity cameraEntity = replayHandler.getCameraEntity(); if (cameraEntity != null) { @@ -105,164 +109,181 @@ public class InputReplayTimer extends WrappedTimer { } } } + } - if (mc.currentScreen == null) { - if (!mc.inGameHasFocus && Mouse.getEventButtonState()) { - // Regrab mouse if the user clicks into the window - mc.setIngameFocus(); - } - } else { + //#if MC<11300 + //$$ protected void handleMouseEvent() { + //$$ if (ForgeHooksClient.postMouseEvent()) return; + //$$ + //$$ int button = Mouse.getEventButton() - 100; + //$$ boolean pressed = Mouse.getEventButtonState(); + //$$ + //$$ // Update key binding states + //$$ KeyBinding.setKeyBindState(button, pressed); + //$$ if (pressed) { + //$$ KeyBinding.onTick(button); + //$$ } + //$$ + //$$ int wheel = Mouse.getEventDWheel(); + //$$ handleScroll(wheel); + //$$ + //$$ if (mc.currentScreen == null) { + //$$ if (!mc.inGameHasFocus && Mouse.getEventButtonState()) { + //$$ // Regrab mouse if the user clicks into the window + //$$ mc.setIngameFocus(); + //$$ } + //$$ } else { //#if MC>=10800 - try { - mc.currentScreen.handleMouseInput(); - } catch (IOException e) { // WHO IS RESPONSIBLE FOR THIS MESS?!? - e.printStackTrace(); - } + //$$ try { + //$$ mc.currentScreen.handleMouseInput(); + //$$ } catch (IOException e) { // WHO IS RESPONSIBLE FOR THIS MESS?!? + //$$ e.printStackTrace(); + //$$ } //#else //$$ mc.currentScreen.handleMouseInput(); //#endif - } - - FMLCommonHandler.instance().fireMouseInput(); - } - - protected void handleKeyEvent() { - // TODO 1.7.10: This might be missing some 1.7.10-only key bindings or implement some of them incorrectly - int key = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() + 256 : Keyboard.getEventKey(); - boolean pressed = Keyboard.getEventKeyState(); - - KeyBinding.setKeyBindState(key, pressed); - if (pressed) { - KeyBinding.onTick(key); - } - - // Still want to be able to create debug crashes ]:D - if (mc.debugCrashKeyPressTime > 0) { - if (Minecraft.getSystemTime() - mc.debugCrashKeyPressTime >= 6000L) { - throw new ReportedException(new CrashReport("Manually triggered debug crash", new Throwable())); - } - - if (!Keyboard.isKeyDown(Keyboard.KEY_F3) || !Keyboard.isKeyDown(Keyboard.KEY_C)) { - mc.debugCrashKeyPressTime = -1; - } - } else if (Keyboard.isKeyDown(Keyboard.KEY_F3) && Keyboard.isKeyDown(Keyboard.KEY_C)) { - mc.debugCrashKeyPressTime = Minecraft.getSystemTime(); - } - - // Twitch, screenshot, fullscreen, etc. (stuff that works everywhere) - if (!MinecraftForge.EVENT_BUS.post(new ReplayDispatchKeypressesEvent.Pre())) { - mc.dispatchKeypresses(); - } - - if (pressed) { - // This might be subject to change as vanilla shaders are still kinda unused in 1.8 - if (key == Keyboard.KEY_F4 && mc.entityRenderer != null) { + //$$ } + //$$ + //$$ FMLCommonHandler.instance().fireMouseInput(); + //$$ } + //$$ + //$$ protected void handleKeyEvent() { + //$$ // TODO 1.7.10: This might be missing some 1.7.10-only key bindings or implement some of them incorrectly + //$$ int key = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() + 256 : Keyboard.getEventKey(); + //$$ boolean pressed = Keyboard.getEventKeyState(); + //$$ + //$$ KeyBinding.setKeyBindState(key, pressed); + //$$ if (pressed) { + //$$ KeyBinding.onTick(key); + //$$ } + //$$ + //$$ // Still want to be able to create debug crashes ]:D + //$$ if (mc.debugCrashKeyPressTime > 0) { + //$$ if (Minecraft.getSystemTime() - mc.debugCrashKeyPressTime >= 6000L) { + //$$ throw newReportedException(new CrashReport("Manually triggered debug crash", new Throwable())); + //$$ } + //$$ + //$$ if (!Keyboard.isKeyDown(Keyboard.KEY_F3) || !Keyboard.isKeyDown(Keyboard.KEY_C)) { + //$$ mc.debugCrashKeyPressTime = -1; + //$$ } + //$$ } else if (Keyboard.isKeyDown(Keyboard.KEY_F3) && Keyboard.isKeyDown(Keyboard.KEY_C)) { + //$$ mc.debugCrashKeyPressTime = Minecraft.getSystemTime(); + //$$ } + //$$ + //$$ // Twitch, screenshot, fullscreen, etc. (stuff that works everywhere) + //$$ if (!MinecraftForge.EVENT_BUS.post(new ReplayDispatchKeypressesEvent.Pre())) { + //$$ mc.dispatchKeypresses(); + //$$ } + //$$ + //$$ if (pressed) { + //$$ // This might be subject to change as vanilla shaders are still kinda unused in 1.8 + //$$ if (key == Keyboard.KEY_F4 && mc.entityRenderer != null) { //#if MC>=10800 - mc.entityRenderer.switchUseShader(); + //$$ mc.entityRenderer.switchUseShader(); //#else //$$ mc.entityRenderer.activateNextShader(); //#endif - } - - if (mc.currentScreen != null) { + //$$ } + //$$ + //$$ if (mc.currentScreen != null) { //#if MC>=10800 - try { - mc.currentScreen.handleKeyboardInput(); - } catch (IOException e) { // AND WHO THOUGHT THIS WAS A GREAT IDEA? - e.printStackTrace(); - } + //$$ try { + //$$ mc.currentScreen.handleKeyboardInput(); + //$$ } catch (IOException e) { // AND WHO THOUGHT THIS WAS A GREAT IDEA? + //$$ e.printStackTrace(); + //$$ } //#else //$$ mc.currentScreen.handleKeyboardInput(); //#endif - } else { - if (key == Keyboard.KEY_ESCAPE) { - mc.displayInGameMenu(); - } - - // Following are a ton of vanilla keyboard shortcuts, some are removed as they're useless in the - // replay viewer as of now - // TODO Update maybe add new key bindings - // TODO: Translate magic values to Keyboard.KEY_ constants - - if (key == 32 && Keyboard.isKeyDown(61) && mc.ingameGUI != null) { + //$$ } else { + //$$ if (key == Keyboard.KEY_ESCAPE) { + //$$ mc.displayInGameMenu(); + //$$ } + //$$ + //$$ // Following are a ton of vanilla keyboard shortcuts, some are removed as they're useless in the + //$$ // replay viewer as of now + //$$ // TODO Update maybe add new key bindings + //$$ // TODO: Translate magic values to Keyboard.KEY_ constants + //$$ + //$$ if (key == 32 && Keyboard.isKeyDown(61) && mc.ingameGUI != null) { //#if MC>=11100 - mc.ingameGUI.getChatGUI().clearChatMessages(false); + //$$ mc.ingameGUI.getChatGUI().clearChatMessages(false); //#else //$$ mc.ingameGUI.getChatGUI().clearChatMessages(); //#endif - } - - if (key == 31 && Keyboard.isKeyDown(61)) { - mc.refreshResources(); - } - - if (key == 20 && Keyboard.isKeyDown(61)) { - mc.refreshResources(); - } - - if (key == 33 && Keyboard.isKeyDown(61)) { - boolean flag1 = Keyboard.isKeyDown(42) | Keyboard.isKeyDown(54); - mc.gameSettings.setOptionValue(GameSettings.Options.RENDER_DISTANCE, flag1 ? -1 : 1); - } - - if (key == 30 && Keyboard.isKeyDown(61)) { - mc.renderGlobal.loadRenderers(); - } - - if (key == 48 && Keyboard.isKeyDown(61)) { + //$$ } + //$$ + //$$ if (key == 31 && Keyboard.isKeyDown(61)) { + //$$ mc.refreshResources(); + //$$ } + //$$ + //$$ if (key == 20 && Keyboard.isKeyDown(61)) { + //$$ mc.refreshResources(); + //$$ } + //$$ + //$$ if (key == 33 && Keyboard.isKeyDown(61)) { + //$$ boolean flag1 = Keyboard.isKeyDown(42) | Keyboard.isKeyDown(54); + //$$ mc.gameSettings.setOptionValue(GameSettings.Options.RENDER_DISTANCE, flag1 ? -1 : 1); + //$$ } + //$$ + //$$ if (key == 30 && Keyboard.isKeyDown(61)) { + //$$ mc.renderGlobal.loadRenderers(); + //$$ } + //$$ + //$$ if (key == 48 && Keyboard.isKeyDown(61)) { //#if MC>=10800 - mc.getRenderManager().setDebugBoundingBox(!mc.getRenderManager().isDebugBoundingBox()); + //$$ mc.getRenderManager().setDebugBoundingBox(!mc.getRenderManager().isDebugBoundingBox()); //#else //$$ RenderManager.debugBoundingBox = !RenderManager.debugBoundingBox; //#endif - } - - if (key == 25 && Keyboard.isKeyDown(61)) { - mc.gameSettings.pauseOnLostFocus = !mc.gameSettings.pauseOnLostFocus; - mc.gameSettings.saveOptions(); - } - - if (key == 59) { - mc.gameSettings.hideGUI = !mc.gameSettings.hideGUI; - } - - if (key == 61) { - mc.gameSettings.showDebugInfo = !mc.gameSettings.showDebugInfo; - mc.gameSettings.showDebugProfilerChart = GuiScreen.isShiftKeyDown(); - } - - if (mc.gameSettings.keyBindTogglePerspective.isPressed()) { - mc.gameSettings.thirdPersonView = (mc.gameSettings.thirdPersonView + 1) % 3; - + //$$ } + //$$ + //$$ if (key == 25 && Keyboard.isKeyDown(61)) { + //$$ mc.gameSettings.pauseOnLostFocus = !mc.gameSettings.pauseOnLostFocus; + //$$ mc.gameSettings.saveOptions(); + //$$ } + //$$ + //$$ if (key == 59) { + //$$ mc.gameSettings.hideGUI = !mc.gameSettings.hideGUI; + //$$ } + //$$ + //$$ if (key == 61) { + //$$ mc.gameSettings.showDebugInfo = !mc.gameSettings.showDebugInfo; + //$$ mc.gameSettings.showDebugProfilerChart = GuiScreen.isShiftKeyDown(); + //$$ } + //$$ + //$$ if (mc.gameSettings.keyBindTogglePerspective.isPressed()) { + //$$ mc.gameSettings.thirdPersonView = (mc.gameSettings.thirdPersonView + 1) % 3; + //$$ //#if MC>=10800 - if (mc.entityRenderer != null) { // Extra check, not in vanilla code - if (mc.gameSettings.thirdPersonView == 0) { - mc.entityRenderer.loadEntityShader(mc.getRenderViewEntity()); - } else if (mc.gameSettings.thirdPersonView == 1) { - mc.entityRenderer.loadEntityShader(null); - } - } + //$$ if (mc.entityRenderer != null) { // Extra check, not in vanilla code + //$$ if (mc.gameSettings.thirdPersonView == 0) { + //$$ mc.entityRenderer.loadEntityShader(mc.getRenderViewEntity()); + //$$ } else if (mc.gameSettings.thirdPersonView == 1) { + //$$ mc.entityRenderer.loadEntityShader(null); + //$$ } + //$$ } //#endif - } - } - - // Navigation in the debug chart - if (mc.gameSettings.showDebugInfo && mc.gameSettings.showDebugProfilerChart) { - if (key == Keyboard.KEY_0) { - mc.updateDebugProfilerName(0); - } - - for (int i = 0; i < 9; ++i) { - if (key == 2 + i) { - mc.updateDebugProfilerName(i + 1); - } - } - } - } - - FMLCommonHandler.instance().fireKeyInput(); - } - */ + //$$ } + //$$ } + //$$ + //$$ // Navigation in the debug chart + //$$ if (mc.gameSettings.showDebugInfo && mc.gameSettings.showDebugProfilerChart) { + //$$ if (key == Keyboard.KEY_0) { + //$$ mc.updateDebugProfilerName(0); + //$$ } + //$$ + //$$ for (int i = 0; i < 9; ++i) { + //$$ if (key == 2 + i) { + //$$ mc.updateDebugProfilerName(i + 1); + //$$ } + //$$ } + //$$ } + //$$ } + //$$ + //$$ FMLCommonHandler.instance().fireKeyInput(); + //$$ } + //#endif //#if MC<=10710 //$$ public static class RunScheduledTasks extends Event {} diff --git a/src/main/java/com/replaymod/replay/QuickReplaySender.java b/src/main/java/com/replaymod/replay/QuickReplaySender.java index f5bf7543..7f2087d4 100644 --- a/src/main/java/com/replaymod/replay/QuickReplaySender.java +++ b/src/main/java/com/replaymod/replay/QuickReplaySender.java @@ -1,6 +1,7 @@ //#if MC>=10904 package com.replaymod.replay; +import com.github.steveice10.mc.auth.data.GameProfile; import com.github.steveice10.mc.protocol.data.game.PlayerListEntry; import com.github.steveice10.mc.protocol.data.game.PlayerListEntryAction; import com.github.steveice10.mc.protocol.data.game.chunk.BlockStorage; @@ -28,6 +29,7 @@ import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerMultiB import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerNotifyClientPacket; import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUnloadChunkPacket; import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdateTimePacket; +import com.github.steveice10.mc.protocol.packet.login.server.LoginSuccessPacket; import com.github.steveice10.mc.protocol.util.NetUtil; import com.github.steveice10.packetlib.io.NetInput; import com.github.steveice10.packetlib.io.NetOutput; @@ -209,6 +211,7 @@ public class QuickReplaySender extends ChannelHandlerAdapter implements ReplaySe public void restart() { activeThings.clear(); currentTimeStamp = 0; + ctx.fireChannelRead(toMC(new LoginSuccessPacket(new GameProfile(UUID.nameUUIDFromBytes(new byte[0]), "Player")), EnumConnectionState.LOGIN)); ctx.fireChannelRead(toMC(new ServerRespawnPacket(0, Difficulty.NORMAL, GameMode.SPECTATOR, WorldType.DEFAULT))); ctx.fireChannelRead(toMC(new ServerPlayerPositionRotationPacket(0, 0, 0, 0, 0, 0))); } @@ -624,6 +627,10 @@ public class QuickReplaySender extends ChannelHandlerAdapter implements ReplaySe private static final Deflater deflater = new Deflater(); private static Packet toMC(com.github.steveice10.packetlib.packet.Packet packet) { + return toMC(packet, EnumConnectionState.PLAY); + } + + private static Packet toMC(com.github.steveice10.packetlib.packet.Packet packet, EnumConnectionState state) { // We need to re-encode MCProtocolLib packets, so we can then decode them as NMS packets // 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. @@ -642,7 +649,7 @@ public class QuickReplaySender extends ChannelHandlerAdapter implements ReplaySe //#else //$$ packetBuf.readVarIntFromBuffer(); //#endif - Packet mcPacket = EnumConnectionState.PLAY.getPacket(EnumPacketDirection.CLIENTBOUND, packetId); + Packet mcPacket = state.getPacket(EnumPacketDirection.CLIENTBOUND, packetId); mcPacket.readPacketData(packetBuf); return mcPacket; } catch (Exception e) { diff --git a/src/main/java/com/replaymod/replay/ReplayHandler.java b/src/main/java/com/replaymod/replay/ReplayHandler.java index 1ac42f97..5abef2d5 100755 --- a/src/main/java/com/replaymod/replay/ReplayHandler.java +++ b/src/main/java/com/replaymod/replay/ReplayHandler.java @@ -49,7 +49,6 @@ import net.minecraft.entity.EntityLivingBase; //#if MC>=10800 import net.minecraft.network.EnumPacketDirection; //#if MC>=11300 -import net.minecraft.client.network.NetHandlerLoginClient; import net.minecraftforge.fml.network.NetworkHooks; //#else //$$ import com.mojang.authlib.GameProfile; @@ -57,6 +56,7 @@ import net.minecraftforge.fml.network.NetworkHooks; //$$ import net.minecraftforge.fml.client.FMLClientHandler; //$$ import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher; //#endif +import net.minecraft.client.network.NetHandlerLoginClient; import static net.minecraft.client.renderer.GlStateManager.*; //#else @@ -236,32 +236,25 @@ public class ReplayHandler { networkManager.setNetHandler(new NetHandlerLoginClient(networkManager, mc, null, it -> {})); NetworkHooks.registerClientLoginChannel(networkManager); + // FIXME make this work (with vanilla and mods) on all other versions again, now that login phase is included + // probably have to change some of the forge handshake calls //#else - //$$ NetHandlerPlayClient netHandlerPlayClient = - //$$ new NetHandlerPlayClient(mc, null, networkManager, new GameProfile(UUID.randomUUID(), "Player")); - //$$ networkManager.setNetHandler(netHandlerPlayClient); - //$$ FMLClientHandler.instance().setPlayClient(netHandlerPlayClient); + //$$ NetHandlerLoginClient netHandlerLoginClient = + //$$ new NetHandlerLoginClient(networkManager, mc, null); + //$$ networkManager.setNetHandler(netHandlerLoginClient); //$$ //#if MC>=11200 //$$ channel = new EmbeddedChannel(); - //$$ NetworkDispatcher networkDispatcher = new NetworkDispatcher(networkManager); - //$$ channel.attr(NetworkDispatcher.FML_DISPATCHER).set(networkDispatcher); - //$$ //$$ channel.pipeline().addFirst("ReplayModReplay_replaySender", fullReplaySender); //$$ channel.pipeline().addFirst("ReplayModReplay_quickReplaySender", quickReplaySender); //$$ channel.pipeline().addLast("packet_handler", networkManager); //$$ channel.pipeline().fireChannelActive(); - //$$ networkDispatcher.clientToServerHandshake(); //#else //$$ channel = new EmbeddedChannel(networkManager); - //$$ NetworkDispatcher networkDispatcher = new NetworkDispatcher(networkManager); - //$$ channel.attr(NetworkDispatcher.FML_DISPATCHER).set(networkDispatcher); - //$$ //$$ channel.pipeline().addFirst("ReplayModReplay_replaySender", fullReplaySender); //#if MC>=10904 //$$ channel.pipeline().addFirst("ReplayModReplay_quickReplaySender", quickReplaySender); //#endif - //$$ channel.pipeline().addAfter("ReplayModReplay_replaySender", "fml:packet_handler", networkDispatcher); //$$ channel.pipeline().fireChannelActive(); //#endif //#endif @@ -295,13 +288,6 @@ public class ReplayHandler { //$$ channel.pipeline().addFirst("ReplayModReplay_replaySender", fullReplaySender); //$$ channel.pipeline().addAfter("ReplayModReplay_replaySender", "packet_handler", networkManager); //$$ channel.pipeline().fireChannelActive(); - //$$ - //$$ // Call twice to force-overwrite the NetworkManager's internal state - //$$ networkManager.setConnectionState(EnumConnectionState.PLAY); - //$$ networkManager.getNetHandler().onConnectionStateTransition(EnumConnectionState.LOGIN, EnumConnectionState.PLAY); - //$$ networkManager.setConnectionState(EnumConnectionState.PLAY); - //$$ - //$$ FMLNetworkHandler.fmlClientHandshake(networkManager); //#endif } diff --git a/src/main/java/com/replaymod/replay/ReplayModReplay.java b/src/main/java/com/replaymod/replay/ReplayModReplay.java index 07e57031..077b8f20 100644 --- a/src/main/java/com/replaymod/replay/ReplayModReplay.java +++ b/src/main/java/com/replaymod/replay/ReplayModReplay.java @@ -172,7 +172,7 @@ public class ReplayModReplay implements Module { }); Minecraft mc = core.getMinecraft(); - // FIXME mc.timer = new InputReplayTimer(mc.timer, this); + mc.timer = new InputReplayTimer(mc.timer, this); new GuiHandler(this).register(); } diff --git a/src/main/java/com/replaymod/replay/gui/screen/GuiReplayViewer.java b/src/main/java/com/replaymod/replay/gui/screen/GuiReplayViewer.java index 378750c3..c24b4607 100755 --- a/src/main/java/com/replaymod/replay/gui/screen/GuiReplayViewer.java +++ b/src/main/java/com/replaymod/replay/gui/screen/GuiReplayViewer.java @@ -399,7 +399,7 @@ public class GuiReplayViewer extends GuiScreen { } else { server.setText(metaData.getServerName()); } - incompatible = !new ReplayStudio().isCompatible(metaData.getFileFormatVersion()); + incompatible = !new ReplayStudio().isCompatible(metaData.getFileFormatVersion(), metaData.getProtocolVersion()); if (incompatible) { version.setText("Minecraft " + metaData.getMcVersion()); } diff --git a/src/main/java/com/replaymod/replay/handler/GuiHandler.java b/src/main/java/com/replaymod/replay/handler/GuiHandler.java index b8875240..4dbbb260 100644 --- a/src/main/java/com/replaymod/replay/handler/GuiHandler.java +++ b/src/main/java/com/replaymod/replay/handler/GuiHandler.java @@ -29,6 +29,9 @@ import static com.replaymod.core.versions.MCVer.*; import static com.replaymod.replay.ReplayModReplay.LOGGER; public class GuiHandler { + //#if MC>=11300 + private static final int BUTTON_OPTIONS = 0; + //#endif private static final int BUTTON_EXIT_SERVER = 1; private static final int BUTTON_ADVANCEMENTS = 5; private static final int BUTTON_STATS = 6; @@ -86,16 +89,24 @@ public class GuiHandler { case BUTTON_OPEN_TO_LAN: removeButton(event, openToLan = b); break; + //#if MC>=11300 + case BUTTON_OPTIONS: + b.width = 200; + break; + //#endif } } if (achievements != null && stats != null) { moveAllButtonsDirectlyBelowUpwards(buttonList, y(achievements), x(achievements), x(stats) + stats.width); } - if (openToLan != null) { - moveAllButtonsDirectlyBelowUpwards(buttonList, y(openToLan), - x(openToLan), x(openToLan) + openToLan.width); - } + // In 1.13+ Forge, the Options button shares one row with the Open to LAN button + //#if MC<11300 + //$$ if (openToLan != null) { + //$$ moveAllButtonsDirectlyBelowUpwards(buttonList, y(openToLan), + //$$ x(openToLan), x(openToLan) + openToLan.width); + //$$ } + //#endif } } diff --git a/src/main/java/com/replaymod/replay/mixin/MixinTileEntityEndPortalRenderer.java b/src/main/java/com/replaymod/replay/mixin/MixinTileEntityEndPortalRenderer.java index 92717657..8ff5e3ad 100644 --- a/src/main/java/com/replaymod/replay/mixin/MixinTileEntityEndPortalRenderer.java +++ b/src/main/java/com/replaymod/replay/mixin/MixinTileEntityEndPortalRenderer.java @@ -37,7 +37,7 @@ public class MixinTileEntityEndPortalRenderer { //#endif //#endif //#endif - private static long replayModReplay_getEnchantmentTime() { + private long replayModReplay_getEnchantmentTime() { ReplayHandler replayHandler = ReplayModReplay.instance.getReplayHandler(); if (replayHandler != null) { return replayHandler.getReplaySender().currentTimeStamp(); diff --git a/src/main/resources/META-INF/replaymod_at.cfg b/src/main/resources/META-INF/replaymod_at.cfg index b1d4b8ff..48677d95 100644 --- a/src/main/resources/META-INF/replaymod_at.cfg +++ b/src/main/resources/META-INF/replaymod_at.cfg @@ -1,6 +1,9 @@ # To apply changes in this file run: ./gradlew clean setupDecompWorkspace idea # Minecraft +##if MC>=11300 +public net.minecraft.client.Minecraft func_184117_aA()V # processKeyBinds +##endif ##if MC>=11002 public-f net.minecraft.client.Minecraft field_71428_T # timer ##else @@ -25,6 +28,9 @@ public net.minecraft.client.Minecraft func_147112_ai()V # middleClickMouse public net.minecraft.client.Minecraft func_147115_a(Z)V # sendClickBlockToController # Packets +##if MC>=11300 +public net.minecraft.network.play.server.SPacketJoinGame field_149200_f # maxPlayers +##endif ##if MC>=10904 public net.minecraft.network.play.server.SPacketSpawnMob field_149043_l # dataManager public net.minecraft.network.play.server.SPacketSpawnPlayer field_148960_i # watcher diff --git a/src/main/resources/mixins.recording.replaymod.json b/src/main/resources/mixins.recording.replaymod.json index a7429f91..d6278d85 100644 --- a/src/main/resources/mixins.recording.replaymod.json +++ b/src/main/resources/mixins.recording.replaymod.json @@ -4,6 +4,10 @@ "mixins": [], "server": [], "client": [ + //#if MC>=11300 + "MixinKeyboardListener", + "MixinMouseHelper", + //#endif //#if MC>=10904 "MixinPlayerControllerMP", "MixinWorldClient", @@ -14,7 +18,9 @@ //#endif "MixinNetHandlerLoginClient", "MixinNetHandlerPlayClient", - "MixinNetworkDispatcher", + //#if MC<11300 + //$$ "MixinNetworkDispatcher", + //#endif "MixinRenderGlobal" ], "compatibilityLevel": "JAVA_8", diff --git a/versions/common.gradle b/versions/common.gradle index 29feb7b8..bf8f86c7 100644 --- a/versions/common.gradle +++ b/versions/common.gradle @@ -184,7 +184,7 @@ dependencies { def studioVersion = mcVersionStr if (studioVersion == '1.8.9') studioVersion = '1.8' - shade("com.replaymod.replaystudio:$studioVersion:98ab667"){ // FIXME + shade("com.replaymod.replaystudio:$studioVersion:9e362ef"){ // FIXME exclude group: 'com.google.guava', module: 'guava' // provided by MC exclude group: 'org.projectlombok', module: 'lombok' // runtime only for @SneakyThrows which isn't used }