From 6a7147b4015023d447cdb5ac3b793be0c7146ae3 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Wed, 23 Aug 2017 20:23:04 +0200 Subject: [PATCH 01/23] Use ReplayInputStream to support loading older replays on newer MC --- ReplayStudio | 2 +- .../com/replaymod/replay/ReplaySender.java | 61 +++++++++++++------ 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/ReplayStudio b/ReplayStudio index 44109f11..f627aac8 160000 --- a/ReplayStudio +++ b/ReplayStudio @@ -1 +1 @@ -Subproject commit 44109f11b157e29615489e83ee5df742b4fb4305 +Subproject commit f627aac83067799d18715fe8db8e9836c4fb2045 diff --git a/src/main/java/com/replaymod/replay/ReplaySender.java b/src/main/java/com/replaymod/replay/ReplaySender.java index fc41cf77..87b285a2 100755 --- a/src/main/java/com/replaymod/replay/ReplaySender.java +++ b/src/main/java/com/replaymod/replay/ReplaySender.java @@ -5,8 +5,12 @@ import com.google.common.io.Files; import com.google.common.util.concurrent.ListenableFutureTask; import com.replaymod.core.utils.Restrictions; import com.replaymod.replay.camera.CameraEntity; +import com.replaymod.replaystudio.io.ReplayInputStream; +import com.replaymod.replaystudio.io.ReplayOutputStream; import com.replaymod.replaystudio.replay.ReplayFile; +import com.replaymod.replaystudio.studio.ReplayStudio; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufOutputStream; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; @@ -103,10 +107,10 @@ public class ReplaySender extends ChannelInboundHandlerAdapter { protected ChannelHandlerContext ctx; /** - * The data input stream from which new packets are read. + * The replay input stream from which new packets are read. * When accessing this stream make sure to synchronize on {@code this} as it's used from multiple threads. */ - protected DataInputStream dis; + protected ReplayInputStream replayIn; /** * The next packet that should be sent. @@ -546,8 +550,8 @@ public class ReplaySender extends ChannelInboundHandlerAdapter { REPLAY_LOOP: while (!terminate) { synchronized (ReplaySender.this) { - if (dis == null) { - dis = new DataInputStream(replayFile.getPacketData()); + if (replayIn == null) { + replayIn = replayFile.getPacketData(); } // Packet loop while (true) { @@ -574,7 +578,7 @@ public class ReplaySender extends ChannelInboundHandlerAdapter { // Read the next packet if we don't already have one if (nextPacket == null) { - nextPacket = new PacketData(dis); + nextPacket = new PacketData(replayIn); } int nextTimeStamp = nextPacket.timestamp; @@ -631,9 +635,9 @@ public class ReplaySender extends ChannelInboundHandlerAdapter { nextPacket = null; lastPacketSent = System.currentTimeMillis(); replayHandler.restartedReplay(); - if (dis != null) { - dis.close(); - dis = null; + if (replayIn != null) { + replayIn.close(); + replayIn = null; } } } @@ -722,17 +726,17 @@ public class ReplaySender extends ChannelInboundHandlerAdapter { if (timestamp < lastTimeStamp) { // Restart the replay if we need to go backwards in time hasWorldLoaded = false; lastTimeStamp = 0; - if (dis != null) { - dis.close(); - dis = null; + if (replayIn != null) { + replayIn.close(); + replayIn = null; } startFromBeginning = false; nextPacket = null; replayHandler.restartedReplay(); } - if (dis == null) { - dis = new DataInputStream(replayFile.getPacketData()); + if (replayIn == null) { + replayIn = replayFile.getPacketData(); } while (true) { // Send packets @@ -744,7 +748,7 @@ public class ReplaySender extends ChannelInboundHandlerAdapter { nextPacket = null; } else { // Otherwise read one from the input stream - pd = new PacketData(dis); + pd = new PacketData(replayIn); } int nextTimeStamp = pd.timestamp; @@ -759,7 +763,7 @@ public class ReplaySender extends ChannelInboundHandlerAdapter { } catch (EOFException eof) { // Shit! We hit the end before finishing our job! What shall we do now? // well, let's just pretend we're done... - dis = null; + replayIn = null; break; } catch (IOException e) { e.printStackTrace(); @@ -842,13 +846,32 @@ public class ReplaySender extends ChannelInboundHandlerAdapter { } 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(DataInputStream in) throws IOException { - timestamp = in.readInt(); - bytes = new byte[in.readInt()]; - in.readFully(bytes); + public PacketData(ReplayInputStream in) 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) { + byteBuf.markReaderIndex(); // Mark the current reader and writer index (should be at start) + byteBuf.markWriterIndex(); + + encoder.write(data); // Re-encode packet, data will end up in byteBuf + encoder.flush(); + + byteBuf.skipBytes(8); // Skip packet length & timestamp + bytes = new byte[byteBuf.readableBytes()]; // Create bytes array of sufficient size + byteBuf.readBytes(bytes); // Read all data into bytes + + byteBuf.resetReaderIndex(); // Reset reader & writer index for next use + byteBuf.resetWriterIndex(); + } } } } From 9671ee605d80d7bf1f1d9e4a8f6e07a6e5d262cb Mon Sep 17 00:00:00 2001 From: CrushedPixel Date: Wed, 27 Sep 2017 00:16:39 +0200 Subject: [PATCH 02/23] =?UTF-8?q?Add=20360=C2=B0=20screenshot=20feature=20?= =?UTF-8?q?when=20pressing=20Ctrl=20+=20Screenshot=20Keybind?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/replaymod/extras/ReplayModExtras.java | 2 + .../AdvancedScreenshots.java | 93 +++++++++++++++++++ .../advancedscreenshots/ScreenshotWriter.java | 56 +++++++++++ .../replaymod/replay/InputReplayTimer.java | 6 +- .../events/ReplayDispatchKeypressesEvent.java | 9 ++ src/main/resources/META-INF/replaymod_at.cfg | 3 + 6 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/replaymod/extras/advancedscreenshots/AdvancedScreenshots.java create mode 100644 src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotWriter.java create mode 100644 src/main/java/com/replaymod/replay/events/ReplayDispatchKeypressesEvent.java diff --git a/src/main/java/com/replaymod/extras/ReplayModExtras.java b/src/main/java/com/replaymod/extras/ReplayModExtras.java index 93ed038a..0e34b7c7 100644 --- a/src/main/java/com/replaymod/extras/ReplayModExtras.java +++ b/src/main/java/com/replaymod/extras/ReplayModExtras.java @@ -1,6 +1,7 @@ package com.replaymod.extras; import com.replaymod.core.ReplayMod; +import com.replaymod.extras.advancedscreenshots.AdvancedScreenshots; import com.replaymod.extras.playeroverview.PlayerOverview; import com.replaymod.extras.urischeme.UriSchemeExtra; import com.replaymod.extras.youtube.YoutubeUpload; @@ -27,6 +28,7 @@ public class ReplayModExtras { public static ReplayModExtras instance; private static final List> builtin = Arrays.asList( + AdvancedScreenshots.class, PlayerOverview.class, UriSchemeExtra.class, YoutubeUpload.class, diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/AdvancedScreenshots.java b/src/main/java/com/replaymod/extras/advancedscreenshots/AdvancedScreenshots.java new file mode 100644 index 00000000..b3dd2ae1 --- /dev/null +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/AdvancedScreenshots.java @@ -0,0 +1,93 @@ +package com.replaymod.extras.advancedscreenshots; + +import com.replaymod.core.ReplayMod; +import com.replaymod.extras.Extra; +import com.replaymod.render.RenderSettings; +import com.replaymod.render.capturer.RenderInfo; +import com.replaymod.render.hooks.ChunkLoadingRenderGlobal; +import com.replaymod.render.rendering.Pipelines; +import com.replaymod.replay.events.ReplayDispatchKeypressesEvent; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiControls; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.util.ScreenShotHelper; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import org.lwjgl.input.Keyboard; +import org.lwjgl.util.Dimension; +import org.lwjgl.util.ReadableDimension; + +import java.io.File; + +public class AdvancedScreenshots implements Extra { + + private final Minecraft mc = Minecraft.getMinecraft(); + + @Override + public void register(ReplayMod mod) throws Exception { + MinecraftForge.EVENT_BUS.register(this); + } + + @SubscribeEvent + public void onDispatchKeypresses(ReplayDispatchKeypressesEvent.Pre event) { + int i = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() : Keyboard.getEventKey(); + + // all the conditions required to trigger a screenshot condensed in a single if statement + if (i != 0 && !Keyboard.isRepeatEvent() + && (!(mc.currentScreen instanceof GuiControls) || ((GuiControls) mc.currentScreen).time <= mc.getSystemTime() - 20L) + && Keyboard.getEventKeyState() + && i == mc.gameSettings.keyBindScreenshot.getKeyCode()) { + + if (GuiScreen.isCtrlKeyDown()) { + ReplayMod.instance.runLater(() -> { + // take 360° screenshot + File screenshotFolder = new File(mc.mcDataDir, "screenshots"); + screenshotFolder.mkdir(); + File screenshotFile = ScreenShotHelper.getTimestampedPNGFileForDirectory(screenshotFolder); + + int width = 8640; + int height = 4320; + + int displayWidthBefore = mc.displayWidth; + int displayHeightBefore = mc.displayHeight; + + ChunkLoadingRenderGlobal clrg = new ChunkLoadingRenderGlobal(mc.renderGlobal); + + Pipelines.newEquirectangularPipeline(new RenderInfo() { + @Override + public ReadableDimension getFrameSize() { + return new Dimension(width, height); + } + + @Override + public int getTotalFrames() { + return 1; + } + + @Override + public float updateForNextFrame() { + return mc.timer.renderPartialTicks; + } + + @Override + public RenderSettings getRenderSettings() { + return new RenderSettings( + null, null, width, height, 0, 0, null, + true, true, true, true, null, + false, RenderSettings.AntiAliasing.NONE, null, null, false + ); + } + }, new ScreenshotWriter(screenshotFile)).run(); + + clrg.uninstall(); + + // the Equirectangular rendering changes mc.displayWidth and mc.displayHeight, + // so we have to reset it to the previous value + mc.resize(displayWidthBefore, displayHeightBefore); + }); + + event.setCanceled(true); + } + } + } +} diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotWriter.java b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotWriter.java new file mode 100644 index 00000000..d487b08b --- /dev/null +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotWriter.java @@ -0,0 +1,56 @@ +package com.replaymod.extras.advancedscreenshots; + +import com.replaymod.core.ReplayMod; +import com.replaymod.core.utils.Utils; +import com.replaymod.extras.ReplayModExtras; +import com.replaymod.render.frame.RGBFrame; +import com.replaymod.render.rendering.FrameConsumer; +import com.replaymod.replay.ReplayModReplay; +import net.minecraft.crash.CrashReport; +import org.lwjgl.util.ReadableDimension; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +public class ScreenshotWriter implements FrameConsumer { + + private final File outputFile; + + public ScreenshotWriter(File outputFile) { + this.outputFile = outputFile; + } + + @Override + public void consume(RGBFrame frame) { + try { + final ReadableDimension frameSize = frame.getSize(); + + BufferedImage img = new BufferedImage(frameSize.getWidth(), frameSize.getHeight(), BufferedImage.TYPE_INT_RGB); + for (int y = 0; y < frameSize.getHeight(); y++) { + for (int x = 0; x < frameSize.getWidth(); x++) { + byte r = frame.getByteBuffer().get(); + byte g = frame.getByteBuffer().get(); + byte b = frame.getByteBuffer().get(); + + int color = ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff); + img.setRGB(x, y, color); + } + } + + ImageIO.write(img, "PNG", outputFile); + } catch (Throwable t) { + CrashReport report = CrashReport.makeCrashReport(t, "Exporting frame"); + + ReplayMod.instance.runLater(() -> Utils.error(ReplayModExtras.LOGGER, + ReplayModReplay.instance.getReplayHandler().getOverlay(), + report, null)); + } + } + + @Override + public void close() throws IOException { + + } +} diff --git a/src/main/java/com/replaymod/replay/InputReplayTimer.java b/src/main/java/com/replaymod/replay/InputReplayTimer.java index da1bd5fb..250ba766 100644 --- a/src/main/java/com/replaymod/replay/InputReplayTimer.java +++ b/src/main/java/com/replaymod/replay/InputReplayTimer.java @@ -3,6 +3,7 @@ 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.GameSettings; @@ -11,6 +12,7 @@ import net.minecraft.crash.CrashReport; import net.minecraft.util.ReportedException; import net.minecraft.util.Timer; import net.minecraftforge.client.ForgeHooksClient; +import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.common.FMLCommonHandler; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; @@ -122,7 +124,9 @@ public class InputReplayTimer extends WrappedTimer { } // Twitch, screenshot, fullscreen, etc. (stuff that works everywhere) - mc.dispatchKeypresses(); + 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 diff --git a/src/main/java/com/replaymod/replay/events/ReplayDispatchKeypressesEvent.java b/src/main/java/com/replaymod/replay/events/ReplayDispatchKeypressesEvent.java new file mode 100644 index 00000000..15b23352 --- /dev/null +++ b/src/main/java/com/replaymod/replay/events/ReplayDispatchKeypressesEvent.java @@ -0,0 +1,9 @@ +package com.replaymod.replay.events; + +import net.minecraftforge.fml.common.eventhandler.Cancelable; +import net.minecraftforge.fml.common.eventhandler.Event; + +@Cancelable +public abstract class ReplayDispatchKeypressesEvent extends Event { + public static class Pre extends ReplayDispatchKeypressesEvent {} +} diff --git a/src/main/resources/META-INF/replaymod_at.cfg b/src/main/resources/META-INF/replaymod_at.cfg index 59d3b95e..08652131 100644 --- a/src/main/resources/META-INF/replaymod_at.cfg +++ b/src/main/resources/META-INF/replaymod_at.cfg @@ -117,5 +117,8 @@ public net.minecraft.client.renderer.GlStateManager$FogState public net.minecraft.client.renderer.GlStateManager$BooleanState public net.minecraft.client.renderer.GlStateManager$BooleanState * +# ScreenShotHelper +public net.minecraft.util.ScreenShotHelper func_74290_a(Ljava/io/File;)Ljava/io/File; # getTimestampedPNGFileForDirectory + # Example # public net.minecraft.package.ClassName func_some_id(Ljava/lang/Class;IZS)V # methodName From d2d7a36139968c9c8889978bc686295b4e96f568 Mon Sep 17 00:00:00 2001 From: CrushedPixel Date: Wed, 27 Sep 2017 13:13:20 +0200 Subject: [PATCH 03/23] Added post-screenshot GUI --- .../com/replaymod/extras/ReplayModExtras.java | 1 + .../java/com/replaymod/extras/Setting.java | 8 ++ .../AdvancedScreenshots.java | 106 ++++++++-------- .../GuiUploadScreenshot.java | 114 ++++++++++++++++++ .../events/ReplayDispatchKeypressesEvent.java | 3 +- 5 files changed, 182 insertions(+), 50 deletions(-) create mode 100644 src/main/java/com/replaymod/extras/Setting.java create mode 100644 src/main/java/com/replaymod/extras/advancedscreenshots/GuiUploadScreenshot.java diff --git a/src/main/java/com/replaymod/extras/ReplayModExtras.java b/src/main/java/com/replaymod/extras/ReplayModExtras.java index 0e34b7c7..463e8805 100644 --- a/src/main/java/com/replaymod/extras/ReplayModExtras.java +++ b/src/main/java/com/replaymod/extras/ReplayModExtras.java @@ -45,6 +45,7 @@ public class ReplayModExtras { @Mod.EventHandler public void preInit(FMLPreInitializationEvent event) { LOGGER = event.getModLog(); + ReplayMod.instance.getSettingsRegistry().register(Setting.class); } @Mod.EventHandler diff --git a/src/main/java/com/replaymod/extras/Setting.java b/src/main/java/com/replaymod/extras/Setting.java new file mode 100644 index 00000000..2f69e4c1 --- /dev/null +++ b/src/main/java/com/replaymod/extras/Setting.java @@ -0,0 +1,8 @@ +package com.replaymod.extras; + +import com.replaymod.core.SettingsRegistry; + +public final class Setting { + public static final SettingsRegistry.SettingKey SKIP_POST_SCREENSHOT_GUI = + new SettingsRegistry.SettingKeys<>("advanced", "skipPostScreenshotGui", null, false); +} diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/AdvancedScreenshots.java b/src/main/java/com/replaymod/extras/advancedscreenshots/AdvancedScreenshots.java index b3dd2ae1..ee55cd2c 100644 --- a/src/main/java/com/replaymod/extras/advancedscreenshots/AdvancedScreenshots.java +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/AdvancedScreenshots.java @@ -6,6 +6,7 @@ import com.replaymod.render.RenderSettings; import com.replaymod.render.capturer.RenderInfo; import com.replaymod.render.hooks.ChunkLoadingRenderGlobal; import com.replaymod.render.rendering.Pipelines; +import com.replaymod.replay.ReplayModReplay; import com.replaymod.replay.events.ReplayDispatchKeypressesEvent; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiControls; @@ -21,73 +22,80 @@ import java.io.File; public class AdvancedScreenshots implements Extra { + private ReplayMod mod; + private final Minecraft mc = Minecraft.getMinecraft(); @Override public void register(ReplayMod mod) throws Exception { + this.mod = mod; MinecraftForge.EVENT_BUS.register(this); } @SubscribeEvent public void onDispatchKeypresses(ReplayDispatchKeypressesEvent.Pre event) { - int i = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() : Keyboard.getEventKey(); + int keyCode = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() : Keyboard.getEventKey(); // all the conditions required to trigger a screenshot condensed in a single if statement - if (i != 0 && !Keyboard.isRepeatEvent() + if (keyCode != 0 && !Keyboard.isRepeatEvent() && (!(mc.currentScreen instanceof GuiControls) || ((GuiControls) mc.currentScreen).time <= mc.getSystemTime() - 20L) && Keyboard.getEventKeyState() - && i == mc.gameSettings.keyBindScreenshot.getKeyCode()) { + && keyCode == mc.gameSettings.keyBindScreenshot.getKeyCode()) { if (GuiScreen.isCtrlKeyDown()) { - ReplayMod.instance.runLater(() -> { - // take 360° screenshot - File screenshotFolder = new File(mc.mcDataDir, "screenshots"); - screenshotFolder.mkdir(); - File screenshotFile = ScreenShotHelper.getTimestampedPNGFileForDirectory(screenshotFolder); - - int width = 8640; - int height = 4320; - - int displayWidthBefore = mc.displayWidth; - int displayHeightBefore = mc.displayHeight; - - ChunkLoadingRenderGlobal clrg = new ChunkLoadingRenderGlobal(mc.renderGlobal); - - Pipelines.newEquirectangularPipeline(new RenderInfo() { - @Override - public ReadableDimension getFrameSize() { - return new Dimension(width, height); - } - - @Override - public int getTotalFrames() { - return 1; - } - - @Override - public float updateForNextFrame() { - return mc.timer.renderPartialTicks; - } - - @Override - public RenderSettings getRenderSettings() { - return new RenderSettings( - null, null, width, height, 0, 0, null, - true, true, true, true, null, - false, RenderSettings.AntiAliasing.NONE, null, null, false - ); - } - }, new ScreenshotWriter(screenshotFile)).run(); - - clrg.uninstall(); - - // the Equirectangular rendering changes mc.displayWidth and mc.displayHeight, - // so we have to reset it to the previous value - mc.resize(displayWidthBefore, displayHeightBefore); - }); + ReplayMod.instance.runLater(this::createEquirectangularScreenshot); event.setCanceled(true); } } } + + private void createEquirectangularScreenshot() { + // take 360° screenshot + File screenshotFolder = new File(mc.mcDataDir, "screenshots"); + screenshotFolder.mkdir(); + File screenshotFile = ScreenShotHelper.getTimestampedPNGFileForDirectory(screenshotFolder); + + int width = 8640; + int height = 4320; + + int displayWidthBefore = mc.displayWidth; + int displayHeightBefore = mc.displayHeight; + + ChunkLoadingRenderGlobal clrg = new ChunkLoadingRenderGlobal(mc.renderGlobal); + + Pipelines.newEquirectangularPipeline(new RenderInfo() { + @Override + public ReadableDimension getFrameSize() { + return new Dimension(width, height); + } + + @Override + public int getTotalFrames() { + return 1; + } + + @Override + public float updateForNextFrame() { + return mc.timer.renderPartialTicks; + } + + @Override + public RenderSettings getRenderSettings() { + return new RenderSettings( + null, null, width, height, 0, 0, null, + true, true, true, true, null, + false, RenderSettings.AntiAliasing.NONE, null, null, false + ); + } + }, new ScreenshotWriter(screenshotFile)).run(); + + clrg.uninstall(); + + // the Equirectangular rendering changes mc.displayWidth and mc.displayHeight, + // so we have to reset it to the previous value + mc.resize(displayWidthBefore, displayHeightBefore); + + new GuiUploadScreenshot(ReplayModReplay.instance.getReplayHandler().getOverlay(), mod, screenshotFile).open(); + } } diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/GuiUploadScreenshot.java b/src/main/java/com/replaymod/extras/advancedscreenshots/GuiUploadScreenshot.java new file mode 100644 index 00000000..828d7f65 --- /dev/null +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/GuiUploadScreenshot.java @@ -0,0 +1,114 @@ +package com.replaymod.extras.advancedscreenshots; + +import com.replaymod.core.ReplayMod; +import com.replaymod.core.SettingsRegistry; +import com.replaymod.extras.Setting; +import de.johni0702.minecraft.gui.container.GuiContainer; +import de.johni0702.minecraft.gui.container.GuiPanel; +import de.johni0702.minecraft.gui.element.GuiButton; +import de.johni0702.minecraft.gui.element.GuiCheckbox; +import de.johni0702.minecraft.gui.element.GuiLabel; +import de.johni0702.minecraft.gui.layout.HorizontalLayout; +import de.johni0702.minecraft.gui.layout.VerticalLayout; +import de.johni0702.minecraft.gui.popup.AbstractGuiPopup; +import org.lwjgl.util.ReadableColor; + +import java.awt.*; +import java.io.File; +import java.io.IOException; +import java.net.URI; + +public class GuiUploadScreenshot extends AbstractGuiPopup { + + public final ReplayMod mod; + + public final File screenshotFile; + + public final GuiLabel successLabel = new GuiLabel() + .setI18nText("replaymod.gui.advancedscreenshots.finished.description.360") + .setColor(ReadableColor.BLACK); + + public final GuiLabel veerLabel = new GuiLabel() + .setI18nText("replaymod.gui.advancedscreenshots.finished.description.veer") + .setColor(ReadableColor.BLACK); + + public final GuiButton veerUploadButton = new GuiButton() + .setSize(150, 20) + .setI18nLabel("replaymod.gui.advancedscreenshots.finished.upload.veer"); + + public final GuiButton showOnDiskButton = new GuiButton() + .setSize(150, 20) + .setI18nLabel("replaymod.gui.advancedscreenshots.finished.showfile"); + + public final GuiButton closeButton = new GuiButton() + .setSize(150, 20) + .setI18nLabel("replaymod.gui.close"); + + public final GuiCheckbox neverOpenCheckbox = new GuiCheckbox(); + + public final GuiLabel neverOpenLabel = new GuiLabel() + .setI18nText("replaymod.gui.notagain") + .setColor(ReadableColor.BLACK); + + public final GuiPanel checkboxPanel = GuiPanel.builder() + .layout(new HorizontalLayout(HorizontalLayout.Alignment.RIGHT).setSpacing(5)) + .with(neverOpenCheckbox, new HorizontalLayout.Data(0.5)) + .with(neverOpenLabel, new HorizontalLayout.Data(0.5)) + .build(); + + public GuiUploadScreenshot(GuiContainer container, ReplayMod mod, File screenshotFile) { + super(container); + this.mod = mod; + this.screenshotFile = screenshotFile; + + veerUploadButton.onClick(() -> { + try { + Desktop.getDesktop().browse(URI.create("https://veer.tv/upload")); + } catch (IOException e) { + e.printStackTrace(); + } + }); + + showOnDiskButton.onClick(() -> { + try { + Desktop.getDesktop().browse(URI.create("file://" + screenshotFile.getAbsolutePath())); + } catch (IOException e) { + e.printStackTrace(); + } + }); + + closeButton.onClick(() -> { + if (neverOpenCheckbox.isChecked()) { + SettingsRegistry settingsRegistry = mod.getSettingsRegistry(); + settingsRegistry.set(Setting.SKIP_POST_SCREENSHOT_GUI, true); + settingsRegistry.save(); + } + close(); + }); + + popup.addElements(new VerticalLayout.Data(0.5), + successLabel, + veerLabel, + veerUploadButton, + showOnDiskButton, + closeButton); + + popup.addElements(new VerticalLayout.Data(1), + checkboxPanel); + + popup.setLayout(new VerticalLayout().setSpacing(5)); + } + + @Override + protected void open() { + if (mod.getSettingsRegistry().get(Setting.SKIP_POST_SCREENSHOT_GUI)) { + return; + } + super.open(); + } + + @Override + protected GuiUploadScreenshot getThis() { + return this; + } +} diff --git a/src/main/java/com/replaymod/replay/events/ReplayDispatchKeypressesEvent.java b/src/main/java/com/replaymod/replay/events/ReplayDispatchKeypressesEvent.java index 15b23352..d3547127 100644 --- a/src/main/java/com/replaymod/replay/events/ReplayDispatchKeypressesEvent.java +++ b/src/main/java/com/replaymod/replay/events/ReplayDispatchKeypressesEvent.java @@ -3,7 +3,8 @@ package com.replaymod.replay.events; import net.minecraftforge.fml.common.eventhandler.Cancelable; import net.minecraftforge.fml.common.eventhandler.Event; -@Cancelable public abstract class ReplayDispatchKeypressesEvent extends Event { + + @Cancelable public static class Pre extends ReplayDispatchKeypressesEvent {} } From 98098ea2ed37b4bcb669b3ffd42d4ee603d6c25b Mon Sep 17 00:00:00 2001 From: CrushedPixel Date: Wed, 27 Sep 2017 13:13:49 +0200 Subject: [PATCH 04/23] Update language submodule --- src/main/resources/assets/replaymod/lang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/assets/replaymod/lang b/src/main/resources/assets/replaymod/lang index 8d77fe06..94282826 160000 --- a/src/main/resources/assets/replaymod/lang +++ b/src/main/resources/assets/replaymod/lang @@ -1 +1 @@ -Subproject commit 8d77fe0697691f0b682f422e268b40383468f31d +Subproject commit 942828260079edb1e35b2e500d6763c5234f6bbb From bfbaec44ba3de26f210ba13c0d9171c769fef203 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 31 Oct 2017 11:11:03 +0100 Subject: [PATCH 05/23] Add logging to BetterSprinting compat class --- src/main/java/com/replaymod/compat/ReplayModCompat.java | 9 +++++++++ .../compat/bettersprinting/DisableBetterSprinting.java | 8 +++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/replaymod/compat/ReplayModCompat.java b/src/main/java/com/replaymod/compat/ReplayModCompat.java index 9347cd2f..7de27c26 100644 --- a/src/main/java/com/replaymod/compat/ReplayModCompat.java +++ b/src/main/java/com/replaymod/compat/ReplayModCompat.java @@ -7,7 +7,9 @@ import com.replaymod.compat.shaders.ShaderBeginRender; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.event.FMLInitializationEvent; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; import net.minecraftforge.fml.common.eventhandler.EventBus; +import org.apache.logging.log4j.Logger; @Mod(modid = ReplayModCompat.MOD_ID, version = "@MOD_VERSION@", @@ -17,6 +19,13 @@ import net.minecraftforge.fml.common.eventhandler.EventBus; public class ReplayModCompat { public static final String MOD_ID = "replaymod-compat"; + public static Logger LOGGER; + + @Mod.EventHandler + public void preInit(FMLPreInitializationEvent event) { + LOGGER = event.getModLog(); + } + @Mod.EventHandler public void init(FMLInitializationEvent event) { EventBus bus = FMLCommonHandler.instance().bus(); diff --git a/src/main/java/com/replaymod/compat/bettersprinting/DisableBetterSprinting.java b/src/main/java/com/replaymod/compat/bettersprinting/DisableBetterSprinting.java index 57ab557a..e6a743c2 100644 --- a/src/main/java/com/replaymod/compat/bettersprinting/DisableBetterSprinting.java +++ b/src/main/java/com/replaymod/compat/bettersprinting/DisableBetterSprinting.java @@ -20,6 +20,8 @@ import net.minecraftforge.fml.common.versioning.VersionRange; import java.util.Collections; +import static com.replaymod.compat.ReplayModCompat.LOGGER; + /** * Old Better Sprinting versions replace the vanilla player with their own, overridden instance (replacing the camera entity). * @@ -39,7 +41,9 @@ public class DisableBetterSprinting { .ifPresent($_ -> MinecraftForge.EVENT_BUS.register(new DisableBetterSprinting())); } - private DisableBetterSprinting() {} + private DisableBetterSprinting() { + LOGGER.info("BetterSprinting workaround enabled"); + } private final Minecraft mc = Minecraft.getMinecraft(); private PlayerControllerMP originalController; @@ -66,6 +70,7 @@ public class DisableBetterSprinting { // Suppress this message if it's the Better Sprinting warning message for (StackTraceElement elem : Thread.currentThread().getStackTrace()) { if (LOGIC_CLASS_NAME.equals(elem.getClassName())) { + LOGGER.info("BetterSprinting warning message suppressed."); event.setCanceled(true); return; } @@ -78,6 +83,7 @@ public class DisableBetterSprinting { if (mc.playerController != null && mc.playerController.getClass().getName().equals(CONTROLLER_OVERRIDE_CLASS_NAME)) { // Someone has secretly swapped out the player controller and is about to substitute their own player entity. // This is the right time to destroy their plan. + LOGGER.info("Preventing player controller {} from being replaced by BetterSprinting with {}.", originalController, mc.playerController); mc.playerController = originalController; } } From 434efd16d183af3ae9a9e1811a2f1093408078e2 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 31 Oct 2017 11:11:33 +0100 Subject: [PATCH 06/23] Fix BetterSprinting compat class not actually functioning (fixes #103) --- .../compat/bettersprinting/DisableBetterSprinting.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/replaymod/compat/bettersprinting/DisableBetterSprinting.java b/src/main/java/com/replaymod/compat/bettersprinting/DisableBetterSprinting.java index e6a743c2..c8928d6b 100644 --- a/src/main/java/com/replaymod/compat/bettersprinting/DisableBetterSprinting.java +++ b/src/main/java/com/replaymod/compat/bettersprinting/DisableBetterSprinting.java @@ -31,7 +31,7 @@ public class DisableBetterSprinting { private static final VersionRange OLD_VERSION = VersionRange.newRange(null, Collections.singletonList(new Restriction(null, false, new DefaultArtifactVersion("2.0.0"), false))); private static final String LOGIC_CLASS_NAME = "chylex.bettersprinting.client.player.impl.LogicImplOverride"; - private static final String CONTROLLER_OVERRIDE_CLASS_NAME = LOGIC_CLASS_NAME + ".PlayerControllerMPOverride"; + private static final String CONTROLLER_OVERRIDE_CLASS_NAME = LOGIC_CLASS_NAME + "$PlayerControllerMPOverride"; public static void register() { Loader.instance().getModList().stream() From 7d380e770a0c884def0e2b45fcf31c5e085e728d Mon Sep 17 00:00:00 2001 From: CrushedPixel Date: Tue, 31 Oct 2017 17:28:21 +0100 Subject: [PATCH 07/23] =?UTF-8?q?Properly=20handle=20OOMExceptions=20when?= =?UTF-8?q?=20creating=20a=20360=C2=B0=20screenshot?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdvancedScreenshots.java | 79 ++++++++++--------- .../advancedscreenshots/ScreenshotWriter.java | 5 ++ 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/AdvancedScreenshots.java b/src/main/java/com/replaymod/extras/advancedscreenshots/AdvancedScreenshots.java index ee55cd2c..4e891b67 100644 --- a/src/main/java/com/replaymod/extras/advancedscreenshots/AdvancedScreenshots.java +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/AdvancedScreenshots.java @@ -11,6 +11,7 @@ import com.replaymod.replay.events.ReplayDispatchKeypressesEvent; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiControls; import net.minecraft.client.gui.GuiScreen; +import net.minecraft.crash.CrashReport; import net.minecraft.util.ScreenShotHelper; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @@ -51,51 +52,57 @@ public class AdvancedScreenshots implements Extra { } private void createEquirectangularScreenshot() { - // take 360° screenshot - File screenshotFolder = new File(mc.mcDataDir, "screenshots"); - screenshotFolder.mkdir(); - File screenshotFile = ScreenShotHelper.getTimestampedPNGFileForDirectory(screenshotFolder); + try { + // take 360° screenshot + File screenshotFolder = new File(mc.mcDataDir, "screenshots"); + screenshotFolder.mkdir(); + File screenshotFile = ScreenShotHelper.getTimestampedPNGFileForDirectory(screenshotFolder); - int width = 8640; - int height = 4320; + int height = 4 * 4320; + int width = 2 * height; - int displayWidthBefore = mc.displayWidth; - int displayHeightBefore = mc.displayHeight; + int displayWidthBefore = mc.displayWidth; + int displayHeightBefore = mc.displayHeight; - ChunkLoadingRenderGlobal clrg = new ChunkLoadingRenderGlobal(mc.renderGlobal); + ChunkLoadingRenderGlobal clrg = new ChunkLoadingRenderGlobal(mc.renderGlobal); - Pipelines.newEquirectangularPipeline(new RenderInfo() { - @Override - public ReadableDimension getFrameSize() { - return new Dimension(width, height); - } + Pipelines.newEquirectangularPipeline(new RenderInfo() { + @Override + public ReadableDimension getFrameSize() { + return new Dimension(width, height); + } - @Override - public int getTotalFrames() { - return 1; - } + @Override + public int getTotalFrames() { + return 1; + } - @Override - public float updateForNextFrame() { - return mc.timer.renderPartialTicks; - } + @Override + public float updateForNextFrame() { + return mc.timer.renderPartialTicks; + } - @Override - public RenderSettings getRenderSettings() { - return new RenderSettings( - null, null, width, height, 0, 0, null, - true, true, true, true, null, - false, RenderSettings.AntiAliasing.NONE, null, null, false - ); - } - }, new ScreenshotWriter(screenshotFile)).run(); + @Override + public RenderSettings getRenderSettings() { + return new RenderSettings( + null, null, width, height, 0, 0, null, + true, true, true, true, null, + false, RenderSettings.AntiAliasing.NONE, null, null, false + ); + } + }, new ScreenshotWriter(screenshotFile)).run(); - clrg.uninstall(); + clrg.uninstall(); - // the Equirectangular rendering changes mc.displayWidth and mc.displayHeight, - // so we have to reset it to the previous value - mc.resize(displayWidthBefore, displayHeightBefore); + // the Equirectangular rendering changes mc.displayWidth and mc.displayHeight, + // so we have to reset it to the previous value + mc.resize(displayWidthBefore, displayHeightBefore); - new GuiUploadScreenshot(ReplayModReplay.instance.getReplayHandler().getOverlay(), mod, screenshotFile).open(); + new GuiUploadScreenshot(ReplayModReplay.instance.getReplayHandler().getOverlay(), mod, screenshotFile).open(); + } catch (OutOfMemoryError e) { + e.printStackTrace(); + CrashReport report = CrashReport.makeCrashReport(e, "Creating Equirectangular Screenshot"); + Minecraft.getMinecraft().crashed(report); + } } } diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotWriter.java b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotWriter.java index d487b08b..e04d1b59 100644 --- a/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotWriter.java +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotWriter.java @@ -6,6 +6,7 @@ import com.replaymod.extras.ReplayModExtras; import com.replaymod.render.frame.RGBFrame; import com.replaymod.render.rendering.FrameConsumer; import com.replaymod.replay.ReplayModReplay; +import net.minecraft.client.Minecraft; import net.minecraft.crash.CrashReport; import org.lwjgl.util.ReadableDimension; @@ -40,6 +41,10 @@ public class ScreenshotWriter implements FrameConsumer { } ImageIO.write(img, "PNG", outputFile); + } catch (OutOfMemoryError e) { + e.printStackTrace(); + CrashReport report = CrashReport.makeCrashReport(e, "Exporting frame"); + Minecraft.getMinecraft().crashed(report); } catch (Throwable t) { CrashReport report = CrashReport.makeCrashReport(t, "Exporting frame"); From 2ebec358e0ceee0ad9374b8faac53bc599fffe97 Mon Sep 17 00:00:00 2001 From: CrushedPixel Date: Wed, 1 Nov 2017 13:24:52 +0100 Subject: [PATCH 08/23] Added Screenshot export settings GUI --- .../AdvancedScreenshots.java | 75 +--------------- .../GuiCreateScreenshot.java | 87 +++++++++++++++++++ .../GuiUploadScreenshot.java | 44 ++++++---- .../ScreenshotRenderer.java | 65 ++++++++++++++ .../render/gui/GuiRenderSettings.java | 4 +- 5 files changed, 187 insertions(+), 88 deletions(-) create mode 100644 src/main/java/com/replaymod/extras/advancedscreenshots/GuiCreateScreenshot.java create mode 100644 src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/AdvancedScreenshots.java b/src/main/java/com/replaymod/extras/advancedscreenshots/AdvancedScreenshots.java index 4e891b67..a3e7b36b 100644 --- a/src/main/java/com/replaymod/extras/advancedscreenshots/AdvancedScreenshots.java +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/AdvancedScreenshots.java @@ -2,24 +2,12 @@ package com.replaymod.extras.advancedscreenshots; import com.replaymod.core.ReplayMod; import com.replaymod.extras.Extra; -import com.replaymod.render.RenderSettings; -import com.replaymod.render.capturer.RenderInfo; -import com.replaymod.render.hooks.ChunkLoadingRenderGlobal; -import com.replaymod.render.rendering.Pipelines; -import com.replaymod.replay.ReplayModReplay; import com.replaymod.replay.events.ReplayDispatchKeypressesEvent; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiControls; -import net.minecraft.client.gui.GuiScreen; -import net.minecraft.crash.CrashReport; -import net.minecraft.util.ScreenShotHelper; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import org.lwjgl.input.Keyboard; -import org.lwjgl.util.Dimension; -import org.lwjgl.util.ReadableDimension; - -import java.io.File; public class AdvancedScreenshots implements Extra { @@ -43,66 +31,11 @@ public class AdvancedScreenshots implements Extra { && Keyboard.getEventKeyState() && keyCode == mc.gameSettings.keyBindScreenshot.getKeyCode()) { - if (GuiScreen.isCtrlKeyDown()) { - ReplayMod.instance.runLater(this::createEquirectangularScreenshot); + ReplayMod.instance.runLater(() -> { + new GuiCreateScreenshot(mod).display(); + }); - event.setCanceled(true); - } - } - } - - private void createEquirectangularScreenshot() { - try { - // take 360° screenshot - File screenshotFolder = new File(mc.mcDataDir, "screenshots"); - screenshotFolder.mkdir(); - File screenshotFile = ScreenShotHelper.getTimestampedPNGFileForDirectory(screenshotFolder); - - int height = 4 * 4320; - int width = 2 * height; - - int displayWidthBefore = mc.displayWidth; - int displayHeightBefore = mc.displayHeight; - - ChunkLoadingRenderGlobal clrg = new ChunkLoadingRenderGlobal(mc.renderGlobal); - - Pipelines.newEquirectangularPipeline(new RenderInfo() { - @Override - public ReadableDimension getFrameSize() { - return new Dimension(width, height); - } - - @Override - public int getTotalFrames() { - return 1; - } - - @Override - public float updateForNextFrame() { - return mc.timer.renderPartialTicks; - } - - @Override - public RenderSettings getRenderSettings() { - return new RenderSettings( - null, null, width, height, 0, 0, null, - true, true, true, true, null, - false, RenderSettings.AntiAliasing.NONE, null, null, false - ); - } - }, new ScreenshotWriter(screenshotFile)).run(); - - clrg.uninstall(); - - // the Equirectangular rendering changes mc.displayWidth and mc.displayHeight, - // so we have to reset it to the previous value - mc.resize(displayWidthBefore, displayHeightBefore); - - new GuiUploadScreenshot(ReplayModReplay.instance.getReplayHandler().getOverlay(), mod, screenshotFile).open(); - } catch (OutOfMemoryError e) { - e.printStackTrace(); - CrashReport report = CrashReport.makeCrashReport(e, "Creating Equirectangular Screenshot"); - Minecraft.getMinecraft().crashed(report); + event.setCanceled(true); } } } diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/GuiCreateScreenshot.java b/src/main/java/com/replaymod/extras/advancedscreenshots/GuiCreateScreenshot.java new file mode 100644 index 00000000..d4512d98 --- /dev/null +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/GuiCreateScreenshot.java @@ -0,0 +1,87 @@ +package com.replaymod.extras.advancedscreenshots; + +import com.replaymod.core.ReplayMod; +import com.replaymod.render.RenderSettings; +import com.replaymod.render.gui.GuiRenderSettings; +import com.replaymod.replay.ReplayModReplay; +import de.johni0702.minecraft.gui.container.GuiContainer; +import de.johni0702.minecraft.gui.container.GuiPanel; +import de.johni0702.minecraft.gui.element.GuiLabel; +import de.johni0702.minecraft.gui.layout.GridLayout; +import de.johni0702.minecraft.gui.layout.VerticalLayout; +import net.minecraft.crash.CrashReport; +import net.minecraft.util.ScreenShotHelper; +import net.minecraftforge.common.config.Configuration; +import net.minecraftforge.common.config.Property; + +import java.io.File; +import java.util.ArrayList; + +import static com.replaymod.core.utils.Utils.error; +import static com.replaymod.render.ReplayModRender.LOGGER; + +public class GuiCreateScreenshot extends GuiRenderSettings { + + private final ReplayMod mod; + + public GuiCreateScreenshot(ReplayMod mod) { + super(null, null); + + this.mod = mod; + + resetChildren(settingsList.getListPanel()).addElements(new VerticalLayout.Data(0.5), + new GuiLabel().setI18nText("replaymod.gui.advancedscreenshots.title"), mainPanel, new GuiPanel(), + new GuiLabel().setI18nText("replaymod.gui.rendersettings.advanced"), advancedPanel, new GuiPanel()); + + resetChildren(mainPanel).addElements(new GridLayout.Data(1, 0.5), + new GuiLabel().setI18nText("replaymod.gui.rendersettings.renderer"), renderMethodDropdown, + new GuiLabel().setI18nText("replaymod.gui.advancedscreenshots.resolution"), videoResolutionPanel, + new GuiLabel().setI18nText("replaymod.gui.rendersettings.outputfile"), outputFileButton); + + resetChildren(advancedPanel).addElements(null, nametagCheckbox, new GuiPanel().setLayout( + new GridLayout().setCellsEqualSize(false).setColumns(2).setSpacingX(5).setSpacingY(15)) + .addElements(new GridLayout.Data(0, 0.5), + new GuiLabel().setI18nText("replaymod.gui.rendersettings.stabilizecamera"), stabilizePanel, + chromaKeyingCheckbox, chromaKeyingColor)); + + exportArguments.setText(""); // To disable any preset-based checks + buttonPanel.removeElement(queueButton); + renderButton.setI18nLabel("replaymod.gui.advancedscreenshots.create").onClick(() -> { + // Closing this GUI ensures that settings are saved + getMinecraft().displayGuiScreen(null); + + mod.runLater(() -> { + try { + RenderSettings settings = save(false); + + boolean success = new ScreenshotRenderer(settings).renderScreenshot(); + if (success) { + new GuiUploadScreenshot(ReplayModReplay.instance.getReplayHandler().getOverlay(), mod, + settings).open(); + } + + } catch (Throwable t) { + error(LOGGER, GuiCreateScreenshot.this, CrashReport.makeCrashReport(t, "Rendering video"), () -> {}); + display(); // Re-show the render settings gui and the new error popup + } + }); + }); + } + + private > T resetChildren(T container) { + new ArrayList<>(container.getChildren()).forEach(container::removeElement); + return container; + } + + @Override + protected File generateOutputFile(RenderSettings.EncodingPreset encodingPreset) { + File screenshotFolder = new File(getMinecraft().mcDataDir, "screenshots"); + return ScreenShotHelper.getTimestampedPNGFileForDirectory(screenshotFolder); + } + + @Override + protected Property getConfigProperty(Configuration configuration) { + return configuration.get("screenshotsettings", "settings", "{}", + "Last state of the screenshot settings GUI. Internal use only."); + } +} \ No newline at end of file diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/GuiUploadScreenshot.java b/src/main/java/com/replaymod/extras/advancedscreenshots/GuiUploadScreenshot.java index 828d7f65..e2168da5 100644 --- a/src/main/java/com/replaymod/extras/advancedscreenshots/GuiUploadScreenshot.java +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/GuiUploadScreenshot.java @@ -3,6 +3,7 @@ package com.replaymod.extras.advancedscreenshots; import com.replaymod.core.ReplayMod; import com.replaymod.core.SettingsRegistry; import com.replaymod.extras.Setting; +import com.replaymod.render.RenderSettings; import de.johni0702.minecraft.gui.container.GuiContainer; import de.johni0702.minecraft.gui.container.GuiPanel; import de.johni0702.minecraft.gui.element.GuiButton; @@ -14,7 +15,6 @@ import de.johni0702.minecraft.gui.popup.AbstractGuiPopup; import org.lwjgl.util.ReadableColor; import java.awt.*; -import java.io.File; import java.io.IOException; import java.net.URI; @@ -22,10 +22,10 @@ public class GuiUploadScreenshot extends AbstractGuiPopup { public final ReplayMod mod; - public final File screenshotFile; + public final RenderSettings renderSettings; public final GuiLabel successLabel = new GuiLabel() - .setI18nText("replaymod.gui.advancedscreenshots.finished.description.360") + .setI18nText("replaymod.gui.advancedscreenshots.finished.description") .setColor(ReadableColor.BLACK); public final GuiLabel veerLabel = new GuiLabel() @@ -56,22 +56,30 @@ public class GuiUploadScreenshot extends AbstractGuiPopup { .with(neverOpenLabel, new HorizontalLayout.Data(0.5)) .build(); - public GuiUploadScreenshot(GuiContainer container, ReplayMod mod, File screenshotFile) { + public GuiUploadScreenshot(GuiContainer container, ReplayMod mod, RenderSettings renderSettings) { super(container); this.mod = mod; - this.screenshotFile = screenshotFile; + this.renderSettings = renderSettings; - veerUploadButton.onClick(() -> { - try { - Desktop.getDesktop().browse(URI.create("https://veer.tv/upload")); - } catch (IOException e) { - e.printStackTrace(); - } - }); + boolean veer = renderSettings.getRenderMethod() == RenderSettings.RenderMethod.EQUIRECTANGULAR; + + if (renderSettings.getRenderMethod() == RenderSettings.RenderMethod.EQUIRECTANGULAR) { + successLabel.setI18nText("replaymod.gui.advancedscreenshots.finished.description.360"); + } + + if (veer) { + veerUploadButton.onClick(() -> { + try { + Desktop.getDesktop().browse(URI.create("https://veer.tv/upload")); + } catch (IOException e) { + e.printStackTrace(); + } + }); + } showOnDiskButton.onClick(() -> { try { - Desktop.getDesktop().browse(URI.create("file://" + screenshotFile.getAbsolutePath())); + Desktop.getDesktop().browse(URI.create("file://" + renderSettings.getOutputFile().getAbsolutePath())); } catch (IOException e) { e.printStackTrace(); } @@ -86,10 +94,16 @@ public class GuiUploadScreenshot extends AbstractGuiPopup { close(); }); + popup.addElements(new VerticalLayout.Data(0.5), successLabel); + + if (veer) { + popup.addElements(new VerticalLayout.Data(0.5), + veerLabel, + veerUploadButton); + } + popup.addElements(new VerticalLayout.Data(0.5), successLabel, - veerLabel, - veerUploadButton, showOnDiskButton, closeButton); diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java new file mode 100644 index 00000000..72aad0ac --- /dev/null +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java @@ -0,0 +1,65 @@ +package com.replaymod.extras.advancedscreenshots; + +import com.replaymod.render.RenderSettings; +import com.replaymod.render.capturer.RenderInfo; +import com.replaymod.render.hooks.ChunkLoadingRenderGlobal; +import com.replaymod.render.rendering.Pipelines; +import lombok.RequiredArgsConstructor; +import net.minecraft.client.Minecraft; +import net.minecraft.crash.CrashReport; +import org.lwjgl.util.Dimension; +import org.lwjgl.util.ReadableDimension; + +@RequiredArgsConstructor +public class ScreenshotRenderer implements RenderInfo { + + private final Minecraft mc = Minecraft.getMinecraft(); + + private final RenderSettings settings; + + public boolean renderScreenshot() throws Throwable { + try { + int displayWidthBefore = mc.displayWidth; + int displayHeightBefore = mc.displayHeight; + + ChunkLoadingRenderGlobal clrg = new ChunkLoadingRenderGlobal(mc.renderGlobal); + + Pipelines.newPipeline(settings.getRenderMethod(),this, + new ScreenshotWriter(settings.getOutputFile())).run(); + + clrg.uninstall(); + + mc.resize(displayWidthBefore, displayHeightBefore); + return true; + } catch (OutOfMemoryError e) { + e.printStackTrace(); + CrashReport report = CrashReport.makeCrashReport(e, "Creating Equirectangular Screenshot"); + Minecraft.getMinecraft().crashed(report); + } + return false; + } + + @Override + public ReadableDimension getFrameSize() { + return new Dimension(settings.getVideoWidth(), settings.getVideoHeight()); + } + + @Override + public int getTotalFrames() { + return 1; + } + + @Override + public float updateForNextFrame() { + return mc.timer.renderPartialTicks; + } + + @Override + public RenderSettings getRenderSettings() { + return new RenderSettings( + null, null, settings.getVideoWidth(), settings.getVideoHeight(), 0, 0, null, + true, true, true, true, null, + false, RenderSettings.AntiAliasing.NONE, null, null, false + ); + } +} diff --git a/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java b/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java index f712dd0d..a07f801e 100644 --- a/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java +++ b/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java @@ -427,7 +427,7 @@ public class GuiRenderSettings extends GuiScreen implements Closeable { ); } - private File generateOutputFile(RenderSettings.EncodingPreset encodingPreset) { + protected File generateOutputFile(RenderSettings.EncodingPreset encodingPreset) { String fileName = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss").format(new Date()); File folder = ReplayModRender.instance.getVideoFolder(); return new File(folder, fileName + "." + encodingPreset.getFileExtension()); @@ -447,7 +447,7 @@ public class GuiRenderSettings extends GuiScreen implements Closeable { config.save(); } - private Property getConfigProperty(Configuration configuration) { + protected Property getConfigProperty(Configuration configuration) { return configuration.get("rendersettings", "settings", "{}", "Last state of the render settings GUI. Internal use only."); } From a4a9473111b30d01359b5491b7519093fcf10ef1 Mon Sep 17 00:00:00 2001 From: CrushedPixel Date: Wed, 1 Nov 2017 15:36:15 +0100 Subject: [PATCH 09/23] Hide GUI when exporting screenshot Workaround not all chunks being loaded in screenshot Fix wrong RenderSettings being exposed in ScreenshotRenderer Update Language submodule --- .../advancedscreenshots/GuiCreateScreenshot.java | 9 ++++++++- .../advancedscreenshots/ScreenshotRenderer.java | 12 ++++++------ .../extras/advancedscreenshots/ScreenshotWriter.java | 3 +++ src/main/resources/assets/replaymod/lang | 2 +- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/GuiCreateScreenshot.java b/src/main/java/com/replaymod/extras/advancedscreenshots/GuiCreateScreenshot.java index d4512d98..3ef09234 100644 --- a/src/main/java/com/replaymod/extras/advancedscreenshots/GuiCreateScreenshot.java +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/GuiCreateScreenshot.java @@ -7,6 +7,7 @@ import com.replaymod.replay.ReplayModReplay; import de.johni0702.minecraft.gui.container.GuiContainer; import de.johni0702.minecraft.gui.container.GuiPanel; import de.johni0702.minecraft.gui.element.GuiLabel; +import de.johni0702.minecraft.gui.function.Loadable; import de.johni0702.minecraft.gui.layout.GridLayout; import de.johni0702.minecraft.gui.layout.VerticalLayout; import net.minecraft.crash.CrashReport; @@ -20,7 +21,7 @@ import java.util.ArrayList; import static com.replaymod.core.utils.Utils.error; import static com.replaymod.render.ReplayModRender.LOGGER; -public class GuiCreateScreenshot extends GuiRenderSettings { +public class GuiCreateScreenshot extends GuiRenderSettings implements Loadable { private final ReplayMod mod; @@ -73,6 +74,12 @@ public class GuiCreateScreenshot extends GuiRenderSettings { return container; } + @Override + public void load() { + // pause replay when opening this gui + ReplayModReplay.instance.getReplayHandler().getReplaySender().setReplaySpeed(0); + } + @Override protected File generateOutputFile(RenderSettings.EncodingPreset encodingPreset) { File screenshotFolder = new File(getMinecraft().mcDataDir, "screenshots"); diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java index 72aad0ac..2133432d 100644 --- a/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java @@ -22,6 +22,8 @@ public class ScreenshotRenderer implements RenderInfo { int displayWidthBefore = mc.displayWidth; int displayHeightBefore = mc.displayHeight; + boolean hideGUIBefore = mc.gameSettings.hideGUI; + ChunkLoadingRenderGlobal clrg = new ChunkLoadingRenderGlobal(mc.renderGlobal); Pipelines.newPipeline(settings.getRenderMethod(),this, @@ -29,6 +31,7 @@ public class ScreenshotRenderer implements RenderInfo { clrg.uninstall(); + mc.gameSettings.hideGUI = hideGUIBefore; mc.resize(displayWidthBefore, displayHeightBefore); return true; } catch (OutOfMemoryError e) { @@ -46,7 +49,8 @@ public class ScreenshotRenderer implements RenderInfo { @Override public int getTotalFrames() { - return 1; + // render 2 frames, because only the second contains all frames fully loaded + return 2; } @Override @@ -56,10 +60,6 @@ public class ScreenshotRenderer implements RenderInfo { @Override public RenderSettings getRenderSettings() { - return new RenderSettings( - null, null, settings.getVideoWidth(), settings.getVideoHeight(), 0, 0, null, - true, true, true, true, null, - false, RenderSettings.AntiAliasing.NONE, null, null, false - ); + return settings; } } diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotWriter.java b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotWriter.java index e04d1b59..c601f28f 100644 --- a/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotWriter.java +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotWriter.java @@ -25,6 +25,9 @@ public class ScreenshotWriter implements FrameConsumer { @Override public void consume(RGBFrame frame) { + // skip the first frame, in which not all chunks are properly loaded + if (frame.getFrameId() == 0) return; + try { final ReadableDimension frameSize = frame.getSize(); diff --git a/src/main/resources/assets/replaymod/lang b/src/main/resources/assets/replaymod/lang index 94282826..75edb999 160000 --- a/src/main/resources/assets/replaymod/lang +++ b/src/main/resources/assets/replaymod/lang @@ -1 +1 @@ -Subproject commit 942828260079edb1e35b2e500d6763c5234f6bbb +Subproject commit 75edb99901404c1364de54352b5ad8b5a21d9536 From 666a3611bbb61a9abdbf268d8dab99192f15e0b4 Mon Sep 17 00:00:00 2001 From: CrushedPixel Date: Wed, 1 Nov 2017 15:43:49 +0100 Subject: [PATCH 10/23] Actually hide the GUI when exporting a screenshot --- .../replaymod/extras/advancedscreenshots/ScreenshotRenderer.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java index 2133432d..6fe7af62 100644 --- a/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java @@ -23,6 +23,7 @@ public class ScreenshotRenderer implements RenderInfo { int displayHeightBefore = mc.displayHeight; boolean hideGUIBefore = mc.gameSettings.hideGUI; + mc.gameSettings.hideGUI = true; ChunkLoadingRenderGlobal clrg = new ChunkLoadingRenderGlobal(mc.renderGlobal); From 650cc1036dc233f3f5243b25d02a5977fcb91e59 Mon Sep 17 00:00:00 2001 From: CrushedPixel Date: Fri, 22 Dec 2017 15:14:20 +0100 Subject: [PATCH 11/23] Fix GuiUploadScreenshot showOnDiskButton crashing the game on Windows --- .../extras/advancedscreenshots/GuiUploadScreenshot.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/GuiUploadScreenshot.java b/src/main/java/com/replaymod/extras/advancedscreenshots/GuiUploadScreenshot.java index e2168da5..4c2cf396 100644 --- a/src/main/java/com/replaymod/extras/advancedscreenshots/GuiUploadScreenshot.java +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/GuiUploadScreenshot.java @@ -79,7 +79,7 @@ public class GuiUploadScreenshot extends AbstractGuiPopup { showOnDiskButton.onClick(() -> { try { - Desktop.getDesktop().browse(URI.create("file://" + renderSettings.getOutputFile().getAbsolutePath())); + Desktop.getDesktop().browse(renderSettings.getOutputFile().toURI()); } catch (IOException e) { e.printStackTrace(); } From 2e62cdf838c10c4117a65f3b1c471fe8ecfcf2de Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 16 Jan 2018 11:42:28 +0100 Subject: [PATCH 12/23] Fix dead lock when rendering without immediate jump in time setupTerrain will loop until (among other conditions) the chunksToUpdate set is empty. However its size is never decreased during setupTerrain. Having a (backwards) jump in time right before rendering the first frame would reset the RenderGlobal due to the world change, leaving the chunksToUpdate set empty to begin with and due to other changes, chunks are never inserted into it during rendering (because they're always updated immediately). The new screenshot feature and rendering a path that's in the future will not trigger any world change, leaving the render process stuck in a life lock. --- src/main/java/com/replaymod/render/mixin/MixinRenderGlobal.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/replaymod/render/mixin/MixinRenderGlobal.java b/src/main/java/com/replaymod/render/mixin/MixinRenderGlobal.java index 7f5cae0a..07b90620 100644 --- a/src/main/java/com/replaymod/render/mixin/MixinRenderGlobal.java +++ b/src/main/java/com/replaymod/render/mixin/MixinRenderGlobal.java @@ -37,6 +37,7 @@ public abstract class MixinRenderGlobal { do { setupTerrain(viewEntity, partialTicks, camera, replayModRender_hook.nextFrameId(), playerSpectator); + replayModRender_hook.updateChunks(); } while (displayListEntitiesDirty); displayListEntitiesDirty = true; From 08e0d656856fbd99fd23d6a17555fd3c6455132c Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 16 Jan 2018 14:02:17 +0100 Subject: [PATCH 13/23] Remove preshadowJar steps from README.md (no longer required as of a8f2c74) --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c462bf7d..f05cdaea 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ to access private fields is a good indication that this has happened). You can build the mod by running `./gradlew :build`. You can then find the final jar files in `build/libs/`. ### IntelliJ -For the initial setup run `./gradlew preshadowJar idea genIntellijRuns`. +For the initial setup run `./gradlew idea genIntellijRuns`. You also need to enable the Mixin annotation processor: 1. Go to File -> Settings -> Build, Execution, Deployment -> Compiler -> Annotation Processors 2. Tick "Enable annotation processing" @@ -20,8 +20,8 @@ You also need to enable the Mixin annotation processor: 4. Set the name to "reobfSrgFile" and the value to "$path/build/mcp-srg.srg" where you replace $path with the full path to the folder containing the gradlew file -Whenever you switch to another branch, you can either just run `./gradlew preshadowJar idea` or instead run -`./gradlew preshadowJar copySrg` and then refresh the gradle project from within IntelliJ. +Whenever you switch to another branch, you can either just run `./gradlew idea` or instead run +`./gradlew copySrg` and then refresh the gradle project from within IntelliJ. ### Eclipse From 5bc5ef5fb8deba64853b56dd7adc23348f77d7e0 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 16 Jan 2018 14:21:38 +0100 Subject: [PATCH 14/23] Add buttons in SP/MP menu for quick en-/disabling of recording --- jGui | 2 +- .../recording/ReplayModRecording.java | 3 ++ .../recording/handler/GuiHandler.java | 52 +++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/replaymod/recording/handler/GuiHandler.java diff --git a/jGui b/jGui index 9e84e724..59ef5390 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit 9e84e724aaf7de21a06fd534faccdfdc6740fc28 +Subproject commit 59ef53903386beda93850351b78c420e7f84b31f diff --git a/src/main/java/com/replaymod/recording/ReplayModRecording.java b/src/main/java/com/replaymod/recording/ReplayModRecording.java index b2458985..afdd4340 100644 --- a/src/main/java/com/replaymod/recording/ReplayModRecording.java +++ b/src/main/java/com/replaymod/recording/ReplayModRecording.java @@ -3,6 +3,7 @@ package com.replaymod.recording; import com.replaymod.core.ReplayMod; import com.replaymod.core.utils.Restrictions; import com.replaymod.recording.handler.ConnectionEventHandler; +import com.replaymod.recording.handler.GuiHandler; import com.replaymod.recording.packet.PacketListener; import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandler; @@ -57,6 +58,8 @@ public class ReplayModRecording { EventBus bus = FMLCommonHandler.instance().bus(); bus.register(connectionEventHandler = new ConnectionEventHandler(logger, core)); + new GuiHandler(core).register(); + NetworkRegistry.INSTANCE.newChannel(Restrictions.PLUGIN_CHANNEL, new RestrictionsChannelHandler()); } diff --git a/src/main/java/com/replaymod/recording/handler/GuiHandler.java b/src/main/java/com/replaymod/recording/handler/GuiHandler.java new file mode 100644 index 00000000..dc6869d4 --- /dev/null +++ b/src/main/java/com/replaymod/recording/handler/GuiHandler.java @@ -0,0 +1,52 @@ +package com.replaymod.recording.handler; + +import com.replaymod.core.ReplayMod; +import com.replaymod.core.SettingsRegistry; +import com.replaymod.recording.Setting; +import de.johni0702.minecraft.gui.container.GuiScreen; +import de.johni0702.minecraft.gui.container.VanillaGuiScreen; +import de.johni0702.minecraft.gui.element.GuiCheckbox; +import de.johni0702.minecraft.gui.layout.CustomLayout; +import net.minecraft.client.gui.GuiMultiplayer; +import net.minecraft.client.gui.GuiSelectWorld; +import net.minecraftforge.client.event.GuiScreenEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +public class GuiHandler { + + private final ReplayMod mod; + + public GuiHandler(ReplayMod mod) { + this.mod = mod; + } + + public void register() { + MinecraftForge.EVENT_BUS.register(this); + } + + @SubscribeEvent + public void onGuiInit(GuiScreenEvent.InitGuiEvent.Post event) { + if (event.gui instanceof GuiSelectWorld || event.gui instanceof GuiMultiplayer) { + SettingsRegistry settingsRegistry = mod.getSettingsRegistry(); + boolean sp = event.gui instanceof GuiSelectWorld; + Setting setting = sp ? Setting.RECORD_SINGLEPLAYER : Setting.RECORD_SERVER; + + GuiCheckbox recordingCheckbox = new GuiCheckbox() + .setI18nLabel("replaymod.gui.settings.record" + (sp ? "singleplayer" : "server")) + .setChecked(settingsRegistry.get(setting)); + recordingCheckbox.onClick(() -> { + settingsRegistry.set(setting, recordingCheckbox.isChecked()); + settingsRegistry.save(); + }); + + VanillaGuiScreen.setup(event.gui).setLayout(new CustomLayout() { + @Override + protected void layout(GuiScreen container, int width, int height) { + //size(recordingCheckbox, 200, 20); + pos(recordingCheckbox, width - width(recordingCheckbox) - 5, 5); + } + }).addElements(null, recordingCheckbox); + } + } +} From e854635a34e8b8f94ff7492ec7424d213b218d9d Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 16 Jan 2018 14:51:07 +0100 Subject: [PATCH 15/23] Allow hiding of server IPs in replay viewer by pressing F1 (fixes #105) --- .../java/com/replaymod/replay/Setting.java | 5 ++++ .../replay/gui/screen/GuiReplayViewer.java | 23 +++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/replaymod/replay/Setting.java b/src/main/java/com/replaymod/replay/Setting.java index aa2a6256..a16e42e7 100644 --- a/src/main/java/com/replaymod/replay/Setting.java +++ b/src/main/java/com/replaymod/replay/Setting.java @@ -4,6 +4,7 @@ import com.replaymod.core.SettingsRegistry; public final class Setting extends SettingsRegistry.SettingKeys { public static final Setting SHOW_CHAT = make("showChat", "showchat", true); + public static final Setting SHOW_SERVER_IPS = new Setting<>("showServerIPs", true); public static final SettingsRegistry.MultipleChoiceSettingKeys CAMERA = new SettingsRegistry.MultipleChoiceSettingKeys<>( "replay", "camera", "replaymod.gui.settings.camera", "replaymod.camera.classic"); @@ -15,4 +16,8 @@ public final class Setting extends SettingsRegistry.SettingKeys { public Setting(String key, String displayString, T defaultValue) { super("replay", key, "replaymod.gui.settings." + displayString, defaultValue); } + + public Setting(String key, T defaultValue) { + super("replay", key, null, defaultValue); + } } 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 e9bd1d4e..6ce4bb39 100755 --- a/src/main/java/com/replaymod/replay/gui/screen/GuiReplayViewer.java +++ b/src/main/java/com/replaymod/replay/gui/screen/GuiReplayViewer.java @@ -5,9 +5,12 @@ import com.google.common.base.Supplier; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.mojang.realmsclient.gui.ChatFormatting; +import com.replaymod.core.ReplayMod; +import com.replaymod.core.SettingsRegistry; import com.replaymod.core.gui.GuiReplaySettings; import com.replaymod.core.utils.Utils; import com.replaymod.replay.ReplayModReplay; +import com.replaymod.replay.Setting; import com.replaymod.replaystudio.replay.ReplayFile; import com.replaymod.replaystudio.replay.ReplayMetaData; import com.replaymod.replaystudio.replay.ZipReplayFile; @@ -18,6 +21,7 @@ import de.johni0702.minecraft.gui.container.GuiPanel; import de.johni0702.minecraft.gui.container.GuiScreen; import de.johni0702.minecraft.gui.element.*; import de.johni0702.minecraft.gui.element.advanced.GuiResourceLoadingList; +import de.johni0702.minecraft.gui.function.Typeable; import de.johni0702.minecraft.gui.layout.CustomLayout; import de.johni0702.minecraft.gui.layout.GridLayout; import de.johni0702.minecraft.gui.layout.HorizontalLayout; @@ -34,8 +38,10 @@ import org.apache.commons.io.filefilter.SuffixFileFilter; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.core.helpers.Strings; import org.lwjgl.Sys; +import org.lwjgl.input.Keyboard; import org.lwjgl.util.Dimension; import org.lwjgl.util.ReadableDimension; +import org.lwjgl.util.ReadablePoint; import java.awt.*; import java.awt.image.BufferedImage; @@ -47,7 +53,7 @@ import java.util.Date; import static com.replaymod.replay.ReplayModReplay.LOGGER; -public class GuiReplayViewer extends GuiScreen { +public class GuiReplayViewer extends GuiScreen implements Typeable { private final ReplayModReplay mod; public final GuiResourceLoadingList list = new GuiResourceLoadingList(this).onSelectionChanged(new Runnable() { @@ -272,6 +278,18 @@ public class GuiReplayViewer extends GuiScreen { } private final GuiImage defaultThumbnail = new GuiImage().setTexture(Utils.DEFAULT_THUMBNAIL); + + @Override + public boolean typeKey(ReadablePoint mousePosition, int keyCode, char keyChar, boolean ctrlDown, boolean shiftDown) { + if (keyCode == Keyboard.KEY_F1) { + SettingsRegistry reg = ReplayMod.instance.getSettingsRegistry(); + reg.set(Setting.SHOW_SERVER_IPS, !reg.get(Setting.SHOW_SERVER_IPS)); + reg.save(); + list.load(); + } + return false; + } + public class GuiReplayEntry extends AbstractGuiContainer implements Comparable { public final File file; public final GuiLabel name = new GuiLabel(); @@ -303,7 +321,8 @@ public class GuiReplayViewer extends GuiScreen { this.file = file; name.setText(ChatFormatting.UNDERLINE + Utils.fileNameToReplayName(file.getName())); - if (Strings.isEmpty(metaData.getServerName())) { + if (Strings.isEmpty(metaData.getServerName()) + || !ReplayMod.instance.getSettingsRegistry().get(Setting.SHOW_SERVER_IPS)) { server.setI18nText("replaymod.gui.iphidden").setColor(Colors.DARK_RED); } else { server.setText(metaData.getServerName()); From 5a1e893a45061f0e444cbabe8318d56eaedffee3 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 16 Jan 2018 15:08:17 +0100 Subject: [PATCH 16/23] Deselect marker when selecting keyframe (and vice versa) (fixes #104) --- .../simplepathing/ReplayModSimplePathing.java | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/replaymod/simplepathing/ReplayModSimplePathing.java b/src/main/java/com/replaymod/simplepathing/ReplayModSimplePathing.java index ecb1e436..6d61e4f1 100644 --- a/src/main/java/com/replaymod/simplepathing/ReplayModSimplePathing.java +++ b/src/main/java/com/replaymod/simplepathing/ReplayModSimplePathing.java @@ -2,8 +2,10 @@ package com.replaymod.simplepathing; import com.replaymod.core.ReplayMod; import com.replaymod.core.events.SettingsChangedEvent; +import com.replaymod.replay.ReplayModReplay; import com.replaymod.replay.events.ReplayCloseEvent; import com.replaymod.replay.events.ReplayOpenEvent; +import com.replaymod.replay.gui.overlay.GuiReplayOverlay; import com.replaymod.replaystudio.pathing.path.Keyframe; import com.replaymod.simplepathing.SPTimeline.SPPath; import com.replaymod.simplepathing.gui.GuiPathing; @@ -81,20 +83,34 @@ public class ReplayModSimplePathing { } } + private GuiReplayOverlay getReplayOverlay() { + return ReplayModReplay.instance.getReplayHandler().getOverlay(); + } + private SPTimeline currentTimeline; - @Getter private SPPath selectedPath; @Getter private long selectedTime; + public SPPath getSelectedPath() { + if (getReplayOverlay().timeline.getSelectedMarker() != null) { + selectedPath = null; + selectedTime = 0; + } + return selectedPath; + } + public boolean isSelected(Keyframe keyframe) { - return selectedPath != null && currentTimeline.getKeyframe(selectedPath, selectedTime) == keyframe; + return getSelectedPath() != null && currentTimeline.getKeyframe(selectedPath, selectedTime) == keyframe; } public void setSelected(SPPath path, long time) { selectedPath = path; selectedTime = time; + if (selectedPath != null) { + getReplayOverlay().timeline.setSelectedMarker(null); + } } public void setCurrentTimeline(SPTimeline newTimeline) { From 23c5df5aaadf6d86b198845eb7a40b1e236413ff Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 16 Jan 2018 16:01:59 +0100 Subject: [PATCH 17/23] Allow the mod to be loaded in a dedicated server environment --- src/main/java/com/replaymod/compat/ReplayModCompat.java | 1 + src/main/java/com/replaymod/core/ReplayMod.java | 1 + src/main/java/com/replaymod/editor/ReplayModEditor.java | 1 + src/main/java/com/replaymod/extras/ReplayModExtras.java | 1 + src/main/java/com/replaymod/online/ReplayModOnline.java | 1 + .../java/com/replaymod/recording/ReplayModRecording.java | 1 + src/main/java/com/replaymod/render/ReplayModRender.java | 1 + src/main/java/com/replaymod/replay/ReplayModReplay.java | 1 + .../com/replaymod/simplepathing/ReplayModSimplePathing.java | 1 + src/main/resources/mixins.render.replaymod.json | 6 +++--- src/main/resources/mixins.replay.replaymod.json | 6 +++--- 11 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/replaymod/compat/ReplayModCompat.java b/src/main/java/com/replaymod/compat/ReplayModCompat.java index 7de27c26..a5a23fea 100644 --- a/src/main/java/com/replaymod/compat/ReplayModCompat.java +++ b/src/main/java/com/replaymod/compat/ReplayModCompat.java @@ -15,6 +15,7 @@ import org.apache.logging.log4j.Logger; version = "@MOD_VERSION@", acceptedMinecraftVersions = "@MC_VERSION@", acceptableRemoteVersions = "*", + clientSideOnly = true, useMetadata = true) public class ReplayModCompat { public static final String MOD_ID = "replaymod-compat"; diff --git a/src/main/java/com/replaymod/core/ReplayMod.java b/src/main/java/com/replaymod/core/ReplayMod.java index 86cf4877..70f9a81c 100755 --- a/src/main/java/com/replaymod/core/ReplayMod.java +++ b/src/main/java/com/replaymod/core/ReplayMod.java @@ -41,6 +41,7 @@ import java.util.Queue; version = "@MOD_VERSION@", acceptedMinecraftVersions = "@MC_VERSION@", acceptableRemoteVersions = "*", + clientSideOnly = true, updateJSON = "https://raw.githubusercontent.com/ReplayMod/ReplayMod/master/versions.json", guiFactory = "com.replaymod.core.gui.GuiFactory") public class ReplayMod { diff --git a/src/main/java/com/replaymod/editor/ReplayModEditor.java b/src/main/java/com/replaymod/editor/ReplayModEditor.java index 7749f5c0..ddc9b61c 100644 --- a/src/main/java/com/replaymod/editor/ReplayModEditor.java +++ b/src/main/java/com/replaymod/editor/ReplayModEditor.java @@ -12,6 +12,7 @@ import org.apache.logging.log4j.Logger; version = "@MOD_VERSION@", acceptedMinecraftVersions = "@MC_VERSION@", acceptableRemoteVersions = "*", + clientSideOnly = true, useMetadata = true) public class ReplayModEditor { public static final String MOD_ID = "replaymod-editor"; diff --git a/src/main/java/com/replaymod/extras/ReplayModExtras.java b/src/main/java/com/replaymod/extras/ReplayModExtras.java index 463e8805..3dd7a033 100644 --- a/src/main/java/com/replaymod/extras/ReplayModExtras.java +++ b/src/main/java/com/replaymod/extras/ReplayModExtras.java @@ -20,6 +20,7 @@ import java.util.Optional; version = "@MOD_VERSION@", acceptedMinecraftVersions = "@MC_VERSION@", acceptableRemoteVersions = "*", + clientSideOnly = true, useMetadata = true) public class ReplayModExtras { public static final String MOD_ID = "replaymod-extras"; diff --git a/src/main/java/com/replaymod/online/ReplayModOnline.java b/src/main/java/com/replaymod/online/ReplayModOnline.java index 44092066..cf1d7f6e 100644 --- a/src/main/java/com/replaymod/online/ReplayModOnline.java +++ b/src/main/java/com/replaymod/online/ReplayModOnline.java @@ -30,6 +30,7 @@ import static net.minecraft.client.Minecraft.getMinecraft; version = "@MOD_VERSION@", acceptedMinecraftVersions = "@MC_VERSION@", acceptableRemoteVersions = "*", + clientSideOnly = true, useMetadata = true) public class ReplayModOnline { public static final String MOD_ID = "replaymod-online"; diff --git a/src/main/java/com/replaymod/recording/ReplayModRecording.java b/src/main/java/com/replaymod/recording/ReplayModRecording.java index afdd4340..c8d68dd6 100644 --- a/src/main/java/com/replaymod/recording/ReplayModRecording.java +++ b/src/main/java/com/replaymod/recording/ReplayModRecording.java @@ -21,6 +21,7 @@ import org.lwjgl.input.Keyboard; version = "@MOD_VERSION@", acceptedMinecraftVersions = "@MC_VERSION@", acceptableRemoteVersions = "*", + clientSideOnly = true, useMetadata = true) public class ReplayModRecording { public static final String MOD_ID = "replaymod-recording"; diff --git a/src/main/java/com/replaymod/render/ReplayModRender.java b/src/main/java/com/replaymod/render/ReplayModRender.java index 6b7f3668..3a5852de 100644 --- a/src/main/java/com/replaymod/render/ReplayModRender.java +++ b/src/main/java/com/replaymod/render/ReplayModRender.java @@ -22,6 +22,7 @@ import java.util.List; version = "@MOD_VERSION@", acceptedMinecraftVersions = "@MC_VERSION@", acceptableRemoteVersions = "*", + clientSideOnly = true, useMetadata = true) public class ReplayModRender { public static final String MOD_ID = "replaymod-render"; diff --git a/src/main/java/com/replaymod/replay/ReplayModReplay.java b/src/main/java/com/replaymod/replay/ReplayModReplay.java index d6ef677d..88a65f19 100644 --- a/src/main/java/com/replaymod/replay/ReplayModReplay.java +++ b/src/main/java/com/replaymod/replay/ReplayModReplay.java @@ -36,6 +36,7 @@ import java.util.Optional; version = "@MOD_VERSION@", acceptedMinecraftVersions = "@MC_VERSION@", acceptableRemoteVersions = "*", + clientSideOnly = true, useMetadata = true) public class ReplayModReplay { public static final String MOD_ID = "replaymod-replay"; diff --git a/src/main/java/com/replaymod/simplepathing/ReplayModSimplePathing.java b/src/main/java/com/replaymod/simplepathing/ReplayModSimplePathing.java index 6d61e4f1..86cb94ca 100644 --- a/src/main/java/com/replaymod/simplepathing/ReplayModSimplePathing.java +++ b/src/main/java/com/replaymod/simplepathing/ReplayModSimplePathing.java @@ -22,6 +22,7 @@ import org.lwjgl.input.Keyboard; version = "@MOD_VERSION@", acceptedMinecraftVersions = "@MC_VERSION@", acceptableRemoteVersions = "*", + clientSideOnly = true, useMetadata = true) public class ReplayModSimplePathing { public static final String MOD_ID = "replaymod-simplepathing"; diff --git a/src/main/resources/mixins.render.replaymod.json b/src/main/resources/mixins.render.replaymod.json index 539d1c55..58617e59 100644 --- a/src/main/resources/mixins.render.replaymod.json +++ b/src/main/resources/mixins.render.replaymod.json @@ -1,7 +1,9 @@ { "required": true, "package": "com.replaymod.render.mixin", - "mixins": [ + "mixins": [], + "server": [], + "client": [ "MixinEffectRenderer", "MixinEntityRenderer", "MixinFrustum", @@ -10,8 +12,6 @@ "MixinRenderGlobal", "MixinRenderManager" ], - "server": [], - "client": [], "compatibilityLevel": "JAVA_8", "minVersion": "0.6.11", "refmap": "mixins.replaymod.refmap.json" diff --git a/src/main/resources/mixins.replay.replaymod.json b/src/main/resources/mixins.replay.replaymod.json index e92257fb..c3471556 100644 --- a/src/main/resources/mixins.replay.replaymod.json +++ b/src/main/resources/mixins.replay.replaymod.json @@ -1,7 +1,9 @@ { "required": true, "package": "com.replaymod.replay.mixin", - "mixins": [ + "mixins": [], + "server": [], + "client": [ "MixinGuiSpectator", "MixinPlayerControllerMP", "MixinRenderArrow", @@ -12,8 +14,6 @@ "MixinViewFrustum", "MixinWorldClient" ], - "server": [], - "client": [], "compatibilityLevel": "JAVA_8", "minVersion": "0.6.11", "refmap": "mixins.replaymod.refmap.json" From eb916c395b39cc682c483d717ae12e8994ed669e Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 16 Jan 2018 16:03:04 +0100 Subject: [PATCH 18/23] Add forge server mod for ReplayRestrictions (fixes #102) --- .../restrictions/ReplayModRestrictions.java | 95 +++++++++++++++++++ .../com/replaymod/restrictions/Setting.java | 19 ++++ src/main/resources/mcmod.info | 16 ++++ 3 files changed, 130 insertions(+) create mode 100644 src/main/java/com/replaymod/restrictions/ReplayModRestrictions.java create mode 100644 src/main/java/com/replaymod/restrictions/Setting.java diff --git a/src/main/java/com/replaymod/restrictions/ReplayModRestrictions.java b/src/main/java/com/replaymod/restrictions/ReplayModRestrictions.java new file mode 100644 index 00000000..9a0fbd28 --- /dev/null +++ b/src/main/java/com/replaymod/restrictions/ReplayModRestrictions.java @@ -0,0 +1,95 @@ +package com.replaymod.restrictions; + +import com.replaymod.core.SettingsRegistry; +import com.replaymod.core.utils.Restrictions; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandler; +import net.minecraft.network.PacketBuffer; +import net.minecraftforge.common.config.Configuration; +import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.event.FMLInitializationEvent; +import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; +import net.minecraftforge.fml.common.eventhandler.EventBus; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.PlayerEvent; +import net.minecraftforge.fml.common.network.FMLEmbeddedChannel; +import net.minecraftforge.fml.common.network.FMLOutboundHandler; +import net.minecraftforge.fml.common.network.NetworkRegistry; +import net.minecraftforge.fml.common.network.internal.FMLProxyPacket; +import net.minecraftforge.fml.relauncher.Side; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +@Mod(modid = ReplayModRestrictions.MOD_ID, + version = "@MOD_VERSION@", + acceptedMinecraftVersions = "@MC_VERSION@", + acceptableRemoteVersions = "*", + serverSideOnly = true, + useMetadata = true) +public class ReplayModRestrictions { + public static final String MOD_ID = "replaymod-restrictions"; + + public static Logger LOGGER; + + private final SettingsRegistry settingsRegistry = new SettingsRegistry(); + private FMLEmbeddedChannel channel; + + @Mod.EventHandler + public void preInit(FMLPreInitializationEvent event) { + LOGGER = event.getModLog(); + + Configuration config = new Configuration(event.getSuggestedConfigurationFile()); + config.load(); + settingsRegistry.setConfiguration(config); + + settingsRegistry.register(Setting.class); + } + + @Mod.EventHandler + public void init(FMLInitializationEvent event) { + EventBus bus = FMLCommonHandler.instance().bus(); + bus.register(this); + + channel = NetworkRegistry.INSTANCE.newChannel(Restrictions.PLUGIN_CHANNEL, new RestrictionsChannelHandler()).get(Side.SERVER); + } + + @Mod.EventHandler + public void postInit(FMLPostInitializationEvent event) throws IOException { + settingsRegistry.save(); // Save default values to disk + } + + @ChannelHandler.Sharable + private static class RestrictionsChannelHandler extends ChannelDuplexHandler {} + + @SubscribeEvent + public void onUserJoin(PlayerEvent.PlayerLoggedInEvent event) { + Map restrictions = new HashMap<>(); + if (settingsRegistry.get(Setting.NO_XRAY)) restrictions.put("no_xray", new byte[0]); + if (settingsRegistry.get(Setting.NO_NOCLIP)) restrictions.put("no_noclip", new byte[0]); + if (settingsRegistry.get(Setting.ONLY_FIRST_PERSON)) restrictions.put("only_first_person", new byte[0]); + if (settingsRegistry.get(Setting.ONLY_RECORDING_PLAYER)) restrictions.put("only_recording_player", new byte[0]); + if (settingsRegistry.get(Setting.HIDE_COORDINATES)) restrictions.put("hide_coordinates", new byte[0]); + + PacketBuffer buf = new PacketBuffer(Unpooled.buffer()); + for (Map.Entry e : restrictions.entrySet()) { + byte[] bytes = e.getKey().getBytes(); + buf.writeByte(bytes.length); + buf.writeBytes(bytes); + buf.writeByte(1); + buf.writeBytes(e.getValue()); + } + + FMLProxyPacket packet = new FMLProxyPacket(buf, Restrictions.PLUGIN_CHANNEL); + + channel.attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.PLAYER); + channel.attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(event.player); + channel.writeAndFlush(packet).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); + } +} diff --git a/src/main/java/com/replaymod/restrictions/Setting.java b/src/main/java/com/replaymod/restrictions/Setting.java new file mode 100644 index 00000000..7a36e936 --- /dev/null +++ b/src/main/java/com/replaymod/restrictions/Setting.java @@ -0,0 +1,19 @@ +package com.replaymod.restrictions; + +import com.replaymod.core.SettingsRegistry; + +public final class Setting extends SettingsRegistry.SettingKeys { + public static final Setting NO_XRAY = make("no_xray", false); + public static final Setting NO_NOCLIP = make("no_noclip", false); + public static final Setting ONLY_FIRST_PERSON = make("only_first_person", false); + public static final Setting ONLY_RECORDING_PLAYER = make("only_recording_player", false); + public static final Setting HIDE_COORDINATES = make("hide_coordinates", false); + + private static Setting make(String key, T defaultValue) { + return new Setting<>("restrictions", key, defaultValue); + } + + public Setting(String category, String key, T defaultValue) { + super(category, key, null, defaultValue); + } +} diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info index 065f181d..3cd255eb 100755 --- a/src/main/resources/mcmod.info +++ b/src/main/resources/mcmod.info @@ -134,6 +134,22 @@ "screenshots": [], "dependencies": [] }, + { + "modid": "replaymod-restrictions", + "name": "Replay Mod - Restrictions", + "description": "Server-side Restrictions Module of the ReplayMod - Restrict what clients can do in replays", + "version": "${version}", + "mcversion": "${mcversion}", + "url": "https://replaymod.com", + "updateUrl": "https://replaymod.com/download", + "authorList": [ + "CrushedPixel", + "johni0702" + ], + "logoFile": "replaymod_logo.png", + "screenshots": [], + "dependencies": [] + }, { "modid": "replaymod-compat", "name": "Replay Mod - Compatibility", From d7368d8c87b454f94029cce9e4f6a363951b93be Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 16 Jan 2018 16:05:08 +0100 Subject: [PATCH 19/23] Remove 5 character restriction from user names (fixes #97) --- src/main/java/com/replaymod/online/gui/GuiRegister.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/replaymod/online/gui/GuiRegister.java b/src/main/java/com/replaymod/online/gui/GuiRegister.java index 574a6c05..08c78f29 100644 --- a/src/main/java/com/replaymod/online/gui/GuiRegister.java +++ b/src/main/java/com/replaymod/online/gui/GuiRegister.java @@ -110,7 +110,7 @@ public class GuiRegister extends AbstractGuiScreen { @Override public void run() { String status = null; - if (usernameInput.getText().length() < 5) { + if (usernameInput.getText().length() < 1) { status = "replaymod.gui.register.error.shortusername"; } else if(!Patterns.ALPHANUMERIC_UNDERSCORE.matcher(usernameInput.getText().trim()).matches()) { status = "replaymod.gui.register.error.invalidname"; From 22e4ce4584492c15eaa74688903eb1e3c29de02b Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 16 Jan 2018 16:14:03 +0100 Subject: [PATCH 20/23] Make sure the replay is stopped if the main menu is opened (fixes #95) --- .../com/replaymod/replay/ReplayModReplay.java | 4 ++++ .../com/replaymod/replay/handler/GuiHandler.java | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/main/java/com/replaymod/replay/ReplayModReplay.java b/src/main/java/com/replaymod/replay/ReplayModReplay.java index 88a65f19..a19741ca 100644 --- a/src/main/java/com/replaymod/replay/ReplayModReplay.java +++ b/src/main/java/com/replaymod/replay/ReplayModReplay.java @@ -195,6 +195,10 @@ public class ReplayModReplay { replayHandler = new ReplayHandler(replayFile, true); } + public void forcefullyStopReplay() { + replayHandler = null; + } + public ReplayMod getCore() { return core; } diff --git a/src/main/java/com/replaymod/replay/handler/GuiHandler.java b/src/main/java/com/replaymod/replay/handler/GuiHandler.java index f05d2971..cad20d5a 100644 --- a/src/main/java/com/replaymod/replay/handler/GuiHandler.java +++ b/src/main/java/com/replaymod/replay/handler/GuiHandler.java @@ -16,6 +16,8 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import static com.replaymod.replay.ReplayModReplay.LOGGER; + public class GuiHandler { private static final int BUTTON_EXIT_SERVER = 1; private static final int BUTTON_ACHIEVEMENTS = 5; @@ -102,6 +104,20 @@ public class GuiHandler { return; } + if (mod.getReplayHandler() != null) { + // Something went terribly wrong and we ended up in the main menu with the replay still active. + // To prevent players from joining live servers and using the CameraEntity, try to stop the replay now. + try { + mod.getReplayHandler().endReplay(); + } catch (IOException e) { + LOGGER.error("Trying to stop broken replay: ", e); + } finally { + if (mod.getReplayHandler() != null) { + mod.forcefullyStopReplay(); + } + } + } + @SuppressWarnings("unchecked") List buttonList = event.buttonList; GuiButton button = new GuiButton(BUTTON_REPLAY_VIEWER, event.gui.width / 2 - 100, From ea2427a73c54781fa73d5074b9476bf2ac4d1bcc Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 16 Jan 2018 21:52:05 +0100 Subject: [PATCH 21/23] Create screenshot folder it it does not yet exist --- .../replaymod/extras/advancedscreenshots/ScreenshotWriter.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotWriter.java b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotWriter.java index c601f28f..fcabe95c 100644 --- a/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotWriter.java +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotWriter.java @@ -43,6 +43,7 @@ public class ScreenshotWriter implements FrameConsumer { } } + outputFile.getParentFile().mkdirs(); ImageIO.write(img, "PNG", outputFile); } catch (OutOfMemoryError e) { e.printStackTrace(); From 87335cd243d00d7ee5ed1166023555c596a9c755 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Wed, 17 Jan 2018 00:12:42 +0100 Subject: [PATCH 22/23] Add lombok-1.16.4.jar to checksums list --- gradle/reprod/checksums.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/gradle/reprod/checksums.txt b/gradle/reprod/checksums.txt index 5c937d3d..c5241a1b 100644 --- a/gradle/reprod/checksums.txt +++ b/gradle/reprod/checksums.txt @@ -411,6 +411,7 @@ cbfacd5dd812db16dc910994007fe58d9402a25507f81a1c2218e15c2c1bedfa /org/ow2/asm/as 347a7a9400f9964e87c91d3980e48eebdc8d024bc3b36f7f22189c662853a51c /org/ow2/asm/asm-tree/5.0.3/asm-tree-5.0.3.jar 65819ca7c5a218ff49f8ebe72f3b39219c81f137d017acc1aec15b1054cf5236 /org/ow2/asm/asm-tree/5.0.3/asm-tree-5.0.3.pom 51215c67d2c068d8b7d2f6f80f51372a098075deccc448d4bdd7b987ba8328fb /org/ow2/ow2/1.3/ow2-1.3.pom +3ca225ce3917eac8bf4b7d2186845df4e70dcdede356dca8537b6d78a535c91e /org/projectlombok/lombok/1.16.4/lombok-1.16.4.jar fcb8d5745f776567f1cce332282750b1653568324621ecef03288c8a25919d0e /org/projectlombok/lombok/1.16.4/lombok-1.16.4.pom e0a471be03e1e6b02bf019480cec7a3ac9801702bf7bf62f15d077ad4df8dd5d /org/projectlombok/lombok/1.16.6/lombok-1.16.6.jar 32ac0a2363ccc0c5086b62cfc05e28a355b74e155efef6b426f5498a0dfc9e4c /org/projectlombok/lombok/1.16.6/lombok-1.16.6.pom From 0f004537afeb0a8e6b725d2c6c22b4632abb65b6 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Wed, 17 Jan 2018 19:20:29 +0100 Subject: [PATCH 23/23] Whitelist version.json checksum Why is there even a sha1 value in the URL if the file can change? --- gradle/reprod/checksums.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/reprod/checksums.txt b/gradle/reprod/checksums.txt index 6307f3d7..216a861a 100644 --- a/gradle/reprod/checksums.txt +++ b/gradle/reprod/checksums.txt @@ -164,7 +164,7 @@ a096bc9f7579cec07483874151578720eeb3189c546c19cff56a6203df17b50e /lzma/lzma/0.0. * /mc/game/version_manifest.json 59e84cf6acc3912e1705ab05c722485afb3ec33343eef4756d8c16edfe6411ca /mc/game/1.12/client/909823f9c467f9934687f136bc95a667a0d19d7f/client.jar feebff3834e41cc096522525707d2dd27adc2431b1f3145b9d0ccfc4c8a3dc09 /mc/game/1.12/server/8494e844e911ea0d63878f64da9dcc21f53a3463/server.jar -096e451c3a9902af2637a1b703ae5fe2063e253d39390448c73355b98b2e906a /mc/game/71579a8bd04a542218613d8015aaf386b84c6ba1/1.12.json +* /mc/game/71579a8bd04a542218613d8015aaf386b84c6ba1/1.12.json c4dadeeecaa90c8847902082aee5eb107fcf59c5d0e63a17fcaf273c0e2d2bd1 /net/java/dev/jna/jna/4.4.0/jna-4.4.0.jar 800bb2831dda341336ea69b7beb675f159973f64dad6aaa1ad8c4fa78e5cb19b /net/java/dev/jna/jna/4.4.0/jna-4.4.0.pom ea89d5090c8303ba4e9a0056e6d8a20429f3e021411e950bfd9eba3b6e6cf15c /net/java/dev/jna/platform/3.4.0/platform-3.4.0.jar