Get recording and replay working

This commit is contained in:
Jonas Herzig
2019-03-10 12:53:03 +01:00
parent 8705bbad9a
commit f8fc3462e8
22 changed files with 538 additions and 331 deletions

View File

@@ -25,7 +25,8 @@ import org.apache.commons.io.FileUtils;
//#if MC>=11300 //#if MC>=11300
import com.replaymod.core.versions.LangResourcePack; import com.replaymod.core.versions.LangResourcePack;
import net.minecraft.resources.FolderPack; 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.DeferredWorkQueue;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
@@ -87,6 +88,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Queue; import java.util.Queue;
import java.util.concurrent.FutureTask; 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 static { // Note: even preInit is too late and we'd have to issue another resource reload
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
//#if MC>=11300 //#if MC>=11300
List<IResourcePack> defaultResourcePacks = new ArrayList<>(); // FIXME: probably replaced with DownloadingPackFinder
FolderPack jGuiResourcePack = new FolderPack(new File("../jGui/src/main/resources")) { FolderPack jGuiResourcePack = new FolderPack(new File("../jGui/src/main/resources")) {
@Override @Override
protected InputStream getInputStream(String resourceName) throws IOException { 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 <T extends ResourcePackInfo> void addPackInfosToMap(Map<String, T> map, ResourcePackInfo.IFactory<T> factory) {
map.put("jgui", ResourcePackInfo.func_195793_a("jgui", true, () -> jGuiResourcePack, factory, ResourcePackInfo.Priority.BOTTOM));
}
});
//#else
//$$ defaultResourcePacks.add(jGuiResourcePack);
//#endif
//#if MC<=10710 //#if MC<=10710
//$$ FolderResourcePack mainResourcePack = new FolderResourcePack(new File("../src/main/resources")) { //$$ FolderResourcePack mainResourcePack = new FolderResourcePack(new File("../src/main/resources")) {
//$$ @Override //$$ @Override

View File

@@ -3,6 +3,7 @@ package com.replaymod.core.utils;
import net.minecraft.network.PacketBuffer; import net.minecraft.network.PacketBuffer;
//#if MC>=10904 //#if MC>=10904
import net.minecraft.network.play.server.SPacketCustomPayload; import net.minecraft.network.play.server.SPacketCustomPayload;
import net.minecraft.util.ResourceLocation;
//#else //#else
//$$ import net.minecraft.network.play.server.S3FPacketCustomPayload; //$$ import net.minecraft.network.play.server.S3FPacketCustomPayload;
//#endif //#endif
@@ -18,8 +19,11 @@ import static com.replaymod.core.versions.MCVer.readString;
* @see <a href="https://gist.github.com/Johni0702/2547c463e51f65f312cb">Replay Restrictions Gist</a> * @see <a href="https://gist.github.com/Johni0702/2547c463e51f65f312cb">Replay Restrictions Gist</a>
*/ */
public class Restrictions { public class Restrictions {
// FIXME these should be ResourceLocations now //#if MC>=11300
public static final String PLUGIN_CHANNEL = "Replay|Restrict"; 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 noXray;
private boolean noNoclip; private boolean noNoclip;
private boolean onlyFirstPerson; private boolean onlyFirstPerson;

View File

@@ -1,23 +1,20 @@
package com.replaymod.extras.advancedscreenshots; package com.replaymod.extras.advancedscreenshots;
import com.replaymod.core.ReplayMod; import com.replaymod.core.ReplayMod;
import com.replaymod.core.versions.MCVer;
import com.replaymod.extras.Extra; 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; import net.minecraftforge.common.MinecraftForge;
//#if MC>=11300 //#if MC<11300
import com.replaymod.core.versions.MCVer.Keyboard; //$$ import com.replaymod.core.versions.MCVer;
import net.minecraftforge.client.event.GuiScreenEvent; //$$ import com.replaymod.replay.events.ReplayDispatchKeypressesEvent;
//#else //$$ import net.minecraft.client.Minecraft;
//$$ import net.minecraft.client.gui.GuiControls;
//$$ import net.minecraftforge.client.event.GuiScreenEvent;
//$$ import org.lwjgl.input.Keyboard; //$$ import org.lwjgl.input.Keyboard;
//#endif //#endif
//#if MC>=10800 //#if MC>=10800
//#if MC>=11300 //#if MC>=11300
import net.minecraftforge.eventbus.api.SubscribeEvent;
//#else //#else
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; //$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#endif //#endif
@@ -29,30 +26,36 @@ public class AdvancedScreenshots implements Extra {
private ReplayMod mod; private ReplayMod mod;
private final Minecraft mc = MCVer.getMinecraft();
@Override @Override
public void register(ReplayMod mod) throws Exception { public void register(ReplayMod mod) {
this.mod = mod; this.mod = mod;
MinecraftForge.EVENT_BUS.register(this); MinecraftForge.EVENT_BUS.register(this);
} }
@SubscribeEvent //#if MC>=11300
public void onDispatchKeypresses(ReplayDispatchKeypressesEvent.Pre event) { private static AdvancedScreenshots instance; { instance = this; }
if (mc.currentScreen instanceof GuiControls) return; public static void take() {
//#if MC>=11300 if (instance != null) {
// FIXME instance.takeScreenshot();
//#else }
//$$ if (!Keyboard.getEventKeyState()) return; }
//$$ if (Keyboard.isRepeatEvent()) return; //#else
//$$ int keyCode = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() : Keyboard.getEventKey(); //$$ @SubscribeEvent
//$$ if (keyCode == 0 || keyCode != mc.gameSettings.keyBindScreenshot.getKeyCode()) return; //$$ public void onDispatchKeypresses(ReplayDispatchKeypressesEvent.Pre event) {
//#endif //$$ 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(() -> { private void takeScreenshot() {
new GuiCreateScreenshot(mod).display(); ReplayMod.instance.runLater(() -> new GuiCreateScreenshot(mod).display());
});
event.setCanceled(true);
} }
} }

View File

@@ -83,6 +83,12 @@ public class RecordingEventHandler {
} }
} }
//#if MC>=11300
public void onPacket(Packet<?> packet) {
packetListener.save(packet);
}
//#endif
public void onPlayerJoin() { public void onPlayerJoin() {
try { try {
//#if MC>=10904 //#if MC>=10904

View File

@@ -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

View File

@@ -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

View File

@@ -9,11 +9,17 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 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 //#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 //#else
//$$ import cpw.mods.fml.common.network.FMLNetworkEvent; //$$ import cpw.mods.fml.common.network.FMLNetworkEvent;
//#endif //#endif
//#endif
@Mixin(NetHandlerLoginClient.class) @Mixin(NetHandlerLoginClient.class)
public abstract class MixinNetHandlerLoginClient { public abstract class MixinNetHandlerLoginClient {
@@ -27,6 +33,16 @@ public abstract class MixinNetHandlerLoginClient {
//#if MC>=11300 //#if MC>=11300
@Inject(method = "func_209521_a", at=@At("HEAD")) @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 //#else
//$$ /** //$$ /**
//$$ * Starts the recording right before switching into PLAY state. //$$ * 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. //$$ * as it only fires after the forge handshake.
//$$ */ //$$ */
//$$ @Inject(method = "handleLoginSuccess", at=@At("HEAD")) //$$ @Inject(method = "handleLoginSuccess", at=@At("HEAD"))
//#endif //$$ public void replayModRecording_initiateRecording(CallbackInfo cb) {
public void replayModRecording_initiateRecording(CallbackInfo cb) {
//#if MC>=10800 //#if MC>=10800
ReplayModRecording.instance.initiateRecording(networkManager); //$$ ReplayModRecording.instance.initiateRecording(networkManager);
//#else //#else
//$$ ReplayModRecording.instance.initiateRecording(field_147393_d); //$$ ReplayModRecording.instance.initiateRecording(field_147393_d);
//#endif //#endif
} //$$ }
//#endif
//#if MC>=11200 //#if MC>=11200
@Inject(method = "handleLoginSuccess", at=@At("RETURN")) @Inject(method = "handleLoginSuccess", at=@At("RETURN"))

View File

@@ -1,5 +1,6 @@
package com.replaymod.recording.mixin; package com.replaymod.recording.mixin;
import com.replaymod.core.versions.MCVer;
import com.replaymod.recording.handler.RecordingEventHandler; import com.replaymod.recording.handler.RecordingEventHandler;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.network.NetHandlerPlayClient; import net.minecraft.client.network.NetHandlerPlayClient;
@@ -13,7 +14,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
//#if MC>=10800 //#if MC>=10800
//#if MC>=10904 //#if MC>=10904
import net.minecraft.network.play.server.SPacketPlayerListItem.Action; 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 //#else
//$$ import net.minecraft.network.play.server.S38PacketPlayerListItem.Action; //$$ import net.minecraft.network.play.server.S38PacketPlayerListItem.Action;
//$$ import net.minecraft.network.play.server.S38PacketPlayerListItem.AddPlayerData; //$$ import net.minecraft.network.play.server.S38PacketPlayerListItem.AddPlayerData;
@@ -30,8 +31,7 @@ import static com.replaymod.core.versions.MCVer.*;
@Mixin(NetHandlerPlayClient.class) @Mixin(NetHandlerPlayClient.class)
public abstract class MixinNetHandlerPlayClient { public abstract class MixinNetHandlerPlayClient {
@Shadow private static Minecraft gameController = MCVer.getMinecraft();
private Minecraft gameController;
//#if MC>=10800 //#if MC>=10800
@Shadow @Shadow
@@ -61,7 +61,6 @@ public abstract class MixinNetHandlerPlayClient {
RecordingEventHandler handler = getRecordingEventHandler(); RecordingEventHandler handler = getRecordingEventHandler();
if (handler != null && packet.getAction() == Action.ADD_PLAYER) { if (handler != null && packet.getAction() == Action.ADD_PLAYER) {
/* FIXME see import
for (AddPlayerData data : packet.getEntries()) { for (AddPlayerData data : packet.getEntries()) {
if (data.getProfile() == null || data.getProfile().getId() == null) continue; 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 // 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(); handler.onPlayerJoin();
} }
} }
*/
} }
} }
//#else //#else

View File

@@ -1,78 +1,77 @@
/* FIXME //#if MC<11300
package com.replaymod.recording.mixin; //$$ package com.replaymod.recording.mixin;
//$$
import com.replaymod.recording.handler.FMLHandshakeFilter; //$$ import com.replaymod.recording.handler.FMLHandshakeFilter;
import io.netty.channel.ChannelPipeline; //$$ import io.netty.channel.ChannelPipeline;
import io.netty.channel.embedded.EmbeddedChannel; //$$ import io.netty.channel.embedded.EmbeddedChannel;
import org.spongepowered.asm.mixin.Mixin; //$$ import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; //$$ import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At; //$$ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; //$$ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; //$$ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
//$$
//#if MC>=11200 //#if MC>=11200
import io.netty.channel.ChannelConfig; //$$ import io.netty.channel.ChannelConfig;
import net.minecraft.network.EnumConnectionState; //$$ import net.minecraft.network.EnumConnectionState;
import net.minecraft.network.NetworkManager; //$$ import net.minecraft.network.NetworkManager;
import org.spongepowered.asm.mixin.injection.Redirect; //$$ import org.spongepowered.asm.mixin.injection.Redirect;
//#endif //#endif
//$$
//#if MC>=10800 //#if MC>=10800
import net.minecraftforge.fml.common.network.handshake.FMLHandshakeCodec; //$$ import net.minecraftforge.fml.common.network.handshake.FMLHandshakeCodec;
import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher; //$$ import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher;
import net.minecraftforge.fml.relauncher.Side; //$$ import net.minecraftforge.fml.relauncher.Side;
//#else //#else
//$$ import cpw.mods.fml.common.network.handshake.FMLHandshakeCodec; //$$ import cpw.mods.fml.common.network.handshake.FMLHandshakeCodec;
//$$ import cpw.mods.fml.common.network.handshake.NetworkDispatcher; //$$ import cpw.mods.fml.common.network.handshake.NetworkDispatcher;
//$$ import cpw.mods.fml.relauncher.Side; //$$ import cpw.mods.fml.relauncher.Side;
//#endif //#endif
//$$
@Mixin(value = NetworkDispatcher.class, remap = false) //$$ @Mixin(value = NetworkDispatcher.class, remap = false)
public abstract class MixinNetworkDispatcher { //$$ public abstract class MixinNetworkDispatcher {
//$$
@Shadow //$$ @Shadow
private Side side; //$$ private Side side;
//$$
@Shadow //$$ @Shadow
private EmbeddedChannel handshakeChannel; //$$ private EmbeddedChannel handshakeChannel;
//$$
/** //$$ /**
* Always sets fml:isLocal to false on the server side. //$$ * Always sets fml:isLocal to false on the server side.
* This effectively removes the difference in the FML handshake between SP and MP //$$ * This effectively removes the difference in the FML handshake between SP and MP
* and forces the block/item ids, etc. to always be send. //$$ * and forces the block/item ids, etc. to always be send.
* Injects a {@link FMLHandshakeFilter} on the client side to filter out //$$ * Injects a {@link FMLHandshakeFilter} on the client side to filter out
* those extra, unexpected packets. //$$ * those extra, unexpected packets.
*/ //$$ */
/* //$$ @Inject(method = "insertIntoChannel", at=@At("HEAD"))
@Inject(method = "insertIntoChannel", at=@At("HEAD")) //$$ public void replayModRecording_setupForLocalRecording(CallbackInfo cb) {
public void replayModRecording_setupForLocalRecording(CallbackInfo cb) { //$$ // If we're in multiplayer, everything is fine as is
// If we're in multiplayer, everything is fine as is //$$ if (!handshakeChannel.attr(NetworkDispatcher.IS_LOCAL).get()) return;
if (!handshakeChannel.attr(NetworkDispatcher.IS_LOCAL).get()) return; //$$
//$$ if (side == Side.SERVER) {
if (side == Side.SERVER) { //$$ // On the server side, force all packets to be sent
// On the server side, force all packets to be sent //$$ handshakeChannel.attr(NetworkDispatcher.IS_LOCAL).set(false);
handshakeChannel.attr(NetworkDispatcher.IS_LOCAL).set(false); //$$ } else {
} else { //$$ // On the client side, discard additional packets
// On the client side, discard additional packets //$$ ChannelPipeline pipeline = handshakeChannel.pipeline();
ChannelPipeline pipeline = handshakeChannel.pipeline(); //$$ pipeline.addAfter(pipeline.context(FMLHandshakeCodec.class).name(),
pipeline.addAfter(pipeline.context(FMLHandshakeCodec.class).name(), //$$ "replaymod_filter", new FMLHandshakeFilter());
"replaymod_filter", new FMLHandshakeFilter()); //$$ }
} //$$ }
} //$$
//#if MC>=11200 //#if MC>=11200
@Redirect(method = "clientListenForServerHandshake", at = @At(value = "INVOKE", remap = true, target = //$$ @Redirect(method = "clientListenForServerHandshake", at = @At(value = "INVOKE", remap = true, target =
"Lnet/minecraft/network/NetworkManager;setConnectionState(Lnet/minecraft/network/EnumConnectionState;)V")) //$$ "Lnet/minecraft/network/NetworkManager;setConnectionState(Lnet/minecraft/network/EnumConnectionState;)V"))
public void replayModRecording_raceConditionWorkAround1(NetworkManager self, EnumConnectionState ignored) { } //$$ public void replayModRecording_raceConditionWorkAround1(NetworkManager self, EnumConnectionState ignored) { }
//$$
@Redirect(method = "insertIntoChannel", at = @At(value = "INVOKE", target = //$$ @Redirect(method = "insertIntoChannel", at = @At(value = "INVOKE", target =
"Lio/netty/channel/ChannelConfig;setAutoRead(Z)Lio/netty/channel/ChannelConfig;")) //$$ "Lio/netty/channel/ChannelConfig;setAutoRead(Z)Lio/netty/channel/ChannelConfig;"))
public ChannelConfig replayModRecording_raceConditionWorkAround2(ChannelConfig self, boolean autoRead) { //$$ public ChannelConfig replayModRecording_raceConditionWorkAround2(ChannelConfig self, boolean autoRead) {
if (side == Side.CLIENT) { //$$ if (side == Side.CLIENT) {
autoRead = false; //$$ autoRead = false;
} //$$ }
return self.setAutoRead(autoRead); //$$ return self.setAutoRead(autoRead);
} //$$ }
//#endif //#endif
} //$$ }
*/ //#endif

View File

@@ -7,6 +7,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
//#if MC>=11300 //#if MC>=11300
import net.minecraft.client.renderer.WorldRenderer;
//#else //#else
//$$ import net.minecraft.client.renderer.RenderGlobal; //$$ import net.minecraft.client.renderer.RenderGlobal;
//#endif //#endif
@@ -19,8 +20,11 @@ import net.minecraft.util.math.BlockPos;
//#endif //#endif
//#endif //#endif
/* FIXME runtimeinvisparameter //#if MC>=11300
@Mixin(RenderGlobal.class) @Mixin(WorldRenderer.class)
//#else
//$$ @Mixin(RenderGlobal.class)
//#endif
public abstract class MixinRenderGlobal implements RecordingEventHandler.RecordingEventSender { public abstract class MixinRenderGlobal implements RecordingEventHandler.RecordingEventSender {
private RecordingEventHandler recordingEventHandler; private RecordingEventHandler recordingEventHandler;
@@ -58,4 +62,3 @@ public abstract class MixinRenderGlobal implements RecordingEventHandler.Recordi
} }
} }
} }
*/

View File

@@ -17,6 +17,10 @@ import net.minecraft.network.play.server.*;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
//#if MC>=11300
import net.minecraft.network.login.server.SPacketLoginSuccess;
//#endif
//#if MC>=10904 //#if MC>=10904
import net.minecraft.network.datasync.EntityDataManager; import net.minecraft.network.datasync.EntityDataManager;
import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextComponentString;
@@ -67,6 +71,11 @@ public class PacketListener extends ChannelInboundHandlerAdapter {
private long lastSentPacket; private long lastSentPacket;
private long timePassedWhilePaused; private long timePassedWhilePaused;
private volatile boolean serverWasPaused; 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 * 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); throw new RuntimeException(e);
} }
}); });
//#if MC>=11300
if (packet instanceof SPacketLoginSuccess) {
connectionState = EnumConnectionState.PLAY;
}
//#endif
} catch(Exception e) { } catch(Exception e) {
logger.error("Writing packet:", e); logger.error("Writing packet:", e);
} }
@@ -339,9 +354,9 @@ public class PacketListener extends ChannelInboundHandlerAdapter {
//#endif //#endif
//#if MC>=10800 //#if MC>=10800
Integer packetId = EnumConnectionState.PLAY.getPacketId(EnumPacketDirection.CLIENTBOUND, packet); Integer packetId = connectionState.getPacketId(EnumPacketDirection.CLIENTBOUND, packet);
//#else //#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 //#endif
if (packetId == null) { if (packetId == null) {
throw new IOException("Unknown packet type:" + packet.getClass()); throw new IOException("Unknown packet type:" + packet.getClass());

View File

@@ -48,8 +48,10 @@ import net.minecraft.world.GameType;
//$$ import net.minecraft.world.WorldSettings.GameType; //$$ import net.minecraft.world.WorldSettings.GameType;
//#endif //#endif
//#if MC>=10904 //#if MC>=10904
import net.minecraft.network.login.server.SPacketLoginSuccess;
import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.ITextComponent;
//#else //#else
//$$ import net.minecraft.network.login.server.S02PacketLoginSuccess;
//$$ import net.minecraft.util.IChatComponent; //$$ import net.minecraft.util.IChatComponent;
//#endif //#endif
@@ -123,6 +125,9 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
private static int TP_DISTANCE_LIMIT = 128; 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. * The replay handler responsible for the current replay.
*/ */
@@ -165,12 +170,22 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
*/ */
protected ReplayInputStream replayIn; protected ReplayInputStream replayIn;
/**
* @see PacketData#PacketData(ReplayInputStream, ReplayOutputStream)
*/
private ReplayOutputStream encoder;
/** /**
* The next packet that should be sent. * 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. * This is required as some actions such as jumping to a specified timestamp have to peek at the next packet.
*/ */
protected PacketData nextPacket; 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 * 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) { if (world(mc) != null) {
for (EntityPlayer playerEntity : playerEntities(world(mc))) { for (EntityPlayer playerEntity : playerEntities(world(mc))) {
if (!playerEntity.addedToChunk && playerEntity instanceof EntityOtherPlayerMP) { 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); int i = readVarInt(pb);
EnumConnectionState state = loginPhase ? EnumConnectionState.LOGIN : EnumConnectionState.PLAY;
//#if MC>=10800 //#if MC>=10800
Packet p = EnumConnectionState.PLAY.getPacket(EnumPacketDirection.CLIENTBOUND, i); Packet p = state.getPacket(EnumPacketDirection.CLIENTBOUND, i);
//#else //#else
//$$ Packet p = Packet.generatePacket(EnumConnectionState.PLAY.func_150755_b(), i); //$$ Packet p = Packet.generatePacket(state.func_150755_b(), i);
//#endif //#endif
p.readPacketData(pb); 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 * @return The processed packet or {@code null} if no packet shall be sent
*/ */
protected Packet processPacket(Packet p) throws Exception { 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 MC>=10904
if (p instanceof SPacketCustomPayload) { if (p instanceof SPacketCustomPayload) {
SPacketCustomPayload packet = (SPacketCustomPayload) p; SPacketCustomPayload packet = (SPacketCustomPayload) p;
@@ -584,7 +613,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
//#endif //#endif
EnumDifficulty difficulty = packet.getDifficulty(); EnumDifficulty difficulty = packet.getDifficulty();
//#if MC>=11300 //#if MC>=11300
int maxPlayers = 0;// FIXME needs AT packet.maxPlayers; int maxPlayers = packet.maxPlayers;
//#else //#else
//$$ int maxPlayers = packet.getMaxPlayers(); //$$ int maxPlayers = packet.getMaxPlayers();
//#endif //#endif
@@ -832,7 +861,8 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
while (!terminate) { while (!terminate) {
synchronized (FullReplaySender.this) { synchronized (FullReplaySender.this) {
if (replayIn == null) { if (replayIn == null) {
replayIn = replayFile.getPacketData(); replayIn = replayFile.getPacketData(new ReplayStudio(), true);
encoder = new ReplayOutputStream(new ReplayStudio(), byteBufOut, true);
} }
// Packet loop // Packet loop
while (true) { while (true) {
@@ -859,7 +889,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
// Read the next packet if we don't already have one // Read the next packet if we don't already have one
if (nextPacket == null) { if (nextPacket == null) {
nextPacket = new PacketData(replayIn); nextPacket = new PacketData(replayIn, encoder);
} }
int nextTimeStamp = nextPacket.timestamp; int nextTimeStamp = nextPacket.timestamp;
@@ -912,6 +942,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
// Restart the replay. // Restart the replay.
hasWorldLoaded = false; hasWorldLoaded = false;
lastTimeStamp = 0; lastTimeStamp = 0;
loginPhase = true;
startFromBeginning = false; startFromBeginning = false;
nextPacket = null; nextPacket = null;
lastPacketSent = System.currentTimeMillis(); lastPacketSent = System.currentTimeMillis();
@@ -1025,13 +1056,15 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
replayIn.close(); replayIn.close();
replayIn = null; replayIn = null;
} }
loginPhase = true;
startFromBeginning = false; startFromBeginning = false;
nextPacket = null; nextPacket = null;
replayHandler.restartedReplay(); replayHandler.restartedReplay();
} }
if (replayIn == null) { if (replayIn == null) {
replayIn = replayFile.getPacketData(); replayIn = replayFile.getPacketData(new ReplayStudio(), true);
encoder = new ReplayOutputStream(new ReplayStudio(), byteBufOut, true);
} }
while (true) { // Send packets while (true) { // Send packets
@@ -1043,7 +1076,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
nextPacket = null; nextPacket = null;
} else { } else {
// Otherwise read one from the input stream // Otherwise read one from the input stream
pd = new PacketData(replayIn); pd = new PacketData(replayIn, encoder);
} }
int nextTimeStamp = pd.timestamp; int nextTimeStamp = pd.timestamp;
@@ -1176,19 +1209,16 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
} }
private static final class PacketData { 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 int timestamp;
private final byte[] bytes; private final byte[] bytes;
public PacketData(ReplayInputStream in) throws IOException { PacketData(ReplayInputStream in, ReplayOutputStream encoder) throws IOException {
com.replaymod.replaystudio.PacketData data = in.readPacket(); com.replaymod.replaystudio.PacketData data = in.readPacket();
timestamp = (int) data.getTime(); timestamp = (int) data.getTime();
// We need to re-encode MCProtocolLib packets, so we can later decode them as NMS packets // 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 // The main reason we aren't reading them as NMS packets is that we want ReplayStudio to be able
// to apply ViaVersion (and potentially other magic) to it. // to apply ViaVersion (and potentially other magic) to it.
synchronized (encoder) { synchronized (byteBuf) {
byteBuf.markReaderIndex(); // Mark the current reader and writer index (should be at start) byteBuf.markReaderIndex(); // Mark the current reader and writer index (should be at start)
byteBuf.markWriterIndex(); byteBuf.markWriterIndex();

View File

@@ -3,18 +3,19 @@ package com.replaymod.replay;
import com.replaymod.core.utils.WrappedTimer; import com.replaymod.core.utils.WrappedTimer;
import com.replaymod.replay.camera.CameraController; import com.replaymod.replay.camera.CameraController;
import com.replaymod.replay.camera.CameraEntity; import com.replaymod.replay.camera.CameraEntity;
import com.replaymod.replay.events.ReplayDispatchKeypressesEvent;
import net.minecraft.client.Minecraft; 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.minecraft.util.Timer;
import net.minecraftforge.client.ForgeHooksClient;
import net.minecraftforge.common.MinecraftForge;
//#if MC>=11300 //#if MC>=11300
import org.lwjgl.glfw.GLFW;
//#else //#else
//$$ import com.replaymod.replay.events.ReplayDispatchKeypressesEvent;
//$$ import net.minecraft.client.gui.GuiScreen;
//$$ import net.minecraft.client.settings.GameSettings; //$$ 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.Keyboard;
//$$ import org.lwjgl.input.Mouse; //$$ import org.lwjgl.input.Mouse;
//#if MC>=10800 //#if MC>=10800
@@ -28,6 +29,7 @@ import net.minecraftforge.common.MinecraftForge;
//$$ //$$
//$$ import static com.replaymod.core.versions.MCVer.FML_BUS; //$$ import static com.replaymod.core.versions.MCVer.FML_BUS;
//#endif //#endif
//$$ import static com.replaymod.core.versions.MCVer.newReportedException;
//#endif //#endif
public class InputReplayTimer extends WrappedTimer { public class InputReplayTimer extends WrappedTimer {
@@ -40,10 +42,14 @@ public class InputReplayTimer extends WrappedTimer {
this.mc = mod.getCore().getMinecraft(); this.mc = mod.getCore().getMinecraft();
} }
/* FIXME
@Override @Override
public void updateTimer() { //#if MC>=11300
super.updateTimer(); 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 // 1.7.10: We have to run the scheduled executables (ours only) because MC would only run them every tick
//#if MC<=10710 //#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 // 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) // tick speed may vary or there may not be any ticks at all (when the replay is paused)
if (mod.getReplayHandler() != null) { if (mod.getReplayHandler() != null) {
//#if MC>=11300
if (mc.currentScreen == null || mc.currentScreen.allowUserInput) { if (mc.currentScreen == null || mc.currentScreen.allowUserInput) {
while (Mouse.next()) { GLFW.glfwPollEvents();
handleMouseEvent(); mc.processKeyBinds();
} }
mc.keyboardListener.tick();
while (Keyboard.next()) { //#else
handleKeyEvent(); //$$ if (mc.currentScreen == null || mc.currentScreen.allowUserInput) {
} //$$ while (Mouse.next()) {
} else { //$$ handleMouseEvent();
//$$ }
//$$
//$$ while (Keyboard.next()) {
//$$ handleKeyEvent();
//$$ }
//$$ } else {
//#if MC<11300
//#if MC>=10800 //#if MC>=10800
try { //$$ try {
mc.currentScreen.handleInput(); //$$ mc.currentScreen.handleInput();
} catch (IOException e) { // *SIGH* //$$ } catch (IOException e) { // *SIGH*
e.printStackTrace(); //$$ e.printStackTrace();
} //$$ }
//#else //#else
//$$ mc.currentScreen.handleInput(); //$$ mc.currentScreen.handleInput();
//#endif //#endif
} //#endif
//$$ }
//#endif
} }
} }
protected void handleMouseEvent() { public static void handleScroll(int wheel) {
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();
if (wheel != 0) { if (wheel != 0) {
ReplayHandler replayHandler = mod.getReplayHandler(); ReplayHandler replayHandler = ReplayModReplay.instance.getReplayHandler();
if (replayHandler != null) { if (replayHandler != null) {
CameraEntity cameraEntity = replayHandler.getCameraEntity(); CameraEntity cameraEntity = replayHandler.getCameraEntity();
if (cameraEntity != null) { if (cameraEntity != null) {
@@ -105,164 +109,181 @@ public class InputReplayTimer extends WrappedTimer {
} }
} }
} }
}
if (mc.currentScreen == null) { //#if MC<11300
if (!mc.inGameHasFocus && Mouse.getEventButtonState()) { //$$ protected void handleMouseEvent() {
// Regrab mouse if the user clicks into the window //$$ if (ForgeHooksClient.postMouseEvent()) return;
mc.setIngameFocus(); //$$
} //$$ int button = Mouse.getEventButton() - 100;
} else { //$$ 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 //#if MC>=10800
try { //$$ try {
mc.currentScreen.handleMouseInput(); //$$ mc.currentScreen.handleMouseInput();
} catch (IOException e) { // WHO IS RESPONSIBLE FOR THIS MESS?!? //$$ } catch (IOException e) { // WHO IS RESPONSIBLE FOR THIS MESS?!?
e.printStackTrace(); //$$ e.printStackTrace();
} //$$ }
//#else //#else
//$$ mc.currentScreen.handleMouseInput(); //$$ mc.currentScreen.handleMouseInput();
//#endif //#endif
} //$$ }
//$$
FMLCommonHandler.instance().fireMouseInput(); //$$ FMLCommonHandler.instance().fireMouseInput();
} //$$ }
//$$
protected void handleKeyEvent() { //$$ protected void handleKeyEvent() {
// TODO 1.7.10: This might be missing some 1.7.10-only key bindings or implement some of them incorrectly //$$ // 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(); //$$ int key = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() + 256 : Keyboard.getEventKey();
boolean pressed = Keyboard.getEventKeyState(); //$$ boolean pressed = Keyboard.getEventKeyState();
//$$
KeyBinding.setKeyBindState(key, pressed); //$$ KeyBinding.setKeyBindState(key, pressed);
if (pressed) { //$$ if (pressed) {
KeyBinding.onTick(key); //$$ KeyBinding.onTick(key);
} //$$ }
//$$
// Still want to be able to create debug crashes ]:D //$$ // Still want to be able to create debug crashes ]:D
if (mc.debugCrashKeyPressTime > 0) { //$$ if (mc.debugCrashKeyPressTime > 0) {
if (Minecraft.getSystemTime() - mc.debugCrashKeyPressTime >= 6000L) { //$$ if (Minecraft.getSystemTime() - mc.debugCrashKeyPressTime >= 6000L) {
throw new ReportedException(new CrashReport("Manually triggered debug crash", new Throwable())); //$$ throw newReportedException(new CrashReport("Manually triggered debug crash", new Throwable()));
} //$$ }
//$$
if (!Keyboard.isKeyDown(Keyboard.KEY_F3) || !Keyboard.isKeyDown(Keyboard.KEY_C)) { //$$ if (!Keyboard.isKeyDown(Keyboard.KEY_F3) || !Keyboard.isKeyDown(Keyboard.KEY_C)) {
mc.debugCrashKeyPressTime = -1; //$$ mc.debugCrashKeyPressTime = -1;
} //$$ }
} else if (Keyboard.isKeyDown(Keyboard.KEY_F3) && Keyboard.isKeyDown(Keyboard.KEY_C)) { //$$ } else if (Keyboard.isKeyDown(Keyboard.KEY_F3) && Keyboard.isKeyDown(Keyboard.KEY_C)) {
mc.debugCrashKeyPressTime = Minecraft.getSystemTime(); //$$ mc.debugCrashKeyPressTime = Minecraft.getSystemTime();
} //$$ }
//$$
// Twitch, screenshot, fullscreen, etc. (stuff that works everywhere) //$$ // Twitch, screenshot, fullscreen, etc. (stuff that works everywhere)
if (!MinecraftForge.EVENT_BUS.post(new ReplayDispatchKeypressesEvent.Pre())) { //$$ if (!MinecraftForge.EVENT_BUS.post(new ReplayDispatchKeypressesEvent.Pre())) {
mc.dispatchKeypresses(); //$$ mc.dispatchKeypresses();
} //$$ }
//$$
if (pressed) { //$$ if (pressed) {
// This might be subject to change as vanilla shaders are still kinda unused in 1.8 //$$ // 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 (key == Keyboard.KEY_F4 && mc.entityRenderer != null) {
//#if MC>=10800 //#if MC>=10800
mc.entityRenderer.switchUseShader(); //$$ mc.entityRenderer.switchUseShader();
//#else //#else
//$$ mc.entityRenderer.activateNextShader(); //$$ mc.entityRenderer.activateNextShader();
//#endif //#endif
} //$$ }
//$$
if (mc.currentScreen != null) { //$$ if (mc.currentScreen != null) {
//#if MC>=10800 //#if MC>=10800
try { //$$ try {
mc.currentScreen.handleKeyboardInput(); //$$ mc.currentScreen.handleKeyboardInput();
} catch (IOException e) { // AND WHO THOUGHT THIS WAS A GREAT IDEA? //$$ } catch (IOException e) { // AND WHO THOUGHT THIS WAS A GREAT IDEA?
e.printStackTrace(); //$$ e.printStackTrace();
} //$$ }
//#else //#else
//$$ mc.currentScreen.handleKeyboardInput(); //$$ mc.currentScreen.handleKeyboardInput();
//#endif //#endif
} else { //$$ } else {
if (key == Keyboard.KEY_ESCAPE) { //$$ if (key == Keyboard.KEY_ESCAPE) {
mc.displayInGameMenu(); //$$ mc.displayInGameMenu();
} //$$ }
//$$
// Following are a ton of vanilla keyboard shortcuts, some are removed as they're useless in the //$$ // Following are a ton of vanilla keyboard shortcuts, some are removed as they're useless in the
// replay viewer as of now //$$ // replay viewer as of now
// TODO Update maybe add new key bindings //$$ // TODO Update maybe add new key bindings
// TODO: Translate magic values to Keyboard.KEY_ constants //$$ // TODO: Translate magic values to Keyboard.KEY_ constants
//$$
if (key == 32 && Keyboard.isKeyDown(61) && mc.ingameGUI != null) { //$$ if (key == 32 && Keyboard.isKeyDown(61) && mc.ingameGUI != null) {
//#if MC>=11100 //#if MC>=11100
mc.ingameGUI.getChatGUI().clearChatMessages(false); //$$ mc.ingameGUI.getChatGUI().clearChatMessages(false);
//#else //#else
//$$ mc.ingameGUI.getChatGUI().clearChatMessages(); //$$ mc.ingameGUI.getChatGUI().clearChatMessages();
//#endif //#endif
} //$$ }
//$$
if (key == 31 && Keyboard.isKeyDown(61)) { //$$ if (key == 31 && Keyboard.isKeyDown(61)) {
mc.refreshResources(); //$$ mc.refreshResources();
} //$$ }
//$$
if (key == 20 && Keyboard.isKeyDown(61)) { //$$ if (key == 20 && Keyboard.isKeyDown(61)) {
mc.refreshResources(); //$$ mc.refreshResources();
} //$$ }
//$$
if (key == 33 && Keyboard.isKeyDown(61)) { //$$ if (key == 33 && Keyboard.isKeyDown(61)) {
boolean flag1 = Keyboard.isKeyDown(42) | Keyboard.isKeyDown(54); //$$ boolean flag1 = Keyboard.isKeyDown(42) | Keyboard.isKeyDown(54);
mc.gameSettings.setOptionValue(GameSettings.Options.RENDER_DISTANCE, flag1 ? -1 : 1); //$$ mc.gameSettings.setOptionValue(GameSettings.Options.RENDER_DISTANCE, flag1 ? -1 : 1);
} //$$ }
//$$
if (key == 30 && Keyboard.isKeyDown(61)) { //$$ if (key == 30 && Keyboard.isKeyDown(61)) {
mc.renderGlobal.loadRenderers(); //$$ mc.renderGlobal.loadRenderers();
} //$$ }
//$$
if (key == 48 && Keyboard.isKeyDown(61)) { //$$ if (key == 48 && Keyboard.isKeyDown(61)) {
//#if MC>=10800 //#if MC>=10800
mc.getRenderManager().setDebugBoundingBox(!mc.getRenderManager().isDebugBoundingBox()); //$$ mc.getRenderManager().setDebugBoundingBox(!mc.getRenderManager().isDebugBoundingBox());
//#else //#else
//$$ RenderManager.debugBoundingBox = !RenderManager.debugBoundingBox; //$$ RenderManager.debugBoundingBox = !RenderManager.debugBoundingBox;
//#endif //#endif
} //$$ }
//$$
if (key == 25 && Keyboard.isKeyDown(61)) { //$$ if (key == 25 && Keyboard.isKeyDown(61)) {
mc.gameSettings.pauseOnLostFocus = !mc.gameSettings.pauseOnLostFocus; //$$ mc.gameSettings.pauseOnLostFocus = !mc.gameSettings.pauseOnLostFocus;
mc.gameSettings.saveOptions(); //$$ mc.gameSettings.saveOptions();
} //$$ }
//$$
if (key == 59) { //$$ if (key == 59) {
mc.gameSettings.hideGUI = !mc.gameSettings.hideGUI; //$$ mc.gameSettings.hideGUI = !mc.gameSettings.hideGUI;
} //$$ }
//$$
if (key == 61) { //$$ if (key == 61) {
mc.gameSettings.showDebugInfo = !mc.gameSettings.showDebugInfo; //$$ mc.gameSettings.showDebugInfo = !mc.gameSettings.showDebugInfo;
mc.gameSettings.showDebugProfilerChart = GuiScreen.isShiftKeyDown(); //$$ mc.gameSettings.showDebugProfilerChart = GuiScreen.isShiftKeyDown();
} //$$ }
//$$
if (mc.gameSettings.keyBindTogglePerspective.isPressed()) { //$$ if (mc.gameSettings.keyBindTogglePerspective.isPressed()) {
mc.gameSettings.thirdPersonView = (mc.gameSettings.thirdPersonView + 1) % 3; //$$ mc.gameSettings.thirdPersonView = (mc.gameSettings.thirdPersonView + 1) % 3;
//$$
//#if MC>=10800 //#if MC>=10800
if (mc.entityRenderer != null) { // Extra check, not in vanilla code //$$ if (mc.entityRenderer != null) { // Extra check, not in vanilla code
if (mc.gameSettings.thirdPersonView == 0) { //$$ if (mc.gameSettings.thirdPersonView == 0) {
mc.entityRenderer.loadEntityShader(mc.getRenderViewEntity()); //$$ mc.entityRenderer.loadEntityShader(mc.getRenderViewEntity());
} else if (mc.gameSettings.thirdPersonView == 1) { //$$ } else if (mc.gameSettings.thirdPersonView == 1) {
mc.entityRenderer.loadEntityShader(null); //$$ mc.entityRenderer.loadEntityShader(null);
} //$$ }
} //$$ }
//#endif //#endif
} //$$ }
} //$$ }
//$$
// Navigation in the debug chart //$$ // Navigation in the debug chart
if (mc.gameSettings.showDebugInfo && mc.gameSettings.showDebugProfilerChart) { //$$ if (mc.gameSettings.showDebugInfo && mc.gameSettings.showDebugProfilerChart) {
if (key == Keyboard.KEY_0) { //$$ if (key == Keyboard.KEY_0) {
mc.updateDebugProfilerName(0); //$$ mc.updateDebugProfilerName(0);
} //$$ }
//$$
for (int i = 0; i < 9; ++i) { //$$ for (int i = 0; i < 9; ++i) {
if (key == 2 + i) { //$$ if (key == 2 + i) {
mc.updateDebugProfilerName(i + 1); //$$ mc.updateDebugProfilerName(i + 1);
} //$$ }
} //$$ }
} //$$ }
} //$$ }
//$$
FMLCommonHandler.instance().fireKeyInput(); //$$ FMLCommonHandler.instance().fireKeyInput();
} //$$ }
*/ //#endif
//#if MC<=10710 //#if MC<=10710
//$$ public static class RunScheduledTasks extends Event {} //$$ public static class RunScheduledTasks extends Event {}

View File

@@ -1,6 +1,7 @@
//#if MC>=10904 //#if MC>=10904
package com.replaymod.replay; 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.PlayerListEntry;
import com.github.steveice10.mc.protocol.data.game.PlayerListEntryAction; import com.github.steveice10.mc.protocol.data.game.PlayerListEntryAction;
import com.github.steveice10.mc.protocol.data.game.chunk.BlockStorage; 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.ServerNotifyClientPacket;
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUnloadChunkPacket; 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.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.mc.protocol.util.NetUtil;
import com.github.steveice10.packetlib.io.NetInput; import com.github.steveice10.packetlib.io.NetInput;
import com.github.steveice10.packetlib.io.NetOutput; import com.github.steveice10.packetlib.io.NetOutput;
@@ -209,6 +211,7 @@ public class QuickReplaySender extends ChannelHandlerAdapter implements ReplaySe
public void restart() { public void restart() {
activeThings.clear(); activeThings.clear();
currentTimeStamp = 0; 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 ServerRespawnPacket(0, Difficulty.NORMAL, GameMode.SPECTATOR, WorldType.DEFAULT)));
ctx.fireChannelRead(toMC(new ServerPlayerPositionRotationPacket(0, 0, 0, 0, 0, 0))); 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 final Deflater deflater = new Deflater();
private static Packet<?> toMC(com.github.steveice10.packetlib.packet.Packet packet) { 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 // 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 // The main reason we aren't reading them as NMS packets is that we want ReplayStudio to be able
// to apply ViaVersion (and potentially other magic) to it. // to apply ViaVersion (and potentially other magic) to it.
@@ -642,7 +649,7 @@ public class QuickReplaySender extends ChannelHandlerAdapter implements ReplaySe
//#else //#else
//$$ packetBuf.readVarIntFromBuffer(); //$$ packetBuf.readVarIntFromBuffer();
//#endif //#endif
Packet<?> mcPacket = EnumConnectionState.PLAY.getPacket(EnumPacketDirection.CLIENTBOUND, packetId); Packet<?> mcPacket = state.getPacket(EnumPacketDirection.CLIENTBOUND, packetId);
mcPacket.readPacketData(packetBuf); mcPacket.readPacketData(packetBuf);
return mcPacket; return mcPacket;
} catch (Exception e) { } catch (Exception e) {

View File

@@ -49,7 +49,6 @@ import net.minecraft.entity.EntityLivingBase;
//#if MC>=10800 //#if MC>=10800
import net.minecraft.network.EnumPacketDirection; import net.minecraft.network.EnumPacketDirection;
//#if MC>=11300 //#if MC>=11300
import net.minecraft.client.network.NetHandlerLoginClient;
import net.minecraftforge.fml.network.NetworkHooks; import net.minecraftforge.fml.network.NetworkHooks;
//#else //#else
//$$ import com.mojang.authlib.GameProfile; //$$ 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.client.FMLClientHandler;
//$$ import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher; //$$ import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher;
//#endif //#endif
import net.minecraft.client.network.NetHandlerLoginClient;
import static net.minecraft.client.renderer.GlStateManager.*; import static net.minecraft.client.renderer.GlStateManager.*;
//#else //#else
@@ -236,32 +236,25 @@ public class ReplayHandler {
networkManager.setNetHandler(new NetHandlerLoginClient(networkManager, mc, null, it -> {})); networkManager.setNetHandler(new NetHandlerLoginClient(networkManager, mc, null, it -> {}));
NetworkHooks.registerClientLoginChannel(networkManager); 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 //#else
//$$ NetHandlerPlayClient netHandlerPlayClient = //$$ NetHandlerLoginClient netHandlerLoginClient =
//$$ new NetHandlerPlayClient(mc, null, networkManager, new GameProfile(UUID.randomUUID(), "Player")); //$$ new NetHandlerLoginClient(networkManager, mc, null);
//$$ networkManager.setNetHandler(netHandlerPlayClient); //$$ networkManager.setNetHandler(netHandlerLoginClient);
//$$ FMLClientHandler.instance().setPlayClient(netHandlerPlayClient);
//$$ //$$
//#if MC>=11200 //#if MC>=11200
//$$ channel = new EmbeddedChannel(); //$$ 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_replaySender", fullReplaySender);
//$$ channel.pipeline().addFirst("ReplayModReplay_quickReplaySender", quickReplaySender); //$$ channel.pipeline().addFirst("ReplayModReplay_quickReplaySender", quickReplaySender);
//$$ channel.pipeline().addLast("packet_handler", networkManager); //$$ channel.pipeline().addLast("packet_handler", networkManager);
//$$ channel.pipeline().fireChannelActive(); //$$ channel.pipeline().fireChannelActive();
//$$ networkDispatcher.clientToServerHandshake();
//#else //#else
//$$ channel = new EmbeddedChannel(networkManager); //$$ channel = new EmbeddedChannel(networkManager);
//$$ NetworkDispatcher networkDispatcher = new NetworkDispatcher(networkManager);
//$$ channel.attr(NetworkDispatcher.FML_DISPATCHER).set(networkDispatcher);
//$$
//$$ channel.pipeline().addFirst("ReplayModReplay_replaySender", fullReplaySender); //$$ channel.pipeline().addFirst("ReplayModReplay_replaySender", fullReplaySender);
//#if MC>=10904 //#if MC>=10904
//$$ channel.pipeline().addFirst("ReplayModReplay_quickReplaySender", quickReplaySender); //$$ channel.pipeline().addFirst("ReplayModReplay_quickReplaySender", quickReplaySender);
//#endif //#endif
//$$ channel.pipeline().addAfter("ReplayModReplay_replaySender", "fml:packet_handler", networkDispatcher);
//$$ channel.pipeline().fireChannelActive(); //$$ channel.pipeline().fireChannelActive();
//#endif //#endif
//#endif //#endif
@@ -295,13 +288,6 @@ public class ReplayHandler {
//$$ channel.pipeline().addFirst("ReplayModReplay_replaySender", fullReplaySender); //$$ channel.pipeline().addFirst("ReplayModReplay_replaySender", fullReplaySender);
//$$ channel.pipeline().addAfter("ReplayModReplay_replaySender", "packet_handler", networkManager); //$$ channel.pipeline().addAfter("ReplayModReplay_replaySender", "packet_handler", networkManager);
//$$ channel.pipeline().fireChannelActive(); //$$ 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 //#endif
} }

View File

@@ -172,7 +172,7 @@ public class ReplayModReplay implements Module {
}); });
Minecraft mc = core.getMinecraft(); Minecraft mc = core.getMinecraft();
// FIXME mc.timer = new InputReplayTimer(mc.timer, this); mc.timer = new InputReplayTimer(mc.timer, this);
new GuiHandler(this).register(); new GuiHandler(this).register();
} }

View File

@@ -399,7 +399,7 @@ public class GuiReplayViewer extends GuiScreen {
} else { } else {
server.setText(metaData.getServerName()); server.setText(metaData.getServerName());
} }
incompatible = !new ReplayStudio().isCompatible(metaData.getFileFormatVersion()); incompatible = !new ReplayStudio().isCompatible(metaData.getFileFormatVersion(), metaData.getProtocolVersion());
if (incompatible) { if (incompatible) {
version.setText("Minecraft " + metaData.getMcVersion()); version.setText("Minecraft " + metaData.getMcVersion());
} }

View File

@@ -29,6 +29,9 @@ import static com.replaymod.core.versions.MCVer.*;
import static com.replaymod.replay.ReplayModReplay.LOGGER; import static com.replaymod.replay.ReplayModReplay.LOGGER;
public class GuiHandler { 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_EXIT_SERVER = 1;
private static final int BUTTON_ADVANCEMENTS = 5; private static final int BUTTON_ADVANCEMENTS = 5;
private static final int BUTTON_STATS = 6; private static final int BUTTON_STATS = 6;
@@ -86,16 +89,24 @@ public class GuiHandler {
case BUTTON_OPEN_TO_LAN: case BUTTON_OPEN_TO_LAN:
removeButton(event, openToLan = b); removeButton(event, openToLan = b);
break; break;
//#if MC>=11300
case BUTTON_OPTIONS:
b.width = 200;
break;
//#endif
} }
} }
if (achievements != null && stats != null) { if (achievements != null && stats != null) {
moveAllButtonsDirectlyBelowUpwards(buttonList, y(achievements), moveAllButtonsDirectlyBelowUpwards(buttonList, y(achievements),
x(achievements), x(stats) + stats.width); x(achievements), x(stats) + stats.width);
} }
if (openToLan != null) { // In 1.13+ Forge, the Options button shares one row with the Open to LAN button
moveAllButtonsDirectlyBelowUpwards(buttonList, y(openToLan), //#if MC<11300
x(openToLan), x(openToLan) + openToLan.width); //$$ if (openToLan != null) {
} //$$ moveAllButtonsDirectlyBelowUpwards(buttonList, y(openToLan),
//$$ x(openToLan), x(openToLan) + openToLan.width);
//$$ }
//#endif
} }
} }

View File

@@ -37,7 +37,7 @@ public class MixinTileEntityEndPortalRenderer {
//#endif //#endif
//#endif //#endif
//#endif //#endif
private static long replayModReplay_getEnchantmentTime() { private long replayModReplay_getEnchantmentTime() {
ReplayHandler replayHandler = ReplayModReplay.instance.getReplayHandler(); ReplayHandler replayHandler = ReplayModReplay.instance.getReplayHandler();
if (replayHandler != null) { if (replayHandler != null) {
return replayHandler.getReplaySender().currentTimeStamp(); return replayHandler.getReplaySender().currentTimeStamp();

View File

@@ -1,6 +1,9 @@
# To apply changes in this file run: ./gradlew clean setupDecompWorkspace idea # To apply changes in this file run: ./gradlew clean setupDecompWorkspace idea
# Minecraft # Minecraft
##if MC>=11300
public net.minecraft.client.Minecraft func_184117_aA()V # processKeyBinds
##endif
##if MC>=11002 ##if MC>=11002
public-f net.minecraft.client.Minecraft field_71428_T # timer public-f net.minecraft.client.Minecraft field_71428_T # timer
##else ##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 public net.minecraft.client.Minecraft func_147115_a(Z)V # sendClickBlockToController
# Packets # Packets
##if MC>=11300
public net.minecraft.network.play.server.SPacketJoinGame field_149200_f # maxPlayers
##endif
##if MC>=10904 ##if MC>=10904
public net.minecraft.network.play.server.SPacketSpawnMob field_149043_l # dataManager public net.minecraft.network.play.server.SPacketSpawnMob field_149043_l # dataManager
public net.minecraft.network.play.server.SPacketSpawnPlayer field_148960_i # watcher public net.minecraft.network.play.server.SPacketSpawnPlayer field_148960_i # watcher

View File

@@ -4,6 +4,10 @@
"mixins": [], "mixins": [],
"server": [], "server": [],
"client": [ "client": [
//#if MC>=11300
"MixinKeyboardListener",
"MixinMouseHelper",
//#endif
//#if MC>=10904 //#if MC>=10904
"MixinPlayerControllerMP", "MixinPlayerControllerMP",
"MixinWorldClient", "MixinWorldClient",
@@ -14,7 +18,9 @@
//#endif //#endif
"MixinNetHandlerLoginClient", "MixinNetHandlerLoginClient",
"MixinNetHandlerPlayClient", "MixinNetHandlerPlayClient",
"MixinNetworkDispatcher", //#if MC<11300
//$$ "MixinNetworkDispatcher",
//#endif
"MixinRenderGlobal" "MixinRenderGlobal"
], ],
"compatibilityLevel": "JAVA_8", "compatibilityLevel": "JAVA_8",

View File

@@ -184,7 +184,7 @@ dependencies {
def studioVersion = mcVersionStr def studioVersion = mcVersionStr
if (studioVersion == '1.8.9') studioVersion = '1.8' 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: 'com.google.guava', module: 'guava' // provided by MC
exclude group: 'org.projectlombok', module: 'lombok' // runtime only for @SneakyThrows which isn't used exclude group: 'org.projectlombok', module: 'lombok' // runtime only for @SneakyThrows which isn't used
} }