From 331efa9ffd9716672a956eabf0cc57071bc7556a Mon Sep 17 00:00:00 2001 From: jannis Date: Wed, 28 Oct 2026 21:56:28 +0100 Subject: [PATCH] replaced BlockPlacementHelper in BuildBattle with blocks-and-stuff placement rules --- build.gradle | 4 + .../buildBattle/BlockPlacementHelper.java | 896 ------------------ .../types/buildBattle/BuildBattle.java | 5 +- .../buildBattle/BuildBattleBlockRules.java | 85 ++ 4 files changed, 91 insertions(+), 899 deletions(-) delete mode 100644 src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BlockPlacementHelper.java create mode 100644 src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BuildBattleBlockRules.java diff --git a/build.gradle b/build.gradle index a216060..9a890d3 100644 --- a/build.gradle +++ b/build.gradle @@ -11,6 +11,7 @@ version '1.0-SNAPSHOT' repositories { mavenCentral() + maven { url = 'https://mvn.everbuild.org/public' } } java { @@ -38,6 +39,9 @@ dependencies { //PvP implementation 'io.github.togar2:MinestomPvP:2026.05.30-26.1.1' + + //Block placement + implementation 'org.everbuild.blocksandstuff:blocksandstuff-blocks:1.10.2-SNAPSHOT' } tasks { diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BlockPlacementHelper.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BlockPlacementHelper.java deleted file mode 100644 index 8d661a3..0000000 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BlockPlacementHelper.java +++ /dev/null @@ -1,896 +0,0 @@ -package eu.mhsl.minenet.minigames.instance.game.stateless.types.buildBattle; - -import net.minestom.server.coordinate.BlockVec; -import net.minestom.server.coordinate.Point; -import net.minestom.server.entity.Player; -import net.minestom.server.event.player.PlayerBlockBreakEvent; -import net.minestom.server.event.player.PlayerBlockInteractEvent; -import net.minestom.server.event.player.PlayerBlockPlaceEvent; -import net.minestom.server.instance.Instance; -import net.minestom.server.instance.block.Block; -import net.minestom.server.instance.block.BlockFace; -import net.minestom.server.utils.Direction; - -import java.util.Map; -import java.util.Set; - -public final class BlockPlacementHelper { - private BlockPlacementHelper() {} - - private static final Set SIX_DIR = Set.of( - "observer", "dispenser", "dropper", "piston", "sticky_piston", - "amethyst_cluster", "small_amethyst_bud", "medium_amethyst_bud", "large_amethyst_bud", - "end_rod", "lightning_rod", "shulker_box" - ); - - public static void apply(PlayerBlockPlaceEvent event) { - Block block = event.getBlock(); - BlockFace face = event.getBlockFace(); - BlockVec pos = event.getBlockPosition(); - Point cursor = event.getCursorPosition(); - Player player = event.getPlayer(); - Instance instance = event.getInstance(); - - String path = block.key().value(); - - Block existing = instance.getBlock(pos); - if ((path.endsWith("_candle") || path.equals("candle")) && existing.compare(block)) { - int n = parseIntOr(existing.getProperty("candles"), 1); - event.setBlock(n < 4 ? existing.withProperty("candles", String.valueOf(n + 1)) : existing); - return; - } - if (path.equals("snow") && existing.compare(block)) { - int n = parseIntOr(existing.getProperty("layers"), 1); - event.setBlock(n < 8 ? existing.withProperty("layers", String.valueOf(n + 1)) : existing); - return; - } - if (path.equals("sea_pickle") && existing.compare(block)) { - int n = parseIntOr(existing.getProperty("pickles"), 1); - event.setBlock(n < 4 ? existing.withProperty("pickles", String.valueOf(n + 1)) : existing); - return; - } - if (path.equals("turtle_egg") && existing.compare(block)) { - int n = parseIntOr(existing.getProperty("eggs"), 1); - event.setBlock(n < 4 ? existing.withProperty("eggs", String.valueOf(n + 1)) : existing); - return; - } - - Block oriented = orient(block, path, face, cursor, player, instance, pos); - if (oriented != block) event.setBlock(oriented); - - Block finalOriented = oriented; - String finalPath = finalOriented.key().value(); - - if (path.endsWith("_door")) { - Block lower = event.getBlock(); - String facing = lower.getProperty("facing"); - String hinge = lower.getProperty("hinge"); - Block upper = lower.withProperty("half", "upper").withProperty("facing", facing).withProperty("hinge", hinge); - instance.scheduler().scheduleNextTick(() -> instance.setBlock(pos.add(0, 1, 0), upper)); - } - - if (path.endsWith("_bed")) { - String facing = finalOriented.getProperty("facing"); - Direction d = facingToDirection(facing); - Block head = finalOriented.withProperty("part", "head"); - BlockVec headPos = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - instance.scheduler().scheduleNextTick(() -> instance.setBlock(headPos, head)); - } - - if (path.equals("big_dripleaf")) { - Block upper = finalOriented; - Block lower = Block.BIG_DRIPLEAF_STEM.withProperty("facing", finalOriented.getProperty("facing")); - instance.scheduler().scheduleNextTick(() -> instance.setBlock(pos.add(0, 1, 0), upper.withProperty("half", "upper"))); - } - - if (isConnecting(path)) { - instance.scheduler().scheduleNextTick(() -> { - for (Direction d : Direction.HORIZONTAL) { - BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - Block nb = instance.getBlock(np); - if (isConnecting(nb.key().value())) instance.setBlock(np, computeConnections(nb, nb.key().value(), instance, np)); - } - Block self = instance.getBlock(pos); - if (isConnecting(self.key().value())) instance.setBlock(pos, computeConnections(self, self.key().value(), instance, pos)); - for (Direction d : Direction.HORIZONTAL) { - BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - Block nb = instance.getBlock(np); - if (nb.key().value().endsWith("_fence_gate")) { - instance.setBlock(np, updateFenceGateInWall(nb, instance, np)); - } - } - }); - } - - if (path.endsWith("_fence_gate")) { - instance.scheduler().scheduleNextTick(() -> instance.setBlock(pos, updateFenceGateInWall(instance.getBlock(pos), instance, pos))); - } - - if (path.equals("redstone_wire")) { - instance.scheduler().scheduleNextTick(() -> { - updateRedstoneWire(instance, pos); - for (Direction d : Direction.HORIZONTAL) { - BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - if (instance.getBlock(np).key().value().equals("redstone_wire")) updateRedstoneWire(instance, np); - } - }); - } - - if (isRail(path)) { - instance.scheduler().scheduleNextTick(() -> updateRailShape(instance, pos)); - } - - if (path.equals("scaffolding")) { - instance.scheduler().scheduleNextTick(() -> updateScaffolding(instance, pos)); - } - - if (finalPath.equals("chest") || finalPath.equals("trapped_chest")) { - instance.scheduler().scheduleNextTick(() -> updateChestPair(instance, pos)); - } - } - - private static Block orient(Block block, String path, BlockFace face, Point cursor, Player player, - Instance instance, BlockVec pos) { - Map props = block.properties(); - Block result = block; - - if (props.containsKey("axis")) { - result = result.withProperty("axis", switch (face) { - case TOP, BOTTOM -> "y"; - case NORTH, SOUTH -> "z"; - case EAST, WEST -> "x"; - }); - } - - if (props.containsKey("type") && path.endsWith("_slab")) { - Block existing = instance.getBlock(pos); - if (existing.compare(block)) { - result = result.withProperty("type", "double"); - } else { - boolean top = face == BlockFace.BOTTOM || (face != BlockFace.TOP && cursor.y() > 0.5); - result = result.withProperty("type", top ? "top" : "bottom"); - } - } - - if (path.endsWith("_stairs")) { - String facing = yawToFacing(player.getPosition().yaw()); - boolean top = face == BlockFace.BOTTOM || (face != BlockFace.TOP && cursor.y() > 0.5); - result = result.withProperty("facing", facing).withProperty("half", top ? "top" : "bottom"); - result = applyStairShape(result, instance, pos, facing, top); - } - - if (path.endsWith("_trapdoor")) { - String facing; - boolean top; - if (face == BlockFace.TOP) { top = false; facing = yawToFacing(player.getPosition().yaw() + 180); } - else if (face == BlockFace.BOTTOM) { top = true; facing = yawToFacing(player.getPosition().yaw() + 180); } - else { top = cursor.y() > 0.5; facing = oppositeFacing(faceName(face)); } - result = result.withProperty("facing", facing).withProperty("half", top ? "top" : "bottom") - .withProperty("open", "false").withProperty("powered", "false"); - } - - if (path.endsWith("_door")) { - String facing = yawToFacing(player.getPosition().yaw()); - String hinge = doorHinge(facing, cursor, instance, pos, path); - result = result.withProperty("facing", facing) - .withProperty("half", "lower") - .withProperty("hinge", hinge) - .withProperty("open", "false") - .withProperty("powered", "false"); - } - - if (path.endsWith("_fence_gate")) { - String facing = yawToFacing(player.getPosition().yaw()); - result = result.withProperty("facing", facing).withProperty("open", "false") - .withProperty("powered", "false").withProperty("in_wall", "false"); - } - - if (path.endsWith("_bed")) { - String facing = yawToFacing(player.getPosition().yaw()); - result = result.withProperty("facing", facing).withProperty("part", "foot").withProperty("occupied", "false"); - } - - if (path.endsWith("_button") || path.equals("lever") || path.equals("grindstone")) { - String attachFace; String facing; - if (face == BlockFace.TOP) { attachFace = "floor"; facing = yawToFacing(player.getPosition().yaw()); } - else if (face == BlockFace.BOTTOM) { attachFace = "ceiling"; facing = yawToFacing(player.getPosition().yaw()); } - else { attachFace = "wall"; facing = oppositeFacing(faceName(face)); } - result = result.withProperty("face", attachFace).withProperty("facing", facing); - } - - if (path.equals("bell")) { - String attachment; String facing; - if (face == BlockFace.TOP) { attachment = "floor"; facing = yawToFacing(player.getPosition().yaw()); } - else if (face == BlockFace.BOTTOM) { attachment = "ceiling"; facing = yawToFacing(player.getPosition().yaw()); } - else { - attachment = "single_wall"; - facing = oppositeFacing(faceName(face)); - } - result = result.withProperty("attachment", attachment).withProperty("facing", facing); - } - - if (path.equals("lantern") || path.equals("soul_lantern")) { - result = result.withProperty("hanging", face == BlockFace.BOTTOM ? "true" : "false"); - } - - if (path.equals("tripwire_hook")) { - String facing = face != BlockFace.TOP && face != BlockFace.BOTTOM - ? oppositeFacing(faceName(face)) - : yawToFacing(player.getPosition().yaw()); - result = result.withProperty("facing", facing).withProperty("attached", "false").withProperty("powered", "false"); - } - - if (path.equals("hopper")) { - String facing = face == BlockFace.TOP ? "down" : (face == BlockFace.BOTTOM ? "down" : oppositeFacing(faceName(face))); - result = result.withProperty("facing", facing).withProperty("enabled", "true"); - } - - if (path.equals("campfire") || path.equals("soul_campfire")) { - Block below = instance.getBlock(new BlockVec(pos.blockX(), pos.blockY() - 1, pos.blockZ())); - String signalFire = below.key().value().equals("hay_block") ? "true" : "false"; - result = result.withProperty("facing", yawToFacing(player.getPosition().yaw())) - .withProperty("lit", "true").withProperty("signal_fire", signalFire); - } - - if (path.equals("pointed_dripstone")) { - String dir = face == BlockFace.BOTTOM ? "down" : "up"; - result = result.withProperty("vertical_direction", dir).withProperty("thickness", "tip"); - } - - if (path.equals("chorus_flower")) { - result = result.withProperty("age", "0"); - } - - if (path.equals("end_portal_frame") || path.equals("respawn_anchor")) { - if (props.containsKey("facing")) { - result = result.withProperty("facing", yawToFacing(player.getPosition().yaw())); - } - if (props.containsKey("eye")) result = result.withProperty("eye", "false"); - } - - if ((path.equals("torch") || path.equals("soul_torch") || path.equals("redstone_torch") || path.equals("copper_torch")) - && face != BlockFace.TOP && face != BlockFace.BOTTOM) { - Block wall = switch (path) { - case "torch" -> Block.WALL_TORCH; - case "soul_torch" -> Block.SOUL_WALL_TORCH; - case "redstone_torch" -> Block.REDSTONE_WALL_TORCH; - case "copper_torch" -> Block.COPPER_WALL_TORCH; - default -> null; - }; - if (wall != null) result = wall.withProperty("facing", oppositeFacing(faceName(face))); - } - - if (path.endsWith("_skull") || path.endsWith("_head")) { - if (face != BlockFace.TOP && face != BlockFace.BOTTOM) { - String wallName = path.endsWith("_skull") ? path.replace("_skull", "_wall_skull") : path.replace("_head", "_wall_head"); - Block wall = Block.fromKey("minecraft:" + wallName); - if (wall != null) result = wall.withProperty("facing", oppositeFacing(faceName(face))); - } else if (face == BlockFace.TOP && result.properties().containsKey("rotation")) { - int rot = (int) Math.floor(((player.getPosition().yaw() + 180.0) * 16.0 / 360.0) + 0.5) & 15; - result = result.withProperty("rotation", String.valueOf(rot)); - } - } - - if (path.endsWith("_sign") && !path.endsWith("_wall_sign") && !path.contains("hanging") - && face != BlockFace.TOP && face != BlockFace.BOTTOM) { - Block wallSign = Block.fromKey("minecraft:" + path.replace("_sign", "_wall_sign")); - if (wallSign != null) result = wallSign.withProperty("facing", oppositeFacing(faceName(face))); - } else if (path.endsWith("_sign") && !path.endsWith("_wall_sign") && !path.contains("hanging") - && face == BlockFace.TOP) { - int rot = (int) Math.floor(((player.getPosition().yaw() + 180.0) * 16.0 / 360.0) + 0.5) & 15; - if (result.properties().containsKey("rotation")) result = result.withProperty("rotation", String.valueOf(rot)); - } - - if (path.endsWith("_hanging_sign") && !path.contains("_wall_") - && face != BlockFace.TOP && face != BlockFace.BOTTOM) { - Block wallHang = Block.fromKey("minecraft:" + path.replace("_hanging_sign", "_wall_hanging_sign")); - if (wallHang != null) result = wallHang.withProperty("facing", oppositeFacing(faceName(face))); - } else if (path.endsWith("_hanging_sign") && !path.contains("_wall_")) { - int rot = (int) Math.floor(((player.getPosition().yaw() + 180.0) * 16.0 / 360.0) + 0.5) & 15; - if (result.properties().containsKey("rotation")) result = result.withProperty("rotation", String.valueOf(rot)); - if (result.properties().containsKey("attached")) result = result.withProperty("attached", face == BlockFace.BOTTOM ? "true" : "false"); - } - - if (isBanner(path)) { - if (face != BlockFace.TOP && face != BlockFace.BOTTOM) { - Block wallBanner = Block.fromKey("minecraft:" + path.replace("_banner", "_wall_banner")); - if (wallBanner != null) result = wallBanner.withProperty("facing", oppositeFacing(faceName(face))); - } else if (face == BlockFace.TOP) { - int rot = (int) Math.floor(((player.getPosition().yaw() + 180.0) * 16.0 / 360.0) + 0.5) & 15; - if (result.properties().containsKey("rotation")) result = result.withProperty("rotation", String.valueOf(rot)); - } - } - - if (path.equals("vine")) { - Block existing = instance.getBlock(pos); - Block base = existing.compare(block) ? existing : result.withProperty("up", "false") - .withProperty("north", "false").withProperty("south", "false") - .withProperty("east", "false").withProperty("west", "false"); - String side = switch (face) { - case BOTTOM -> "up"; - case NORTH -> "south"; - case SOUTH -> "north"; - case EAST -> "west"; - case WEST -> "east"; - default -> null; - }; - result = side != null ? base.withProperty(side, "true") : base; - } - - if (path.equals("glow_lichen") || path.equals("sculk_vein") || path.equals("resin_clump")) { - Block existing = instance.getBlock(pos); - Block base = existing.compare(block) ? existing : result - .withProperty("up", "false").withProperty("down", "false") - .withProperty("north", "false").withProperty("south", "false") - .withProperty("east", "false").withProperty("west", "false"); - String side = switch (face) { - case TOP -> "down"; - case BOTTOM -> "up"; - case NORTH -> "south"; - case SOUTH -> "north"; - case EAST -> "west"; - case WEST -> "east"; - }; - result = base.withProperty(side, "true"); - } - - if (path.equals("red_mushroom_block") || path.equals("brown_mushroom_block") || path.equals("mushroom_stem")) { - result = result.withProperty("up", "true").withProperty("down", "true") - .withProperty("north", "true").withProperty("south", "true") - .withProperty("east", "true").withProperty("west", "true"); - String hiddenFace = faceName(face); - if (result.properties().containsKey(hiddenFace)) result = result.withProperty(hiddenFace, "false"); - } - - if (props.containsKey("facing") && !path.endsWith("_stairs") && !path.endsWith("_door") - && !path.endsWith("_trapdoor") && !path.endsWith("_fence_gate") && !path.endsWith("_button") - && !path.equals("lever") && !path.equals("grindstone") && !path.equals("bell") - && !path.equals("hopper") && !path.equals("campfire") && !path.equals("soul_campfire") - && !path.equals("tripwire_hook") - && !path.endsWith("wall_torch") && !path.endsWith("_bed") && !path.endsWith("_sign") - && !path.endsWith("_hanging_sign") && !path.endsWith("_banner") && !path.endsWith("_wall_banner") - && !path.endsWith("_skull") && !path.endsWith("_head") - && !path.equals("end_portal_frame") && !path.equals("respawn_anchor")) { - Direction fdir = faceDirection(face); - String facing; - if (fdir != null && SIX_DIR.contains(path)) { - facing = fdir.opposite().name().toLowerCase(); - } else if (path.equals("repeater") || path.equals("comparator")) { - facing = oppositeFacing(yawToFacing(player.getPosition().yaw())); - } else { - facing = yawToFacing(player.getPosition().yaw()); - } - try { result = result.withProperty("facing", facing); } catch (Exception ignored) {} - } - - if (isConnecting(path)) result = computeConnections(result, path, instance, pos); - - if (props.containsKey("waterlogged") && Block.WATER.compare(instance.getBlock(pos))) { - try { result = result.withProperty("waterlogged", "true"); } catch (Exception ignored) {} - } - - return result; - } - - private static boolean isBanner(String path) { - return path.endsWith("_banner") && !path.endsWith("_wall_banner"); - } - - private static Block applyStairShape(Block stair, Instance instance, BlockVec pos, String facing, boolean top) { - Direction f = facingToDirection(facing); - Block front = instance.getBlock(new BlockVec(pos.blockX() + f.normalX(), pos.blockY(), pos.blockZ() + f.normalZ())); - if (front.key().value().endsWith("_stairs") && top == isTopStair(front)) { - Direction frontFacing = facingToDirection(front.getProperty("facing")); - if (frontFacing != f && frontFacing != f.opposite()) { - if (frontFacing == rotateCW(f)) return stair.withProperty("shape", "outer_right"); - else return stair.withProperty("shape", "outer_left"); - } - } - Block back = instance.getBlock(new BlockVec(pos.blockX() - f.normalX(), pos.blockY(), pos.blockZ() - f.normalZ())); - if (back.key().value().endsWith("_stairs") && top == isTopStair(back)) { - Direction backFacing = facingToDirection(back.getProperty("facing")); - if (backFacing != f && backFacing != f.opposite()) { - if (backFacing == rotateCW(f)) return stair.withProperty("shape", "inner_right"); - else return stair.withProperty("shape", "inner_left"); - } - } - return stair.withProperty("shape", "straight"); - } - - private static boolean isTopStair(Block b) { return "top".equals(b.getProperty("half")); } - - private static Block computeConnections(Block block, String path, Instance instance, BlockVec pos) { - boolean isWall = path.endsWith("_wall") && !path.endsWith("head_wall") && !path.endsWith("_wall_sign") && !path.endsWith("_wall_banner"); - if (path.endsWith("_fence_gate")) return block; - - Block result = block; - for (Direction d : Direction.HORIZONTAL) { - BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - Block nb = instance.getBlock(np); - boolean connect = canConnectTo(nb, path, d); - String propName = d.name().toLowerCase(); - if (isWall) { - boolean tall = connect && isSolidAbove(instance, pos); - result = result.withProperty(propName, connect ? (tall ? "tall" : "low") : "none"); - } else { - result = result.withProperty(propName, connect ? "true" : "false"); - } - } - if (isWall && result.properties().containsKey("up")) { - boolean up = computeWallUp(result, instance, pos); - result = result.withProperty("up", up ? "true" : "false"); - } - return result; - } - - private static boolean isSolidAbove(Instance instance, BlockVec pos) { - Block above = instance.getBlock(new BlockVec(pos.blockX(), pos.blockY() + 1, pos.blockZ())); - return above.isSolid(); - } - - private static boolean computeWallUp(Block wall, Instance instance, BlockVec pos) { - boolean n = !"none".equals(wall.getProperty("north")); - boolean s = !"none".equals(wall.getProperty("south")); - boolean e = !"none".equals(wall.getProperty("east")); - boolean w = !"none".equals(wall.getProperty("west")); - boolean straight = (n && s && !e && !w) || (!n && !s && e && w); - if (!straight) return true; - return isSolidAbove(instance, pos); - } - - private static boolean canConnectTo(Block neighbor, String selfPath, Direction toward) { - if (neighbor.isAir()) return false; - String np = neighbor.key().value(); - if (np.endsWith("_fence_gate")) { - String facing = neighbor.getProperty("facing"); - if (facing != null) { - Direction f = facingToDirection(facing); - return toward != f && toward != f.opposite(); - } - return true; - } - if (selfPath.endsWith("_fence") && np.endsWith("_fence")) { - boolean selfNether = selfPath.contains("nether_brick"); - boolean nNether = np.contains("nether_brick"); - return selfNether == nNether; - } - if (selfPath.endsWith("_wall") && np.endsWith("_wall")) return true; - if ((selfPath.equals("glass_pane") || selfPath.endsWith("_stained_glass_pane") || selfPath.equals("iron_bars")) - && (np.equals("glass_pane") || np.endsWith("_stained_glass_pane") || np.equals("iron_bars"))) return true; - return neighbor.isSolid(); - } - - private static boolean isConnecting(String path) { - return path.endsWith("_fence") || (path.endsWith("_wall") && !path.endsWith("head_wall") - && !path.endsWith("_wall_sign") && !path.endsWith("_wall_banner") && !path.endsWith("_wall_torch") - && !path.endsWith("_wall_skull") && !path.endsWith("_wall_head") && !path.endsWith("_wall_hanging_sign")) - || path.equals("iron_bars") || path.equals("glass_pane") || path.endsWith("_stained_glass_pane"); - } - - private static Block updateFenceGateInWall(Block gate, Instance instance, BlockVec pos) { - if (!gate.key().value().endsWith("_fence_gate")) return gate; - String facing = gate.getProperty("facing"); - if (facing == null) return gate; - Direction f = facingToDirection(facing); - Direction left = rotateCCW(f); - Direction right = rotateCW(f); - Block l = instance.getBlock(new BlockVec(pos.blockX() + left.normalX(), pos.blockY(), pos.blockZ() + left.normalZ())); - Block r = instance.getBlock(new BlockVec(pos.blockX() + right.normalX(), pos.blockY(), pos.blockZ() + right.normalZ())); - boolean inWall = l.key().value().endsWith("_wall") || r.key().value().endsWith("_wall"); - return gate.withProperty("in_wall", inWall ? "true" : "false"); - } - - private static void updateRedstoneWire(Instance instance, BlockVec pos) { - Block wire = instance.getBlock(pos); - if (!wire.key().value().equals("redstone_wire")) return; - Block result = wire; - for (Direction d : Direction.HORIZONTAL) { - BlockVec side = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - Block sideBlock = instance.getBlock(side); - Block upBlock = instance.getBlock(new BlockVec(side.blockX(), side.blockY() + 1, side.blockZ())); - String state; - if (upBlock.key().value().equals("redstone_wire")) state = "up"; - else if (isRedstoneConnectable(sideBlock) - || instance.getBlock(new BlockVec(side.blockX(), side.blockY() - 1, side.blockZ())).key().value().equals("redstone_wire")) state = "side"; - else state = "none"; - result = result.withProperty(d.name().toLowerCase(), state); - } - instance.setBlock(pos, result); - } - - private static boolean isRedstoneConnectable(Block b) { - String p = b.key().value(); - return p.equals("redstone_wire") || p.equals("lever") || p.endsWith("_button") - || p.equals("repeater") || p.equals("comparator") || p.equals("redstone_torch") - || p.equals("redstone_wall_torch") || p.equals("observer") || p.equals("daylight_detector") - || p.endsWith("_pressure_plate") || p.equals("target") || p.equals("redstone_block") - || p.equals("tripwire_hook"); - } - - private static boolean isRail(String path) { - return path.equals("rail") || path.equals("powered_rail") || path.equals("detector_rail") || path.equals("activator_rail"); - } - - private static void updateRailShape(Instance instance, BlockVec pos) { - Block rail = instance.getBlock(pos); - String path = rail.key().value(); - if (!isRail(path)) return; - boolean canCurve = path.equals("rail"); - boolean[] adj = new boolean[4]; - boolean[] ascAdj = new boolean[4]; - Direction[] dirs = {Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST}; - for (int i = 0; i < 4; i++) { - BlockVec np = new BlockVec(pos.blockX() + dirs[i].normalX(), pos.blockY(), pos.blockZ() + dirs[i].normalZ()); - adj[i] = isRail(instance.getBlock(np).key().value()); - BlockVec upNp = new BlockVec(np.blockX(), np.blockY() + 1, np.blockZ()); - ascAdj[i] = isRail(instance.getBlock(upNp).key().value()); - } - String shape; - if (canCurve) { - if (adj[0] && adj[1]) shape = "north_east"; - else if (adj[1] && adj[2]) shape = "south_east"; - else if (adj[2] && adj[3]) shape = "south_west"; - else if (adj[3] && adj[0]) shape = "north_west"; - else if (ascAdj[0]) shape = "ascending_north"; - else if (ascAdj[1]) shape = "ascending_east"; - else if (ascAdj[2]) shape = "ascending_south"; - else if (ascAdj[3]) shape = "ascending_west"; - else if (adj[1] || adj[3]) shape = "east_west"; - else shape = "north_south"; - } else { - if (ascAdj[0]) shape = "ascending_north"; - else if (ascAdj[1]) shape = "ascending_east"; - else if (ascAdj[2]) shape = "ascending_south"; - else if (ascAdj[3]) shape = "ascending_west"; - else if (adj[1] || adj[3]) shape = "east_west"; - else shape = "north_south"; - } - instance.setBlock(pos, rail.withProperty("shape", shape)); - } - - private static void updateScaffolding(Instance instance, BlockVec pos) { - Block s = instance.getBlock(pos); - if (!s.key().value().equals("scaffolding")) return; - Block below = instance.getBlock(new BlockVec(pos.blockX(), pos.blockY() - 1, pos.blockZ())); - boolean bottom; - int distance; - if (below.isSolid() && !below.key().value().equals("scaffolding")) { bottom = false; distance = 0; } - else if (below.key().value().equals("scaffolding")) { bottom = false; distance = 0; } - else { - int min = 7; - for (Direction d : Direction.HORIZONTAL) { - Block n = instance.getBlock(new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ())); - if (n.key().value().equals("scaffolding")) min = Math.min(min, parseIntOr(n.getProperty("distance"), 7) + 1); - } - bottom = true; - distance = min; - } - instance.setBlock(pos, s.withProperty("bottom", String.valueOf(bottom)).withProperty("distance", String.valueOf(distance))); - } - - private static void updateChestPair(Instance instance, BlockVec pos) { - Block chest = instance.getBlock(pos); - String path = chest.key().value(); - if (!(path.equals("chest") || path.equals("trapped_chest"))) return; - String facing = chest.getProperty("facing"); - if (facing == null) return; - Direction f = facingToDirection(facing); - Direction left = rotateCCW(f); - Direction right = rotateCW(f); - BlockVec leftPos = new BlockVec(pos.blockX() + left.normalX(), pos.blockY(), pos.blockZ() + left.normalZ()); - BlockVec rightPos = new BlockVec(pos.blockX() + right.normalX(), pos.blockY(), pos.blockZ() + right.normalZ()); - Block leftBlock = instance.getBlock(leftPos); - Block rightBlock = instance.getBlock(rightPos); - if (leftBlock.key().value().equals(path) && facing.equals(leftBlock.getProperty("facing")) - && "single".equals(leftBlock.getProperty("type"))) { - instance.setBlock(pos, chest.withProperty("type", "right")); - instance.setBlock(leftPos, leftBlock.withProperty("type", "left")); - return; - } - if (rightBlock.key().value().equals(path) && facing.equals(rightBlock.getProperty("facing")) - && "single".equals(rightBlock.getProperty("type"))) { - instance.setBlock(pos, chest.withProperty("type", "left")); - instance.setBlock(rightPos, rightBlock.withProperty("type", "right")); - } - } - - private static String yawToFacing(float yaw) { - float y = ((yaw % 360) + 360) % 360; - if (y >= 315 || y < 45) return "south"; - if (y < 135) return "west"; - if (y < 225) return "north"; - return "east"; - } - - private static String faceName(BlockFace face) { - return switch (face) { - case NORTH -> "north"; - case SOUTH -> "south"; - case EAST -> "east"; - case WEST -> "west"; - case TOP -> "up"; - case BOTTOM -> "down"; - }; - } - - private static String oppositeFacing(String f) { - return switch (f) { - case "north" -> "south"; - case "south" -> "north"; - case "east" -> "west"; - case "west" -> "east"; - case "up" -> "down"; - case "down" -> "up"; - default -> f; - }; - } - - private static Direction faceDirection(BlockFace face) { - return switch (face) { - case NORTH -> Direction.NORTH; - case SOUTH -> Direction.SOUTH; - case EAST -> Direction.EAST; - case WEST -> Direction.WEST; - case TOP -> Direction.UP; - case BOTTOM -> Direction.DOWN; - }; - } - - private static Direction facingToDirection(String f) { - if (f == null) return Direction.NORTH; - return switch (f) { - case "north" -> Direction.NORTH; - case "south" -> Direction.SOUTH; - case "east" -> Direction.EAST; - case "west" -> Direction.WEST; - case "up" -> Direction.UP; - case "down" -> Direction.DOWN; - default -> Direction.NORTH; - }; - } - - private static Direction rotateCW(Direction d) { - return switch (d) { - case NORTH -> Direction.EAST; - case EAST -> Direction.SOUTH; - case SOUTH -> Direction.WEST; - case WEST -> Direction.NORTH; - default -> d; - }; - } - - private static Direction rotateCCW(Direction d) { - return switch (d) { - case NORTH -> Direction.WEST; - case WEST -> Direction.SOUTH; - case SOUTH -> Direction.EAST; - case EAST -> Direction.NORTH; - default -> d; - }; - } - - private static String doorHinge(String facing, Point cursor, Instance instance, BlockVec pos, String path) { - Direction f = facingToDirection(facing); - Direction left = rotateCCW(f); - BlockVec leftPos = new BlockVec(pos.blockX() + left.normalX(), pos.blockY(), pos.blockZ() + left.normalZ()); - Block leftBlock = instance.getBlock(leftPos); - if (leftBlock.key().value().equals(path) && facing.equals(leftBlock.getProperty("facing"))) { - return "right"; - } - double x = cursor.x() - 0.5; - double z = cursor.z() - 0.5; - return switch (facing) { - case "north" -> x < 0 ? "right" : "left"; - case "south" -> x > 0 ? "right" : "left"; - case "west" -> z > 0 ? "right" : "left"; - case "east" -> z < 0 ? "right" : "left"; - default -> "left"; - }; - } - - public static void onInteract(PlayerBlockInteractEvent event) { - Block block = event.getBlock(); - String path = block.key().value(); - Instance instance = event.getInstance(); - BlockVec pos = event.getBlockPosition(); - - if (path.endsWith("_door")) { - String half = block.getProperty("half"); - BlockVec lowerPos = "upper".equals(half) - ? new BlockVec(pos.blockX(), pos.blockY() - 1, pos.blockZ()) - : pos; - BlockVec upperPos = new BlockVec(lowerPos.blockX(), lowerPos.blockY() + 1, lowerPos.blockZ()); - Block lower = instance.getBlock(lowerPos); - Block upper = instance.getBlock(upperPos); - if (!lower.key().value().equals(path) || !upper.key().value().equals(path)) return; - boolean open = !"true".equals(lower.getProperty("open")); - instance.setBlock(lowerPos, lower.withProperty("open", String.valueOf(open))); - instance.setBlock(upperPos, upper.withProperty("open", String.valueOf(open))); - - String facing = lower.getProperty("facing"); - String hinge = lower.getProperty("hinge"); - if (facing != null && hinge != null) { - Direction f = facingToDirection(facing); - Direction side = "left".equals(hinge) ? rotateCW(f) : rotateCCW(f); - BlockVec partnerPos = new BlockVec(lowerPos.blockX() + side.normalX(), lowerPos.blockY(), lowerPos.blockZ() + side.normalZ()); - Block partner = instance.getBlock(partnerPos); - if (partner.key().value().equals(path) && facing.equals(partner.getProperty("facing")) - && !hinge.equals(partner.getProperty("hinge"))) { - Block partnerUpper = instance.getBlock(new BlockVec(partnerPos.blockX(), partnerPos.blockY() + 1, partnerPos.blockZ())); - instance.setBlock(partnerPos, partner.withProperty("open", String.valueOf(open))); - if (partnerUpper.key().value().equals(path)) { - instance.setBlock(new BlockVec(partnerPos.blockX(), partnerPos.blockY() + 1, partnerPos.blockZ()), - partnerUpper.withProperty("open", String.valueOf(open))); - } - } - } - event.setBlockingItemUse(true); - return; - } - - if (path.endsWith("_fence_gate")) { - boolean open = !"true".equals(block.getProperty("open")); - Block updated = block.withProperty("open", String.valueOf(open)); - if (open) { - String facing = block.getProperty("facing"); - if (facing != null) { - Direction f = facingToDirection(facing); - Direction playerDir = horizontalFacingToDirection(yawToFacing(event.getPlayer().getPosition().yaw())); - if (playerDir == f) updated = updated.withProperty("facing", oppositeFacing(facing)); - } - } - instance.setBlock(pos, updated); - event.setBlockingItemUse(true); - return; - } - - if (path.endsWith("_trapdoor")) { - boolean open = !"true".equals(block.getProperty("open")); - instance.setBlock(pos, block.withProperty("open", String.valueOf(open))); - event.setBlockingItemUse(true); - } - } - - private static Direction horizontalFacingToDirection(String f) { - return facingToDirection(f); - } - - public static void onBreak(PlayerBlockBreakEvent event) { - Instance instance = event.getInstance(); - BlockVec pos = event.getBlockPosition(); - Block broken = event.getBlock(); - String path = broken.key().value(); - - if (path.endsWith("_door")) { - String half = broken.getProperty("half"); - BlockVec other = "upper".equals(half) - ? new BlockVec(pos.blockX(), pos.blockY() - 1, pos.blockZ()) - : new BlockVec(pos.blockX(), pos.blockY() + 1, pos.blockZ()); - instance.scheduler().scheduleNextTick(() -> { - Block ob = instance.getBlock(other); - if (ob.key().value().equals(path)) instance.setBlock(other, Block.AIR); - }); - } - - if (path.endsWith("_bed")) { - String part = broken.getProperty("part"); - String facing = broken.getProperty("facing"); - if (facing != null) { - Direction d = facingToDirection(facing); - if ("foot".equals(part)) { - BlockVec headPos = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - instance.scheduler().scheduleNextTick(() -> { - if (instance.getBlock(headPos).key().value().equals(path)) instance.setBlock(headPos, Block.AIR); - }); - } else if ("head".equals(part)) { - BlockVec footPos = new BlockVec(pos.blockX() - d.normalX(), pos.blockY(), pos.blockZ() - d.normalZ()); - instance.scheduler().scheduleNextTick(() -> { - if (instance.getBlock(footPos).key().value().equals(path)) instance.setBlock(footPos, Block.AIR); - }); - } - } - } - - if (path.equals("big_dripleaf") || path.equals("big_dripleaf_stem")) { - String half = broken.getProperty("half"); - BlockVec other = "upper".equals(half) - ? new BlockVec(pos.blockX(), pos.blockY() - 1, pos.blockZ()) - : new BlockVec(pos.blockX(), pos.blockY() + 1, pos.blockZ()); - instance.scheduler().scheduleNextTick(() -> { - String op = instance.getBlock(other).key().value(); - if (op.equals("big_dripleaf") || op.equals("big_dripleaf_stem")) instance.setBlock(other, Block.AIR); - }); - } - - instance.scheduler().scheduleNextTick(() -> { - if (isConnecting(path)) { - for (Direction d : Direction.HORIZONTAL) { - BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - Block nb = instance.getBlock(np); - if (isConnecting(nb.key().value())) instance.setBlock(np, computeConnections(nb, nb.key().value(), instance, np)); - if (nb.key().value().endsWith("_fence_gate")) instance.setBlock(np, updateFenceGateInWall(nb, instance, np)); - } - } - - if (path.endsWith("_wall")) { - for (Direction d : Direction.HORIZONTAL) { - BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - Block nb = instance.getBlock(np); - if (nb.key().value().endsWith("_fence_gate")) instance.setBlock(np, updateFenceGateInWall(nb, instance, np)); - } - } - - for (Direction d : Direction.HORIZONTAL) { - BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - Block nb = instance.getBlock(np); - String npath = nb.key().value(); - if (npath.equals("redstone_wire")) updateRedstoneWire(instance, np); - if (isRail(npath)) updateRailShape(instance, np); - } - BlockVec above = new BlockVec(pos.blockX(), pos.blockY() + 1, pos.blockZ()); - if (instance.getBlock(above).key().value().equals("redstone_wire")) updateRedstoneWire(instance, above); - BlockVec belowRail = new BlockVec(pos.blockX(), pos.blockY() - 1, pos.blockZ()); - if (isRail(instance.getBlock(belowRail).key().value())) updateRailShape(instance, belowRail); - - if (path.equals("scaffolding") || isAnyScaffoldingAround(instance, pos)) { - recomputeScaffoldingColumn(instance, pos); - for (Direction d : Direction.HORIZONTAL) { - BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - if (instance.getBlock(np).key().value().equals("scaffolding")) recomputeScaffoldingColumn(instance, np); - } - } - - if (path.equals("chest") || path.equals("trapped_chest")) { - String facing = broken.getProperty("facing"); - if (facing != null) { - Direction f = facingToDirection(facing); - for (Direction d : new Direction[]{rotateCW(f), rotateCCW(f)}) { - BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - Block nb = instance.getBlock(np); - if (nb.key().value().equals(path) && facing.equals(nb.getProperty("facing"))) { - String t = nb.getProperty("type"); - if ("left".equals(t) || "right".equals(t)) instance.setBlock(np, nb.withProperty("type", "single")); - } - } - } - } - - if (isStairLike(path)) { - for (Direction d : Direction.HORIZONTAL) { - BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - Block nb = instance.getBlock(np); - if (nb.key().value().endsWith("_stairs")) { - String nf = nb.getProperty("facing"); - boolean nt = isTopStair(nb); - instance.setBlock(np, applyStairShape(nb, instance, np, nf, nt)); - } - } - } - }); - } - - private static boolean isStairLike(String path) { return path.endsWith("_stairs"); } - - private static boolean isAnyScaffoldingAround(Instance instance, BlockVec pos) { - for (Direction d : Direction.HORIZONTAL) { - BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - if (instance.getBlock(np).key().value().equals("scaffolding")) return true; - } - BlockVec above = new BlockVec(pos.blockX(), pos.blockY() + 1, pos.blockZ()); - return instance.getBlock(above).key().value().equals("scaffolding"); - } - - private static void recomputeScaffoldingColumn(Instance instance, BlockVec start) { - int x = start.blockX(), z = start.blockZ(); - for (int y = start.blockY(); y < start.blockY() + 32; y++) { - BlockVec p = new BlockVec(x, y, z); - if (!instance.getBlock(p).key().value().equals("scaffolding")) break; - updateScaffolding(instance, p); - } - } - - private static int parseIntOr(String s, int d) { - if (s == null) return d; - try { return Integer.parseInt(s); } catch (NumberFormatException e) { return d; } - } -} diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BuildBattle.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BuildBattle.java index 03c6db2..ccb2a25 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BuildBattle.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BuildBattle.java @@ -62,10 +62,11 @@ public class BuildBattle extends StatelessGame { super(Dimension.THE_END.key, "BuildBattle", new PointsWinScore()); this.seconds = seconds; this.setGenerator(new BuildBattleChunkgenerator(height)); + BuildBattleBlockRules.register(); this.eventNode().addListener(PlayerUseItemEvent.class, this::onRatingItemUse); this.eventNode().addListener(PlayerUseItemOnBlockEvent.class, e -> FluidFlowHelper.onBucketUse(e, p -> this.isInArea(p, e.getPlayer()))); this.eventNode().addListener(PlayerBlockInteractEvent.class, e -> { - if (this.isInArea(e.getBlockPosition(), e.getPlayer())) BlockPlacementHelper.onInteract(e); + if (this.isInArea(e.getBlockPosition(), e.getPlayer())) BuildBattleBlockRules.onInteract(e); }); } @@ -134,7 +135,6 @@ public class BuildBattle extends StatelessGame { event.setCancelled(true); return; } - BlockPlacementHelper.onBreak(event); FluidFlowHelper.onBreak(event); } @@ -144,7 +144,6 @@ public class BuildBattle extends StatelessGame { event.setCancelled(true); return; } - BlockPlacementHelper.apply(event); FluidFlowHelper.onPlace(event); } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BuildBattleBlockRules.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BuildBattleBlockRules.java new file mode 100644 index 0000000..5ab090c --- /dev/null +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BuildBattleBlockRules.java @@ -0,0 +1,85 @@ +package eu.mhsl.minenet.minigames.instance.game.stateless.types.buildBattle; + +import net.minestom.server.MinecraftServer; +import net.minestom.server.event.player.PlayerBlockInteractEvent; +import net.minestom.server.instance.block.Block; +import net.minestom.server.instance.block.BlockHandler; +import net.minestom.server.instance.block.rule.BlockPlacementRule; +import org.everbuild.blocksandstuff.blocks.group.VanillaBlockBehaviour; +import org.everbuild.blocksandstuff.blocks.group.VanillaPlacementRules; +import org.everbuild.blocksandstuff.blocks.group.behaviour.BehaviourGroup; +import org.everbuild.blocksandstuff.blocks.group.placement.PlacementGroup; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; + +public final class BuildBattleBlockRules { + private BuildBattleBlockRules() {} + + private static final ThreadLocal interactingInBuildBattle = ThreadLocal.withInitial(() -> false); + private static final Map behaviours = new HashMap<>(); + private static boolean registered = false; + + public static synchronized void register() { + if (registered) return; + registered = true; + + var blockManager = MinecraftServer.getBlockManager(); + for (PlacementGroup group : VanillaPlacementRules.INSTANCE.getALL()) { + for (Block block : group.getBlockGroup().allMatching()) { + blockManager.registerBlockPlacementRule(new BuildBattleOnlyRule(group.createRule(block))); + } + } + + for (BehaviourGroup group : VanillaBlockBehaviour.INSTANCE.getALL()) { + for (Block block : group.getBlockGroup().allMatching()) { + behaviours.put(block.id(), group.createHandler(block)); + } + } + + MinecraftServer.getGlobalEventHandler().addListener(PlayerBlockInteractEvent.class, + e -> interactingInBuildBattle.set(e.getInstance() instanceof BuildBattle)); + } + + public static void onInteract(PlayerBlockInteractEvent event) { + BlockHandler handler = behaviours.get(event.getBlock().id()); + if (handler == null) return; + boolean continueItemUse = handler.onInteract(new BlockHandler.Interaction( + event.getBlock(), event.getInstance(), event.getBlockFace(), event.getBlockPosition(), + event.getCursorPosition(), event.getPlayer(), event.getHand() + )); + if (!continueItemUse) event.setBlockingItemUse(true); + } + + private static final class BuildBattleOnlyRule extends BlockPlacementRule { + private final BlockPlacementRule delegate; + + private BuildBattleOnlyRule(BlockPlacementRule delegate) { + super(delegate.getBlock()); + this.delegate = delegate; + } + + @Override + public @Nullable Block blockPlace(PlacementState placementState) { + if (!(placementState.instance() instanceof BuildBattle)) return placementState.block(); + return this.delegate.blockPlace(placementState); + } + + @Override + public Block blockUpdate(UpdateState updateState) { + if (!(updateState.instance() instanceof BuildBattle)) return updateState.currentBlock(); + return this.delegate.blockUpdate(updateState); + } + + @Override + public boolean isSelfReplaceable(Replacement replacement) { + return interactingInBuildBattle.get() && this.delegate.isSelfReplaceable(replacement); + } + + @Override + public int maxUpdateDistance() { + return this.delegate.maxUpdateDistance(); + } + } +}