From 702865eba16502192a5490697efddffcd0c469c6 Mon Sep 17 00:00:00 2001 From: yoyosource Date: Sun, 25 Dec 2022 14:38:05 +0100 Subject: [PATCH] Finalize basic editor --- .../lexer/ExpressionColorizer.java | 2 +- .../lexer/ScriptColorizer.java | 52 +++++- .../screen/ScriptEditScreen.java | 160 +++++++++++++++--- 3 files changed, 187 insertions(+), 27 deletions(-) diff --git a/src/main/java/de/zonlykroks/advancedscripts/lexer/ExpressionColorizer.java b/src/main/java/de/zonlykroks/advancedscripts/lexer/ExpressionColorizer.java index a0e691a..feaea4a 100644 --- a/src/main/java/de/zonlykroks/advancedscripts/lexer/ExpressionColorizer.java +++ b/src/main/java/de/zonlykroks/advancedscripts/lexer/ExpressionColorizer.java @@ -88,7 +88,7 @@ public class ExpressionColorizer { private static String get(List parts, int index, int direction) { for (int i = index + direction; i >= 0 && i < parts.size(); i += direction) { String part = parts.get(i); - if (!part.isEmpty()) return part; + if (!part.isBlank()) return part; } return null; } diff --git a/src/main/java/de/zonlykroks/advancedscripts/lexer/ScriptColorizer.java b/src/main/java/de/zonlykroks/advancedscripts/lexer/ScriptColorizer.java index 54322be..6086486 100644 --- a/src/main/java/de/zonlykroks/advancedscripts/lexer/ScriptColorizer.java +++ b/src/main/java/de/zonlykroks/advancedscripts/lexer/ScriptColorizer.java @@ -72,7 +72,7 @@ public class ScriptColorizer { if (command.equals(line)) return tokens; tokens.add(Token.SPACE); - String args = line.substring(command.length() + 1).trim(); + String args = line.substring(command.length() + 1); tokens.addAll(colorizeArgs(args, repeatable, argumentTypes)); return tokens; } @@ -163,7 +163,7 @@ public class ScriptColorizer { depth--; } index++; - } while (depth != 0 && index <= current.length()); + } while (depth != 0 && index < current.length()); if (depth != 0) return List.of(new Token(current, TokenTypeColors.ERROR)); return ExpressionColorizer.colorize(current.substring(0, index)); } @@ -188,11 +188,51 @@ public class ScriptColorizer { private static List parseText(String current) { int index = current.indexOf(' '); - if (index == -1) { - return List.of(new Token(current, TokenTypeColors.TEXT)); - } else { - return List.of(new Token(current.substring(0, index), TokenTypeColors.TEXT)); + if (index != -1) { + current = current.substring(0, index); } + List tokens = new ArrayList<>(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < current.length(); i++) { + char c = current.charAt(i); + if (c == '&' && i + 1 < current.length()) { + char color = current.charAt(i + 1); + if (color >= '0' && color <= '9' || color >= 'a' && color <= 'f' || color >= 'A' && color <= 'F') { + if (sb.length() > 0) { + tokens.add(new Token(sb.toString(), TokenTypeColors.TEXT)); + sb = new StringBuilder(); + } + i++; + switch (color) { + case '0' -> tokens.add(new Token("&0", 0xFF000000)); + case '1' -> tokens.add(new Token("&1", 0xFF0000AA)); + case '2' -> tokens.add(new Token("&2", 0xFF00AA00)); + case '3' -> tokens.add(new Token("&3", 0xFF00AAAA)); + case '4' -> tokens.add(new Token("&4", 0xFFAA0000)); + case '5' -> tokens.add(new Token("&5", 0xFFAA00AA)); + case '6' -> tokens.add(new Token("&6", 0xFFFFAA00)); + case '7' -> tokens.add(new Token("&7", 0xFFAAAAAA)); + case '8' -> tokens.add(new Token("&8", 0xFF555555)); + case '9' -> tokens.add(new Token("&9", 0xFF5555FF)); + case 'a', 'A' -> tokens.add(new Token("&a", 0xFF55FF55)); + case 'b', 'B' -> tokens.add(new Token("&b", 0xFF55FFFF)); + case 'c', 'C' -> tokens.add(new Token("&c", 0xFFFF5555)); + case 'd', 'D' -> tokens.add(new Token("&d", 0xFFFF55FF)); + case 'e', 'E' -> tokens.add(new Token("&e", 0xFFFFFF55)); + case 'f', 'F' -> tokens.add(new Token("&f", 0xFFFFFFFF)); + default -> tokens.add(new Token("&" + color, TokenTypeColors.TEXT)); + } + } else { + sb.append(c); + } + } else { + sb.append(c); + } + } + if (sb.length() > 0) { + tokens.add(new Token(sb.toString(), TokenTypeColors.TEXT)); + } + return tokens; } private static List parseNumber(String current) { diff --git a/src/main/java/de/zonlykroks/advancedscripts/screen/ScriptEditScreen.java b/src/main/java/de/zonlykroks/advancedscripts/screen/ScriptEditScreen.java index b6e3b8f..582f3b1 100644 --- a/src/main/java/de/zonlykroks/advancedscripts/screen/ScriptEditScreen.java +++ b/src/main/java/de/zonlykroks/advancedscripts/screen/ScriptEditScreen.java @@ -8,20 +8,23 @@ import net.minecraft.client.font.TextHandler; import net.minecraft.client.gui.DrawableHelper; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.ingame.BookScreen; +import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; +import net.minecraft.client.gui.widget.PressableWidget; import net.minecraft.client.render.GameRenderer; import net.minecraft.client.util.NarratorManager; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtList; +import net.minecraft.nbt.NbtString; +import net.minecraft.network.packet.c2s.play.BookUpdateC2SPacket; import net.minecraft.text.Style; +import net.minecraft.text.Text; import net.minecraft.util.Hand; import org.apache.commons.lang3.mutable.MutableInt; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; public class ScriptEditScreen extends Screen { @@ -36,6 +39,9 @@ public class ScriptEditScreen extends Screen { private int tickCounter; + private int keyCode = -1; + private long time; + public ScriptEditScreen(PlayerEntity player, ItemStack itemStack, Hand hand) { super(NarratorManager.EMPTY); this.player = player; @@ -53,10 +59,49 @@ public class ScriptEditScreen extends Screen { } } + @Override + protected void init() { + this.addDrawableChild( + new DoneButton(this.width / 2 - 98 / 2, height - 40, () -> { + this.client.setScreen(null); + finalizeBook(); + }) + ); + } + + public static final Text DONE = Text.translatable("gui.done"); + + private class DoneButton extends PressableWidget { + private Runnable onPress; + + public DoneButton(int x, int y, Runnable onPress) { + super(x, y, 98, 20, DONE); + visible = true; + this.onPress = onPress; + } + + @Override + public void onPress() { + onPress.run(); + } + + @Override + protected void appendClickableNarrations(NarrationMessageBuilder builder) { + } + + @Override + public boolean isNarratable() { + return false; + } + } + @Override public void tick() { super.tick(); ++this.tickCounter; + if (keyCode != -1 && System.currentTimeMillis() - time > 500) { + key(keyCode); + } } @Override @@ -64,36 +109,50 @@ public class ScriptEditScreen extends Screen { this.renderBackground(matrices); RenderSystem.setShader(GameRenderer::getPositionTexProgram); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - fill(matrices, 23, 23, this.width - 23, this.height - 72, TokenTypeColors.BACKGROUND); + fill(matrices, 23, 23, this.width - 23, this.height - 63, TokenTypeColors.BACKGROUND); int lineNumberLength = textRenderer.getWidth(lines.size() + ""); - // TODO: Implement text rendering int lineNumberText = 1; MutableInt lineNumber = new MutableInt(); TextHandler textHandler = this.textRenderer.getTextHandler(); for (int i = 0; i < lines.size(); i++) { String s = lines.get(i); - if (lineNumber.getValue() * 9 + 25 > this.height - 75) { + if (lineNumber.getValue() * 9 + 25 > this.height - 66) { break; } + if (s.isEmpty() && i == cursorY) { + drawCursor(matrices, 25 + lineNumberLength + 5, lineNumber.getValue() * 9 + 25, true); + } + // Line number + if (lineTooLong(s)) { + int height = this.textRenderer.getWrappedLinesHeight(s, this.width - 50 - lineNumberLength - 5); + fill(matrices, 25 + lineNumberLength + 2, 25 + lineNumber.getValue() * 9, 25 + lineNumberLength + 3, 25 + lineNumber.getValue() * 9 + height, TokenTypeColors.ERROR); + } this.textRenderer.draw(matrices, lineNumberText + "", 25 + lineNumberLength - textRenderer.getWidth(lineNumberText + ""), 25 + lineNumber.getValue() * 9, 0xFFFFFF); lineNumberText++; // Line text List tokens = ScriptColorizer.colorize(lineNumber.getValue(), s); AtomicInteger x = new AtomicInteger(25 + lineNumberLength + 5); + AtomicInteger currentXIndex = new AtomicInteger(0); for (Token token : tokens) { + int finalI = i; textHandler.wrapLines(token.text, this.width - x.get() - 25, Style.EMPTY, true, (style, start, end) -> { int y = lineNumber.getValue() * 9; - if (y + 25 > this.height - 75) { + if (y + 25 > this.height - 66) { return; } String line = token.text.substring(start, end); + int previousXIndex = currentXIndex.get(); + currentXIndex.addAndGet(line.length()); + if (finalI == cursorY && currentXIndex.get() >= cursorX && previousXIndex <= cursorX) { + drawCursor(matrices, x.get() + textRenderer.getWidth(line.substring(0, cursorX - previousXIndex)) - 1, 25 + y, isAtEndOfLine()); + } this.textRenderer.draw(matrices, line, x.get(), 25 + y, token.color); x.addAndGet(textRenderer.getWidth(line)); if (x.get() > this.width - 50 - lineNumberLength - 5) { @@ -104,32 +163,30 @@ public class ScriptEditScreen extends Screen { } lineNumber.increment(); } - drawCursor(matrices, 25 + lineNumberLength + 5 + textRenderer.getWidth(lines.get(cursorY).substring(0, cursorX)), 25 + cursorY * 9, isAtEndOfLine()); super.render(matrices, mouseX, mouseY, delta); } + private boolean lineTooLong(String s) { + if (s.length() >= 1024) { + return true; + } + return textRenderer.getWrappedLinesHeight(s, 114) > 128; + } + private void drawCursor(MatrixStack matrices, int x, int y, boolean atEnd) { if (this.tickCounter / 6 % 2 == 0) { if (!atEnd) { - int var10001 = x; - int var10002 = y - 1; - int var10003 = x + 1; - int var10004 = y; Objects.requireNonNull(this.textRenderer); - DrawableHelper.fill(matrices, var10001, var10002, var10003, var10004 + 9, 0xFFFFFFFF); + DrawableHelper.fill(matrices, x, y - 1, x + 1, y + 9, 0xFFFFFFFF); } else { - this.textRenderer.draw(matrices, "_", (float)x, (float)y, 0xFFFFFFFF); + this.textRenderer.draw(matrices, "_", (float) x, (float) y, 0xFFFFFFFF); } } } - @Override - public boolean keyReleased(int keyCode, int scanCode, int modifiers) { - if (super.keyReleased(keyCode, scanCode, modifiers)) { - return true; - } + private void key(int keyCode) { switch (keyCode) { case 257: case 335: @@ -153,10 +210,32 @@ public class ScriptEditScreen extends Screen { case 265: moveUp(); break; + case 268: + cursorX = 0; + break; + case 269: + cursorX = lines.get(cursorY).length(); + break; } + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + if (super.keyPressed(keyCode, scanCode, modifiers)) { + return true; + } + key(keyCode); + this.keyCode = keyCode; + this.time = System.currentTimeMillis(); return true; } + @Override + public boolean keyReleased(int keyCode, int scanCode, int modifiers) { + this.keyCode = -1; + return super.keyReleased(keyCode, scanCode, modifiers); + } + @Override public boolean charTyped(char chr, int modifiers) { if (super.charTyped(chr, modifiers)) { @@ -249,6 +328,7 @@ public class ScriptEditScreen extends Screen { private boolean moveDown() { if (cursorY == lines.size() - 1) { + cursorX = lines.get(cursorY).length(); return true; } cursorY++; @@ -258,6 +338,7 @@ public class ScriptEditScreen extends Screen { private boolean moveUp() { if (cursorY == 0) { + cursorX = 0; return true; } cursorY--; @@ -273,4 +354,43 @@ public class ScriptEditScreen extends Screen { public boolean mouseClicked(double mouseX, double mouseY, int button) { return super.mouseClicked(mouseX, mouseY, button); } + + private List toPages() { + List pages = new ArrayList<>(); + StringBuilder page = new StringBuilder(); + for (String line : lines) { + if (!page.isEmpty()) { + page.append("\n"); + } + if (page.length() + line.length() > 1024) { + pages.add(page.toString()); + page = new StringBuilder(); + } + String temp = page + line; + if (textRenderer.getWrappedLinesHeight(temp, 114) > 128) { + pages.add(page.toString()); + page = new StringBuilder(); + } + page.append(line); + } + if (!page.isEmpty()) { + pages.add(page.toString()); + } + return pages; + } + + private void finalizeBook() { + List pages = toPages(); + this.writeNbtData(pages); + int i = this.hand == Hand.MAIN_HAND ? this.player.getInventory().selectedSlot : 40; + this.client.getNetworkHandler().sendPacket(new BookUpdateC2SPacket(i, pages, Optional.empty())); + } + + private void writeNbtData(List pages) { + NbtList nbtList = new NbtList(); + pages.stream().map(NbtString::of).forEach(nbtList::add); + if (!pages.isEmpty()) { + this.itemStack.setSubNbt("pages", nbtList); + } + } }