diff --git a/modules/block-placement/src/main/java/net/hollowcube/block/placement/BlockPlaceMechanicAnvil.java b/modules/block-placement/src/main/java/net/hollowcube/block/placement/BlockPlaceMechanicAnvil.java new file mode 100644 index 0000000..141f407 --- /dev/null +++ b/modules/block-placement/src/main/java/net/hollowcube/block/placement/BlockPlaceMechanicAnvil.java @@ -0,0 +1,17 @@ +package net.hollowcube.block.placement; + +import net.minestom.server.event.player.PlayerBlockPlaceEvent; +import net.minestom.server.instance.block.Block; + +public class BlockPlaceMechanicAnvil { + public static void onPlace(Block block, PlayerBlockPlaceEvent event) { + block = event.getBlock(); + switch (event.getBlockFace()) { + case NORTH -> event.setBlock(block.withProperty("facing", "east")); + case EAST -> event.setBlock(block.withProperty("facing", "south")); + case SOUTH -> event.setBlock(block.withProperty("facing", "west")); + // West and others default to north + default -> event.setBlock(block.withProperty("facing", "north")); + } + } +} diff --git a/modules/block-placement/src/main/java/net/hollowcube/block/placement/BlockPlaceMechanicBell.java b/modules/block-placement/src/main/java/net/hollowcube/block/placement/BlockPlaceMechanicBell.java new file mode 100644 index 0000000..66f299f --- /dev/null +++ b/modules/block-placement/src/main/java/net/hollowcube/block/placement/BlockPlaceMechanicBell.java @@ -0,0 +1,38 @@ +package net.hollowcube.block.placement; + +import net.minestom.server.event.player.PlayerBlockPlaceEvent; +import net.minestom.server.instance.block.Block; + +import java.util.HashMap; +import java.util.Locale; + +public class BlockPlaceMechanicBell { + + public static void onPlace(Block block, PlayerBlockPlaceEvent event) { + block = event.getBlock(); + + switch (event.getBlockFace()) { + case NORTH -> event.setBlock(block.withProperty("facing", "east")); + case EAST -> event.setBlock(block.withProperty("facing", "south")); + case SOUTH -> event.setBlock(block.withProperty("facing", "west")); + // West and others default to north + default -> event.setBlock(block.withProperty("facing", "north")); + } + String attachment = switch (event.getBlockFace()) { + case TOP -> "ceiling"; + case BOTTOM -> "floor"; + default -> "floor"; + // TODO: Handle double_wall and single_wall attachments + }; + String facing = switch (event.getBlockFace()) { + case TOP, BOTTOM -> "north"; + default -> event.getBlockFace().getOppositeFace().name().toLowerCase(Locale.ROOT); + }; + HashMap properties = new HashMap<>(); + properties.put("facing", facing); + properties.put("powered", "false"); + properties.put("attachment", attachment); + + event.setBlock(block.withProperties(properties)); + } +} diff --git a/modules/block-placement/src/main/java/net/hollowcube/block/placement/BlockPlaceMechanicDoor.java b/modules/block-placement/src/main/java/net/hollowcube/block/placement/BlockPlaceMechanicDoor.java new file mode 100644 index 0000000..60ef03e --- /dev/null +++ b/modules/block-placement/src/main/java/net/hollowcube/block/placement/BlockPlaceMechanicDoor.java @@ -0,0 +1,57 @@ +package net.hollowcube.block.placement; + +import net.minestom.server.coordinate.Point; +import net.minestom.server.event.player.PlayerBlockPlaceEvent; +import net.minestom.server.instance.block.Block; +import net.minestom.server.instance.block.BlockFace; + +import java.util.HashMap; + +public class BlockPlaceMechanicDoor { + + public static void onPlace(Block block, PlayerBlockPlaceEvent event) { + if (event.getBlockFace() != BlockFace.TOP) { + event.setCancelled(true); + return; + } + Point upperBlockPos = event.getBlockPosition().add(0, 1, 0); + if (event.getInstance().getBlock(upperBlockPos).isAir()) { + // We have space to place the other door half + HashMap properties = new HashMap<>(); + properties.put("half", "upper"); + properties.put("open", "false"); + properties.put("powered", "false"); + properties.put("hinge", "left"); + // TODO: Properly handle hinge + /* + By default, a door's "hinge" appears on the side of the half of the block that the player pointed at when placing and its "handle" on the opposite side, but the hinge is forced to other side by: + Placing a door besides another door (creating a double door where both doors open away from each other) + Placing a door between a full solid and any opaque block (top or bottom), making the hinge appear to attach to the solid block. + */ + // Calculate facing direction + var playerDir = event.getPlayer().getPosition().direction(); + double absX = Math.abs(playerDir.x()); + double absZ = Math.abs(playerDir.z()); + + if (absX > absZ) { + if (playerDir.x() > 0) { + properties.put("facing", "west"); + } else { + properties.put("facing", "east"); + } + } else { + if (playerDir.z() > 0) { + properties.put("facing", "north"); + } else { + properties.put("facing", "south"); + } + } + event.getInstance().setBlock(upperBlockPos, block.withProperties(properties)); + + properties.put("half", "lower"); + event.setBlock(block.withProperties(properties)); + } else { + event.setCancelled(true); + } + } +} diff --git a/modules/block-placement/src/main/java/net/hollowcube/block/placement/BlockPlaceMechanicRotation.java b/modules/block-placement/src/main/java/net/hollowcube/block/placement/BlockPlaceMechanicRotation.java index a1bea81..1feb3ca 100644 --- a/modules/block-placement/src/main/java/net/hollowcube/block/placement/BlockPlaceMechanicRotation.java +++ b/modules/block-placement/src/main/java/net/hollowcube/block/placement/BlockPlaceMechanicRotation.java @@ -93,7 +93,7 @@ public static void onPlace(Block block, PlayerBlockPlaceEvent event) { } private static final Set ROTATION_VERTICAL = new HashSet<>(); - private static Set ROTATION_INVERT = Set.of( + private static final Set ROTATION_INVERT = Set.of( NamespaceID.from("minecraft:barrel"), NamespaceID.from("minecraft:command_block"), NamespaceID.from("minecraft:repeating_command_block"), @@ -107,7 +107,8 @@ public static void onPlace(Block block, PlayerBlockPlaceEvent event) { NamespaceID.from("minecraft:bee_nest"), NamespaceID.from("minecraft:piston") ); - private static Set USE_BLOCK_FACING = new HashSet<>(Set.of( + // TODO: I think there may be a tag that can be used instead of this + private static final Set USE_BLOCK_FACING = new HashSet<>(Set.of( NamespaceID.from("minecraft:glow_lichen"), NamespaceID.from("minecraft:cocoa"), NamespaceID.from("minecraft:dead_tube_coral_wall_fan"), diff --git a/modules/block-placement/src/main/java/net/hollowcube/block/placement/BlockPlaceMechanicRotation16.java b/modules/block-placement/src/main/java/net/hollowcube/block/placement/BlockPlaceMechanicRotation16.java new file mode 100644 index 0000000..b0a9c0b --- /dev/null +++ b/modules/block-placement/src/main/java/net/hollowcube/block/placement/BlockPlaceMechanicRotation16.java @@ -0,0 +1,47 @@ +package net.hollowcube.block.placement; + +import net.minestom.server.coordinate.Vec; +import net.minestom.server.event.player.PlayerBlockPlaceEvent; +import net.minestom.server.instance.block.Block; + +public class BlockPlaceMechanicRotation16 { + public static void onPlace(Block block, PlayerBlockPlaceEvent event) { + event.setBlock(block.withProperty("rotation", String.valueOf(getRotationNumber(event.getPlayer().getPosition().direction())))); + } + + public static int getRotationNumber(Vec playerFacing) { + // From https://gamedev.stackexchange.com/questions/49290/whats-the-best-way-of-transforming-a-2d-vector-into-the-closest-8-way-compass-d + // Scaled to a 16 way compass + + double delta = Math.PI * 2 / 16; + double theta = Math.atan2(playerFacing.z(), playerFacing.x()); + + double testangle = -Math.PI + delta/2; + int index = 12; // Initial offset to get the compass to align properly with Minecraft's x/z directions + + // TODO: Would this work better with a division/modulo? + while (theta > testangle) { + index++; + testangle += delta; + } + return index % 16; + /* + 0 The block is facing south. - Player faces north (Negative Z) + 1 The block is facing south-southwest. + 2 The block is facing southwest. + 3 The block is facing west-southwest. + 4 The block is facing west. - Player Faces east (Positive X) + 5 The block is facing west-northwest. + 6 The block is facing northwest. + 7 The block is facing north-northwest. + 8 The block is facing north. + 9 The block is facing north-northeast. + 10 The block is facing northeast. + 11 The block is facing east-northeast. + 12 The block is facing east. + 13 The block is facing east-southeast. + 14 The block is facing southeast. + 15 The block is facing south-southeast. + */ + } +} diff --git a/modules/block-placement/src/main/java/net/hollowcube/block/placement/BlockPlaceMechanicWall.java b/modules/block-placement/src/main/java/net/hollowcube/block/placement/BlockPlaceMechanicWall.java index 02cfafe..801fb62 100644 --- a/modules/block-placement/src/main/java/net/hollowcube/block/placement/BlockPlaceMechanicWall.java +++ b/modules/block-placement/src/main/java/net/hollowcube/block/placement/BlockPlaceMechanicWall.java @@ -5,7 +5,6 @@ import net.minestom.server.event.player.PlayerBlockUpdateNeighborEvent; import net.minestom.server.instance.Instance; import net.minestom.server.instance.block.Block; -import net.minestom.server.utils.NamespaceID; public class BlockPlaceMechanicWall { diff --git a/modules/block-placement/src/main/java/net/hollowcube/block/placement/HCPlacementRules.java b/modules/block-placement/src/main/java/net/hollowcube/block/placement/HCPlacementRules.java index acf3d6a..d03905e 100644 --- a/modules/block-placement/src/main/java/net/hollowcube/block/placement/HCPlacementRules.java +++ b/modules/block-placement/src/main/java/net/hollowcube/block/placement/HCPlacementRules.java @@ -1,7 +1,9 @@ package net.hollowcube.block.placement; import net.minestom.server.MinecraftServer; -import net.minestom.server.event.*; +import net.minestom.server.event.EventBinding; +import net.minestom.server.event.EventFilter; +import net.minestom.server.event.EventNode; import net.minestom.server.event.player.PlayerBlockPlaceEvent; import net.minestom.server.event.player.PlayerBlockUpdateNeighborEvent; import net.minestom.server.event.trait.BlockEvent; @@ -16,16 +18,11 @@ public final class HCPlacementRules { //TODO: // Twisting Vines // Weeping Vines - // Anvils (flip X/Z rotation) // Small Dripleaf (convert Y) // Big Dripleaf (convert Y) // Candles (stacking) // Non-collding blocks to place inside player // Waterlogged state - // Bells - // Banners (int rot) - // Signs (int rot) - // Doors (place upper door) // Sunflower (place upper sunflower) // Fern (place upper fern) // Beds (place 2nd block) @@ -84,6 +81,19 @@ public final class HCPlacementRules { .map(PlayerBlockPlaceEvent.class, BlockPlaceMechanicAxis::onPlace) .build(); + private static final EventBinding ANVIL_BINDING = EventBinding.filtered(EventFilter.BLOCK, HCPlacementRules::isAnvil) + .map(PlayerBlockPlaceEvent.class, BlockPlaceMechanicAnvil::onPlace) + .build(); + + private static final EventBinding BELL_BINDING = EventBinding.filtered(EventFilter.BLOCK, block -> block.compare(Block.BELL)) + .map(PlayerBlockPlaceEvent.class, BlockPlaceMechanicBell::onPlace) + .build(); + + private static final EventBinding DOOR_BINDING = EventBinding.filtered(EventFilter.BLOCK, HCPlacementRules::isDoor) + .map(PlayerBlockPlaceEvent.class, BlockPlaceMechanicDoor::onPlace) + .build(); + + private static final EventBinding HALF_BINDING = EventBinding.filtered(EventFilter.BLOCK, HCPlacementRules::hasHalf) .map(PlayerBlockPlaceEvent.class, BlockPlaceMechanicHalf::onPlace) .build(); @@ -93,6 +103,11 @@ public final class HCPlacementRules { .map(PlayerBlockPlaceEvent.class, BlockPlaceMechanicWallReplacement::onPlace) .build(); + private static final EventBinding ROTATION_16_BINDING = + EventBinding.filtered(EventFilter.BLOCK, HCPlacementRules::hasRotation16) + .map(PlayerBlockPlaceEvent.class, BlockPlaceMechanicRotation16::onPlace) + .build(); + /* Checks */ public static final Tag MINECRAFT_STAIRS = Objects.requireNonNull(MinecraftServer.getTagManager().getTag(Tag.BasicType.BLOCKS, "minecraft:stairs")); @@ -156,10 +171,22 @@ private static boolean hasAxis(Block block) { return block.getProperty("axis") != null; } + private static boolean isAnvil(Block block) { + return block.compare(Block.ANVIL); + } + private static boolean hasHalf(Block block) { return block.getProperty("half") != null; } + private static boolean hasRotation16(Block block) { return block.getProperty("rotation") != null; } + + private static final Tag MINECRAFT_DOORS = Objects.requireNonNull(MinecraftServer.getTagManager().getTag(Tag.BasicType.BLOCKS, "minecraft:doors")); + + private static boolean isDoor(Block block) { + return MINECRAFT_DOORS.contains(block.namespace()); + } + /* Init */ public static void init() { @@ -188,6 +215,10 @@ public static void init(EventNode handler) { handler.register(GLOW_LICHEN_BINDING); handler.register(VINE_BINDING); handler.register(POINTED_DRIPSTONE_BINDING); + handler.register(ANVIL_BINDING); + handler.register(BELL_BINDING); + handler.register(DOOR_BINDING); + handler.register(ROTATION_16_BINDING); for (short stateId = 0; stateId < Short.MAX_VALUE; stateId++) { Block block = Block.fromStateId(stateId); diff --git a/modules/block-placement/src/test/java/net/hollowcube/test/Rotation16Test.java b/modules/block-placement/src/test/java/net/hollowcube/test/Rotation16Test.java new file mode 100644 index 0000000..f1e54d2 --- /dev/null +++ b/modules/block-placement/src/test/java/net/hollowcube/test/Rotation16Test.java @@ -0,0 +1,18 @@ +package net.hollowcube.test; + +import net.hollowcube.block.placement.BlockPlaceMechanicRotation16; +import net.minestom.server.coordinate.Vec; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class Rotation16Test { + + @Test + public void testRotation16() { + assertEquals(0, BlockPlaceMechanicRotation16.getRotationNumber(new Vec(0, -1))); + assertEquals(8, BlockPlaceMechanicRotation16.getRotationNumber(new Vec(0, 1))); + assertEquals(4, BlockPlaceMechanicRotation16.getRotationNumber(new Vec(1, 0))); + assertEquals(12, BlockPlaceMechanicRotation16.getRotationNumber(new Vec(-1, 0))); + } +} diff --git a/modules/dev/src/main/java/net/hollowcube/dev/Main.java b/modules/dev/src/main/java/net/hollowcube/dev/Main.java index f628b6a..066cf11 100644 --- a/modules/dev/src/main/java/net/hollowcube/dev/Main.java +++ b/modules/dev/src/main/java/net/hollowcube/dev/Main.java @@ -10,7 +10,7 @@ import net.minestom.server.instance.InstanceManager; import net.minestom.server.instance.block.Block; -import java.sql.*; +import java.sql.SQLException; public class Main {