Cleanup, relocate and split up GuiReplayOverlay
Merge gui resources into one texture
This commit is contained in:
@@ -4,6 +4,7 @@ import com.google.common.util.concurrent.ListenableFutureTask;
|
|||||||
import eu.crushedpixel.replaymod.api.ApiClient;
|
import eu.crushedpixel.replaymod.api.ApiClient;
|
||||||
import eu.crushedpixel.replaymod.chat.ChatMessageHandler;
|
import eu.crushedpixel.replaymod.chat.ChatMessageHandler;
|
||||||
import eu.crushedpixel.replaymod.events.*;
|
import eu.crushedpixel.replaymod.events.*;
|
||||||
|
import eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay;
|
||||||
import eu.crushedpixel.replaymod.holders.KeyframeSet;
|
import eu.crushedpixel.replaymod.holders.KeyframeSet;
|
||||||
import eu.crushedpixel.replaymod.localization.LocalizedResourcePack;
|
import eu.crushedpixel.replaymod.localization.LocalizedResourcePack;
|
||||||
import eu.crushedpixel.replaymod.online.authentication.AuthenticationHandler;
|
import eu.crushedpixel.replaymod.online.authentication.AuthenticationHandler;
|
||||||
@@ -130,9 +131,7 @@ public class ReplayMod {
|
|||||||
public void postInit(FMLPostInitializationEvent event) throws IOException {
|
public void postInit(FMLPostInitializationEvent event) throws IOException {
|
||||||
GameSettings.Options.RENDER_DISTANCE.setValueMax(64f);
|
GameSettings.Options.RENDER_DISTANCE.setValueMax(64f);
|
||||||
|
|
||||||
overlay = new GuiReplayOverlay();
|
overlay.register();
|
||||||
FMLCommonHandler.instance().bus().register(overlay);
|
|
||||||
MinecraftForge.EVENT_BUS.register(overlay);
|
|
||||||
|
|
||||||
TickAndRenderListener tarl = new TickAndRenderListener();
|
TickAndRenderListener tarl = new TickAndRenderListener();
|
||||||
FMLCommonHandler.instance().bus().register(tarl);
|
FMLCommonHandler.instance().bus().register(tarl);
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import net.minecraftforge.client.event.GuiScreenEvent.ActionPerformedEvent;
|
|||||||
import net.minecraftforge.client.event.GuiScreenEvent.DrawScreenEvent;
|
import net.minecraftforge.client.event.GuiScreenEvent.DrawScreenEvent;
|
||||||
import net.minecraftforge.client.event.GuiScreenEvent.InitGuiEvent;
|
import net.minecraftforge.client.event.GuiScreenEvent.InitGuiEvent;
|
||||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||||
|
import org.lwjgl.util.Point;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|||||||
@@ -1,830 +0,0 @@
|
|||||||
package eu.crushedpixel.replaymod.events;
|
|
||||||
|
|
||||||
import eu.crushedpixel.replaymod.ReplayMod;
|
|
||||||
import eu.crushedpixel.replaymod.entities.CameraEntity;
|
|
||||||
import eu.crushedpixel.replaymod.gui.*;
|
|
||||||
import eu.crushedpixel.replaymod.holders.Keyframe;
|
|
||||||
import eu.crushedpixel.replaymod.holders.Position;
|
|
||||||
import eu.crushedpixel.replaymod.holders.PositionKeyframe;
|
|
||||||
import eu.crushedpixel.replaymod.holders.TimeKeyframe;
|
|
||||||
import eu.crushedpixel.replaymod.recording.ConnectionEventHandler;
|
|
||||||
import eu.crushedpixel.replaymod.registry.ReplayGuiRegistry;
|
|
||||||
import eu.crushedpixel.replaymod.replay.ReplayHandler;
|
|
||||||
import eu.crushedpixel.replaymod.replay.ReplayProcess;
|
|
||||||
import eu.crushedpixel.replaymod.utils.MouseUtils;
|
|
||||||
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.gui.inventory.GuiInventory;
|
|
||||||
import net.minecraft.client.renderer.GlStateManager;
|
|
||||||
import net.minecraft.client.resources.I18n;
|
|
||||||
import net.minecraft.entity.Entity;
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
|
||||||
import net.minecraftforge.client.event.RenderGameOverlayEvent;
|
|
||||||
import net.minecraftforge.fml.client.FMLClientHandler;
|
|
||||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
|
||||||
import org.lwjgl.input.Mouse;
|
|
||||||
import org.lwjgl.opengl.Display;
|
|
||||||
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import static net.minecraft.client.renderer.GlStateManager.*;
|
|
||||||
import static org.lwjgl.opengl.GL11.*;
|
|
||||||
|
|
||||||
public class GuiReplayOverlay extends Gui {
|
|
||||||
|
|
||||||
private final Minecraft mc = Minecraft.getMinecraft();
|
|
||||||
int sl_begin_x = 0;
|
|
||||||
int sl_end_x = 63;
|
|
||||||
int sl_y = 40;
|
|
||||||
int plus_x = 0;
|
|
||||||
int plus_y = 0;
|
|
||||||
int minus_x = 0;
|
|
||||||
int minus_y = 9;
|
|
||||||
int slider_begin_x = 1;
|
|
||||||
int slider_begin_width = 1;
|
|
||||||
int slider_end_x = 62;
|
|
||||||
int slider_end_width = 1;
|
|
||||||
int slider_y = 50;
|
|
||||||
int slider_height = 7;
|
|
||||||
private int sliderX = 35;
|
|
||||||
private int sliderY = 10;
|
|
||||||
private int timelineX = sliderX + 100 + 5;
|
|
||||||
private int realTimelineX = 10 + 4 * 25;
|
|
||||||
private int realTimelineY = 33 + 10;
|
|
||||||
private int ppButtonX = 10;
|
|
||||||
private int ppButtonY = 10;
|
|
||||||
private int r_ppButtonX = 10;
|
|
||||||
private int r_ppButtonY = realTimelineY + 1;
|
|
||||||
private int exportButtonX = 35;
|
|
||||||
private int exportButtonY = realTimelineY + 1;
|
|
||||||
private int place_ButtonX = 60;
|
|
||||||
private int place_ButtonY = realTimelineY + 1;
|
|
||||||
private int time_ButtonX = 85;
|
|
||||||
private int time_ButtonY = realTimelineY + 1;
|
|
||||||
private ResourceLocation replay_gui = new ResourceLocation("replaymod", "replay_gui.png");
|
|
||||||
private ResourceLocation extended_gui = new ResourceLocation("replaymod", "extended_gui.png");
|
|
||||||
private ResourceLocation timeline_icons = new ResourceLocation("replaymod", "timeline_icons.png");
|
|
||||||
private GuiReplaySpeedSlider speedSlider;
|
|
||||||
private boolean mouseDown = false;
|
|
||||||
private int tl_begin_x = 0;
|
|
||||||
private int tl_begin_width = 4;
|
|
||||||
private int tl_end_x = 60;
|
|
||||||
private int tl_end_width = 4;
|
|
||||||
private int tl_middle_x = 4;
|
|
||||||
private int tl_y = 40;
|
|
||||||
private float zoom_scale = 0.1f; //can see 1/10th of the timeline
|
|
||||||
private float pos_left = 0f; //left border of timeline is at 0%
|
|
||||||
private long timelineLength = 10 * 60 * 1000; //10 min of timeline
|
|
||||||
private float zoom_steps = 0.05f;
|
|
||||||
private boolean wasSliding = false;
|
|
||||||
private boolean mouseDwn = false;
|
|
||||||
|
|
||||||
public void resetUI(boolean slider) throws Exception {
|
|
||||||
if(FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class)) {
|
|
||||||
mc.displayGuiScreen(null);
|
|
||||||
}
|
|
||||||
ReplayHandler.setRealTimelineCursor(0);
|
|
||||||
if(slider)
|
|
||||||
speedSlider = new GuiReplaySpeedSlider(1, sliderX, sliderY, I18n.format("replaymod.gui.speed"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
public void onRenderGui(RenderGameOverlayEvent event) {
|
|
||||||
if(ReplayProcess.isVideoRecording() && ReplayHandler.isInPath() && !(mc.currentScreen instanceof GuiCancelRender)) {
|
|
||||||
if(event.isCancelable()) event.setCanceled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
public void onRenderTabList(RenderGameOverlayEvent.Pre event) { //cancelling tab list rendering and rendering help instead
|
|
||||||
if(ReplayHandler.isInReplay() && event.type == RenderGameOverlayEvent.ElementType.PLAYER_LIST) {
|
|
||||||
event.setCanceled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
public void renderRecordingIndicator(RenderGameOverlayEvent.Text event) {
|
|
||||||
if(!ReplayHandler.isInReplay() && ReplayMod.replaySettings.showRecordingIndicator() && ConnectionEventHandler.isRecording()) {
|
|
||||||
this.drawString(mc.fontRendererObj, I18n.format("replaymod.gui.recording").toUpperCase(), 30, 18 - (mc.fontRendererObj.FONT_HEIGHT / 2), Color.WHITE.getRGB());
|
|
||||||
mc.renderEngine.bindTexture(replay_gui);
|
|
||||||
GlStateManager.resetColor();
|
|
||||||
GlStateManager.enableAlpha();
|
|
||||||
this.drawModalRectWithCustomSizedTexture(10, 10, 40, 21, 16, 16, 64, 64);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
public void onRenderGui(RenderGameOverlayEvent.Post event) throws IllegalArgumentException, IllegalAccessException {
|
|
||||||
if(!ReplayHandler.isInReplay() || FMLClientHandler.instance().isGUIOpen(GuiPlayerOverview.class)
|
|
||||||
|| FMLClientHandler.instance().isGUIOpen(GuiKeyframeRepository.class)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!ReplayGuiRegistry.hidden && ReplayHandler.isCamera()) ReplayGuiRegistry.hide();
|
|
||||||
else if(!ReplayHandler.isCamera() && ReplayGuiRegistry.hidden) ReplayGuiRegistry.show();
|
|
||||||
|
|
||||||
if(FMLClientHandler.instance().isGUIOpen(GuiChat.class) || FMLClientHandler.instance().isGUIOpen(GuiInventory.class)) {
|
|
||||||
mc.displayGuiScreen(new GuiMouseInput());
|
|
||||||
}
|
|
||||||
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
|
|
||||||
Point mousePoint = MouseUtils.getMousePos();
|
|
||||||
final int mouseX = (int) mousePoint.getX();
|
|
||||||
final int mouseY = (int) mousePoint.getY();
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
//Play/Pause button
|
|
||||||
int x = 0;
|
|
||||||
int y = 0;
|
|
||||||
|
|
||||||
boolean play = !ReplayMod.replaySender.paused();
|
|
||||||
boolean hover = false;
|
|
||||||
|
|
||||||
if(FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class)) {
|
|
||||||
if(mouseX >= ppButtonX && mouseX <= ppButtonX + 20
|
|
||||||
&& mouseY >= ppButtonY && mouseY <= ppButtonY + 20) {
|
|
||||||
hover = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(play) {
|
|
||||||
y = 20;
|
|
||||||
}
|
|
||||||
if(hover) {
|
|
||||||
x = 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
mc.renderEngine.bindTexture(replay_gui);
|
|
||||||
|
|
||||||
GlStateManager.resetColor();
|
|
||||||
this.drawModalRectWithCustomSizedTexture(ppButtonX, ppButtonY, x, y, 20, 20, 64, 64);
|
|
||||||
|
|
||||||
//When hurrying, no Timeline jumping etc. is possible
|
|
||||||
if(Mouse.isButtonDown(0) && FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class)) { //clicking the Button
|
|
||||||
if(!ReplayMod.replaySender.isHurrying()) {
|
|
||||||
speedSlider.mousePressed(mc, mouseX, mouseY);
|
|
||||||
if(!mouseDown) {
|
|
||||||
mouseDown = true;
|
|
||||||
if(hover) {
|
|
||||||
playOrPause();
|
|
||||||
} else if(mouseX >= exportButtonX && mouseX <= exportButtonX + 20 && mouseY >= exportButtonY && exportButtonY <= exportButtonY + 20) {
|
|
||||||
mc.displayGuiScreen(new GuiRenderSettings());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mouseX >= timelineX + 4 && mouseX <= width - 18 && mouseY >= 11 && mouseY <= 29) {
|
|
||||||
double tot = (width - 18) - (timelineX + 4);
|
|
||||||
double perc = (mouseX - (timelineX + 4)) / tot;
|
|
||||||
final double time = perc * (double) ReplayMod.replaySender.replayLength();
|
|
||||||
|
|
||||||
if(time < ReplayMod.replaySender.currentTimeStamp()) {
|
|
||||||
mc.displayGuiScreen(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
CameraEntity cam = ReplayHandler.getCameraEntity();
|
|
||||||
if(cam != null) {
|
|
||||||
ReplayHandler.setLastPosition(new Position(cam.posX, cam.posY, cam.posZ, cam.rotationPitch, cam.rotationYaw));
|
|
||||||
} else {
|
|
||||||
ReplayHandler.setLastPosition(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
long diff = (long) time - ReplayMod.replaySender.getDesiredTimestamp();
|
|
||||||
if(diff != 0) {
|
|
||||||
if (diff > 0 && diff < 5000) { // Small difference and no time travel
|
|
||||||
ReplayMod.replaySender.jumpToTime((int) time);
|
|
||||||
} else { // We either have to restart the replay or send a significant amount of packets
|
|
||||||
// Render our please-wait-screen
|
|
||||||
GuiScreen guiScreen = new GuiScreen() {
|
|
||||||
@Override
|
|
||||||
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
|
|
||||||
drawBackground(0);
|
|
||||||
drawCenteredString(fontRendererObj, I18n.format("replaymod.gui.pleasewait"),
|
|
||||||
width / 2, height / 2, 0xffffffff);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Make sure that the replaysender changes into sync mode
|
|
||||||
ReplayMod.replaySender.setAsyncMode(false);
|
|
||||||
synchronized (ReplayMod.replaySender) {
|
|
||||||
// This will make sure that the async thread has stopped
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perform the rendering using OpenGL
|
|
||||||
pushMatrix();
|
|
||||||
clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
||||||
enableTexture2D();
|
|
||||||
mc.getFramebuffer().bindFramebuffer(true);
|
|
||||||
mc.entityRenderer.setupOverlayRendering();
|
|
||||||
|
|
||||||
guiScreen.setWorldAndResolution(mc, width, height);
|
|
||||||
guiScreen.drawScreen(0, 0, 0);
|
|
||||||
|
|
||||||
mc.getFramebuffer().unbindFramebuffer();
|
|
||||||
popMatrix();
|
|
||||||
pushMatrix();
|
|
||||||
mc.getFramebuffer().framebufferRender(mc.displayWidth, mc.displayHeight);
|
|
||||||
popMatrix();
|
|
||||||
|
|
||||||
Display.update();
|
|
||||||
|
|
||||||
// Send the packets
|
|
||||||
ReplayMod.replaySender.sendPacketsTill((int) time);
|
|
||||||
ReplayMod.replaySender.setAsyncMode(true);
|
|
||||||
ReplayMod.replaySender.setReplaySpeed(0);
|
|
||||||
|
|
||||||
// Tick twice to process all packets and position interpolation
|
|
||||||
try {
|
|
||||||
mc.runTick();
|
|
||||||
mc.runTick();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace(); // This should never be thrown but whatever
|
|
||||||
}
|
|
||||||
|
|
||||||
// No need to remove our please-wait-screen. It'll vanish with the next
|
|
||||||
// render pass as it's never been a real GuiScreen in the first place.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
speedSlider.mouseReleased(mouseX, mouseY);
|
|
||||||
mouseDown = false;
|
|
||||||
} catch(Exception e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hover = false;
|
|
||||||
x = 0;
|
|
||||||
y = 18;
|
|
||||||
|
|
||||||
if(FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class)) {
|
|
||||||
if(mouseX >= exportButtonX && mouseX <= exportButtonX + 20
|
|
||||||
&& mouseY >= exportButtonY && mouseY <= exportButtonY + 20) {
|
|
||||||
hover = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(hover) {
|
|
||||||
x = 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
mc.renderEngine.bindTexture(timeline_icons);
|
|
||||||
|
|
||||||
GlStateManager.resetColor();
|
|
||||||
this.drawModalRectWithCustomSizedTexture(exportButtonX, exportButtonY, x, y, 20, 20, 64, 64);
|
|
||||||
|
|
||||||
//GlStateManager.resetColor();
|
|
||||||
|
|
||||||
//Place Keyframe Button
|
|
||||||
hover = false;
|
|
||||||
x = 0;
|
|
||||||
y = 0;
|
|
||||||
|
|
||||||
if(FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class)) {
|
|
||||||
if(mouseX >= place_ButtonX && mouseX <= place_ButtonX + 20
|
|
||||||
&& mouseY >= place_ButtonY && mouseY <= place_ButtonY + 20) {
|
|
||||||
hover = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(hover) {
|
|
||||||
x = 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ReplayHandler.getSelectedKeyframe() != null && ReplayHandler.getSelectedKeyframe() instanceof PositionKeyframe) {
|
|
||||||
y += 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
mc.renderEngine.bindTexture(extended_gui);
|
|
||||||
|
|
||||||
if(hover && Mouse.isButtonDown(0) && isClick() && FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class)
|
|
||||||
&& !ReplayHandler.isInPath()) {
|
|
||||||
if(ReplayHandler.getSelectedKeyframe() == null || !(ReplayHandler.getSelectedKeyframe() instanceof PositionKeyframe)) {
|
|
||||||
addPlaceKeyframe();
|
|
||||||
} else {
|
|
||||||
ReplayHandler.removeKeyframe(ReplayHandler.getSelectedKeyframe());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GlStateManager.resetColor();
|
|
||||||
this.drawModalRectWithCustomSizedTexture(place_ButtonX, place_ButtonY, x, y, 20, 20, 64, 64);
|
|
||||||
|
|
||||||
|
|
||||||
//Time Keyframe Button
|
|
||||||
hover = false;
|
|
||||||
x = 0;
|
|
||||||
y = 40;
|
|
||||||
|
|
||||||
boolean timeSelected = false;
|
|
||||||
if(ReplayHandler.getSelectedKeyframe() != null && ReplayHandler.getSelectedKeyframe() instanceof TimeKeyframe) {
|
|
||||||
timeSelected = true;
|
|
||||||
x = 40;
|
|
||||||
y = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class)) {
|
|
||||||
if(mouseX >= time_ButtonX && mouseX <= time_ButtonX + 20
|
|
||||||
&& mouseY >= time_ButtonY && mouseY <= time_ButtonY + 20) {
|
|
||||||
hover = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(hover) {
|
|
||||||
if(timeSelected) {
|
|
||||||
y = 20;
|
|
||||||
} else {
|
|
||||||
x = 20;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mc.renderEngine.bindTexture(extended_gui);
|
|
||||||
|
|
||||||
if(hover && Mouse.isButtonDown(0) && isClick() && FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class)) {
|
|
||||||
if(ReplayHandler.getSelectedKeyframe() == null || !(ReplayHandler.getSelectedKeyframe() instanceof TimeKeyframe) && !ReplayHandler.isInPath()) {
|
|
||||||
addTimeKeyframe();
|
|
||||||
} else {
|
|
||||||
ReplayHandler.removeKeyframe(ReplayHandler.getSelectedKeyframe());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GlStateManager.resetColor();
|
|
||||||
this.drawModalRectWithCustomSizedTexture(time_ButtonX, time_ButtonY, x, y, 20, 20, 64, 64);
|
|
||||||
|
|
||||||
if(mouseX >= (timelineX + 4) && mouseX <= width - 18 && mouseY >= 11 && mouseY <= 29 && FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class)) {
|
|
||||||
double tot = (width - 18) - (timelineX + 4);
|
|
||||||
double perc = (mouseX - (timelineX + 4)) / tot;
|
|
||||||
long time = Math.round(perc * (double) ReplayMod.replaySender.replayLength());
|
|
||||||
|
|
||||||
String timestamp = (String.format("%02d:%02ds",
|
|
||||||
TimeUnit.MILLISECONDS.toMinutes(time),
|
|
||||||
TimeUnit.MILLISECONDS.toSeconds(time) -
|
|
||||||
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(time))
|
|
||||||
));
|
|
||||||
|
|
||||||
this.drawCenteredString(mc.fontRendererObj, timestamp, mouseX, mouseY + 5, Color.WHITE.getRGB());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mc.inGameHasFocus) {
|
|
||||||
Mouse.setCursorPosition(width / 2, height / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
speedSlider.drawButton(mc, mouseX, mouseY);
|
|
||||||
} catch(Exception e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
GlStateManager.resetColor();
|
|
||||||
|
|
||||||
Entity player = ReplayHandler.getCameraEntity();
|
|
||||||
if(player != null) {
|
|
||||||
player.setVelocity(0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!Mouse.isButtonDown(0)) isClick();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawTimeline(int minX, int maxX, int y) {
|
|
||||||
int zero = minX + tl_begin_width;
|
|
||||||
int full = maxX - tl_end_width;
|
|
||||||
|
|
||||||
GlStateManager.resetColor();
|
|
||||||
mc.renderEngine.bindTexture(replay_gui);
|
|
||||||
this.drawModalRectWithCustomSizedTexture(minX, y, tl_begin_x, tl_y, tl_begin_width, 22, 64, 64);
|
|
||||||
|
|
||||||
for(int i = minX + tl_begin_width; i < maxX - tl_end_width; i += tl_end_x - tl_begin_width) {
|
|
||||||
this.drawModalRectWithCustomSizedTexture(i, y, tl_begin_x + tl_begin_width
|
|
||||||
, tl_y, Math.min(tl_end_x - tl_begin_width, maxX - tl_end_width - i)
|
|
||||||
, 22, 64, 64);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.drawModalRectWithCustomSizedTexture(maxX - tl_end_width, y, tl_end_x, tl_y, tl_end_width, 22, 64, 64);
|
|
||||||
|
|
||||||
//Cursor
|
|
||||||
double width = full - zero;
|
|
||||||
double perc = (double) ReplayMod.replaySender.currentTimeStamp() / (double) ReplayMod.replaySender.replayLength();
|
|
||||||
|
|
||||||
int cursorX = (int) Math.round(zero + (perc * width));
|
|
||||||
this.drawModalRectWithCustomSizedTexture(cursorX - 3, y + 3, 44, 0, 8, 16, 64, 64);
|
|
||||||
}
|
|
||||||
|
|
||||||
private long keyframeSelectionTime = 0;
|
|
||||||
|
|
||||||
private boolean liftedSinceSelection = false;
|
|
||||||
private int selectionTimestamp = 0;
|
|
||||||
private boolean overcameToleranceSinceSelection = false;
|
|
||||||
|
|
||||||
private void drawRealTimeline(int minX, int maxX, int y, int mouseX, int mouseY) {
|
|
||||||
int zero = minX + tl_begin_width;
|
|
||||||
int full = maxX - tl_end_width;
|
|
||||||
|
|
||||||
//the real timeline
|
|
||||||
GlStateManager.resetColor();
|
|
||||||
mc.renderEngine.bindTexture(replay_gui);
|
|
||||||
this.drawModalRectWithCustomSizedTexture(minX, y, tl_begin_x, tl_y, tl_begin_width, 22, 64, 64);
|
|
||||||
|
|
||||||
for(int i = minX + tl_begin_width; i < maxX - tl_end_width; i += tl_end_x - tl_begin_width) {
|
|
||||||
this.drawModalRectWithCustomSizedTexture(i, y, tl_begin_x + tl_begin_width
|
|
||||||
, tl_y, Math.min(tl_end_x - tl_begin_width, maxX - tl_end_width - i)
|
|
||||||
, 22, 64, 64);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.drawModalRectWithCustomSizedTexture(maxX - tl_end_width, y, tl_end_x, tl_y, tl_end_width, 22, 64, 64);
|
|
||||||
|
|
||||||
//Time Slider
|
|
||||||
int yo = y + 22 + 1;
|
|
||||||
GlStateManager.resetColor();
|
|
||||||
mc.renderEngine.bindTexture(timeline_icons);
|
|
||||||
this.drawModalRectWithCustomSizedTexture(minX, yo, sl_begin_x, sl_y, 2, 9, 64, 64);
|
|
||||||
|
|
||||||
for(int i = minX + 2; i < maxX - 1; i += sl_end_x - 2) {
|
|
||||||
this.drawModalRectWithCustomSizedTexture(i, yo, 2, sl_y,
|
|
||||||
Math.min(sl_end_x - 2, maxX - 1 - i), 9, 64, 64);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.drawModalRectWithCustomSizedTexture(maxX - 1, yo, sl_end_x, sl_y, 1, 9, 64, 64);
|
|
||||||
|
|
||||||
//Timeline Pos Slider
|
|
||||||
int sl_y = yo + 1;
|
|
||||||
int minPos = minX + 1;
|
|
||||||
int maxPos = maxX - 2;
|
|
||||||
int tlWidth = maxPos - minPos;
|
|
||||||
|
|
||||||
int slider_min = minPos + Math.round(pos_left * tlWidth);
|
|
||||||
int slider_width = Math.round(zoom_scale * tlWidth);
|
|
||||||
|
|
||||||
int sl_max = slider_min + slider_width;
|
|
||||||
|
|
||||||
this.drawModalRectWithCustomSizedTexture(slider_min, sl_y, slider_begin_x, slider_y, slider_begin_width, slider_height, 64, 64);
|
|
||||||
|
|
||||||
for(int i = slider_min + slider_begin_width; i < sl_max - slider_end_width; i += slider_end_x - slider_begin_width - slider_begin_x) {
|
|
||||||
this.drawModalRectWithCustomSizedTexture(i, sl_y, slider_begin_x + slider_begin_width, slider_y,
|
|
||||||
Math.min(slider_end_x - slider_end_width - slider_begin_x, sl_max - slider_end_width - i), slider_height, 64, 64);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.drawModalRectWithCustomSizedTexture(sl_max - slider_end_width, sl_y, slider_end_x, slider_y,
|
|
||||||
slider_end_width, slider_height, 64, 64);
|
|
||||||
|
|
||||||
//Slider dragging
|
|
||||||
if(Mouse.isButtonDown(0) && FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class) && (mouseX >= slider_min && mouseX <= sl_max && mouseY >= sl_y && mouseY <= sl_y + slider_height || wasSliding)) {
|
|
||||||
wasSliding = true;
|
|
||||||
float dx = ((float) Mouse.getDX() * (float) new ScaledResolution(mc, mc.displayWidth, mc.displayHeight).getScaledWidth() / mc.displayWidth);
|
|
||||||
this.pos_left = Math.min(1f - this.zoom_scale, Math.max(0f, this.pos_left + (dx / (float) tlWidth)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!Mouse.isButtonDown(0)) {
|
|
||||||
wasSliding = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Timeline Buttons
|
|
||||||
//+- Buttons
|
|
||||||
boolean hover = false;
|
|
||||||
int px = plus_x;
|
|
||||||
if(FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class)) {
|
|
||||||
if(mouseX >= maxX + 2 && mouseX <= maxX + 2 + 9
|
|
||||||
&& mouseY >= y + 1 && mouseY <= y + 1 + 9) {
|
|
||||||
hover = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(hover) {
|
|
||||||
px += 9;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.drawModalRectWithCustomSizedTexture(maxX + 2, y + 1, px, plus_y, 9, 9, 64, 64);
|
|
||||||
|
|
||||||
if(hover && Mouse.isButtonDown(0) && FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class)) {
|
|
||||||
zoomIn();
|
|
||||||
}
|
|
||||||
|
|
||||||
hover = false;
|
|
||||||
int mx = minus_x;
|
|
||||||
|
|
||||||
if(FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class)) {
|
|
||||||
if(mouseX >= maxX + 2 && mouseX <= maxX + 2 + 9
|
|
||||||
&& mouseY >= y + 9 + 3 && mouseY <= y + 9 + 3 + 9) {
|
|
||||||
hover = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(hover) {
|
|
||||||
mx += 9;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.drawModalRectWithCustomSizedTexture(maxX + 2, y + 9 + 3, mx, minus_y, 9, 9, 64, 64);
|
|
||||||
|
|
||||||
if(hover && Mouse.isButtonDown(0) && FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class)) {
|
|
||||||
zoomOut();
|
|
||||||
}
|
|
||||||
|
|
||||||
//show Time String
|
|
||||||
if(mouseX >= zero && mouseX <= full && mouseY >= y && mouseY <= y + 22 && FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class)) {
|
|
||||||
long tot = Math.round((double) timelineLength * zoom_scale);
|
|
||||||
double perc = (mouseX - (realTimelineX + 4)) / (double) (full - zero);
|
|
||||||
|
|
||||||
long time = Math.round(this.pos_left * (double) timelineLength) + Math.round(perc * (double) tot);
|
|
||||||
|
|
||||||
String timestamp = (String.format("%02d:%02ds",
|
|
||||||
TimeUnit.MILLISECONDS.toMinutes(time),
|
|
||||||
TimeUnit.MILLISECONDS.toSeconds(time) -
|
|
||||||
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(time))
|
|
||||||
));
|
|
||||||
this.drawCenteredString(mc.fontRendererObj, timestamp, mouseX, mouseY + 5, Color.WHITE.getRGB());
|
|
||||||
}
|
|
||||||
|
|
||||||
//draw Markers on timeline
|
|
||||||
MarkerType mt = MarkerType.getMarkerType(zoom_scale, timelineLength);
|
|
||||||
|
|
||||||
//every x seconds, draw small marker
|
|
||||||
long left_real = Math.round(pos_left * (double) timelineLength);
|
|
||||||
long right_real = left_real + (Math.round(zoom_scale * timelineLength));
|
|
||||||
long tot = Math.round((double) timelineLength * zoom_scale);
|
|
||||||
|
|
||||||
for(int s = 0; s <= timelineLength; s += mt.getSmallDistance()) {
|
|
||||||
if(s > right_real) break;
|
|
||||||
if(s >= left_real) {
|
|
||||||
//calculate absolute position on screen
|
|
||||||
long relative = (s) - (left_real);
|
|
||||||
double perc = ((double) relative / (double) tot);
|
|
||||||
|
|
||||||
long real_width = full - zero;
|
|
||||||
long rel_x = Math.round(perc * (double) real_width);
|
|
||||||
|
|
||||||
long real_x = zero + rel_x;
|
|
||||||
|
|
||||||
this.drawVerticalLine((int) real_x, y + 19 - 3, y + 19, Color.WHITE.getRGB());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//every x seconds, draw big marker
|
|
||||||
for(int s = 0; s <= timelineLength; s += mt.getDistance()) {
|
|
||||||
if(s > right_real) break;
|
|
||||||
if(s >= left_real) {
|
|
||||||
//calculate absolute position on screen
|
|
||||||
long relative = s - (left_real);
|
|
||||||
double perc = ((double) relative / (double) tot);
|
|
||||||
|
|
||||||
long real_width = full - zero;
|
|
||||||
long rel_x = Math.round(perc * (double) real_width);
|
|
||||||
|
|
||||||
long real_x = zero + rel_x;
|
|
||||||
|
|
||||||
this.drawVerticalLine((int) real_x, y + 19 - 7, y + 19, Color.LIGHT_GRAY.getRGB());
|
|
||||||
|
|
||||||
//write text
|
|
||||||
int time = s;
|
|
||||||
String timestamp = (String.format("%02d:%02d",
|
|
||||||
TimeUnit.MILLISECONDS.toMinutes(time),
|
|
||||||
TimeUnit.MILLISECONDS.toSeconds(time) -
|
|
||||||
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(time))
|
|
||||||
));
|
|
||||||
|
|
||||||
this.drawCenteredString(mc.fontRendererObj, timestamp, (int) real_x, y - 8, Color.WHITE.getRGB());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//handle Mouse clicks on realTimeLine
|
|
||||||
if(Mouse.isButtonDown(0) && FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class) && !wasSliding && mouseX >= minX + tl_begin_width && mouseX <= maxX - tl_end_width &&
|
|
||||||
mouseY >= y && mouseY <= y + 22 && !ReplayHandler.isInPath()) {
|
|
||||||
|
|
||||||
//calculate real time and set cursor accordingly
|
|
||||||
int width = (maxX - tl_end_width) - (minX + tl_begin_width);
|
|
||||||
int rel_x = mouseX - (minX + tl_begin_width);
|
|
||||||
|
|
||||||
float rel_pos = (float) rel_x / (float) width;
|
|
||||||
|
|
||||||
float abs_width = (zoom_scale * (float) timelineLength);
|
|
||||||
int real_pos = (int)Math.floor(left_real + ((rel_pos) * abs_width));
|
|
||||||
|
|
||||||
if(liftedSinceSelection) {
|
|
||||||
ReplayHandler.setRealTimelineCursor(real_pos);
|
|
||||||
} else if(ReplayHandler.getSelectedKeyframe() != null) {
|
|
||||||
int tolerance = 2 * Math.round(abs_width / (float) width);
|
|
||||||
|
|
||||||
if(Math.abs(selectionTimestamp - real_pos) > tolerance || overcameToleranceSinceSelection) {
|
|
||||||
ReplayHandler.setRealTimelineCursor(real_pos);
|
|
||||||
ReplayHandler.getSelectedKeyframe().setRealTimestamp(real_pos);
|
|
||||||
ReplayHandler.sortKeyframes();
|
|
||||||
overcameToleranceSinceSelection = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Keyframe click handling here
|
|
||||||
if(isClick()) {
|
|
||||||
//tolerance is 2 pixels multiplied with the timespan of one pixel
|
|
||||||
int tolerance = 2 * Math.round(abs_width / (float) width);
|
|
||||||
|
|
||||||
Keyframe close;
|
|
||||||
if(mouseY >= y + 9) {
|
|
||||||
close = ReplayHandler.getClosestTimeKeyframeForRealTime(ReplayHandler.getRealTimelineCursor(), tolerance);
|
|
||||||
ReplayHandler.selectKeyframe(close); //can be null, deselects keyframe
|
|
||||||
} else {
|
|
||||||
close = ReplayHandler.getClosestPlaceKeyframeForRealTime(ReplayHandler.getRealTimelineCursor(), tolerance);
|
|
||||||
ReplayHandler.selectKeyframe(close); //can be null, deselects keyframe
|
|
||||||
}
|
|
||||||
|
|
||||||
if(close != null) {
|
|
||||||
liftedSinceSelection = false;
|
|
||||||
overcameToleranceSinceSelection = false;
|
|
||||||
selectionTimestamp = close.getRealTimestamp();
|
|
||||||
float perc = (selectionTimestamp - left_real) / abs_width;
|
|
||||||
int newX = Math.round(minX + tl_begin_width + (perc * width));
|
|
||||||
MouseUtils.moveMouse(newX, mouseY);
|
|
||||||
ReplayHandler.setRealTimelineCursor(selectionTimestamp);
|
|
||||||
|
|
||||||
long cur = System.currentTimeMillis();
|
|
||||||
if(cur - keyframeSelectionTime < 500) { //if double click on Keyframe
|
|
||||||
mc.displayGuiScreen(new GuiEditKeyframe(close));
|
|
||||||
} else {
|
|
||||||
keyframeSelectionTime = cur;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if(!Mouse.isButtonDown(0)) {
|
|
||||||
liftedSinceSelection = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Draw Realtime Cursor
|
|
||||||
if(ReplayHandler.getRealTimelineCursor() >= left_real && ReplayHandler.getRealTimelineCursor() <= right_real) {
|
|
||||||
long rel_pos = ReplayHandler.getRealTimelineCursor() - left_real;
|
|
||||||
long rel_width = right_real - left_real;
|
|
||||||
double perc = (double) rel_pos / (double) rel_width;
|
|
||||||
|
|
||||||
int real_width = (maxX - tl_end_width) - (minX + tl_begin_width);
|
|
||||||
double rel_x = (float) real_width * perc;
|
|
||||||
|
|
||||||
int real_x = (int) Math.round((minX + tl_begin_width) + rel_x);
|
|
||||||
mc.renderEngine.bindTexture(this.replay_gui);
|
|
||||||
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
this.drawModalRectWithCustomSizedTexture(real_x - 3, y + 3, 44, 0, 8, 16, 64, 64);
|
|
||||||
//this.drawModalRectWithCustomSizedTexture(real_x, sl_y, u, v, width, height, textureWidth, textureHeight)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//Draw Keyframe logos
|
|
||||||
mc.renderEngine.bindTexture(timeline_icons);
|
|
||||||
for(Keyframe kf : ReplayHandler.getKeyframes()) {
|
|
||||||
if(kf.getRealTimestamp() > right_real) break;
|
|
||||||
if(kf.getRealTimestamp() >= left_real) {
|
|
||||||
int dx = 18;
|
|
||||||
int dy = 0;
|
|
||||||
|
|
||||||
int ry = y + 3;
|
|
||||||
|
|
||||||
if(kf instanceof TimeKeyframe) {
|
|
||||||
dy = 5;
|
|
||||||
ry += 5;
|
|
||||||
}
|
|
||||||
if(ReplayHandler.isSelected(kf)) {
|
|
||||||
dx += 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
long relative = kf.getRealTimestamp() - (left_real);
|
|
||||||
double perc = ((double) relative / (double) tot);
|
|
||||||
|
|
||||||
long real_width = full - zero;
|
|
||||||
long rel_x = Math.round(perc * (double) real_width);
|
|
||||||
|
|
||||||
long real_x = zero + rel_x - 2;
|
|
||||||
|
|
||||||
this.drawModalRectWithCustomSizedTexture((int) real_x, ry, dx, dy, 5, 5, 64, 64);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Draw Play/Pause Button
|
|
||||||
//Play/Pause button
|
|
||||||
|
|
||||||
int dx = 0;
|
|
||||||
int dy = 0;
|
|
||||||
|
|
||||||
boolean play = ReplayHandler.isInPath();
|
|
||||||
hover = false;
|
|
||||||
|
|
||||||
if(FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class)) {
|
|
||||||
if(mouseX >= r_ppButtonX && mouseX <= r_ppButtonX + 20
|
|
||||||
&& mouseY >= r_ppButtonY && mouseY <= r_ppButtonY + 20) {
|
|
||||||
hover = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(play) {
|
|
||||||
dy = 20;
|
|
||||||
}
|
|
||||||
if(hover) {
|
|
||||||
dx = 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
mc.renderEngine.bindTexture(replay_gui);
|
|
||||||
|
|
||||||
GlStateManager.resetColor();
|
|
||||||
this.drawModalRectWithCustomSizedTexture(r_ppButtonX, r_ppButtonY, dx, dy, 20, 20, 64, 64);
|
|
||||||
|
|
||||||
//Handling the click on the Replay starter
|
|
||||||
if(hover && Mouse.isButtonDown(0) && isClick() && FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class)) {
|
|
||||||
if(ReplayHandler.isInPath()) {
|
|
||||||
ReplayHandler.interruptReplay();
|
|
||||||
} else {
|
|
||||||
ReplayHandler.startPath(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addPlaceKeyframe() {
|
|
||||||
Entity cam = mc.getRenderViewEntity();
|
|
||||||
if(cam == null) return;
|
|
||||||
ReplayHandler.addKeyframe(new PositionKeyframe(ReplayHandler.getRealTimelineCursor(), new Position(cam.posX, cam.posY, cam.posZ, cam.rotationPitch, cam.rotationYaw % 360, ReplayHandler.getCameraTilt())));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addTimeKeyframe() {
|
|
||||||
ReplayHandler.addKeyframe(new TimeKeyframe(ReplayHandler.getRealTimelineCursor(), ReplayMod.replaySender.currentTimeStamp()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void zoomIn() {
|
|
||||||
if(!isClick()) return;
|
|
||||||
this.zoom_scale = Math.max(0.025f, zoom_scale - zoom_steps);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void zoomOut() {
|
|
||||||
if(!isClick()) return;
|
|
||||||
this.zoom_scale = Math.min(1f, zoom_scale + zoom_steps);
|
|
||||||
this.pos_left = Math.min(pos_left, 1f - zoom_scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isClick() {
|
|
||||||
if(Mouse.isButtonDown(0)) {
|
|
||||||
boolean bef = mouseDwn;
|
|
||||||
mouseDwn = true;
|
|
||||||
return !bef;
|
|
||||||
} else {
|
|
||||||
mouseDwn = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum MarkerType {
|
|
||||||
|
|
||||||
ONE_S(1 * 1000, 100),
|
|
||||||
FIVE_S(5 * 1000, 1 * 1000),
|
|
||||||
QUARTER_M(15 * 1000, 3 * 1000),
|
|
||||||
HALF_M(30 * 1000, 5 * 1000),
|
|
||||||
ONE_M(60 * 1000, 10 * 1000),
|
|
||||||
FIVE_M(5 * 60 * 1000, 50 * 1000);
|
|
||||||
|
|
||||||
int minimum;
|
|
||||||
int small_min;
|
|
||||||
int maximum = 10;
|
|
||||||
|
|
||||||
MarkerType(int minimum, int small_min) {
|
|
||||||
this.minimum = minimum;
|
|
||||||
this.small_min = small_min;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MarkerType getMarkerType(float scale, long totalLength) {
|
|
||||||
long visible = Math.round((double) totalLength * scale);
|
|
||||||
long seconds = visible;
|
|
||||||
|
|
||||||
for(MarkerType mt : values()) {
|
|
||||||
if(seconds / mt.getDistance() <= 10) {
|
|
||||||
return mt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return FIVE_M;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getDistance() {
|
|
||||||
return minimum;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getSmallDistance() {
|
|
||||||
return small_min;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void playOrPause() {
|
|
||||||
boolean paused = !ReplayMod.replaySender.paused();
|
|
||||||
if(paused) {
|
|
||||||
ReplayMod.replaySender.setReplaySpeed(0);
|
|
||||||
} else {
|
|
||||||
ReplayMod.replaySender.setReplaySpeed(speedSlider.getSliderValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -89,7 +89,7 @@ public class KeyInputHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(kb.getKeyDescription().equals("key.chat") && kb.isPressed()) {
|
if(kb.getKeyDescription().equals("key.chat") && kb.isPressed()) {
|
||||||
mc.displayGuiScreen(new GuiMouseInput());
|
mc.displayGuiScreen(new GuiMouseInput(ReplayMod.overlay));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package eu.crushedpixel.replaymod.gui;
|
|||||||
import eu.crushedpixel.replaymod.ReplayMod;
|
import eu.crushedpixel.replaymod.ReplayMod;
|
||||||
import eu.crushedpixel.replaymod.gui.elements.GuiEntryList;
|
import eu.crushedpixel.replaymod.gui.elements.GuiEntryList;
|
||||||
import eu.crushedpixel.replaymod.gui.elements.listeners.SelectionListener;
|
import eu.crushedpixel.replaymod.gui.elements.listeners.SelectionListener;
|
||||||
|
import eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay;
|
||||||
import eu.crushedpixel.replaymod.holders.Keyframe;
|
import eu.crushedpixel.replaymod.holders.Keyframe;
|
||||||
import eu.crushedpixel.replaymod.holders.KeyframeSet;
|
import eu.crushedpixel.replaymod.holders.KeyframeSet;
|
||||||
import eu.crushedpixel.replaymod.replay.ReplayHandler;
|
import eu.crushedpixel.replaymod.replay.ReplayHandler;
|
||||||
@@ -18,7 +19,7 @@ import java.awt.*;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class GuiKeyframeRepository extends GuiScreen {
|
public class GuiKeyframeRepository extends GuiScreen implements GuiReplayOverlay.NoOverlay {
|
||||||
|
|
||||||
private boolean initialized = false;
|
private boolean initialized = false;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package eu.crushedpixel.replaymod.gui;
|
package eu.crushedpixel.replaymod.gui;
|
||||||
|
|
||||||
import eu.crushedpixel.replaymod.ReplayMod;
|
import eu.crushedpixel.replaymod.ReplayMod;
|
||||||
|
import eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.GuiScreen;
|
import net.minecraft.client.gui.GuiScreen;
|
||||||
import net.minecraft.client.settings.KeyBinding;
|
import net.minecraft.client.settings.KeyBinding;
|
||||||
@@ -9,6 +10,27 @@ import java.io.IOException;
|
|||||||
|
|
||||||
public class GuiMouseInput extends GuiScreen {
|
public class GuiMouseInput extends GuiScreen {
|
||||||
|
|
||||||
|
private final GuiReplayOverlay overlay;
|
||||||
|
|
||||||
|
public GuiMouseInput(GuiReplayOverlay overlay) {
|
||||||
|
this.overlay = overlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
|
||||||
|
overlay.mouseClicked(mouseX, mouseY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void mouseReleased(int mouseX, int mouseY, int state) {
|
||||||
|
overlay.mouseReleased(mouseX, mouseY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) {
|
||||||
|
overlay.mouseDrag(mouseX, mouseY);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void keyTyped(char typedChar, int keyCode) throws IOException {
|
protected void keyTyped(char typedChar, int keyCode) throws IOException {
|
||||||
for(KeyBinding kb : Minecraft.getMinecraft().gameSettings.keyBindings)
|
for(KeyBinding kb : Minecraft.getMinecraft().gameSettings.keyBindings)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package eu.crushedpixel.replaymod.gui;
|
|||||||
|
|
||||||
import com.mojang.realmsclient.util.Pair;
|
import com.mojang.realmsclient.util.Pair;
|
||||||
import eu.crushedpixel.replaymod.ReplayMod;
|
import eu.crushedpixel.replaymod.ReplayMod;
|
||||||
|
import eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay;
|
||||||
import eu.crushedpixel.replaymod.holders.PlayerVisibility;
|
import eu.crushedpixel.replaymod.holders.PlayerVisibility;
|
||||||
import eu.crushedpixel.replaymod.registry.PlayerHandler;
|
import eu.crushedpixel.replaymod.registry.PlayerHandler;
|
||||||
import eu.crushedpixel.replaymod.replay.ReplayHandler;
|
import eu.crushedpixel.replaymod.replay.ReplayHandler;
|
||||||
@@ -30,7 +31,7 @@ import java.util.Collections;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class GuiPlayerOverview extends GuiScreen {
|
public class GuiPlayerOverview extends GuiScreen implements GuiReplayOverlay.NoOverlay {
|
||||||
|
|
||||||
public static boolean defaultSave = false;
|
public static boolean defaultSave = false;
|
||||||
|
|
||||||
@@ -289,7 +290,7 @@ public class GuiPlayerOverview extends GuiScreen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//this is necessary to reset the GL parameters for further GUI rendering
|
//this is necessary to reset the GL parameters for further GUI rendering
|
||||||
drawRect(0, 0, 0, 0, Color.LIGHT_GRAY.getRGB());
|
GlStateManager.enableBlend();
|
||||||
}
|
}
|
||||||
|
|
||||||
private PlayerVisibility getVisibilityInstance() {
|
private PlayerVisibility getVisibilityInstance() {
|
||||||
|
|||||||
@@ -26,11 +26,6 @@ public class GuiReplaySpeedSlider extends GuiButton {
|
|||||||
this.valueStep = 1;
|
this.valueStep = 1;
|
||||||
this.displayString = displayKey + ": 1x";
|
this.displayString = displayKey + ": 1x";
|
||||||
this.displayKey = displayKey;
|
this.displayKey = displayKey;
|
||||||
|
|
||||||
Minecraft.getMinecraft().getTextureManager().bindTexture(buttonTextures);
|
|
||||||
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
|
|
||||||
this.drawTexturedModalRect(this.xPosition + (int) (sliderValue * (float) (this.width - 8)), this.yPosition, 0, 66, 4, 20);
|
|
||||||
this.drawTexturedModalRect(this.xPosition + (int) (sliderValue * (float) (this.width - 8)) + 4, this.yPosition, 196, 66, 4, 20);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float convertScaleRet(float value) {
|
public static float convertScaleRet(float value) {
|
||||||
@@ -151,7 +146,7 @@ public class GuiReplaySpeedSlider extends GuiButton {
|
|||||||
float min = 0 - valueMin;
|
float min = 0 - valueMin;
|
||||||
float max = valueMax + min;
|
float max = valueMax + min;
|
||||||
|
|
||||||
return Math.round(value * (max) - min);
|
return Math.round(value * max - min);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) {
|
public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) {
|
||||||
|
|||||||
@@ -0,0 +1,125 @@
|
|||||||
|
package eu.crushedpixel.replaymod.gui.elements;
|
||||||
|
|
||||||
|
import eu.crushedpixel.replaymod.gui.GuiEditKeyframe;
|
||||||
|
import eu.crushedpixel.replaymod.holders.Keyframe;
|
||||||
|
import eu.crushedpixel.replaymod.holders.PositionKeyframe;
|
||||||
|
import eu.crushedpixel.replaymod.holders.TimeKeyframe;
|
||||||
|
import eu.crushedpixel.replaymod.replay.ReplayHandler;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
|
||||||
|
public class GuiKeyframeTimeline extends GuiTimeline {
|
||||||
|
private static final int KEYFRAME_PLACE_X = 74;
|
||||||
|
private static final int KEYFRAME_PLACE_Y = 20;
|
||||||
|
private static final int KEYFRAME_TIME_X = 74;
|
||||||
|
private static final int KEYFRAME_TIME_Y = 25;
|
||||||
|
|
||||||
|
private Keyframe clickedKeyFrame;
|
||||||
|
private long clickTime;
|
||||||
|
private boolean dragging;
|
||||||
|
|
||||||
|
public GuiKeyframeTimeline(int positionX, int positionY, int width) {
|
||||||
|
super(positionX, positionY, width);
|
||||||
|
showMarkers = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void mouseClicked(Minecraft mc, int mouseX, int mouseY) {
|
||||||
|
long time = getTimeAt(mouseX, mouseY);
|
||||||
|
if (time == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tolerance = (int) (2 * Math.round(zoom * timelineLength / width));
|
||||||
|
|
||||||
|
Keyframe closest;
|
||||||
|
if (mouseY >= positionY + BORDER_TOP + 5) {
|
||||||
|
closest = ReplayHandler.getClosestTimeKeyframeForRealTime((int) time, tolerance);
|
||||||
|
} else if (mouseY >= positionY + BORDER_TOP) {
|
||||||
|
closest = ReplayHandler.getClosestPlaceKeyframeForRealTime((int) time, tolerance);
|
||||||
|
} else {
|
||||||
|
closest = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReplayHandler.selectKeyframe(closest); //can be null, deselects keyframe
|
||||||
|
|
||||||
|
// If we clicked on a key frame, then continue monitoring the mouse for movements
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
if (closest != null) {
|
||||||
|
if (currentTime - clickTime < 500) { // if double clicked then open GUI instead
|
||||||
|
mc.displayGuiScreen(new GuiEditKeyframe(closest));
|
||||||
|
this.clickedKeyFrame = null;
|
||||||
|
} else {
|
||||||
|
this.clickedKeyFrame = closest;
|
||||||
|
this.dragging = false;
|
||||||
|
}
|
||||||
|
} else { // If we didn't then just update the cursor
|
||||||
|
ReplayHandler.setRealTimelineCursor((int) time);
|
||||||
|
this.dragging = true;
|
||||||
|
}
|
||||||
|
this.clickTime = currentTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void mouseDrag(int mouseX, int mouseY) {
|
||||||
|
long time = getTimeAt(mouseX, mouseY);
|
||||||
|
if (time != -1) {
|
||||||
|
if (clickedKeyFrame != null) {
|
||||||
|
int tolerance = (int) (2 * Math.round(zoom * timelineLength / width));
|
||||||
|
|
||||||
|
if (dragging || Math.abs(clickedKeyFrame.getRealTimestamp() - time) > tolerance) {
|
||||||
|
clickedKeyFrame.setRealTimestamp((int) time);
|
||||||
|
ReplayHandler.sortKeyframes();
|
||||||
|
dragging = true;
|
||||||
|
}
|
||||||
|
} else if (dragging) {
|
||||||
|
ReplayHandler.setRealTimelineCursor((int) time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void mouseRelease(int mouseX, int mouseY) {
|
||||||
|
mouseDrag(mouseX, mouseY);
|
||||||
|
clickedKeyFrame = null;
|
||||||
|
dragging = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(Minecraft mc, int mouseX, int mouseY) {
|
||||||
|
super.draw(mc, mouseX, mouseY);
|
||||||
|
|
||||||
|
int bodyWidth = width - BORDER_LEFT - BORDER_RIGHT;
|
||||||
|
|
||||||
|
long leftTime = Math.round(timeStart * timelineLength);
|
||||||
|
long rightTime = Math.round((timeStart + zoom) * timelineLength);
|
||||||
|
|
||||||
|
double segmentLength = timelineLength * zoom;
|
||||||
|
|
||||||
|
//Draw Keyframe logos
|
||||||
|
for(Keyframe kf : ReplayHandler.getKeyframes()) {
|
||||||
|
if (kf.getRealTimestamp() <= rightTime && kf.getRealTimestamp() >= leftTime) {
|
||||||
|
int textureX;
|
||||||
|
int textureY;
|
||||||
|
int y = positionY;
|
||||||
|
if (kf instanceof PositionKeyframe) {
|
||||||
|
textureX = KEYFRAME_PLACE_X;
|
||||||
|
textureY = KEYFRAME_PLACE_Y;
|
||||||
|
y += 0;
|
||||||
|
} else if (kf instanceof TimeKeyframe) {
|
||||||
|
textureX = KEYFRAME_TIME_X;
|
||||||
|
textureY = KEYFRAME_TIME_Y;
|
||||||
|
y += 5;
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedOperationException("Unknown keyframe type: " + kf.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ReplayHandler.isSelected(kf)) {
|
||||||
|
textureX += 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
long positionInSegment = kf.getRealTimestamp() - leftTime;
|
||||||
|
double fractionOfSegment = positionInSegment / segmentLength;
|
||||||
|
int x = (int) (positionX + BORDER_LEFT + fractionOfSegment * bodyWidth);
|
||||||
|
|
||||||
|
rect(x - 2, y + BORDER_TOP, textureX, textureY, 5, 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
package eu.crushedpixel.replaymod.gui.elements;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.Gui;
|
||||||
|
import net.minecraft.client.renderer.GlStateManager;
|
||||||
|
|
||||||
|
import static eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay.TEXTURE_SIZE;
|
||||||
|
import static eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay.replay_gui;
|
||||||
|
import static org.lwjgl.opengl.GL11.GL_BLEND;
|
||||||
|
import static org.lwjgl.opengl.GL11.glEnable;
|
||||||
|
|
||||||
|
public class GuiScrollbar extends Gui {
|
||||||
|
|
||||||
|
protected static final int BORDER_LEFT = 1;
|
||||||
|
protected static final int BORDER_RIGHT = 2;
|
||||||
|
protected static final int BORDER_TOP = 1;
|
||||||
|
|
||||||
|
protected static final int BACKGROUND_WIDTH = 64;
|
||||||
|
protected static final int BACKGROUND_HEIGHT = 9;
|
||||||
|
protected static final int BACKGROUND_BODY_WIDTH = BACKGROUND_WIDTH - BORDER_LEFT - BORDER_RIGHT;
|
||||||
|
protected static final int BACKGROUND_TEXTURE_X = 64;
|
||||||
|
protected static final int BACKGROUND_TEXTURE_Y = 97;
|
||||||
|
|
||||||
|
protected static final int SLIDER_WIDTH = 62;
|
||||||
|
protected static final int SLIDER_HEIGHT = 7;
|
||||||
|
protected static final int SLIDER_TEXTURE_X = 64;
|
||||||
|
protected static final int SLIDER_TEXTURE_Y = 90;
|
||||||
|
protected static final int SLIDER_BORDER_LEFT = 1;
|
||||||
|
protected static final int SLIDER_BORDER_RIGHT = 2;
|
||||||
|
protected static final int SLIDER_BODY_WIDTH = SLIDER_WIDTH - SLIDER_BORDER_LEFT - SLIDER_BORDER_RIGHT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current position of the left end of the slider. Must be between 0 and 1 - {@link #size} (inclusive).
|
||||||
|
*/
|
||||||
|
public double sliderPosition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size of the slider. Should be between 0 (exclusive) and 1 (inclusive)
|
||||||
|
*/
|
||||||
|
public double size = 1;
|
||||||
|
|
||||||
|
protected final int positionX;
|
||||||
|
protected final int positionY;
|
||||||
|
protected final int width;
|
||||||
|
|
||||||
|
private int draggingStart;
|
||||||
|
private double draggingStartPosition;
|
||||||
|
|
||||||
|
public GuiScrollbar(int positionX, int positionY, int width) {
|
||||||
|
this.positionX = positionX;
|
||||||
|
this.positionY = positionY;
|
||||||
|
this.width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getSliderOffsetX() {
|
||||||
|
return (int) Math.round((width - BORDER_LEFT - BORDER_RIGHT) * sliderPosition) + BORDER_LEFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean startDragging(int mouseX, int mouseY) {
|
||||||
|
int offsetX = getSliderOffsetX();
|
||||||
|
int minX = positionX + offsetX;
|
||||||
|
int maxX = positionX + offsetX + (int) (width * size);
|
||||||
|
int minY = positionY + BORDER_TOP;
|
||||||
|
int maxY = minY + SLIDER_HEIGHT;
|
||||||
|
if (mouseX >= minX && mouseY >= minY && mouseX < maxX && mouseY < maxY) {
|
||||||
|
draggingStart = mouseX;
|
||||||
|
draggingStartPosition = sliderPosition;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doDragging(int mouseX) {
|
||||||
|
if (draggingStart != -1) {
|
||||||
|
double delta = (double) (mouseX - draggingStart) / (width - BORDER_LEFT - BORDER_RIGHT);
|
||||||
|
sliderPosition = Math.max(0, Math.min(1 - size, draggingStartPosition + delta));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void endDragging(int mouseX) {
|
||||||
|
doDragging(mouseX);
|
||||||
|
draggingStart = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void draw(Minecraft mc) {
|
||||||
|
GlStateManager.resetColor();
|
||||||
|
mc.renderEngine.bindTexture(replay_gui);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
|
||||||
|
// Background
|
||||||
|
{
|
||||||
|
// We have to increase the border size as there is one pixel row which is part of the border while drawing
|
||||||
|
// but isn't during position calculations
|
||||||
|
int BORDER_LEFT = GuiScrollbar.BORDER_LEFT + 1;
|
||||||
|
int BACKGROUND_BODY_WIDTH = GuiScrollbar.BACKGROUND_BODY_WIDTH - 1;
|
||||||
|
|
||||||
|
int bodyLeft = positionX + BORDER_LEFT;
|
||||||
|
int bodyRight = positionX + width - BORDER_RIGHT;
|
||||||
|
|
||||||
|
// Left border
|
||||||
|
rect(positionX, positionY, BACKGROUND_TEXTURE_X, BACKGROUND_TEXTURE_Y, BORDER_LEFT, BACKGROUND_HEIGHT);
|
||||||
|
// Body
|
||||||
|
for (int i = bodyLeft; i < bodyRight; i += BACKGROUND_BODY_WIDTH) {
|
||||||
|
rect(i, positionY, BACKGROUND_TEXTURE_X + BORDER_LEFT, BACKGROUND_TEXTURE_Y,
|
||||||
|
Math.min(BACKGROUND_BODY_WIDTH, bodyRight - i), BACKGROUND_HEIGHT);
|
||||||
|
}
|
||||||
|
// Right border
|
||||||
|
rect(bodyRight, positionY, BACKGROUND_TEXTURE_X + BACKGROUND_WIDTH - BORDER_RIGHT,
|
||||||
|
BACKGROUND_TEXTURE_Y, BORDER_RIGHT, BACKGROUND_HEIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The slider itself
|
||||||
|
{
|
||||||
|
int positionX = this.positionX + getSliderOffsetX();
|
||||||
|
int positionY = this.positionY + BORDER_TOP;
|
||||||
|
|
||||||
|
int backgroundBodyWidth = width - BORDER_LEFT - BORDER_RIGHT;
|
||||||
|
int bodyLeft = positionX + SLIDER_BORDER_LEFT;
|
||||||
|
int bodyRight = positionX + (int) Math.round(backgroundBodyWidth * size) - SLIDER_BORDER_RIGHT;
|
||||||
|
|
||||||
|
// Left border
|
||||||
|
rect(positionX, positionY, SLIDER_TEXTURE_X, SLIDER_TEXTURE_Y, SLIDER_BORDER_LEFT, SLIDER_HEIGHT);
|
||||||
|
// Body
|
||||||
|
for (int i = bodyLeft; i < bodyRight; i += SLIDER_BODY_WIDTH) {
|
||||||
|
rect(i, positionY, SLIDER_TEXTURE_X + SLIDER_BORDER_LEFT, SLIDER_TEXTURE_Y,
|
||||||
|
Math.min(SLIDER_BODY_WIDTH, bodyRight - i), SLIDER_HEIGHT);
|
||||||
|
}
|
||||||
|
// Right border
|
||||||
|
rect(bodyRight, positionY, SLIDER_TEXTURE_X + SLIDER_WIDTH - SLIDER_BORDER_RIGHT,
|
||||||
|
SLIDER_TEXTURE_Y, SLIDER_BORDER_RIGHT, SLIDER_HEIGHT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void rect(int x, int y, int u, int v, int width, int height) {
|
||||||
|
GlStateManager.resetColor();
|
||||||
|
Minecraft.getMinecraft().renderEngine.bindTexture(replay_gui);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
|
||||||
|
drawModalRectWithCustomSizedTexture(x, y, u, v, width, height, TEXTURE_SIZE, TEXTURE_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package eu.crushedpixel.replaymod.gui.elements;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.Gui;
|
||||||
|
import net.minecraft.client.gui.GuiButton;
|
||||||
|
import net.minecraft.client.renderer.GlStateManager;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
|
||||||
|
public class GuiTexturedButton extends GuiButton {
|
||||||
|
private final ResourceLocation texture;
|
||||||
|
private final int u, v;
|
||||||
|
private final int textureWidth, textureHeight;
|
||||||
|
public GuiTexturedButton(int buttonId, int x, int y, int width, int height, ResourceLocation texture,
|
||||||
|
int u, int v, int textureWidth, int textureHeight) {
|
||||||
|
super(buttonId, x, y, width, height, "");
|
||||||
|
this.texture = texture;
|
||||||
|
this.u = u;
|
||||||
|
this.v = v;
|
||||||
|
this.textureWidth = textureWidth;
|
||||||
|
this.textureHeight = textureHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawButton(Minecraft mc, int mouseX, int mouseY) {
|
||||||
|
if (visible) {
|
||||||
|
hovered = mouseX >= xPosition
|
||||||
|
&& mouseY >= yPosition
|
||||||
|
&& mouseX < xPosition + width
|
||||||
|
&& mouseY < yPosition + height;
|
||||||
|
|
||||||
|
mc.renderEngine.bindTexture(texture);
|
||||||
|
|
||||||
|
GlStateManager.color(1, 1, 1);
|
||||||
|
int u = this.u + (hovered ? width : 0);
|
||||||
|
Gui.drawModalRectWithCustomSizedTexture(xPosition, yPosition, u, v, width, height, textureWidth, textureHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,194 @@
|
|||||||
|
package eu.crushedpixel.replaymod.gui.elements;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.Gui;
|
||||||
|
|
||||||
|
import static eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay.TEXTURE_SIZE;
|
||||||
|
import static eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay.replay_gui;
|
||||||
|
import static org.lwjgl.opengl.GL11.GL_BLEND;
|
||||||
|
import static org.lwjgl.opengl.GL11.glEnable;
|
||||||
|
|
||||||
|
public class GuiTimeline extends Gui {
|
||||||
|
|
||||||
|
protected static final int TEXTURE_WIDTH = 64;
|
||||||
|
protected static final int BORDER_TOP = 4;
|
||||||
|
protected static final int BORDER_BOTTOM = 3;
|
||||||
|
|
||||||
|
protected static final int HEIGHT = 22;
|
||||||
|
protected static final int TEXTURE_X = 64;
|
||||||
|
protected static final int TEXTURE_Y = 106;
|
||||||
|
|
||||||
|
protected static final int BORDER_LEFT = 4;
|
||||||
|
protected static final int BORDER_RIGHT = 4;
|
||||||
|
protected static final int BODY_WIDTH = TEXTURE_WIDTH - BORDER_LEFT - BORDER_RIGHT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current position of the cursor. Should normally be between 0 and {@link #timelineLength}.
|
||||||
|
*/
|
||||||
|
public int cursorPosition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total length of the timeline.
|
||||||
|
*/
|
||||||
|
public int timelineLength;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time at the left border of this timeline (fraction of the total length).
|
||||||
|
*/
|
||||||
|
public double timeStart;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zoom of this timeline. 1/10 allows the user to see 1/10 of the total length.
|
||||||
|
*/
|
||||||
|
public double zoom = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to draw markers on the timeline in regular time intervals.
|
||||||
|
* This draws the time at big markers above the timeline. Therefore extra space in negative y direction
|
||||||
|
* should be kept empty if markers are desired.
|
||||||
|
*/
|
||||||
|
public boolean showMarkers;
|
||||||
|
|
||||||
|
protected final int positionX;
|
||||||
|
protected final int positionY;
|
||||||
|
protected final int width;
|
||||||
|
|
||||||
|
public GuiTimeline(int positionX, int positionY, int width) {
|
||||||
|
this.positionX = positionX;
|
||||||
|
this.positionY = positionY;
|
||||||
|
this.width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the time which the mouse is at.
|
||||||
|
* @param mouseX X coordinate of the mouse
|
||||||
|
* @param mouseY Y coordinate of the mouse
|
||||||
|
* @return The time or -1 if the mouse isn't on the timeline
|
||||||
|
*/
|
||||||
|
public long getTimeAt(int mouseX, int mouseY) {
|
||||||
|
int left = positionX + BORDER_LEFT;
|
||||||
|
int right = positionX + width - BORDER_RIGHT;
|
||||||
|
int bodyWidth = width - BORDER_LEFT - BORDER_RIGHT;
|
||||||
|
if (mouseX >= left && mouseX <= right && mouseY >= positionY && mouseY <= positionY + HEIGHT) {
|
||||||
|
double segmentLength = timelineLength * zoom;
|
||||||
|
double segmentTime = segmentLength * (mouseX - left) / bodyWidth;
|
||||||
|
return Math.round(timeStart * timelineLength + segmentTime);
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void draw(Minecraft mc, int mouseX, int mouseY) {
|
||||||
|
int bodyLeft = positionX + BORDER_LEFT;
|
||||||
|
int bodyRight = positionX + width - BORDER_RIGHT;
|
||||||
|
int bodyWidth = width - BORDER_LEFT - BORDER_RIGHT;
|
||||||
|
|
||||||
|
{
|
||||||
|
// We have to increase the border size as there is one pixel row which is part of the border while drawing
|
||||||
|
// but isn't during position calculations
|
||||||
|
int BORDER_LEFT = GuiTimeline.BORDER_LEFT + 1;
|
||||||
|
int BODY_WIDTH = GuiTimeline.BODY_WIDTH - 1;
|
||||||
|
|
||||||
|
// Left border
|
||||||
|
rect(positionX, positionY, TEXTURE_X, TEXTURE_Y, BORDER_LEFT, HEIGHT);
|
||||||
|
// Body
|
||||||
|
for (int i = bodyLeft; i < bodyRight; i += BODY_WIDTH) {
|
||||||
|
rect(i, positionY, TEXTURE_X + BORDER_LEFT, TEXTURE_Y, Math.min(BODY_WIDTH, bodyRight - i), HEIGHT);
|
||||||
|
}
|
||||||
|
// Right border
|
||||||
|
rect(bodyRight, positionY, TEXTURE_X + BORDER_LEFT + BODY_WIDTH, TEXTURE_Y, BORDER_RIGHT, HEIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
long leftTime = Math.round(timeStart * timelineLength);
|
||||||
|
long rightTime = Math.round((timeStart + zoom) * timelineLength);
|
||||||
|
|
||||||
|
// Draw markers
|
||||||
|
if (showMarkers) {
|
||||||
|
int markerY = positionY + HEIGHT - BORDER_BOTTOM;
|
||||||
|
MarkerType mt = MarkerType.getMarkerType(zoom, timelineLength);
|
||||||
|
|
||||||
|
// Small markers
|
||||||
|
for (int s = 0; s <= timelineLength; s += mt.smallDistance) {
|
||||||
|
if (s <= rightTime && s >= leftTime) {
|
||||||
|
long positionInSegment = s - leftTime;
|
||||||
|
double fractionOfSegment = positionInSegment / (zoom * timelineLength);
|
||||||
|
int markerX = (int) (positionX + BORDER_LEFT + fractionOfSegment * bodyWidth);
|
||||||
|
|
||||||
|
drawVerticalLine(markerX, markerY - 3, markerY, 0xffffffff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Big markers
|
||||||
|
for (int s = 0; s <= timelineLength; s += mt.distance) {
|
||||||
|
if (s <= rightTime && s >= leftTime) {
|
||||||
|
long positionInSegment = s - leftTime;
|
||||||
|
double fractionOfSegment = positionInSegment / (zoom * timelineLength);
|
||||||
|
int markerX = (int) (positionX + BORDER_LEFT + fractionOfSegment * bodyWidth);
|
||||||
|
|
||||||
|
drawVerticalLine(markerX, markerY - 7, markerY, 0xffc0c0c0); // Light gray
|
||||||
|
|
||||||
|
// Write time above the timeline
|
||||||
|
long sec = Math.round(s / 1000.0);
|
||||||
|
String timestamp = String.format("%02d:%02ds", sec / 60, sec % 60);
|
||||||
|
drawCenteredString(mc.fontRendererObj, timestamp, markerX, positionY - 8, 0xffffffff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the cursor if it's on the current timeline segment
|
||||||
|
if (cursorPosition >= leftTime && cursorPosition <= rightTime) {
|
||||||
|
long positionInSegment = cursorPosition - leftTime;
|
||||||
|
double fractionOfSegment = positionInSegment / (zoom * timelineLength);
|
||||||
|
int cursorX = (int) (positionX + BORDER_LEFT + fractionOfSegment * bodyWidth);
|
||||||
|
|
||||||
|
rect(cursorX - 2, positionY + BORDER_TOP, 84, 20, 5, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw time under cursor if the mouse is on the timeline
|
||||||
|
long mouseTime = getTimeAt(mouseX, mouseY);
|
||||||
|
if (mouseTime != -1) {
|
||||||
|
long sec = mouseTime / 1000;
|
||||||
|
String timestamp = String.format("%02d:%02ds", sec / 60, sec % 60);
|
||||||
|
drawCenteredString(mc.fontRendererObj, timestamp, mouseX, mouseY + 5, 0xffffffff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void rect(int x, int y, int u, int v, int width, int height) {
|
||||||
|
Minecraft.getMinecraft().renderEngine.bindTexture(replay_gui);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
|
||||||
|
drawModalRectWithCustomSizedTexture(x, y, u, v, width, height, TEXTURE_SIZE, TEXTURE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private enum MarkerType {
|
||||||
|
|
||||||
|
ONE_S(1000, 100),
|
||||||
|
FIVE_S(5 * 1000, 1000),
|
||||||
|
QUARTER_M(15 * 1000, 3 * 1000),
|
||||||
|
HALF_M(30 * 1000, 5 * 1000),
|
||||||
|
ONE_M(60 * 1000, 10 * 1000),
|
||||||
|
FIVE_M(5 * 60 * 1000, 50 * 1000);
|
||||||
|
|
||||||
|
int distance;
|
||||||
|
int smallDistance;
|
||||||
|
int maximum = 10;
|
||||||
|
|
||||||
|
MarkerType(int minimum, int smallDistance) {
|
||||||
|
this.distance = minimum;
|
||||||
|
this.smallDistance = smallDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MarkerType getMarkerType(double scale, long totalLength) {
|
||||||
|
long seconds = Math.round(totalLength * scale);
|
||||||
|
|
||||||
|
for(MarkerType mt : values()) {
|
||||||
|
if(seconds / mt.distance <= 10) {
|
||||||
|
return mt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FIVE_M;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package eu.crushedpixel.replaymod.gui.overlay;
|
||||||
|
|
||||||
|
import eu.crushedpixel.replaymod.ReplayMod;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.FontRenderer;
|
||||||
|
import net.minecraft.client.gui.Gui;
|
||||||
|
import net.minecraft.client.renderer.GlStateManager;
|
||||||
|
import net.minecraft.client.resources.I18n;
|
||||||
|
import net.minecraftforge.client.event.RenderGameOverlayEvent;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders overlay during recording.
|
||||||
|
*/
|
||||||
|
public class GuiRecordingOverlay {
|
||||||
|
private final Minecraft mc;
|
||||||
|
|
||||||
|
public GuiRecordingOverlay(Minecraft mc) {
|
||||||
|
this.mc = mc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the recording icon and text in the top left corner of the screen.
|
||||||
|
* @param event Rendered post game overlay
|
||||||
|
*/
|
||||||
|
@SubscribeEvent
|
||||||
|
public void renderRecordingIndicator(RenderGameOverlayEvent.Post event) {
|
||||||
|
if(ReplayMod.replaySettings.showRecordingIndicator()) {
|
||||||
|
FontRenderer fontRenderer = mc.fontRendererObj;
|
||||||
|
fontRenderer.drawString(I18n.format("replaymod.gui.recording").toUpperCase(), 30, 18 - (fontRenderer.FONT_HEIGHT / 2), 0xffffffff);
|
||||||
|
mc.renderEngine.bindTexture(GuiReplayOverlay.replay_gui);
|
||||||
|
GlStateManager.resetColor();
|
||||||
|
GlStateManager.enableAlpha();
|
||||||
|
Gui.drawModalRectWithCustomSizedTexture(10, 10, 40, 21, 16, 16, 64, 64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
411
src/main/java/eu/crushedpixel/replaymod/gui/overlay/GuiReplayOverlay.java
Executable file
411
src/main/java/eu/crushedpixel/replaymod/gui/overlay/GuiReplayOverlay.java
Executable file
@@ -0,0 +1,411 @@
|
|||||||
|
package eu.crushedpixel.replaymod.gui.overlay;
|
||||||
|
|
||||||
|
import eu.crushedpixel.replaymod.ReplayMod;
|
||||||
|
import eu.crushedpixel.replaymod.entities.CameraEntity;
|
||||||
|
import eu.crushedpixel.replaymod.gui.GuiMouseInput;
|
||||||
|
import eu.crushedpixel.replaymod.gui.GuiRenderSettings;
|
||||||
|
import eu.crushedpixel.replaymod.gui.GuiReplaySpeedSlider;
|
||||||
|
import eu.crushedpixel.replaymod.gui.elements.GuiKeyframeTimeline;
|
||||||
|
import eu.crushedpixel.replaymod.gui.elements.GuiScrollbar;
|
||||||
|
import eu.crushedpixel.replaymod.gui.elements.GuiTexturedButton;
|
||||||
|
import eu.crushedpixel.replaymod.gui.elements.GuiTimeline;
|
||||||
|
import eu.crushedpixel.replaymod.holders.Keyframe;
|
||||||
|
import eu.crushedpixel.replaymod.holders.Position;
|
||||||
|
import eu.crushedpixel.replaymod.holders.PositionKeyframe;
|
||||||
|
import eu.crushedpixel.replaymod.holders.TimeKeyframe;
|
||||||
|
import eu.crushedpixel.replaymod.registry.ReplayGuiRegistry;
|
||||||
|
import eu.crushedpixel.replaymod.replay.ReplayHandler;
|
||||||
|
import eu.crushedpixel.replaymod.utils.MouseUtils;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.Gui;
|
||||||
|
import net.minecraft.client.gui.GuiButton;
|
||||||
|
import net.minecraft.client.gui.GuiChat;
|
||||||
|
import net.minecraft.client.gui.GuiScreen;
|
||||||
|
import net.minecraft.client.gui.inventory.GuiInventory;
|
||||||
|
import net.minecraft.client.renderer.GlStateManager;
|
||||||
|
import net.minecraft.client.resources.I18n;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
import net.minecraftforge.client.event.RenderGameOverlayEvent;
|
||||||
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
|
import net.minecraftforge.fml.client.FMLClientHandler;
|
||||||
|
import net.minecraftforge.fml.common.FMLCommonHandler;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||||
|
import org.lwjgl.input.Mouse;
|
||||||
|
import org.lwjgl.opengl.Display;
|
||||||
|
import org.lwjgl.util.Point;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static net.minecraft.client.renderer.GlStateManager.*;
|
||||||
|
import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
|
||||||
|
import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT;
|
||||||
|
|
||||||
|
public class GuiReplayOverlay extends Gui {
|
||||||
|
private static final Minecraft mc = Minecraft.getMinecraft();
|
||||||
|
public static final ResourceLocation replay_gui = new ResourceLocation("replaymod", "replay_gui.png");
|
||||||
|
public static final int TEXTURE_SIZE = 128;
|
||||||
|
private static final float ZOOM_STEPS = 0.05f;
|
||||||
|
|
||||||
|
private static GuiTexturedButton texturedButton(int x, int y, int u, int v, int size) {
|
||||||
|
return new GuiTexturedButton(0, x, y, size, size, replay_gui, u, v, TEXTURE_SIZE, TEXTURE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final int displayWidth = mc.displayWidth;
|
||||||
|
private final int displayHeight = mc.displayHeight;
|
||||||
|
|
||||||
|
private final Point screenDimensions = MouseUtils.getScaledDimensions();
|
||||||
|
private final int WIDTH = screenDimensions.getX();
|
||||||
|
private final int HEIGHT = screenDimensions.getY();
|
||||||
|
|
||||||
|
// Top row
|
||||||
|
private final int TOP_ROW = 10;
|
||||||
|
private final int BUTTON_PLAY_PAUSE_X = 10;
|
||||||
|
private final int SPEED_X = 35;
|
||||||
|
private final int SPEED_WIDTH = 100;
|
||||||
|
private final int TIMELINE_X = SPEED_X + SPEED_WIDTH + 5;
|
||||||
|
|
||||||
|
// Bottom row
|
||||||
|
private final int BOTTOM_ROW = TOP_ROW + 33;
|
||||||
|
private final int BUTTON_PLAY_PATH_X = 10;
|
||||||
|
private final int BUTTON_EXPORT_X = BUTTON_PLAY_PATH_X + 25;
|
||||||
|
private final int BUTTON_PLACE_X = BUTTON_EXPORT_X + 25;
|
||||||
|
private final int BUTTON_TIME_X = BUTTON_PLACE_X + 25;
|
||||||
|
private final int TIMELINE_REAL_X = BUTTON_TIME_X + 25;
|
||||||
|
private final int TIMELINE_REAL_WIDTH = WIDTH - 14 - 11 - TIMELINE_REAL_X;
|
||||||
|
|
||||||
|
private final GuiButton buttonPlay = texturedButton(BUTTON_PLAY_PAUSE_X, TOP_ROW, 0, 0, 20);
|
||||||
|
private final GuiButton buttonPause = texturedButton(BUTTON_PLAY_PAUSE_X, TOP_ROW, 0, 20, 20);
|
||||||
|
private final GuiButton buttonExport = texturedButton(BUTTON_EXPORT_X, BOTTOM_ROW, 40, 0, 20);
|
||||||
|
private final GuiButton buttonPlayPath = texturedButton(BUTTON_PLAY_PATH_X, BOTTOM_ROW, 0, 0, 20);
|
||||||
|
private final GuiButton buttonPlace = texturedButton(BUTTON_PLACE_X, BOTTOM_ROW, 0, 40, 20);
|
||||||
|
private final GuiButton buttonPlaceSelected = texturedButton(BUTTON_PLACE_X, BOTTOM_ROW, 0, 60, 20);
|
||||||
|
private final GuiButton buttonTime = texturedButton(BUTTON_TIME_X, BOTTOM_ROW, 0, 80, 20);
|
||||||
|
private final GuiButton buttonTimeSelected = texturedButton(BUTTON_TIME_X, BOTTOM_ROW, 0, 100, 20);
|
||||||
|
private final GuiButton buttonZoomIn = texturedButton(WIDTH - 14 - 9, BOTTOM_ROW, 40, 20, 9);
|
||||||
|
private final GuiButton buttonZoomOut = texturedButton(WIDTH - 14 - 9, BOTTOM_ROW + 11, 40, 30, 9);
|
||||||
|
|
||||||
|
private final GuiTimeline timeline = new GuiTimeline(TIMELINE_X, TOP_ROW - 1, WIDTH - 14 - TIMELINE_X);
|
||||||
|
private final GuiKeyframeTimeline timelineReal = new GuiKeyframeTimeline(TIMELINE_REAL_X, BOTTOM_ROW - 1, TIMELINE_REAL_WIDTH);
|
||||||
|
{
|
||||||
|
timelineReal.timelineLength = 10 * 60 * 1000;
|
||||||
|
}
|
||||||
|
private final GuiScrollbar scrollbar = new GuiScrollbar(TIMELINE_REAL_X, BOTTOM_ROW + 22, TIMELINE_REAL_WIDTH);
|
||||||
|
|
||||||
|
private GuiReplaySpeedSlider speedSlider = new GuiReplaySpeedSlider(1, SPEED_X, TOP_ROW, I18n.format("replaymod.gui.speed"));
|
||||||
|
|
||||||
|
private float zoom_scale = 0.1f; //can see 1/10th of the timeline
|
||||||
|
private double pos_left = 0f; //left border of timeline is at 0%
|
||||||
|
|
||||||
|
public boolean isVisible() {
|
||||||
|
return ReplayHandler.isInReplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the UI.
|
||||||
|
* @param slider {@code true} if the speed-slider should be reset as well
|
||||||
|
*/
|
||||||
|
public void resetUI(boolean slider) {
|
||||||
|
if(FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class)) {
|
||||||
|
mc.displayGuiScreen(null);
|
||||||
|
}
|
||||||
|
ReplayHandler.setRealTimelineCursor(0);
|
||||||
|
if(slider)
|
||||||
|
speedSlider = new GuiReplaySpeedSlider(1, SPEED_X, TOP_ROW, I18n.format("replaymod.gui.speed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void register() {
|
||||||
|
FMLCommonHandler.instance().bus().register(this);
|
||||||
|
MinecraftForge.EVENT_BUS.register(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unregister() {
|
||||||
|
FMLCommonHandler.instance().bus().unregister(this);
|
||||||
|
MinecraftForge.EVENT_BUS.unregister(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkResize() {
|
||||||
|
if (displayWidth != mc.displayWidth || displayHeight != mc.displayHeight) {
|
||||||
|
GuiReplayOverlay other = new GuiReplayOverlay();
|
||||||
|
other.zoom_scale = this.zoom_scale;
|
||||||
|
other.pos_left = this.pos_left;
|
||||||
|
other.speedSlider = this.speedSlider;
|
||||||
|
|
||||||
|
this.unregister();
|
||||||
|
other.register();
|
||||||
|
ReplayMod.overlay = other;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onRenderTabList(RenderGameOverlayEvent.Pre event) { //cancelling tab list rendering and rendering help instead
|
||||||
|
if (!isVisible()) return;
|
||||||
|
if (event.type == RenderGameOverlayEvent.ElementType.PLAYER_LIST) {
|
||||||
|
event.setCanceled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tick() {
|
||||||
|
if (mc.inGameHasFocus) { // TODO Check if this is necessary
|
||||||
|
Point scaled = MouseUtils.getScaledDimensions();
|
||||||
|
Mouse.setCursorPosition(scaled.getX() / 2, scaled.getY() / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class)) {
|
||||||
|
Entity player = ReplayHandler.getCameraEntity();
|
||||||
|
if(player != null) {
|
||||||
|
player.setVelocity(0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkResize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void mouseDrag(int mouseX, int mouseY) {
|
||||||
|
speedSlider.mousePressed(mc, mouseX, mouseY);
|
||||||
|
|
||||||
|
scrollbar.doDragging(mouseX);
|
||||||
|
pos_left = scrollbar.sliderPosition;
|
||||||
|
|
||||||
|
timelineReal.mouseDrag(mouseX, mouseY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void mouseReleased(int mouseX, int mouseY) {
|
||||||
|
speedSlider.mouseReleased(mouseX, mouseY);
|
||||||
|
|
||||||
|
scrollbar.endDragging(mouseX);
|
||||||
|
pos_left = scrollbar.sliderPosition;
|
||||||
|
|
||||||
|
timelineReal.mouseRelease(mouseX, mouseY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void mouseClicked(int mouseX, int mouseY) {
|
||||||
|
if (buttonPlayPath.mousePressed(mc, mouseX, mouseY)) {
|
||||||
|
if (ReplayHandler.isInPath()) {
|
||||||
|
ReplayHandler.interruptReplay();
|
||||||
|
} else {
|
||||||
|
ReplayHandler.startPath(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ReplayHandler.isInPath()) {
|
||||||
|
return; // Only allow clicking of cancel button during path replay
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ReplayMod.replaySender.paused()) {
|
||||||
|
if (buttonPlay.mousePressed(mc, mouseX, mouseY)) {
|
||||||
|
ReplayMod.replaySender.setReplaySpeed(speedSlider.getSliderValue());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (buttonPause.mousePressed(mc, mouseX, mouseY)) {
|
||||||
|
ReplayMod.replaySender.setReplaySpeed(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
speedSlider.mousePressed(mc, mouseX, mouseY);
|
||||||
|
scrollbar.startDragging(mouseX, mouseY);
|
||||||
|
timelineReal.mouseClicked(mc, mouseX, mouseY);
|
||||||
|
|
||||||
|
if (buttonExport.mousePressed(mc, mouseX, mouseY)) {
|
||||||
|
mc.displayGuiScreen(new GuiRenderSettings());
|
||||||
|
}
|
||||||
|
|
||||||
|
Keyframe keyframe = ReplayHandler.getSelectedKeyframe();
|
||||||
|
|
||||||
|
if (buttonPlace.mousePressed(mc, mouseX, mouseY)) {
|
||||||
|
if (keyframe instanceof PositionKeyframe) {
|
||||||
|
ReplayHandler.removeKeyframe(keyframe);
|
||||||
|
} else {
|
||||||
|
Entity cam = mc.getRenderViewEntity();
|
||||||
|
if(cam != null) {
|
||||||
|
Position position = new Position(cam.posX, cam.posY, cam.posZ, cam.rotationPitch,
|
||||||
|
cam.rotationYaw % 360, ReplayHandler.getCameraTilt());
|
||||||
|
ReplayHandler.addKeyframe(new PositionKeyframe(ReplayHandler.getRealTimelineCursor(), position));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buttonTime.mousePressed(mc, mouseX, mouseY)) {
|
||||||
|
if (keyframe instanceof TimeKeyframe) {
|
||||||
|
ReplayHandler.removeKeyframe(keyframe);
|
||||||
|
} else {
|
||||||
|
ReplayHandler.addKeyframe(new TimeKeyframe(ReplayHandler.getRealTimelineCursor(), ReplayMod.replaySender.currentTimeStamp()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buttonZoomIn.mousePressed(mc, mouseX, mouseY)) {
|
||||||
|
zoom_scale = Math.max(0.025f, zoom_scale - ZOOM_STEPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buttonZoomOut.mousePressed(mc, mouseX, mouseY)) {
|
||||||
|
zoom_scale = Math.min(1f, zoom_scale + ZOOM_STEPS);
|
||||||
|
pos_left = Math.min(pos_left, 1f - zoom_scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
long timelineTime = timeline.getTimeAt(mouseX, mouseY);
|
||||||
|
if (timelineTime != -1) { // Click on timeline
|
||||||
|
//When hurrying, no Timeline jumping etc. is possible
|
||||||
|
if(!ReplayMod.replaySender.isHurrying()) {
|
||||||
|
if(timelineTime < ReplayMod.replaySender.currentTimeStamp()) {
|
||||||
|
mc.displayGuiScreen(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
CameraEntity cam = ReplayHandler.getCameraEntity();
|
||||||
|
if(cam != null) {
|
||||||
|
ReplayHandler.setLastPosition(new Position(cam.posX, cam.posY, cam.posZ, cam.rotationPitch, cam.rotationYaw));
|
||||||
|
} else {
|
||||||
|
ReplayHandler.setLastPosition(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
long diff = timelineTime - ReplayMod.replaySender.getDesiredTimestamp();
|
||||||
|
if(diff != 0) {
|
||||||
|
if (diff > 0 && diff < 5000) { // Small difference and no time travel
|
||||||
|
ReplayMod.replaySender.jumpToTime((int) timelineTime);
|
||||||
|
} else { // We either have to restart the replay or send a significant amount of packets
|
||||||
|
// Render our please-wait-screen
|
||||||
|
GuiScreen guiScreen = new GuiScreen() {
|
||||||
|
@Override
|
||||||
|
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
|
||||||
|
drawBackground(0);
|
||||||
|
drawCenteredString(fontRendererObj, I18n.format("replaymod.gui.pleasewait"),
|
||||||
|
width / 2, height / 2, 0xffffffff);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Make sure that the replaysender changes into sync mode
|
||||||
|
ReplayMod.replaySender.setSyncModeAndWait();
|
||||||
|
|
||||||
|
// Perform the rendering using OpenGL
|
||||||
|
pushMatrix();
|
||||||
|
clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
enableTexture2D();
|
||||||
|
mc.getFramebuffer().bindFramebuffer(true);
|
||||||
|
mc.entityRenderer.setupOverlayRendering();
|
||||||
|
|
||||||
|
guiScreen.setWorldAndResolution(mc, WIDTH, HEIGHT);
|
||||||
|
guiScreen.drawScreen(0, 0, 0);
|
||||||
|
|
||||||
|
mc.getFramebuffer().unbindFramebuffer();
|
||||||
|
popMatrix();
|
||||||
|
pushMatrix();
|
||||||
|
mc.getFramebuffer().framebufferRender(mc.displayWidth, mc.displayHeight);
|
||||||
|
popMatrix();
|
||||||
|
|
||||||
|
Display.update();
|
||||||
|
|
||||||
|
// Send the packets
|
||||||
|
ReplayMod.replaySender.sendPacketsTill((int) timelineTime);
|
||||||
|
ReplayMod.replaySender.setAsyncMode(true);
|
||||||
|
ReplayMod.replaySender.setReplaySpeed(0);
|
||||||
|
|
||||||
|
// Tick twice to process all packets and position interpolation
|
||||||
|
try {
|
||||||
|
mc.runTick();
|
||||||
|
mc.runTick();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace(); // This should never be thrown but whatever
|
||||||
|
}
|
||||||
|
|
||||||
|
// No need to remove our please-wait-screen. It'll vanish with the next
|
||||||
|
// render pass as it's never been a real GuiScreen in the first place.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onRenderGui(RenderGameOverlayEvent.Post event) throws IllegalArgumentException, IllegalAccessException {
|
||||||
|
if (!isVisible()) return;
|
||||||
|
|
||||||
|
FMLClientHandler fml = FMLClientHandler.instance();
|
||||||
|
|
||||||
|
tick();
|
||||||
|
|
||||||
|
// Do not draw if GUI doesn't want us to
|
||||||
|
if(mc.currentScreen instanceof NoOverlay) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are not currently spectating someone
|
||||||
|
if (ReplayHandler.isCamera()) {
|
||||||
|
ReplayGuiRegistry.hide(); // hide all normal UI
|
||||||
|
} else {
|
||||||
|
ReplayGuiRegistry.show(); // otherwise show them
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace chat and inventory GUI (opened by pressing the respective hotkey) with a dummy input GUI
|
||||||
|
if(fml.isGUIOpen(GuiChat.class) || fml.isGUIOpen(GuiInventory.class)) {
|
||||||
|
mc.displayGuiScreen(new GuiMouseInput(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
GlStateManager.resetColor();
|
||||||
|
|
||||||
|
Keyframe keyframe = ReplayHandler.getSelectedKeyframe();
|
||||||
|
|
||||||
|
Point mousePoint = MouseUtils.getMousePos();
|
||||||
|
int mouseX = mousePoint.getX();
|
||||||
|
int mouseY = mousePoint.getY();
|
||||||
|
|
||||||
|
if (!(mc.currentScreen instanceof GuiMouseInput)) {
|
||||||
|
// We only react to the mouse if our gui screen is opened.
|
||||||
|
// Otherwise we just move the mouse away so it doesn't activate any buttons
|
||||||
|
mouseX = mouseY = -1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw speed slider
|
||||||
|
speedSlider.drawButton(mc, mouseX, mouseY);
|
||||||
|
|
||||||
|
// Draw buttons
|
||||||
|
buttonExport.drawButton(mc, mouseX, mouseY);
|
||||||
|
|
||||||
|
// Draw play/pause button
|
||||||
|
if (ReplayMod.replaySender.paused()) {
|
||||||
|
buttonPlay.drawButton(mc, mouseX, mouseY);
|
||||||
|
} else {
|
||||||
|
buttonPause.drawButton(mc, mouseX, mouseY);
|
||||||
|
}
|
||||||
|
|
||||||
|
buttonPlayPath.drawButton(mc, mouseX, mouseY);
|
||||||
|
|
||||||
|
// Keyframe buttons
|
||||||
|
if (keyframe instanceof PositionKeyframe) {
|
||||||
|
buttonPlaceSelected.drawButton(mc, mouseX, mouseY);
|
||||||
|
} else {
|
||||||
|
buttonPlace.drawButton(mc, mouseX, mouseY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyframe instanceof TimeKeyframe) {
|
||||||
|
buttonTimeSelected.drawButton(mc, mouseX, mouseY);
|
||||||
|
} else {
|
||||||
|
buttonTime.drawButton(mc, mouseX, mouseY);
|
||||||
|
}
|
||||||
|
|
||||||
|
buttonZoomIn.drawButton(mc, mouseX, mouseY);
|
||||||
|
buttonZoomOut.drawButton(mc, mouseX, mouseY);
|
||||||
|
|
||||||
|
// Draw scrollbar for real timeline
|
||||||
|
scrollbar.size = zoom_scale;
|
||||||
|
scrollbar.sliderPosition = pos_left;
|
||||||
|
scrollbar.draw(mc);
|
||||||
|
|
||||||
|
// Finally draw timelines so that no other GUI elements overlap the mouse-position strings
|
||||||
|
timeline.cursorPosition = ReplayMod.replaySender.currentTimeStamp();
|
||||||
|
timeline.timelineLength = ReplayMod.replaySender.replayLength();
|
||||||
|
timeline.draw(mc, mouseX, mouseY);
|
||||||
|
|
||||||
|
timelineReal.cursorPosition = ReplayHandler.getRealTimelineCursor();
|
||||||
|
timelineReal.zoom = zoom_scale;
|
||||||
|
timelineReal.timeStart = pos_left;
|
||||||
|
timelineReal.draw(mc, mouseX, mouseY);
|
||||||
|
|
||||||
|
GlStateManager.enableBlend();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dummy interface for GUI on which this replay overlay shall not be rendered.
|
||||||
|
*/
|
||||||
|
public static interface NoOverlay {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,6 +24,7 @@ import net.minecraft.util.Util;
|
|||||||
import org.apache.commons.io.FilenameUtils;
|
import org.apache.commons.io.FilenameUtils;
|
||||||
import org.lwjgl.Sys;
|
import org.lwjgl.Sys;
|
||||||
import org.lwjgl.input.Keyboard;
|
import org.lwjgl.input.Keyboard;
|
||||||
|
import org.lwjgl.util.Point;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
|||||||
@@ -2,14 +2,17 @@ package eu.crushedpixel.replaymod.recording;
|
|||||||
|
|
||||||
import eu.crushedpixel.replaymod.ReplayMod;
|
import eu.crushedpixel.replaymod.ReplayMod;
|
||||||
import eu.crushedpixel.replaymod.chat.ChatMessageHandler.ChatMessageType;
|
import eu.crushedpixel.replaymod.chat.ChatMessageHandler.ChatMessageType;
|
||||||
|
import eu.crushedpixel.replaymod.gui.overlay.GuiRecordingOverlay;
|
||||||
import eu.crushedpixel.replaymod.utils.ReplayFile;
|
import eu.crushedpixel.replaymod.utils.ReplayFile;
|
||||||
import eu.crushedpixel.replaymod.utils.ReplayFileIO;
|
import eu.crushedpixel.replaymod.utils.ReplayFileIO;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.channel.ChannelHandler;
|
import io.netty.channel.ChannelHandler;
|
||||||
import io.netty.channel.ChannelPipeline;
|
import io.netty.channel.ChannelPipeline;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.network.NetworkManager;
|
import net.minecraft.network.NetworkManager;
|
||||||
import net.minecraft.network.Packet;
|
import net.minecraft.network.Packet;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||||
import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientConnectedToServerEvent;
|
import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientConnectedToServerEvent;
|
||||||
import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientDisconnectionFromServerEvent;
|
import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientDisconnectionFromServerEvent;
|
||||||
@@ -33,6 +36,7 @@ public class ConnectionEventHandler {
|
|||||||
private static final SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
|
private static final SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
|
||||||
private static PacketListener packetListener = null;
|
private static PacketListener packetListener = null;
|
||||||
private static boolean isRecording = false;
|
private static boolean isRecording = false;
|
||||||
|
private final GuiRecordingOverlay guiOverlay = new GuiRecordingOverlay(Minecraft.getMinecraft());
|
||||||
private File currentFile;
|
private File currentFile;
|
||||||
private String fileName;
|
private String fileName;
|
||||||
|
|
||||||
@@ -101,6 +105,8 @@ public class ConnectionEventHandler {
|
|||||||
ReplayMod.chatMessageHandler.addLocalizedChatMessage("replaymod.chat.recordingstarted", ChatMessageType.INFORMATION);
|
ReplayMod.chatMessageHandler.addLocalizedChatMessage("replaymod.chat.recordingstarted", ChatMessageType.INFORMATION);
|
||||||
isRecording = true;
|
isRecording = true;
|
||||||
|
|
||||||
|
MinecraftForge.EVENT_BUS.register(guiOverlay);
|
||||||
|
|
||||||
final PacketListener listener = insert;
|
final PacketListener listener = insert;
|
||||||
|
|
||||||
if(insert != null && event.isLocal) {
|
if(insert != null && event.isLocal) {
|
||||||
@@ -139,6 +145,7 @@ public class ConnectionEventHandler {
|
|||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public void onDisconnectedFromServerEvent(ClientDisconnectionFromServerEvent event) {
|
public void onDisconnectedFromServerEvent(ClientDisconnectionFromServerEvent event) {
|
||||||
isRecording = false;
|
isRecording = false;
|
||||||
|
MinecraftForge.EVENT_BUS.unregister(guiOverlay);
|
||||||
packetListener = null;
|
packetListener = null;
|
||||||
ReplayMod.chatMessageHandler.stop();
|
ReplayMod.chatMessageHandler.stop();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,6 +176,20 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether this replay sender to operate in sync mode.
|
||||||
|
* When in sync mode, it will send packets when {@link #sendPacketsTill(int)} is called.
|
||||||
|
* This call will block until the async worker thread has stopped.
|
||||||
|
*/
|
||||||
|
public void setSyncModeAndWait() {
|
||||||
|
if (!this.asyncMode) return;
|
||||||
|
this.asyncMode = false;
|
||||||
|
this.terminate = true;
|
||||||
|
synchronized (this) {
|
||||||
|
// This will wait for the worker thread to leave the synchronized code part
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the timestamp of the last packet sent.
|
* Return the timestamp of the last packet sent.
|
||||||
* @return The timestamp in milliseconds since the start of the replay
|
* @return The timestamp in milliseconds since the start of the replay
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ package eu.crushedpixel.replaymod.utils;
|
|||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.ScaledResolution;
|
import net.minecraft.client.gui.ScaledResolution;
|
||||||
import org.lwjgl.input.Mouse;
|
import org.lwjgl.input.Mouse;
|
||||||
|
import org.lwjgl.util.Point;
|
||||||
import java.awt.*;
|
|
||||||
|
|
||||||
public class MouseUtils {
|
public class MouseUtils {
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.9 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 6.1 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.2 KiB |
Reference in New Issue
Block a user