diff --git a/build.gradle b/build.gradle index a31e6e47..64b486fe 100755 --- a/build.gradle +++ b/build.gradle @@ -99,4 +99,8 @@ processResources } } +sourceSets { + main { output.resourcesDir = output.classesDir } +} + defaultTasks 'build' \ No newline at end of file diff --git a/src/main/java/eu/crushedpixel/replaymod/events/KeyInputHandler.java b/src/main/java/eu/crushedpixel/replaymod/events/KeyInputHandler.java index 88a12bf0..87556c35 100755 --- a/src/main/java/eu/crushedpixel/replaymod/events/KeyInputHandler.java +++ b/src/main/java/eu/crushedpixel/replaymod/events/KeyInputHandler.java @@ -98,8 +98,7 @@ public class KeyInputHandler { //Custom registered handlers if(kb.getKeyDescription().equals(KeybindRegistry.KEY_THUMBNAIL) && kb.isPressed() && !found) { - ReplayScreenshot.prepareScreenshot(); - //GuiReplayOverlay.requestScreenshot(); + TickAndRenderListener.requestScreenshot(); //TODO: Make this properly work } diff --git a/src/main/java/eu/crushedpixel/replaymod/events/TickAndRenderListener.java b/src/main/java/eu/crushedpixel/replaymod/events/TickAndRenderListener.java index 7926fd87..6a40c4f4 100644 --- a/src/main/java/eu/crushedpixel/replaymod/events/TickAndRenderListener.java +++ b/src/main/java/eu/crushedpixel/replaymod/events/TickAndRenderListener.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; +import eu.crushedpixel.replaymod.chat.ChatMessageRequests; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; import org.lwjgl.opengl.Display; @@ -39,11 +40,30 @@ public class TickAndRenderListener { e.printStackTrace(); } } - + @SubscribeEvent public void onRenderWorld(RenderWorldLastEvent event) throws InvocationTargetException, IOException, IllegalAccessException, IllegalArgumentException { - if(!ReplayHandler.isInReplay()) return; + if(!ReplayHandler.isInReplay()) return; //If not in Replay, cancel + + if(requestScreenshot == 1) { + mc.addScheduledTask(new Runnable() { + @Override + public void run() { + ChatMessageRequests.addChatMessage("Saving Thumbnail...", ChatMessageRequests.ChatMessageType.INFORMATION); + ReplayScreenshot.prepareScreenshot(); + requestScreenshot = 2; + } + }); + } else if(requestScreenshot == 2) { + mc.addScheduledTask(new Runnable() { + @Override + public void run() { + ReplayScreenshot.saveScreenshot(); + } + }); + } + if(ReplayHandler.isInPath()) ReplayProcess.unblockAndTick(false); if(ReplayHandler.isCamera()) ReplayHandler.setCameraEntity(ReplayHandler.getCameraEntity()); if(ReplayHandler.isInReplay() && ReplayHandler.isPaused()) { @@ -60,19 +80,24 @@ public class TickAndRenderListener { lastPitch = mc.getRenderViewEntity().rotationPitch; lastYaw = mc.getRenderViewEntity().rotationYaw; } - /* - if(requestScreenshot) { - requestScreenshot = false; - ReplayScreenshot.saveScreenshot(mc.getFramebuffer()); - } - */ + if(mc.isGamePaused() && ReplayHandler.isInPath()) { isGamePaused.set(mc, false); } } //private boolean f1Down = false; - + + private static int requestScreenshot = 0; + + public static void requestScreenshot() { + if(requestScreenshot == 0) requestScreenshot = 1; + } + + public static void finishScreenshot() { + requestScreenshot = 0; + } + @SubscribeEvent public void tick(TickEvent event) { if(!ReplayHandler.isInReplay()) return; diff --git a/src/main/java/eu/crushedpixel/replaymod/recording/ConnectionEventHandler.java b/src/main/java/eu/crushedpixel/replaymod/recording/ConnectionEventHandler.java index 5d6d43ed..038f816a 100755 --- a/src/main/java/eu/crushedpixel/replaymod/recording/ConnectionEventHandler.java +++ b/src/main/java/eu/crushedpixel/replaymod/recording/ConnectionEventHandler.java @@ -1,8 +1,18 @@ package eu.crushedpixel.replaymod.recording; +import eu.crushedpixel.replaymod.ReplayMod; +import eu.crushedpixel.replaymod.chat.ChatMessageRequests; +import eu.crushedpixel.replaymod.chat.ChatMessageRequests.ChatMessageType; +import eu.crushedpixel.replaymod.utils.ReplayFileIO; import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelPipeline; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.Packet; +import net.minecraft.server.MinecraftServer; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientConnectedToServerEvent; +import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientDisconnectionFromServerEvent; import java.io.File; import java.net.InetSocketAddress; @@ -13,19 +23,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map.Entry; -import sun.java2d.SunGraphics2D; -import net.minecraft.network.NetworkManager; -import net.minecraft.network.Packet; -import net.minecraft.network.play.server.S42PacketCombatEvent; -import net.minecraft.server.MinecraftServer; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientConnectedToServerEvent; -import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientDisconnectionFromServerEvent; -import eu.crushedpixel.replaymod.ReplayMod; -import eu.crushedpixel.replaymod.chat.ChatMessageRequests; -import eu.crushedpixel.replaymod.chat.ChatMessageRequests.ChatMessageType; -import eu.crushedpixel.replaymod.utils.ReplayFileIO; - public class ConnectionEventHandler { private static final String decoderKey = "decoder"; diff --git a/src/main/java/eu/crushedpixel/replaymod/utils/ReplayFileIO.java b/src/main/java/eu/crushedpixel/replaymod/utils/ReplayFileIO.java index 72e7171d..06c56103 100755 --- a/src/main/java/eu/crushedpixel/replaymod/utils/ReplayFileIO.java +++ b/src/main/java/eu/crushedpixel/replaymod/utils/ReplayFileIO.java @@ -1,47 +1,32 @@ package eu.crushedpixel.replaymod.utils; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; - -import java.io.BufferedReader; -import java.io.DataInputStream; -import java.io.DataOutput; -import java.io.EOFException; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.PrintWriter; -import java.io.RandomAccessFile; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - -import net.minecraft.network.EnumConnectionState; -import net.minecraft.network.EnumPacketDirection; -import net.minecraft.network.Packet; -import net.minecraft.network.PacketBuffer; -import net.minecraft.network.play.server.S01PacketJoinGame; -import net.minecraft.network.play.server.S08PacketPlayerPosLook; - -import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; -import org.apache.commons.compress.archivers.zip.ZipFile; -import org.apache.commons.io.FilenameUtils; - import akka.japi.Pair; - import com.google.gson.Gson; - import eu.crushedpixel.replaymod.ReplayMod; import eu.crushedpixel.replaymod.holders.PacketData; import eu.crushedpixel.replaymod.recording.ConnectionEventHandler; import eu.crushedpixel.replaymod.recording.PacketSerializer; import eu.crushedpixel.replaymod.recording.ReplayMetaData; import eu.crushedpixel.replaymod.replay.PacketDeserializer; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import net.minecraft.network.EnumConnectionState; +import net.minecraft.network.EnumPacketDirection; +import net.minecraft.network.Packet; +import net.minecraft.network.PacketBuffer; +import net.minecraft.network.play.server.S01PacketJoinGame; +import net.minecraft.network.play.server.S08PacketPlayerPosLook; +import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; +import org.apache.commons.compress.archivers.zip.ZipFile; +import org.apache.commons.io.FilenameUtils; + +import java.io.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; @SuppressWarnings("resource") //Gets handled by finalizer public class ReplayFileIO { @@ -51,7 +36,7 @@ public class ReplayFileIO { folder.mkdirs(); return folder; } - + public static File getReplayFolder() { String path = ReplayMod.replaySettings.getRecordingPath(); File folder = new File(path); @@ -237,7 +222,7 @@ public class ReplayFileIO { private static boolean lastContainsJoinPacket = false; /** - * + * * @param replayFile The File to reverse * @param outputFile The File to save the reversed Packets in * @param seekJoinPacket Whether a {@link S01PacketJoinGame} should be seeked in the Replay File. If containsJoinPacket is being @@ -319,4 +304,58 @@ public class ReplayFileIO { return false; } + + private static final byte[] uniqueBytes = new byte[]{0,1,1,2,3,5,8}; + + public static void addThumbToZip(File zipFile, File thumb) throws IOException { + // get a temp file + File tempFile = File.createTempFile(zipFile.getName(), null); + // delete it, otherwise you cannot rename your existing zip to it. + tempFile.delete(); + + zipFile.renameTo(tempFile); + + byte[] buf = new byte[1024]; + + ZipInputStream zin = new ZipInputStream(new FileInputStream(tempFile)); + ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile)); + + ZipEntry entry = zin.getNextEntry(); + while (entry != null) { + String name = entry.getName(); + boolean isThumb = name.contains("thumb"); + if(!isThumb) { + // Add ZIP entry to output stream. + out.putNextEntry(new ZipEntry(name)); + // Transfer bytes from the ZIP file to the output file + int len; + while ((len = zin.read(buf)) > 0) { + out.write(buf, 0, len); + } + } + entry = zin.getNextEntry(); + } + // Close the streams + zin.close(); + // Compress the files + + InputStream in = new FileInputStream(thumb); + // Add ZIP entry to output stream. + out.putNextEntry(new ZipEntry("thumb")); + // Transfer bytes from the file to the ZIP file + int len; + + out.write(uniqueBytes); + + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + // Complete the entry + out.closeEntry(); + in.close(); + + // Complete the ZIP file + out.close(); + tempFile.delete(); + } } diff --git a/src/main/java/eu/crushedpixel/replaymod/video/ReplayScreenshot.java b/src/main/java/eu/crushedpixel/replaymod/video/ReplayScreenshot.java index 7b2f3b10..fa8dcad4 100755 --- a/src/main/java/eu/crushedpixel/replaymod/video/ReplayScreenshot.java +++ b/src/main/java/eu/crushedpixel/replaymod/video/ReplayScreenshot.java @@ -13,6 +13,7 @@ import java.util.zip.ZipOutputStream; import javax.imageio.ImageIO; +import eu.crushedpixel.replaymod.events.TickAndRenderListener; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.renderer.GlStateManager; @@ -35,8 +36,6 @@ public class ReplayScreenshot { private static Minecraft mc = Minecraft.getMinecraft(); - private static final byte[] uniqueBytes = new byte[]{0,1,1,2,3,5,8}; - private static long last_finish = -1; private static boolean before; @@ -51,7 +50,7 @@ public class ReplayScreenshot { private static boolean locked = false; - public static void saveScreenshot(Framebuffer buffer) { + public static void saveScreenshot() { if(locked) return; locked = true; @@ -94,32 +93,28 @@ public class ReplayScreenshot { File replayFile = ReplayHandler.getReplayFile(); - File folder = ReplayFileIO.getReplayFolder(); - - File temp = File.createTempFile("thumb", null); + File tempImage = File.createTempFile("thumb", null); int h = 720; int w = 1280; BufferedImage img = ImageUtils.scaleImage(nbi, new Dimension(w, h)); - ImageIO.write(img, "jpg", temp); + ImageIO.write(img, "jpg", tempImage); - File tempFile = File.createTempFile(replayFile.getName(), null); - tempFile.delete(); tempFile.deleteOnExit(); + ReplayFileIO.addThumbToZip(replayFile, tempImage); - replayFile.renameTo(tempFile); + tempImage.delete(); - replayFile.delete(); - replayFile.createNewFile(); + /* + File outputFile = File.createTempFile(replayFile.getName(), null); byte[] buf = new byte[1024]; - ZipInputStream zin = new ZipInputStream(new FileInputStream(tempFile)); - ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(replayFile)); - - FileInputStream fis = new FileInputStream(temp); + ZipInputStream zin = new ZipInputStream(new FileInputStream(replayFile)); + ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(outputFile)); + //copying all of the old Zip Entries to the new file, unless it's a thumb ZipEntry entry = zin.getNextEntry(); while (entry != null) { String name = entry.getName(); @@ -137,6 +132,8 @@ public class ReplayScreenshot { entry = zin.getNextEntry(); } + FileInputStream fis = new FileInputStream(tempImage); + zout.putNextEntry(new ZipEntry("thumb")); int len; //Add unique bytes to the end of the file @@ -146,21 +143,26 @@ public class ReplayScreenshot { zout.write(buf, 0, len); } - // Close the streams + fis.close(); zin.close(); - // Compress the files - // Complete the ZIP file + zout.close(); - tempFile.delete(); - temp.delete(); - System.out.println("thumbnail saving finished"); + + replayFile.delete(); + outputFile.renameTo(replayFile); + + tempImage.delete(); + */ ChatMessageRequests.addChatMessage("Thumbnail has been successfully saved", ChatMessageType.INFORMATION); - } catch(Exception e) {} + } catch(Exception e) { + e.printStackTrace(); + } finally { GuiReplaySaving.replaySaving = false; locked = false; + TickAndRenderListener.finishScreenshot(); } } }); @@ -168,6 +170,7 @@ public class ReplayScreenshot { ioThread.start(); } catch (Exception exception) { + exception.printStackTrace(); mc.gameSettings.hideGUI = before; mc.currentScreen = beforeScreen; ReplayHandler.setSpeed(beforeSpeed);