package cz.jzitnik.tui; import cz.jzitnik.game.entities.Block; import cz.jzitnik.game.Game; import cz.jzitnik.game.sprites.Steve; import cz.jzitnik.game.blocks.Chest; import cz.jzitnik.game.blocks.Furnace; import cz.jzitnik.game.ui.Healthbar; import cz.jzitnik.tui.utils.SpriteCombiner; import lombok.Getter; import lombok.Setter; import org.jline.terminal.Terminal; import java.util.ArrayList; import java.util.List; import java.util.Optional; public class ScreenRenderer { private final SpriteList spriteList; private final Terminal terminal; public ScreenRenderer(SpriteList spriteList, Terminal terminal) { this.spriteList = spriteList; this.terminal = terminal; } @Getter @Setter private Optional> selectedBlock = Optional.empty(); private int[] getPlayerCords(List[][] world) { for (int i = 0; i < world.length; i++) { for (int j = 0; j < world[i].length; j++) { if (world[i][j].stream().anyMatch(x -> x.getBlockId().equals("steve") && x.getSpriteState().isPresent() && x.getSpriteState().get() == Steve.SteveState.SECOND)) { return new int[] { j, i }; } } } return null; } public synchronized void render(Game game) { var world = game.getWorld(); StringBuilder main = new StringBuilder(); main.append("\033[H\033[2J"); switch (game.getWindow()) { case INVENTORY -> game.getInventory().renderFull(main, terminal, spriteList, true, Optional.empty()); case CRAFTING_TABLE -> game.getGameStates().craftingTable.render(main, terminal, spriteList); case CHEST -> ((Chest) game.getWorld()[game.getGameStates().clickY][game.getGameStates().clickX].stream() .filter(i -> i.getBlockId().equals("chest")).toList().getFirst().getData()).render(game, main, terminal, spriteList); case FURNACE -> ((Furnace) game.getWorld()[game.getGameStates().clickY][game.getGameStates().clickX] .stream().filter(i -> i.getBlockId().equals("furnace")).toList().getFirst().getData()).render(game, main, terminal, spriteList); case WORLD -> { // World int[] cords = getPlayerCords(world); if (cords == null) return; int playerX = cords[0]; int playerY = cords[1]; int terminalWidth = terminal.getWidth(); int terminalHeight = terminal.getHeight(); int[] data = ScreenMovingCalculationProvider.calculate(playerX, playerY, terminalHeight, terminalWidth, world[0].length, world.length); // Calculate visible area boundaries int startX = data[0]; int endX = data[1]; int startY = data[2]; int endY = data[3]; int visibleWidth = endX - startX; int visibleHeight = endY - startY; if (visibleWidth % 2 != 0) { endX = Math.max(startX, endX - 1); } if (visibleHeight % 2 != 0) { endY = Math.max(startY, endY - 1); } StringBuilder[] lines = new StringBuilder[(endY - startY) * 25 + 1]; for (int i = 0; i < lines.length; i++) { lines[i] = new StringBuilder(); } int counter = 0; for (int y = startY; y < endY; y++) { for (int x = startX; x < endX; x++) { List blocks = world[y][x]; List sprites = new ArrayList<>(blocks.stream() .map(block -> block.getSpriteState().isEmpty() ? spriteList.getSprite(block.getSprite()).getSprite() : spriteList.getSprite(block.getSprite()) .getSprite(block.getSpriteState().get())) .toList()); if (selectedBlock.isPresent() && selectedBlock.get().get(0) == x && selectedBlock.get().get(1) == y) { StringBuilder stringBuilder = getStringBuilder(); sprites.add(stringBuilder.toString()); } String sprite = SpriteCombiner.combineSprites(sprites.toArray(String[]::new)); String[] spriteLines = sprite.split("\n"); for (int i = 0; i < spriteLines.length; i++) { lines[counter * 25 + i].append(spriteLines[i]).append("\033[0m"); } } counter++; } // World for (int i = 0; i < lines.length; i++) { main.append(lines[i]); if (i < lines.length - 1) { main.append("\n"); } } // Empty space between world and hotbar main.append("\n\n\n"); Healthbar.render(main, spriteList, terminal, game); game.getInventory().renderHotbar(main, spriteList, terminal, false); } } System.out.println(main); } private static StringBuilder getStringBuilder() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("\033[38;5;231;48;5;231m▓".repeat(50)); stringBuilder.append("\n"); for (int i = 0; i < 23; i++) { stringBuilder.append("\033[38;5;231;48;5;231m▓"); stringBuilder.append("\033[38;5;231;48;5;231m▓"); stringBuilder.append("\033[0m ".repeat(46)); stringBuilder.append("\033[38;5;231;48;5;231m▓"); stringBuilder.append("\033[38;5;231;48;5;231m▓"); stringBuilder.append("\n"); } stringBuilder.append("\033[38;5;231;48;5;231m▓".repeat(50)); stringBuilder.append("\n"); return stringBuilder; } }