From 6e44ed8aa59d7c6ea9b7f7956855d8739ff8c094 Mon Sep 17 00:00:00 2001 From: BenCheung0422 <74168521+BenCheung0422@users.noreply.github.com> Date: Wed, 2 Aug 2023 23:45:06 +0800 Subject: [PATCH 01/13] Add sign --- .../java/minicraft/core/io/InputHandler.java | 41 ++- src/client/java/minicraft/entity/Entity.java | 5 + src/client/java/minicraft/item/SignItem.java | 42 +++ .../java/minicraft/level/tile/SignTile.java | 104 ++++++ .../java/minicraft/level/tile/Tile.java | 3 + .../java/minicraft/level/tile/Tiles.java | 10 + .../java/minicraft/level/tile/TorchTile.java | 2 +- .../java/minicraft/screen/SignDisplay.java | 323 ++++++++++++++++++ .../minicraft/screen/SignDisplayMenu.java | 49 +++ .../resources/assets/textures/item/sign.png | Bin 0 -> 181 bytes .../resources/assets/textures/tile/sign.png | Bin 0 -> 237 bytes 11 files changed, 565 insertions(+), 14 deletions(-) create mode 100644 src/client/java/minicraft/item/SignItem.java create mode 100644 src/client/java/minicraft/level/tile/SignTile.java create mode 100644 src/client/java/minicraft/screen/SignDisplay.java create mode 100644 src/client/java/minicraft/screen/SignDisplayMenu.java create mode 100644 src/client/resources/assets/textures/item/sign.png create mode 100644 src/client/resources/assets/textures/tile/sign.png diff --git a/src/client/java/minicraft/core/io/InputHandler.java b/src/client/java/minicraft/core/io/InputHandler.java index d24b53c37..7e299367a 100644 --- a/src/client/java/minicraft/core/io/InputHandler.java +++ b/src/client/java/minicraft/core/io/InputHandler.java @@ -520,40 +520,55 @@ public void keyTyped(KeyEvent ke) { keyTypedBuffer = String.valueOf(ke.getKeyChar()); } - private static final String control = "\\p{Print}"; // Should match only printable characters. + private static final String control = "\\p{Print}&&\b"; // Should match only printable characters. public String addKeyTyped(String typing, @Nullable String pattern) { + return handleBackspaceChars(getKeysTyped(typing, pattern)); + } + + /** This returns a raw format of the keys typed, i.e. {@code \b} are not handled here. */ + public String getKeysTyped(@Nullable String pattern) { return getKeysTyped(null, pattern); } + public String getKeysTyped(@Nullable String typing, @Nullable String pattern) { + StringBuilder typed = typing == null ? new StringBuilder() : new StringBuilder(typing); if (lastKeyTyped.length() > 0) { - String letter = lastKeyTyped; + for (char letter : lastKeyTyped.toCharArray()) { + String letterString = String.valueOf(letter); + if (letterString.matches(control) && (pattern == null || letterString.matches(pattern))) + typed.append(letter); + } lastKeyTyped = ""; - if ( letter.matches(control) && (pattern == null || letter.matches(pattern)) || letter.equals("\b") ) - typing += letter; } + return typed.toString(); + } + + public static String handleBackspaceChars(String typing) { return handleBackspaceChars(typing, false); } + /** + * This handles and erases backspace control characters {@code \b} from the given string. + * Evaluation to backspace characters stops if no more characters are in front of them. + * @param keepUnevaluated {@code true} if intending to keep the unhandled backspace characters in the returned string; + * otherwise, those characters are removed even that they are not evaluated. + */ + public static String handleBackspaceChars(String typing, boolean keepUnevaluated) { // Erasing characters by \b. Reference: https://stackoverflow.com/a/30174028 Stack stack = new Stack<>(); // for-each character in the string for (int i = 0; i < typing.length(); i++) { char c = typing.charAt(i); - - // push if it's not a backspace - if (c != '\b') { - stack.push(c); - // else pop if possible - } else if (!stack.empty()) { + if (c == '\b' && !stack.empty() && stack.peek() != '\b') { // pop if the last char exists and is not \b stack.pop(); + } else if (c != '\b' || keepUnevaluated) { + stack.push(c); } } // convert stack to string StringBuilder builder = new StringBuilder(stack.size()); - for (Character c : stack) { builder.append(c); } - typing = builder.toString(); - return typing; + return builder.toString(); } public boolean anyControllerConnected() { diff --git a/src/client/java/minicraft/entity/Entity.java b/src/client/java/minicraft/entity/Entity.java index 0ff319460..4655dd3f3 100644 --- a/src/client/java/minicraft/entity/Entity.java +++ b/src/client/java/minicraft/entity/Entity.java @@ -120,6 +120,9 @@ public boolean interact(Player player, @Nullable Item item, Direction attackDir) public boolean move(int xd, int yd) { if (Updater.saving || (xd == 0 && yd == 0)) return true; // Pretend that it kept moving + int prevXt = x >> 4; + int prevYt = y >> 4; + boolean stopped = true; // Used to check if the entity has BEEN stopped, COMPLETELY; below checks for a lack of collision. //noinspection RedundantIfStatement if (moveX(xd)) stopped = false; // Becomes false if horizontal movement was successful. @@ -127,6 +130,8 @@ public boolean move(int xd, int yd) { if (!stopped) { int xt = x >> 4; // The x tile coordinate that the entity is standing on. int yt = y >> 4; // The y tile coordinate that the entity is standing on. + if (prevXt != xt || prevYt != yt) + level.getTile(xt, yt).steppedOn(level, xt, yt, this); // Calls the steppedOn() method in a tile's class. (used for tiles like sand (footprints) or lava (burning)) } diff --git a/src/client/java/minicraft/item/SignItem.java b/src/client/java/minicraft/item/SignItem.java new file mode 100644 index 000000000..825f21ce4 --- /dev/null +++ b/src/client/java/minicraft/item/SignItem.java @@ -0,0 +1,42 @@ +package minicraft.item; + +import java.util.ArrayList; + +import minicraft.core.Game; +import minicraft.entity.Direction; +import minicraft.entity.mob.Player; +import minicraft.gfx.Sprite; +import minicraft.gfx.SpriteLinker; +import minicraft.level.Level; +import minicraft.level.tile.SignTile; +import minicraft.level.tile.Tile; +import minicraft.screen.SignDisplay; +import org.jetbrains.annotations.NotNull; + +public class SignItem extends TileItem { + private static final SpriteLinker.LinkedSprite sprite = new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Item, "sign"); + + public static ArrayList getAllInstances() { + ArrayList items = new ArrayList<>(); + items.add(new SignItem()); + return items; + } + + private SignItem() { this(1); } + private SignItem(int count) { + super("Torch", sprite, count, "", "dirt", "Wood Planks", "Stone Bricks", "Obsidian", "Wool", "Red Wool", "Blue Wool", "Green Wool", "Yellow Wool", "Black Wool", "grass", "sand"); + } + + public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { + if (validTiles.contains(tile.name)) { + level.setTile(xt, yt, SignTile.getSignTile(tile)); + Game.setDisplay(new SignDisplay(level, xt, yt)); + return super.interactOn(true); + } + return super.interactOn(false); + } + + public @NotNull SignItem copy() { + return new SignItem(count); + } +} diff --git a/src/client/java/minicraft/level/tile/SignTile.java b/src/client/java/minicraft/level/tile/SignTile.java new file mode 100644 index 000000000..1b5dfecb1 --- /dev/null +++ b/src/client/java/minicraft/level/tile/SignTile.java @@ -0,0 +1,104 @@ +package minicraft.level.tile; + +import minicraft.core.Game; +import minicraft.core.io.Sound; +import minicraft.entity.Direction; +import minicraft.entity.Entity; +import minicraft.entity.mob.Mob; +import minicraft.entity.mob.Player; +import minicraft.gfx.Screen; +import minicraft.gfx.SpriteAnimation; +import minicraft.gfx.SpriteLinker; +import minicraft.item.Item; +import minicraft.item.Items; +import minicraft.item.PowerGloveItem; +import minicraft.item.ToolItem; +import minicraft.item.ToolType; +import minicraft.level.Level; +import minicraft.screen.SignDisplay; +import minicraft.screen.SignDisplayMenu; +import org.jetbrains.annotations.Nullable; +import org.tinylog.Logger; + +public class SignTile extends Tile { + private static final SpriteAnimation sprite = new SpriteAnimation(SpriteLinker.SpriteType.Tile, "sign"); + + private static @Nullable SignDisplayMenu signDisplayMenu; + + private final Tile onType; + + public static SignTile getSignTile(Tile onTile) { + int id = onTile.id & 0xFFFF; + if(id < 16384) id += 16384; + else Logger.tag("SignTile").info("Tried to place torch on torch or sign tile..."); + + if(Tiles.containsTile(id)) { + return (SignTile)Tiles.get(id); + } else { + SignTile tile = new SignTile(onTile); + Tiles.add(id, tile); + return tile; + } + } + + private SignTile(Tile onType) { + super("Sign "+ onType.name, sprite); + this.onType = onType; + this.connectsToSand = onType.connectsToSand; + this.connectsToGrass = onType.connectsToGrass; + this.connectsToFluid = onType.connectsToFluid; + } + + public void render(Screen screen, Level level, int x, int y) { + onType.render(screen, level, x, y); + sprite.render(screen, level, x, y); + if (signDisplayMenu != null) { + signDisplayMenu.render(screen); + } + } + + public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { + if (item != null) { + if (item instanceof ToolItem && ((ToolItem) item).type == ToolType.Axe) { + level.setTile(xt, yt, this.onType); + SignDisplay.removeSign(xt, yt); + Sound.play("monsterhurt"); + level.dropItem(xt*16+8, yt*16+8, Items.get("Sign")); + return true; + } + } else { // TODO Add a way to lock signs + Game.setDisplay(new SignDisplay(level, xt, yt)); + return true; + } + + return false; + } + + @Override + public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction attackDir) { + if (source instanceof Player) { + Game.setDisplay(new SignDisplay(level, x, y)); + return true; + } + + return false; + } + + @Override + public void steppedOn(Level level, int xt, int yt, Entity entity) { + if (entity instanceof Player) { + if (signDisplayMenu == null || signDisplayMenu.differsFrom(level.depth, xt, yt)) { + signDisplayMenu = new SignDisplayMenu(level, xt, yt); + } + } + } + + @Override + public void steppedOut(Level level, int xt, int yt, Entity entity) { + if (entity instanceof Player) { + if (signDisplayMenu != null && signDisplayMenu.matches(level.depth, xt, yt)) { + signDisplayMenu = null; + } + } + } +} diff --git a/src/client/java/minicraft/level/tile/Tile.java b/src/client/java/minicraft/level/tile/Tile.java index fe52cf1e1..9f5d8e732 100644 --- a/src/client/java/minicraft/level/tile/Tile.java +++ b/src/client/java/minicraft/level/tile/Tile.java @@ -109,6 +109,9 @@ public void bumpedInto(Level level, int xt, int yt, Entity entity) {} /** What happens when you are inside the tile (ex: lava) */ public void steppedOn(Level level, int xt, int yt, Entity entity) {} + /** What happens when you have just stepped out the tile (ex: sign) */ + public void steppedOut(Level level, int xt, int yt, Entity entity) {} + /** * Called when you hit an item on a tile (ex: Pickaxe on rock). * @param level The level the player is on. diff --git a/src/client/java/minicraft/level/tile/Tiles.java b/src/client/java/minicraft/level/tile/Tiles.java index c5106a385..c21fde9a1 100644 --- a/src/client/java/minicraft/level/tile/Tiles.java +++ b/src/client/java/minicraft/level/tile/Tiles.java @@ -204,6 +204,12 @@ public static Tile get(String name) { name = name.substring(6); // Cuts off torch prefix. } + boolean isSign = false; + if (name.startsWith("SIGN")) { + isSign = true; + name = name.substring(5); + } + if(name.contains("_")) { name = name.substring(0, name.indexOf("_")); } @@ -225,6 +231,10 @@ public static Tile get(String name) { getting = TorchTile.getTorchTile(getting); } + if (isSign) { + getting = SignTile.getSignTile(getting); + } + overflowCheck = 0; return getting; } diff --git a/src/client/java/minicraft/level/tile/TorchTile.java b/src/client/java/minicraft/level/tile/TorchTile.java index 52353ac45..0c5c53202 100644 --- a/src/client/java/minicraft/level/tile/TorchTile.java +++ b/src/client/java/minicraft/level/tile/TorchTile.java @@ -19,7 +19,7 @@ public class TorchTile extends Tile { public static TorchTile getTorchTile(Tile onTile) { int id = onTile.id & 0xFFFF; if(id < 16384) id += 16384; - else Logger.tag("TorchTile").info("Tried to place torch on torch tile..."); + else Logger.tag("TorchTile").info("Tried to place torch on torch or sign tile..."); if(Tiles.containsTile(id)) return (TorchTile)Tiles.get(id); diff --git a/src/client/java/minicraft/screen/SignDisplay.java b/src/client/java/minicraft/screen/SignDisplay.java new file mode 100644 index 000000000..58b7b608a --- /dev/null +++ b/src/client/java/minicraft/screen/SignDisplay.java @@ -0,0 +1,323 @@ +package minicraft.screen; + +import minicraft.core.Game; +import minicraft.core.io.ClipboardHandler; +import minicraft.core.io.InputHandler; +import minicraft.core.io.Localization; +import minicraft.gfx.Color; +import minicraft.gfx.Dimension; +import minicraft.gfx.Font; +import minicraft.gfx.MinicraftImage; +import minicraft.gfx.Point; +import minicraft.gfx.Rectangle; +import minicraft.gfx.Screen; +import minicraft.level.Level; +import minicraft.util.Logging; +import org.jetbrains.annotations.Nullable; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class SignDisplay extends Display { + public static final int MAX_TEXT_LENGTH = 20; + public static final int MAX_ROW_COUNT = 4; + + // TODO make this into an attached attribute of a sign tile. + private static final HashMap, List> signTexts = new HashMap<>(); // The lines of signs should be immutable when stored. + + public static void resetSignTexts() { + signTexts.clear(); + } + + public static void loadSignTexts(Map, List> signTexts) { + SignDisplay.signTexts.clear(); + signTexts.forEach((pt, texts) -> SignDisplay.signTexts.put(pt, Collections.emptyList())); + } + + public static void updateSign(int levelDepth, int x, int y, List lines) { + signTexts.put(new AbstractMap.SimpleImmutableEntry<>(levelDepth, new Point(x, y)), Collections.unmodifiableList(new ArrayList<>(lines))); + } + + public static void removeSign(int levelDepth, int x, int y) { + if (signTexts.remove(new AbstractMap.SimpleImmutableEntry<>(levelDepth, new Point(x, y))) == null) + Logging.WORLDNAMED.warn("Sign at ({}, {}) does not exist to be removed.", x, y); + } + + public static @Nullable List getSign(int levelDepth, int x, int y) { + return signTexts.get(new AbstractMap.SimpleImmutableEntry<>(levelDepth, new Point(x, y))); + } + + private final int levelDepth, x, y; + + private final SignEditor editor; + + public SignDisplay(Level level, int x, int y) { + super(false, new Menu.Builder(true, 3, RelPos.CENTER) + .setPositioning(new Point(Screen.w, 6), RelPos.BOTTOM) + .setMenuSize(new Dimension(MinicraftImage.boxWidth * (MAX_TEXT_LENGTH + 2), MinicraftImage.boxWidth * (MAX_ROW_COUNT + 2))) + .setSelectable(false) + .createMenu()); + this.levelDepth = level.depth; + this.x = x; + this.y = y; + editor = new SignEditor(getSign(levelDepth, x, y)); + } + + private class SignEditor { + private final ClipboardHandler clipboard = new ClipboardHandler(); + private final ArrayList rows = new ArrayList<>(); + private int cursorX = 0, cursorY = 0; + private int caretFrameCountDown = 60; + private boolean caretShown = true; + + public SignEditor(@Nullable List lines) { + if (lines != null) lines.forEach(l -> rows.add(new StringBuilder(l))); + if (rows.isEmpty()) rows.add(new StringBuilder()); + } + + public List getLines() { + ArrayList lines = new ArrayList<>(); + rows.forEach(r -> { + // Reference: https://www.baeldung.com/java-string-split-every-n-characters#using-the-stringsubstring-method + int length = r.length(); + for (int i = 0; i < length; i += MAX_TEXT_LENGTH) { + lines.add(r.substring(i, Math.min(length, i + MAX_TEXT_LENGTH))); + } + }); + return lines; + } + + public void tick(InputHandler input) { + if (caretFrameCountDown-- == 0) { // Caret flashing animation + caretFrameCountDown = 30; + caretShown = !caretShown; + } + + insertChars(input.getKeysTyped(null)); + if (input.getKey("PAGE-UP").clicked) { + cursorX = 0; + cursorY = 0; + updateCaretAnimation(); + } else if (input.getKey("PAGE-DOWN").clicked) { + cursorY = rows.size() - 1; + cursorX = rows.get(cursorY).length(); + updateCaretAnimation(); + + } else if (input.getKey("HOME").clicked) { + cursorX = (cursorX - 1) / MAX_TEXT_LENGTH * MAX_TEXT_LENGTH; // Rounding down + updateCaretAnimation(); + } else if (input.getKey("END").clicked) { + cursorX = Math.min((cursorX + MAX_TEXT_LENGTH - 1) / MAX_TEXT_LENGTH * MAX_TEXT_LENGTH, rows.get(cursorY).length()); // Rounding up + updateCaretAnimation(); + + // Cursor navigating + // As lines are centered, the character above in rendering would not always be the one in indices. + // The position is set to the beginning of line when the cursor moved upward or downward. + } else if (input.inputPressed("CURSOR-UP")) { + if (cursorX > MAX_TEXT_LENGTH) { // This should be safe. + cursorX -= (cursorX % MAX_TEXT_LENGTH == 0 ? MAX_TEXT_LENGTH : cursorX % MAX_TEXT_LENGTH) + MAX_TEXT_LENGTH; + } else if (cursorY > 0) { + int length = rows.get(--cursorY).length(); + if (cursorX > 0 && cursorX % MAX_TEXT_LENGTH == 0) { // If the current position is at the end of line + cursorX = length; + } else { + if (length > 0 && (length % MAX_TEXT_LENGTH) == 0) { + cursorX += length - MAX_TEXT_LENGTH; + } else { + cursorX += length / MAX_TEXT_LENGTH * MAX_TEXT_LENGTH; + } + + if (cursorX > length) cursorX = length; // Collapses the spaces between the cursor and the end of row + } + } else { + cursorX = 0; + } + + updateCaretAnimation(); + } else if (input.inputPressed("CURSOR-DOWN")) { + if (cursorX / MAX_TEXT_LENGTH < rows.get(cursorY).length() / MAX_TEXT_LENGTH) { + cursorX += MAX_TEXT_LENGTH - cursorX % MAX_TEXT_LENGTH; + } else if (cursorY < rows.size() - 1) { + cursorX = 0; // It is always in the first line of the row, so it is always the beginning of the row. + } else { + cursorX = rows.get(cursorY).length(); + } + + updateCaretAnimation(); + } else if (input.inputDown("CURSOR-LEFT")) { + if (cursorX > 0) cursorX--; + updateCaretAnimation(); + } else if (input.inputDown("CURSOR-RIGHT")) { + if (cursorX == rows.get(cursorY).length()) { // The end of row + if (cursorY < rows.size() - 1) { // If it is not in the last row + cursorX = 0; + cursorY++; + } + } else { + cursorX++; + } + + updateCaretAnimation(); + + // Clipboard operations + } else if (input.getKey("CTRL-X").clicked) { + cursorX = 0; + cursorY = 0; + clipboard.setClipboardContents(String.join("\n", rows)); + rows.clear(); + rows.add(new StringBuilder()); + updateCaretAnimation(); + } else if (input.getKey("CTRL-C").clicked) { + clipboard.setClipboardContents(String.join("\n", rows)); + updateCaretAnimation(); + } else if (input.getKey("CTRL-V").clicked) { + insertChars(clipboard.getClipboardContents()); + } + } + + public void render(Screen screen) { + Rectangle bounds = menus[0].getBounds(); + int yPos = bounds.getTop() + MinicraftImage.boxWidth; // Upper border + int centeredX = bounds.getLeft() + bounds.getWidth() / 2; + for (StringBuilder row : rows) { + // See #getLines + String r = row.toString(); + int length = r.length(); + for (int j = 0; j < length; j += MAX_TEXT_LENGTH) { // For each line + Font.drawCentered(r.substring(j, Math.min(length, j + MAX_TEXT_LENGTH)), screen, yPos, Color.WHITE); + //noinspection SuspiciousNameCombination + yPos += MinicraftImage.boxWidth; + } + } + + // Cursor rendering + int lineWidth = getLineWidthOfRow(cursorX, cursorY) * MinicraftImage.boxWidth; + int displayX = calculateDisplayX(cursorX) * MinicraftImage.boxWidth; + int displayY = calculateDisplayY(cursorX, cursorY) * MinicraftImage.boxWidth; + int lineBeginning = centeredX - lineWidth / 2; + int cursorX = lineBeginning + displayX; + int cursorY = bounds.getTop() + MinicraftImage.boxWidth + displayY; + int cursorRenderY = cursorY + MinicraftImage.boxWidth - 1; + for (int i = 0; i < MinicraftImage.boxWidth; i++) { // 1 pixel high and 8 pixel wide + int idx = cursorX + i + cursorRenderY; + screen.pixels[idx] = idx == Color.WHITE ? Color.BLACK : Color.WHITE; + } + } + + private void updateCaretAnimation() { + caretShown = true; + caretFrameCountDown = 120; + } + + private int calculateDisplayX(int x) { + return x > MAX_TEXT_LENGTH ? x % MAX_TEXT_LENGTH : x; + } + + private int getLineWidthOfRow(int x, int y) { + int length = rows.get(y).length(); + return (x == 0 ? MAX_TEXT_LENGTH : (x + MAX_TEXT_LENGTH - 1) / MAX_TEXT_LENGTH * MAX_TEXT_LENGTH) > length + ? length - (x - 1) / MAX_TEXT_LENGTH : MAX_TEXT_LENGTH; + } + + private int calculateDisplayY(int x, int y) { + int count = 0; + for (int i = 0; i <= y; i++) { + if (i != y) count += calculateNumberOfOccupiedLinesOfRow(i); + else count += (x - 1) / MAX_TEXT_LENGTH; // A new line is regarded when the current line exceeds MAX_TEST_LENGTH. + } + + return count; + } + + private boolean checkNewLineAvailable() { + int maxY = rows.size() - 1; + return calculateDisplayY(rows.get(maxY).length(), maxY) < MAX_ROW_COUNT - 1; + } + + private boolean checkRowLineCapacity(int y) { + int len = rows.get(y).length(); + // If the current row is not enough to fill in a line or the existing new line + return len < MAX_TEXT_LENGTH || len % MAX_TEXT_LENGTH != 0; + } + + private int calculateNumberOfOccupiedLinesOfRow(int y) { + int length = rows.get(y).length(); + return length == 0 ? 1 : (length + MAX_TEXT_LENGTH - 1) / MAX_TEXT_LENGTH * MAX_TEXT_LENGTH; + } + + private void insertChars(String chars) { + chars = InputHandler.handleBackspaceChars(chars, true); // Reduce the number of unnecessary operations. + if (chars.isEmpty()) return; + updateCaretAnimation(); + for (int i = 0; i < chars.length(); i++) { + char c = chars.charAt(i); + if (!insertChar(c)) break; // Terminates the processing of characters if no more character can be proceeded. + } + } + + /** + * Inserts a character to be inserted at the current cursor position. Cursor position is handled when needed. + * This controls whether the procedure should be terminated depending on how the characters are handled. + * @param c A printable or line break (line feed) or backspace {@code \b} character to be inserted. Regex: {@code \p{Print}&&[\b\n]} + * @return {@code true} if the char is handled and valid to be continuing processing the following chars; + * otherwise, the procedure of processing characters is terminated. + */ + private boolean insertChar(char c) { + if (c == '\b') { // Backspace + if (cursorX == 0 && cursorY == 0) return true; // No effect; valid behaviour; handled + else if (cursorX > 0) { + rows.get(cursorY).deleteCharAt(--cursorX); // Remove the char in front of the cursor. + } else { // cursorY > 0 && cursorX == 0 + // Combining the current row to the row above. Remove the current line and decrement cursorY by 1. + rows.get(cursorY - 1).append(rows.remove(cursorY--)); + } + + return true; // A backspace is always not limited by the line count limit, and it could reduce characters when appropriate. + } else if (c == '\n') { // Line break + StringBuilder curRow = rows.get(cursorY); + int rowLen = curRow.length(); + // If the row occupies more than 1 line and the string of the cursor until the end of line plus the last line + // does not contain enough chars to require a new line, so that the line break does not affect the line count. + // The cursor should be within the row so that it does not create an empty new line, which breaks the case mentioned above. + // One of the cases is that the cursor is at the end of line. + if (rowLen > MAX_TEXT_LENGTH && cursorX > 0 && cursorX < rowLen && + cursorX <= rowLen - rowLen % MAX_TEXT_LENGTH && // The cursor should be in the line before the last line. + MAX_TEXT_LENGTH - cursorX + rowLen % MAX_TEXT_LENGTH <= MAX_TEXT_LENGTH || + checkNewLineAvailable()) { // For other cases, a new line would always be required. + rows.add(++cursorY, new StringBuilder(curRow.substring(cursorX))); // Create new builder from the split point. + curRow.delete(cursorX, rowLen); // Remove string part starts with the split point. + cursorX = 0; // A pointer to the new line after the break. + return true; + } else return false; // No line break; the char is discarded; no effect; unhandled + } else { + // If the current line has spaces to expand, or else a new line would be required. + if (checkRowLineCapacity(cursorY) || checkNewLineAvailable()) { + rows.get(cursorY).insert(cursorX++, c); + return true; + } else return false; // No more chars are accepted to expand at the current cursor position. + } + } + } + + @Override + public void render(Screen screen) { + super.render(screen); + Rectangle bounds = menus[0].getBounds(); + Font.draw(Localization.getLocalized("Use SHIFT-ENTER to confirm input."), screen, bounds.getLeft(), bounds.getBottom() + 8, Color.GRAY); + } + + @Override + public void tick(InputHandler input) { + if (input.inputPressed("exit") || input.getKey("SHIFT-ENTER").clicked) { + updateSign(levelDepth, x, y, editor.getLines()); + Game.exitDisplay(); + return; + } + + editor.tick(input); + } +} diff --git a/src/client/java/minicraft/screen/SignDisplayMenu.java b/src/client/java/minicraft/screen/SignDisplayMenu.java new file mode 100644 index 000000000..c56652baa --- /dev/null +++ b/src/client/java/minicraft/screen/SignDisplayMenu.java @@ -0,0 +1,49 @@ +package minicraft.screen; + +import minicraft.core.io.InputHandler; +import minicraft.gfx.Dimension; +import minicraft.gfx.MinicraftImage; +import minicraft.gfx.Point; +import minicraft.gfx.Screen; +import minicraft.level.Level; +import minicraft.screen.entry.StringEntry; +import minicraft.util.Logging; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class SignDisplayMenu extends Menu { + private final int levelDepth, x, y; + + public SignDisplayMenu(Level level, int x, int y) { + super(new Menu.Builder(true, 3, RelPos.CENTER) + .setPositioning(new Point(Screen.w, 6), RelPos.BOTTOM) + .setMenuSize(new Dimension(MinicraftImage.boxWidth * (SignDisplay.MAX_TEXT_LENGTH + 2), MinicraftImage.boxWidth * (SignDisplay.MAX_ROW_COUNT + 2))) + .setSelectable(false) + .createMenu()); + this.levelDepth = level.depth; + this.x = x; + this.y = y; + List lines; + if ((lines = SignDisplay.getSign(levelDepth, x, y)) == null) { + lines = Collections.emptyList(); + Logging.WORLDNAMED.warn("Sign at ({}, {}) does not exist or has not initialized, but a display menu is invoked.", x, y); + } + setEntries(lines.stream().map(r -> new StringEntry(r, false)).collect(Collectors.toList())); + } + + /** Checks if this sign's coordinates differ from the given ones. */ + public boolean differsFrom(int levelDepth, int x, int y) { + return this.levelDepth != levelDepth || this.x != x || this.y != y; + } + + /** Checks if this sign's coordinates match the given ones. */ + public boolean matches(int levelDepth, int x, int y) { + return this.levelDepth == levelDepth && this.x == x && this.y == y; + } + + @Deprecated + @Override + public void tick(InputHandler input) {} // Render only +} diff --git a/src/client/resources/assets/textures/item/sign.png b/src/client/resources/assets/textures/item/sign.png new file mode 100644 index 0000000000000000000000000000000000000000..99fc4f104d08f4ffc1b3779bfdcbacbffe2552d0 GIT binary patch literal 181 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucK`&1i#}JL+WE(r Date: Wed, 2 Aug 2023 23:51:47 +0800 Subject: [PATCH 02/13] Fix an error of sign --- src/client/java/minicraft/level/tile/SignTile.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/java/minicraft/level/tile/SignTile.java b/src/client/java/minicraft/level/tile/SignTile.java index 1b5dfecb1..532cb055d 100644 --- a/src/client/java/minicraft/level/tile/SignTile.java +++ b/src/client/java/minicraft/level/tile/SignTile.java @@ -61,7 +61,7 @@ public boolean interact(Level level, int xt, int yt, Player player, Item item, D if (item != null) { if (item instanceof ToolItem && ((ToolItem) item).type == ToolType.Axe) { level.setTile(xt, yt, this.onType); - SignDisplay.removeSign(xt, yt); + SignDisplay.removeSign(level.depth, xt, yt); Sound.play("monsterhurt"); level.dropItem(xt*16+8, yt*16+8, Items.get("Sign")); return true; From d4cb9bb2848f40635b9f8e88d2c6b7154a4abc75 Mon Sep 17 00:00:00 2001 From: BenCheung0422 <74168521+BenCheung0422@users.noreply.github.com> Date: Thu, 3 Aug 2023 18:33:21 +0800 Subject: [PATCH 03/13] Add sign tile data save and load support --- src/client/java/minicraft/core/World.java | 2 + src/client/java/minicraft/item/Items.java | 1 + src/client/java/minicraft/saveload/Load.java | 35 ++++++++++++++++ src/client/java/minicraft/saveload/Save.java | 42 ++++++++++++++----- .../java/minicraft/screen/SignDisplay.java | 4 ++ 5 files changed, 74 insertions(+), 10 deletions(-) diff --git a/src/client/java/minicraft/core/World.java b/src/client/java/minicraft/core/World.java index 4e5a2aa8d..4b2c70902 100644 --- a/src/client/java/minicraft/core/World.java +++ b/src/client/java/minicraft/core/World.java @@ -11,6 +11,7 @@ import minicraft.screen.LoadingDisplay; import minicraft.screen.PlayerDeathDisplay; import minicraft.screen.QuestsDisplay; +import minicraft.screen.SignDisplay; import minicraft.screen.TutorialDisplayHandler; import minicraft.screen.WorldGenDisplay; import minicraft.screen.WorldSelectDisplay; @@ -150,6 +151,7 @@ public static void resetGame(boolean keepPlayer) { CraftingDisplay.resetRecipeUnlocks(); TutorialDisplayHandler.reset(true); AdvancementElement.resetRecipeUnlockingElements(); + SignDisplay.resetSignTexts(); } Renderer.readyToRenderGameplay = true; diff --git a/src/client/java/minicraft/item/Items.java b/src/client/java/minicraft/item/Items.java index 9430bd63c..55b2c5cbb 100644 --- a/src/client/java/minicraft/item/Items.java +++ b/src/client/java/minicraft/item/Items.java @@ -43,6 +43,7 @@ private static void addAll(ArrayList items) { addAll(FishingRodItem.getAllInstances()); addAll(SummonItem.getAllInstances()); addAll(HeartItem.getAllInstances()); + addAll(SignItem.getAllInstances()); } public static ArrayList getAll() { diff --git a/src/client/java/minicraft/saveload/Load.java b/src/client/java/minicraft/saveload/Load.java index 03b06c5b2..2b1e79f5b 100644 --- a/src/client/java/minicraft/saveload/Load.java +++ b/src/client/java/minicraft/saveload/Load.java @@ -39,6 +39,7 @@ import minicraft.entity.particle.SmashParticle; import minicraft.entity.particle.TextParticle; import minicraft.gfx.Color; +import minicraft.gfx.Point; import minicraft.item.ArmorItem; import minicraft.item.Inventory; import minicraft.item.Item; @@ -57,6 +58,7 @@ import minicraft.screen.PopupDisplay; import minicraft.screen.QuestsDisplay; import minicraft.screen.ResourcePackDisplay; +import minicraft.screen.SignDisplay; import minicraft.screen.SkinDisplay; import minicraft.screen.TutorialDisplayHandler; import minicraft.screen.entry.ListEntry; @@ -77,12 +79,16 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; +import java.util.AbstractMap; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Stack; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Predicate; +import java.util.stream.Collectors; public class Load { @@ -714,6 +720,35 @@ private void loadWorld(String filename) { AdvancementElement.resetRecipeUnlockingElements(); QuestsDisplay.resetGameQuests(); } + + boolean signsLoadSucceeded = false; + if (new File(location+"signs.json").exists()) { + try { + JSONObject fileObj = new JSONObject(loadFromFile(location + "signs.json", true)); + @SuppressWarnings("unused") + Version dataVersion = new Version(fileObj.getString("Version")); + JSONArray dataObj = fileObj.getJSONArray("signs"); + HashMap, List> signTexts = new HashMap<>(); + for (int i = 0; i < dataObj.length(); i++) { + JSONObject signObj = dataObj.getJSONObject(i); + signTexts.put( + new AbstractMap.SimpleImmutableEntry<>(signObj.getInt("level"), new Point(signObj.getInt("x"), signObj.getInt("y"))), + signObj.getJSONArray("lines").toList().stream().map(e -> (String) e).collect(Collectors.toList()) + ); + } + + SignDisplay.loadSignTexts(signTexts); + signsLoadSucceeded = true; + } catch (IOException e) { + Logging.SAVELOAD.error(e, "Unable to load signs.json, reset sign data instead."); + } + } else { + Logging.SAVELOAD.debug("signs.json not found, reset sign data instead."); + } + + if (!signsLoadSucceeded) { + SignDisplay.resetSignTexts(); + } } public void loadPlayer(String filename, Player player) { diff --git a/src/client/java/minicraft/saveload/Save.java b/src/client/java/minicraft/saveload/Save.java index a5096b15e..96a5efe1e 100644 --- a/src/client/java/minicraft/saveload/Save.java +++ b/src/client/java/minicraft/saveload/Save.java @@ -26,6 +26,7 @@ import minicraft.entity.mob.Sheep; import minicraft.entity.particle.Particle; import minicraft.entity.particle.TextParticle; +import minicraft.gfx.Point; import minicraft.item.Inventory; import minicraft.item.Item; import minicraft.item.PotionType; @@ -36,6 +37,7 @@ import minicraft.screen.MultiplayerDisplay; import minicraft.screen.QuestsDisplay; import minicraft.screen.ResourcePackDisplay; +import minicraft.screen.SignDisplay; import minicraft.screen.SkinDisplay; import minicraft.screen.TutorialDisplayHandler; import minicraft.screen.WorldSelectDisplay; @@ -50,6 +52,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Map; public class Save { @@ -257,17 +260,36 @@ private void writeWorld(String filename) { writeToFile(location + filename + l + "data" + extension, data); } - JSONObject fileObj = new JSONObject(); - fileObj.put("Version", Game.VERSION.toString()); - TutorialDisplayHandler.save(fileObj); - AdvancementElement.saveRecipeUnlockingElements(fileObj); - QuestsDisplay.save(fileObj); + { // Advancements + JSONObject fileObj = new JSONObject(); + fileObj.put("Version", Game.VERSION.toString()); + TutorialDisplayHandler.save(fileObj); + AdvancementElement.saveRecipeUnlockingElements(fileObj); + QuestsDisplay.save(fileObj); + try { + writeJSONToFile(location + "advancements.json", fileObj.toString(4)); + } catch (IOException e) { + e.printStackTrace(); + Logging.SAVELOAD.error("Unable to write advancements.json."); + } + } - try { - writeJSONToFile(location + "advancements.json", fileObj.toString(4)); - } catch (IOException e) { - e.printStackTrace(); - Logging.SAVELOAD.error("Unable to write advancements.json."); + { // Sign Data + JSONObject fileObj = new JSONObject(); + fileObj.put("Version", Game.VERSION.toString()); + JSONArray dataObj = new JSONArray(); + SignDisplay.getSignTexts().forEach((key, value) -> dataObj.put(new JSONObject() + .put("level", key.getKey()) + .put("x", key.getValue().x) + .put("y", key.getValue().y) + .put("lines", value))); + fileObj.put("signs", dataObj); + try { + writeJSONToFile(location + "signs.json", fileObj.toString(4)); + } catch (IOException e) { + e.printStackTrace(); + Logging.SAVELOAD.error("Unable to write signs.json."); + } } } diff --git a/src/client/java/minicraft/screen/SignDisplay.java b/src/client/java/minicraft/screen/SignDisplay.java index 58b7b608a..4f422856f 100644 --- a/src/client/java/minicraft/screen/SignDisplay.java +++ b/src/client/java/minicraft/screen/SignDisplay.java @@ -38,6 +38,10 @@ public static void loadSignTexts(Map, List> si signTexts.forEach((pt, texts) -> SignDisplay.signTexts.put(pt, Collections.emptyList())); } + public static Map, List> getSignTexts() { + return new HashMap<>(signTexts); + } + public static void updateSign(int levelDepth, int x, int y, List lines) { signTexts.put(new AbstractMap.SimpleImmutableEntry<>(levelDepth, new Point(x, y)), Collections.unmodifiableList(new ArrayList<>(lines))); } From a8399e8633c78bcad9d7be31a7f0734399961642 Mon Sep 17 00:00:00 2001 From: BenCheung0422 <74168521+BenCheung0422@users.noreply.github.com> Date: Thu, 3 Aug 2023 18:55:19 +0800 Subject: [PATCH 04/13] Fix input filter and sign item name --- src/client/java/minicraft/core/io/InputHandler.java | 9 +++++---- src/client/java/minicraft/item/SignItem.java | 2 +- src/client/java/minicraft/screen/SignDisplay.java | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/client/java/minicraft/core/io/InputHandler.java b/src/client/java/minicraft/core/io/InputHandler.java index 7e299367a..e8af57cfc 100644 --- a/src/client/java/minicraft/core/io/InputHandler.java +++ b/src/client/java/minicraft/core/io/InputHandler.java @@ -520,19 +520,20 @@ public void keyTyped(KeyEvent ke) { keyTypedBuffer = String.valueOf(ke.getKeyChar()); } - private static final String control = "\\p{Print}&&\b"; // Should match only printable characters. + private static final String control = "[\\p{Print}\n]+"; // Should match only printable characters. public String addKeyTyped(String typing, @Nullable String pattern) { return handleBackspaceChars(getKeysTyped(typing, pattern)); } /** This returns a raw format of the keys typed, i.e. {@code \b} are not handled here. */ - public String getKeysTyped(@Nullable String pattern) { return getKeysTyped(null, pattern); } - public String getKeysTyped(@Nullable String typing, @Nullable String pattern) { + public String getKeysTyped(@Nullable String pattern) { return getKeysTyped(null, pattern, true); } + public String getKeysTyped(@Nullable String typing, @Nullable String pattern) { return getKeysTyped(typing, pattern, false); } + public String getKeysTyped(@Nullable String typing, @Nullable String pattern, boolean multiline) { StringBuilder typed = typing == null ? new StringBuilder() : new StringBuilder(typing); if (lastKeyTyped.length() > 0) { for (char letter : lastKeyTyped.toCharArray()) { String letterString = String.valueOf(letter); - if (letterString.matches(control) && (pattern == null || letterString.matches(pattern))) + if (letter == '\b' || letterString.matches(control) && (letter != '\n' || multiline) && (pattern == null || letterString.matches(pattern))) typed.append(letter); } lastKeyTyped = ""; diff --git a/src/client/java/minicraft/item/SignItem.java b/src/client/java/minicraft/item/SignItem.java index 825f21ce4..645878bde 100644 --- a/src/client/java/minicraft/item/SignItem.java +++ b/src/client/java/minicraft/item/SignItem.java @@ -24,7 +24,7 @@ public static ArrayList getAllInstances() { private SignItem() { this(1); } private SignItem(int count) { - super("Torch", sprite, count, "", "dirt", "Wood Planks", "Stone Bricks", "Obsidian", "Wool", "Red Wool", "Blue Wool", "Green Wool", "Yellow Wool", "Black Wool", "grass", "sand"); + super("Sign", sprite, count, "", "dirt", "Wood Planks", "Stone Bricks", "Obsidian", "Wool", "Red Wool", "Blue Wool", "Green Wool", "Yellow Wool", "Black Wool", "grass", "sand"); } public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { diff --git a/src/client/java/minicraft/screen/SignDisplay.java b/src/client/java/minicraft/screen/SignDisplay.java index 4f422856f..eae717935 100644 --- a/src/client/java/minicraft/screen/SignDisplay.java +++ b/src/client/java/minicraft/screen/SignDisplay.java @@ -266,7 +266,7 @@ private void insertChars(String chars) { /** * Inserts a character to be inserted at the current cursor position. Cursor position is handled when needed. * This controls whether the procedure should be terminated depending on how the characters are handled. - * @param c A printable or line break (line feed) or backspace {@code \b} character to be inserted. Regex: {@code \p{Print}&&[\b\n]} + * @param c A printable or line break (line feed) or backspace {@code \b} character to be inserted. Regex: {@code [\p{Print}\b\n]+} * @return {@code true} if the char is handled and valid to be continuing processing the following chars; * otherwise, the procedure of processing characters is terminated. */ From ee4a8b6aa08cc27fcb8721421812491e1750942b Mon Sep 17 00:00:00 2001 From: BenCheung0422 <74168521+BenCheung0422@users.noreply.github.com> Date: Thu, 3 Aug 2023 23:14:37 +0800 Subject: [PATCH 05/13] Fix more problems related to sign --- src/client/java/minicraft/core/Renderer.java | 4 ++ src/client/java/minicraft/core/World.java | 2 + src/client/java/minicraft/entity/Entity.java | 2 +- src/client/java/minicraft/level/Level.java | 2 +- .../java/minicraft/level/tile/SignTile.java | 14 +++---- .../java/minicraft/screen/SignDisplay.java | 39 ++++++++++--------- .../minicraft/screen/SignDisplayMenu.java | 3 +- 7 files changed, 36 insertions(+), 30 deletions(-) diff --git a/src/client/java/minicraft/core/Renderer.java b/src/client/java/minicraft/core/Renderer.java index 01e024f4e..b332fd3b7 100644 --- a/src/client/java/minicraft/core/Renderer.java +++ b/src/client/java/minicraft/core/Renderer.java @@ -28,6 +28,7 @@ import minicraft.screen.Menu; import minicraft.screen.QuestsDisplay; import minicraft.screen.RelPos; +import minicraft.screen.SignDisplayMenu; import minicraft.screen.TutorialDisplayHandler; import minicraft.screen.entry.ListEntry; import minicraft.screen.entry.StringEntry; @@ -72,6 +73,8 @@ private Renderer() { public static boolean readyToRenderGameplay = false; public static boolean showDebugInfo = false; + public static SignDisplayMenu signDisplayMenu = null; + private static Ellipsis ellipsis = new SmoothEllipsis(new TickUpdater()); private static int potionRenderOffset = 0; @@ -411,6 +414,7 @@ private static void renderGui() { TutorialDisplayHandler.render(screen); renderQuestsDisplay(); + if (signDisplayMenu != null) signDisplayMenu.render(screen); renderDebugInfo(); } diff --git a/src/client/java/minicraft/core/World.java b/src/client/java/minicraft/core/World.java index 4b2c70902..a52588bec 100644 --- a/src/client/java/minicraft/core/World.java +++ b/src/client/java/minicraft/core/World.java @@ -156,6 +156,8 @@ public static void resetGame(boolean keepPlayer) { Renderer.readyToRenderGameplay = true; + Renderer.signDisplayMenu = null; + PlayerDeathDisplay.shouldRespawn = true; Logging.WORLD.trace("World initialized."); diff --git a/src/client/java/minicraft/entity/Entity.java b/src/client/java/minicraft/entity/Entity.java index 4655dd3f3..b09321c19 100644 --- a/src/client/java/minicraft/entity/Entity.java +++ b/src/client/java/minicraft/entity/Entity.java @@ -131,7 +131,7 @@ public boolean move(int xd, int yd) { int xt = x >> 4; // The x tile coordinate that the entity is standing on. int yt = y >> 4; // The y tile coordinate that the entity is standing on. if (prevXt != xt || prevYt != yt) - + level.getTile(prevXt, prevYt).steppedOut(level, prevXt, prevYt, this); level.getTile(xt, yt).steppedOn(level, xt, yt, this); // Calls the steppedOn() method in a tile's class. (used for tiles like sand (footprints) or lava (burning)) } diff --git a/src/client/java/minicraft/level/Level.java b/src/client/java/minicraft/level/Level.java index 716e62a87..3e844872b 100644 --- a/src/client/java/minicraft/level/Level.java +++ b/src/client/java/minicraft/level/Level.java @@ -507,7 +507,7 @@ private void sortAndRender(Screen screen, List list) { public Tile getTile(int x, int y) { if (x < 0 || y < 0 || x >= w || y >= h /* || (x + y * w) >= tiles.length*/ ) return Tiles.get("connector tile"); int id = tiles[x + y * w]; - if(id < 0) id += 256; + if(id < 0) id += 32768; return Tiles.get(id); } diff --git a/src/client/java/minicraft/level/tile/SignTile.java b/src/client/java/minicraft/level/tile/SignTile.java index 532cb055d..55858f98f 100644 --- a/src/client/java/minicraft/level/tile/SignTile.java +++ b/src/client/java/minicraft/level/tile/SignTile.java @@ -1,6 +1,7 @@ package minicraft.level.tile; import minicraft.core.Game; +import minicraft.core.Renderer; import minicraft.core.io.Sound; import minicraft.entity.Direction; import minicraft.entity.Entity; @@ -23,8 +24,6 @@ public class SignTile extends Tile { private static final SpriteAnimation sprite = new SpriteAnimation(SpriteLinker.SpriteType.Tile, "sign"); - private static @Nullable SignDisplayMenu signDisplayMenu; - private final Tile onType; public static SignTile getSignTile(Tile onTile) { @@ -52,9 +51,6 @@ private SignTile(Tile onType) { public void render(Screen screen, Level level, int x, int y) { onType.render(screen, level, x, y); sprite.render(screen, level, x, y); - if (signDisplayMenu != null) { - signDisplayMenu.render(screen); - } } public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { @@ -87,8 +83,8 @@ public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction at @Override public void steppedOn(Level level, int xt, int yt, Entity entity) { if (entity instanceof Player) { - if (signDisplayMenu == null || signDisplayMenu.differsFrom(level.depth, xt, yt)) { - signDisplayMenu = new SignDisplayMenu(level, xt, yt); + if (Renderer.signDisplayMenu == null || Renderer.signDisplayMenu.differsFrom(level.depth, xt, yt)) { + Renderer.signDisplayMenu = new SignDisplayMenu(level, xt, yt); } } } @@ -96,8 +92,8 @@ public void steppedOn(Level level, int xt, int yt, Entity entity) { @Override public void steppedOut(Level level, int xt, int yt, Entity entity) { if (entity instanceof Player) { - if (signDisplayMenu != null && signDisplayMenu.matches(level.depth, xt, yt)) { - signDisplayMenu = null; + if (Renderer.signDisplayMenu != null && Renderer.signDisplayMenu.matches(level.depth, xt, yt)) { + Renderer.signDisplayMenu = null; } } } diff --git a/src/client/java/minicraft/screen/SignDisplay.java b/src/client/java/minicraft/screen/SignDisplay.java index eae717935..8398fac5f 100644 --- a/src/client/java/minicraft/screen/SignDisplay.java +++ b/src/client/java/minicraft/screen/SignDisplay.java @@ -35,7 +35,7 @@ public static void resetSignTexts() { public static void loadSignTexts(Map, List> signTexts) { SignDisplay.signTexts.clear(); - signTexts.forEach((pt, texts) -> SignDisplay.signTexts.put(pt, Collections.emptyList())); + signTexts.forEach((pt, texts) -> SignDisplay.signTexts.put(pt, Collections.unmodifiableList(new ArrayList<>(texts)))); } public static Map, List> getSignTexts() { @@ -61,7 +61,7 @@ public static void removeSign(int levelDepth, int x, int y) { public SignDisplay(Level level, int x, int y) { super(false, new Menu.Builder(true, 3, RelPos.CENTER) - .setPositioning(new Point(Screen.w, 6), RelPos.BOTTOM) + .setPositioning(new Point(Screen.w / 2, 6), RelPos.BOTTOM) .setMenuSize(new Dimension(MinicraftImage.boxWidth * (MAX_TEXT_LENGTH + 2), MinicraftImage.boxWidth * (MAX_ROW_COUNT + 2))) .setSelectable(false) .createMenu()); @@ -152,10 +152,10 @@ public void tick(InputHandler input) { } updateCaretAnimation(); - } else if (input.inputDown("CURSOR-LEFT")) { + } else if (input.inputPressed("CURSOR-LEFT")) { if (cursorX > 0) cursorX--; updateCaretAnimation(); - } else if (input.inputDown("CURSOR-RIGHT")) { + } else if (input.inputPressed("CURSOR-RIGHT")) { if (cursorX == rows.get(cursorY).length()) { // The end of row if (cursorY < rows.size() - 1) { // If it is not in the last row cursorX = 0; @@ -199,16 +199,18 @@ public void render(Screen screen) { } // Cursor rendering - int lineWidth = getLineWidthOfRow(cursorX, cursorY) * MinicraftImage.boxWidth; - int displayX = calculateDisplayX(cursorX) * MinicraftImage.boxWidth; - int displayY = calculateDisplayY(cursorX, cursorY) * MinicraftImage.boxWidth; - int lineBeginning = centeredX - lineWidth / 2; - int cursorX = lineBeginning + displayX; - int cursorY = bounds.getTop() + MinicraftImage.boxWidth + displayY; - int cursorRenderY = cursorY + MinicraftImage.boxWidth - 1; - for (int i = 0; i < MinicraftImage.boxWidth; i++) { // 1 pixel high and 8 pixel wide - int idx = cursorX + i + cursorRenderY; - screen.pixels[idx] = idx == Color.WHITE ? Color.BLACK : Color.WHITE; + if (caretShown) { + int lineWidth = getLineWidthOfRow(cursorX, cursorY) * MinicraftImage.boxWidth; + int displayX = calculateDisplayX(cursorX) * MinicraftImage.boxWidth; + int displayY = calculateDisplayY(cursorX, cursorY) * MinicraftImage.boxWidth; + int lineBeginning = centeredX - lineWidth / 2; + int cursorX = lineBeginning + displayX; + int cursorY = bounds.getTop() + MinicraftImage.boxWidth + displayY; + int cursorRenderY = cursorY + MinicraftImage.boxWidth - 2; + for (int i = 0; i < MinicraftImage.boxWidth; i++) { // 1 pixel high and 8 pixel wide + int idx = cursorX + i + cursorRenderY * Screen.w; + screen.pixels[idx] = screen.pixels[idx] == Color.WHITE ? Color.BLACK : Color.WHITE; + } } } @@ -218,13 +220,13 @@ private void updateCaretAnimation() { } private int calculateDisplayX(int x) { - return x > MAX_TEXT_LENGTH ? x % MAX_TEXT_LENGTH : x; + return x > MAX_TEXT_LENGTH ? x - (x - 1) / MAX_TEXT_LENGTH * MAX_TEXT_LENGTH : x; } private int getLineWidthOfRow(int x, int y) { int length = rows.get(y).length(); return (x == 0 ? MAX_TEXT_LENGTH : (x + MAX_TEXT_LENGTH - 1) / MAX_TEXT_LENGTH * MAX_TEXT_LENGTH) > length - ? length - (x - 1) / MAX_TEXT_LENGTH : MAX_TEXT_LENGTH; + ? length - (x - 1) / MAX_TEXT_LENGTH * MAX_TEXT_LENGTH : MAX_TEXT_LENGTH; } private int calculateDisplayY(int x, int y) { @@ -250,7 +252,7 @@ private boolean checkRowLineCapacity(int y) { private int calculateNumberOfOccupiedLinesOfRow(int y) { int length = rows.get(y).length(); - return length == 0 ? 1 : (length + MAX_TEXT_LENGTH - 1) / MAX_TEXT_LENGTH * MAX_TEXT_LENGTH; + return length == 0 ? 1 : (length + MAX_TEXT_LENGTH - 1) / MAX_TEXT_LENGTH; } private void insertChars(String chars) { @@ -311,7 +313,8 @@ else if (cursorX > 0) { public void render(Screen screen) { super.render(screen); Rectangle bounds = menus[0].getBounds(); - Font.draw(Localization.getLocalized("Use SHIFT-ENTER to confirm input."), screen, bounds.getLeft(), bounds.getBottom() + 8, Color.GRAY); + Font.drawCentered(Localization.getLocalized("Use SHIFT-ENTER to confirm input."), screen, bounds.getBottom() + 8, Color.GRAY); + editor.render(screen); } @Override diff --git a/src/client/java/minicraft/screen/SignDisplayMenu.java b/src/client/java/minicraft/screen/SignDisplayMenu.java index c56652baa..f8cbaea17 100644 --- a/src/client/java/minicraft/screen/SignDisplayMenu.java +++ b/src/client/java/minicraft/screen/SignDisplayMenu.java @@ -18,8 +18,9 @@ public class SignDisplayMenu extends Menu { public SignDisplayMenu(Level level, int x, int y) { super(new Menu.Builder(true, 3, RelPos.CENTER) - .setPositioning(new Point(Screen.w, 6), RelPos.BOTTOM) + .setPositioning(new Point(Screen.w / 2, 6), RelPos.BOTTOM) .setMenuSize(new Dimension(MinicraftImage.boxWidth * (SignDisplay.MAX_TEXT_LENGTH + 2), MinicraftImage.boxWidth * (SignDisplay.MAX_ROW_COUNT + 2))) + .setDisplayLength(4) .setSelectable(false) .createMenu()); this.levelDepth = level.depth; From 40a8bd435f936f02ab8661e96683670824270e32 Mon Sep 17 00:00:00 2001 From: BenCheung0422 <74168521+BenCheung0422@users.noreply.github.com> Date: Fri, 4 Aug 2023 21:12:01 +0800 Subject: [PATCH 06/13] Fix some sign edit and rendering problems --- src/client/java/minicraft/gfx/Color.java | 13 +++++++ .../java/minicraft/screen/SignDisplay.java | 35 +++++-------------- .../minicraft/screen/SignDisplayMenu.java | 2 +- 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/src/client/java/minicraft/gfx/Color.java b/src/client/java/minicraft/gfx/Color.java index cdc1e757d..e967749fe 100644 --- a/src/client/java/minicraft/gfx/Color.java +++ b/src/client/java/minicraft/gfx/Color.java @@ -173,6 +173,19 @@ protected static int[] decodeRGBColor(int rgbInt) { return new int[] {r, g, b}; } + /** + * Gets the lightness of the given 24-bit RGB color value. + * This is strictly calculated by L from RGB to HSL conversion. + * For other formula and method reference: https://stackoverflow.com/a/56678483. + * @return lightness, from 0 to 1 floating point number + */ + public static float getLightnessFromRGB(int color) { + int r = (color >> 16) & 0xFF; + int g = (color >> 8) & 0xFF; + int b = color & 0xFF; + return (Math.max(Math.max(r, g), b) + Math.min(Math.min(r, g), b)) / 510f; + } + /// This is for color testing. public static void main(String[] args) { int r, g, b; diff --git a/src/client/java/minicraft/screen/SignDisplay.java b/src/client/java/minicraft/screen/SignDisplay.java index 8398fac5f..327d02dd9 100644 --- a/src/client/java/minicraft/screen/SignDisplay.java +++ b/src/client/java/minicraft/screen/SignDisplay.java @@ -122,38 +122,21 @@ public void tick(InputHandler input) { // As lines are centered, the character above in rendering would not always be the one in indices. // The position is set to the beginning of line when the cursor moved upward or downward. } else if (input.inputPressed("CURSOR-UP")) { - if (cursorX > MAX_TEXT_LENGTH) { // This should be safe. - cursorX -= (cursorX % MAX_TEXT_LENGTH == 0 ? MAX_TEXT_LENGTH : cursorX % MAX_TEXT_LENGTH) + MAX_TEXT_LENGTH; - } else if (cursorY > 0) { - int length = rows.get(--cursorY).length(); - if (cursorX > 0 && cursorX % MAX_TEXT_LENGTH == 0) { // If the current position is at the end of line - cursorX = length; - } else { - if (length > 0 && (length % MAX_TEXT_LENGTH) == 0) { - cursorX += length - MAX_TEXT_LENGTH; - } else { - cursorX += length / MAX_TEXT_LENGTH * MAX_TEXT_LENGTH; - } - - if (cursorX > length) cursorX = length; // Collapses the spaces between the cursor and the end of row - } - } else { - cursorX = 0; + cursorX = 0; + if (cursorY > 0) { + cursorY--; } updateCaretAnimation(); } else if (input.inputPressed("CURSOR-DOWN")) { - if (cursorX / MAX_TEXT_LENGTH < rows.get(cursorY).length() / MAX_TEXT_LENGTH) { - cursorX += MAX_TEXT_LENGTH - cursorX % MAX_TEXT_LENGTH; - } else if (cursorY < rows.size() - 1) { - cursorX = 0; // It is always in the first line of the row, so it is always the beginning of the row. - } else { - cursorX = rows.get(cursorY).length(); - } - + cursorX = rows.get(cursorY < rows.size() - 1 ? ++cursorY : cursorY).length(); updateCaretAnimation(); } else if (input.inputPressed("CURSOR-LEFT")) { if (cursorX > 0) cursorX--; + else if (cursorY > 0) { + cursorX = rows.get(--cursorY).length(); + } + updateCaretAnimation(); } else if (input.inputPressed("CURSOR-RIGHT")) { if (cursorX == rows.get(cursorY).length()) { // The end of row @@ -209,7 +192,7 @@ public void render(Screen screen) { int cursorRenderY = cursorY + MinicraftImage.boxWidth - 2; for (int i = 0; i < MinicraftImage.boxWidth; i++) { // 1 pixel high and 8 pixel wide int idx = cursorX + i + cursorRenderY * Screen.w; - screen.pixels[idx] = screen.pixels[idx] == Color.WHITE ? Color.BLACK : Color.WHITE; + screen.pixels[idx] = Color.getLightnessFromRGB(screen.pixels[idx]) >= .5 ? Color.BLACK : Color.WHITE; } } } diff --git a/src/client/java/minicraft/screen/SignDisplayMenu.java b/src/client/java/minicraft/screen/SignDisplayMenu.java index f8cbaea17..b5846b7ac 100644 --- a/src/client/java/minicraft/screen/SignDisplayMenu.java +++ b/src/client/java/minicraft/screen/SignDisplayMenu.java @@ -17,7 +17,7 @@ public class SignDisplayMenu extends Menu { private final int levelDepth, x, y; public SignDisplayMenu(Level level, int x, int y) { - super(new Menu.Builder(true, 3, RelPos.CENTER) + super(new Menu.Builder(true, 0, RelPos.CENTER) .setPositioning(new Point(Screen.w / 2, 6), RelPos.BOTTOM) .setMenuSize(new Dimension(MinicraftImage.boxWidth * (SignDisplay.MAX_TEXT_LENGTH + 2), MinicraftImage.boxWidth * (SignDisplay.MAX_ROW_COUNT + 2))) .setDisplayLength(4) From a4d469cdac40a5bcda38d6d9dfea1f335c7b6916 Mon Sep 17 00:00:00 2001 From: BenCheung0422 <74168521+BenCheung0422@users.noreply.github.com> Date: Mon, 7 Aug 2023 20:18:28 +0800 Subject: [PATCH 07/13] Resolve SignDisplay OSK and cursor problems --- .../java/minicraft/screen/SignDisplay.java | 196 +++++++----------- 1 file changed, 77 insertions(+), 119 deletions(-) diff --git a/src/client/java/minicraft/screen/SignDisplay.java b/src/client/java/minicraft/screen/SignDisplay.java index 327d02dd9..cb970ba6c 100644 --- a/src/client/java/minicraft/screen/SignDisplay.java +++ b/src/client/java/minicraft/screen/SignDisplay.java @@ -1,5 +1,6 @@ package minicraft.screen; +import com.studiohartman.jamepad.ControllerButton; import minicraft.core.Game; import minicraft.core.io.ClipboardHandler; import minicraft.core.io.InputHandler; @@ -21,6 +22,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; public class SignDisplay extends Display { public static final int MAX_TEXT_LENGTH = 20; @@ -69,6 +71,9 @@ public SignDisplay(Level level, int x, int y) { this.x = x; this.y = y; editor = new SignEditor(getSign(levelDepth, x, y)); + onScreenKeyboardMenu = OnScreenKeyboardMenu.checkAndCreateMenu(); + if (onScreenKeyboardMenu != null) + onScreenKeyboardMenu.setVisible(false); } private class SignEditor { @@ -80,19 +85,12 @@ private class SignEditor { public SignEditor(@Nullable List lines) { if (lines != null) lines.forEach(l -> rows.add(new StringBuilder(l))); - if (rows.isEmpty()) rows.add(new StringBuilder()); + while (rows.size() < MAX_ROW_COUNT) + rows.add(new StringBuilder()); } public List getLines() { - ArrayList lines = new ArrayList<>(); - rows.forEach(r -> { - // Reference: https://www.baeldung.com/java-string-split-every-n-characters#using-the-stringsubstring-method - int length = r.length(); - for (int i = 0; i < length; i += MAX_TEXT_LENGTH) { - lines.add(r.substring(i, Math.min(length, i + MAX_TEXT_LENGTH))); - } - }); - return lines; + return rows.stream().map(StringBuilder::toString).collect(Collectors.toList()); } public void tick(InputHandler input) { @@ -103,63 +101,43 @@ public void tick(InputHandler input) { insertChars(input.getKeysTyped(null)); if (input.getKey("PAGE-UP").clicked) { - cursorX = 0; - cursorY = 0; + cursorX = rows.get(cursorY = 0).length(); updateCaretAnimation(); } else if (input.getKey("PAGE-DOWN").clicked) { - cursorY = rows.size() - 1; - cursorX = rows.get(cursorY).length(); + cursorX = rows.get(cursorY = rows.size() - 1).length(); updateCaretAnimation(); } else if (input.getKey("HOME").clicked) { - cursorX = (cursorX - 1) / MAX_TEXT_LENGTH * MAX_TEXT_LENGTH; // Rounding down + cursorX = 0; updateCaretAnimation(); } else if (input.getKey("END").clicked) { - cursorX = Math.min((cursorX + MAX_TEXT_LENGTH - 1) / MAX_TEXT_LENGTH * MAX_TEXT_LENGTH, rows.get(cursorY).length()); // Rounding up + cursorX = rows.get(cursorY).length(); updateCaretAnimation(); // Cursor navigating // As lines are centered, the character above in rendering would not always be the one in indices. - // The position is set to the beginning of line when the cursor moved upward or downward. + // The position is set to the end of line when the cursor moved upward or downward. } else if (input.inputPressed("CURSOR-UP")) { - cursorX = 0; - if (cursorY > 0) { - cursorY--; - } - + cursorX = rows.get(cursorY == 0 ? cursorY = rows.size() - 1 : --cursorY).length(); updateCaretAnimation(); - } else if (input.inputPressed("CURSOR-DOWN")) { - cursorX = rows.get(cursorY < rows.size() - 1 ? ++cursorY : cursorY).length(); + } else if (input.inputPressed("CURSOR-DOWN") || input.getKey("ENTER").clicked) { + cursorX = rows.get(cursorY == rows.size() - 1 ? cursorY = 0 : ++cursorY).length(); updateCaretAnimation(); } else if (input.inputPressed("CURSOR-LEFT")) { if (cursorX > 0) cursorX--; - else if (cursorY > 0) { - cursorX = rows.get(--cursorY).length(); - } - updateCaretAnimation(); } else if (input.inputPressed("CURSOR-RIGHT")) { - if (cursorX == rows.get(cursorY).length()) { // The end of row - if (cursorY < rows.size() - 1) { // If it is not in the last row - cursorX = 0; - cursorY++; - } - } else { - cursorX++; - } - + if (cursorX < rows.get(cursorY).length()) cursorX++; updateCaretAnimation(); // Clipboard operations } else if (input.getKey("CTRL-X").clicked) { cursorX = 0; - cursorY = 0; - clipboard.setClipboardContents(String.join("\n", rows)); - rows.clear(); - rows.add(new StringBuilder()); + clipboard.setClipboardContents(rows.get(cursorY).toString()); + rows.set(cursorY, new StringBuilder()); updateCaretAnimation(); } else if (input.getKey("CTRL-C").clicked) { - clipboard.setClipboardContents(String.join("\n", rows)); + clipboard.setClipboardContents(rows.get(cursorY).toString()); updateCaretAnimation(); } else if (input.getKey("CTRL-V").clicked) { insertChars(clipboard.getClipboardContents()); @@ -171,28 +149,30 @@ public void render(Screen screen) { int yPos = bounds.getTop() + MinicraftImage.boxWidth; // Upper border int centeredX = bounds.getLeft() + bounds.getWidth() / 2; for (StringBuilder row : rows) { - // See #getLines - String r = row.toString(); - int length = r.length(); - for (int j = 0; j < length; j += MAX_TEXT_LENGTH) { // For each line - Font.drawCentered(r.substring(j, Math.min(length, j + MAX_TEXT_LENGTH)), screen, yPos, Color.WHITE); - //noinspection SuspiciousNameCombination - yPos += MinicraftImage.boxWidth; - } + Font.drawCentered(row.toString(), screen, yPos, Color.WHITE); + //noinspection SuspiciousNameCombination + yPos += MinicraftImage.boxWidth; } // Cursor rendering if (caretShown) { - int lineWidth = getLineWidthOfRow(cursorX, cursorY) * MinicraftImage.boxWidth; - int displayX = calculateDisplayX(cursorX) * MinicraftImage.boxWidth; - int displayY = calculateDisplayY(cursorX, cursorY) * MinicraftImage.boxWidth; + int lineWidth = rows.get(cursorY).length() * MinicraftImage.boxWidth; + int displayX = cursorX * MinicraftImage.boxWidth; + int displayY = cursorY * MinicraftImage.boxWidth; int lineBeginning = centeredX - lineWidth / 2; int cursorX = lineBeginning + displayX; int cursorY = bounds.getTop() + MinicraftImage.boxWidth + displayY; - int cursorRenderY = cursorY + MinicraftImage.boxWidth - 2; - for (int i = 0; i < MinicraftImage.boxWidth; i++) { // 1 pixel high and 8 pixel wide - int idx = cursorX + i + cursorRenderY * Screen.w; - screen.pixels[idx] = Color.getLightnessFromRGB(screen.pixels[idx]) >= .5 ? Color.BLACK : Color.WHITE; + if (this.cursorX == rows.get(this.cursorY).length()) { // Replace cursor + int cursorRenderY = cursorY + MinicraftImage.boxWidth - 1; + for (int i = 0; i < MinicraftImage.boxWidth; i++) { // 1 pixel high and 8 pixel wide + int idx = cursorX + i + cursorRenderY * Screen.w; + screen.pixels[idx] = Color.getLightnessFromRGB(screen.pixels[idx]) >= .5 ? Color.BLACK : Color.WHITE; + } + } else { // Insert cursor + for (int i = 0; i < MinicraftImage.boxWidth; i++) { // 8 pixel high and 1 pixel wide + int idx = cursorX + (cursorY + i) * Screen.w; + screen.pixels[idx] = Color.getLightnessFromRGB(screen.pixels[idx]) >= .5 ? Color.BLACK : Color.WHITE; + } } } } @@ -202,42 +182,6 @@ private void updateCaretAnimation() { caretFrameCountDown = 120; } - private int calculateDisplayX(int x) { - return x > MAX_TEXT_LENGTH ? x - (x - 1) / MAX_TEXT_LENGTH * MAX_TEXT_LENGTH : x; - } - - private int getLineWidthOfRow(int x, int y) { - int length = rows.get(y).length(); - return (x == 0 ? MAX_TEXT_LENGTH : (x + MAX_TEXT_LENGTH - 1) / MAX_TEXT_LENGTH * MAX_TEXT_LENGTH) > length - ? length - (x - 1) / MAX_TEXT_LENGTH * MAX_TEXT_LENGTH : MAX_TEXT_LENGTH; - } - - private int calculateDisplayY(int x, int y) { - int count = 0; - for (int i = 0; i <= y; i++) { - if (i != y) count += calculateNumberOfOccupiedLinesOfRow(i); - else count += (x - 1) / MAX_TEXT_LENGTH; // A new line is regarded when the current line exceeds MAX_TEST_LENGTH. - } - - return count; - } - - private boolean checkNewLineAvailable() { - int maxY = rows.size() - 1; - return calculateDisplayY(rows.get(maxY).length(), maxY) < MAX_ROW_COUNT - 1; - } - - private boolean checkRowLineCapacity(int y) { - int len = rows.get(y).length(); - // If the current row is not enough to fill in a line or the existing new line - return len < MAX_TEXT_LENGTH || len % MAX_TEXT_LENGTH != 0; - } - - private int calculateNumberOfOccupiedLinesOfRow(int y) { - int length = rows.get(y).length(); - return length == 0 ? 1 : (length + MAX_TEXT_LENGTH - 1) / MAX_TEXT_LENGTH; - } - private void insertChars(String chars) { chars = InputHandler.handleBackspaceChars(chars, true); // Reduce the number of unnecessary operations. if (chars.isEmpty()) return; @@ -257,34 +201,17 @@ private void insertChars(String chars) { */ private boolean insertChar(char c) { if (c == '\b') { // Backspace - if (cursorX == 0 && cursorY == 0) return true; // No effect; valid behaviour; handled - else if (cursorX > 0) { + if (cursorX == 0) return true; // No effect; valid behaviour; handled + else { // cursorX > 0 rows.get(cursorY).deleteCharAt(--cursorX); // Remove the char in front of the cursor. - } else { // cursorY > 0 && cursorX == 0 - // Combining the current row to the row above. Remove the current line and decrement cursorY by 1. - rows.get(cursorY - 1).append(rows.remove(cursorY--)); } return true; // A backspace is always not limited by the line count limit, and it could reduce characters when appropriate. } else if (c == '\n') { // Line break - StringBuilder curRow = rows.get(cursorY); - int rowLen = curRow.length(); - // If the row occupies more than 1 line and the string of the cursor until the end of line plus the last line - // does not contain enough chars to require a new line, so that the line break does not affect the line count. - // The cursor should be within the row so that it does not create an empty new line, which breaks the case mentioned above. - // One of the cases is that the cursor is at the end of line. - if (rowLen > MAX_TEXT_LENGTH && cursorX > 0 && cursorX < rowLen && - cursorX <= rowLen - rowLen % MAX_TEXT_LENGTH && // The cursor should be in the line before the last line. - MAX_TEXT_LENGTH - cursorX + rowLen % MAX_TEXT_LENGTH <= MAX_TEXT_LENGTH || - checkNewLineAvailable()) { // For other cases, a new line would always be required. - rows.add(++cursorY, new StringBuilder(curRow.substring(cursorX))); // Create new builder from the split point. - curRow.delete(cursorX, rowLen); // Remove string part starts with the split point. - cursorX = 0; // A pointer to the new line after the break. - return true; - } else return false; // No line break; the char is discarded; no effect; unhandled + return true; // No effect; the char is ignored; handled } else { // If the current line has spaces to expand, or else a new line would be required. - if (checkRowLineCapacity(cursorY) || checkNewLineAvailable()) { + if (rows.get(cursorY).length() < MAX_TEXT_LENGTH) { rows.get(cursorY).insert(cursorX++, c); return true; } else return false; // No more chars are accepted to expand at the current cursor position. @@ -292,22 +219,53 @@ else if (cursorX > 0) { } } + OnScreenKeyboardMenu onScreenKeyboardMenu; + @Override public void render(Screen screen) { super.render(screen); Rectangle bounds = menus[0].getBounds(); Font.drawCentered(Localization.getLocalized("Use SHIFT-ENTER to confirm input."), screen, bounds.getBottom() + 8, Color.GRAY); editor.render(screen); + if (onScreenKeyboardMenu != null) + onScreenKeyboardMenu.render(screen); } @Override public void tick(InputHandler input) { - if (input.inputPressed("exit") || input.getKey("SHIFT-ENTER").clicked) { - updateSign(levelDepth, x, y, editor.getLines()); - Game.exitDisplay(); - return; + boolean acted = false; // Checks if typing action is needed to be handled. + boolean mainMethod = false; + if (onScreenKeyboardMenu == null || !onScreenKeyboardMenu.isVisible()) { + if (input.inputPressed("exit") || input.getKey("SHIFT-ENTER").clicked) { + updateSign(levelDepth, x, y, editor.getLines()); + Game.exitDisplay(); + return; + } + + mainMethod = true; + } else { + try { + onScreenKeyboardMenu.tick(input); + } catch (OnScreenKeyboardMenu.OnScreenKeyboardMenuTickActionCompleted | + OnScreenKeyboardMenu.OnScreenKeyboardMenuBackspaceButtonActed e) { + acted = true; + } + + if (acted) + editor.tick(input); + + if (input.getKey("exit").clicked || input.getKey("SHIFT-ENTER").clicked) { // Should not listen button press + updateSign(levelDepth, x, y, editor.getLines()); + Game.exitDisplay(); + return; + } + + if (input.buttonPressed(ControllerButton.X)) { // Hide the keyboard. + onScreenKeyboardMenu.setVisible(!onScreenKeyboardMenu.isVisible()); + } } - editor.tick(input); + if (mainMethod || !onScreenKeyboardMenu.isVisible()) + editor.tick(input); } } From 42abfbb3e68680997051f9ab8b4fe47e3f3804e0 Mon Sep 17 00:00:00 2001 From: BenCheung0422 <74168521+BenCheung0422@users.noreply.github.com> Date: Mon, 5 Feb 2024 23:14:06 +0800 Subject: [PATCH 08/13] Resolve post-merge errors --- src/client/java/minicraft/item/SignItem.java | 2 +- .../java/minicraft/screen/SignDisplay.java | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/client/java/minicraft/item/SignItem.java b/src/client/java/minicraft/item/SignItem.java index 645878bde..f6a88d9e6 100644 --- a/src/client/java/minicraft/item/SignItem.java +++ b/src/client/java/minicraft/item/SignItem.java @@ -24,7 +24,7 @@ public static ArrayList getAllInstances() { private SignItem() { this(1); } private SignItem(int count) { - super("Sign", sprite, count, "", "dirt", "Wood Planks", "Stone Bricks", "Obsidian", "Wool", "Red Wool", "Blue Wool", "Green Wool", "Yellow Wool", "Black Wool", "grass", "sand"); + super("Sign", sprite, count, null, "dirt", "Wood Planks", "Stone Bricks", "Obsidian", "Wool", "Red Wool", "Blue Wool", "Green Wool", "Yellow Wool", "Black Wool", "grass", "sand"); } public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { diff --git a/src/client/java/minicraft/screen/SignDisplay.java b/src/client/java/minicraft/screen/SignDisplay.java index cb970ba6c..b434c5d09 100644 --- a/src/client/java/minicraft/screen/SignDisplay.java +++ b/src/client/java/minicraft/screen/SignDisplay.java @@ -100,17 +100,17 @@ public void tick(InputHandler input) { } insertChars(input.getKeysTyped(null)); - if (input.getKey("PAGE-UP").clicked) { + if (input.getMappedKey("PAGE-UP").isClicked()) { cursorX = rows.get(cursorY = 0).length(); updateCaretAnimation(); - } else if (input.getKey("PAGE-DOWN").clicked) { + } else if (input.getMappedKey("PAGE-DOWN").isClicked()) { cursorX = rows.get(cursorY = rows.size() - 1).length(); updateCaretAnimation(); - } else if (input.getKey("HOME").clicked) { + } else if (input.getMappedKey("HOME").isClicked()) { cursorX = 0; updateCaretAnimation(); - } else if (input.getKey("END").clicked) { + } else if (input.getMappedKey("END").isClicked()) { cursorX = rows.get(cursorY).length(); updateCaretAnimation(); @@ -120,7 +120,7 @@ public void tick(InputHandler input) { } else if (input.inputPressed("CURSOR-UP")) { cursorX = rows.get(cursorY == 0 ? cursorY = rows.size() - 1 : --cursorY).length(); updateCaretAnimation(); - } else if (input.inputPressed("CURSOR-DOWN") || input.getKey("ENTER").clicked) { + } else if (input.inputPressed("CURSOR-DOWN") || input.getMappedKey("ENTER").isClicked()) { cursorX = rows.get(cursorY == rows.size() - 1 ? cursorY = 0 : ++cursorY).length(); updateCaretAnimation(); } else if (input.inputPressed("CURSOR-LEFT")) { @@ -131,15 +131,15 @@ public void tick(InputHandler input) { updateCaretAnimation(); // Clipboard operations - } else if (input.getKey("CTRL-X").clicked) { + } else if (input.getMappedKey("CTRL-X").isClicked()) { cursorX = 0; clipboard.setClipboardContents(rows.get(cursorY).toString()); rows.set(cursorY, new StringBuilder()); updateCaretAnimation(); - } else if (input.getKey("CTRL-C").clicked) { + } else if (input.getMappedKey("CTRL-C").isClicked()) { clipboard.setClipboardContents(rows.get(cursorY).toString()); updateCaretAnimation(); - } else if (input.getKey("CTRL-V").clicked) { + } else if (input.getMappedKey("CTRL-V").isClicked()) { insertChars(clipboard.getClipboardContents()); } } @@ -236,7 +236,7 @@ public void tick(InputHandler input) { boolean acted = false; // Checks if typing action is needed to be handled. boolean mainMethod = false; if (onScreenKeyboardMenu == null || !onScreenKeyboardMenu.isVisible()) { - if (input.inputPressed("exit") || input.getKey("SHIFT-ENTER").clicked) { + if (input.inputPressed("exit") || input.getMappedKey("SHIFT-ENTER").isClicked()) { updateSign(levelDepth, x, y, editor.getLines()); Game.exitDisplay(); return; @@ -254,7 +254,7 @@ public void tick(InputHandler input) { if (acted) editor.tick(input); - if (input.getKey("exit").clicked || input.getKey("SHIFT-ENTER").clicked) { // Should not listen button press + if (input.getMappedKey("exit").isClicked() || input.getMappedKey("SHIFT-ENTER").isClicked()) { // Should not listen button press updateSign(levelDepth, x, y, editor.getLines()); Game.exitDisplay(); return; From 3e961ca13a396d96134afb68f0b48e090788eaa7 Mon Sep 17 00:00:00 2001 From: BenCheung0422 <74168521+BenCheung0422@users.noreply.github.com> Date: Fri, 9 Feb 2024 04:21:53 +0800 Subject: [PATCH 09/13] Add SignTileEntity in place of sign tile bumping --- src/client/java/minicraft/level/Level.java | 1 + .../java/minicraft/level/tile/SignTile.java | 20 ++--------- .../java/minicraft/level/tile/Tile.java | 2 ++ .../level/tile/entity/SignTileEntity.java | 35 +++++++++++++++++++ src/client/java/minicraft/saveload/Load.java | 7 ++++ 5 files changed, 48 insertions(+), 17 deletions(-) create mode 100644 src/client/java/minicraft/level/tile/entity/SignTileEntity.java diff --git a/src/client/java/minicraft/level/Level.java b/src/client/java/minicraft/level/Level.java index fbdeae189..bc8e38e6a 100644 --- a/src/client/java/minicraft/level/Level.java +++ b/src/client/java/minicraft/level/Level.java @@ -583,6 +583,7 @@ public void setTile(int x, int y, Tile t, int dataVal) { tiles[x + y * w] = t.id; data[x + y * w] = (short) dataVal; + t.onTileSet(this, x, y); } public int getData(int x, int y) { diff --git a/src/client/java/minicraft/level/tile/SignTile.java b/src/client/java/minicraft/level/tile/SignTile.java index 55858f98f..36f1ae294 100644 --- a/src/client/java/minicraft/level/tile/SignTile.java +++ b/src/client/java/minicraft/level/tile/SignTile.java @@ -12,13 +12,12 @@ import minicraft.gfx.SpriteLinker; import minicraft.item.Item; import minicraft.item.Items; -import minicraft.item.PowerGloveItem; import minicraft.item.ToolItem; import minicraft.item.ToolType; import minicraft.level.Level; +import minicraft.level.tile.entity.SignTileEntity; import minicraft.screen.SignDisplay; import minicraft.screen.SignDisplayMenu; -import org.jetbrains.annotations.Nullable; import org.tinylog.Logger; public class SignTile extends Tile { @@ -81,20 +80,7 @@ public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction at } @Override - public void steppedOn(Level level, int xt, int yt, Entity entity) { - if (entity instanceof Player) { - if (Renderer.signDisplayMenu == null || Renderer.signDisplayMenu.differsFrom(level.depth, xt, yt)) { - Renderer.signDisplayMenu = new SignDisplayMenu(level, xt, yt); - } - } - } - - @Override - public void steppedOut(Level level, int xt, int yt, Entity entity) { - if (entity instanceof Player) { - if (Renderer.signDisplayMenu != null && Renderer.signDisplayMenu.matches(level.depth, xt, yt)) { - Renderer.signDisplayMenu = null; - } - } + public void onTileSet(Level level, int x, int y) { + level.add(new SignTileEntity(), x, y, true); } } diff --git a/src/client/java/minicraft/level/tile/Tile.java b/src/client/java/minicraft/level/tile/Tile.java index 0efac4f56..dda2fc706 100644 --- a/src/client/java/minicraft/level/tile/Tile.java +++ b/src/client/java/minicraft/level/tile/Tile.java @@ -75,6 +75,8 @@ public boolean maySpawn() { return maySpawn; } + public void onTileSet(Level level, int x, int y) {} + /** * Returns if the player can walk on it, overrides in sub-classes */ diff --git a/src/client/java/minicraft/level/tile/entity/SignTileEntity.java b/src/client/java/minicraft/level/tile/entity/SignTileEntity.java new file mode 100644 index 000000000..719c7e7e5 --- /dev/null +++ b/src/client/java/minicraft/level/tile/entity/SignTileEntity.java @@ -0,0 +1,35 @@ +package minicraft.level.tile.entity; + +import minicraft.core.Game; +import minicraft.core.Renderer; +import minicraft.entity.Entity; +import minicraft.gfx.Screen; +import minicraft.screen.SignDisplayMenu; + +public class SignTileEntity extends Entity { + public SignTileEntity() { + super(8, 8); + } + + @Override + public void render(Screen screen) {} + + @Override + public boolean isSolid() { + return false; + } + + @Override + public void tick() { + int xt = x >> 4, yt = y >> 4; + if (Game.player.x >> 4 == xt && Game.player.y >> 4 == yt) { + if (Renderer.signDisplayMenu == null || Renderer.signDisplayMenu.differsFrom(level.depth, xt, yt)) { + Renderer.signDisplayMenu = new SignDisplayMenu(level, xt, yt); + } + } else { + if (Renderer.signDisplayMenu != null && Renderer.signDisplayMenu.matches(level.depth, xt, yt)) { + Renderer.signDisplayMenu = null; + } + } + } +} diff --git a/src/client/java/minicraft/saveload/Load.java b/src/client/java/minicraft/saveload/Load.java index d9e8d034a..5dedd6dbc 100644 --- a/src/client/java/minicraft/saveload/Load.java +++ b/src/client/java/minicraft/saveload/Load.java @@ -683,6 +683,13 @@ private void loadWorld(String filename) { curLevel.tiles = tiles; curLevel.data = tdata; + // Tile initialization + for (int x = 0; x < curLevel.w; ++x) { + for (int y = 0; y < curLevel.h; ++y) { + Tiles.get(curLevel.tiles[x + y * curLevel.w]).onTileSet(curLevel, x, y); + } + } + if (Logging.logLevel) curLevel.printTileLocs(Tiles.get("Stairs Down")); if (parent == null) continue; From 5d7df9a9f8cf43a29ec045ecfcb03d992c5fadce Mon Sep 17 00:00:00 2001 From: BenCheung0422 <74168521+BenCheung0422@users.noreply.github.com> Date: Sat, 17 Feb 2024 02:18:37 +0800 Subject: [PATCH 10/13] Remove SHIFT-[S|W] debugging keys --- src/client/java/minicraft/core/Updater.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/client/java/minicraft/core/Updater.java b/src/client/java/minicraft/core/Updater.java index 70dacc202..3db1c7268 100644 --- a/src/client/java/minicraft/core/Updater.java +++ b/src/client/java/minicraft/core/Updater.java @@ -92,14 +92,6 @@ static void updateFullscreen() { // In the end, calls menu.tick() if there's a menu, or level.tick() if no menu. public static void tick() { - // Quick Level change: move the player for -1, or 1 levels - if (isMode("minicraft.settings.mode.creative") && input.getMappedKey("SHIFT-S").isClicked()) { - Game.setDisplay(new LevelTransitionDisplay(-1)); - - } else if (isMode("minicraft.settings.mode.creative") && input.getMappedKey("SHIFT-W").isClicked()) { - Game.setDisplay(new LevelTransitionDisplay(1)); - } - if (input.getMappedKey("FULLSCREEN").isClicked()) { Updater.FULLSCREEN = !Updater.FULLSCREEN; Updater.updateFullscreen(); From 1ffa8f64ae1b1bbc2851c3a250c42103668f7cc3 Mon Sep 17 00:00:00 2001 From: BenCheung0422 <74168521+BenCheung0422@users.noreply.github.com> Date: Sun, 25 Feb 2024 22:30:58 +0800 Subject: [PATCH 11/13] Add back SHIFT-[S|W] debugging keys --- src/client/java/minicraft/core/Updater.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/client/java/minicraft/core/Updater.java b/src/client/java/minicraft/core/Updater.java index 3db1c7268..9e9e92097 100644 --- a/src/client/java/minicraft/core/Updater.java +++ b/src/client/java/minicraft/core/Updater.java @@ -217,6 +217,14 @@ public static void tick() { // For debugging only { + // Quick Level change: move the player for -1, or 1 levels + if (isMode("minicraft.settings.mode.creative") && input.getMappedKey("SHIFT-S").isClicked()) { + Game.setDisplay(new LevelTransitionDisplay(-1)); + + } else if (isMode("minicraft.settings.mode.creative") && input.getMappedKey("SHIFT-W").isClicked()) { + Game.setDisplay(new LevelTransitionDisplay(1)); + } + if (input.getMappedKey("F3-L").isClicked()) { // Print all players on all levels, and their coordinates. Logging.WORLD.info("Printing players on all levels."); From 20365ff7e833f2c8c58ef958905eea7f534aebe2 Mon Sep 17 00:00:00 2001 From: Litorom Date: Mon, 11 Mar 2024 13:36:22 -0400 Subject: [PATCH 12/13] Fixed Conflicts --- src/client/java/minicraft/item/SignItem.java | 5 ++++- .../java/minicraft/level/tile/SignTile.java | 18 +++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/client/java/minicraft/item/SignItem.java b/src/client/java/minicraft/item/SignItem.java index f6a88d9e6..f2a0ca269 100644 --- a/src/client/java/minicraft/item/SignItem.java +++ b/src/client/java/minicraft/item/SignItem.java @@ -15,6 +15,9 @@ public class SignItem extends TileItem { private static final SpriteLinker.LinkedSprite sprite = new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Item, "sign"); + private static final String[] solidTiles = { "dirt", "Wood Planks", "Stone Bricks", "Obsidian", "Wool", "Red Wool", "Blue Wool", + "Green Wool", "Yellow Wool", "Black Wool", "grass", "sand", "path", "ornate stone", "ornate obsidian" }; + public static ArrayList getAllInstances() { ArrayList items = new ArrayList<>(); @@ -24,7 +27,7 @@ public static ArrayList getAllInstances() { private SignItem() { this(1); } private SignItem(int count) { - super("Sign", sprite, count, null, "dirt", "Wood Planks", "Stone Bricks", "Obsidian", "Wool", "Red Wool", "Blue Wool", "Green Wool", "Yellow Wool", "Black Wool", "grass", "sand"); + super("Sign", sprite, count, null, solidTiles); } public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { diff --git a/src/client/java/minicraft/level/tile/SignTile.java b/src/client/java/minicraft/level/tile/SignTile.java index 36f1ae294..3823604ca 100644 --- a/src/client/java/minicraft/level/tile/SignTile.java +++ b/src/client/java/minicraft/level/tile/SignTile.java @@ -42,9 +42,21 @@ public static SignTile getSignTile(Tile onTile) { private SignTile(Tile onType) { super("Sign "+ onType.name, sprite); this.onType = onType; - this.connectsToSand = onType.connectsToSand; - this.connectsToGrass = onType.connectsToGrass; - this.connectsToFluid = onType.connectsToFluid; + } + + @Override + public boolean connectsToSand(Level level, int x, int y) { + return onType.connectsToSand(level, x, y);//Tiles.get((short) level.getData(x, y)).connectsToSand(level, x, y); + } + + @Override + public boolean connectsToFluid(Level level, int x, int y) { + return onType.connectsToFluid(level, x, y);//Tiles.get((short) level.getData(x, y)).connectsToFluid(level, x, y); + } + + @Override + public boolean connectsToGrass(Level level, int x, int y) { + return onType.connectsToGrass(level, x, y);//Tiles.get((short) level.getData(x, y)).connectsToGrass(level, x, y); } public void render(Screen screen, Level level, int x, int y) { From 50b59bb48e9ae9f4e869cc04090009215cd1e49a Mon Sep 17 00:00:00 2001 From: BenCheung0422 <74168521+BenCheung0422@users.noreply.github.com> Date: Thu, 28 Mar 2024 22:28:59 +0800 Subject: [PATCH 13/13] Update Sign to have similar mechanisms as Torch --- src/client/java/minicraft/entity/Entity.java | 5 --- src/client/java/minicraft/item/Items.java | 1 - src/client/java/minicraft/item/SignItem.java | 45 ------------------- src/client/java/minicraft/item/TileItem.java | 5 +++ .../java/minicraft/level/tile/SignTile.java | 38 +++++----------- .../java/minicraft/level/tile/Tile.java | 3 -- .../java/minicraft/level/tile/Tiles.java | 1 + 7 files changed, 18 insertions(+), 80 deletions(-) delete mode 100644 src/client/java/minicraft/item/SignItem.java diff --git a/src/client/java/minicraft/entity/Entity.java b/src/client/java/minicraft/entity/Entity.java index f0d1ff16b..e4720b59b 100644 --- a/src/client/java/minicraft/entity/Entity.java +++ b/src/client/java/minicraft/entity/Entity.java @@ -162,9 +162,6 @@ public boolean interact(Player player, @Nullable Item item, Direction attackDir) public boolean move(int xd, int yd) { if (Updater.saving || (xd == 0 && yd == 0)) return true; // Pretend that it kept moving - int prevXt = x >> 4; - int prevYt = y >> 4; - boolean stopped = true; // Used to check if the entity has BEEN stopped, COMPLETELY; below checks for a lack of collision. //noinspection RedundantIfStatement if (moveX(xd)) stopped = false; // Becomes false if horizontal movement was successful. @@ -172,8 +169,6 @@ public boolean move(int xd, int yd) { if (!stopped) { int xt = x >> 4; // The x tile coordinate that the entity is standing on. int yt = y >> 4; // The y tile coordinate that the entity is standing on. - if (prevXt != xt || prevYt != yt) - level.getTile(prevXt, prevYt).steppedOut(level, prevXt, prevYt, this); level.getTile(xt, yt).steppedOn(level, xt, yt, this); // Calls the steppedOn() method in a tile's class. (used for tiles like sand (footprints) or lava (burning)) } return !stopped; diff --git a/src/client/java/minicraft/item/Items.java b/src/client/java/minicraft/item/Items.java index 0d471827d..1cd9a1860 100644 --- a/src/client/java/minicraft/item/Items.java +++ b/src/client/java/minicraft/item/Items.java @@ -44,7 +44,6 @@ private static void addAll(ArrayList items) { addAll(SummonItem.getAllInstances()); addAll(HeartItem.getAllInstances()); addAll(WateringCanItem.getAllInstances()); - addAll(SignItem.getAllInstances()); } public static ArrayList getAll() { diff --git a/src/client/java/minicraft/item/SignItem.java b/src/client/java/minicraft/item/SignItem.java deleted file mode 100644 index f2a0ca269..000000000 --- a/src/client/java/minicraft/item/SignItem.java +++ /dev/null @@ -1,45 +0,0 @@ -package minicraft.item; - -import java.util.ArrayList; - -import minicraft.core.Game; -import minicraft.entity.Direction; -import minicraft.entity.mob.Player; -import minicraft.gfx.Sprite; -import minicraft.gfx.SpriteLinker; -import minicraft.level.Level; -import minicraft.level.tile.SignTile; -import minicraft.level.tile.Tile; -import minicraft.screen.SignDisplay; -import org.jetbrains.annotations.NotNull; - -public class SignItem extends TileItem { - private static final SpriteLinker.LinkedSprite sprite = new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Item, "sign"); - private static final String[] solidTiles = { "dirt", "Wood Planks", "Stone Bricks", "Obsidian", "Wool", "Red Wool", "Blue Wool", - "Green Wool", "Yellow Wool", "Black Wool", "grass", "sand", "path", "ornate stone", "ornate obsidian" }; - - - public static ArrayList getAllInstances() { - ArrayList items = new ArrayList<>(); - items.add(new SignItem()); - return items; - } - - private SignItem() { this(1); } - private SignItem(int count) { - super("Sign", sprite, count, null, solidTiles); - } - - public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { - if (validTiles.contains(tile.name)) { - level.setTile(xt, yt, SignTile.getSignTile(tile)); - Game.setDisplay(new SignDisplay(level, xt, yt)); - return super.interactOn(true); - } - return super.interactOn(false); - } - - public @NotNull SignItem copy() { - return new SignItem(count); - } -} diff --git a/src/client/java/minicraft/item/TileItem.java b/src/client/java/minicraft/item/TileItem.java index c8298e323..24973aea3 100644 --- a/src/client/java/minicraft/item/TileItem.java +++ b/src/client/java/minicraft/item/TileItem.java @@ -12,6 +12,7 @@ import minicraft.level.tile.Tile; import minicraft.level.tile.Tiles; import minicraft.screen.AchievementsDisplay; +import minicraft.screen.SignDisplay; import minicraft.util.AdvancementElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -77,6 +78,10 @@ protected static ArrayList getAllInstances() { items.add(new TileItem("Grass Seeds", new LinkedSprite(SpriteType.Item, "seed"), new TileModel("grass"), "dirt")); items.add(new TileItem("Torch", new LinkedSprite(SpriteType.Item, "torch"), new TileModel("Torch", placeOverWithID), solidTiles)); + items.add(new TileItem("Sign", new LinkedSprite(SpriteType.Item, "sign"), new TileModel("Sign", (model1, target, level, xt, yt, player, attackDir) -> { + Game.setDisplay(new SignDisplay(level, xt, yt)); + return placeOverWithID.getTileData(model1, target, level, xt, yt, player, attackDir); + }), solidTiles)); // Creative mode available tiles: items.add(new TileItem("Farmland", SpriteLinker.missingTexture(SpriteType.Item), new TileModel("farmland"), "dirt", "grass", "hole")); diff --git a/src/client/java/minicraft/level/tile/SignTile.java b/src/client/java/minicraft/level/tile/SignTile.java index 3823604ca..88fb97ff5 100644 --- a/src/client/java/minicraft/level/tile/SignTile.java +++ b/src/client/java/minicraft/level/tile/SignTile.java @@ -18,59 +18,45 @@ import minicraft.level.tile.entity.SignTileEntity; import minicraft.screen.SignDisplay; import minicraft.screen.SignDisplayMenu; +import minicraft.util.AdvancementElement; import org.tinylog.Logger; public class SignTile extends Tile { - private static final SpriteAnimation sprite = new SpriteAnimation(SpriteLinker.SpriteType.Tile, "sign"); - - private final Tile onType; - - public static SignTile getSignTile(Tile onTile) { - int id = onTile.id & 0xFFFF; - if(id < 16384) id += 16384; - else Logger.tag("SignTile").info("Tried to place torch on torch or sign tile..."); - - if(Tiles.containsTile(id)) { - return (SignTile)Tiles.get(id); - } else { - SignTile tile = new SignTile(onTile); - Tiles.add(id, tile); - return tile; - } - } - - private SignTile(Tile onType) { - super("Sign "+ onType.name, sprite); - this.onType = onType; + protected SignTile() { + super("Sign", new SpriteAnimation(SpriteLinker.SpriteType.Tile, "sign")); } @Override public boolean connectsToSand(Level level, int x, int y) { - return onType.connectsToSand(level, x, y);//Tiles.get((short) level.getData(x, y)).connectsToSand(level, x, y); + return Tiles.get((short) level.getData(x, y)).connectsToSand(level, x, y); } @Override public boolean connectsToFluid(Level level, int x, int y) { - return onType.connectsToFluid(level, x, y);//Tiles.get((short) level.getData(x, y)).connectsToFluid(level, x, y); + return Tiles.get((short) level.getData(x, y)).connectsToFluid(level, x, y); } @Override public boolean connectsToGrass(Level level, int x, int y) { - return onType.connectsToGrass(level, x, y);//Tiles.get((short) level.getData(x, y)).connectsToGrass(level, x, y); + return Tiles.get((short) level.getData(x, y)).connectsToGrass(level, x, y); } public void render(Screen screen, Level level, int x, int y) { - onType.render(screen, level, x, y); + Tiles.get((short) level.getData(x, y)).render(screen, level, x, y); sprite.render(screen, level, x, y); } public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { if (item != null) { if (item instanceof ToolItem && ((ToolItem) item).type == ToolType.Axe) { - level.setTile(xt, yt, this.onType); + int data = level.getData(xt, yt); + level.setTile(xt, yt, Tiles.get((short) data)); SignDisplay.removeSign(level.depth, xt, yt); Sound.play("monsterhurt"); level.dropItem(xt*16+8, yt*16+8, Items.get("Sign")); + AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( + new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( + item, this, data, xt, yt, level.depth)); return true; } } else { // TODO Add a way to lock signs diff --git a/src/client/java/minicraft/level/tile/Tile.java b/src/client/java/minicraft/level/tile/Tile.java index 0cdf4948a..05873f53a 100644 --- a/src/client/java/minicraft/level/tile/Tile.java +++ b/src/client/java/minicraft/level/tile/Tile.java @@ -133,9 +133,6 @@ public boolean tick(Level level, int xt, int yt) { public void steppedOn(Level level, int xt, int yt, Entity entity) { } - /** What happens when you have just stepped out the tile (ex: sign) */ - public void steppedOut(Level level, int xt, int yt, Entity entity) {} - /** * Called when you hit an item on a tile (ex: Pickaxe on rock). * diff --git a/src/client/java/minicraft/level/tile/Tiles.java b/src/client/java/minicraft/level/tile/Tiles.java index dd4f6d4cb..0f7a481e9 100644 --- a/src/client/java/minicraft/level/tile/Tiles.java +++ b/src/client/java/minicraft/level/tile/Tiles.java @@ -84,6 +84,7 @@ public static void initTileList() { tiles.put((short) 55, new FenceTile(Tile.Material.Stone)); tiles.put((short) 56, new FenceTile(Tile.Material.Obsidian)); tiles.put((short) 57, new TorchTile()); + tiles.put((short) 58, new SignTile()); // WARNING: don't use this tile for anything! tiles.put((short) 255, new ConnectTile());