diff --git a/src/main/java/cz/jzitnik/Main.java b/src/main/java/cz/jzitnik/Main.java index 5e87555..1478a16 100644 --- a/src/main/java/cz/jzitnik/Main.java +++ b/src/main/java/cz/jzitnik/Main.java @@ -51,7 +51,8 @@ public class Main { } try { customLogicProvider.update(game); - } catch (Exception _) { + } catch (Exception e) { + e.printStackTrace(); } if ( game.getWindow() == Window.WORLD) { diff --git a/src/main/java/cz/jzitnik/game/SpriteLoader.java b/src/main/java/cz/jzitnik/game/SpriteLoader.java index 9bc1f27..12d19a3 100644 --- a/src/main/java/cz/jzitnik/game/SpriteLoader.java +++ b/src/main/java/cz/jzitnik/game/SpriteLoader.java @@ -12,7 +12,7 @@ public class SpriteLoader { // BLOCKS // Blocks - AIR, WATER, LAVA, DIRT, GRASS, STONE, BEDROCK, COBBLESTONE, WOOL, OAK_LOG, OAK_LEAF, OAK_PLANKS, OAK_DOOR, + AIR, WATER, LAVA, DIRT, GRASS, STONE, BEDROCK, COBBLESTONE, WOOL, OAK_LOG, OAK_LEAF, OAK_PLANKS, OAK_DOOR, OBSIDIAN, // Ores COAL_ORE, IRON_ORE, GOLD_ORE, DIAMOND_ORE, @@ -81,6 +81,7 @@ public class SpriteLoader { SPRITES_MAP.put(SPRITES.OAK_DOOR, new OakDoor()); SPRITES_MAP.put(SPRITES.WOOL, new Wool()); SPRITES_MAP.put(SPRITES.COBBLESTONE, new SimpleSprite("cobblestone.ans")); + SPRITES_MAP.put(SPRITES.OBSIDIAN, new SimpleSprite("obsidian.ans")); // Ores SPRITES_MAP.put(SPRITES.COAL_ORE, new SimpleSprite("coal_ore.ans")); diff --git a/src/main/java/cz/jzitnik/game/entities/items/registry/blocks/LavaBlock.java b/src/main/java/cz/jzitnik/game/entities/items/registry/blocks/LavaBlock.java index f5c6139..38c4b52 100644 --- a/src/main/java/cz/jzitnik/game/entities/items/registry/blocks/LavaBlock.java +++ b/src/main/java/cz/jzitnik/game/entities/items/registry/blocks/LavaBlock.java @@ -3,16 +3,17 @@ package cz.jzitnik.game.entities.items.registry.blocks; import cz.jzitnik.game.SpriteLoader; import cz.jzitnik.game.annotations.BlockRegistry; import cz.jzitnik.game.entities.Block; -import cz.jzitnik.game.logic.services.flowing.lava.LavaData; +import cz.jzitnik.game.logic.services.flowing.FlowingData; import cz.jzitnik.game.sprites.Lava; +import cz.jzitnik.game.sprites.Water; @BlockRegistry(value = "lava", drops = "lava_bucket") public class LavaBlock extends Block { public LavaBlock() { super("lava", SpriteLoader.SPRITES.LAVA); setMineable(false); - setSpriteState(Lava.LavaState.FIRST); - setData(new LavaData()); + setSpriteState(Water.WaterState.FIRST); + setData(new FlowingData()); setFlowing(true); setGhost(true); } diff --git a/src/main/java/cz/jzitnik/game/entities/items/registry/blocks/ObsidianBlock.java b/src/main/java/cz/jzitnik/game/entities/items/registry/blocks/ObsidianBlock.java new file mode 100644 index 0000000..d70b8b7 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/entities/items/registry/blocks/ObsidianBlock.java @@ -0,0 +1,16 @@ +package cz.jzitnik.game.entities.items.registry.blocks; + +import cz.jzitnik.game.SpriteLoader; +import cz.jzitnik.game.annotations.BlockRegistry; +import cz.jzitnik.game.entities.Block; +import cz.jzitnik.game.entities.items.ItemType; +import cz.jzitnik.game.entities.items.ToolVariant; + +import java.util.List; + +@BlockRegistry("obsidian") +public class ObsidianBlock extends Block { + public ObsidianBlock() { + super("obsidian", SpriteLoader.SPRITES.OBSIDIAN, 45, ItemType.PICKAXE, List.of(ToolVariant.DIAMOND)); + } +} diff --git a/src/main/java/cz/jzitnik/game/entities/items/registry/blocks/WaterBlock.java b/src/main/java/cz/jzitnik/game/entities/items/registry/blocks/WaterBlock.java index 376e66d..e90312c 100644 --- a/src/main/java/cz/jzitnik/game/entities/items/registry/blocks/WaterBlock.java +++ b/src/main/java/cz/jzitnik/game/entities/items/registry/blocks/WaterBlock.java @@ -3,7 +3,7 @@ package cz.jzitnik.game.entities.items.registry.blocks; import cz.jzitnik.game.SpriteLoader; import cz.jzitnik.game.annotations.BlockRegistry; import cz.jzitnik.game.entities.Block; -import cz.jzitnik.game.logic.services.flowing.water.WaterData; +import cz.jzitnik.game.logic.services.flowing.FlowingData; import cz.jzitnik.game.sprites.Water; @BlockRegistry(value = "water", drops = "water_bucket") @@ -12,7 +12,7 @@ public class WaterBlock extends Block { super("water", SpriteLoader.SPRITES.WATER); setMineable(false); setSpriteState(Water.WaterState.FIRST); - setData(new WaterData()); + setData(new FlowingData()); setFlowing(true); setGhost(true); } diff --git a/src/main/java/cz/jzitnik/game/generation/Generation.java b/src/main/java/cz/jzitnik/game/generation/Generation.java index 2df0ba4..71ce3ad 100644 --- a/src/main/java/cz/jzitnik/game/generation/Generation.java +++ b/src/main/java/cz/jzitnik/game/generation/Generation.java @@ -36,6 +36,9 @@ public class Generation { // Spawn player at a valid starting point world[terrainHeight[256] - 1][256].add(steveBlock2); world[terrainHeight[256] - 2][256].add(steveBlock); + + game.getInventory().addItem(ItemBlockSupplier.getItem("water_bucket")); + game.getInventory().addItem(ItemBlockSupplier.getItem("lava_bucket")); } private static void initializeWorld(List[][] world) { diff --git a/src/main/java/cz/jzitnik/game/logic/services/flowing/FlowingLogic.java b/src/main/java/cz/jzitnik/game/logic/services/flowing/FlowingLogic.java new file mode 100644 index 0000000..419a790 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/logic/services/flowing/FlowingLogic.java @@ -0,0 +1,126 @@ +package cz.jzitnik.game.logic.services.flowing; + +import cz.jzitnik.game.Game; +import cz.jzitnik.game.annotations.CustomLogic; +import cz.jzitnik.game.entities.Block; +import cz.jzitnik.game.entities.items.ItemBlockSupplier; +import cz.jzitnik.game.logic.CustomLogicInterface; +import cz.jzitnik.game.sprites.Water; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.awt.*; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@CustomLogic +public class FlowingLogic implements CustomLogicInterface { + private static final int RADIUS = 20; + + @AllArgsConstructor + @Getter + private static class LiquidBlock { + private Block block; + private int x; + private int y; + } + + @Override + public void nextIteration(Game game) { + processFlow(game, "water"); + processFlow(game, "lava"); + } + + private void processFlow(Game game, String liquidId) { + int[] data = game.getPlayerCords(); + var world = game.getWorld(); + int playerX = data[0]; + int playerY = data[1]; + + int startX = Math.max(0, playerX - RADIUS); + int startY = Math.max(0, playerY - RADIUS); + int endX = Math.min(world[0].length - 1, playerX + RADIUS); + int endY = Math.min(world.length - 1, playerY + RADIUS); + + List sourceBlocks = new ArrayList<>(); + + for (int y = startY; y <= endY; y++) { + for (int x = startX; x <= endX; x++) { + var blocks = world[y][x]; + var sourceLiquidBlocks = blocks.stream() + .filter(block -> block.getBlockId().equals(liquidId) && ((FlowingData) block.getData()).isSource()) + .toList(); + if (!sourceLiquidBlocks.isEmpty()) { + sourceBlocks.add(new LiquidBlock(sourceLiquidBlocks.getFirst(), x, y)); + } + world[y][x].removeAll(blocks.stream() + .filter(i -> i.getBlockId().equals(liquidId) && !((FlowingData) i.getData()).isSource()).toList()); + } + } + + for (LiquidBlock sourceBlock : sourceBlocks) { + flow(world, sourceBlock.getX(), sourceBlock.getY(), 5, new HashSet<>(), liquidId); + } + } + + private void flow(List[][] world, int x, int y, int strength, Set visited, String liquidId) { + if (y + 1 < world.length && canFlowInto(world[y + 1][x])) { + Block newLiquid = ItemBlockSupplier.getBlock(liquidId); + newLiquid.setSpriteState(Water.WaterState.get(5)); + ((FlowingData) newLiquid.getData()).setSource(false); + world[y + 1][x].add(newLiquid); + flow(world, x, y + 1, 5, visited, liquidId); + return; + } + + if (strength == 1 || visited.contains(new Point(x, y))) { + return; + } + visited.add(new Point(x, y)); + + if (x - 1 >= 0 && canFlowInto(world[y][x - 1])) { + try { + transformOrFlow(world, x - 1, y, strength, visited, liquidId); + } catch (Exception _) {} + } + + if (x + 1 < world[y].length && canFlowInto(world[y][x + 1])) { + try { + transformOrFlow(world, x + 1, y, strength, visited, liquidId); + } catch (Exception _) {} + } + } + + private void transformOrFlow(List[][] world, int newX, int newY, int strength, Set visited, String liquidId) { + var targetBlocks = world[newY][newX]; + boolean hasWater = targetBlocks.stream().anyMatch(b -> b.getBlockId().equals("water")); + boolean hasLava = targetBlocks.stream().anyMatch(b -> b.getBlockId().equals("lava")); + boolean isLavaSource = hasLava && targetBlocks.stream().anyMatch(b -> ((FlowingData) b.getData()).isSource()); + + if (liquidId.equals("water") && hasLava) { + if (isLavaSource) { + world[newY][newX].add(ItemBlockSupplier.getBlock("obsidian")); + } else { + world[newY][newX].add(ItemBlockSupplier.getBlock("cobblestone")); + } + return; + } + if (liquidId.equals("lava") && hasWater) { + world[newY][newX].add(ItemBlockSupplier.getBlock("cobblestone")); + return; + } + + Block newLiquid = ItemBlockSupplier.getBlock(liquidId); + newLiquid.setSpriteState(Water.WaterState.get(strength - 1)); + ((FlowingData) newLiquid.getData()).setSource(false); + world[newY][newX].add(newLiquid); + flow(world, newX, newY, strength - 1, visited, liquidId); + } + + private boolean canFlowInto(List blocks) { + return blocks.stream().allMatch( + block -> block.getBlockId().equals("steve") || block.getBlockId().equals("air") || block.isMob() || block.isFlowing()); + } +} diff --git a/src/main/java/cz/jzitnik/game/logic/services/flowing/LavaWaterLogic.java b/src/main/java/cz/jzitnik/game/logic/services/flowing/LavaWaterLogic.java new file mode 100644 index 0000000..3372b1f --- /dev/null +++ b/src/main/java/cz/jzitnik/game/logic/services/flowing/LavaWaterLogic.java @@ -0,0 +1,47 @@ +package cz.jzitnik.game.logic.services.flowing; + +import cz.jzitnik.game.Game; +import cz.jzitnik.game.annotations.CustomLogic; +import cz.jzitnik.game.entities.items.ItemBlockSupplier; +import cz.jzitnik.game.logic.CustomLogicInterface; + +@CustomLogic +public class LavaWaterLogic implements CustomLogicInterface { + private static final int RADIUS = 20; + + @Override + public void nextIteration(Game game) { + int[] data = game.getPlayerCords(); + var world = game.getWorld(); + int playerX = data[0]; + int playerY = data[1]; + + int startX = Math.max(0, playerX - RADIUS); + int startY = Math.max(0, playerY - RADIUS); + int endX = Math.min(world[0].length - 1, playerX + RADIUS); + int endY = Math.min(world.length - 1, playerY + RADIUS); + + for (int y = startY; y <= endY; y++) { + for (int x = startX; x <= endX; x++) { + var blocks = world[y][x]; + if (blocks.stream().anyMatch(block -> block.getBlockId().equals("water") && blocks.stream().anyMatch(block2 -> block2.getBlockId().equals("lava")))) { + // Generate + var water = blocks.stream().filter(block -> block.getBlockId().equals("water")).findFirst().get(); + var lava = blocks.stream().filter(block -> block.getBlockId().equals("lava")).findFirst().get(); + + var waterData = (FlowingData) water.getData(); + var lavaData = (FlowingData) lava.getData(); + + world[y][x].remove(water); + world[y][x].remove(lava); + + if (lavaData.isSource()) { + world[y][x].add(ItemBlockSupplier.getBlock("obsidian")); + } else { + world[y][x].add(ItemBlockSupplier.getBlock("cobblestone")); + } + } + } + } + } +} diff --git a/src/main/java/cz/jzitnik/game/logic/services/flowing/lava/LavaData.java b/src/main/java/cz/jzitnik/game/logic/services/flowing/lava/LavaData.java deleted file mode 100644 index 67b97d9..0000000 --- a/src/main/java/cz/jzitnik/game/logic/services/flowing/lava/LavaData.java +++ /dev/null @@ -1,6 +0,0 @@ -package cz.jzitnik.game.logic.services.flowing.lava; - -import cz.jzitnik.game.logic.services.flowing.FlowingData; - -public class LavaData extends FlowingData { -} diff --git a/src/main/java/cz/jzitnik/game/logic/services/flowing/lava/LavaLogic.java b/src/main/java/cz/jzitnik/game/logic/services/flowing/lava/LavaLogic.java deleted file mode 100644 index 4276e63..0000000 --- a/src/main/java/cz/jzitnik/game/logic/services/flowing/lava/LavaLogic.java +++ /dev/null @@ -1,125 +0,0 @@ -package cz.jzitnik.game.logic.services.flowing.lava; - -import cz.jzitnik.game.Game; -import cz.jzitnik.game.annotations.CustomLogic; -import cz.jzitnik.game.entities.Block; -import cz.jzitnik.game.entities.items.ItemBlockSupplier; -import cz.jzitnik.game.logic.CustomLogicInterface; -import cz.jzitnik.game.sprites.Lava; -import lombok.AllArgsConstructor; -import lombok.Getter; - -import java.awt.*; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -@CustomLogic -public class LavaLogic implements CustomLogicInterface { - private static final int RADIUS = 20; - - @AllArgsConstructor - @Getter - private static class WaterBlock { - private Block block; - private int x; - private int y; - } - - @Override - public void nextIteration(Game game) { - int[] data = game.getPlayerCords(); - var world = game.getWorld(); - int playerX = data[0]; - int playerY = data[1]; - - int startX = Math.max(0, playerX - RADIUS); - int startY = Math.max(0, playerY - RADIUS); - int endX = Math.min(world[0].length - 1, playerX + RADIUS); - int endY = Math.min(world.length - 1, playerY + RADIUS); - - List sourceBlocks = new ArrayList<>(); - - for (int y = startY; y <= endY; y++) { - for (int x = startX; x <= endX; x++) { - var blocks = world[y][x]; - - var waterSourceBlocks = blocks.stream() - .filter(block -> block.getBlockId().equals("lava") && ((LavaData) block.getData()).isSource()) - .toList(); - if (!waterSourceBlocks.isEmpty()) { - sourceBlocks.add(new WaterBlock(waterSourceBlocks.getFirst(), x, y)); - } - - world[y][x].removeAll(blocks.stream() - .filter(i -> i.getBlockId().equals("lava") && !((LavaData) i.getData()).isSource()).toList()); - } - } - - for (WaterBlock sourceBlock : sourceBlocks) { - int x = sourceBlock.getX(); - int y = sourceBlock.getY(); - - flow(world, x, y, 5, new HashSet<>()); - } - - checkFire(game, startX, endX, startY, endY); - } - - public void flow(List[][] world, int x, int y, int strength, Set visited) { - if (y + 1 < world.length && waterCanFlow(world[y + 1][x])) { - Block newWater = ItemBlockSupplier.getBlock("lava"); - newWater.setSpriteState(Lava.LavaState.get(5)); - ((LavaData) newWater.getData()).setSource(false); - world[y + 1][x].add(newWater); - flow(world, x, y + 1, 5, visited); - return; - } - - if (strength == 1 || visited.contains(new Point(x, y))) { - return; - } - visited.add(new Point(x, y)); - - if (x - 1 >= 0 && waterCanFlow(world[y][x - 1])) { - Block newWater = ItemBlockSupplier.getBlock("lava"); - newWater.setSpriteState(Lava.LavaState.get(strength - 1)); - ((LavaData) newWater.getData()).setSource(false); - world[y][x - 1].add(newWater); - flow(world, x - 1, y, strength - 1, visited); - } - - if (x + 1 < world[y].length && waterCanFlow(world[y][x + 1])) { - Block newWater = ItemBlockSupplier.getBlock("lava"); - newWater.setSpriteState(Lava.LavaState.get(strength - 1)); - ((LavaData) newWater.getData()).setSource(false); - world[y][x + 1].add(newWater); - flow(world, x + 1, y, strength - 1, visited); - } - } - - public void checkFire(Game game, int startX, int endX, int startY, int endY) { - var world = game.getWorld(); - for (int y = startY; y <= endY; y++) { - for (int x = startX; x <= endX; x++) { - var blocks = world[y][x]; - if (blocks.stream().anyMatch(block -> block.getBlockId().equals("lava"))) { - var entities = blocks.stream().filter(Block::isMob).toList(); - for (Block block : entities) { - if (block.getBlockId().equals("steve")) { - game.getPlayer().setHealth(game.getPlayer().getHealth() - 1); - continue; - } - block.decreaseHp(1); - } - } - } - } - } - - private boolean waterCanFlow(List blocks) { - return blocks.stream().allMatch( - block -> block.getBlockId().equals("steve") || block.getBlockId().equals("air") || block.isMob()); - } -} diff --git a/src/main/java/cz/jzitnik/game/logic/services/flowing/water/WaterData.java b/src/main/java/cz/jzitnik/game/logic/services/flowing/water/WaterData.java deleted file mode 100644 index 5ae35f4..0000000 --- a/src/main/java/cz/jzitnik/game/logic/services/flowing/water/WaterData.java +++ /dev/null @@ -1,6 +0,0 @@ -package cz.jzitnik.game.logic.services.flowing.water; - -import cz.jzitnik.game.logic.services.flowing.FlowingData; - -public class WaterData extends FlowingData { -} diff --git a/src/main/java/cz/jzitnik/game/logic/services/flowing/water/WaterLogic.java b/src/main/java/cz/jzitnik/game/logic/services/flowing/water/WaterLogic.java deleted file mode 100644 index eae0d11..0000000 --- a/src/main/java/cz/jzitnik/game/logic/services/flowing/water/WaterLogic.java +++ /dev/null @@ -1,104 +0,0 @@ -package cz.jzitnik.game.logic.services.flowing.water; - -import cz.jzitnik.game.Game; -import cz.jzitnik.game.annotations.CustomLogic; -import cz.jzitnik.game.entities.Block; -import cz.jzitnik.game.entities.items.ItemBlockSupplier; -import cz.jzitnik.game.logic.CustomLogicInterface; -import cz.jzitnik.game.sprites.Water; -import lombok.AllArgsConstructor; -import lombok.Getter; - -import java.awt.*; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -@CustomLogic -public class WaterLogic implements CustomLogicInterface { - private static final int RADIUS = 20; - - @AllArgsConstructor - @Getter - private static class WaterBlock { - private Block block; - private int x; - private int y; - } - - @Override - public void nextIteration(Game game) { - int[] data = game.getPlayerCords(); - var world = game.getWorld(); - int playerX = data[0]; - int playerY = data[1]; - - int startX = Math.max(0, playerX - RADIUS); - int startY = Math.max(0, playerY - RADIUS); - int endX = Math.min(world[0].length - 1, playerX + RADIUS); - int endY = Math.min(world.length - 1, playerY + RADIUS); - - List sourceBlocks = new ArrayList<>(); - - for (int y = startY; y <= endY; y++) { - for (int x = startX; x <= endX; x++) { - var blocks = world[y][x]; - - var waterSourceBlocks = blocks.stream() - .filter(block -> block.getBlockId().equals("water") && ((WaterData) block.getData()).isSource()) - .toList(); - if (!waterSourceBlocks.isEmpty()) { - sourceBlocks.add(new WaterBlock(waterSourceBlocks.getFirst(), x, y)); - } - - world[y][x].removeAll(blocks.stream() - .filter(i -> i.getBlockId().equals("water") && !((WaterData) i.getData()).isSource()).toList()); - } - } - - for (WaterBlock sourceBlock : sourceBlocks) { - int x = sourceBlock.getX(); - int y = sourceBlock.getY(); - - flow(world, x, y, 5, new HashSet<>()); - } - } - - public void flow(List[][] world, int x, int y, int strength, Set visited) { - if (y + 1 < world.length && waterCanFlow(world[y + 1][x])) { - Block newWater = ItemBlockSupplier.getBlock("water"); - newWater.setSpriteState(Water.WaterState.get(5)); - ((WaterData) newWater.getData()).setSource(false); - world[y + 1][x].add(newWater); - flow(world, x, y + 1, 5, visited); - return; - } - - if (strength == 1 || visited.contains(new Point(x, y))) { - return; - } - visited.add(new Point(x, y)); - - if (x - 1 >= 0 && waterCanFlow(world[y][x - 1])) { - Block newWater = ItemBlockSupplier.getBlock("water"); - newWater.setSpriteState(Water.WaterState.get(strength - 1)); - ((WaterData) newWater.getData()).setSource(false); - world[y][x - 1].add(newWater); - flow(world, x - 1, y, strength - 1, visited); - } - - if (x + 1 < world[y].length && waterCanFlow(world[y][x + 1])) { - Block newWater = ItemBlockSupplier.getBlock("water"); - newWater.setSpriteState(Water.WaterState.get(strength - 1)); - ((WaterData) newWater.getData()).setSource(false); - world[y][x + 1].add(newWater); - flow(world, x + 1, y, strength - 1, visited); - } - } - - private boolean waterCanFlow(List blocks) { - return blocks.stream().allMatch( - block -> block.getBlockId().equals("steve") || block.getBlockId().equals("air") || block.isMob()); - } -} diff --git a/src/main/java/cz/jzitnik/game/sprites/Lava.java b/src/main/java/cz/jzitnik/game/sprites/Lava.java index 614a7a0..d799f14 100644 --- a/src/main/java/cz/jzitnik/game/sprites/Lava.java +++ b/src/main/java/cz/jzitnik/game/sprites/Lava.java @@ -6,34 +6,19 @@ import cz.jzitnik.tui.Sprite; import java.util.Optional; public class Lava extends Sprite { - public enum LavaState { - FIRST, SECOND, THIRD, FOURTH, FIFTH; - - public static LavaState get(int x) { - return switch (x) { - case 5 -> FIRST; - case 4 -> SECOND; - case 3 -> THIRD; - case 2 -> FOURTH; - case 1 -> FIFTH; - default -> throw new IllegalStateException("Unexpected value: " + x); - }; - } - } - public String getSprite() { - return getSprite(LavaState.FIRST); + return getSprite(Water.WaterState.FIRST); } public String getSprite(Enum e) { String[] resource = ResourceLoader.loadResource("lava.ans").split("\n"); int numberFormTop = switch (e) { - case LavaState.FIRST -> 0; - case LavaState.SECOND -> 5; - case LavaState.THIRD -> 10; - case LavaState.FOURTH -> 15; - case LavaState.FIFTH -> 20; + case Water.WaterState.FIRST -> 0; + case Water.WaterState.SECOND -> 5; + case Water.WaterState.THIRD -> 10; + case Water.WaterState.FOURTH -> 15; + case Water.WaterState.FIFTH -> 20; default -> throw new IllegalStateException("Unexpected value: " + e); }; @@ -52,7 +37,7 @@ public class Lava extends Sprite { } @Override - public Optional> getStates() { - return Optional.of(LavaState.class); + public Optional> getStates() { + return Optional.of(Water.WaterState.class); } } diff --git a/src/main/resources/textures/obsidian.ans b/src/main/resources/textures/obsidian.ans new file mode 100644 index 0000000..cd1fe1c --- /dev/null +++ b/src/main/resources/textures/obsidian.ans @@ -0,0 +1,25 @@ +                    +                      +                      +                        +                       +                     +                       +                       +                     +                       +                      +                         +                     +                      +                  +                        +                    +                       +                    +                      +                     +                  +                   +                +