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

@@ -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.network.EnumPacketDirection;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet;
import net.minecraft.network.play.INetHandlerPlayClient;
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.PositionKeyframe;
import eu.crushedpixel.replaymod.holders.TimeKeyframe;
import eu.crushedpixel.replaymod.registry.ReplayGuiRegistry;
public class ReplayHandler {
@@ -54,6 +54,15 @@ public class ReplayHandler {
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) {
currentEntity = e;
mc.setRenderViewEntity(currentEntity);
@@ -88,8 +97,8 @@ public class ReplayHandler {
isReplaying = replaying;
}
public static void startPath() {
ReplayProcess.startReplayProcess();
public static void startPath(boolean save) {
if(!ReplayHandler.isReplaying()) ReplayProcess.startReplayProcess(save);
}
public static void interruptReplay() {

View File

@@ -1,5 +1,7 @@
package eu.crushedpixel.replaymod.replay;
import java.io.File;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
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.LinearTimestamp;
import eu.crushedpixel.replaymod.interpolation.SplinePoint;
import eu.crushedpixel.replaymod.video.ScreenCapture;
import eu.crushedpixel.replaymod.video.VideoWriter;
public class ReplayProcess {
@@ -31,15 +35,23 @@ public class ReplayProcess {
private static LinearTimestamp timeLinear = null;
private static double previousReplaySpeed = 0;
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;
motionSpline = null;
timeLinear = null;
calculated = false;
requestFinish = false;
ChatMessageRequests.initialize();
if(ReplayHandler.getPosKeyframeCount() < 2) {
ChatMessageRequests.addChatMessage("At least 2 position keyframes required!", ChatMessageType.WARNING);
@@ -64,17 +76,69 @@ public class ReplayProcess {
}
ChatMessageRequests.addChatMessage("Replay started!", ChatMessageType.INFORMATION);
if(isVideoRecording()) {
ticks = 0;
MCTimerHandler.setTimerSpeed(1);
MCTimerHandler.setPassiveTimer();
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while(ReplayHandler.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) {
if(!ReplayHandler.isReplaying()) return;
if(finished) ChatMessageRequests.addChatMessage("Replay finished!", ChatMessageType.INFORMATION);
else ChatMessageRequests.addChatMessage("Replay stopped!", ChatMessageType.INFORMATION);
ReplayHandler.setReplaying(false);
MCTimerHandler.setActiveTimer();
ReplayHandler.setSpeed(previousReplaySpeed);
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()) {
lastRealTime = System.currentTimeMillis();
return;
@@ -91,7 +155,7 @@ public class ReplayProcess {
}
}
}
if(linear && motionLinear == null) {
//set up linear path
motionLinear = new LinearPoint();
@@ -115,9 +179,9 @@ public class ReplayProcess {
if(!calculated) {
calculated = true;
motionSpline.calcSpline();
if(motionSpline != null) motionSpline.calcSpline();
}
long curTime = System.currentTimeMillis();
long timeStep = curTime - lastRealTime;
@@ -169,7 +233,165 @@ public class ReplayProcess {
if(!(nextTime == null || lastTime == null)) {
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) {
curSpeed = 0f;
}
@@ -198,8 +420,10 @@ public class ReplayProcess {
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);
//splinePos = (index of last entry + add) / total entries
@@ -207,6 +431,28 @@ public class ReplayProcess {
lastRealReplayTime = curRealReplayTime;
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.lang.reflect.Field;
import java.util.ArrayList;
import java.util.UUID;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiDownloadTerrain;
@@ -27,10 +28,12 @@ import net.minecraft.network.Packet;
import net.minecraft.network.PacketBuffer;
import net.minecraft.network.play.server.S01PacketJoinGame;
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.S07PacketRespawn;
import net.minecraft.network.play.server.S08PacketPlayerPosLook;
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.S1DPacketEntityEffect;
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.S36PacketSignEditorOpen;
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.S43PacketCamera;
import net.minecraft.network.play.server.S45PacketTitle;
import net.minecraft.network.play.server.S48PacketResourcePackSend;
import net.minecraft.util.Timer;
import net.minecraft.world.EnumDifficulty;
import net.minecraft.world.WorldSettings.GameType;
import net.minecraft.world.WorldType;
@@ -59,6 +63,7 @@ import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.commons.io.FilenameUtils;
import com.google.gson.Gson;
import com.mojang.authlib.GameProfile;
import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.entities.CameraEntity;
@@ -106,16 +111,6 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
private Field chatPacketPosition;
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();
@@ -168,13 +163,7 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
public void setReplaySpeed(final double d) {
if(d != 0) this.replaySpeed = d;
try {
Timer timer = (Timer)mcTimer.get(mc);
timer.timerSpeed = (float)d;
} catch (Exception e) {
e.printStackTrace();
}
MCTimerHandler.setTimerSpeed((float)d);
}
public ReplaySender(final File replayFile, NetworkManager nm) {
@@ -246,7 +235,6 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
@Override
public void run() {
try {
dis = new DataInputStream(archive.getInputStream(replayEntry));
} catch(Exception e) {
@@ -267,7 +255,7 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
lastPacketSent = System.currentTimeMillis();
ReplayHandler.restartReplay();
}
while(!startFromBeginning && (!paused() || FMLClientHandler.instance().isGUIOpen(GuiDownloadTerrain.class))) {
while(!terminate && !startFromBeginning && (!paused() || FMLClientHandler.instance().isGUIOpen(GuiDownloadTerrain.class))) {
try {
/*
@@ -316,9 +304,9 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
if(hurryToTimestamp && currentTimeStamp >= desiredTimeStamp && !startFromBeginning) {
hurryToTimestamp = false;
if(!ReplayHandler.isReplaying() || hasRestarted) {
((Timer)mcTimer.get(mc)).elapsedPartialTicks += 5;
((Timer)mcTimer.get(mc)).elapsedTicks += 5;
((Timer)mcTimer.get(mc)).renderPartialTicks += 5;
MCTimerHandler.advanceRenderPartialTicks(5);
MCTimerHandler.advancePartialTicks(5);
MCTimerHandler.advanceTicks(5);
}
if(!ReplayHandler.isReplaying()) {
Position pos = ReplayHandler.getLastPosition();
@@ -339,8 +327,11 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
}
} catch(EOFException eof) {
dis = new DataInputStream(archive.getInputStream(replayEntry));
setReplaySpeed(0);
} catch(IOException e) {}
} catch(IOException e) {
e.printStackTrace();
}
}
}
} catch(Exception e) {
@@ -369,6 +360,21 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
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
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
@@ -376,6 +382,10 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
return;
}
if(ctx == null) {
ctx = this.ctx;
}
if(msg instanceof Packet) {
super.channelRead(ctx, msg);
return;
@@ -396,6 +406,10 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
p instanceof S2APacketParticles) return;
}
if(p instanceof S03PacketTimeUpdate) {
p = TimeHandler.getTimePacket((S03PacketTimeUpdate)p);
}
if(p instanceof S02PacketChat) {
byte pos = (Byte)chatPacketPosition.get(p);
if(pos == 1) { //Ignores command block output sent
@@ -408,22 +422,6 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
try {
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((Integer)metadataPacketEntityId.get(p) == actualID) {
metadataPacketEntityId.set(p, RecordingHandler.entityID);
@@ -444,6 +442,33 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
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) {
allowMovement = true;
@@ -491,8 +516,6 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
if(p instanceof S43PacketCamera) {
return;
}
//if(ReplayHandler.isReplaying())
// System.out.println("packet arrived");
super.channelRead(ctx, p);
} catch(Exception e) {
System.out.println(p.getClass());
@@ -520,7 +543,7 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
public boolean paused() {
try {
return ((Timer)mcTimer.get(mc)).timerSpeed == 0;
return MCTimerHandler.getTimerSpeed() == 0;
} catch(Exception e) {}
return true;
}
@@ -528,7 +551,6 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
public double getReplaySpeed() {
if(!paused()) return replaySpeed;
else return 0;
//return timeInfo.get().getSpeed();
}
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

@@ -1,233 +0,0 @@
package eu.crushedpixel.replaymod.replay.screenshot;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.IntBuffer;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import javax.imageio.ImageIO;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
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 eu.crushedpixel.replaymod.chat.ChatMessageRequests;
import eu.crushedpixel.replaymod.chat.ChatMessageRequests.ChatMessageType;
import eu.crushedpixel.replaymod.gui.GuiReplaySaving;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.utils.ImageUtils;
public class ReplayScreenshot {
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 long last_finish = -1;
private static boolean before;
private static double beforeSpeed;
private static GuiScreen beforeScreen;
public static void prepareScreenshot() {
before = mc.gameSettings.hideGUI;
beforeSpeed = ReplayHandler.getSpeed();
beforeScreen = mc.currentScreen;
}
public static void saveScreenshot(Framebuffer buffer) {
try {
GuiReplaySaving.replaySaving = true;
mc.gameSettings.hideGUI = true;
mc.currentScreen = null;
mc.entityRenderer.updateCameraAndRender(0);
ReplayHandler.setSpeed(0);
int width = mc.displayWidth;
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.currentScreen = beforeScreen;
ReplayHandler.setSpeed(beforeSpeed);
//The actual cropping and saving should be executed in a separate thread
Thread ioThread = new Thread(new Runnable() {
@Override
public void run() {
try {
float aspect = 1280f/720f;
Rectangle rect;
if((float)fbi.getWidth()/(float)fbi.getHeight() <= aspect) {
int h = Math.round(fbi.getWidth()/aspect);
int y = (fbi.getHeight()/2) - (h/2);
System.out.println(h+" | "+y);
rect = new Rectangle(0, y, fbi.getWidth(), h);
} else {
int w = Math.round(fbi.getHeight()*aspect);
int x = (fbi.getWidth()/2) - (w/2);
rect = new Rectangle(x, 0, w, fbi.getHeight());
}
final BufferedImage nbi = ImageUtils.cropImage(fbi, rect);
File replayFile = ReplayHandler.getReplayFile();
File folder = new File("./replay_recordings/");
folder.mkdirs();
File temp = File.createTempFile("thumb", null);
int h = 720;
int w = 1280;
//int w = width*(h/height);
BufferedImage img = ImageUtils.scaleImage(nbi, new Dimension(w, h));
ImageIO.write(img, "jpg", temp);
File tempFile = File.createTempFile(replayFile.getName(), null);
tempFile.delete(); tempFile.deleteOnExit();
replayFile.renameTo(tempFile);
replayFile.delete();
replayFile.createNewFile();
byte[] buf = new byte[1024];
ZipInputStream zin = new ZipInputStream(new FileInputStream(tempFile));
ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(replayFile));
FileInputStream fis = new FileInputStream(temp);
ZipEntry entry = zin.getNextEntry();
while (entry != null) {
String name = entry.getName();
if(!name.contains("thumb")) {
// Add ZIP entry to output stream.
zout.putNextEntry(new ZipEntry(name));
// Transfer bytes from the ZIP file to the output file
int len;
while ((len = zin.read(buf)) > 0) {
zout.write(buf, 0, len);
}
}
entry = zin.getNextEntry();
}
zout.putNextEntry(new ZipEntry("thumb"));
int len;
//Add unique bytes to the end of the file
zout.write(uniqueBytes);
while ((len = fis.read(buf)) > 0) {
zout.write(buf, 0, len);
}
// Close the streams
fis.close();
zin.close();
// Compress the files
// Complete the ZIP file
zout.close();
tempFile.delete();
temp.delete();
ChatMessageRequests.addChatMessage("Thumbnail has been successfully saved", ChatMessageType.INFORMATION);
} catch(Exception e) {}
finally {
GuiReplaySaving.replaySaving = false;
}
}
});
ioThread.start();
}
catch (Exception exception) {
mc.gameSettings.hideGUI = before;
mc.currentScreen = beforeScreen;
ReplayHandler.setSpeed(beforeSpeed);
exception.printStackTrace();
ChatMessageRequests.addChatMessage("Thumbnail could not be saved", ChatMessageType.WARNING);
}
last_finish = System.currentTimeMillis();
}
}