Cleaned up even more GUIs

Added possibility to create Thumbnails and show them in the Replay Manager
This commit is contained in:
Marius Metzger
2015-01-25 20:36:02 +01:00
parent f39e0f9eae
commit 8c2cf9011e
23 changed files with 663 additions and 206 deletions

View File

@@ -1,8 +1,5 @@
package eu.crushedpixel.replaymod; package eu.crushedpixel.replaymod;
import java.io.IOException;
import net.minecraft.client.Minecraft;
import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.config.Configuration; import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.common.config.Property; import net.minecraftforge.common.config.Property;
@@ -10,18 +7,13 @@ import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler; import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.Mod.Instance; import net.minecraftforge.fml.common.Mod.Instance;
import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; 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.api.client.holders.AuthKey;
import eu.crushedpixel.replaymod.authentication.AuthenticationHandler; import eu.crushedpixel.replaymod.authentication.AuthenticationHandler;
import eu.crushedpixel.replaymod.events.GuiEventHandler; import eu.crushedpixel.replaymod.events.GuiEventHandler;
import eu.crushedpixel.replaymod.events.GuiReplayOverlay; import eu.crushedpixel.replaymod.events.GuiReplayOverlay;
import eu.crushedpixel.replaymod.events.RecordingHandler; import eu.crushedpixel.replaymod.events.RecordingHandler;
import eu.crushedpixel.replaymod.events.ReplayTickHandler;
import eu.crushedpixel.replaymod.recording.ConnectionEventHandler; import eu.crushedpixel.replaymod.recording.ConnectionEventHandler;
import eu.crushedpixel.replaymod.settings.ReplaySettings; import eu.crushedpixel.replaymod.settings.ReplaySettings;
@@ -78,9 +70,6 @@ public class ReplayMod
public void init(FMLInitializationEvent event) { public void init(FMLInitializationEvent event) {
FMLCommonHandler.instance().bus().register(new ConnectionEventHandler()); FMLCommonHandler.instance().bus().register(new ConnectionEventHandler());
MinecraftForge.EVENT_BUS.register(new GuiEventHandler()); MinecraftForge.EVENT_BUS.register(new GuiEventHandler());
ReplayTickHandler tickHandler = new ReplayTickHandler();
FMLCommonHandler.instance().bus().register(tickHandler);
MinecraftForge.EVENT_BUS.register(tickHandler);
recordingHandler = new RecordingHandler(); recordingHandler = new RecordingHandler();
FMLCommonHandler.instance().bus().register(recordingHandler); FMLCommonHandler.instance().bus().register(recordingHandler);

View File

@@ -3,7 +3,9 @@ package eu.crushedpixel.replaymod.api.client;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL; import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import java.util.List; import java.util.List;
@@ -26,6 +28,7 @@ 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;
import eu.crushedpixel.replaymod.utils.StreamTools;
public class ApiClient { public class ApiClient {
@@ -61,23 +64,25 @@ public class ApiClient {
builder.put("auth", auth); builder.put("auth", auth);
builder.put("category", category.getId()); builder.put("category", category.getId());
String url = builder.toString(); String url = builder.toString();
HttpClient client = new DefaultHttpClient(); HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(url); HttpPost post = new HttpPost(url);
((InputStream)client).close();
FileEntity entity = new FileEntity(file); FileEntity entity = new FileEntity(file);
post.setEntity(entity); post.setEntity(entity);
HttpResponse response = client.execute(post); HttpResponse response = client.execute(post);
JsonElement element = jsonParser.parse(EntityUtils.toString(response.getEntity())); //((InputStream)client).close(); TODO: Find working solution
try {
ApiError err = gson.fromJson(element, ApiError.class); if(response.getStatusLine().getStatusCode() != 200) {
if(err.getDesc() != null) { JsonElement element = jsonParser.parse(EntityUtils.toString(response.getEntity()));
throw new ApiException(err); try {
} ApiError err = gson.fromJson(element, ApiError.class);
} catch(Exception e) {} if(err.getDesc() != null) {
throw new ApiException(err);
}
} catch(Exception e) {}
}
} }
public void downloadFile(String auth, int file, File target) throws IOException { public void downloadFile(String auth, int file, File target) throws IOException {
@@ -86,11 +91,19 @@ public class ApiClient {
builder.put("id", file); builder.put("id", file);
String url = builder.toString(); String url = builder.toString();
URL website = new URL(url); URL website = new URL(url);
InputStream is = website.openStream(); HttpURLConnection con = (HttpURLConnection)website.openConnection();
try { //If valid json, an error occured InputStream is = con.getInputStream();
jsonParser.parse(StreamTools.readStreamtoString(is));
} catch(Exception e) { if(con.getResponseCode() == 200) {
Files.copy(is, target.toPath(), StandardCopyOption.REPLACE_EXISTING); Files.copy(is, target.toPath(), StandardCopyOption.REPLACE_EXISTING);
} else {
JsonElement element = jsonParser.parse(StreamTools.readStreamtoString(is));
try {
ApiError err = gson.fromJson(element, ApiError.class);
if(err.getDesc() != null) {
throw new ApiException(err);
}
} catch(Exception e) {}
} }
} }

View File

@@ -11,6 +11,7 @@ import com.google.gson.JsonObject;
import com.google.gson.JsonParser; 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.utils.StreamTools;
public class SimpleApiClient { public class SimpleApiClient {
@@ -73,7 +74,7 @@ public class SimpleApiClient {
HttpURLConnection.setFollowRedirects(false); HttpURLConnection.setFollowRedirects(false);
try { try {
URL url = new URL(urlString); URL url = new URL(urlString);
httpUrlConnection = (HttpURLConnection) url.openConnection(); httpUrlConnection = (HttpURLConnection)url.openConnection();
httpUrlConnection.setRequestMethod("GET"); httpUrlConnection.setRequestMethod("GET");

View File

@@ -28,7 +28,7 @@ public class CameraEntity extends EntityPlayer {
private double decay = 6; //decays by 75% per second; private double decay = 6; //decays by 75% per second;
private long lastCall = 0; private long lastCall = 0;
//frac = time since last tick //frac = time since last tick
public void updateMovement() { public void updateMovement() {
Minecraft mc = Minecraft.getMinecraft(); Minecraft mc = Minecraft.getMinecraft();

View File

@@ -1,5 +1,6 @@
package eu.crushedpixel.replaymod.events; package eu.crushedpixel.replaymod.events;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
@@ -9,38 +10,49 @@ import net.minecraft.client.gui.GuiDisconnected;
import net.minecraft.client.gui.GuiIngameMenu; import net.minecraft.client.gui.GuiIngameMenu;
import net.minecraft.client.gui.GuiMainMenu; import net.minecraft.client.gui.GuiMainMenu;
import net.minecraft.client.gui.GuiOptions; import net.minecraft.client.gui.GuiOptions;
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.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.InitGuiEvent; import net.minecraftforge.client.event.GuiScreenEvent.InitGuiEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.authentication.AuthenticationHandler; import eu.crushedpixel.replaymod.authentication.AuthenticationHandler;
import eu.crushedpixel.replaymod.gui.GuiExitReplay;
import eu.crushedpixel.replaymod.gui.GuiReplayManager;
import eu.crushedpixel.replaymod.gui.GuiReplaySaving; import eu.crushedpixel.replaymod.gui.GuiReplaySaving;
import eu.crushedpixel.replaymod.gui.GuiReplaySettings; import eu.crushedpixel.replaymod.gui.GuiReplaySettings;
import eu.crushedpixel.replaymod.recording.ConnectionEventHandler; import eu.crushedpixel.replaymod.gui.replaymanager.GuiReplayManager;
import eu.crushedpixel.replaymod.gui.replaymanager.ResourceHelper;
import eu.crushedpixel.replaymod.replay.ReplayHandler; import eu.crushedpixel.replaymod.replay.ReplayHandler;
public class GuiEventHandler { public class GuiEventHandler {
private static Minecraft mc = Minecraft.getMinecraft();
private static List<Class> allowedGUIs = new ArrayList<Class>() {
{
add(GuiReplaySettings.class);
add(GuiReplaySaving.class);
add(GuiIngameMenu.class);
add(GuiOptions.class);
add(GuiVideoSettings.class);
}
};
@SubscribeEvent @SubscribeEvent
public void onGui(GuiOpenEvent event) { public void onGui(GuiOpenEvent event) {
if(!AuthenticationHandler.isAuthenticated()) return; if(!AuthenticationHandler.isAuthenticated()) return;
if(event.gui != null && GuiReplaySaving.replaySaving && !allowedGUIs.contains(event.gui.getClass())) {
event.gui = new GuiReplaySaving(event.gui);
return;
}
if(!(event.gui instanceof GuiReplayManager)) ResourceHelper.freeResources();
if(event.gui instanceof GuiChat || event.gui instanceof GuiInventory) { if(event.gui instanceof GuiChat || event.gui instanceof GuiInventory) {
if(ReplayHandler.replayActive()) { if(ReplayHandler.replayActive()) {
event.setCanceled(true); event.setCanceled(true);
} }
} }
else if(event.gui instanceof GuiIngameMenu) {
if(ReplayHandler.replayActive()) {
event.gui = new GuiExitReplay();
}
}
else if(event.gui instanceof GuiDisconnected) { else if(event.gui instanceof GuiDisconnected) {
if(!ReplayHandler.replayActive() && System.currentTimeMillis() - ReplayHandler.lastExit < 5000) { if(!ReplayHandler.replayActive() && System.currentTimeMillis() - ReplayHandler.lastExit < 5000) {
event.setCanceled(true); event.setCanceled(true);
@@ -53,7 +65,18 @@ public class GuiEventHandler {
@SubscribeEvent @SubscribeEvent
public void onInit(InitGuiEvent event) { public void onInit(InitGuiEvent event) {
if(event.gui instanceof GuiMainMenu) { if(event.gui instanceof GuiIngameMenu && ReplayHandler.replayActive()) {
for(GuiButton b : new ArrayList<GuiButton>(event.buttonList)) {
if(b.id == 1) {
b.displayString = "Exit Replay";
b.yPosition -= 24*2;
} else if(b.id >= 5 && b.id <= 7) {
event.buttonList.remove(b);
} else if(b.id != 4) {
b.yPosition -= 24*2;
}
}
} else if(event.gui instanceof GuiMainMenu) {
int i1 = event.gui.height / 4 + 48; int i1 = event.gui.height / 4 + 48;
for(GuiButton b : (List<GuiButton>)event.buttonList) { for(GuiButton b : (List<GuiButton>)event.buttonList) {
@@ -69,18 +92,32 @@ public class GuiEventHandler {
event.buttonList.add(new GuiButton(9001, event.gui.width / 2 - 155, event.gui.height / 6 + 48 - 6 - 24, 310, 20, "Replay Mod Settings...")); event.buttonList.add(new GuiButton(9001, event.gui.width / 2 - 155, event.gui.height / 6 + 48 - 6 - 24, 310, 20, "Replay Mod Settings..."));
} }
} }
@SubscribeEvent @SubscribeEvent
public void onButton(ActionPerformedEvent event) { public void onButton(ActionPerformedEvent event) {
if(!AuthenticationHandler.isAuthenticated()) return; if(!AuthenticationHandler.isAuthenticated()) return;
if(event.gui instanceof GuiMainMenu && event.button.id == REPLAY_MANAGER_ID) { if(event.gui instanceof GuiMainMenu && event.button.id == REPLAY_MANAGER_ID) {
if(ConnectionEventHandler.saving) { mc.displayGuiScreen(new GuiReplayManager());
Minecraft.getMinecraft().displayGuiScreen(new GuiReplaySaving());
} else {
Minecraft.getMinecraft().displayGuiScreen(new GuiReplayManager());
}
} else if(event.gui instanceof GuiOptions && event.button.id == REPLAY_OPTIONS_ID) { } else if(event.gui instanceof GuiOptions && event.button.id == REPLAY_OPTIONS_ID) {
Minecraft.getMinecraft().displayGuiScreen(new GuiReplaySettings(event.gui)); mc.displayGuiScreen(new GuiReplaySettings(event.gui));
}
if(ReplayHandler.isReplaying() && event.gui instanceof GuiIngameMenu && event.button.id == 1) {
event.button.enabled = false;
Thread t = new Thread(new Runnable() {
@Override
public void run() {
mc.displayGuiScreen(new GuiReplaySaving(new GuiMainMenu()));
ReplayHandler.setSpeed(1f);
ReplayHandler.endReplay();
mc.gameSettings.setOptionFloatValue(Options.GAMMA, ReplayHandler.getInitialGamma());
ReplayHandler.lastExit = System.currentTimeMillis();
mc.theWorld.sendQuittingDisconnectingPacket();
}
});
t.run();
} }
} }

View File

@@ -19,6 +19,7 @@ import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.GuiIngameForge; import net.minecraftforge.client.GuiIngameForge;
import net.minecraftforge.client.event.MouseEvent; import net.minecraftforge.client.event.MouseEvent;
import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.client.event.RenderGameOverlayEvent.ElementType;
import net.minecraftforge.client.event.RenderHandEvent; import net.minecraftforge.client.event.RenderHandEvent;
import net.minecraftforge.client.event.RenderWorldLastEvent; import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.fml.client.FMLClientHandler; import net.minecraftforge.fml.client.FMLClientHandler;
@@ -43,6 +44,7 @@ import eu.crushedpixel.replaymod.holders.TimeKeyframe;
import eu.crushedpixel.replaymod.reflection.MCPNames; import eu.crushedpixel.replaymod.reflection.MCPNames;
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.screenshot.ReplayScreenshot;
public class GuiReplayOverlay extends Gui { public class GuiReplayOverlay extends Gui {
@@ -77,6 +79,8 @@ public class GuiReplayOverlay extends Gui {
private boolean mouseDown = false; private boolean mouseDown = false;
private boolean requestScreenshot = false;
private Field drawBlockOutline; private Field drawBlockOutline;
public GuiReplayOverlay() { public GuiReplayOverlay() {
@@ -114,6 +118,10 @@ public class GuiReplayOverlay extends Gui {
if(mc != null && mc.thePlayer != null) if(mc != null && mc.thePlayer != null)
MinecraftTicker.runMouseKeyboardTick(mc); MinecraftTicker.runMouseKeyboardTick(mc);
} }
if(requestScreenshot) {
requestScreenshot = false;
ReplayScreenshot.saveScreenshot(mc.getFramebuffer());
}
} }
public void resetUI() throws Exception { public void resetUI() throws Exception {
@@ -128,10 +136,42 @@ public class GuiReplayOverlay extends Gui {
public void onRenderGui(RenderGameOverlayEvent.Post event) throws IllegalArgumentException, IllegalAccessException { public void onRenderGui(RenderGameOverlayEvent.Post event) throws IllegalArgumentException, IllegalAccessException {
if(!ReplayHandler.replayActive()) { if(!ReplayHandler.replayActive()) {
GuiIngameForge.renderExperiance = true; GuiIngameForge.renderExperiance = true;
GuiIngameForge.renderArmor = true;
GuiIngameForge.renderAir = true;
GuiIngameForge.renderHealth = true;
GuiIngameForge.renderHotbar = true;
GuiIngameForge.renderFood = true;
GuiIngameForge.renderBossHealth = true;
GuiIngameForge.renderCrosshairs = true;
GuiIngameForge.renderHelmet = true;
GuiIngameForge.renderPortal = true;
GuiIngameForge.renderHealthMount = true;
GuiIngameForge.renderJumpBar = true;
GuiIngameForge.renderObjective = true;
return;
}
if(event.type == ElementType.PLAYER_LIST) {
if(event.isCancelable()) {
event.setCanceled(true);
}
return; return;
} }
GuiIngameForge.renderExperiance = false; GuiIngameForge.renderExperiance = false;
GuiIngameForge.renderArmor = false;
GuiIngameForge.renderAir = false;
GuiIngameForge.renderHealth = false;
GuiIngameForge.renderHotbar = false;
GuiIngameForge.renderFood = false;
GuiIngameForge.renderBossHealth = false;
GuiIngameForge.renderCrosshairs = false;
GuiIngameForge.renderHelmet = false;
GuiIngameForge.renderPortal = false;
GuiIngameForge.renderHealthMount = false;
GuiIngameForge.renderJumpBar = false;
GuiIngameForge.renderObjective = false;
GL11.glEnable(GL11.GL_BLEND); GL11.glEnable(GL11.GL_BLEND);
drawBlockOutline.set(Minecraft.getMinecraft().entityRenderer, false); drawBlockOutline.set(Minecraft.getMinecraft().entityRenderer, false);
@@ -204,11 +244,11 @@ public class GuiReplayOverlay extends Gui {
CameraEntity cam = ReplayHandler.getCameraEntity(); CameraEntity cam = ReplayHandler.getCameraEntity();
if(cam != null) { if(cam != null) {
ReplayHandler.setLastPosition(new Position(cam.posX, cam.posY, cam.posZ, cam.rotationPitch, cam.rotationYaw)); ReplayHandler.setLastPosition(new Position(cam.posX, cam.posY, cam.posZ, cam.rotationPitch, cam.rotationYaw));
} else { } else {
ReplayHandler.setLastPosition(null); ReplayHandler.setLastPosition(null);
} }
ReplayHandler.setReplayPos((int)time); ReplayHandler.setReplayPos((int)time);
} }
} }
@@ -316,7 +356,7 @@ public class GuiReplayOverlay extends Gui {
try { try {
speedSlider.drawButton(mc, mouseX, mouseY); speedSlider.drawButton(mc, mouseX, mouseY);
} catch(Exception e) {} } catch(Exception e) {}
GlStateManager.resetColor(); GlStateManager.resetColor();
Entity player = ReplayHandler.getCameraEntity(); Entity player = ReplayHandler.getCameraEntity();
@@ -746,7 +786,7 @@ public class GuiReplayOverlay extends Gui {
return false; return false;
} }
} }
@SubscribeEvent @SubscribeEvent
public void onMouseMove(MouseEvent event) { public void onMouseMove(MouseEvent event) {
if(!ReplayHandler.replayActive()) return; if(!ReplayHandler.replayActive()) return;
@@ -783,15 +823,16 @@ public class GuiReplayOverlay extends Gui {
@SubscribeEvent @SubscribeEvent
public void onKeyInput(KeyInputEvent event) { public void onKeyInput(KeyInputEvent event) {
if(!ReplayHandler.replayActive()) return; if(!ReplayHandler.replayActive()) return;
if(FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class)) { if(FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class)) {
return; return;
} }
if(Keyboard.isKeyDown(Keyboard.KEY_V) && !Keyboard.isRepeatEvent() && Keyboard.getKeyCount() == 1) { if(Keyboard.isKeyDown(Keyboard.KEY_V) && !Keyboard.isRepeatEvent()) {
ReplayMod.replaySettings.setLightingEnabled(!ReplayMod.replaySettings.isLightingEnabled()); ReplayMod.replaySettings.setLightingEnabled(!ReplayMod.replaySettings.isLightingEnabled());
} }
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()) {
@@ -833,6 +874,12 @@ public class GuiReplayOverlay extends Gui {
mc.displayGuiScreen(new GuiMouseInput()); mc.displayGuiScreen(new GuiMouseInput());
continue; continue;
} }
//TODO: Register key handlers
if(kb.getKeyDescription().equals("key.screenshot") && kb.isPressed()) {
ReplayScreenshot.prepareScreenshot();
requestScreenshot = true;
}
} catch(Exception e) { } catch(Exception e) {
e.printStackTrace(); e.printStackTrace();
} }

View File

@@ -1,33 +0,0 @@
package eu.crushedpixel.replaymod.events;
import java.lang.reflect.Field;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.entity.Entity;
import net.minecraft.world.WorldSettings.GameType;
import net.minecraftforge.client.event.FOVUpdateEvent;
import net.minecraftforge.client.event.RenderWorldEvent;
import net.minecraftforge.event.entity.player.AchievementEvent;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.event.entity.player.PlayerFlyableFallEvent;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.fml.common.eventhandler.Event;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent.PlayerTickEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent.ServerTickEvent;
import eu.crushedpixel.replaymod.reflection.MCPNames;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
public class ReplayTickHandler {
private Minecraft mc = Minecraft.getMinecraft();
@SubscribeEvent
public void onPlayer(PlayerEvent event) {
if(ReplayHandler.replayActive() && event.isCancelable()) {
event.setCanceled(true);
}
}
}

View File

@@ -1,66 +0,0 @@
package eu.crushedpixel.replaymod.gui;
import java.io.IOException;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiIngameMenu;
import net.minecraft.client.gui.GuiMainMenu;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.settings.GameSettings.Options;
public class GuiExitReplay extends GuiIngameMenu {
@Override
public void initGui()
{
this.buttonList.clear();
byte b0 = -16;
boolean flag = true;
this.buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 4 + 120 + b0, I18n.format("menu.returnToMenu", new Object[0])));
if (!this.mc.isIntegratedServerRunning())
{
((GuiButton)this.buttonList.get(0)).displayString = I18n.format("Exit Replay", new Object[0]);
}
this.buttonList.add(new GuiButton(4, this.width / 2 - 100, this.height / 4 + 24 + b0, I18n.format("menu.returnToGame", new Object[0])));
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 96 + b0, 98, 20, I18n.format("menu.options", new Object[0])));
this.buttonList.add(new GuiButton(12, this.width / 2 + 2, this.height / 4 + 96 + b0, 98, 20, I18n.format("fml.menu.modoptions")));
GuiButton guibutton;
this.buttonList.add(guibutton = new GuiButton(7, this.width / 2 - 100, this.height / 4 + 72 + b0, 200, 20, I18n.format("menu.shareToLan", new Object[0])));
this.buttonList.add(new GuiButton(5, this.width / 2 - 100, this.height / 4 + 48 + b0, 98, 20, I18n.format("gui.achievements", new Object[0])));
this.buttonList.add(new GuiButton(6, this.width / 2 + 2, this.height / 4 + 48 + b0, 98, 20, I18n.format("gui.stats", new Object[0])));
guibutton.enabled = this.mc.isSingleplayer() && !this.mc.getIntegratedServer().getPublic();
}
@Override
protected void actionPerformed(GuiButton button) throws IOException
{
if(button.id == 1) {
button.enabled = false;
Thread t = new Thread(new Runnable() {
@Override
public void run() {
mc.displayGuiScreen(new GuiReplaySaving());
ReplayHandler.endReplay();
ReplayHandler.setSpeed(1f);
mc.gameSettings.setOptionFloatValue(Options.GAMMA, ReplayHandler.getInitialGamma());
ReplayHandler.lastExit = System.currentTimeMillis();
mc.theWorld.sendQuittingDisconnectingPacket();
}
});
t.run();
} else {
super.actionPerformed(button);
}
}
}

View File

@@ -2,6 +2,7 @@ package eu.crushedpixel.replaymod.gui;
import java.awt.Color; import java.awt.Color;
import eu.crushedpixel.replaymod.gui.replaymanager.GuiReplayManager;
import eu.crushedpixel.replaymod.recording.ConnectionEventHandler; import eu.crushedpixel.replaymod.recording.ConnectionEventHandler;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiIngameMenu; import net.minecraft.client.gui.GuiIngameMenu;
@@ -10,14 +11,22 @@ import net.minecraftforge.fml.client.FMLClientHandler;
public class GuiReplaySaving extends GuiScreen { public class GuiReplaySaving extends GuiScreen {
public static boolean replaySaving = false;
private GuiScreen waiting = null;
public GuiReplaySaving(GuiScreen waiting) {
this.waiting = waiting;
}
@Override @Override
public void drawScreen(int mouseX, int mouseY, float partialTicks) { public void drawScreen(int mouseX, int mouseY, float partialTicks) {
this.drawDefaultBackground(); this.drawDefaultBackground();
this.drawCenteredString(this.fontRendererObj, "Saving Replay File...", this.width / 2, 20, 16777215); this.drawCenteredString(this.fontRendererObj, "Saving Replay File...", this.width / 2, 20, 16777215);
this.drawCenteredString(this.fontRendererObj, "Please wait while your recent Replay is being saved.", this.width / 2, 40, 16777215); this.drawCenteredString(this.fontRendererObj, "Please wait while your recent Replay is being saved.", this.width / 2, 40, 16777215);
super.drawScreen(mouseX, mouseY, partialTicks); super.drawScreen(mouseX, mouseY, partialTicks);
if(!ConnectionEventHandler.saving) { if(!replaySaving) {
Minecraft.getMinecraft().displayGuiScreen(new GuiReplayManager()); Minecraft.getMinecraft().displayGuiScreen(waiting);
} }
} }

View File

@@ -1,4 +1,4 @@
package eu.crushedpixel.replaymod.gui; package eu.crushedpixel.replaymod.gui.replaymanager;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;

View File

@@ -1,11 +1,15 @@
package eu.crushedpixel.replaymod.gui; package eu.crushedpixel.replaymod.gui.replaymanager;
import java.awt.image.BufferedImage;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.zip.ZipInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui; import net.minecraft.client.gui.Gui;
@@ -13,6 +17,8 @@ import net.minecraft.client.gui.GuiListExtended.IGuiListEntry;
import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.texture.DynamicTexture;
import net.minecraft.util.ResourceLocation;
import eu.crushedpixel.replaymod.recording.ReplayMetaData; import eu.crushedpixel.replaymod.recording.ReplayMetaData;
public class GuiReplayListEntry implements IGuiListEntry { public class GuiReplayListEntry implements IGuiListEntry {
@@ -22,8 +28,11 @@ public class GuiReplayListEntry implements IGuiListEntry {
private ReplayMetaData metaData; private ReplayMetaData metaData;
private String fileName; private String fileName;
private final ResourceLocation textureResource;
private DynamicTexture dynTex = null;
private BufferedImage image = null;
public ReplayMetaData getMetaData() { public ReplayMetaData getMetaData() {
return metaData; return metaData;
@@ -41,20 +50,34 @@ public class GuiReplayListEntry implements IGuiListEntry {
this.fileName = fileName; this.fileName = fileName;
} }
private boolean selected = false;
private GuiReplayListExtended parent; private GuiReplayListExtended parent;
public GuiReplayListEntry(GuiReplayListExtended parent, String fileName, ReplayMetaData metaData) { public GuiReplayListEntry(GuiReplayListExtended parent, String fileName, ReplayMetaData metaData, BufferedImage image) {
this.metaData = metaData; this.metaData = metaData;
this.fileName = fileName; this.fileName = fileName;
this.parent = parent; this.parent = parent;
this.textureResource = new ResourceLocation("thumbs/"+fileName);
dynTex = null;
this.image = image;
} }
@Override @Override
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) {
{
minecraft.fontRendererObj.drawString(fileName, x + 3, y + 1, 16777215); minecraft.fontRendererObj.drawString(fileName, x + 3, y + 1, 16777215);
//Draw thumbnail
if(image != null) {
if(dynTex == null) {
dynTex = new DynamicTexture(image);
minecraft.getTextureManager().loadTexture(textureResource, dynTex);
dynTex.updateDynamicTexture();
ResourceHelper.registerResource(textureResource);
}
minecraft.getTextureManager().bindTexture(textureResource); //Will be freed by the ResourceHelper
Gui.drawScaledCustomSizeModalRect(x-60, y, 0, 0, 1280, 720, 57, 32, 1280, 720);
}
List<String> list = new ArrayList<String>(); List<String> list = new ArrayList<String>();
list.add(metaData.getServerName()+" ("+dateFormat.format(new Date(metaData.getDate()))+")"); list.add(metaData.getServerName()+" ("+dateFormat.format(new Date(metaData.getDate()))+")");
@@ -67,6 +90,8 @@ public class GuiReplayListEntry implements IGuiListEntry {
for (int l1 = 0; l1 < Math.min(list.size(), 2); ++l1) { for (int l1 = 0; l1 < Math.min(list.size(), 2); ++l1) {
minecraft.fontRendererObj.drawString((String)list.get(l1), x + 3, y + 12 + minecraft.fontRendererObj.FONT_HEIGHT * l1, 8421504); minecraft.fontRendererObj.drawString((String)list.get(l1), x + 3, y + 12 + minecraft.fontRendererObj.FONT_HEIGHT * l1, 8421504);
} }
} }
@Override @Override

View File

@@ -1,5 +1,6 @@
package eu.crushedpixel.replaymod.gui; 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;
@@ -48,6 +49,7 @@ public class GuiReplayListExtended extends GuiListExtended {
for (int j1 = 0; j1 < i1; ++j1) for (int j1 = 0; j1 < i1; ++j1)
{ {
int k1 = p_148120_2_ + j1 * this.slotHeight + this.headerPadding; int k1 = p_148120_2_ + j1 * this.slotHeight + this.headerPadding;
int l1 = this.slotHeight - 4; int l1 = this.slotHeight - 4;
@@ -76,7 +78,7 @@ public class GuiReplayListExtended extends GuiListExtended {
tessellator.draw(); tessellator.draw();
GlStateManager.enableTexture2D(); GlStateManager.enableTexture2D();
} }
this.drawSlot(j1, p_148120_1_, k1, l1, p_148120_3_, p_148120_4_); this.drawSlot(j1, p_148120_1_, k1, l1, p_148120_3_, p_148120_4_);
} }
} }
@@ -88,8 +90,8 @@ public class GuiReplayListExtended extends GuiListExtended {
entries = new ArrayList<GuiReplayListEntry>(); entries = new ArrayList<GuiReplayListEntry>();
} }
public void addEntry(String fileName, ReplayMetaData metaData) { public void addEntry(String fileName, ReplayMetaData metaData, BufferedImage image) {
entries.add(new GuiReplayListEntry(this, fileName, metaData)); entries.add(new GuiReplayListEntry(this, fileName, metaData, image));
} }
@Override @Override

View File

@@ -1,5 +1,11 @@
package eu.crushedpixel.replaymod.gui; package eu.crushedpixel.replaymod.gui.replaymanager;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.Unpooled;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@@ -12,10 +18,13 @@ import java.util.Comparator;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import javax.imageio.ImageIO;
import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiYesNo; import net.minecraft.client.gui.GuiYesNo;
import net.minecraft.client.gui.GuiYesNoCallback; import net.minecraft.client.gui.GuiYesNoCallback;
import net.minecraft.client.renderer.texture.TextureUtil;
import net.minecraft.client.resources.I18n; import net.minecraft.client.resources.I18n;
import net.minecraft.util.Util; import net.minecraft.util.Util;
@@ -28,9 +37,11 @@ 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.GuiReplaySettings;
import eu.crushedpixel.replaymod.recording.ConnectionEventHandler; import eu.crushedpixel.replaymod.recording.ConnectionEventHandler;
import eu.crushedpixel.replaymod.recording.ReplayMetaData; import eu.crushedpixel.replaymod.recording.ReplayMetaData;
import eu.crushedpixel.replaymod.replay.ReplayHandler; import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.utils.ImageUtils;
public class GuiReplayManager extends GuiScreen implements GuiYesNoCallback { public class GuiReplayManager extends GuiScreen implements GuiYesNoCallback {
@@ -41,12 +52,12 @@ public class GuiReplayManager extends GuiScreen implements GuiYesNoCallback {
private String hoveringText; private String hoveringText;
private boolean initialized; private boolean initialized;
private GuiReplayListExtended replayGuiList; private GuiReplayListExtended replayGuiList;
private List<Pair<File, ReplayMetaData>> replayFileList = new ArrayList<Pair<File, ReplayMetaData>>(); private List<Pair<Pair<File, ReplayMetaData>, BufferedImage>> replayFileList = new ArrayList<Pair<Pair<File, ReplayMetaData>, BufferedImage>>();
private GuiButton loadButton, folderButton, renameButton, deleteButton, cancelButton, settingsButton; private GuiButton loadButton, folderButton, renameButton, deleteButton, cancelButton, settingsButton;
private static Gson gson = new Gson(); private static Gson gson = new Gson();
private boolean replaying = false; private boolean replaying = false;
private static final int LOAD_BUTTON_ID = 9001; private static final int LOAD_BUTTON_ID = 9001;
private static final int FOLDER_BUTTON_ID = 9002; private static final int FOLDER_BUTTON_ID = 9002;
private static final int RENAME_BUTTON_ID = 9003; private static final int RENAME_BUTTON_ID = 9003;
@@ -55,14 +66,14 @@ public class GuiReplayManager extends GuiScreen implements GuiYesNoCallback {
private static final int CANCEL_BUTTON_ID = 9006; private static final int CANCEL_BUTTON_ID = 9006;
private boolean delete_file = false; private boolean delete_file = false;
private void reloadFiles() { private void reloadFiles() {
replayGuiList.clearEntries(); replayGuiList.clearEntries();
replayFileList = new ArrayList<Pair<File, ReplayMetaData>>(); replayFileList = new ArrayList<Pair<Pair<File, ReplayMetaData>, BufferedImage>>();
File folder = new File("./replay_recordings/"); File folder = new File("./replay_recordings/");
folder.mkdirs(); folder.mkdirs();
for(File file : folder.listFiles()) { for(File file : folder.listFiles()) {
if(("."+FilenameUtils.getExtension(file.getAbsolutePath())).equals(ConnectionEventHandler.ZIP_FILE_EXTENSION)) { if(("."+FilenameUtils.getExtension(file.getAbsolutePath())).equals(ConnectionEventHandler.ZIP_FILE_EXTENSION)) {
try { try {
@@ -70,14 +81,33 @@ public class GuiReplayManager extends GuiScreen implements GuiYesNoCallback {
ZipArchiveEntry recfile = archive.getEntry("recording"+ConnectionEventHandler.TEMP_FILE_EXTENSION); ZipArchiveEntry recfile = archive.getEntry("recording"+ConnectionEventHandler.TEMP_FILE_EXTENSION);
ZipArchiveEntry metadata = archive.getEntry("metaData"+ConnectionEventHandler.JSON_FILE_EXTENSION); ZipArchiveEntry metadata = archive.getEntry("metaData"+ConnectionEventHandler.JSON_FILE_EXTENSION);
ZipArchiveEntry image = archive.getEntry("thumb");
BufferedImage img = null;
if(image != null) {
InputStream is = archive.getInputStream(image);
is.skip(7);
BufferedImage bimg = ImageIO.read(is);
if(bimg != null) {
img = ImageUtils.scaleImage(bimg, new Dimension(1280, 720));
}
/* Old way of reading thumbnail
else {
is = archive.getInputStream(image);
bimg = ImageIO.read(is);
img = ImageUtils.scaleImage(bimg, new Dimension(1280, 720));
}
*/
}
InputStream is = archive.getInputStream(metadata); InputStream is = archive.getInputStream(metadata);
BufferedReader br = new BufferedReader(new InputStreamReader(is)); BufferedReader br = new BufferedReader(new InputStreamReader(is));
String json = br.readLine(); String json = br.readLine();
ReplayMetaData metaData = gson.fromJson(json, ReplayMetaData.class); ReplayMetaData metaData = gson.fromJson(json, ReplayMetaData.class);
replayFileList.add(Pair.of(file, metaData)); replayFileList.add(Pair.of(Pair.of(file, metaData), img));
archive.close(); archive.close();
} catch(Exception e) { } catch(Exception e) {
@@ -85,21 +115,25 @@ public class GuiReplayManager extends GuiScreen implements GuiYesNoCallback {
} }
} }
} }
Collections.sort(replayFileList, new FileAgeComparator()); Collections.sort(replayFileList, new FileAgeComparator());
for(Pair<File, ReplayMetaData> p : replayFileList) { for(Pair<Pair<File, ReplayMetaData>, BufferedImage> p : replayFileList) {
replayGuiList.addEntry(FilenameUtils.getBaseName(p.first().getName()), p.second()); replayGuiList.addEntry(FilenameUtils.getBaseName(p.first().first().getName()), p.first().second(), p.second());
} }
} }
public class FileAgeComparator implements Comparator<Pair<File, ReplayMetaData>> { public class FileAgeComparator implements Comparator<Pair<Pair<File, ReplayMetaData>, BufferedImage>> {
@Override @Override
public int compare(Pair<File, ReplayMetaData> o1, Pair<File, ReplayMetaData> o2) { public int compare(Pair<Pair<File, ReplayMetaData>, BufferedImage> o1, Pair<Pair<File, ReplayMetaData>, BufferedImage> o2) {
return (int)(new Date(o2.second().getDate()).compareTo(new Date(o1.second().getDate()))); try {
return (int)(new Date(o2.first().second().getDate()).compareTo(new Date(o1.first().second().getDate())));
} catch(Exception e) {
return 0;
}
} }
} }
public void initGui() public void initGui()
@@ -183,7 +217,7 @@ public class GuiReplayManager extends GuiScreen implements GuiYesNoCallback {
} }
else if(button.id == RENAME_BUTTON_ID) else if(button.id == RENAME_BUTTON_ID)
{ {
File file = replayFileList.get(replayGuiList.selected).first(); File file = replayFileList.get(replayGuiList.selected).first().first();
this.mc.displayGuiScreen(new GuiRenameReplay(this, file)); this.mc.displayGuiScreen(new GuiRenameReplay(this, file));
} }
else if(button.id == FOLDER_BUTTON_ID) else if(button.id == FOLDER_BUTTON_ID)
@@ -241,7 +275,7 @@ public class GuiReplayManager extends GuiScreen implements GuiYesNoCallback {
if (result) if (result)
{ {
replayFileList.get(replayGuiList.selected).first().delete(); replayFileList.get(replayGuiList.selected).first().first().delete();
replayFileList.remove(replayGuiList.selected); replayFileList.remove(replayGuiList.selected);
} }
@@ -265,16 +299,15 @@ public class GuiReplayManager extends GuiScreen implements GuiYesNoCallback {
deleteButton.enabled = b; deleteButton.enabled = b;
} }
public void loadReplay(int id) public void loadReplay(int id) {
{ mc.displayGuiScreen((GuiScreen)null);
mc.displayGuiScreen((GuiScreen)null);
try { try {
ReplayHandler.startReplay(replayFileList.get(id).first()); ReplayHandler.startReplay(replayFileList.get(id).first().first());
} catch(Exception e) { } catch(Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
} }

View File

@@ -0,0 +1,24 @@
package eu.crushedpixel.replaymod.gui.replaymanager;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.client.Minecraft;
import net.minecraft.util.ResourceLocation;
public class ResourceHelper {
private static List<ResourceLocation> openResources = new ArrayList<ResourceLocation>();
public static void registerResource(ResourceLocation loc) {
openResources.add(loc);
}
public static void freeResources() {
for(ResourceLocation loc : openResources) {
Minecraft.getMinecraft().getTextureManager().deleteTexture(loc);
}
openResources = new ArrayList<ResourceLocation>();
}
}

View File

@@ -39,8 +39,6 @@ public class ConnectionEventHandler {
private static PacketListener packetListener = null; private static PacketListener packetListener = null;
private static boolean isRecording = false; private static boolean isRecording = false;
public static boolean saving = false;
public static boolean isRecording() { public static boolean isRecording() {
return isRecording; return isRecording;

View File

@@ -23,6 +23,7 @@ import net.minecraft.client.Minecraft;
import com.google.gson.Gson; import com.google.gson.Gson;
import eu.crushedpixel.replaymod.gui.GuiReplaySaving;
import eu.crushedpixel.replaymod.holders.PacketData; import eu.crushedpixel.replaymod.holders.PacketData;
public abstract class DataListener extends ChannelInboundHandlerAdapter { public abstract class DataListener extends ChannelInboundHandlerAdapter {
@@ -144,7 +145,7 @@ public abstract class DataListener extends ChannelInboundHandlerAdapter {
byte[] buffer = new byte[1024]; byte[] buffer = new byte[1024];
try { try {
ConnectionEventHandler.saving = true; GuiReplaySaving.replaySaving = true;
String mcversion = Minecraft.getMinecraft().getVersion(); String mcversion = Minecraft.getMinecraft().getVersion();
String[] pl = players.toArray(new String[players.size()]); String[] pl = players.toArray(new String[players.size()]);
@@ -181,10 +182,10 @@ public abstract class DataListener extends ChannelInboundHandlerAdapter {
file.delete(); file.delete();
ConnectionEventHandler.saving = false; GuiReplaySaving.replaySaving = false;
} catch(Exception e) { } catch(Exception e) {
e.printStackTrace(); e.printStackTrace();
ConnectionEventHandler.saving = false; GuiReplaySaving.replaySaving = false;
} }
} }

View File

@@ -389,4 +389,11 @@ public class ReplayHandler {
public static Position getLastPosition() { public static Position getLastPosition() {
return lastPosition; return lastPosition;
} }
public static File getReplayFile() {
if(replaySender != null) {
return replaySender.getReplayFile();
}
return null;
}
} }

View File

@@ -523,4 +523,8 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
//return timeInfo.get().getSpeed(); //return timeInfo.get().getSpeed();
} }
public File getReplayFile() {
return replayFile;
}
} }

View File

@@ -0,0 +1,234 @@
package eu.crushedpixel.replaymod.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();
}
}

View File

@@ -20,9 +20,9 @@ public class ReplaySettings {
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 static Field mcTimer; private static Field mcTimer;
static { static {
try { try {
mcTimer = Minecraft.class.getDeclaredField(MCPNames.field("field_71428_T")); mcTimer = Minecraft.class.getDeclaredField(MCPNames.field("field_71428_T"));
@@ -89,13 +89,17 @@ public class ReplaySettings {
Minecraft.getMinecraft().gameSettings.setOptionFloatValue(Options.GAMMA, ReplayHandler.getInitialGamma()); Minecraft.getMinecraft().gameSettings.setOptionFloatValue(Options.GAMMA, ReplayHandler.getInitialGamma());
} }
try { try {
Timer timer = (Timer)mcTimer.get(Minecraft.getMinecraft()); if(ReplayHandler.isPaused()) {
timer.elapsedPartialTicks++; Timer timer = (Timer)mcTimer.get(Minecraft.getMinecraft());
timer.renderPartialTicks++; timer.elapsedPartialTicks++;
timer.renderPartialTicks++;
} else {
Minecraft.getMinecraft().entityRenderer.updateCameraAndRender(0);
}
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
rewriteSettings(); rewriteSettings();
} }

View File

@@ -0,0 +1,69 @@
package eu.crushedpixel.replaymod.utils;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
public class ImageUtils {
public static BufferedImage scaleImage(BufferedImage img, Dimension d) {
img = scaleByHalf(img, d);
img = scaleExact(img, d);
return img;
}
private static BufferedImage scaleByHalf(BufferedImage img, Dimension d) {
int w = img.getWidth();
int h = img.getHeight();
float factor = getBinFactor(w, h, d);
// make new size
w *= factor;
h *= factor;
BufferedImage scaled = new BufferedImage(w, h,
BufferedImage.TYPE_INT_RGB);
Graphics2D g = scaled.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
g.drawImage(img, 0, 0, w, h, null);
g.dispose();
return scaled;
}
private static BufferedImage scaleExact(BufferedImage img, Dimension d) {
float factor = getFactor(img.getWidth(), img.getHeight(), d);
// create the image
int w = (int) (img.getWidth() * factor);
int h = (int) (img.getHeight() * factor);
BufferedImage scaled = new BufferedImage(w, h,
BufferedImage.TYPE_INT_RGB);
Graphics2D g = scaled.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(img, 0, 0, w, h, null);
g.dispose();
return scaled;
}
static float getBinFactor(int width, int height, Dimension dim) {
float factor = 1;
float target = getFactor(width, height, dim);
if (target <= 1) { while (factor / 2 > target) { factor /= 2; }
} else { while (factor * 2 < target) { factor *= 2; } }
return factor;
}
static float getFactor(int width, int height, Dimension dim) {
float sx = dim.width / (float) width;
float sy = dim.height / (float) height;
return Math.min(sx, sy);
}
public static BufferedImage cropImage(BufferedImage src, Rectangle rect) {
return src.getSubimage(rect.x, rect.y, rect.width, rect.height);
}
}

View File

@@ -15,7 +15,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
package eu.crushedpixel.replaymod.api.client; package eu.crushedpixel.replaymod.utils;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;

View File

@@ -0,0 +1,59 @@
package eu.crushedpixel.replaymod.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
public class ZipFileUtils {
public static void deleteZipEntry(File zipFile,
String[] files) throws IOException {
// get a temp file
File tempFile = File.createTempFile(zipFile.getName(), null);
// delete it, otherwise you cannot rename your existing zip to it.
tempFile.delete();
tempFile.deleteOnExit();
boolean renameOk=zipFile.renameTo(tempFile);
if (!renameOk)
{
throw new RuntimeException("could not rename the file "+zipFile.getAbsolutePath()+" to "+tempFile.getAbsolutePath());
}
byte[] buf = new byte[1024];
ZipInputStream zin = new ZipInputStream(new FileInputStream(tempFile));
ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(zipFile));
ZipEntry entry = zin.getNextEntry();
while (entry != null) {
String name = entry.getName();
boolean toBeDeleted = false;
for (String f : files) {
if (f.equals(name)) {
toBeDeleted = true;
break;
}
}
if (!toBeDeleted) {
// 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();
}
// Close the streams
zin.close();
// Compress the files
// Complete the ZIP file
zout.close();
tempFile.delete();
}
}