Get recording and replay working
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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<ITextComponent> 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
|
||||
@@ -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
|
||||
@@ -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"))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user