Added Video Export feature with according Options in the Options Menu

Fixed Linear Interpolation
This commit is contained in:
Marius Metzger
2015-02-08 12:40:37 +01:00
parent 0fc9662449
commit 03f6ba1ade
39 changed files with 1235 additions and 456 deletions

View File

@@ -17,9 +17,9 @@ buildscript {
apply plugin: 'forge' apply plugin: 'forge'
version = "1.0" version = "0.4"
group= "com.yourname.modid" // http://maven.apache.org/guides/mini/guide-naming-conventions.html group= "eu.crushedpixel.replaymod"
archivesBaseName = "modid" archivesBaseName = "replaymod"
minecraft { minecraft {
version = "1.8-11.14.0.1255-1.8" version = "1.8-11.14.0.1255-1.8"
@@ -34,6 +34,7 @@ minecraft {
} }
dependencies { dependencies {
compile fileTree(dir: 'lib', includes: ['*.jar'])
// you may put jars on which you depend on in ./libs // you may put jars on which you depend on in ./libs
// or you may define them like so.. // or you may define them like so..
//compile "some.group:artifact:version:classifier" //compile "some.group:artifact:version:classifier"

View File

@@ -27,6 +27,8 @@ public class ReplayMod
{ {
//TODO: Set ReplayHandler replaying to false when replay is exited //TODO: Set ReplayHandler replaying to false when replay is exited
//TODO: Hide Titles upon hurrying
//TODO: Override Enchantment Rendering for items when replaying (to adjust speed of animation)
//XXX //XXX
//Known Bugs //Known Bugs
@@ -44,7 +46,7 @@ public class ReplayMod
public static GuiReplayOverlay overlay = new GuiReplayOverlay(); public static GuiReplayOverlay overlay = new GuiReplayOverlay();
public static ReplaySettings replaySettings = new ReplaySettings(0, true, true, true, false, false); public static ReplaySettings replaySettings = new ReplaySettings(true, true, true, false, false, 30, 0.5f);
public static Configuration config; public static Configuration config;
public static boolean firstMainMenu = true; public static boolean firstMainMenu = true;
@@ -66,13 +68,14 @@ public class ReplayMod
Property recServer = config.get("settings", "enableRecordingServer", true, "Defines whether a recording should be started upon joining a server."); 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 recSP = config.get("settings", "enableRecordingSingleplayer", true, "Defines whether a recording should be started upon joining a singleplayer world.");
Property maxFileSize = config.get("settings", "maximumFileSize", 0, "The maximum File size (in MB) of a recording. 0 means unlimited.");
Property showNot = ReplayMod.instance.config.get("settings", "showNotifications", true, "Defines whether notifications should be sent to the player."); 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 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 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(maxFileSize.getInt(0), recServer.getBoolean(true), recSP.getBoolean(true), showNot.getBoolean(true), replaySettings = new ReplaySettings(recServer.getBoolean(true), recSP.getBoolean(true), showNot.getBoolean(true),
linear.getBoolean(false), lighting.getBoolean(false)); linear.getBoolean(false), lighting.getBoolean(false), framerate.getInt(30), (float)vq.getDouble(0.5));
config.save(); config.save();
} }

View File

@@ -9,12 +9,7 @@ import java.nio.file.Files;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import java.util.List; import java.util.List;
import org.apache.http.HttpResponse; import org.apache.commons.io.FileUtils;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.FileEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
@@ -22,7 +17,6 @@ import com.google.gson.JsonParser;
import eu.crushedpixel.replaymod.api.client.holders.ApiError; import eu.crushedpixel.replaymod.api.client.holders.ApiError;
import eu.crushedpixel.replaymod.api.client.holders.AuthKey; import eu.crushedpixel.replaymod.api.client.holders.AuthKey;
import eu.crushedpixel.replaymod.api.client.holders.Category;
import eu.crushedpixel.replaymod.api.client.holders.FileInfo; import eu.crushedpixel.replaymod.api.client.holders.FileInfo;
import eu.crushedpixel.replaymod.api.client.holders.Success; import eu.crushedpixel.replaymod.api.client.holders.Success;
import eu.crushedpixel.replaymod.api.client.holders.UserFiles; import eu.crushedpixel.replaymod.api.client.holders.UserFiles;
@@ -77,6 +71,13 @@ public class ApiClient {
FileInfo[] info = invokeAndReturn(builder, FileInfo[].class); //TODO: Test if that works FileInfo[] info = invokeAndReturn(builder, FileInfo[].class); //TODO: Test if that works
return info; return info;
} }
public void downloadThumbnail(int file, File target) throws IOException {
QueryBuilder builder = new QueryBuilder(ApiMethods.get_thumbnail);
builder.put("id", file);
URL url = new URL(builder.toString());
FileUtils.copyURLToFile(url, target);
}
public void downloadFile(String auth, int file, File target) throws IOException { public void downloadFile(String auth, int file, File target) throws IOException {
QueryBuilder builder = new QueryBuilder(ApiMethods.download_file); QueryBuilder builder = new QueryBuilder(ApiMethods.download_file);

View File

@@ -8,6 +8,7 @@ public class ApiMethods {
public static final String file_details = "file_details"; public static final String file_details = "file_details";
public static final String upload_file = "upload_file"; public static final String upload_file = "upload_file";
public static final String download_file = "download_file"; public static final String download_file = "download_file";
public static final String get_thumbnail = "get_thumbnail";
public static final String remove_file = "remove_file"; public static final String remove_file = "remove_file";
public static final String rate_file = "rate_file"; public static final String rate_file = "rate_file";

View File

@@ -10,6 +10,9 @@ public class FileInfo {
private Rating ratings; private Rating ratings;
private int size; private int size;
private int category; private int category;
private int downloads;
private String name;
private boolean thumbnail;
public int getId() { public int getId() {
return id; return id;
@@ -29,5 +32,15 @@ public class FileInfo {
public int getCategory() { public int getCategory() {
return category; return category;
} }
public int getDownloads() {
return downloads;
}
public String getName() {
return name;
}
public boolean hasThumbnail() {
return thumbnail;
}
} }

View File

@@ -5,6 +5,7 @@ import java.lang.reflect.Field;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.network.play.server.S03PacketTimeUpdate;
import net.minecraft.util.MathHelper; import net.minecraft.util.MathHelper;
import net.minecraft.util.MovingObjectPosition; import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.Vec3; import net.minecraft.util.Vec3;
@@ -15,6 +16,7 @@ import org.lwjgl.Sys;
import eu.crushedpixel.replaymod.holders.Position; import eu.crushedpixel.replaymod.holders.Position;
import eu.crushedpixel.replaymod.replay.LesserDataWatcher; import eu.crushedpixel.replaymod.replay.LesserDataWatcher;
import eu.crushedpixel.replaymod.replay.ReplayHandler; import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.replay.TimeHandler;
public class CameraEntity extends EntityPlayer { public class CameraEntity extends EntityPlayer {
@@ -37,14 +39,19 @@ public class CameraEntity extends EntityPlayer {
mc.thePlayer.rotationPitch = mc.getRenderViewEntity().rotationPitch; mc.thePlayer.rotationPitch = mc.getRenderViewEntity().rotationPitch;
mc.thePlayer.rotationYaw = mc.getRenderViewEntity().rotationYaw; mc.thePlayer.rotationYaw = mc.getRenderViewEntity().rotationYaw;
/*
mc.thePlayer.posX = mc.getRenderViewEntity().posX; mc.thePlayer.posX = mc.getRenderViewEntity().posX;
mc.thePlayer.posY = mc.getRenderViewEntity().posY; mc.thePlayer.posY = mc.getRenderViewEntity().posY;
mc.thePlayer.posZ = mc.getRenderViewEntity().posZ; mc.thePlayer.posZ = mc.getRenderViewEntity().posZ;
TimeHandler.setDesiredDaytime(18000);
TimeHandler.setTimeOverridden(true);
*/
//removes water/suffocation/shadow overlays in screen //removes water/suffocation/shadow overlays in screen
//mc.thePlayer.posX = 0; mc.thePlayer.posX = 0;
//mc.thePlayer.posY = 500; mc.thePlayer.posY = 500;
//mc.thePlayer.posZ = 0; mc.thePlayer.posZ = 0;
} }
if(direction == null || motion < 0.1) { if(direction == null || motion < 0.1) {

View File

@@ -15,11 +15,11 @@ import net.minecraft.client.gui.GuiVideoSettings;
import net.minecraft.client.gui.inventory.GuiInventory; import net.minecraft.client.gui.inventory.GuiInventory;
import net.minecraft.client.resources.I18n; import net.minecraft.client.resources.I18n;
import net.minecraft.client.settings.GameSettings.Options; import net.minecraft.client.settings.GameSettings.Options;
import net.minecraft.util.Timer;
import net.minecraftforge.client.event.GuiOpenEvent; import net.minecraftforge.client.event.GuiOpenEvent;
import net.minecraftforge.client.event.GuiScreenEvent.ActionPerformedEvent; import net.minecraftforge.client.event.GuiScreenEvent.ActionPerformedEvent;
import net.minecraftforge.client.event.GuiScreenEvent.DrawScreenEvent; import net.minecraftforge.client.event.GuiScreenEvent.DrawScreenEvent;
import net.minecraftforge.client.event.GuiScreenEvent.InitGuiEvent; import net.minecraftforge.client.event.GuiScreenEvent.InitGuiEvent;
import net.minecraftforge.fml.common.eventhandler.Event.Result;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import eu.crushedpixel.replaymod.ReplayMod; import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.gui.GuiConstants; import eu.crushedpixel.replaymod.gui.GuiConstants;
@@ -32,8 +32,9 @@ import eu.crushedpixel.replaymod.gui.replaymanager.GuiReplayManager;
import eu.crushedpixel.replaymod.gui.replaymanager.ResourceHelper; import eu.crushedpixel.replaymod.gui.replaymanager.ResourceHelper;
import eu.crushedpixel.replaymod.online.authentication.AuthenticationHandler; import eu.crushedpixel.replaymod.online.authentication.AuthenticationHandler;
import eu.crushedpixel.replaymod.registry.ReplayGuiRegistry; import eu.crushedpixel.replaymod.registry.ReplayGuiRegistry;
import eu.crushedpixel.replaymod.replay.MCTimerHandler;
import eu.crushedpixel.replaymod.replay.ReplayHandler; import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.replay.ReplaySender; import eu.crushedpixel.replaymod.video.VideoWriter;
public class GuiEventHandler { public class GuiEventHandler {
@@ -51,6 +52,11 @@ public class GuiEventHandler {
@SubscribeEvent @SubscribeEvent
public void onGui(GuiOpenEvent event) { public void onGui(GuiOpenEvent event) {
if(VideoWriter.isRecording()) {
event.gui = null;
return;
}
if(!(event.gui instanceof GuiReplayManager || event.gui instanceof GuiUploadFile)) ResourceHelper.freeAllResources(); if(!(event.gui instanceof GuiReplayManager || event.gui instanceof GuiUploadFile)) ResourceHelper.freeAllResources();
if(event.gui instanceof GuiMainMenu) { if(event.gui instanceof GuiMainMenu) {
@@ -60,8 +66,7 @@ public class GuiEventHandler {
return; return;
} else { } else {
try { try {
Timer timer = (Timer)ReplaySender.mcTimer.get(mc); MCTimerHandler.setTimerSpeed(1);
timer.timerSpeed = 1f;
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }

View File

@@ -46,9 +46,11 @@ import eu.crushedpixel.replaymod.holders.PositionKeyframe;
import eu.crushedpixel.replaymod.holders.TimeKeyframe; import eu.crushedpixel.replaymod.holders.TimeKeyframe;
import eu.crushedpixel.replaymod.reflection.MCPNames; import eu.crushedpixel.replaymod.reflection.MCPNames;
import eu.crushedpixel.replaymod.registry.ReplayGuiRegistry; import eu.crushedpixel.replaymod.registry.ReplayGuiRegistry;
import eu.crushedpixel.replaymod.replay.MCTimerHandler;
import eu.crushedpixel.replaymod.replay.ReplayHandler; import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.replay.ReplayProcess; import eu.crushedpixel.replaymod.replay.ReplayProcess;
import eu.crushedpixel.replaymod.replay.screenshot.ReplayScreenshot; import eu.crushedpixel.replaymod.video.ReplayScreenshot;
import eu.crushedpixel.replaymod.video.VideoWriter;
public class GuiReplayOverlay extends Gui { public class GuiReplayOverlay extends Gui {
@@ -58,7 +60,7 @@ public class GuiReplayOverlay extends Gui {
private int sliderY = 10; private int sliderY = 10;
private int timelineX = sliderX+100+5; private int timelineX = sliderX+100+5;
private int realTimelineX = 10 + 3*25; private int realTimelineX = 10 + 4*25;
private int realTimelineY = 33+10; private int realTimelineY = 33+10;
private int ppButtonX = 10; private int ppButtonX = 10;
@@ -67,10 +69,13 @@ public class GuiReplayOverlay extends Gui {
private int r_ppButtonX = 10; private int r_ppButtonX = 10;
private int r_ppButtonY = realTimelineY+1; private int r_ppButtonY = realTimelineY+1;
private int place_ButtonX = 35; private int exportButtonX = 35;
private int exportButtonY = realTimelineY+1;
private int place_ButtonX = 60;
private int place_ButtonY = realTimelineY+1; private int place_ButtonY = realTimelineY+1;
private int time_ButtonX = 60; private int time_ButtonX = 85;
private int time_ButtonY = realTimelineY+1; private int time_ButtonY = realTimelineY+1;
private long lastSystemTime = System.currentTimeMillis(); private long lastSystemTime = System.currentTimeMillis();
@@ -109,11 +114,12 @@ public class GuiReplayOverlay extends Gui {
@SubscribeEvent @SubscribeEvent
public void tick(TickEvent event) { public void tick(TickEvent event) {
if(!ReplayHandler.replayActive()) return; if(!ReplayHandler.replayActive()) return;
if(ReplayHandler.isReplaying() && !ReplayProcess.isVideoRecording()) ReplayProcess.tickReplay();
ReplayProcess.unblock();
if(ReplayHandler.getCameraEntity() != null) if(ReplayHandler.getCameraEntity() != null)
ReplayHandler.getCameraEntity().updateMovement(); ReplayHandler.getCameraEntity().updateMovement();
onMouseMove(new MouseEvent()); if(!ReplayHandler.isReplaying()) onMouseMove(new MouseEvent());
FMLCommonHandler.instance().bus().post(new InputEvent.KeyInputEvent()); FMLCommonHandler.instance().bus().post(new InputEvent.KeyInputEvent());
if(ReplayHandler.isReplaying()) ReplayProcess.tickReplay();
} }
private double lastX, lastY, lastZ; private double lastX, lastY, lastZ;
@@ -129,7 +135,7 @@ public class GuiReplayOverlay extends Gui {
if(mc != null && mc.thePlayer != null) if(mc != null && mc.thePlayer != null)
MinecraftTicker.runMouseKeyboardTick(mc); MinecraftTicker.runMouseKeyboardTick(mc);
} }
if(mc.getRenderViewEntity() == mc.thePlayer) { if(mc.getRenderViewEntity() == mc.thePlayer || !mc.getRenderViewEntity().isEntityAlive()) {
ReplayHandler.spectateCamera(); ReplayHandler.spectateCamera();
ReplayHandler.getCameraEntity().movePath(new Position(lastX, lastY, lastZ, lastPitch, lastYaw)); ReplayHandler.getCameraEntity().movePath(new Position(lastX, lastY, lastZ, lastPitch, lastYaw));
} else if(!ReplayHandler.isCamera()) { } else if(!ReplayHandler.isCamera()) {
@@ -153,12 +159,22 @@ public class GuiReplayOverlay extends Gui {
speedSlider = new GuiReplaySpeedSlider(1, sliderX, sliderY, "Speed"); speedSlider = new GuiReplaySpeedSlider(1, sliderX, sliderY, "Speed");
} }
@SubscribeEvent
public void onRenderGui(RenderGameOverlayEvent event) {
if(VideoWriter.isRecording()) {
event.setCanceled(true);
}
}
@SubscribeEvent @SubscribeEvent
public void onRenderGui(RenderGameOverlayEvent.Post event) throws IllegalArgumentException, IllegalAccessException { public void onRenderGui(RenderGameOverlayEvent.Post event) throws IllegalArgumentException, IllegalAccessException {
if(!ReplayHandler.replayActive() || FMLClientHandler.instance().isGUIOpen(GuiSpectateSelection.class)) { if(!ReplayHandler.replayActive() || FMLClientHandler.instance().isGUIOpen(GuiSpectateSelection.class) || VideoWriter.isRecording()) {
return; return;
} }
//System.out.println(System.currentTimeMillis()+" | "+MCTimerHandler.getTicks()+" | "+MCTimerHandler.getPartialTicks());
if(!ReplayGuiRegistry.hidden) ReplayGuiRegistry.hide(); if(!ReplayGuiRegistry.hidden) ReplayGuiRegistry.hide();
if(event.type == ElementType.PLAYER_LIST) { if(event.type == ElementType.PLAYER_LIST) {
@@ -227,6 +243,8 @@ public class GuiReplayOverlay extends Gui {
ReplayHandler.setSpeed(speedSlider.getSliderValue()); ReplayHandler.setSpeed(speedSlider.getSliderValue());
} }
} else if(mouseX >= exportButtonX && mouseX <= exportButtonX+20 && mouseY >= exportButtonY && exportButtonY <= exportButtonY+20) {
ReplayHandler.startPath(true);
} }
if(mouseX >= timelineX+4 && mouseX <= width - 18 && mouseY >= 11 && mouseY <= 29) { if(mouseX >= timelineX+4 && mouseX <= width - 18 && mouseY >= 11 && mouseY <= 29) {
@@ -256,6 +274,28 @@ public class GuiReplayOverlay extends Gui {
} catch(Exception e) {} } catch(Exception e) {}
} }
//TODO: Save Video Button
hover = false;
x = 0;
y = 18;
if(FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class)) {
if(mouseX >= exportButtonX && mouseX <= exportButtonX+20
&& mouseY >= exportButtonY && mouseY <= exportButtonY+20) {
hover = true;
}
}
if(hover) {
x = 20;
}
mc.renderEngine.bindTexture(timelineLocation);
GlStateManager.resetColor();
this.drawModalRectWithCustomSizedTexture(exportButtonX, exportButtonY, x, y, 20, 20, 64, 64);
//GlStateManager.resetColor();
//Place Keyframe Button //Place Keyframe Button
hover = false; hover = false;
@@ -703,7 +743,7 @@ public class GuiReplayOverlay extends Gui {
if(ReplayHandler.isReplaying()) { if(ReplayHandler.isReplaying()) {
ReplayHandler.interruptReplay(); ReplayHandler.interruptReplay();
} else { } else {
ReplayHandler.startPath(); ReplayHandler.startPath(false);
} }
} }

View File

@@ -11,8 +11,8 @@ import eu.crushedpixel.replaymod.entities.CameraEntity.MoveDirection;
import eu.crushedpixel.replaymod.gui.GuiMouseInput; import eu.crushedpixel.replaymod.gui.GuiMouseInput;
import eu.crushedpixel.replaymod.registry.KeybindRegistry; import eu.crushedpixel.replaymod.registry.KeybindRegistry;
import eu.crushedpixel.replaymod.replay.ReplayHandler; import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.replay.screenshot.ReplayScreenshot;
import eu.crushedpixel.replaymod.replay.spectate.SpectateHandler; import eu.crushedpixel.replaymod.replay.spectate.SpectateHandler;
import eu.crushedpixel.replaymod.video.ReplayScreenshot;
public class KeyInputHandler { public class KeyInputHandler {
@@ -25,7 +25,9 @@ public class KeyInputHandler {
if(mc.currentScreen != null) { if(mc.currentScreen != null) {
return; return;
} }
boolean found = false;
KeyBinding[] keyBindings = Minecraft.getMinecraft().gameSettings.keyBindings; KeyBinding[] keyBindings = Minecraft.getMinecraft().gameSettings.keyBindings;
for(KeyBinding kb : keyBindings) { for(KeyBinding kb : keyBindings) {
if(!kb.isKeyDown()) { if(!kb.isKeyDown()) {
@@ -36,27 +38,22 @@ public class KeyInputHandler {
if(ReplayHandler.isCamera()) { if(ReplayHandler.isCamera()) {
if(kb.getKeyDescription().equals("key.forward")) { if(kb.getKeyDescription().equals("key.forward")) {
ReplayHandler.getCameraEntity().setMovement(MoveDirection.FORWARD); ReplayHandler.getCameraEntity().setMovement(MoveDirection.FORWARD);
continue;
} }
if(kb.getKeyDescription().equals("key.back")) { if(kb.getKeyDescription().equals("key.back")) {
ReplayHandler.getCameraEntity().setMovement(MoveDirection.BACKWARD); ReplayHandler.getCameraEntity().setMovement(MoveDirection.BACKWARD);
continue;
} }
if(kb.getKeyDescription().equals("key.jump")) { if(kb.getKeyDescription().equals("key.jump")) {
ReplayHandler.getCameraEntity().setMovement(MoveDirection.UP); ReplayHandler.getCameraEntity().setMovement(MoveDirection.UP);
continue;
} }
if(kb.getKeyDescription().equals("key.left")) { if(kb.getKeyDescription().equals("key.left")) {
ReplayHandler.getCameraEntity().setMovement(MoveDirection.LEFT); ReplayHandler.getCameraEntity().setMovement(MoveDirection.LEFT);
continue;
} }
if(kb.getKeyDescription().equals("key.right")) { if(kb.getKeyDescription().equals("key.right")) {
ReplayHandler.getCameraEntity().setMovement(MoveDirection.RIGHT); ReplayHandler.getCameraEntity().setMovement(MoveDirection.RIGHT);
continue;
} }
} }
if(kb.getKeyDescription().equals("key.sneak")) { if(kb.getKeyDescription().equals("key.sneak")) {
@@ -65,35 +62,31 @@ public class KeyInputHandler {
} else { } else {
ReplayHandler.spectateCamera(); ReplayHandler.spectateCamera();
} }
continue;
} }
if(kb.getKeyDescription().equals("key.chat")) { if(kb.getKeyDescription().equals("key.chat")) {
mc.displayGuiScreen(new GuiMouseInput()); mc.displayGuiScreen(new GuiMouseInput());
continue;
} }
//Custom registered handlers //Custom registered handlers
if(kb.getKeyDescription().equals(KeybindRegistry.KEY_THUMBNAIL) && kb.isPressed()) { if(kb.getKeyDescription().equals(KeybindRegistry.KEY_THUMBNAIL) && kb.isPressed() && !found) {
System.out.println("thumbnail key pressed");
ReplayScreenshot.prepareScreenshot(); ReplayScreenshot.prepareScreenshot();
GuiReplayOverlay.requestScreenshot(); GuiReplayOverlay.requestScreenshot();
continue;
} }
if(kb.getKeyDescription().equals(KeybindRegistry.KEY_SPECTATE) && kb.isPressed()) { if(kb.getKeyDescription().equals(KeybindRegistry.KEY_SPECTATE) && kb.isPressed() && !found) {
SpectateHandler.openSpectateSelection(); SpectateHandler.openSpectateSelection();
continue;
} }
if(kb.getKeyDescription().equals(KeybindRegistry.KEY_LIGHTING) && kb.isPressed()) { if(kb.getKeyDescription().equals(KeybindRegistry.KEY_LIGHTING) && kb.isPressed() && !found) {
ReplayMod.replaySettings.setLightingEnabled(!ReplayMod.replaySettings.isLightingEnabled()); ReplayMod.replaySettings.setLightingEnabled(!ReplayMod.replaySettings.isLightingEnabled());
continue;
} }
} catch(Exception e) { } catch(Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
found = true;
} }
} }
} }

View File

@@ -76,6 +76,7 @@ public class MinecraftTicker {
public static void runMouseKeyboardTick(Minecraft mc) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException { public static void runMouseKeyboardTick(Minecraft mc) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException {
if(mc.thePlayer == null) return;
try { try {
mc.mcProfiler.endStartSection("mouse"); mc.mcProfiler.endStartSection("mouse");
int i; int i;
@@ -435,8 +436,6 @@ public class MinecraftTicker {
if(mc != null) if(mc != null)
systemTime.set(mc, getSystemTime.invoke(mc)); systemTime.set(mc, getSystemTime.invoke(mc));
} catch(Exception e) { } catch(Exception e) {}
e.printStackTrace();
}
} }
} }

View File

@@ -1,4 +1,4 @@
package eu.crushedpixel.replaymod.gui.replaymanager; package eu.crushedpixel.replaymod.gui;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.File; import java.io.File;
@@ -18,6 +18,7 @@ import net.minecraft.client.gui.GuiListExtended.IGuiListEntry;
import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.texture.DynamicTexture; import net.minecraft.client.renderer.texture.DynamicTexture;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import eu.crushedpixel.replaymod.gui.replaymanager.ResourceHelper;
import eu.crushedpixel.replaymod.recording.ReplayMetaData; import eu.crushedpixel.replaymod.recording.ReplayMetaData;
public class GuiReplayListEntry implements IGuiListEntry { public class GuiReplayListEntry implements IGuiListEntry {
@@ -66,7 +67,7 @@ public class GuiReplayListEntry implements IGuiListEntry {
public void drawEntry(int slotIndex, int x, int y, int listWidth, int slotHeight, int mouseX, int mouseY, boolean isSelected) { public void drawEntry(int slotIndex, int x, int y, int listWidth, int slotHeight, int mouseX, int mouseY, boolean isSelected) {
try { try {
minecraft.fontRendererObj.drawString(fileName, x + 3, y + 1, 16777215); minecraft.fontRendererObj.drawString(fileName, x + 3, y + 1, 16777215);
if(y < -slotHeight || y > parent.height) { if(y < -slotHeight || y > parent.height) {
if(registered) { if(registered) {
registered = false; registered = false;
@@ -79,7 +80,11 @@ public class GuiReplayListEntry implements IGuiListEntry {
} else { } else {
if(!registered) { if(!registered) {
textureResource = new ResourceLocation("thumbs/"+fileName); textureResource = new ResourceLocation("thumbs/"+fileName);
image = ImageIO.read(imageFile); if(imageFile == null) {
image = ResourceHelper.getDefaultThumbnail();
} else {
image = ImageIO.read(imageFile);
}
dynTex = new DynamicTexture(image); dynTex = new DynamicTexture(image);
minecraft.getTextureManager().loadTexture(textureResource, dynTex); minecraft.getTextureManager().loadTexture(textureResource, dynTex);
dynTex.updateDynamicTexture(); dynTex.updateDynamicTexture();

View File

@@ -1,4 +1,4 @@
package eu.crushedpixel.replaymod.gui.replaymanager; package eu.crushedpixel.replaymod.gui;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
@@ -15,29 +15,21 @@ import org.lwjgl.input.Mouse;
import eu.crushedpixel.replaymod.recording.ReplayMetaData; import eu.crushedpixel.replaymod.recording.ReplayMetaData;
public class GuiReplayListExtended extends GuiListExtended { public abstract class GuiReplayListExtended extends GuiListExtended {
private GuiReplayManager parent; public GuiReplayListExtended(Minecraft mcIn, int p_i45010_2_,
public int selected = -1;
public GuiReplayListExtended(GuiReplayManager parent, Minecraft mcIn, int p_i45010_2_,
int p_i45010_3_, int p_i45010_4_, int p_i45010_5_, int p_i45010_6_) { int p_i45010_3_, int p_i45010_4_, int p_i45010_5_, int p_i45010_6_) {
super(mcIn, p_i45010_2_, p_i45010_3_, p_i45010_4_, p_i45010_5_, p_i45010_6_); super(mcIn, p_i45010_2_, p_i45010_3_, p_i45010_4_, p_i45010_5_, p_i45010_6_);
this.parent = parent;
} }
public int selected = -1;
@Override @Override
protected void elementClicked(int slotIndex, boolean isDoubleClick, protected void elementClicked(int slotIndex, boolean isDoubleClick,
int mouseX, int mouseY) { int mouseX, int mouseY) {
super.elementClicked(slotIndex, isDoubleClick, mouseX, mouseY); super.elementClicked(slotIndex, isDoubleClick, mouseX, mouseY);
this.selected = slotIndex; this.selected = slotIndex;
parent.setButtonsEnabled(true);
if(isDoubleClick) {
parent.loadReplay(slotIndex);
}
} }
@Override @Override
protected void drawSelectionBox(int p_148120_1_, int p_148120_2_, int p_148120_3_, int p_148120_4_) protected void drawSelectionBox(int p_148120_1_, int p_148120_2_, int p_148120_3_, int p_148120_4_)

View File

@@ -22,12 +22,14 @@ public class GuiReplaySettings extends GuiScreen {
private GuiScreen parentGuiScreen; private GuiScreen parentGuiScreen;
protected String screenTitle = "Replay Mod Settings"; protected String screenTitle = "Replay Mod Settings";
private static final int MAXSIZE_SLIDER_ID = 9003; //TODO: Move to GuiConstants
private static final int QUALITY_SLIDER_ID = 9003;
private static final int RECORDSERVER_ID = 9004; private static final int RECORDSERVER_ID = 9004;
private static final int RECORDSP_ID = 9005; private static final int RECORDSP_ID = 9005;
private static final int SEND_CHAT = 9006; private static final int SEND_CHAT = 9006;
private static final int FORCE_LINEAR = 9007; private static final int FORCE_LINEAR = 9007;
private static final int ENABLE_LIGHTING = 9008; private static final int ENABLE_LIGHTING = 9008;
private static final int FRAMERATE_SLIDER_ID = 9009;
private GuiButton recordServerButton, recordSPButton, sendChatButton, linearButton, lightingButton; private GuiButton recordServerButton, recordSPButton, sendChatButton, linearButton, lightingButton;
@@ -47,18 +49,11 @@ public class GuiReplaySettings extends GuiScreen {
int i = 0; int i = 0;
for (Entry<String, Object> e : aoptions.entrySet()) { for (Entry<String, Object> e : aoptions.entrySet()) {
/* if(e.getKey().equals("Video Quality")) {
if(e.getKey().equals("Maximum File Size")) { this.buttonList.add(new GuiVideoQualitySlider(QUALITY_SLIDER_ID, this.width / 2 - 155 + i % 2 * 160, this.height / 6 + 24 * (i >> 1), (Float)e.getValue(), "Video Quality"));
float minValue = -1; } else if(e.getKey().equals("Video Framerate")) {
float maxValue = 10000; this.buttonList.add(new GuiVideoFramerateSlider(FRAMERATE_SLIDER_ID, this.width / 2 - 155 + i % 2 * 160, this.height / 6 + 24 * (i >> 1), (Integer)e.getValue(), "Video Framerate"));
float valueSteps = 1; } else if(e.getKey().equals("Enable Notifications")) {
int val = (Integer)e.getValue();
this.buttonList.add(new GuiSizeLimitOptionSlider(MAXSIZE_SLIDER_ID, this.width / 2 - 155 + i % 2 * 160, this.height / 6 + 24 * (i >> 1), 0, 39, 1, val, e.getKey()));
} else
*/
if(e.getKey().equals("Enable Notifications")) {
sendChatButton = new GuiButton(SEND_CHAT, this.width / 2 - 155 + i % 2 * 160, this.height / 6 + 24 * (i >> 1), 150, 20, "Enable Notifications: "+onOff((Boolean)e.getValue())); sendChatButton = new GuiButton(SEND_CHAT, this.width / 2 - 155 + i % 2 * 160, this.height / 6 + 24 * (i >> 1), 150, 20, "Enable Notifications: "+onOff((Boolean)e.getValue()));
this.buttonList.add(sendChatButton); this.buttonList.add(sendChatButton);
} else if(e.getKey().equals("Record Server")) { } else if(e.getKey().equals("Record Server")) {

View File

@@ -1,185 +0,0 @@
package eu.crushedpixel.replaymod.gui;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.settings.GameSettings;
import net.minecraft.util.MathHelper;
import eu.crushedpixel.replaymod.ReplayMod;
public class GuiSizeLimitOptionSlider extends GuiButton {
public GuiSizeLimitOptionSlider(int buttonId, int p_i45017_2_, int p_i45017_3_, float valueMin, float valueMax, float valueStep, int sliderValue, String displayKey)
{
super(buttonId, p_i45017_2_, p_i45017_3_, 150, 20, "");
this.valueMin = valueMin;
this.valueMax = valueMax;
this.valueStep = valueStep;
this.sliderValue = sliderValue;
this.displayString = displayKey+": "+translate(sliderValue);
this.displayKey = displayKey;
float val = realToNormalized(convertScaleRet(sliderValue));
this.sliderValue = val;
}
private float sliderValue;
public boolean dragging;
private GameSettings.Options options;
private float valueStep, valueMin, valueMax;
private String displayKey;
protected int getHoverState(boolean mouseOver) {
return 0;
}
@Override
protected void mouseDragged(Minecraft mc, int mouseX, int mouseY) {
if (this.visible) {
if (this.dragging) {
sliderValue = (float)(mouseX - (this.xPosition + 4)) / (float)(this.width - 8);
sliderValue = MathHelper.clamp_float(sliderValue, 0.0F, 1.0F);
float f = denormalizeValue(sliderValue);
sliderValue = normalizeValue(f);
this.displayString = displayKey+": "+translate(convertScale(normalizedToReal(sliderValue)));
ReplayMod.replaySettings.setMaximumFileSize(convertScale(normalizedToReal(sliderValue)));
}
mc.getTextureManager().bindTexture(buttonTextures);
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
this.drawTexturedModalRect(this.xPosition + (int)(sliderValue * (float)(this.width - 8)), this.yPosition, 0, 66, 4, 20);
this.drawTexturedModalRect(this.xPosition + (int)(sliderValue * (float)(this.width - 8)) + 4, this.yPosition, 196, 66, 4, 20);
}
}
public static String translate(int value) {
if(value == 0) {
return "Unlimited";
} else {
return convertToStringRepresentation(value);
}
}
public static int convertScale(float value) {
if(value == 0) {
return 0;
} else {
if(value > 20) {
value = 1024+((value-20)*1024);
} else {
value = value*50;
}
if(value == 1000) {
value = 1024;
}
return Math.round(value);
}
}
public static int convertScaleRet(float value) {
if(value == 0) {
return 0;
} else {
if(value >= 1024) {
value = 20+((value-1024)/1024);
} else {
value = value/50;
}
if(value == 1024) {
value = 1000;
}
return Math.round(value);
}
}
public static String convertToStringRepresentation(final long value){
long M = 1;
long G = 1024;
long T = G * 1024;
final long[] dividers = new long[] { T, G, M};
final String[] units = new String[] { "TB", "GB", "MB"};
if(value < 1)
throw new IllegalArgumentException("Invalid file size: " + value);
String result = null;
for(int i = 0; i < dividers.length; i++){
final long divider = dividers[i];
if(value >= divider){
result = format(value, divider, units[i]);
break;
}
}
return result;
}
private static String format(final long value,
final long divider,
final String unit){
final double result =
divider > 1 ? (double) value / (double) divider : (double) value;
return String.format("%.0f %s", Double.valueOf(result), unit);
}
public float normalizedToReal(float value) {
float min = 0 - valueMin;
float max = valueMax + min;
return Math.round(value*(max) - min);
}
public float realToNormalized(float value) {
float min = 0 - valueMin;
float max = valueMax + min;
return value/(max) - min;
}
public float normalizeValue(float p_148266_1_)
{
return MathHelper.clamp_float((this.snapToStepClamp(p_148266_1_) - this.valueMin) / (this.valueMax - this.valueMin), 0.0F, 1.0F);
}
public float denormalizeValue(float p_148262_1_)
{
return this.snapToStepClamp(this.valueMin + (this.valueMax - this.valueMin) * MathHelper.clamp_float(p_148262_1_, 0.0F, 1.0F));
}
public float snapToStepClamp(float p_148268_1_)
{
p_148268_1_ = this.snapToStep(p_148268_1_);
return MathHelper.clamp_float(p_148268_1_, this.valueMin, this.valueMax);
}
protected float snapToStep(float p_148264_1_)
{
if (this.valueStep > 0.0F)
{
p_148264_1_ = this.valueStep * (float)Math.round(p_148264_1_ / this.valueStep);
}
return p_148264_1_;
}
public boolean mousePressed(Minecraft mc, int mouseX, int mouseY)
{
if (super.mousePressed(mc, mouseX, mouseY))
{
this.dragging = true;
return true;
}
else
{
return false;
}
}
public void mouseReleased(int mouseX, int mouseY)
{
this.dragging = false;
}
}

View File

@@ -0,0 +1,71 @@
package eu.crushedpixel.replaymod.gui;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.settings.GameSettings;
import net.minecraft.util.MathHelper;
import eu.crushedpixel.replaymod.ReplayMod;
public class GuiVideoFramerateSlider extends GuiButton {
public GuiVideoFramerateSlider(int buttonId, int p_i45017_2_, int p_i45017_3_, int initialFramerate, String displayKey) {
super(buttonId, p_i45017_2_, p_i45017_3_, 150, 20, "");
this.sliderValue = normalizeValue(initialFramerate);
this.displayString = displayKey+": "+translate(initialFramerate);
this.displayKey = displayKey;
}
private String displayKey;
private float sliderValue;
public boolean dragging;
private String translate(int value) {
return String.valueOf(value);
}
protected int getHoverState(boolean mouseOver) {
return 0;
}
@Override
protected void mouseDragged(Minecraft mc, int mouseX, int mouseY) {
if (this.visible) {
if (this.dragging) {
sliderValue = (float)(mouseX - (this.xPosition + 4)) / (float)(this.width - 8);
sliderValue = MathHelper.clamp_float(sliderValue, 0.0F, 1.0F);
int f = denormalizeValue(sliderValue);
this.displayString = displayKey+": "+translate(f);
ReplayMod.replaySettings.setVideoFramerate(f);
}
mc.getTextureManager().bindTexture(buttonTextures);
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
this.drawTexturedModalRect(this.xPosition + (int)(sliderValue * (float)(this.width - 8)), this.yPosition, 0, 66, 4, 20);
this.drawTexturedModalRect(this.xPosition + (int)(sliderValue * (float)(this.width - 8)) + 4, this.yPosition, 196, 66, 4, 20);
}
}
private float normalizeValue(int val) {
return (val-10)/110f;
}
private int denormalizeValue(float val) {
//Transfers the value ranging from 0.0 to 1.0 to the scale of 10 to 120
float r = 110f*val;
return Math.round(10+r);
}
public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) {
if (super.mousePressed(mc, mouseX, mouseY)) {
this.dragging = true;
return true;
} else {
return false;
}
}
public void mouseReleased(int mouseX, int mouseY) {
this.dragging = false;
}
}

View File

@@ -0,0 +1,85 @@
package eu.crushedpixel.replaymod.gui;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.settings.GameSettings;
import net.minecraft.util.MathHelper;
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) {
super(buttonId, p_i45017_2_, p_i45017_3_, 150, 20, "");
this.sliderValue = normalizeValue(initialQuality);
this.displayString = displayKey+": "+translate(initialQuality);
this.displayKey = displayKey;
}
private String displayKey;
private float sliderValue;
public boolean dragging;
private String translate(float value) {
if(value <= 0.3) {
return "Draft";
} else if(value <= 0.5) {
return "Normal";
} else if(value <= 0.7) {
return "Good";
}
return "Best";
}
protected int getHoverState(boolean mouseOver) {
return 0;
}
@Override
protected void mouseDragged(Minecraft mc, int mouseX, int mouseY) {
if (this.visible) {
if (this.dragging) {
sliderValue = (float)(mouseX - (this.xPosition + 4)) / (float)(this.width - 8);
sliderValue = MathHelper.clamp_float(sliderValue, 0.0F, 1.0F);
float f = denormalizeValue(sliderValue);
f = snapValue(f);
sliderValue = normalizeValue(f);
this.displayString = displayKey+": "+translate(f);
ReplayMod.replaySettings.setVideoQuality(f);
}
mc.getTextureManager().bindTexture(buttonTextures);
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
this.drawTexturedModalRect(this.xPosition + (int)(sliderValue * (float)(this.width - 8)), this.yPosition, 0, 66, 4, 20);
this.drawTexturedModalRect(this.xPosition + (int)(sliderValue * (float)(this.width - 8)) + 4, this.yPosition, 196, 66, 4, 20);
}
}
private float snapValue(float val) {
int i = Math.round(val*10);
return i/10f;
}
private float normalizeValue(float val) {
return (val-0.1f)/0.8f;
}
private float denormalizeValue(float val) {
//Transfers the value ranging from 0.0 to 1.0 to the scale of 0.1 to 0.9
float r = 0.8f*val;
return 0.1f+r;
}
public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) {
if (super.mousePressed(mc, mouseX, mouseY)) {
this.dragging = true;
return true;
} else {
return false;
}
}
public void mouseReleased(int mouseX, int mouseY) {
this.dragging = false;
}
}

View File

@@ -1,6 +1,7 @@
package eu.crushedpixel.replaymod.gui.online; package eu.crushedpixel.replaymod.gui.online;
import java.awt.Color; import java.awt.Color;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -14,19 +15,26 @@ import net.minecraft.client.resources.I18n;
import org.lwjgl.input.Keyboard; import org.lwjgl.input.Keyboard;
import scala.actors.threadpool.Arrays;
import com.mojang.realmsclient.gui.GuiCallback;
import eu.crushedpixel.replaymod.ReplayMod; import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.api.client.ApiException; import eu.crushedpixel.replaymod.api.client.ApiException;
import eu.crushedpixel.replaymod.api.client.holders.FileInfo; import eu.crushedpixel.replaymod.api.client.holders.FileInfo;
import eu.crushedpixel.replaymod.gui.GuiConstants; import eu.crushedpixel.replaymod.gui.GuiConstants;
import eu.crushedpixel.replaymod.gui.GuiReplayListExtended;
import eu.crushedpixel.replaymod.gui.replaymanager.GuiReplayManager; import eu.crushedpixel.replaymod.gui.replaymanager.GuiReplayManager;
import eu.crushedpixel.replaymod.online.authentication.AuthenticationHandler; import eu.crushedpixel.replaymod.online.authentication.AuthenticationHandler;
public class GuiReplayCenter extends GuiScreen implements GuiYesNoCallback { public class GuiReplayCenter extends GuiScreen implements GuiYesNoCallback {
private enum Tab {
RECENT_FILES, BEST_FILES, MY_FILES, SEARCH;
}
private GuiReplayListExtended currentList;
private ReplayFileList recentFileList, bestFileList, myFileList, searchFileList;
private Tab currentTab = Tab.RECENT_FILES;
@Override @Override
public void initGui() { public void initGui() {
Keyboard.enableRepeatEvents(true); Keyboard.enableRepeatEvents(true);
@@ -40,7 +48,7 @@ public class GuiReplayCenter extends GuiScreen implements GuiYesNoCallback {
GuiButton recentButton = new GuiButton(GuiConstants.CENTER_RECENT_BUTTON, 20, 30, "Newest Replays"); GuiButton recentButton = new GuiButton(GuiConstants.CENTER_RECENT_BUTTON, 20, 30, "Newest Replays");
buttonBar.add(recentButton); buttonBar.add(recentButton);
GuiButton bestButton = new GuiButton(GuiConstants.CENTER_BEST_BUTTON, 20, 30, "Best Replays"); GuiButton bestButton = new GuiButton(GuiConstants.CENTER_BEST_BUTTON, 20, 30, "Best Replays");
buttonBar.add(bestButton); buttonBar.add(bestButton);
@@ -70,7 +78,7 @@ public class GuiReplayCenter extends GuiScreen implements GuiYesNoCallback {
GuiButton exitButton = new GuiButton(GuiConstants.CENTER_BACK_BUTTON, 20, 20, "Main Menu"); GuiButton exitButton = new GuiButton(GuiConstants.CENTER_BACK_BUTTON, 20, 20, "Main Menu");
bottomBar.add(exitButton); bottomBar.add(exitButton);
GuiButton managerButton = new GuiButton(GuiConstants.CENTER_MANAGER_BUTTON, 20, 20, "Replay Manager"); GuiButton managerButton = new GuiButton(GuiConstants.CENTER_MANAGER_BUTTON, 20, 20, "Replay Manager");
bottomBar.add(managerButton); bottomBar.add(managerButton);
@@ -91,7 +99,7 @@ public class GuiReplayCenter extends GuiScreen implements GuiYesNoCallback {
i++; i++;
} }
showOnlineRecent(); showOnlineRecent();
} }
@@ -107,11 +115,11 @@ public class GuiReplayCenter extends GuiScreen implements GuiYesNoCallback {
} else if(button.id == GuiConstants.CENTER_RECENT_BUTTON) { } else if(button.id == GuiConstants.CENTER_RECENT_BUTTON) {
showOnlineRecent(); showOnlineRecent();
} else if(button.id == GuiConstants.CENTER_BEST_BUTTON) { } else if(button.id == GuiConstants.CENTER_BEST_BUTTON) {
} else if(button.id == GuiConstants.CENTER_MY_REPLAYS_BUTTON) { } else if(button.id == GuiConstants.CENTER_MY_REPLAYS_BUTTON) {
} else if(button.id == GuiConstants.CENTER_SEARCH_BUTTON) { } else if(button.id == GuiConstants.CENTER_SEARCH_BUTTON) {
} }
} }
@@ -144,22 +152,66 @@ public class GuiReplayCenter extends GuiScreen implements GuiYesNoCallback {
this.drawDefaultBackground(); this.drawDefaultBackground();
this.drawCenteredString(fontRendererObj, "Replay Center", this.width/2, 8, Color.WHITE.getRGB()); this.drawCenteredString(fontRendererObj, "Replay Center", this.width/2, 8, Color.WHITE.getRGB());
if(currentList != null) {
currentList.drawScreen(mouseX, mouseY, partialTicks);
}
super.drawScreen(mouseX, mouseY, partialTicks); super.drawScreen(mouseX, mouseY, partialTicks);
} }
@Override
public void handleMouseInput() throws IOException {
super.handleMouseInput();
if(currentList != null) {
this.currentList.handleMouseInput();
}
}
@Override
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
super.mouseClicked(mouseX, mouseY, mouseButton);
if(currentList != null) {
this.currentList.mouseClicked(mouseX, mouseY, mouseButton);
}
}
@Override
protected void mouseReleased(int mouseX, int mouseY, int state) {
super.mouseReleased(mouseX, mouseY, state);
if(currentList != null) {
this.currentList.mouseReleased(mouseX, mouseY, state);
}
}
@Override @Override
public void onGuiClosed() { public void onGuiClosed() {
Keyboard.enableRepeatEvents(false); Keyboard.enableRepeatEvents(false);
} }
public void showOnlineRecent() { public void showOnlineRecent() {
mc.addScheduledTask(new Runnable() { Thread t = new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
try { try {
if(recentFileList == null) {
recentFileList = new ReplayFileList(mc, width, height, 50, height-40, 36);
} else {
recentFileList.clearEntries();
recentFileList.width = width;
recentFileList.height = height;
recentFileList.top = 50;
recentFileList.bottom = height-40;
}
currentTab = Tab.RECENT_FILES;
currentList = recentFileList;
FileInfo[] files = ReplayMod.apiClient.getRecentFiles(); FileInfo[] files = ReplayMod.apiClient.getRecentFiles();
for(FileInfo i : files) { for(FileInfo i : files) {
//TODO: Display the Files File tmp = null;
if(i.hasThumbnail()) {
tmp = File.createTempFile("thumb_online_"+i.getId(), "jpg");
ReplayMod.apiClient.downloadThumbnail(i.getId(), tmp);
}
recentFileList.addEntry(i.getName(), i.getMetadata(), tmp);
} }
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
@@ -168,7 +220,8 @@ public class GuiReplayCenter extends GuiScreen implements GuiYesNoCallback {
} }
} }
}); });
t.start();
} }
} }

View File

@@ -0,0 +1,12 @@
package eu.crushedpixel.replaymod.gui.online;
import net.minecraft.client.Minecraft;
import eu.crushedpixel.replaymod.gui.GuiReplayListExtended;
public class ReplayFileList extends GuiReplayListExtended {
public ReplayFileList(Minecraft mcIn, int p_i45010_2_, int p_i45010_3_,
int p_i45010_4_, int p_i45010_5_, int p_i45010_6_) {
super(mcIn, p_i45010_2_, p_i45010_3_, p_i45010_4_, p_i45010_5_, p_i45010_6_);
}
}

View File

@@ -37,6 +37,7 @@ import org.lwjgl.input.Keyboard;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.mojang.realmsclient.util.Pair; import com.mojang.realmsclient.util.Pair;
import eu.crushedpixel.replaymod.gui.GuiReplayListExtended;
import eu.crushedpixel.replaymod.gui.GuiReplaySettings; import eu.crushedpixel.replaymod.gui.GuiReplaySettings;
import eu.crushedpixel.replaymod.gui.online.GuiUploadFile; import eu.crushedpixel.replaymod.gui.online.GuiUploadFile;
import eu.crushedpixel.replaymod.online.authentication.AuthenticationHandler; import eu.crushedpixel.replaymod.online.authentication.AuthenticationHandler;
@@ -95,16 +96,14 @@ public class GuiReplayManager extends GuiScreen implements GuiYesNoCallback {
img = ImageUtils.scaleImage(bimg, new Dimension(1280, 720)); img = ImageUtils.scaleImage(bimg, new Dimension(1280, 720));
} }
} }
//If thumb is null, set image to placeholder File tmp = null;
if(img == null) { if(img != null) {
img = ImageIO.read(MCPNames.class.getClassLoader().getResourceAsStream("default_thumb.jpg")); tmp = File.createTempFile(FilenameUtils.getBaseName(file.getAbsolutePath()), "jpg");
tmp.deleteOnExit();
ImageIO.write(img, "jpg", tmp);
} }
File tmp = File.createTempFile(FilenameUtils.getBaseName(file.getAbsolutePath()), "jpg");
tmp.deleteOnExit();
ImageIO.write(img, "jpg", tmp);
InputStream is = archive.getInputStream(metadata); InputStream is = archive.getInputStream(metadata);
BufferedReader br = new BufferedReader(new InputStreamReader(is)); BufferedReader br = new BufferedReader(new InputStreamReader(is));
@@ -116,9 +115,7 @@ public class GuiReplayManager extends GuiScreen implements GuiYesNoCallback {
replayFileList.add(Pair.of(Pair.of(file, metaData), tmp)); replayFileList.add(Pair.of(Pair.of(file, metaData), tmp));
archive.close(); archive.close();
} catch(Exception e) { } catch(Exception e) {}
e.printStackTrace();
}
} }
} }
@@ -144,7 +141,7 @@ public class GuiReplayManager extends GuiScreen implements GuiYesNoCallback {
@Override @Override
public void initGui() { public void initGui() {
replayGuiList = new GuiReplayListExtended(this, this.mc, this.width, this.height, 32, this.height - 64, 36); replayGuiList = new ReplayManagerReplayList(this, this.mc, this.width, this.height, 32, this.height - 64, 36);
Keyboard.enableRepeatEvents(true); Keyboard.enableRepeatEvents(true);
this.buttonList.clear(); this.buttonList.clear();
@@ -170,26 +167,26 @@ public class GuiReplayManager extends GuiScreen implements GuiYesNoCallback {
setButtonsEnabled(false); setButtonsEnabled(false);
} }
public void handleMouseInput() throws IOException @Override
{ public void handleMouseInput() throws IOException {
super.handleMouseInput(); super.handleMouseInput();
this.replayGuiList.handleMouseInput(); this.replayGuiList.handleMouseInput();
} }
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException @Override
{ protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
super.mouseClicked(mouseX, mouseY, mouseButton); super.mouseClicked(mouseX, mouseY, mouseButton);
this.replayGuiList.mouseClicked(mouseX, mouseY, mouseButton); this.replayGuiList.mouseClicked(mouseX, mouseY, mouseButton);
} }
protected void mouseReleased(int mouseX, int mouseY, int state) @Override
{ protected void mouseReleased(int mouseX, int mouseY, int state) {
super.mouseReleased(mouseX, mouseY, state); super.mouseReleased(mouseX, mouseY, state);
this.replayGuiList.mouseReleased(mouseX, mouseY, state); this.replayGuiList.mouseReleased(mouseX, mouseY, state);
} }
public void drawScreen(int mouseX, int mouseY, float partialTicks) @Override
{ public void drawScreen(int mouseX, int mouseY, float partialTicks) {
this.hoveringText = null; this.hoveringText = null;
this.drawDefaultBackground(); this.drawDefaultBackground();
this.replayGuiList.drawScreen(mouseX, mouseY, partialTicks); this.replayGuiList.drawScreen(mouseX, mouseY, partialTicks);
@@ -198,8 +195,7 @@ public class GuiReplayManager extends GuiScreen implements GuiYesNoCallback {
} }
@Override @Override
protected void actionPerformed(GuiButton button) throws IOException protected void actionPerformed(GuiButton button) throws IOException {
{
if(button.enabled) { if(button.enabled) {
if(button.id == LOAD_BUTTON_ID) { if(button.id == LOAD_BUTTON_ID) {
loadReplay(replayGuiList.selected); loadReplay(replayGuiList.selected);

View File

@@ -0,0 +1,29 @@
package eu.crushedpixel.replaymod.gui.replaymanager;
import eu.crushedpixel.replaymod.gui.GuiReplayListExtended;
import net.minecraft.client.Minecraft;
public class ReplayManagerReplayList extends GuiReplayListExtended {
private GuiReplayManager parent;
public ReplayManagerReplayList(GuiReplayManager parent, Minecraft mcIn,
int p_i45010_2_, int p_i45010_3_, int p_i45010_4_, int p_i45010_5_,
int p_i45010_6_) {
super(mcIn, p_i45010_2_, p_i45010_3_, p_i45010_4_, p_i45010_5_,
p_i45010_6_);
this.parent = parent;
}
@Override
protected void elementClicked(int slotIndex, boolean isDoubleClick,
int mouseX, int mouseY) {
super.elementClicked(slotIndex, isDoubleClick, mouseX, mouseY);
parent.setButtonsEnabled(true);
if(isDoubleClick) {
parent.loadReplay(slotIndex);
}
}
}

View File

@@ -1,29 +1,47 @@
package eu.crushedpixel.replaymod.gui.replaymanager; package eu.crushedpixel.replaymod.gui.replaymanager;
import java.awt.image.BufferedImage;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.imageio.ImageIO;
import eu.crushedpixel.replaymod.reflection.MCPNames;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
public class ResourceHelper { public class ResourceHelper {
private static BufferedImage defaultThumb;
static {
try {
defaultThumb = ImageIO.read(MCPNames.class.getClassLoader().getResourceAsStream("default_thumb.jpg"));
} catch(Exception e) {
defaultThumb = new BufferedImage(1, 1, BufferedImage.TYPE_3BYTE_BGR);
e.printStackTrace();
}
}
private static List<ResourceLocation> openResources = new ArrayList<ResourceLocation>(); private static List<ResourceLocation> openResources = new ArrayList<ResourceLocation>();
public static void registerResource(ResourceLocation loc) { public static void registerResource(ResourceLocation loc) {
openResources.add(loc); openResources.add(loc);
} }
public static void freeResource(ResourceLocation loc) { public static void freeResource(ResourceLocation loc) {
Minecraft.getMinecraft().getTextureManager().deleteTexture(loc); Minecraft.getMinecraft().getTextureManager().deleteTexture(loc);
openResources.remove(loc); openResources.remove(loc);
} }
public static void freeAllResources() { public static void freeAllResources() {
for(ResourceLocation loc : openResources) { for(ResourceLocation loc : openResources) {
Minecraft.getMinecraft().getTextureManager().deleteTexture(loc); Minecraft.getMinecraft().getTextureManager().deleteTexture(loc);
} }
openResources = new ArrayList<ResourceLocation>(); openResources = new ArrayList<ResourceLocation>();
} }
public static BufferedImage getDefaultThumbnail() {
return defaultThumb;
}
} }

View File

@@ -63,5 +63,8 @@ public class Position {
this.yaw = yaw; this.yaw = yaw;
} }
@Override
public String toString() {
return "X="+x+", Y="+y+", Z="+z+", Yaw="+yaw+", Pitch="+pitch;
}
} }

View File

@@ -7,6 +7,10 @@ import akka.japi.Pair;
public abstract class LinearInterpolation<K> { public abstract class LinearInterpolation<K> {
public LinearInterpolation() {
points = new ArrayList<K>();
}
protected List<K> points = new ArrayList<K>(); protected List<K> points = new ArrayList<K>();
public abstract K getPoint(float position); public abstract K getPoint(float position);
@@ -21,9 +25,9 @@ public abstract class LinearInterpolation<K> {
protected Pair<Float, Pair<K, K>> getCurrentPoints(float position) { protected Pair<Float, Pair<K, K>> getCurrentPoints(float position) {
if(points.size() == 0) return null; if(points.size() == 0) return null;
float pos = position * (points.size()-1); position = position * (points.size()-1);
int cubicNum = Math.round(pos); int cubicNum = (int)Math.min(points.size()-1, position);
float cubicPos = (pos - cubicNum); float cubicPos = (position - cubicNum);
if(cubicNum == points.size()-1) { if(cubicNum == points.size()-1) {
cubicNum--; cubicNum--;

View File

@@ -6,11 +6,16 @@ import eu.crushedpixel.replaymod.holders.Position;
public class LinearPoint extends LinearInterpolation<Position> { public class LinearPoint extends LinearInterpolation<Position> {
@Override @Override
public Position getPoint(float position) { public Position getPoint(float positionIn) {
Pair<Float, Pair<Position, Position>> pair = getCurrentPoints(position); Pair<Float, Pair<Position, Position>> pair = getCurrentPoints(positionIn);
if(pair == null) return null; if(pair == null) return null;
float perc = pair.first(); float perc = pair.first();
//float position = positionIn * (points.size()-1);
//int cubicNum = (int)Math.min(points.size()-1, position);
//float perc = (position - cubicNum);
//System.out.println(cubicNum+" | "+perc+" | "+positionIn);
Position first = pair.second().first(); Position first = pair.second().first();
Position second = pair.second().second(); Position second = pair.second().second();
@@ -23,7 +28,7 @@ public class LinearPoint extends LinearInterpolation<Position> {
float yaw = (float)getInterpolatedValue(first.getYaw(), second.getYaw(), perc); float yaw = (float)getInterpolatedValue(first.getYaw(), second.getYaw(), perc);
Position inter = new Position(x, y, z, pitch, yaw); Position inter = new Position(x, y, z, pitch, yaw);
//System.out.println(position+" | "+cubicNum+" | "+perc+" | "+first+" | "+second+" | "+inter);
return inter; return inter;
} }
} }

View File

@@ -99,12 +99,10 @@ public class ConnectionEventHandler {
currentFile.createNewFile(); currentFile.createNewFile();
int maxFileSize = ReplayMod.replaySettings.getMaximumFileSize();
PacketListener insert = null; PacketListener insert = null;
pipeline.addBefore(packetHandlerKey, "replay_recorder", insert = new PacketListener pipeline.addBefore(packetHandlerKey, "replay_recorder", insert = new PacketListener
(currentFile, fileName, worldName, System.currentTimeMillis(), maxFileSize, event.isLocal)); (currentFile, fileName, worldName, System.currentTimeMillis(), event.isLocal));
ChatMessageRequests.addChatMessage("Recording started!", ChatMessageType.INFORMATION); ChatMessageRequests.addChatMessage("Recording started!", ChatMessageType.INFORMATION);
isRecording = true; isRecording = true;

View File

@@ -31,8 +31,6 @@ public abstract class DataListener extends ChannelInboundHandlerAdapter {
protected File file; protected File file;
protected Long startTime = null; protected Long startTime = null;
protected long maxSize;
protected long totalBytes = 0;
protected String name; protected String name;
protected String worldName; protected String worldName;
@@ -53,10 +51,9 @@ public abstract class DataListener extends ChannelInboundHandlerAdapter {
System.out.println(worldName); System.out.println(worldName);
} }
public DataListener(File file, String name, String worldName, long startTime, int maxSize, boolean singleplayer) throws FileNotFoundException { public DataListener(File file, String name, String worldName, long startTime, boolean singleplayer) throws FileNotFoundException {
this.file = file; this.file = file;
this.startTime = startTime; this.startTime = startTime;
this.maxSize = maxSize*1024*1024;
this.name = name; this.name = name;
this.worldName = worldName; this.worldName = worldName;
this.singleplayer = singleplayer; this.singleplayer = singleplayer;

View File

@@ -24,8 +24,8 @@ import eu.crushedpixel.replaymod.reflection.MCPNames;
public class PacketListener extends DataListener { public class PacketListener extends DataListener {
public PacketListener(File file, String name, String worldName, long startTime, int maxSize, boolean singleplayer) throws FileNotFoundException { public PacketListener(File file, String name, String worldName, long startTime, boolean singleplayer) throws FileNotFoundException {
super(file, name, worldName, startTime, maxSize, singleplayer); super(file, name, worldName, startTime, singleplayer);
} }
private static final Minecraft mc = Minecraft.getMinecraft(); private static final Minecraft mc = Minecraft.getMinecraft();
@@ -132,13 +132,6 @@ public class PacketListener extends DataListener {
byte[] array = new byte[bb.readableBytes()]; byte[] array = new byte[bb.readableBytes()];
bb.readBytes(array); bb.readBytes(array);
totalBytes += (array.length + (2*4)); //two Integer values and the Packet size
if(totalBytes >= maxSize && maxSize > 0) {
ChatMessageRequests.addChatMessage("Maximum file size exceeded", ChatMessageType.WARNING);
ChatMessageRequests.addChatMessage("The Recording has been stopped", ChatMessageType.WARNING);
alive = false;
}
bb.readerIndex(0); bb.readerIndex(0);
return new PacketData(array, timestamp); return new PacketData(array, timestamp);

View File

@@ -0,0 +1,175 @@
package eu.crushedpixel.replaymod.replay;
import java.lang.reflect.Field;
import net.minecraft.client.Minecraft;
import net.minecraft.util.MathHelper;
import net.minecraft.util.Timer;
import eu.crushedpixel.replaymod.reflection.MCPNames;
import eu.crushedpixel.replaymod.video.ReplayTimer;
public class MCTimerHandler {
private static Field mcTimer;
private static Minecraft mc = Minecraft.getMinecraft();
private static ReplayTimer rpt = new ReplayTimer(20);
private static Timer timerBefore;
static {
try {
mcTimer = Minecraft.class.getDeclaredField(MCPNames.field("field_71428_T"));
mcTimer.setAccessible(true);
} catch(Exception e) {
e.printStackTrace();
}
}
public static void setActiveTimer() {
try {
if(timerBefore != null) {
mcTimer.set(mc, timerBefore);
}
} catch(Exception e) {
e.printStackTrace();
}
}
public static void setPassiveTimer() {
try {
if(!(getTimer() instanceof ReplayTimer)) {
timerBefore = getTimer();
System.out.println("here");
mcTimer.set(mc, rpt);
}
} catch(Exception e) {
e.printStackTrace();
}
}
public static int getTicks() {
try {
Timer t = getTimer();
return t.elapsedTicks;
} catch(Exception e) {
e.printStackTrace();
}
return 0;
}
public static float getPartialTicks() {
try {
Timer t = getTimer();
return t.elapsedPartialTicks;
} catch(Exception e) {
e.printStackTrace();
}
return 0;
}
public static float getRenderTicks() {
try {
Timer t = getTimer();
return t.renderPartialTicks;
} catch(Exception e) {
e.printStackTrace();
}
return 0;
}
private static Timer getTimer() throws IllegalArgumentException, IllegalAccessException {
return (Timer)mcTimer.get(mc);
}
public static void advanceTicks(int ticks) {
try {
Timer t = getTimer();
t.elapsedTicks += ticks;
} catch(Exception e) {
e.printStackTrace();
}
}
public static void advancePartialTicks(float ticks) {
try {
Timer t = getTimer();
t.elapsedPartialTicks += ticks;
} catch(Exception e) {
e.printStackTrace();
}
}
public static void advanceRenderPartialTicks(float ticks) {
try {
Timer t = getTimer();
t.renderPartialTicks += ticks;
} catch(Exception e) {
e.printStackTrace();
}
}
public static void setTimerSpeed(float speed) {
try {
Timer t = getTimer();
t.timerSpeed = speed;
if(timerBefore != null) {
timerBefore.timerSpeed = speed;
}
} catch(Exception e) {
e.printStackTrace();
}
}
public static void setRenderPartialTicks(float ticks) {
try {
getTimer().renderPartialTicks = ticks;
} catch(Exception e) {
e.printStackTrace();
}
}
public static void setPartialTicks(float ticks) {
try {
getTimer().elapsedPartialTicks = ticks;
} catch(Exception e) {
e.printStackTrace();
}
}
public static void setTicks(int ticks) {
try {
getTimer().elapsedTicks = ticks;
} catch(Exception e) {
e.printStackTrace();
}
}
public static float getTimerSpeed() {
try {
return getTimer().timerSpeed;
} catch(Exception e) {
e.printStackTrace();
}
return 1;
}
public static void updateTimer(double d) {
try{
Timer t = getTimer();
double d2 = d;
d2 = MathHelper.clamp_double(d2, 0.0D, 1.0D);
t.elapsedPartialTicks = (float)((double)t.elapsedPartialTicks + d2 * (double)t.timerSpeed * 20);
t.elapsedTicks = (int)t.elapsedPartialTicks;
t.elapsedPartialTicks -= (float)t.elapsedTicks;
if (t.elapsedTicks > 10)
{
t.elapsedTicks = 10;
}
t.renderPartialTicks = t.elapsedPartialTicks;
} catch(Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -15,6 +15,7 @@ import net.minecraft.client.network.NetHandlerPlayClient;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.network.EnumPacketDirection; import net.minecraft.network.EnumPacketDirection;
import net.minecraft.network.NetworkManager; import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet;
import net.minecraft.network.play.INetHandlerPlayClient; import net.minecraft.network.play.INetHandlerPlayClient;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
@@ -27,7 +28,6 @@ import eu.crushedpixel.replaymod.holders.KeyframeComparator;
import eu.crushedpixel.replaymod.holders.Position; import eu.crushedpixel.replaymod.holders.Position;
import eu.crushedpixel.replaymod.holders.PositionKeyframe; import eu.crushedpixel.replaymod.holders.PositionKeyframe;
import eu.crushedpixel.replaymod.holders.TimeKeyframe; import eu.crushedpixel.replaymod.holders.TimeKeyframe;
import eu.crushedpixel.replaymod.registry.ReplayGuiRegistry;
public class ReplayHandler { public class ReplayHandler {
@@ -54,6 +54,15 @@ public class ReplayHandler {
private static Entity currentEntity = null; private static Entity currentEntity = null;
public static void insertPacketInstantly(Packet p) {
if(replaySender != null) {
try {
replaySender.channelRead(null, p);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void spectateEntity(Entity e) { public static void spectateEntity(Entity e) {
currentEntity = e; currentEntity = e;
mc.setRenderViewEntity(currentEntity); mc.setRenderViewEntity(currentEntity);
@@ -88,8 +97,8 @@ public class ReplayHandler {
isReplaying = replaying; isReplaying = replaying;
} }
public static void startPath() { public static void startPath(boolean save) {
ReplayProcess.startReplayProcess(); if(!ReplayHandler.isReplaying()) ReplayProcess.startReplayProcess(save);
} }
public static void interruptReplay() { public static void interruptReplay() {

View File

@@ -1,5 +1,7 @@
package eu.crushedpixel.replaymod.replay; package eu.crushedpixel.replaymod.replay;
import java.io.File;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.GuiScreen;
import eu.crushedpixel.replaymod.ReplayMod; import eu.crushedpixel.replaymod.ReplayMod;
@@ -12,6 +14,8 @@ import eu.crushedpixel.replaymod.holders.TimeKeyframe;
import eu.crushedpixel.replaymod.interpolation.LinearPoint; import eu.crushedpixel.replaymod.interpolation.LinearPoint;
import eu.crushedpixel.replaymod.interpolation.LinearTimestamp; import eu.crushedpixel.replaymod.interpolation.LinearTimestamp;
import eu.crushedpixel.replaymod.interpolation.SplinePoint; import eu.crushedpixel.replaymod.interpolation.SplinePoint;
import eu.crushedpixel.replaymod.video.ScreenCapture;
import eu.crushedpixel.replaymod.video.VideoWriter;
public class ReplayProcess { public class ReplayProcess {
@@ -31,15 +35,23 @@ public class ReplayProcess {
private static LinearTimestamp timeLinear = null; private static LinearTimestamp timeLinear = null;
private static double previousReplaySpeed = 0; private static double previousReplaySpeed = 0;
private static boolean calculated = false; private static boolean calculated = false;
public static void startReplayProcess() { private static boolean isVideoRecording = false;
public static boolean isVideoRecording() {
return isVideoRecording;
}
public static void startReplayProcess(boolean record) {
isVideoRecording = record;
lastPosition = null; lastPosition = null;
motionSpline = null; motionSpline = null;
timeLinear = null; timeLinear = null;
calculated = false; calculated = false;
requestFinish = false;
ChatMessageRequests.initialize(); ChatMessageRequests.initialize();
if(ReplayHandler.getPosKeyframeCount() < 2) { if(ReplayHandler.getPosKeyframeCount() < 2) {
ChatMessageRequests.addChatMessage("At least 2 position keyframes required!", ChatMessageType.WARNING); ChatMessageRequests.addChatMessage("At least 2 position keyframes required!", ChatMessageType.WARNING);
@@ -64,17 +76,69 @@ public class ReplayProcess {
} }
ChatMessageRequests.addChatMessage("Replay started!", ChatMessageType.INFORMATION); 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.isReplaying()) {
if(!blocked) {
mc.addScheduledTask(new Runnable() {
@Override
public void run() {
ReplayProcess.tickReplay();
}
});
} else {
try {
Thread.sleep(10);
} catch(Exception e) {
e.printStackTrace();
}
}
}
}
});
t.start();
}
} }
public static void stopReplayProcess(boolean finished) { public static void stopReplayProcess(boolean finished) {
if(!ReplayHandler.isReplaying()) return;
if(finished) ChatMessageRequests.addChatMessage("Replay finished!", ChatMessageType.INFORMATION); if(finished) ChatMessageRequests.addChatMessage("Replay finished!", ChatMessageType.INFORMATION);
else ChatMessageRequests.addChatMessage("Replay stopped!", ChatMessageType.INFORMATION); else ChatMessageRequests.addChatMessage("Replay stopped!", ChatMessageType.INFORMATION);
ReplayHandler.setReplaying(false); ReplayHandler.setReplaying(false);
MCTimerHandler.setActiveTimer();
ReplayHandler.setSpeed(previousReplaySpeed); ReplayHandler.setSpeed(previousReplaySpeed);
ReplayHandler.setSpeed(0); ReplayHandler.setSpeed(0);
} }
public static void tickReplay() { private static boolean blocked = false;
private static boolean deepBlock = false;
private static float ticks = 0;
private static boolean requestFinish = false;
public static void unblock() {
if(!deepBlock) blocked = false;
}
public static void tickReplay() {
if(isVideoRecording()) {
recordingTick();
} else {
normalTick();
}
}
private static void normalTick() {
if(ReplayHandler.isHurrying()) { if(ReplayHandler.isHurrying()) {
lastRealTime = System.currentTimeMillis(); lastRealTime = System.currentTimeMillis();
return; return;
@@ -91,7 +155,7 @@ public class ReplayProcess {
} }
} }
} }
if(linear && motionLinear == null) { if(linear && motionLinear == null) {
//set up linear path //set up linear path
motionLinear = new LinearPoint(); motionLinear = new LinearPoint();
@@ -115,9 +179,9 @@ public class ReplayProcess {
if(!calculated) { if(!calculated) {
calculated = true; calculated = true;
motionSpline.calcSpline(); if(motionSpline != null) motionSpline.calcSpline();
} }
long curTime = System.currentTimeMillis(); long curTime = System.currentTimeMillis();
long timeStep = curTime - lastRealTime; long timeStep = curTime - lastRealTime;
@@ -169,7 +233,165 @@ public class ReplayProcess {
if(!(nextTime == null || lastTime == null)) { if(!(nextTime == null || lastTime == null)) {
curSpeed = ((double)((nextTime.getTimestamp()-lastTime.getTimestamp())))/((double)((nextTimeStamp-lastTimeStamp))); curSpeed = ((double)((nextTime.getTimestamp()-lastTime.getTimestamp())))/((double)((nextTimeStamp-lastTimeStamp)));
} }
if(lastTimeStamp == nextTimeStamp) {
curSpeed = 0f;
}
}
int currentDiff = nextPosStamp - lastPosStamp;
int current = curRealReplayTime - lastPosStamp;
float currentStepPerc = (float)current/(float)currentDiff; //The percentage of the travelled path between the current positions
if(Float.isInfinite(currentStepPerc)) currentStepPerc = 0;
float splinePos = ((float)ReplayHandler.getKeyframeIndex(lastPos) + currentStepPerc)/(float)(ReplayHandler.getPosKeyframeCount()-1);
float timePos = ((float)ReplayHandler.getKeyframeIndex(lastTime) + currentStepPerc)/(float)(ReplayHandler.getTimeKeyframeCount()-1);
Position pos = null;
if(!linear) {
pos = motionSpline.getPoint(Math.max(0, Math.min(1, splinePos)));
} else {
pos = motionLinear.getPoint(Math.max(0, Math.min(1, splinePos)));
}
Integer curPos = null;
if(timeLinear != null) {
curPos = timeLinear.getPoint(Math.max(0, Math.min(1, timePos)));
}
if(pos != null) ReplayHandler.getCameraEntity().movePath(pos);
ReplayHandler.setSpeed(curSpeed);
if(curPos != null) ReplayHandler.setReplayPos(curPos);
//splinePos = (index of last entry + add) / total entries
lastRealReplayTime = curRealReplayTime;
lastRealTime = curTime;
if(requestFinish) {
stopReplayProcess(true);
requestFinish = false;
}
if(splinePos >= 1) {
requestFinish = true;
}
}
private static void recordingTick() {
if(ReplayHandler.isHurrying()) {
if(!isVideoRecording()) {
lastRealTime = System.currentTimeMillis();
}
return;
}
if(blocked && isVideoRecording()) {
return;
}
deepBlock = true;
blocked = true;
if(!linear && motionSpline == null) {
//set up spline path
motionSpline = new SplinePoint();
for(Keyframe kf : ReplayHandler.getKeyframes()) {
if(kf instanceof PositionKeyframe) {
PositionKeyframe pkf = (PositionKeyframe)kf;
Position pos = pkf.getPosition();
motionSpline.addPoint(pos);
}
}
}
if(linear && motionLinear == null) {
//set up linear path
motionLinear = new LinearPoint();
for(Keyframe kf : ReplayHandler.getKeyframes()) {
if(kf instanceof PositionKeyframe) {
PositionKeyframe pkf = (PositionKeyframe)kf;
Position pos = pkf.getPosition();
motionLinear.addPoint(pos);
}
}
}
if(timeLinear == null) {
timeLinear = new LinearTimestamp();
for(Keyframe kf : ReplayHandler.getKeyframes()) {
if(kf instanceof TimeKeyframe) {
timeLinear.addPoint(((TimeKeyframe)kf).getTimestamp());
}
}
}
if(!calculated) {
calculated = true;
motionSpline.calcSpline();
}
long timeStep;
long curTime = System.currentTimeMillis();
if(isVideoRecording()) {
timeStep = 1000/ReplayMod.replaySettings.getVideoFramerate();
} else {
timeStep = curTime - lastRealTime;
}
int curRealReplayTime = (int)(lastRealReplayTime + timeStep);
PositionKeyframe lastPos = ReplayHandler.getPreviousPositionKeyframe(curRealReplayTime);
PositionKeyframe nextPos = ReplayHandler.getNextPositionKeyframe(curRealReplayTime);
ReplayHandler.setRealTimelineCursor(curRealReplayTime);
int lastPosStamp = 0;
int nextPosStamp = 0;
if(nextPos != null || lastPos != null) {
if(nextPos != null) {
nextPosStamp = nextPos.getRealTimestamp();
} else {
nextPosStamp = lastPos.getRealTimestamp();
}
if(lastPos != null) {
lastPosStamp = lastPos.getRealTimestamp();
} else {
lastPosStamp = nextPos.getRealTimestamp();
}
}
TimeKeyframe lastTime = ReplayHandler.getPreviousTimeKeyframe(curRealReplayTime);
TimeKeyframe nextTime = ReplayHandler.getNextTimeKeyframe(curRealReplayTime);
int lastTimeStamp = 0;
int nextTimeStamp = 0;
double curSpeed = 0f;
if(nextTime != null || lastTime != null) {
if(nextTime != null) {
nextTimeStamp = nextTime.getRealTimestamp();
} else {
nextTimeStamp = lastTime.getRealTimestamp();
}
if(lastTime != null) {
lastTimeStamp = lastTime.getRealTimestamp();
} else {
lastTimeStamp = nextTime.getRealTimestamp();
}
if(!(nextTime == null || lastTime == null)) {
curSpeed = ((double)((nextTime.getTimestamp()-lastTime.getTimestamp())))/((double)((nextTimeStamp-lastTimeStamp)));
}
if(lastTimeStamp == nextTimeStamp) { if(lastTimeStamp == nextTimeStamp) {
curSpeed = 0f; curSpeed = 0f;
} }
@@ -198,8 +420,10 @@ public class ReplayProcess {
if(pos != null) ReplayHandler.getCameraEntity().movePath(pos); if(pos != null) ReplayHandler.getCameraEntity().movePath(pos);
ReplayHandler.setSpeed(curSpeed); ReplayHandler.setSpeed((float)curSpeed);
if(isVideoRecording()) {
MCTimerHandler.updateTimer((1f/ReplayMod.replaySettings.getVideoFramerate()));
}
if(curPos != null) ReplayHandler.setReplayPos(curPos); if(curPos != null) ReplayHandler.setReplayPos(curPos);
//splinePos = (index of last entry + add) / total entries //splinePos = (index of last entry + add) / total entries
@@ -207,6 +431,28 @@ public class ReplayProcess {
lastRealReplayTime = curRealReplayTime; lastRealReplayTime = curRealReplayTime;
lastRealTime = curTime; lastRealTime = curTime;
if(splinePos >= 1) stopReplayProcess(true); //Video capturing, for testing purposes
if(isVideoRecording()) {
try {
if(!VideoWriter.isRecording() && ReplayHandler.isReplaying()) {
VideoWriter.startRecording(mc.displayWidth, mc.displayHeight);
} else {
VideoWriter.writeImage(ScreenCapture.captureScreen());
}
} catch(Exception e) {
e.printStackTrace();
}
}
if(requestFinish) {
stopReplayProcess(true);
VideoWriter.endRecording();
}
if(splinePos >= 1) {
requestFinish = true;
}
deepBlock = false;
} }
} }

View File

@@ -15,6 +15,7 @@ import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.UUID;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiDownloadTerrain; import net.minecraft.client.gui.GuiDownloadTerrain;
@@ -27,10 +28,12 @@ import net.minecraft.network.Packet;
import net.minecraft.network.PacketBuffer; import net.minecraft.network.PacketBuffer;
import net.minecraft.network.play.server.S01PacketJoinGame; import net.minecraft.network.play.server.S01PacketJoinGame;
import net.minecraft.network.play.server.S02PacketChat; import net.minecraft.network.play.server.S02PacketChat;
import net.minecraft.network.play.server.S03PacketTimeUpdate;
import net.minecraft.network.play.server.S06PacketUpdateHealth; import net.minecraft.network.play.server.S06PacketUpdateHealth;
import net.minecraft.network.play.server.S07PacketRespawn; import net.minecraft.network.play.server.S07PacketRespawn;
import net.minecraft.network.play.server.S08PacketPlayerPosLook; import net.minecraft.network.play.server.S08PacketPlayerPosLook;
import net.minecraft.network.play.server.S0BPacketAnimation; import net.minecraft.network.play.server.S0BPacketAnimation;
import net.minecraft.network.play.server.S0CPacketSpawnPlayer;
import net.minecraft.network.play.server.S1CPacketEntityMetadata; import net.minecraft.network.play.server.S1CPacketEntityMetadata;
import net.minecraft.network.play.server.S1DPacketEntityEffect; import net.minecraft.network.play.server.S1DPacketEntityEffect;
import net.minecraft.network.play.server.S1FPacketSetExperience; import net.minecraft.network.play.server.S1FPacketSetExperience;
@@ -44,11 +47,12 @@ import net.minecraft.network.play.server.S2FPacketSetSlot;
import net.minecraft.network.play.server.S30PacketWindowItems; import net.minecraft.network.play.server.S30PacketWindowItems;
import net.minecraft.network.play.server.S36PacketSignEditorOpen; import net.minecraft.network.play.server.S36PacketSignEditorOpen;
import net.minecraft.network.play.server.S37PacketStatistics; import net.minecraft.network.play.server.S37PacketStatistics;
import net.minecraft.network.play.server.S38PacketPlayerListItem;
import net.minecraft.network.play.server.S38PacketPlayerListItem.AddPlayerData;
import net.minecraft.network.play.server.S39PacketPlayerAbilities; import net.minecraft.network.play.server.S39PacketPlayerAbilities;
import net.minecraft.network.play.server.S43PacketCamera; import net.minecraft.network.play.server.S43PacketCamera;
import net.minecraft.network.play.server.S45PacketTitle; import net.minecraft.network.play.server.S45PacketTitle;
import net.minecraft.network.play.server.S48PacketResourcePackSend; import net.minecraft.network.play.server.S48PacketResourcePackSend;
import net.minecraft.util.Timer;
import net.minecraft.world.EnumDifficulty; import net.minecraft.world.EnumDifficulty;
import net.minecraft.world.WorldSettings.GameType; import net.minecraft.world.WorldSettings.GameType;
import net.minecraft.world.WorldType; import net.minecraft.world.WorldType;
@@ -59,6 +63,7 @@ import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.mojang.authlib.GameProfile;
import eu.crushedpixel.replaymod.ReplayMod; import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.entities.CameraEntity; import eu.crushedpixel.replaymod.entities.CameraEntity;
@@ -106,16 +111,6 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
private Field chatPacketPosition; private Field chatPacketPosition;
private Minecraft mc = Minecraft.getMinecraft(); private Minecraft mc = Minecraft.getMinecraft();
public static Field mcTimer;
static {
try {
mcTimer = Minecraft.class.getDeclaredField(MCPNames.field("field_71428_T"));
mcTimer.setAccessible(true);
} catch(Exception e) {
e.printStackTrace();
}
}
private long now = System.currentTimeMillis(); private long now = System.currentTimeMillis();
@@ -168,13 +163,7 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
public void setReplaySpeed(final double d) { public void setReplaySpeed(final double d) {
if(d != 0) this.replaySpeed = d; if(d != 0) this.replaySpeed = d;
try { MCTimerHandler.setTimerSpeed((float)d);
Timer timer = (Timer)mcTimer.get(mc);
timer.timerSpeed = (float)d;
} catch (Exception e) {
e.printStackTrace();
}
} }
public ReplaySender(final File replayFile, NetworkManager nm) { public ReplaySender(final File replayFile, NetworkManager nm) {
@@ -246,7 +235,6 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
@Override @Override
public void run() { public void run() {
try { try {
dis = new DataInputStream(archive.getInputStream(replayEntry)); dis = new DataInputStream(archive.getInputStream(replayEntry));
} catch(Exception e) { } catch(Exception e) {
@@ -267,7 +255,7 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
lastPacketSent = System.currentTimeMillis(); lastPacketSent = System.currentTimeMillis();
ReplayHandler.restartReplay(); ReplayHandler.restartReplay();
} }
while(!startFromBeginning && (!paused() || FMLClientHandler.instance().isGUIOpen(GuiDownloadTerrain.class))) { while(!terminate && !startFromBeginning && (!paused() || FMLClientHandler.instance().isGUIOpen(GuiDownloadTerrain.class))) {
try { try {
/* /*
@@ -316,9 +304,9 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
if(hurryToTimestamp && currentTimeStamp >= desiredTimeStamp && !startFromBeginning) { if(hurryToTimestamp && currentTimeStamp >= desiredTimeStamp && !startFromBeginning) {
hurryToTimestamp = false; hurryToTimestamp = false;
if(!ReplayHandler.isReplaying() || hasRestarted) { if(!ReplayHandler.isReplaying() || hasRestarted) {
((Timer)mcTimer.get(mc)).elapsedPartialTicks += 5; MCTimerHandler.advanceRenderPartialTicks(5);
((Timer)mcTimer.get(mc)).elapsedTicks += 5; MCTimerHandler.advancePartialTicks(5);
((Timer)mcTimer.get(mc)).renderPartialTicks += 5; MCTimerHandler.advanceTicks(5);
} }
if(!ReplayHandler.isReplaying()) { if(!ReplayHandler.isReplaying()) {
Position pos = ReplayHandler.getLastPosition(); Position pos = ReplayHandler.getLastPosition();
@@ -339,8 +327,11 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
} }
} catch(EOFException eof) { } catch(EOFException eof) {
dis = new DataInputStream(archive.getInputStream(replayEntry));
setReplaySpeed(0); setReplaySpeed(0);
} catch(IOException e) {} } catch(IOException e) {
e.printStackTrace();
}
} }
} }
} catch(Exception e) { } catch(Exception e) {
@@ -369,6 +360,21 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
private boolean allowMovement = false; private boolean allowMovement = false;
private static Field playerUUIDField;
private static Field gameProfileField;
static {
try {
playerUUIDField = S0CPacketSpawnPlayer.class.getDeclaredField(MCPNames.field("field_179820_b"));
playerUUIDField.setAccessible(true);
gameProfileField = S38PacketPlayerListItem.AddPlayerData.class.getDeclaredField("field_179964_d");
gameProfileField.setAccessible(true);
} catch(Exception e) {
e.printStackTrace();
}
}
@Override @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception { throws Exception {
@@ -376,6 +382,10 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
return; return;
} }
if(ctx == null) {
ctx = this.ctx;
}
if(msg instanceof Packet) { if(msg instanceof Packet) {
super.channelRead(ctx, msg); super.channelRead(ctx, msg);
return; return;
@@ -396,6 +406,10 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
p instanceof S2APacketParticles) return; p instanceof S2APacketParticles) return;
} }
if(p instanceof S03PacketTimeUpdate) {
p = TimeHandler.getTimePacket((S03PacketTimeUpdate)p);
}
if(p instanceof S02PacketChat) { if(p instanceof S02PacketChat) {
byte pos = (Byte)chatPacketPosition.get(p); byte pos = (Byte)chatPacketPosition.get(p);
if(pos == 1) { //Ignores command block output sent if(pos == 1) { //Ignores command block output sent
@@ -408,22 +422,6 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
try { try {
p.readPacketData(pb); p.readPacketData(pb);
/*
if(p instanceof S0CPacketSpawnPlayer) {
S0CPacketSpawnPlayer sp = (S0CPacketSpawnPlayer)p;
System.out.println("PACKET SPAWN PLAYER ----------");
System.out.println("ENTITY ID: "+sp.func_148943_d());
System.out.println("UUID: "+sp.func_179819_c());
System.out.println("X: "+sp.func_148942_f());
System.out.println("Y: "+sp.func_148949_g());
System.out.println("Z: "+sp.func_148946_h());
System.out.println("YAW: "+sp.func_148941_i());
System.out.println("PITCH: "+sp.func_148945_j());
System.out.println("ITEM: "+sp.func_148947_k());
System.out.println("PACKET END -------------------");
}
*/
if(p instanceof S1CPacketEntityMetadata) { if(p instanceof S1CPacketEntityMetadata) {
if((Integer)metadataPacketEntityId.get(p) == actualID) { if((Integer)metadataPacketEntityId.get(p) == actualID) {
metadataPacketEntityId.set(p, RecordingHandler.entityID); metadataPacketEntityId.set(p, RecordingHandler.entityID);
@@ -444,6 +442,33 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
difficulty, maxPlayers, worldType, false); difficulty, maxPlayers, worldType, false);
} }
String crPxl = "2cb08a5951f34e98bd0985d9747e80df";
String johni = "cd3d4be14ffc2f9db432db09e0cd254b";
if(p instanceof S38PacketPlayerListItem) {
S38PacketPlayerListItem pp = (S38PacketPlayerListItem)p;
if(((AddPlayerData)pp.func_179767_a().get(0)).func_179962_a().getId().toString().replace("-", "").equals(crPxl)) {
GameProfile johniGP = new GameProfile(UUID.fromString(johni.replaceAll(
"(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})",
"$1-$2-$3-$4-$5")), "Johni0702");
gameProfileField.set(pp.func_179767_a().get(0), johniGP);
//pp.func_179767_a().set(0, johniGP);
p = pp;
}
}
if(p instanceof S0CPacketSpawnPlayer) {
S0CPacketSpawnPlayer sp = (S0CPacketSpawnPlayer)p;
if(sp.func_179819_c().toString().replace("-", "").equals(crPxl)) {
playerUUIDField.set(sp, UUID.fromString(johni.replaceAll(
"(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})",
"$1-$2-$3-$4-$5")));
}
p = sp;
}
if(p instanceof S07PacketRespawn) { if(p instanceof S07PacketRespawn) {
allowMovement = true; allowMovement = true;
@@ -491,8 +516,6 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
if(p instanceof S43PacketCamera) { if(p instanceof S43PacketCamera) {
return; return;
} }
//if(ReplayHandler.isReplaying())
// System.out.println("packet arrived");
super.channelRead(ctx, p); super.channelRead(ctx, p);
} catch(Exception e) { } catch(Exception e) {
System.out.println(p.getClass()); System.out.println(p.getClass());
@@ -520,7 +543,7 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
public boolean paused() { public boolean paused() {
try { try {
return ((Timer)mcTimer.get(mc)).timerSpeed == 0; return MCTimerHandler.getTimerSpeed() == 0;
} catch(Exception e) {} } catch(Exception e) {}
return true; return true;
} }
@@ -528,7 +551,6 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
public double getReplaySpeed() { public double getReplaySpeed() {
if(!paused()) return replaySpeed; if(!paused()) return replaySpeed;
else return 0; else return 0;
//return timeInfo.get().getSpeed();
} }
public File getReplayFile() { public File getReplayFile() {

View File

@@ -0,0 +1,28 @@
package eu.crushedpixel.replaymod.replay;
import net.minecraft.network.play.server.S03PacketTimeUpdate;
public class TimeHandler {
private static long actualDaytime;
private static long desiredDaytime;
private static boolean timeOverridden = false;
public static boolean isTimeOverridden() {
return timeOverridden;
}
public static void setDesiredDaytime(long ddt) {
desiredDaytime = ddt;
}
public static void setTimeOverridden(boolean overridden) {
timeOverridden = overridden;
}
public static S03PacketTimeUpdate getTimePacket(S03PacketTimeUpdate packet) {
if(!timeOverridden) return packet;
return new S03PacketTimeUpdate(packet.func_149366_c(), desiredDaytime, true);
}
}

View File

@@ -14,12 +14,13 @@ import eu.crushedpixel.replaymod.replay.ReplayHandler;
public class ReplaySettings { public class ReplaySettings {
private int maximumFileSize = 0;
private boolean enableRecordingServer = true; private boolean enableRecordingServer = true;
private boolean enableRecordingSingleplayer = true; private boolean enableRecordingSingleplayer = true;
private boolean showNotifications = true; private boolean showNotifications = true;
private boolean forceLinearPath = false; private boolean forceLinearPath = false;
private boolean lightingEnabled = false; private boolean lightingEnabled = false;
private float videoQuality = 0.5f;
private int videoFramerate = 30;
private static Field mcTimer; private static Field mcTimer;
@@ -33,21 +34,29 @@ public class ReplaySettings {
} }
} }
public ReplaySettings(int maximumFileSize, boolean enableRecordingServer, public ReplaySettings(boolean enableRecordingServer,
boolean enableRecordingSingleplayer, boolean showNotifications, boolean forceLinearPath, boolean lightingEnabled) { boolean enableRecordingSingleplayer, boolean showNotifications, boolean forceLinearPath, boolean lightingEnabled, int framerate, float videoQuality) {
this.maximumFileSize = maximumFileSize;
this.enableRecordingServer = enableRecordingServer; this.enableRecordingServer = enableRecordingServer;
this.enableRecordingSingleplayer = enableRecordingSingleplayer; this.enableRecordingSingleplayer = enableRecordingSingleplayer;
this.showNotifications = showNotifications; this.showNotifications = showNotifications;
this.forceLinearPath = forceLinearPath; this.forceLinearPath = forceLinearPath;
this.lightingEnabled = lightingEnabled; this.lightingEnabled = lightingEnabled;
this.videoFramerate = Math.min(120, Math.max(10, framerate));
this.videoQuality = Math.min(0.9f, Math.max(0.1f, videoQuality));
} }
public int getMaximumFileSize() { public int getVideoFramerate() {
return maximumFileSize; return videoFramerate;
} }
public void setMaximumFileSize(int maximumFileSize) { public void setVideoFramerate(int framerate) {
this.maximumFileSize = maximumFileSize; this.videoFramerate = Math.min(120, Math.max(10, framerate));
rewriteSettings();
}
public float getVideoQuality() {
return videoQuality;
}
public void setVideoQuality(float videoQuality) {
this.videoQuality = Math.min(0.9f, Math.max(0.1f, videoQuality));
rewriteSettings(); rewriteSettings();
} }
public boolean isEnableRecordingServer() { public boolean isEnableRecordingServer() {
@@ -108,11 +117,13 @@ public class ReplaySettings {
Map<String, Object> map = new LinkedHashMap<String, Object>(); Map<String, Object> map = new LinkedHashMap<String, Object>();
map.put("Enable Notifications", showNotifications); map.put("Enable Notifications", showNotifications);
map.put("Maximum File Size", maximumFileSize);
map.put("Record Server", enableRecordingServer); map.put("Record Server", enableRecordingServer);
map.put("Record Singleplayer", enableRecordingSingleplayer); map.put("Record Singleplayer", enableRecordingSingleplayer);
map.put("Placeholder 1", null);
map.put("Force Linear Movement", forceLinearPath); map.put("Force Linear Movement", forceLinearPath);
map.put("Enable Lighting", lightingEnabled); map.put("Enable Lighting", lightingEnabled);
map.put("Video Quality", videoQuality);
map.put("Video Framerate", videoFramerate);
return map; return map;
} }
@@ -120,12 +131,13 @@ public class ReplaySettings {
public void setOptions(Map<String, Object> map) { public void setOptions(Map<String, Object> map) {
try { try {
maximumFileSize = (Integer)map.get("Maximum File Size");
showNotifications = (Boolean)map.get("Enable Notifications"); showNotifications = (Boolean)map.get("Enable Notifications");
enableRecordingServer = (Boolean)map.get("Record Server"); enableRecordingServer = (Boolean)map.get("Record Server");
enableRecordingSingleplayer = (Boolean)map.get("Record Singleplayer"); enableRecordingSingleplayer = (Boolean)map.get("Record Singleplayer");
forceLinearPath = (Boolean)map.get("Force Linear Movement"); forceLinearPath = (Boolean)map.get("Force Linear Movement");
lightingEnabled = (Boolean)map.get("Enable Lighting"); lightingEnabled = (Boolean)map.get("Enable Lighting");
videoQuality = (Float)map.get("Video Quality");
videoFramerate = (Integer)map.get("Video Framerate");
rewriteSettings(); rewriteSettings();
} catch(Exception e) { } catch(Exception e) {
@@ -139,11 +151,12 @@ public class ReplaySettings {
ReplayMod.instance.config.removeCategory(ReplayMod.instance.config.getCategory("settings")); ReplayMod.instance.config.removeCategory(ReplayMod.instance.config.getCategory("settings"));
Property recServer = ReplayMod.instance.config.get("settings", "enableRecordingServer", enableRecordingServer, "Defines whether a recording should be started upon joining a server."); Property recServer = ReplayMod.instance.config.get("settings", "enableRecordingServer", enableRecordingServer, "Defines whether a recording should be started upon joining a server.");
Property recSP = ReplayMod.instance.config.get("settings", "enableRecordingSingleplayer", enableRecordingSingleplayer, "Defines whether a recording should be started upon joining a singleplayer world."); Property recSP = ReplayMod.instance.config.get("settings", "enableRecordingSingleplayer", enableRecordingSingleplayer, "Defines whether a recording should be started upon joining a singleplayer world.");
Property maxFileSize = ReplayMod.instance.config.get("settings", "maximumFileSize", maximumFileSize, "The maximum File size (in MB) of a recording. 0 means unlimited.");
Property showNot = ReplayMod.instance.config.get("settings", "showNotifications", showNotifications, "Defines whether notifications should be sent to the player."); Property showNot = ReplayMod.instance.config.get("settings", "showNotifications", showNotifications, "Defines whether notifications should be sent to the player.");
Property linear = ReplayMod.instance.config.get("settings", "forceLinearPath", forceLinearPath, "Defines whether travelling paths should be linear instead of interpolated."); Property linear = ReplayMod.instance.config.get("settings", "forceLinearPath", forceLinearPath, "Defines whether travelling paths should be linear instead of interpolated.");
Property lighting = ReplayMod.instance.config.get("settings", "enableLighting", lightingEnabled, "If enabled, the whole map is lighted."); Property lighting = ReplayMod.instance.config.get("settings", "enableLighting", lightingEnabled, "If enabled, the whole map is lighted.");
Property vq = ReplayMod.instance.config.get("settings", "videoQuality", videoQuality, "The quality of the exported video files from 0.1 to 0.9");
Property framerate = ReplayMod.instance.config.get("settings", "videoFramerate", videoFramerate, "The framerate of the exported video files from 10 to 120");
ReplayMod.instance.config.save(); ReplayMod.instance.config.save();
} }
} }

View File

@@ -1,4 +1,4 @@
package eu.crushedpixel.replaymod.replay.screenshot; package eu.crushedpixel.replaymod.video;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Rectangle; import java.awt.Rectangle;
@@ -33,8 +33,6 @@ import eu.crushedpixel.replaymod.utils.ImageUtils;
public class ReplayScreenshot { public class ReplayScreenshot {
private static Minecraft mc = Minecraft.getMinecraft(); private static Minecraft mc = Minecraft.getMinecraft();
private static IntBuffer pixelBuffer;
private static int[] pixelValues;
private static final byte[] uniqueBytes = new byte[]{0,1,1,2,3,5,8}; private static final byte[] uniqueBytes = new byte[]{0,1,1,2,3,5,8};
@@ -45,13 +43,20 @@ public class ReplayScreenshot {
private static GuiScreen beforeScreen; private static GuiScreen beforeScreen;
public static void prepareScreenshot() { public static void prepareScreenshot() {
System.out.println("thumbnail preparing");
before = mc.gameSettings.hideGUI; before = mc.gameSettings.hideGUI;
beforeSpeed = ReplayHandler.getSpeed(); beforeSpeed = ReplayHandler.getSpeed();
beforeScreen = mc.currentScreen; beforeScreen = mc.currentScreen;
} }
private static boolean locked = false;
public static void saveScreenshot(Framebuffer buffer) { public static void saveScreenshot(Framebuffer buffer) {
if(locked) return;
locked = true;
System.out.println("thumbnail started");
try { try {
GuiReplaySaving.replaySaving = true; GuiReplaySaving.replaySaving = true;
@@ -61,59 +66,7 @@ public class ReplayScreenshot {
mc.entityRenderer.updateCameraAndRender(0); mc.entityRenderer.updateCameraAndRender(0);
ReplayHandler.setSpeed(0); ReplayHandler.setSpeed(0);
int width = mc.displayWidth; final BufferedImage fbi = ScreenCapture.captureScreen();
int height = mc.displayHeight;
if (OpenGlHelper.isFramebufferEnabled())
{
width = buffer.framebufferTextureWidth;
height = buffer.framebufferTextureHeight;
}
int k = width * height;
if (pixelBuffer == null || pixelBuffer.capacity() < k)
{
pixelBuffer = BufferUtils.createIntBuffer(k);
pixelValues = new int[k];
}
GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 1);
GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
pixelBuffer.clear();
if (OpenGlHelper.isFramebufferEnabled()) {
GlStateManager.bindTexture(buffer.framebufferTexture);
GL11.glGetTexImage(GL11.GL_TEXTURE_2D, 0, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, pixelBuffer);
}
else {
GL11.glReadPixels(0, 0, width, height, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, pixelBuffer);
}
pixelBuffer.get(pixelValues);
TextureUtil.processPixelValues(pixelValues, width, height);
BufferedImage bufferedimage = null;
if (OpenGlHelper.isFramebufferEnabled())
{
bufferedimage = new BufferedImage(buffer.framebufferWidth, buffer.framebufferHeight, 1);
int l = buffer.framebufferTextureHeight - buffer.framebufferHeight;
for (int i1 = l; i1 < buffer.framebufferTextureHeight; ++i1)
{
for (int j1 = 0; j1 < buffer.framebufferWidth; ++j1)
{
bufferedimage.setRGB(j1, i1 - l, pixelValues[i1 * buffer.framebufferTextureWidth + j1]);
}
}
}
else {
bufferedimage = new BufferedImage(width, height, 1);
bufferedimage.setRGB(0, 0, width, height, pixelValues, 0, width);
}
final BufferedImage fbi = bufferedimage;
mc.gameSettings.hideGUI = before; mc.gameSettings.hideGUI = before;
mc.currentScreen = beforeScreen; mc.currentScreen = beforeScreen;
@@ -125,15 +78,13 @@ public class ReplayScreenshot {
@Override @Override
public void run() { public void run() {
try { try {
System.out.println("thumbnail saving started");
float aspect = 1280f/720f; float aspect = 1280f/720f;
Rectangle rect; Rectangle rect;
if((float)fbi.getWidth()/(float)fbi.getHeight() <= aspect) { if((float)fbi.getWidth()/(float)fbi.getHeight() <= aspect) {
int h = Math.round(fbi.getWidth()/aspect); int h = Math.round(fbi.getWidth()/aspect);
int y = (fbi.getHeight()/2) - (h/2); int y = (fbi.getHeight()/2) - (h/2);
System.out.println(h+" | "+y);
rect = new Rectangle(0, y, fbi.getWidth(), h); rect = new Rectangle(0, y, fbi.getWidth(), h);
} else { } else {
int w = Math.round(fbi.getHeight()*aspect); int w = Math.round(fbi.getHeight()*aspect);
@@ -152,7 +103,6 @@ public class ReplayScreenshot {
int h = 720; int h = 720;
int w = 1280; int w = 1280;
//int w = width*(h/height);
BufferedImage img = ImageUtils.scaleImage(nbi, new Dimension(w, h)); BufferedImage img = ImageUtils.scaleImage(nbi, new Dimension(w, h));
@@ -207,11 +157,13 @@ public class ReplayScreenshot {
zout.close(); zout.close();
tempFile.delete(); tempFile.delete();
temp.delete(); temp.delete();
System.out.println("thumbnail saving finished");
ChatMessageRequests.addChatMessage("Thumbnail has been successfully saved", ChatMessageType.INFORMATION); ChatMessageRequests.addChatMessage("Thumbnail has been successfully saved", ChatMessageType.INFORMATION);
} catch(Exception e) {} } catch(Exception e) {}
finally { finally {
GuiReplaySaving.replaySaving = false; GuiReplaySaving.replaySaving = false;
locked = false;
} }
} }
}); });

View File

@@ -0,0 +1,17 @@
package eu.crushedpixel.replaymod.video;
import eu.crushedpixel.replaymod.replay.ReplayProcess;
import net.minecraft.util.Timer;
public class ReplayTimer extends Timer {
public ReplayTimer(float p_i1018_1_) {
super(p_i1018_1_);
}
@Override
public void updateTimer() {
if(ReplayProcess.isVideoRecording()) return;
super.updateTimer();
}
}

View File

@@ -0,0 +1,85 @@
package eu.crushedpixel.replaymod.video;
import java.awt.AWTException;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.nio.IntBuffer;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.texture.TextureUtil;
import net.minecraft.client.shader.Framebuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.monte.screenrecorder.ScreenRecorder;
public class ScreenCapture {
private static final Minecraft mc = Minecraft.getMinecraft();
private static IntBuffer pixelBuffer;
private static int[] pixelValues;
public static BufferedImage captureScreen() {
int width = mc.displayWidth;
int height = mc.displayHeight;
Framebuffer buffer = mc.getFramebuffer();
if (OpenGlHelper.isFramebufferEnabled())
{
width = buffer.framebufferTextureWidth;
height = buffer.framebufferTextureHeight;
}
int k = width * height;
if (pixelBuffer == null || pixelBuffer.capacity() < k)
{
pixelBuffer = BufferUtils.createIntBuffer(k);
pixelValues = new int[k];
}
GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 1);
GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
pixelBuffer.clear();
if (OpenGlHelper.isFramebufferEnabled()) {
GlStateManager.bindTexture(buffer.framebufferTexture);
GL11.glGetTexImage(GL11.GL_TEXTURE_2D, 0, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, pixelBuffer);
}
else {
GL11.glReadPixels(0, 0, width, height, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, pixelBuffer);
}
pixelBuffer.get(pixelValues);
TextureUtil.processPixelValues(pixelValues, width, height);
BufferedImage bufferedimage = null;
if (OpenGlHelper.isFramebufferEnabled())
{
bufferedimage = new BufferedImage(buffer.framebufferWidth, buffer.framebufferHeight, 1);
int l = buffer.framebufferTextureHeight - buffer.framebufferHeight;
for (int i1 = l; i1 < buffer.framebufferTextureHeight; ++i1)
{
for (int j1 = 0; j1 < buffer.framebufferWidth; ++j1)
{
bufferedimage.setRGB(j1, i1 - l, pixelValues[i1 * buffer.framebufferTextureWidth + j1]);
}
}
}
else {
bufferedimage = new BufferedImage(width, height, 1);
bufferedimage.setRGB(0, 0, width, height, pixelValues, 0, width);
}
return bufferedimage;
}
}

View File

@@ -0,0 +1,98 @@
package eu.crushedpixel.replaymod.video;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import org.monte.media.Buffer;
import org.monte.media.Format;
import org.monte.media.FormatKeys;
import org.monte.media.FormatKeys.MediaType;
import org.monte.media.MovieWriter;
import org.monte.media.Registry;
import org.monte.media.VideoFormatKeys;
import org.monte.media.math.Rational;
import eu.crushedpixel.replaymod.ReplayMod;
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;
private static Buffer buf;
private static int track;
public static boolean isRecording() {
return isRecording;
}
public static void startRecording(int width, int height) {
if(isRecording) {
IllegalStateException up = new IllegalStateException("VideoWriter is already recording!");
throw up; //lolololo
}
isRecording = true;
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();
out = Registry.getInstance().getWriter(file);
Format format = new Format(FormatKeys.MediaTypeKey, MediaType.VIDEO,
FormatKeys.EncodingKey, VideoFormatKeys.ENCODING_AVI_MJPG,
FormatKeys.FrameRateKey, new Rational(ReplayMod.replaySettings.getVideoFramerate(), 1),
VideoFormatKeys.WidthKey, width,
VideoFormatKeys.HeightKey, height,
VideoFormatKeys.DepthKey, 24,
VideoFormatKeys.QualityKey, ReplayMod.replaySettings.getVideoQuality());
track = out.addTrack(format);
buf = new Buffer();
buf.format = new Format(VideoFormatKeys.DataClassKey, BufferedImage.class);
buf.sampleDuration = out.getFormat(track).get(VideoFormatKeys.FrameRateKey).inverse();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void writeImage(BufferedImage image) {
if(requestFinish || !isRecording) {
IllegalStateException up = new IllegalStateException(
"The VideoWriter is currently not available. Please try again later.");
throw up; //lolololo^2
}
try {
buf.data = image;
out.write(track, buf);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void endRecording() {
if(!isRecording) return;
isRecording = false;
try {
out.close();
} catch(Exception e) {
e.printStackTrace();
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB