From bc33c5f531c13d93c63cabd5e53755dece6f6a8c Mon Sep 17 00:00:00 2001 From: jzitnik-dev Date: Wed, 19 Mar 2025 13:04:36 +0100 Subject: [PATCH] feat: Twoblock block Added new Sprite for creating two block tall blocks. This sprite takes 2 sprite files (top, bottom). Also created new annotation that handles breaking and placing two block tall blocks and also manages the sprite state. --- .../java/cz/jzitnik/game/SpriteLoader.java | 9 +++- .../game/annotations/BlockBreakAction.java | 12 +++++ .../game/annotations/TwoblockBlock.java | 11 ++++ .../java/cz/jzitnik/game/blocks/Furnace.java | 2 + .../blocks/grassy/flowers/LilacBlock.java | 21 ++++++++ .../items/grassy/flowers/LilacItem.java | 13 +++++ .../jzitnik/game/generation/Generation.java | 5 +- .../handlers/BreakBlockActionProvider.java | 49 +++++++++++++++++ .../place/CustomAnnotationHandler.java | 53 +++++++++++++++++-- .../jzitnik/game/sprites/TwoBlockSprite.java | 37 +++++++++++++ src/main/resources/textures/items/lilac.ans | 25 +++++++++ src/main/resources/textures/lilac_bottom.ans | 25 +++++++++ src/main/resources/textures/lilac_top.ans | 25 +++++++++ 13 files changed, 282 insertions(+), 5 deletions(-) create mode 100644 src/main/java/cz/jzitnik/game/annotations/BlockBreakAction.java create mode 100644 src/main/java/cz/jzitnik/game/annotations/TwoblockBlock.java create mode 100644 src/main/java/cz/jzitnik/game/entities/items/registry/blocks/grassy/flowers/LilacBlock.java create mode 100644 src/main/java/cz/jzitnik/game/entities/items/registry/items/grassy/flowers/LilacItem.java create mode 100644 src/main/java/cz/jzitnik/game/handlers/BreakBlockActionProvider.java create mode 100644 src/main/java/cz/jzitnik/game/sprites/TwoBlockSprite.java create mode 100644 src/main/resources/textures/items/lilac.ans create mode 100644 src/main/resources/textures/lilac_bottom.ans create mode 100644 src/main/resources/textures/lilac_top.ans diff --git a/src/main/java/cz/jzitnik/game/SpriteLoader.java b/src/main/java/cz/jzitnik/game/SpriteLoader.java index 16edd8f..1faca99 100644 --- a/src/main/java/cz/jzitnik/game/SpriteLoader.java +++ b/src/main/java/cz/jzitnik/game/SpriteLoader.java @@ -1,7 +1,6 @@ package cz.jzitnik.game; import cz.jzitnik.game.sprites.*; -import cz.jzitnik.game.sprites.SimpleSprite; import cz.jzitnik.tui.Sprite; import cz.jzitnik.tui.SpriteList; @@ -42,6 +41,7 @@ public class SpriteLoader { OXEYE_DAISY, AZURE_BLUET, LILY_OF_THE_VALLEY, + LILAC, // Ores COAL_ORE, @@ -94,6 +94,9 @@ public class SpriteLoader { ITEM_OBSIDIAN, ITEM_SAND, + // Tall Flowers + ITEM_LILAC, + // Ore Items ITEM_COAL_ORE, ITEM_IRON_ORE, @@ -224,6 +227,7 @@ public class SpriteLoader { SPRITES_MAP.put(SPRITES.BLUE_ORCHID, new SimpleSprite("blue_orchid.ans")); SPRITES_MAP.put(SPRITES.OXEYE_DAISY, new SimpleSprite("oxeye_daisy.ans")); SPRITES_MAP.put(SPRITES.AZURE_BLUET, new SimpleSprite("azure_bluet.ans")); + SPRITES_MAP.put(SPRITES.LILAC, new TwoBlockSprite("lilac_top.ans", "lilac_bottom.ans")); // Grass SPRITES_MAP.put(SPRITES.GRASS_BUSH, new SimpleSprite("grass_bush.ans")); @@ -262,6 +266,9 @@ public class SpriteLoader { SPRITES_MAP.put(SPRITES.ITEM_OBSIDIAN, new SimpleSprite("items/obsidian.ans")); SPRITES_MAP.put(SPRITES.ITEM_SAND, new SimpleSprite("items/sand.ans")); + // Tall flowers + SPRITES_MAP.put(SPRITES.ITEM_LILAC, new SimpleSprite("items/lilac.ans")); + // Ore Items SPRITES_MAP.put(SPRITES.ITEM_COAL_ORE, new SimpleSprite("items/coal_ore.ans")); SPRITES_MAP.put(SPRITES.ITEM_IRON_ORE, new SimpleSprite("items/iron_ore.ans")); diff --git a/src/main/java/cz/jzitnik/game/annotations/BlockBreakAction.java b/src/main/java/cz/jzitnik/game/annotations/BlockBreakAction.java new file mode 100644 index 0000000..f4db47a --- /dev/null +++ b/src/main/java/cz/jzitnik/game/annotations/BlockBreakAction.java @@ -0,0 +1,12 @@ +package cz.jzitnik.game.annotations; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface BlockBreakAction { + String value(); +} diff --git a/src/main/java/cz/jzitnik/game/annotations/TwoblockBlock.java b/src/main/java/cz/jzitnik/game/annotations/TwoblockBlock.java new file mode 100644 index 0000000..4df13a9 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/annotations/TwoblockBlock.java @@ -0,0 +1,11 @@ +package cz.jzitnik.game.annotations; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface TwoblockBlock { +} diff --git a/src/main/java/cz/jzitnik/game/blocks/Furnace.java b/src/main/java/cz/jzitnik/game/blocks/Furnace.java index 627673d..9be659a 100644 --- a/src/main/java/cz/jzitnik/game/blocks/Furnace.java +++ b/src/main/java/cz/jzitnik/game/blocks/Furnace.java @@ -1,5 +1,6 @@ package cz.jzitnik.game.blocks; +import cz.jzitnik.game.annotations.BlockBreakAction; import cz.jzitnik.game.annotations.RightClickLogic; import cz.jzitnik.game.entities.Block; import cz.jzitnik.game.Game; @@ -251,6 +252,7 @@ public class Furnace implements RightClickHandler, Serializable { thread2.start(); } + @BlockBreakAction("furnace") public void breakBlock(Game game) { for (var i = 0; i < items.length; i++) { if (items[i] == null) { diff --git a/src/main/java/cz/jzitnik/game/entities/items/registry/blocks/grassy/flowers/LilacBlock.java b/src/main/java/cz/jzitnik/game/entities/items/registry/blocks/grassy/flowers/LilacBlock.java new file mode 100644 index 0000000..15ffa80 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/entities/items/registry/blocks/grassy/flowers/LilacBlock.java @@ -0,0 +1,21 @@ +package cz.jzitnik.game.entities.items.registry.blocks.grassy.flowers; + +import cz.jzitnik.game.SpriteLoader; +import cz.jzitnik.game.annotations.BlockRegistry; +import cz.jzitnik.game.annotations.BreakableByWater; +import cz.jzitnik.game.annotations.BreaksFalling; +import cz.jzitnik.game.annotations.PlaceOnSolid; +import cz.jzitnik.game.annotations.TwoblockBlock; +import cz.jzitnik.game.entities.Block; + +@PlaceOnSolid +@BreakableByWater +@BreaksFalling +@TwoblockBlock +@BlockRegistry(value = "lilac") +public class LilacBlock extends Block { + public LilacBlock() { + super("lilac", SpriteLoader.SPRITES.LILAC, 0); + setGhost(true); + } +} diff --git a/src/main/java/cz/jzitnik/game/entities/items/registry/items/grassy/flowers/LilacItem.java b/src/main/java/cz/jzitnik/game/entities/items/registry/items/grassy/flowers/LilacItem.java new file mode 100644 index 0000000..6b857a9 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/entities/items/registry/items/grassy/flowers/LilacItem.java @@ -0,0 +1,13 @@ +package cz.jzitnik.game.entities.items.registry.items.grassy.flowers; + +import cz.jzitnik.game.SpriteLoader; +import cz.jzitnik.game.annotations.ItemRegistry; +import cz.jzitnik.game.entities.items.Item; +import cz.jzitnik.game.entities.items.ItemType; + +@ItemRegistry("lilac") +public class LilacItem extends Item { + public LilacItem() { + super("lilac", "Lilac", ItemType.BLOCK, SpriteLoader.SPRITES.ITEM_LILAC); + } +} diff --git a/src/main/java/cz/jzitnik/game/generation/Generation.java b/src/main/java/cz/jzitnik/game/generation/Generation.java index 006b128..4eb591c 100644 --- a/src/main/java/cz/jzitnik/game/generation/Generation.java +++ b/src/main/java/cz/jzitnik/game/generation/Generation.java @@ -34,7 +34,10 @@ public class Generation { world[terrainHeight[256] - 1][256].add(steveBlock2); world[terrainHeight[256] - 2][256].add(steveBlock); - game.getInventory().addItem(ItemBlockSupplier.getItem("lava_bucket")); + game.getInventory().addItem(ItemBlockSupplier.getItem("furnace")); + game.getInventory().addItem(ItemBlockSupplier.getItem("coal")); + game.getInventory().addItem(ItemBlockSupplier.getItem("oak_log")); + game.getInventory().addItem(ItemBlockSupplier.getItem("diamond_pickaxe")); } private static void initializeWorld(List[][] world) { diff --git a/src/main/java/cz/jzitnik/game/handlers/BreakBlockActionProvider.java b/src/main/java/cz/jzitnik/game/handlers/BreakBlockActionProvider.java new file mode 100644 index 0000000..3a12be1 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/handlers/BreakBlockActionProvider.java @@ -0,0 +1,49 @@ +package cz.jzitnik.game.handlers; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Set; +import java.util.function.Function; + +import org.reflections.Reflections; +import org.reflections.scanners.Scanners; +import org.reflections.util.ConfigurationBuilder; + +import cz.jzitnik.game.Game; +import cz.jzitnik.game.annotations.MineEventHandler; + +public class BreakBlockActionProvider { + private HashMap> actions = new HashMap<>(); + + public BreakBlockActionProvider() { + register(); + } + + private void register() { + Reflections reflections = new Reflections( + new ConfigurationBuilder() + .forPackage("cz.jzitnik.game.handlers.events.handlers.mine") + .addScanners(Scanners.MethodsAnnotated) + ); + Set mineHandlers = reflections.getMethodsAnnotatedWith(MineEventHandler.class); + + for (Method method : mineHandlers) { + if (method.getParameterCount() == 1 && + method.getParameterTypes()[0] == Game.class) + try { + Object instance = method.getDeclaringClass().getDeclaredConstructor().newInstance(); + Function handler = (screenRenderer, game, x, y) -> { + try { + method.invoke(instance, screenRenderer, game, x, y); + } catch (Exception e) { + e.printStackTrace(); + } + }; + this.mineHandlers.add(handler); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } +} diff --git a/src/main/java/cz/jzitnik/game/handlers/place/CustomAnnotationHandler.java b/src/main/java/cz/jzitnik/game/handlers/place/CustomAnnotationHandler.java index 5dbc962..23368ec 100644 --- a/src/main/java/cz/jzitnik/game/handlers/place/CustomAnnotationHandler.java +++ b/src/main/java/cz/jzitnik/game/handlers/place/CustomAnnotationHandler.java @@ -4,6 +4,7 @@ import cz.jzitnik.game.Game; import cz.jzitnik.game.annotations.*; import cz.jzitnik.game.entities.Block; import cz.jzitnik.game.entities.items.ItemBlockSupplier; +import cz.jzitnik.game.sprites.TwoBlockSprite; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; @@ -22,11 +23,47 @@ public class CustomAnnotationHandler implements CustomPlaceHandler { @Override public boolean place(Game game, int x, int y) { + boolean place = true; + boolean customPlace = false; if (clazz.isAnnotationPresent(PlaceOnSolid.class)) { - return placeOnSolid(game, x, y); + place = placeOnSolid(game, x, y); + } + + if (place && clazz.isAnnotationPresent(TwoblockBlock.class)) { + var blocksTop = game.getWorld()[y - 1][x]; + if (!blocksTop.stream().allMatch(block -> block.getBlockId().equals("air"))) { + place = false; + } } - return defaultPlaceHandler.place(game, x, y); + if (place && clazz.isAnnotationPresent(TwoblockBlock.class)) { + var inventory = game.getInventory(); + var blocks = game.getWorld()[y][x]; + var blocksTop = game.getWorld()[y - 1][x]; + + Block block = inventory.getItemInHand().get().getBlock().get(); + block.setSpriteState(TwoBlockSprite.TwoBlockSpriteState.BOTTOM); + blocks.add(block); + blocks.removeAll(blocks.stream().filter(Block::isFlowing).toList()); + + Block block2 = ItemBlockSupplier.getBlock(block.getBlockId()); + block2.setSpriteState(TwoBlockSprite.TwoBlockSpriteState.TOP); + blocksTop.add(block2); + blocksTop.removeAll(blocksTop.stream().filter(Block::isFlowing).toList()); + + inventory.decreaseItemInHand(); + + + customPlace = true; + return true; + } + + + if (!customPlace && place) { + return defaultPlaceHandler.place(game, x, y); + } + + return false; } @Override @@ -63,6 +100,16 @@ public class CustomAnnotationHandler implements CustomPlaceHandler { dropDefault = blockDropPercentage(game, x, y); } + if (clazz.isAnnotationPresent(TwoblockBlock.class)) { + var blocksTop = game.getWorld()[y - 1][x]; + if (blocksTop.stream().anyMatch(i -> !i.getBlockId().equals("air") && !i.isMob())) { + blocksTop.removeAll(blocksTop.stream().filter(i -> !i.getBlockId().equals("air") && !i.isMob()).toList()); + } else { + var blocksBottom = game.getWorld()[y + 1][x]; + blocksBottom.removeAll(blocksBottom.stream().filter(i -> !i.getBlockId().equals("air") && !i.isMob()).toList()); + } + } + defaultPlaceHandler.mine(game, x, y); return dropDefault; @@ -83,7 +130,7 @@ public class CustomAnnotationHandler implements CustomPlaceHandler { return false; } - return defaultPlaceHandler.place(game, x, y); + return true; } private void resetDataOnMine(Game game, int x, int y) { diff --git a/src/main/java/cz/jzitnik/game/sprites/TwoBlockSprite.java b/src/main/java/cz/jzitnik/game/sprites/TwoBlockSprite.java new file mode 100644 index 0000000..bd11e63 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/sprites/TwoBlockSprite.java @@ -0,0 +1,37 @@ +package cz.jzitnik.game.sprites; + +import cz.jzitnik.tui.ResourceLoader; +import cz.jzitnik.tui.Sprite; + +import java.util.Optional; + +public class TwoBlockSprite extends Sprite { + public enum TwoBlockSpriteState { + TOP, BOTTOM + } + + private final String top; + private final String bottom; + + public TwoBlockSprite(String top, String bottom) { + this.top = top; + this.bottom = bottom; + } + + public String getSprite() { + return getSprite(TwoBlockSpriteState.TOP); + } + + public String getSprite(Enum key) { + return ResourceLoader.loadResource(switch (key) { + case TwoBlockSpriteState.TOP -> top; + case TwoBlockSpriteState.BOTTOM -> bottom; + default -> throw new RuntimeException("Invalid state!"); + }); + } + + @Override + public Optional> getStates() { + return Optional.empty(); + } +} diff --git a/src/main/resources/textures/items/lilac.ans b/src/main/resources/textures/items/lilac.ans new file mode 100644 index 0000000..a9a8095 --- /dev/null +++ b/src/main/resources/textures/items/lilac.ans @@ -0,0 +1,25 @@ +                                                   +                                                   +                                                  +                                       +                                       +                                       +                                          +                                          +                                           +                                  +                                   +                                     +                                     +                                    +                                       +                                       +                                          +                                           +                                             +                                      +                                       +                                         +                                        +                                           +                                           diff --git a/src/main/resources/textures/lilac_bottom.ans b/src/main/resources/textures/lilac_bottom.ans new file mode 100644 index 0000000..20e04aa --- /dev/null +++ b/src/main/resources/textures/lilac_bottom.ans @@ -0,0 +1,25 @@ +                                  +                                   +                                      +                                  +                                    +                                           +                                             +                                             +                                      +                                       +                                    +                                  +                                    +                                    +                                   +                                   +                                       +                                       +                                         +                                   +                                          +                                          +                                                +                                                +                                                diff --git a/src/main/resources/textures/lilac_top.ans b/src/main/resources/textures/lilac_top.ans new file mode 100644 index 0000000..e334731 --- /dev/null +++ b/src/main/resources/textures/lilac_top.ans @@ -0,0 +1,25 @@ +                                                   +                                                   +                                                   +                                           +                                           +                                       +                                        +                                       +                                           +                                          +                                          +                                             +                                         +                                       +                                      +                                      +                                       +                                     +                                       +                                    +                                           +                                            +                                         +                                         +