Reworked Camera Movement in Replay Viewer

Finally made Replay Trimming work
Fixed and dried ReplayProcess pathTick() method
This commit is contained in:
Marius Metzger
2015-03-31 01:10:01 +02:00
parent 11e26e0129
commit becbf47088
19 changed files with 237 additions and 247 deletions

View File

@@ -1,5 +1,9 @@
package eu.crushedpixel.replaymod;
import java.io.IOException;
import javax.swing.JOptionPane;
import net.minecraft.client.Minecraft;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.config.Configuration;
@@ -12,10 +16,12 @@ import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import eu.crushedpixel.replaymod.api.client.ApiClient;
import eu.crushedpixel.replaymod.api.client.ApiException;
import eu.crushedpixel.replaymod.events.GuiEventHandler;
import eu.crushedpixel.replaymod.events.GuiReplayOverlay;
import eu.crushedpixel.replaymod.events.KeyInputHandler;
import eu.crushedpixel.replaymod.events.RecordingHandler;
import eu.crushedpixel.replaymod.online.authentication.AuthenticationHandler;
import eu.crushedpixel.replaymod.recording.ConnectionEventHandler;
import eu.crushedpixel.replaymod.registry.KeybindRegistry;
import eu.crushedpixel.replaymod.renderer.SafeEntityRenderer;
@@ -108,9 +114,21 @@ public class ReplayMod
} catch(Exception e) {
e.printStackTrace();
}
//ReplayTrimmer.trim(new File("/Users/mariusmetzger/toTrim.mcpr"), new File("/Users/mariusmetzger/trimmed.mcpr"), 1000*60, 2000*60);
//if(AuthenticationHandler.isBlacklisted(Minecraft.getMinecraft().getSession().getPlayerID())) {
//System.exit(0);
//}
/*
boolean auth = false;
try {
auth = AuthenticationHandler.hasDonated(Minecraft.getMinecraft().getSession().getPlayerID());
} catch(Exception e) {
JOptionPane.showMessageDialog(null, "Couldn't connect to the Replay Mod Server to verify whether you donated!");
FMLCommonHandler.instance().exitJava(0, false);
}
if(!auth) {
JOptionPane.showMessageDialog(null, "It seems like you didn't donate, so you can't use the Replay Mod yet.");
FMLCommonHandler.instance().exitJava(0, false);
}
*/
}
}

View File

