diff --git a/common/src/main/java/io/github/kurrycat/mpkmod/Main.java b/common/src/main/java/io/github/kurrycat/mpkmod/Main.java index 76b1ba4..ca515dd 100644 --- a/common/src/main/java/io/github/kurrycat/mpkmod/Main.java +++ b/common/src/main/java/io/github/kurrycat/mpkmod/Main.java @@ -7,6 +7,7 @@ import io.github.kurrycat.mpkmod.events.*; import io.github.kurrycat.mpkmod.gui.TickThread; import io.github.kurrycat.mpkmod.gui.components.Component; +import io.github.kurrycat.mpkmod.gui.components.InputHistory; import io.github.kurrycat.mpkmod.gui.infovars.InfoString; import io.github.kurrycat.mpkmod.gui.infovars.InfoTree; import io.github.kurrycat.mpkmod.gui.screens.LandingBlockGuiScreen; @@ -125,7 +126,7 @@ public void loaded() { EventAPI.EventListener.onRenderOverlay( e -> { if (!displayOverlay) return; - if(Minecraft.isF3Enabled()) return; + if (Minecraft.isF3Enabled()) return; Profiler.startSection("components"); if (mainGUI != null) { @@ -179,6 +180,12 @@ public void loaded() { ); }); Profiler.endSection(); + Profiler.startSection("tickInputHistories"); + for (Component component : mainGUI.movableComponents) { + if (!(component instanceof InputHistory)) continue; + ((InputHistory) component).onTick(); + } + Profiler.endSection(); } ) ); diff --git a/common/src/main/java/io/github/kurrycat/mpkmod/compatibility/MCClasses/FontRenderer.java b/common/src/main/java/io/github/kurrycat/mpkmod/compatibility/MCClasses/FontRenderer.java index 2a64528..2a91315 100644 --- a/common/src/main/java/io/github/kurrycat/mpkmod/compatibility/MCClasses/FontRenderer.java +++ b/common/src/main/java/io/github/kurrycat/mpkmod/compatibility/MCClasses/FontRenderer.java @@ -24,6 +24,10 @@ public static void drawCenteredString(String text, Vector2D pos, Color color, bo drawString(text, pos.sub(getStringSize(text).div(2)), color, shadow); } + public static void drawCenteredMonospaceString(String text, Vector2D pos, Color color, boolean shadow) { + drawMonospaceString(text, pos.sub(getStringSize(text).div(2)), color, shadow); + } + /** * Draws one line of text to the screen with the {@link FontRenderer#DEFAULT_FONT_SIZE default font size} * @@ -36,6 +40,10 @@ public static void drawString(String text, Vector2D pos, Color color, boolean sh drawString(text, pos, color, DEFAULT_FONT_SIZE, shadow); } + public static void drawMonospaceString(String text, Vector2D pos, Color color, boolean shadow) { + drawMonospaceString(text, pos, color, DEFAULT_FONT_SIZE, shadow); + } + /** * @param text A single line String * @return The size of the text when rendered using {@link #drawString(String, Vector2D, Color, boolean)} as a {@link Vector2D} containing the width and the height @@ -57,6 +65,10 @@ public static void drawString(String text, Vector2D pos, Color color, double fon drawString(text, pos.getX(), pos.getY(), color, fontSize, shadow); } + public static void drawMonospaceString(String text, Vector2D pos, Color color, double fontSize, boolean shadow) { + drawMonospaceString(text, pos.getX(), pos.getY(), color, fontSize, shadow); + } + public static Vector2D getStringSize(String text, double fontSize) { return Interface.get().map(f -> f.getStringSize(text, fontSize)).orElse(Vector2D.ZERO.copy()); } @@ -67,6 +79,17 @@ public static void drawString(String text, double x, double y, Color color, doub x, y, color, fontSize, shadow)); } + public static void drawMonospaceString(String text, double x, double y, Color color, double fontSize, boolean shadow) { + for (int i = 0; i < text.length(); i++) { + int finalI = i; + Interface.get().ifPresent(f -> { + if (text.charAt(finalI) == ' ') return; + f.drawString(Colors.RESET.getCode() + text.charAt(finalI), + x + finalI * fontSize * 6d / 9d, y, color, fontSize, shadow); + }); + } + } + public static void drawCenteredString(String text, ComponentHolder parent, Color color, boolean shadow) { drawCenteredString(text, parent, color, DEFAULT_FONT_SIZE, shadow); } @@ -119,6 +142,9 @@ public static void drawRightCenteredString(String text, Vector2D pos, Color colo public static void drawLeftCenteredString(String text, Vector2D pos, Color color, boolean shadow) { drawString(text, pos.sub(0, getStringSize(text).getY() / 2), color, shadow); } + public static void drawLeftCenteredMonospaceString(String text, Vector2D pos, Color color, boolean shadow) { + drawMonospaceString(text, pos.sub(0, getStringSize(text).getY() / 2), color, shadow); + } public interface Interface extends FunctionHolder { static Optional get() { diff --git a/common/src/main/java/io/github/kurrycat/mpkmod/compatibility/MCClasses/Player.java b/common/src/main/java/io/github/kurrycat/mpkmod/compatibility/MCClasses/Player.java index 892409a..f352afd 100644 --- a/common/src/main/java/io/github/kurrycat/mpkmod/compatibility/MCClasses/Player.java +++ b/common/src/main/java/io/github/kurrycat/mpkmod/compatibility/MCClasses/Player.java @@ -453,6 +453,15 @@ public String toString() { return "{W:" + forward + ", A:" + left + ", S:" + back + ", D:" + right + ", N:" + sneak + ", P:" + sprint + ", J:" + jump + "}"; } + public Vector2D getMovementVector() { + Vector2D vector2D = Vector2D.ZERO; + if(this.forward) vector2D = vector2D.add(1, 0); + if(this.back) vector2D = vector2D.add(-1, 0); + if(this.left) vector2D = vector2D.add(0, -1); + if(this.right) vector2D = vector2D.add(0, 1); + return vector2D; + } + public boolean isMovingSideways() { return left ^ right; } diff --git a/common/src/main/java/io/github/kurrycat/mpkmod/gui/ComponentScreen.java b/common/src/main/java/io/github/kurrycat/mpkmod/gui/ComponentScreen.java index 1def6f8..97f097f 100644 --- a/common/src/main/java/io/github/kurrycat/mpkmod/gui/ComponentScreen.java +++ b/common/src/main/java/io/github/kurrycat/mpkmod/gui/ComponentScreen.java @@ -176,6 +176,14 @@ public void onMouseClicked(Vector2D mouse, int mouseButton) { addComponent(barrierDisplay); menu.close(); })); + newLabelMenu.addComponent(new Button("Add InputHistory", b -> { + if (b != Mouse.Button.LEFT) return; + InputHistory inputHistory = new InputHistory(); + inputHistory.setPos(mouse); + inputHistory.setSize(new Vector2D(InputHistory.preferredWidth, 120)); + addComponent(inputHistory); + menu.close(); + })); newLabelMenu.addComponent(new Button("Add Plot (WIP)", b -> { if (b != Mouse.Button.LEFT) return; Plot plot = new Last45Plot(); diff --git a/common/src/main/java/io/github/kurrycat/mpkmod/gui/components/InputHistory.java b/common/src/main/java/io/github/kurrycat/mpkmod/gui/components/InputHistory.java new file mode 100644 index 0000000..6fee3e2 --- /dev/null +++ b/common/src/main/java/io/github/kurrycat/mpkmod/gui/components/InputHistory.java @@ -0,0 +1,147 @@ +package io.github.kurrycat.mpkmod.gui.components; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.github.kurrycat.mpkmod.compatibility.MCClasses.FontRenderer; +import io.github.kurrycat.mpkmod.compatibility.MCClasses.Player; +import io.github.kurrycat.mpkmod.compatibility.MCClasses.Renderer2D; +import io.github.kurrycat.mpkmod.util.ColorUtil; +import io.github.kurrycat.mpkmod.util.MathUtil; +import io.github.kurrycat.mpkmod.util.Mouse; +import io.github.kurrycat.mpkmod.util.Vector2D; + +import java.awt.*; +import java.util.ArrayList; +import java.util.HashMap; + +public class InputHistory extends ResizableComponent { + static ArrayList inputHistory = new ArrayList<>(); + @JsonProperty + public Color backgroundColor = new Color(100, 100, 100, 40); + @JsonProperty + public Color messageColor = new Color(255, 255, 255, 255); + @JsonProperty + public Color edgeColor = new Color(100, 100, 100, 50); + public Color selectedColor = new Color(255, 170, 0, 100); + @JsonProperty + public boolean inverted = false; + @JsonProperty + int maxTickAge = 80; + @JsonProperty + public boolean transparentBackground = false; + public static int preferredWidth = 86; + public int maxStoredMessages = 30; + private static final HashMap movementCharacters = new HashMap<>(); + + static { + movementCharacters.put(new Vector2D(0, 0), ' '); + movementCharacters.put(new Vector2D(-1, 0), '⬇'); + movementCharacters.put(new Vector2D(1, 0), '⬆'); + movementCharacters.put(new Vector2D(0, -1), '⬅'); + movementCharacters.put(new Vector2D(0, 1), '➡'); + movementCharacters.put(new Vector2D(1, 1), '⬈'); + movementCharacters.put(new Vector2D(1, -1), '⬉'); + movementCharacters.put(new Vector2D(-1, 1), '⬊'); + movementCharacters.put(new Vector2D(-1, -1), '⬋'); + } + + @JsonCreator + public InputHistory() { + this.setMinSize(new Vector2D(preferredWidth, 60)); + this.setXResizeLocked(true); + } + + @Override + public void render(Vector2D mouse) { + if (!transparentBackground) + Renderer2D.drawRectWithEdge(getDisplayedPos(), getDisplayedSize(), 1, selected ? selectedColor : backgroundColor, edgeColor); + if (highlighted) Renderer2D.drawDottedRect(getDisplayedPos(), getDisplayedSize(), 1, 1, 1, Color.BLACK); + + double lineHeight = 10; + int maxDisplayedMessages = (int) (((getDisplayedSize().getY() - 2) / lineHeight) - 0.5f); + for (int i = 0; i < inputHistory.size() && i < maxDisplayedMessages; i++) { + double yOffset = inverted ? getDisplayedSize().getYI() - (1 + i) * lineHeight : (1 + i) * lineHeight; + inputHistory.get(i).render(new Vector2D(getDisplayedPos().getXI(), getDisplayedPos().getYI() + yOffset)); + } + renderHoverEdges(mouse); + } + + public void onTick() { + Player.KeyInput keyInput = Player.getLatest() == null ? null : Player.getLatest().keyInput; + if (keyInput == null) return; + StringBuilder keysPressed = new StringBuilder(); + keysPressed.append(movementCharacters.getOrDefault(keyInput.getMovementVector(), ' ')); + keysPressed.append(' '); + keysPressed.append(keyInput.jump ? 'J' : ' '); + keysPressed.append(' '); + keysPressed.append(keyInput.sneak ? "Sn" : " "); + keysPressed.append(' '); + keysPressed.append(keyInput.sprint ? "Sp" : " "); + + if (!inputHistory.isEmpty() && keysPressed.toString().equals(inputHistory.get(0).keysPressed)) { + inputHistory.get(0).stillPressed(); + } else { + inputHistory.add(0, new InputHistoryMessage(keysPressed.toString())); + } + if (inputHistory.size() > maxStoredMessages) inputHistory.subList(maxStoredMessages, inputHistory.size()).clear(); + + for (InputHistoryMessage message : inputHistory) message.tick(); + } + + @Override + public PopupMenu getPopupMenu() { + PopupMenu menu = new PopupMenu(); + + menu.addComponent( + new TextCheckButton(Vector2D.OFFSCREEN, "Inverted", inverted, checked -> { + inverted = checked; + }) + ); + menu.addComponent(new TextCheckButton(Vector2D.OFFSCREEN, "Background", !transparentBackground, checked -> { + transparentBackground = !checked; + })); + menu.addComponent( + new NumberSlider(20, 300, 1, maxTickAge - 20, Vector2D.OFFSCREEN, new Vector2D(56, 11), sliderValue -> { + maxTickAge = (int) sliderValue + 20; + }) + ); + menu.addComponent( + new Button("Delete", mouseButton -> { + if (Mouse.Button.LEFT.equals(mouseButton)) { + menu.paneHolder.removeComponent(this); + menu.close(); + } + }) + ); + return menu; + } + + public class InputHistoryMessage { + int tickAge = 0; + int ticksPressed = 1; + final String keysPressed; + private int fadeOutAlpha = 255; + + public InputHistoryMessage(String keysPressed) { + this.keysPressed = keysPressed; + } + + public void render(Vector2D pos) { + Color finalMessageColor = ColorUtil.withAlpha(messageColor, fadeOutAlpha); + + FontRenderer.drawLeftCenteredMonospaceString(keysPressed, pos.add(3, 0), finalMessageColor, true); + FontRenderer.drawRightCenteredString(String.valueOf(ticksPressed), pos.add(preferredWidth - 3, 0), finalMessageColor, true); + } + + public void stillPressed() { + this.tickAge = 0; + this.ticksPressed++; + } + + public void tick() { + this.tickAge++; + int fadeOutTime = 20; + this.fadeOutAlpha = this.tickAge < maxTickAge - fadeOutTime ? 255 : MathUtil.map(maxTickAge - Math.min(tickAge, maxTickAge), fadeOutTime, 0, 255, 0); + } + } +} diff --git a/common/src/main/java/io/github/kurrycat/mpkmod/gui/components/ResizableComponent.java b/common/src/main/java/io/github/kurrycat/mpkmod/gui/components/ResizableComponent.java index 828ab24..2b16652 100644 --- a/common/src/main/java/io/github/kurrycat/mpkmod/gui/components/ResizableComponent.java +++ b/common/src/main/java/io/github/kurrycat/mpkmod/gui/components/ResizableComponent.java @@ -12,6 +12,8 @@ public abstract class ResizableComponent extends Component implements MouseInputListener { private Vector2D minSize = new Vector2D(5, 5); private BoundingBox2D.Edge[] areBeingResized = null; + private boolean xResizeLocked = false; + private boolean yResizeLocked = false; public Vector2D getMinSize() { return minSize; @@ -63,7 +65,7 @@ public void resizeAccordingToSavedEdges(Vector2D mousePos) { Boolean yResizing = beingResized.contains(BoundingBox2D.Edge.TOP) ? Boolean.FALSE : (beingResized.contains(BoundingBox2D.Edge.BOTTOM) ? Boolean.TRUE : null); - if (xResizing != null) { + if (xResizing != null && !xResizeLocked) { double mouseX = mousePos.getX(); double edgePos = xResizing ? bb.maxX() : bb.minX(); double oppositeEdgePos = xResizing ? bb.minX() : bb.maxX(); @@ -79,7 +81,7 @@ public void resizeAccordingToSavedEdges(Vector2D mousePos) { addPos(new Vector2D(mouseX - edgePos, 0)); } } - if (yResizing != null) { + if (yResizing != null && !yResizeLocked) { double mouseY = mousePos.getY(); double edgePos = yResizing ? bb.maxY() : bb.minY(); double oppositeEdgePos = yResizing ? bb.minY() : bb.maxY(); @@ -103,8 +105,18 @@ public void renderHoverEdges(Vector2D mouse) { if (areBeingResized != null) edges = areBeingResized; for (BoundingBox2D.Edge e : edges) { Line2D l = e.getLine(bb); + if(l.p1.getXI() == l.p2.getXI() && xResizeLocked) continue; + if(l.p1.getYI() == l.p2.getYI() && yResizeLocked) continue; BoundingBox2D lineExpandedBB = new BoundingBox2D(l.p1.sub(1), l.p2.add(1)); Renderer2D.drawRect(lineExpandedBB.getMin(), lineExpandedBB.getSize(), Color.RED); } } + + public void setXResizeLocked(boolean xResizeLocked) { + this.xResizeLocked = xResizeLocked; + } + + public void setYResizeLocked(boolean yResizeLocked) { + this.yResizeLocked = yResizeLocked; + } }