diff --git a/src/main/java/eu/crushedpixel/replaymod/ReplayMod.java b/src/main/java/eu/crushedpixel/replaymod/ReplayMod.java index 8a54b0d6..bf162843 100755 --- a/src/main/java/eu/crushedpixel/replaymod/ReplayMod.java +++ b/src/main/java/eu/crushedpixel/replaymod/ReplayMod.java @@ -75,18 +75,8 @@ public class ReplayMod config = new Configuration(event.getSuggestedConfigurationFile()); config.load(); - Property recServer = config.get("settings", "enableRecordingServer", true, "Defines whether a recording should be started upon joining a server."); - Property recSP = config.get("settings", "enableRecordingSingleplayer", true, "Defines whether a recording should be started upon joining a singleplayer world."); - Property showNot = ReplayMod.instance.config.get("settings", "showNotifications", true, "Defines whether notifications should be sent to the player."); - Property linear = ReplayMod.instance.config.get("settings", "forceLinearPath", false, "Defines whether travelling paths should be linear instead of interpolated."); - Property lighting = ReplayMod.instance.config.get("settings", "enableLighting", false, "If enabled, the whole map is lighted."); - Property vq = ReplayMod.instance.config.get("settings", "videoQuality", 0.5f, "The quality of the exported video files from 0.1 to 0.9"); - Property framerate = ReplayMod.instance.config.get("settings", "videoFramerate", 30, "The framerate of the exported video files from 10 to 120"); - - replaySettings = new ReplaySettings(recServer.getBoolean(true), recSP.getBoolean(true), showNot.getBoolean(true), - linear.getBoolean(false), lighting.getBoolean(false), framerate.getInt(30), (float)vq.getDouble(0.5)); - - config.save(); + replaySettings = new ReplaySettings(); + replaySettings.readValues(); } @EventHandler diff --git a/src/main/java/eu/crushedpixel/replaymod/events/GuiReplayOverlay.java b/src/main/java/eu/crushedpixel/replaymod/events/GuiReplayOverlay.java index 0049b534..c27f2780 100755 --- a/src/main/java/eu/crushedpixel/replaymod/events/GuiReplayOverlay.java +++ b/src/main/java/eu/crushedpixel/replaymod/events/GuiReplayOverlay.java @@ -121,8 +121,7 @@ public class GuiReplayOverlay extends Gui { @SubscribeEvent public void tick(TickEvent event) { if(!ReplayHandler.isInReplay()) return; - if(ReplayHandler.isInPath() && !ReplayProcess.isVideoRecording()) ReplayProcess.tickReplay(); - ReplayProcess.unblock(); + if(ReplayHandler.isInPath()) ReplayProcess.unblockAndTick(); if(ReplayHandler.getCameraEntity() != null) ReplayHandler.getCameraEntity().updateMovement(); if(!ReplayHandler.isInPath()) onMouseMove(new MouseEvent()); diff --git a/src/main/java/eu/crushedpixel/replaymod/gui/GuiReplaySettings.java b/src/main/java/eu/crushedpixel/replaymod/gui/GuiReplaySettings.java index 0b2d98c5..bcc5a034 100755 --- a/src/main/java/eu/crushedpixel/replaymod/gui/GuiReplaySettings.java +++ b/src/main/java/eu/crushedpixel/replaymod/gui/GuiReplaySettings.java @@ -7,8 +7,15 @@ import java.util.Map.Entry; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.resources.I18n; +import net.minecraft.entity.item.EntityArmorStand; +import net.minecraft.network.play.server.S0EPacketSpawnObject; +import net.minecraft.network.play.server.S0FPacketSpawnMob; +import net.minecraft.network.play.server.S14PacketEntity; +import net.minecraft.network.play.server.S14PacketEntity.S15PacketEntityRelMove; +import net.minecraft.network.play.server.S14PacketEntity.S16PacketEntityLook; import net.minecraftforge.fml.client.FMLClientHandler; import eu.crushedpixel.replaymod.ReplayMod; +import eu.crushedpixel.replaymod.settings.ReplaySettings; import eu.crushedpixel.replaymod.settings.ReplaySettings.Option; public class GuiReplaySettings extends GuiScreen { @@ -28,8 +35,7 @@ public class GuiReplaySettings extends GuiScreen { private GuiButton recordServerButton, recordSPButton, sendChatButton, linearButton, lightingButton, resourcePackButton; - public GuiReplaySettings(GuiScreen parentGuiScreen) - { + public GuiReplaySettings(GuiScreen parentGuiScreen) { this.parentGuiScreen = parentGuiScreen; } @@ -40,6 +46,8 @@ public class GuiReplaySettings extends GuiScreen { Option[] aoptions = Option.values(); + ReplaySettings settings = ReplayMod.replaySettings; + int k = 0; int i = 0; for (Option o : aoptions) { @@ -47,36 +55,37 @@ public class GuiReplaySettings extends GuiScreen { switch(o) { case lighting: this.buttonList.add(lightingButton = new GuiButton(ENABLE_LIGHTING, this.width / 2 - 155 + i % 2 * 160, - this.height / 6 + 24 * (i >> 1), 150, 20, "Enable Lighting: "+onOff((Boolean)o.getValue()))); + this.height / 6 + 24 * (i >> 1), 150, 20, "Enable Lighting: "+onOff(settings.isLightingEnabled()))); break; case linear: this.buttonList.add(linearButton = new GuiButton(FORCE_LINEAR, this.width / 2 - 155 + i % 2 * 160, - this.height / 6 + 24 * (i >> 1), 150, 20, "Camera Path: "+linearOnOff((Boolean)o.getValue()))); + this.height / 6 + 24 * (i >> 1), 150, 20, "Camera Path: "+linearOnOff(settings.isLinearMovement()))); break; case notifications: this.buttonList.add(sendChatButton = new GuiButton(SEND_CHAT, this.width / 2 - 155 + i % 2 * 160, this.height / 6 + 24 * (i >> 1), 150, 20, - "Enable Notifications: "+onOff((Boolean)o.getValue()))); + "Enable Notifications: "+onOff(settings.isShowNotifications()))); break; case recordServer: this.buttonList.add(recordServerButton = new GuiButton(RECORDSERVER_ID, - this.width / 2 - 155 + i % 2 * 160, this.height / 6 + 24 * (i >> 1), 150, 20, "Record Server: "+onOff((Boolean)o.getValue()))); + this.width / 2 - 155 + i % 2 * 160, this.height / 6 + 24 * (i >> 1), 150, 20, "Record Server: " + +onOff(settings.isEnableRecordingServer()))); break; case recordSingleplayer: this.buttonList.add(recordSPButton = new GuiButton(RECORDSP_ID, this.width / 2 - 155 + i % 2 * 160, - this.height / 6 + 24 * (i >> 1), 150, 20, "Record Singleplayer: "+onOff((Boolean)o.getValue()))); + this.height / 6 + 24 * (i >> 1), 150, 20, "Record Singleplayer: "+onOff(settings.isEnableRecordingSingleplayer()))); break; case useResources: this.buttonList.add(resourcePackButton = new GuiButton(RESOURCEPACK_ID, this.width / 2 - 155 + i % 2 * 160, - this.height / 6 + 24 * (i >> 1), 150, 20, "Server Resource Packs: "+onOff((Boolean)o.getValue()))); + this.height / 6 + 24 * (i >> 1), 150, 20, "Server Resource Packs: "+onOff(settings.getUseResourcePacks()))); break; case videoFramerate: this.buttonList.add(new GuiVideoFramerateSlider(FRAMERATE_SLIDER_ID, - this.width / 2 - 155 + i % 2 * 160, this.height / 6 + 24 * (i >> 1), (Integer)o.getValue(), "Video Framerate")); + this.width / 2 - 155 + i % 2 * 160, this.height / 6 + 24 * (i >> 1), settings.getVideoFramerate(), "Video Framerate")); break; case videoQuality: this.buttonList.add(new GuiVideoQualitySlider(QUALITY_SLIDER_ID, - this.width / 2 - 155 + i % 2 * 160, this.height / 6 + 24 * (i >> 1), (Float)o.getValue(), "Video Quality")); + this.width / 2 - 155 + i % 2 * 160, this.height / 6 + 24 * (i >> 1), (float)settings.getVideoQuality(), "Video Quality")); break; default: break; diff --git a/src/main/java/eu/crushedpixel/replaymod/gui/GuiVideoQualitySlider.java b/src/main/java/eu/crushedpixel/replaymod/gui/GuiVideoQualitySlider.java index 30a253eb..78489e52 100755 --- a/src/main/java/eu/crushedpixel/replaymod/gui/GuiVideoQualitySlider.java +++ b/src/main/java/eu/crushedpixel/replaymod/gui/GuiVideoQualitySlider.java @@ -9,10 +9,10 @@ import eu.crushedpixel.replaymod.ReplayMod; public class GuiVideoQualitySlider extends GuiButton { - public GuiVideoQualitySlider(int buttonId, int p_i45017_2_, int p_i45017_3_, float initialQuality, String displayKey) { + public GuiVideoQualitySlider(int buttonId, int p_i45017_2_, int p_i45017_3_, float d, String displayKey) { super(buttonId, p_i45017_2_, p_i45017_3_, 150, 20, ""); - this.sliderValue = normalizeValue(initialQuality); - this.displayString = displayKey+": "+translate(initialQuality); + this.sliderValue = normalizeValue(d); + this.displayString = displayKey+": "+translate(d); this.displayKey = displayKey; } diff --git a/src/main/java/eu/crushedpixel/replaymod/replay/ReplayProcess.java b/src/main/java/eu/crushedpixel/replaymod/replay/ReplayProcess.java index 7420ab4d..a3cde603 100755 --- a/src/main/java/eu/crushedpixel/replaymod/replay/ReplayProcess.java +++ b/src/main/java/eu/crushedpixel/replaymod/replay/ReplayProcess.java @@ -1,10 +1,9 @@ package eu.crushedpixel.replaymod.replay; -import java.io.File; +import java.awt.image.BufferedImage; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; -import net.minecraft.enchantment.Enchantment; import eu.crushedpixel.replaymod.ReplayMod; import eu.crushedpixel.replaymod.chat.ChatMessageRequests; import eu.crushedpixel.replaymod.chat.ChatMessageRequests.ChatMessageType; @@ -87,33 +86,8 @@ public class ReplayProcess { ChatMessageRequests.addChatMessage("Replay started!", ChatMessageType.INFORMATION); if(isVideoRecording()) { - ticks = 0; MCTimerHandler.setTimerSpeed(1); MCTimerHandler.setPassiveTimer(); - Thread t = new Thread(new Runnable() { - - @Override - public void run() { - while(ReplayHandler.isInPath()) { - if(!blocked) { - mc.addScheduledTask(new Runnable() { - @Override - public void run() { - ReplayProcess.tickReplay(); - } - }); - } else { - try { - Thread.sleep(10); - } catch(Exception e) { - e.printStackTrace(); - } - } - } - } - }); - - t.start(); } } @@ -130,12 +104,13 @@ public class ReplayProcess { private static boolean blocked = false; private static boolean deepBlock = false; - private static float ticks = 0; - private static boolean requestFinish = false; - public static void unblock() { + public static void unblockAndTick() { if(!deepBlock) blocked = false; + if(!blocked || !isVideoRecording()) + ReplayProcess.tickReplay(); + else System.out.println("nope"); } public static void tickReplay() { @@ -144,8 +119,7 @@ public class ReplayProcess { private static void pathTick(boolean recording) { if(ReplayHandler.isHurrying()) { - if(!recording) - lastRealTime = System.currentTimeMillis(); + lastRealTime = System.currentTimeMillis(); return; } @@ -193,7 +167,7 @@ public class ReplayProcess { if(!calculated) { calculated = true; - if(posCount > 1) + if(posCount > 1 && motionSpline != null) motionSpline.calcSpline(); } @@ -320,7 +294,8 @@ public class ReplayProcess { if(!VideoWriter.isRecording() && ReplayHandler.isInPath()) { VideoWriter.startRecording(mc.displayWidth, mc.displayHeight); } else { - VideoWriter.writeImage(ScreenCapture.captureScreen()); + final BufferedImage screen = ScreenCapture.captureScreen(); + VideoWriter.writeImage(screen); } } catch(Exception e) { e.printStackTrace(); diff --git a/src/main/java/eu/crushedpixel/replaymod/settings/ReplaySettings.java b/src/main/java/eu/crushedpixel/replaymod/settings/ReplaySettings.java index 8a0460a2..ff6c7b53 100755 --- a/src/main/java/eu/crushedpixel/replaymod/settings/ReplaySettings.java +++ b/src/main/java/eu/crushedpixel/replaymod/settings/ReplaySettings.java @@ -6,6 +6,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.settings.GameSettings.Options; import net.minecraft.util.Timer; import net.minecraftforge.common.config.Configuration; +import net.minecraftforge.common.config.Property; import eu.crushedpixel.replaymod.ReplayMod; import eu.crushedpixel.replaymod.reflection.MCPNames; import eu.crushedpixel.replaymod.replay.ReplayHandler; @@ -42,18 +43,18 @@ public class ReplaySettings { e.printStackTrace(); } } - - public ReplaySettings(boolean enableRecordingServer, - boolean enableRecordingSingleplayer, boolean showNotifications, boolean forceLinearPath, boolean lightingEnabled, int framerate, float videoQuality) { - setEnableRecordingServer(enableRecordingServer); - setEnableRecordingSingleplayer(enableRecordingSingleplayer); - setLinearMovement(forceLinearPath); - setShowNotifications(showNotifications); - setLightingEnabled(lightingEnabled); - setVideoFramerate(Math.min(120, Math.max(10, framerate))); - setVideoQuality(Math.min(0.9f, Math.max(0.1f, videoQuality))); + + public void readValues() { + Configuration config = ReplayMod.config; + + for(Option o : Option.values()) { + Property p = getConfigSetting(config, o); + o.setValue(getValueObject(p)); + } + + config.save(); } - + public int getVideoFramerate() { return (Integer)Option.videoFramerate.getValue(); } @@ -61,8 +62,8 @@ public class ReplaySettings { Option.videoFramerate.setValue(Math.min(120, Math.max(10, framerate))); rewriteSettings(); } - public float getVideoQuality() { - return (Float)Option.videoQuality.getValue(); + public double getVideoQuality() { + return (Double)Option.videoQuality.getValue(); } public void setVideoQuality(float videoQuality) { Option.videoQuality.setValue(Math.min(0.9f, Math.max(0.1f, videoQuality))); @@ -135,22 +136,36 @@ public class ReplaySettings { ReplayMod.instance.config.removeCategory(ReplayMod.instance.config.getCategory("settings")); for(Option o : Option.values()) { - addConfigSetting(ReplayMod.instance.config, o); + getConfigSetting(ReplayMod.instance.config, o); } ReplayMod.instance.config.save(); } - private void addConfigSetting(Configuration config, Option o) { + private Property getConfigSetting(Configuration config, Option o) { Object value = o.getValue(); if(value instanceof Integer) { - config.get("settings", o.name(), (Integer)o.getValue()); + return config.get("settings", o.name(), (Integer)o.getValue()); } else if(value instanceof Boolean) { - config.get("settings", o.name(), (Boolean)o.getValue()); + return config.get("settings", o.name(), (Boolean)o.getValue()); } else if(value instanceof Double) { - config.get("settings", o.name(), (Double)o.getValue()); + return config.get("settings", o.name(), (Double)o.getValue()); + } else if(value instanceof Float) { + return config.get("settings", o.name(), (double)(Float)o.getValue()); } else if(value instanceof String) { - config.get("settings", o.name(), (String)o.getValue()); + return config.get("settings", o.name(), (String)o.getValue()); } + return null; + } + + private Object getValueObject(Property p) { + if(p.isIntValue()) { + return p.getInt(); + } else if(p.isDoubleValue()) { + return p.getDouble(); + } else if(p.isBooleanValue()) { + return p.getBoolean(); + } + return null; } } diff --git a/src/main/java/eu/crushedpixel/replaymod/video/VideoWriter.java b/src/main/java/eu/crushedpixel/replaymod/video/VideoWriter.java index bfc72e12..9d01d9fc 100755 --- a/src/main/java/eu/crushedpixel/replaymod/video/VideoWriter.java +++ b/src/main/java/eu/crushedpixel/replaymod/video/VideoWriter.java @@ -5,6 +5,8 @@ import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Calendar; +import java.util.Queue; +import java.util.concurrent.LinkedBlockingQueue; import org.monte.media.Buffer; import org.monte.media.Format; @@ -21,9 +23,9 @@ public class VideoWriter { private static final String DATE_FORMAT = "yyyy_MM_dd_HH_mm_ss"; private static final SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT); - + private static final String VIDEO_EXTENSION = ".avi"; - + private static MovieWriter out; private static boolean isRecording = false; private static boolean requestFinish = false; @@ -42,12 +44,14 @@ public class VideoWriter { } isRecording = true; + toWrite = new LinkedBlockingQueue(); + try { File folder = new File("./replay_videos/"); folder.mkdirs(); - + String fileName = sdf.format(Calendar.getInstance().getTime()); - + File file = new File(folder, fileName+VIDEO_EXTENSION); file.createNewFile(); @@ -69,8 +73,39 @@ public class VideoWriter { } catch (IOException e) { e.printStackTrace(); } + + Thread t = new Thread(new Runnable() { + + @Override + public void run() { + while(true) { + if(toWrite.isEmpty()) { + if(requestFinish) { + requestFinish = false; + isRecording = false; + try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return; + } + try { + Thread.sleep(10); + } catch(Exception e) { + e.printStackTrace(); + } + } else { + write(); + } + } + } + }); + t.start(); } + private static Queue toWrite = new LinkedBlockingQueue(); + public static void writeImage(BufferedImage image) { if(requestFinish || !isRecording) { IllegalStateException up = new IllegalStateException( @@ -78,20 +113,22 @@ public class VideoWriter { throw up; //lolololo^2 } - try { - buf.data = image; - out.write(track, buf); - } catch (IOException e) { - e.printStackTrace(); - } + toWrite.add(image); } public static void endRecording() { if(!isRecording) return; - isRecording = false; + requestFinish = true; + } + + private static void write() { try { - out.close(); - } catch(Exception e) { + BufferedImage img = toWrite.poll(); + if(img != null) { + buf.data = img; + out.write(track, buf); + } + } catch (IOException e) { e.printStackTrace(); } }