diff --git a/.gitignore b/.gitignore index 480bdf5..29a880c 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,6 @@ build/ .vscode/ ### Mac OS ### -.DS_Store \ No newline at end of file +.DS_Store + +logs diff --git a/src/main/java/cz/jzitnik/config/RoomSizeConfig.java b/src/main/java/cz/jzitnik/config/RoomSizeConfig.java new file mode 100644 index 0000000..4b2ba6a --- /dev/null +++ b/src/main/java/cz/jzitnik/config/RoomSizeConfig.java @@ -0,0 +1,11 @@ +package cz.jzitnik.config; + +import cz.jzitnik.annotations.Config; +import lombok.Getter; + +@Config +@Getter +public class RoomSizeConfig { + private final int roomHeight = 450; + private final int roomWidth = 450; +} diff --git a/src/main/java/cz/jzitnik/events/FullRoomDraw.java b/src/main/java/cz/jzitnik/events/FullRoomDraw.java new file mode 100644 index 0000000..cff76fc --- /dev/null +++ b/src/main/java/cz/jzitnik/events/FullRoomDraw.java @@ -0,0 +1,6 @@ +package cz.jzitnik.events; + +import cz.jzitnik.utils.events.Event; + +public class FullRoomDraw implements Event { +} diff --git a/src/main/java/cz/jzitnik/events/handlers/CliHandler.java b/src/main/java/cz/jzitnik/events/handlers/CliHandler.java index 272aa24..a260657 100644 --- a/src/main/java/cz/jzitnik/events/handlers/CliHandler.java +++ b/src/main/java/cz/jzitnik/events/handlers/CliHandler.java @@ -1,9 +1,7 @@ package cz.jzitnik.events.handlers; -import com.googlecode.lanterna.TextCharacter; import com.googlecode.lanterna.TextColor; import com.googlecode.lanterna.graphics.TextGraphics; -import com.googlecode.lanterna.screen.Screen; import cz.jzitnik.annotations.EventHandler; import cz.jzitnik.annotations.injectors.InjectState; import cz.jzitnik.events.RerenderScreen; @@ -13,10 +11,12 @@ import cz.jzitnik.ui.pixels.Empty; import cz.jzitnik.ui.pixels.Pixel; import cz.jzitnik.utils.DependencyManager; import cz.jzitnik.utils.events.AbstractEventHandler; +import lombok.extern.slf4j.Slf4j; import java.awt.*; import java.io.IOException; +@Slf4j @EventHandler(RerenderScreen.class) public class CliHandler extends AbstractEventHandler { @InjectState @@ -43,7 +43,7 @@ public class CliHandler extends AbstractEventHandler { for (int y = start.getRow(); y <= end.getRow(); y++) { for (int x = start.getColumn(); x <= end.getColumn(); x++) { Pixel pixel = buffer[y][x]; - TextColor color = pixel.getClass().equals(Empty.class) ? TextColor.ANSI.BLACK : pixel.getColor(); + TextColor color = pixel.getClass().equals(Empty.class) ? new TextColor.RGB(4, 4, 16) : pixel.getColor(); drawPixel(tg, x, y, color); } @@ -57,8 +57,8 @@ public class CliHandler extends AbstractEventHandler { } } - private static void drawPixel(TextGraphics tg, int x, int y, TextColor color) { + private void drawPixel(TextGraphics tg, int x, int y, TextColor color) { tg.setForegroundColor(color); - tg.setCharacter(x, y, '█'); // full block character + tg.setCharacter(x, y, '█'); } } diff --git a/src/main/java/cz/jzitnik/events/handlers/FullRoomDrawHandler.java b/src/main/java/cz/jzitnik/events/handlers/FullRoomDrawHandler.java new file mode 100644 index 0000000..9b7e56b --- /dev/null +++ b/src/main/java/cz/jzitnik/events/handlers/FullRoomDrawHandler.java @@ -0,0 +1,99 @@ +package cz.jzitnik.events.handlers; + +import com.googlecode.lanterna.TerminalPosition; +import com.googlecode.lanterna.TerminalSize; +import com.googlecode.lanterna.TextColor; +import com.googlecode.lanterna.screen.TerminalScreen; +import cz.jzitnik.annotations.EventHandler; +import cz.jzitnik.annotations.injectors.InjectDependency; +import cz.jzitnik.annotations.injectors.InjectState; +import cz.jzitnik.events.FullRoomDraw; +import cz.jzitnik.events.RerenderScreen; +import cz.jzitnik.game.GameState; +import cz.jzitnik.game.ResourceManager; +import cz.jzitnik.states.RenderState; +import cz.jzitnik.states.ScreenBuffer; +import cz.jzitnik.states.TerminalState; +import cz.jzitnik.ui.pixels.ColoredPixel; +import cz.jzitnik.ui.pixels.Pixel; +import cz.jzitnik.utils.DependencyManager; +import cz.jzitnik.utils.events.AbstractEventHandler; +import cz.jzitnik.utils.events.EventManager; +import lombok.extern.slf4j.Slf4j; + +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.List; + +@Slf4j +@EventHandler(FullRoomDraw.class) +public class FullRoomDrawHandler extends AbstractEventHandler { + public FullRoomDrawHandler(DependencyManager dm) { + super(dm); + } + + @InjectState + private GameState gameState; + + @InjectState + private ScreenBuffer screenBuffer; + + @InjectDependency + private ResourceManager resourceManager; + + @InjectState + private TerminalState terminalState; + + @InjectDependency + private EventManager eventManager; + + @InjectState + private RenderState renderState; + + @Override + public void handle(FullRoomDraw event) { + log.debug("Rendering full room"); + TerminalScreen terminalScreen = terminalState.getTerminalScreen(); + List partsToRerender = new ArrayList<>(); + + var buffer = screenBuffer.getBuffer(); + + BufferedImage room = resourceManager.getResource(ResourceManager.Resource.ROOM1); + TerminalSize terminalSize = terminalScreen.getTerminalSize(); + + int terminalHeight = terminalSize.getRows(); + int terminalWidth = terminalSize.getColumns(); + + int width = room.getWidth(); + int height = room.getHeight(); + + int startX = (terminalWidth - (width * 2)) / 2; + int startY = (terminalHeight - height) / 2; + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + int pixel = room.getRGB(x, y); + int red = (pixel >> 16) & 0xff; + int green = (pixel >> 8) & 0xff; + int blue = pixel & 0xff; + + Pixel pixel1 = new ColoredPixel(new TextColor.RGB(red, green, blue)); + + buffer[y + startY][x * 2 + startX] = pixel1; + buffer[y + startY][x * 2 + 1 + startX] = pixel1; + } + } + partsToRerender.add(new RerenderScreen.ScreenPart( + new TerminalPosition(startX, startY), + new TerminalPosition(startY + height - 1, (startX + height - 1) * 2) + )); + + if (renderState.isFirstRender()) { + eventManager.emitEvent(RerenderScreen.full(terminalSize)); + renderState.setFirstRender(false); + } else { + + eventManager.emitEvent(new RerenderScreen(partsToRerender.toArray(RerenderScreen.ScreenPart[]::new))); + } + } +} diff --git a/src/main/java/cz/jzitnik/events/handlers/TerminalResizeEventHandler.java b/src/main/java/cz/jzitnik/events/handlers/TerminalResizeEventHandler.java index baf1371..440c124 100644 --- a/src/main/java/cz/jzitnik/events/handlers/TerminalResizeEventHandler.java +++ b/src/main/java/cz/jzitnik/events/handlers/TerminalResizeEventHandler.java @@ -4,6 +4,7 @@ import com.googlecode.lanterna.TerminalSize; import cz.jzitnik.annotations.EventHandler; import cz.jzitnik.annotations.injectors.InjectDependency; import cz.jzitnik.annotations.injectors.InjectState; +import cz.jzitnik.events.FullRoomDraw; import cz.jzitnik.events.RerenderScreen; import cz.jzitnik.events.TerminalResizeEvent; import cz.jzitnik.states.ScreenBuffer; @@ -12,7 +13,9 @@ import cz.jzitnik.ui.pixels.Pixel; import cz.jzitnik.utils.DependencyManager; import cz.jzitnik.utils.events.AbstractEventHandler; import cz.jzitnik.utils.events.EventManager; +import lombok.extern.slf4j.Slf4j; +@Slf4j @EventHandler(TerminalResizeEvent.class) public class TerminalResizeEventHandler extends AbstractEventHandler { public TerminalResizeEventHandler(DependencyManager dm) { @@ -39,6 +42,6 @@ public class TerminalResizeEventHandler extends AbstractEventHandler objects; + + public GameRoom() { + objects = new ArrayList<>(); + } +} diff --git a/src/main/java/cz/jzitnik/game/GameState.java b/src/main/java/cz/jzitnik/game/GameState.java new file mode 100644 index 0000000..097fd38 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/GameState.java @@ -0,0 +1,11 @@ +package cz.jzitnik.game; + +import cz.jzitnik.annotations.State; +import cz.jzitnik.game.utils.RoomCords; + +@State +public class GameState { + private GameRoom currentRoom; + + private RoomCords playerCords; +} diff --git a/src/main/java/cz/jzitnik/game/ResourceManager.java b/src/main/java/cz/jzitnik/game/ResourceManager.java new file mode 100644 index 0000000..7a5aa06 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/ResourceManager.java @@ -0,0 +1,41 @@ +package cz.jzitnik.game; + +import cz.jzitnik.annotations.Dependency; +import cz.jzitnik.annotations.injectors.InjectDependency; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; + +@Dependency +public class ResourceManager { + @InjectDependency + private ClassLoader classLoader; + + @AllArgsConstructor + @Getter + public enum Resource { + ROOM1("rooms/1.png"); + + private final String path; // Field must be final for enum + } + + private HashMap resourceCache = new HashMap<>(); + + public BufferedImage getResource(Resource resource) { + InputStream is = classLoader.getResourceAsStream("textures/" + resource.getPath()); + if (is == null) { + throw new RuntimeException("Image not found in resources!"); + } + + try { + return ImageIO.read(is); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/cz/jzitnik/game/exceptions/InvalidCoordinatesException.java b/src/main/java/cz/jzitnik/game/exceptions/InvalidCoordinatesException.java new file mode 100644 index 0000000..3383b2f --- /dev/null +++ b/src/main/java/cz/jzitnik/game/exceptions/InvalidCoordinatesException.java @@ -0,0 +1,11 @@ +package cz.jzitnik.game.exceptions; + +public class InvalidCoordinatesException extends RuntimeException { + public InvalidCoordinatesException(String message) { + super(message); + } + + public InvalidCoordinatesException() { + super(); + } +} diff --git a/src/main/java/cz/jzitnik/game/items/Item.java b/src/main/java/cz/jzitnik/game/items/Item.java new file mode 100644 index 0000000..2a6e462 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/items/Item.java @@ -0,0 +1,4 @@ +package cz.jzitnik.game.items; + +public abstract class Item { +} diff --git a/src/main/java/cz/jzitnik/game/objects/Chest.java b/src/main/java/cz/jzitnik/game/objects/Chest.java new file mode 100644 index 0000000..1b07ddf --- /dev/null +++ b/src/main/java/cz/jzitnik/game/objects/Chest.java @@ -0,0 +1,10 @@ +package cz.jzitnik.game.objects; + +import cz.jzitnik.game.utils.RoomCords; +import cz.jzitnik.ui.pixels.Pixel; + +public final class Chest extends GameObject { + public Chest(Pixel[][] texture, RoomCords cords) { + super(texture, cords); + } +} diff --git a/src/main/java/cz/jzitnik/game/objects/GameObject.java b/src/main/java/cz/jzitnik/game/objects/GameObject.java new file mode 100644 index 0000000..86ce3de --- /dev/null +++ b/src/main/java/cz/jzitnik/game/objects/GameObject.java @@ -0,0 +1,14 @@ +package cz.jzitnik.game.objects; + +import cz.jzitnik.game.utils.Renderable; +import cz.jzitnik.game.utils.RoomCords; +import cz.jzitnik.ui.pixels.Pixel; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public sealed abstract class GameObject implements Renderable permits Chest { + private Pixel[][] texture; + private RoomCords cords; +} diff --git a/src/main/java/cz/jzitnik/game/utils/Renderable.java b/src/main/java/cz/jzitnik/game/utils/Renderable.java new file mode 100644 index 0000000..771f958 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/utils/Renderable.java @@ -0,0 +1,7 @@ +package cz.jzitnik.game.utils; + +import cz.jzitnik.ui.pixels.Pixel; + +public interface Renderable { + Pixel[][] getTexture(); +} diff --git a/src/main/java/cz/jzitnik/game/utils/RoomCords.java b/src/main/java/cz/jzitnik/game/utils/RoomCords.java new file mode 100644 index 0000000..79d8bd0 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/utils/RoomCords.java @@ -0,0 +1,27 @@ +package cz.jzitnik.game.utils; + +import cz.jzitnik.config.RoomSizeConfig; +import cz.jzitnik.game.exceptions.InvalidCoordinatesException; +import lombok.Getter; + +@Getter +public class RoomCords { + private final RoomSizeConfig roomSizeConfig; + private int x; + private int y; + + public RoomCords(int x, int y, RoomSizeConfig roomSizeConfig) { + this.roomSizeConfig = roomSizeConfig; + + updateCords(x, y); + } + + public void updateCords(int x, int y) { + if (x >= roomSizeConfig.getRoomWidth() || y >= roomSizeConfig.getRoomHeight()) { + throw new InvalidCoordinatesException(); + } + + this.x = x; + this.y = y; + } +} diff --git a/src/main/java/cz/jzitnik/states/RenderState.java b/src/main/java/cz/jzitnik/states/RenderState.java new file mode 100644 index 0000000..81fe07d --- /dev/null +++ b/src/main/java/cz/jzitnik/states/RenderState.java @@ -0,0 +1,12 @@ +package cz.jzitnik.states; + +import cz.jzitnik.annotations.State; +import lombok.Getter; +import lombok.Setter; + +@State +@Getter +@Setter +public class RenderState { + private boolean isFirstRender = true; +} diff --git a/src/main/java/cz/jzitnik/utils/events/EventManager.java b/src/main/java/cz/jzitnik/utils/events/EventManager.java index d21ea5e..d435fb5 100644 --- a/src/main/java/cz/jzitnik/utils/events/EventManager.java +++ b/src/main/java/cz/jzitnik/utils/events/EventManager.java @@ -86,7 +86,7 @@ public class EventManager extends Thread { try { handler.handle(typedEvent); } catch (Exception e) { - e.printStackTrace(System.err); + log.debug(e.toString()); } }); } diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..52ec92f --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,40 @@ + + + logs/general.log + + + + logs/general.%d{yyyy-MM-dd}.%i.log.zip + + 3MB + + 30 + + 30MB + + + + ERROR + DENY + ACCEPT + + + + %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n + + + + + + ERROR + + + %d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + diff --git a/src/main/resources/textures/rooms/1.png b/src/main/resources/textures/rooms/1.png new file mode 100644 index 0000000..a8f7eda Binary files /dev/null and b/src/main/resources/textures/rooms/1.png differ