From 1fef12d2bd4ddcba79fecfbb3fa52e3c4a742fea Mon Sep 17 00:00:00 2001 From: johni0702 Date: Sat, 3 Dec 2016 17:25:57 +0100 Subject: [PATCH] Include FML handshake in recording --- .../recording/ReplayModRecording.java | 8 ++++++ .../handler/ConnectionEventHandler.java | 23 ++++++---------- .../mixin/MixinNetHandlerLoginClient.java | 27 +++++++++++++++++++ .../mixin/MixinNetworkDispatcher.java | 27 +++++++++++++++++++ .../resources/mixins.recording.replaymod.json | 2 ++ 5 files changed, 72 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/replaymod/recording/mixin/MixinNetHandlerLoginClient.java create mode 100644 src/main/java/com/replaymod/recording/mixin/MixinNetworkDispatcher.java diff --git a/src/main/java/com/replaymod/recording/ReplayModRecording.java b/src/main/java/com/replaymod/recording/ReplayModRecording.java index 093a7441..e686724a 100644 --- a/src/main/java/com/replaymod/recording/ReplayModRecording.java +++ b/src/main/java/com/replaymod/recording/ReplayModRecording.java @@ -5,6 +5,7 @@ import com.replaymod.core.utils.Restrictions; import com.replaymod.recording.handler.ConnectionEventHandler; import com.replaymod.recording.packet.PacketListener; import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraft.network.NetworkManager; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; @@ -17,6 +18,9 @@ import org.lwjgl.input.Keyboard; public class ReplayModRecording { public static final String MOD_ID = "replaymod-recording"; + @Mod.Instance(MOD_ID) + public static ReplayModRecording instance; + @Mod.Instance(ReplayMod.MOD_ID) private static ReplayMod core; @@ -49,4 +53,8 @@ public class ReplayModRecording { NetworkRegistry.INSTANCE.newSimpleChannel(Restrictions.PLUGIN_CHANNEL); } + + public void initiateRecording(NetworkManager networkManager) { + connectionEventHandler.onConnectedToServerEvent(networkManager); + } } diff --git a/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java b/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java index ad9d7b46..e63d1d13 100755 --- a/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java +++ b/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java @@ -9,14 +9,10 @@ import com.replaymod.replaystudio.replay.ReplayFile; import com.replaymod.replaystudio.replay.ReplayMetaData; import com.replaymod.replaystudio.replay.ZipReplayFile; import com.replaymod.replaystudio.studio.ReplayStudio; -import io.netty.channel.Channel; -import io.netty.channel.ChannelPipeline; import net.minecraft.client.Minecraft; import net.minecraft.network.NetworkManager; -import net.minecraft.server.MinecraftServer; import net.minecraft.world.WorldType; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientConnectedToServerEvent; import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientDisconnectionFromServerEvent; import org.apache.logging.log4j.Logger; @@ -46,11 +42,11 @@ public class ConnectionEventHandler { this.core = core; } - @SubscribeEvent - public void onConnectedToServerEvent(ClientConnectedToServerEvent event) { + public void onConnectedToServerEvent(NetworkManager networkManager) { try { - if(event.isLocal) { - if (MinecraftServer.getServer().getEntityWorld().getWorldType() == WorldType.DEBUG_WORLD) { + boolean local = networkManager.isLocalChannel(); + if (local) { + if (mc.getIntegratedServer().getEntityWorld().getWorldType() == WorldType.DEBUG_WORLD) { logger.info("Debug World recording is not supported."); return; } @@ -65,18 +61,15 @@ public class ConnectionEventHandler { } } - NetworkManager nm = event.manager; String worldName; - if(event.isLocal) { - worldName = MinecraftServer.getServer().getWorldName(); + if (local) { + worldName = mc.getIntegratedServer().getWorldName(); } else if (Minecraft.getMinecraft().getCurrentServerData() != null) { worldName = Minecraft.getMinecraft().getCurrentServerData().serverIP; } else { logger.info("Recording not started as the world is neither local nor remote (probably a replay)."); return; } - Channel channel = nm.channel(); - ChannelPipeline pipeline = channel.pipeline(); File folder = core.getReplayFolder(); @@ -87,13 +80,13 @@ public class ConnectionEventHandler { replayFile.writeModInfo(ModCompat.getInstalledNetworkMods()); ReplayMetaData metaData = new ReplayMetaData(); - metaData.setSingleplayer(event.isLocal); + metaData.setSingleplayer(local); metaData.setServerName(worldName); metaData.setGenerator("ReplayMod v" + ReplayMod.getContainer().getVersion()); metaData.setDate(System.currentTimeMillis()); metaData.setMcVersion(ReplayMod.getMinecraftVersion()); packetListener = new PacketListener(replayFile, metaData); - pipeline.addBefore(packetHandlerKey, "replay_recorder", packetListener); + networkManager.channel().pipeline().addBefore(packetHandlerKey, "replay_recorder", packetListener); recordingEventHandler = new RecordingEventHandler(packetListener); recordingEventHandler.register(); diff --git a/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerLoginClient.java b/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerLoginClient.java new file mode 100644 index 00000000..5cbe64bc --- /dev/null +++ b/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerLoginClient.java @@ -0,0 +1,27 @@ +package com.replaymod.recording.mixin; + +import com.replaymod.recording.ReplayModRecording; +import net.minecraft.client.network.NetHandlerLoginClient; +import net.minecraft.network.NetworkManager; +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; + +@Mixin(NetHandlerLoginClient.class) +public abstract class MixinNetHandlerLoginClient { + + @Shadow + private NetworkManager networkManager; + + /** + * Starts the recording right before switching into PLAY state. + * We cannot use the {@link net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientConnectedToServerEvent} + * as it only fires after the forge handshake. + */ + @Inject(method = "handleLoginSuccess", at=@At("HEAD")) + public void replayModRecording_initiateRecording(CallbackInfo cb) { + ReplayModRecording.instance.initiateRecording(networkManager); + } +} diff --git a/src/main/java/com/replaymod/recording/mixin/MixinNetworkDispatcher.java b/src/main/java/com/replaymod/recording/mixin/MixinNetworkDispatcher.java new file mode 100644 index 00000000..9ef0b6da --- /dev/null +++ b/src/main/java/com/replaymod/recording/mixin/MixinNetworkDispatcher.java @@ -0,0 +1,27 @@ +package com.replaymod.recording.mixin; + +import io.netty.channel.embedded.EmbeddedChannel; +import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher; +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; + +@Mixin(value = NetworkDispatcher.class, remap = false) +public abstract class MixinNetworkDispatcher { + + @Shadow + private EmbeddedChannel handshakeChannel; + + /** + * Always sets fml:isLocal to false. + * This effectively removes the difference in the FML handshake between SP and MP + * and forces the block/item ids, etc. to always be send. + * This might have undesired side effects but at least it works at all. + */ + @Inject(method = "insertIntoChannel", at=@At("HEAD")) + public void replayModRecording_forceIsLocalToFalse(CallbackInfo cb) { + handshakeChannel.attr(NetworkDispatcher.IS_LOCAL).set(false); + } +} diff --git a/src/main/resources/mixins.recording.replaymod.json b/src/main/resources/mixins.recording.replaymod.json index 272114ff..26e2126d 100644 --- a/src/main/resources/mixins.recording.replaymod.json +++ b/src/main/resources/mixins.recording.replaymod.json @@ -4,7 +4,9 @@ "mixins": [], "server": [], "client": [ + "MixinNetHandlerLoginClient", "MixinNetHandlerPlayClient", + "MixinNetworkDispatcher", "MixinRenderGlobal" ], "refmap": "mixins.replaymod.refmap.json"