@@ -17,6 +17,7 @@ import com.google.gson.JsonParser;
import eu.crushedpixel.replaymod.api.client.holders.ApiError;
import eu.crushedpixel.replaymod.api.client.holders.AuthKey;
import eu.crushedpixel.replaymod.api.client.holders.Donated;
import eu.crushedpixel.replaymod.api.client.holders.FileInfo;
import eu.crushedpixel.replaymod.api.client.holders.SearchResult;
import eu.crushedpixel.replaymod.api.client.holders.Success;
@@ -35,7 +36,7 @@ public class ApiClient {
AuthKey auth = invokeAndReturn(builder, AuthKey.class);
return auth;
}
public boolean logout(String auth) throws IOException, ApiException {
QueryBuilder builder = new QueryBuilder(ApiMethods.logout);
builder.put("auth", auth);
@@ -43,6 +44,13 @@ public class ApiClient {
return succ.isSuccess();
}
public boolean hasDonated(String uuid) throws IOException, ApiException {
QueryBuilder builder = new QueryBuilder(ApiMethods.check_auth);
builder.put("uuid", uuid);
Donated succ = invokeAndReturn(builder, Donated.class);
return succ.hasDonated();
}
public UserFiles getUserFiles(String auth, String user) throws IOException, ApiException {
QueryBuilder builder = new QueryBuilder(ApiMethods.replay_files);
builder.put("auth", auth);

View File

@@ -11,5 +11,6 @@ public class ApiMethods {
public static final String get_thumbnail = "get_thumbnail";
public static final String remove_file = "remove_file";
public static final String rate_file = "rate_file";
public static final String check_auth = "check_auth";
}

View File

@@ -0,0 +1,10 @@
package eu.crushedpixel.replaymod.api.client.holders;
public class Donated {
private boolean donated = false;
public boolean hasDonated() {
return donated;
}
}

View File

@@ -21,7 +21,6 @@ public class ClassTransformer implements IClassTransformer {
@Override
public byte[] transform(String name, String transformedName,
byte[] basicClass) {
if(name.equals("cqh")) {
return patchRenderEffectMethod(name, basicClass, true);
}

View File

@@ -25,12 +25,14 @@ public class CameraEntity extends EntityPlayer {
private Field drawBlockOutline;
private static final double SPEED = 10; //2 blocks per second
private static final double MAX_SPEED = 20;
private double decay = 6; //decays by 75% per second;
private double decay = 4;
private long lastCall = 0;
private boolean speedup = false;
//frac = time since last tick
public void updateMovement() {
Minecraft mc = Minecraft.getMinecraft();
@@ -40,15 +42,6 @@ public class CameraEntity extends EntityPlayer {
mc.thePlayer.rotationPitch = mc.getRenderViewEntity().rotationPitch;
mc.thePlayer.rotationYaw = mc.getRenderViewEntity().rotationYaw;
/*
mc.thePlayer.posX = mc.getRenderViewEntity().posX;
mc.thePlayer.posY = mc.getRenderViewEntity().posY;
mc.thePlayer.posZ = mc.getRenderViewEntity().posZ;
TimeHandler.setDesiredDaytime(18000);
TimeHandler.setTimeOverridden(true);
*/
//removes water/suffocation/shadow overlays in screen
mc.thePlayer.posX = 0;
mc.thePlayer.posY = 500;
@@ -70,7 +63,12 @@ public class CameraEntity extends EntityPlayer {
moveRelative(movement.xCoord*factor, movement.yCoord*factor, movement.zCoord*factor);
double decFac = Math.max(0, 1-(decay*(frac/1000D)));
motion *= decFac;
if(!speedup) {
motion *= decFac;
} else {
speedup = false;
}
lastCall = Sys.getTime();
}
@@ -79,6 +77,11 @@ public class CameraEntity extends EntityPlayer {
this.setRotation(yaw, pitch);
}
public void speedUp() {
this.motion = Math.min(MAX_SPEED, motion+0.1);
speedup = true;
}
public void setMovement(MoveDirection dir) {
Vec3 oldDir = direction;
@@ -104,8 +107,6 @@ public class CameraEntity extends EntityPlayer {
}
if(oldDir != null) direction = direction.normalize().add(new Vec3(oldDir.xCoord*(motion/4f), oldDir.yCoord*(motion/4f), oldDir.zCoord*(motion/4f)).normalize());
this.motion = SPEED;
}
public void moveAbsolute(double x, double y, double z) {

View File

@@ -36,6 +36,7 @@ import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.studio.VersionValidator;
import eu.crushedpixel.replaymod.timer.MCTimerHandler;
import eu.crushedpixel.replaymod.utils.MouseUtils;
import eu.crushedpixel.replaymod.utils.ReplayFileIO;
import eu.crushedpixel.replaymod.utils.ResourceHelper;
import eu.crushedpixel.replaymod.video.VideoWriter;
@@ -43,6 +44,8 @@ public class GuiEventHandler {
private static Minecraft mc = Minecraft.getMinecraft();
private static int replayCount = 0;
private static List<Class> allowedGUIs = new ArrayList<Class>() {
{
add(GuiReplaySettings.class);
@@ -107,7 +110,12 @@ public class GuiEventHandler {
e.gui.drawString(mc.fontRendererObj, "LOGGED OUT", 5, 15, DARK_RED.getRGB());
}
if(!VersionValidator.isValid) {
if(replayCount == 0) {
if(editorButton.isMouseOver()) {
Point mouse = MouseUtils.getMousePos();
e.gui.drawCenteredString(mc.fontRendererObj, "At least one Replay required", (int)mouse.getX(), (int)mouse.getY()+4, Color.RED.getRGB());
}
} else if(!VersionValidator.isValid) {
if(editorButton.isMouseOver()) {
Point mouse = MouseUtils.getMousePos();
e.gui.drawCenteredString(mc.fontRendererObj, "Java 1.7 or newer required", (int)mouse.getX(), (int)mouse.getY()+4, Color.RED.getRGB());
@@ -146,9 +154,11 @@ public class GuiEventHandler {
//rm.enabled = AuthenticationHandler.isAuthenticated();
event.buttonList.add(rm);
replayCount = ReplayFileIO.getAllReplayFiles().size();
GuiButton re = new GuiButton(GuiConstants.REPLAY_EDITOR_BUTTON_ID, event.gui.width / 2 + 2, i1 + 2*24, "Replay Editor");
re.width = re.width/2 - 2;
re.enabled = VersionValidator.isValid;
re.enabled = VersionValidator.isValid && replayCount > 0;
event.buttonList.add(re);
editorButton = re;

View File

@@ -10,6 +10,7 @@ import java.util.concurrent.TimeUnit;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiChat;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.renderer.GlStateManager;
@@ -83,9 +84,9 @@ public class GuiReplayOverlay extends Gui {
private boolean mouseDown = false;
private static boolean requestScreenshot = false;
private static Field isGamePaused;
static {
try {
isGamePaused = Minecraft.class.getDeclaredField(MCPNames.field("field_71445_n"));
@@ -103,9 +104,9 @@ public class GuiReplayOverlay extends Gui {
public GuiReplayOverlay() {
try {
// drawBlockOutline = EntityRenderer.class.getDeclaredField(MCPNames.field("field_175073_D"));
// drawBlockOutline.setAccessible(true);
// drawBlockOutline.set(Minecraft.getMinecraft().entityRenderer, false);
// drawBlockOutline = EntityRenderer.class.getDeclaredField(MCPNames.field("field_175073_D"));
// drawBlockOutline.setAccessible(true);
// drawBlockOutline.set(Minecraft.getMinecraft().entityRenderer, false);
} catch(Exception e) {}
}
@@ -125,20 +126,20 @@ public class GuiReplayOverlay extends Gui {
ReplayHandler.getCameraEntity().updateMovement();
if(!ReplayHandler.isInPath()) onMouseMove(new MouseEvent());
FMLCommonHandler.instance().bus().post(new InputEvent.KeyInputEvent());
}
private double lastX, lastY, lastZ;
private float lastPitch, lastYaw;
@SubscribeEvent
public void onChangeView(MouseEvent event) {
if(ReplayHandler.isInPath()) {
event.setCanceled(true);
}
}
@SubscribeEvent
public void onRenderWorld(RenderWorldLastEvent event)
throws IllegalAccessException, IllegalArgumentException,
@@ -187,7 +188,7 @@ public class GuiReplayOverlay extends Gui {
@SubscribeEvent
public void onRenderGui(RenderGameOverlayEvent.Post event) throws IllegalArgumentException, IllegalAccessException {
if(!ReplayHandler.isInReplay() || FMLClientHandler.instance().isGUIOpen(GuiSpectateSelection.class) || VideoWriter.isRecording()) {
return;
}
@@ -195,7 +196,11 @@ public class GuiReplayOverlay extends Gui {
//System.out.println(System.currentTimeMillis()+" | "+MCTimerHandler.getTicks()+" | "+MCTimerHandler.getPartialTicks());
if(!ReplayGuiRegistry.hidden) ReplayGuiRegistry.hide();
if(FMLClientHandler.instance().isGUIOpen(GuiChat.class)) {
mc.displayGuiScreen(new GuiMouseInput());
}
if(event.type == ElementType.PLAYER_LIST) {
if(event.isCancelable()) {
event.setCanceled(true);
@@ -204,7 +209,7 @@ public class GuiReplayOverlay extends Gui {
}
GL11.glEnable(GL11.GL_BLEND);
// drawBlockOutline.set(Minecraft.getMinecraft().entityRenderer, false);
// drawBlockOutline.set(Minecraft.getMinecraft().entityRenderer, false);
if(!ReplayHandler.isInReplay()) {
return;
@@ -217,7 +222,7 @@ public class GuiReplayOverlay extends Gui {
Point scaled = MouseUtils.getScaledDimensions();
final int width = (int)scaled.getX();
final int height = (int)scaled.getY();
//Draw Timeline
drawTimeline(timelineX, width - 14, 9);
drawRealTimeline(realTimelineX, width - 14 - 11, realTimelineY, mouseX, mouseY);
@@ -872,8 +877,9 @@ public class GuiReplayOverlay extends Gui {
b0 = -1;
}
ReplayHandler.getCameraEntity().setAngles(f3, f4 * (float)b0);
if(ReplayHandler.getCameraEntity() != null) {
ReplayHandler.getCameraEntity().setAngles(f3, f4 * (float)b0);
}
}
}
}

View File

@@ -34,38 +34,50 @@ public class KeyInputHandler {
continue;
}
try {
boolean speedup = false;
if(ReplayHandler.isCamera()) {
if(kb.getKeyDescription().equals("key.forward")) {
ReplayHandler.getCameraEntity().setMovement(MoveDirection.FORWARD);
speedup = true;
}
if(kb.getKeyDescription().equals("key.back")) {
ReplayHandler.getCameraEntity().setMovement(MoveDirection.BACKWARD);
speedup = true;
}
if(kb.getKeyDescription().equals("key.jump")) {
ReplayHandler.getCameraEntity().setMovement(MoveDirection.UP);
speedup = true;
}
if(kb.getKeyDescription().equals("key.left")) {
ReplayHandler.getCameraEntity().setMovement(MoveDirection.LEFT);
speedup = true;
}
if(kb.getKeyDescription().equals("key.right")) {
ReplayHandler.getCameraEntity().setMovement(MoveDirection.RIGHT);
speedup = true;
}
}
if(kb.getKeyDescription().equals("key.sneak")) {
if(ReplayHandler.isCamera()) {
ReplayHandler.getCameraEntity().setMovement(MoveDirection.DOWN);
speedup = true;
} else {
ReplayHandler.spectateCamera();
}
}
if(speedup) {
ReplayHandler.getCameraEntity().speedUp();
}
if(kb.getKeyDescription().equals("key.chat")) {
mc.displayGuiScreen(new GuiMouseInput());
break;
}
//Custom registered handlers

View File

@@ -41,11 +41,6 @@ public class GuiConnectPart extends GuiStudioPart {
fontRendererObj = mc.fontRendererObj;
}
@Override
public void applyFilters() {
// TODO Auto-generated method stub
}
@Override
public String getDescription() {
return DESCRIPTION;
@@ -195,4 +190,10 @@ public class GuiConnectPart extends GuiStudioPart {
}
}
}
@Override
public void applyFilters(File replayFile, File outputFile) {
// TODO Auto-generated method stub
}
}

View File

@@ -141,6 +141,21 @@ public class GuiReplayStudio extends GuiScreen {
currentTab = StudioTab.CONNECT;
} else if(button.id == GuiConstants.REPLAY_EDITOR_MODIFY_TAB) {
currentTab = StudioTab.MODIFY;
} else if(button.id == GuiConstants.REPLAY_EDITOR_SAVE_BUTTON) {
File outputFile = getSelectedFile();
File folder = ReplayFileIO.getReplayFolder();
if(!overrideSave) {
String name = FilenameUtils.getBaseName(outputFile.getAbsolutePath())+"_edited";
File f = new File(folder, name+".mcpr");
int num = 0;
while(f.exists()) {
num++;
String fileName = name+"_"+num;
f = new File(folder, fileName+".mcpr");
}
outputFile = f;
}
currentTab.getStudioPart().applyFilters(getSelectedFile(), outputFile);
}
}

View File

@@ -1,5 +1,6 @@
package eu.crushedpixel.replaymod.gui.replaystudio;
import java.io.File;
import java.io.IOException;
import net.minecraft.client.gui.GuiScreen;
@@ -12,7 +13,7 @@ public abstract class GuiStudioPart extends GuiScreen {
protected int yPos = 0;
public abstract void applyFilters();
public abstract void applyFilters(File replayFile, File outputFile);
public abstract String getDescription();

View File

@@ -1,6 +1,10 @@
package eu.crushedpixel.replaymod.gui.replaystudio;
import java.awt.Color;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -9,6 +13,7 @@ import net.minecraft.client.Minecraft;
import org.lwjgl.input.Keyboard;
import eu.crushedpixel.replaymod.gui.elements.GuiNumberInput;
import eu.crushedpixel.replaymod.studio.StudioImplementation;
public class GuiTrimPart extends GuiStudioPart {
@@ -30,8 +35,12 @@ public class GuiTrimPart extends GuiStudioPart {
}
@Override
public void applyFilters() {
// TODO Auto-generated method stub
public void applyFilters(File replayFile, File outputFile) {
try {
StudioImplementation.trimReplay(replayFile, false, getStartTimestamp(), getEndTimestamp(), outputFile);
} catch(Exception e) {
e.printStackTrace();
}
}
private int valueOf(String text) {

View File

@@ -1,11 +1,13 @@
package eu.crushedpixel.replaymod.online.authentication;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import net.minecraft.client.Minecraft;
import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.api.client.ApiClient;
import eu.crushedpixel.replaymod.api.client.ApiException;
import eu.crushedpixel.replaymod.reflection.MCPNames;
@@ -15,6 +17,8 @@ public class AuthenticationHandler {
public static final int INVALID = 2;
public static final int NO_CONNECTION = 3;
private static final ApiClient apiClient = new ApiClient();
private static Minecraft mc = Minecraft.getMinecraft();
private static String authkey = null;
@@ -26,15 +30,9 @@ public class AuthenticationHandler {
public static String getKey() {
return authkey;
}
private static List<String> blackUUIDs = new ArrayList<String>() {
{
add("23978392a78c49cf9f5235a151fd4083"); //Hudelsohn
}
};
public static boolean isBlacklisted(String uuid) {
return blackUUIDs.contains(uuid.replace("-", ""));
public static boolean hasDonated(String uuid) throws IOException, ApiException {
return apiClient.hasDonated(uuid);
}
public static int authenticate(String username, String password) {

View File

@@ -49,7 +49,7 @@ public class ReplayProcess {
public static void startReplayProcess(boolean record) {
ReplayHandler.selectKeyframe(null);
isVideoRecording = record;
lastPosition = null;
motionSpline = null;
@@ -59,10 +59,11 @@ public class ReplayProcess {
requestFinish = false;
ChatMessageRequests.initialize();
if(ReplayHandler.getPosKeyframeCount() < 2) {
ChatMessageRequests.addChatMessage("At least 2 position keyframes required!", ChatMessageType.WARNING);
if(ReplayHandler.getPosKeyframeCount() < 2 && ReplayHandler.getTimeKeyframeCount() < 2) {
ChatMessageRequests.addChatMessage("At least 2 position or time keyframes required!", ChatMessageType.WARNING);
return;
}
startRealTime = System.currentTimeMillis();
lastRealTime = startRealTime;
lastRealReplayTime = 0;
@@ -73,7 +74,7 @@ public class ReplayProcess {
previousReplaySpeed = ReplayHandler.getSpeed();
EnchantmentTimer.resetRecordingTime();
TimeKeyframe tf = ReplayHandler.getNextTimeKeyframe(-1);
if(tf != null) {
int ts = tf.getTimestamp();
@@ -138,20 +139,26 @@ public class ReplayProcess {
}
public static void tickReplay() {
if(isVideoRecording()) {
recordingTick();
} else {
normalTick();
}
pathTick(isVideoRecording());
}
private static void normalTick() {
private static void pathTick(boolean recording) {
if(ReplayHandler.isHurrying()) {
lastRealTime = System.currentTimeMillis();
if(!recording)
lastRealTime = System.currentTimeMillis();
return;
}
if(recording) {
if(blocked) return;
deepBlock = true;
blocked = true;
}
int posCount = ReplayHandler.getPosKeyframeCount();
int timeCount = ReplayHandler.getTimeKeyframeCount();
if(!linear && motionSpline == null) {
//set up spline path
motionSpline = new SplinePoint();
@@ -182,16 +189,21 @@ public class ReplayProcess {
timeLinear.addPoint(((TimeKeyframe)kf).getTimestamp());
}
}
}
if(!calculated) {
calculated = true;
if(motionSpline != null) motionSpline.calcSpline();
if(posCount > 1)
motionSpline.calcSpline();
}
long curTime = System.currentTimeMillis();
long timeStep = curTime - lastRealTime;
long timeStep;
if(recording) {
timeStep = 1000/ReplayMod.replaySettings.getVideoFramerate();
} else {
timeStep = curTime - lastRealTime;
}
int curRealReplayTime = (int)(lastRealReplayTime + timeStep);
@@ -225,7 +237,7 @@ public class ReplayProcess {
double curSpeed = 0f;
if(nextTime != null || lastTime != null) {
if(timeCount > 1 && (nextTime != null || lastTime != null)) {
if(nextTime != null) {
nextTimeStamp = nextTime.getRealTimestamp();
} else {
@@ -239,7 +251,8 @@ public class ReplayProcess {
}
if(!(nextTime == null || lastTime == null)) {
curSpeed = ((double)((nextTime.getTimestamp()-lastTime.getTimestamp())))/((double)((nextTimeStamp-lastTimeStamp)));
if(lastTimeStamp == nextTimeStamp) curSpeed = 0f;
else curSpeed = ((double)((nextTime.getTimestamp()-lastTime.getTimestamp())))/((double)((nextTimeStamp-lastTimeStamp)));
}
if(lastTimeStamp == nextTimeStamp) {
@@ -252,25 +265,31 @@ public class ReplayProcess {
float currentPosStepPerc = (float)currentPos/(float)currentPosDiff; //The percentage of the travelled path between the current positions
if(Float.isInfinite(currentPosStepPerc)) currentPosStepPerc = 0;
int currentTimeDiff = nextTimeStamp - lastTimeStamp;
int currentTime = curRealReplayTime - lastTimeStamp;
float currentTimeStepPerc = (float)currentTime/(float)currentTimeDiff; //The percentage of the travelled path between the current timestamps
if(Float.isInfinite(currentTimeStepPerc)) currentTimeStepPerc = 0;
float splinePos = ((float)ReplayHandler.getKeyframeIndex(lastPos) + currentPosStepPerc)/(float)(ReplayHandler.getPosKeyframeCount()-1);
float timePos = ((float)ReplayHandler.getKeyframeIndex(lastTime) + currentTimeStepPerc)/(float)(ReplayHandler.getTimeKeyframeCount()-1);
float splinePos = ((float)ReplayHandler.getKeyframeIndex(lastPos) + currentPosStepPerc)/(float)(posCount-1);
float timePos = ((float)ReplayHandler.getKeyframeIndex(lastTime) + currentTimeStepPerc)/(float)(timeCount-1);
Position pos = null;
if(!linear) {
pos = motionSpline.getPoint(Math.max(0, Math.min(1, splinePos)));
if(posCount > 1) {
if(!linear) {
pos = motionSpline.getPoint(Math.max(0, Math.min(1, splinePos)));
} else {
pos = motionLinear.getPoint(Math.max(0, Math.min(1, splinePos)));
}
} else {
pos = motionLinear.getPoint(Math.max(0, Math.min(1, splinePos)));
if(posCount == 1) {
pos = ReplayHandler.getNextPositionKeyframe(-1).getPosition();
}
}
Integer curPos = null;
if(timeLinear != null) {
if(timeLinear != null && timeCount > 1) {
curPos = timeLinear.getPoint(Math.max(0, Math.min(1, timePos)));
}
@@ -278,164 +297,11 @@ public class ReplayProcess {
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()) {
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 curTime = System.currentTimeMillis();
long timeStep = 1000/ReplayMod.replaySettings.getVideoFramerate();
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) {
curSpeed = 0f;
}
}
int currentPosDiff = nextPosStamp - lastPosStamp;
int currentPos = curRealReplayTime - lastPosStamp;
float currentPosStepPerc = (float)currentPos/(float)currentPosDiff; //The percentage of the travelled path between the current positions
if(Float.isInfinite(currentPosStepPerc)) currentPosStepPerc = 0;
int currentTimeDiff = nextTimeStamp - lastTimeStamp;
int currentTime = curRealReplayTime - lastTimeStamp;
float currentTimeStepPerc = (float)currentTime/(float)currentTimeDiff; //The percentage of the travelled path between the current timestamps
if(Float.isInfinite(currentTimeStepPerc)) currentTimeStepPerc = 0;
float splinePos = ((float)ReplayHandler.getKeyframeIndex(lastPos) + currentPosStepPerc)/(float)(ReplayHandler.getPosKeyframeCount()-1);
float timePos = ((float)ReplayHandler.getKeyframeIndex(lastTime) + currentTimeStepPerc)/(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((float)curSpeed);
if(isVideoRecording()) {
if(recording) {
MCTimerHandler.updateTimer((1f/ReplayMod.replaySettings.getVideoFramerate()));
EnchantmentTimer.increaseRecordingTime((1000/ReplayMod.replaySettings.getVideoFramerate()));
}
if(curPos != null) ReplayHandler.setReplayPos(curPos);
//splinePos = (index of last entry + add) / total entries
@@ -458,13 +324,19 @@ public class ReplayProcess {
if(requestFinish) {
stopReplayProcess(true);
VideoWriter.endRecording();
requestFinish = false;
if(recording) {
VideoWriter.endRecording();
}
}
if(splinePos >= 1) {
if((splinePos >= 1 || posCount <= 1) && (timePos >= 1 || timeCount <= 1)) {
System.out.println(timePos+" | "+timeCount);
requestFinish = true;
}
deepBlock = false;
if(recording) {
deepBlock = false;
}
}
}

View File

@@ -280,7 +280,7 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
currentTimeStamp = pd.getTimestamp();
//System.out.println(currentTimeStamp);
if(!ReplayHandler.isInPath() && !hurryToTimestamp && !FMLClientHandler.instance().isGUIOpen(GuiDownloadTerrain.class)) {
if(!ReplayHandler.isInPath() && !hurryToTimestamp && (mc.theWorld != null && mc.theWorld.getChunkProvider().getLoadedChunkCount() > 0)) {
//if(!hurryToTimestamp && !FMLClientHandler.instance().isGUIOpen(GuiDownloadTerrain.class)) {
int timeWait = (int)Math.round((currentTimeStamp - lastTimeStamp)/replaySpeed);
long timeDiff = System.currentTimeMillis() - lastPacketSent;

View File

@@ -1,28 +1,43 @@
package eu.crushedpixel.replaymod.studio;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import com.google.gson.JsonObject;
import net.minecraft.network.play.server.S3EPacketTeams;
import de.johni0702.replaystudio.PacketData;
import de.johni0702.replaystudio.filter.ChangeTimestampFilter;
import de.johni0702.replaystudio.filter.RemoveFilter;
import de.johni0702.replaystudio.filter.SquashFilter;
import de.johni0702.replaystudio.io.ReplayOutputStream;
import de.johni0702.replaystudio.stream.PacketStream;
import de.johni0702.replaystudio.studio.ReplayStudio;
import eu.crushedpixel.replaymod.recording.ReplayMetaData;
import eu.crushedpixel.replaymod.utils.ReplayFileIO;
public class StudioImplementation {
public static void trimReplay(InputStream replayFileStream, boolean isTmcpr, int beginning, int ending, File outputFile) throws IOException {
public static void trimReplay(File replayFile, boolean isTmcpr, int beginning, int ending, File outputFile) throws IOException {
ReplayStudio studio = new ReplayStudio();
PacketStream stream = studio.createReplayStream(replayFileStream, isTmcpr);
studio.setWrappingEnabled(false);
PacketStream stream = studio.createReplayStream(new FileInputStream(replayFile), isTmcpr);
stream.addFilter(new SquashFilter(), -1, beginning);
stream.addFilter(new RemoveFilter(), ending, -1);
outputFile.createNewFile();
ChangeTimestampFilter ctf = new ChangeTimestampFilter();
JsonObject cfg = new JsonObject();
cfg.addProperty("offset", -beginning);
ctf.init(studio, cfg);
FileOutputStream fos = new FileOutputStream(outputFile);
stream.addFilter(ctf, beginning, ending);
File temp = File.createTempFile("trimmed", "tmcpr");
temp.deleteOnExit();
FileOutputStream fos = new FileOutputStream(temp);
ReplayOutputStream out = new ReplayOutputStream(studio, fos);
PacketData packetData;
@@ -32,6 +47,15 @@ public class StudioImplementation {
for(PacketData data : stream.end()) {
out.write(data);
}
out.close();
ReplayMetaData metaData = ReplayFileIO.getMetaData(replayFile);
ending = Math.min(metaData.getDuration(), ending);
metaData.setDuration(ending-beginning);
outputFile.createNewFile();
ReplayFileIO.writeReplayFile(outputFile, temp, metaData);
}
}

View File

@@ -45,10 +45,15 @@ import eu.crushedpixel.replaymod.replay.PacketDeserializer;
@SuppressWarnings("resource") //Gets handled by finalizer
public class ReplayFileIO {
public static List<File> getAllReplayFiles() {
public static File getReplayFolder() {
File folder = new File("./replay_recordings/");
folder.mkdirs();
return folder;
}
public static List<File> getAllReplayFiles() {
List<File> files = new ArrayList<File>();
File folder = getReplayFolder();
for(File file : folder.listFiles()) {
if(("."+FilenameUtils.getExtension(file.getAbsolutePath())).equals(
ConnectionEventHandler.ZIP_FILE_EXTENSION)) {
@@ -58,7 +63,7 @@ public class ReplayFileIO {
return files;
}
private static DataInputStream getMetaDataInputStream(File replayFile) throws Exception {
private static DataInputStream getMetaDataInputStream(File replayFile) throws IOException {
ZipFile archive = null;
try {
@@ -67,7 +72,7 @@ public class ReplayFileIO {
ConnectionEventHandler.JSON_FILE_EXTENSION);
return new DataInputStream(archive.getInputStream(tmcpr));
} catch(Exception e) {
} catch(IOException e) {
throw e;
}
}
@@ -118,7 +123,7 @@ public class ReplayFileIO {
}
}
public static ReplayMetaData getMetaData(File replayFile) throws Exception {
public static ReplayMetaData getMetaData(File replayFile) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(getMetaDataInputStream(replayFile)));
String json = br.readLine();