Skip to content
This repository was archived by the owner on Feb 29, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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"));
}
}
}
Original file line number Diff line number Diff line change
@@ -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<String, String> properties = new HashMap<>();
properties.put("facing", facing);
properties.put("powered", "false");
properties.put("attachment", attachment);

event.setBlock(block.withProperties(properties));
}
}
Original file line number Diff line number Diff line change
@@ -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<String, String> 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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public static void onPlace(Block block, PlayerBlockPlaceEvent event) {
}

private static final Set<Integer> ROTATION_VERTICAL = new HashSet<>();
private static Set<NamespaceID> ROTATION_INVERT = Set.of(
private static final Set<NamespaceID> ROTATION_INVERT = Set.of(
NamespaceID.from("minecraft:barrel"),
NamespaceID.from("minecraft:command_block"),
NamespaceID.from("minecraft:repeating_command_block"),
Expand All @@ -107,7 +107,8 @@ public static void onPlace(Block block, PlayerBlockPlaceEvent event) {
NamespaceID.from("minecraft:bee_nest"),
NamespaceID.from("minecraft:piston")
);
private static Set<NamespaceID> 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<NamespaceID> USE_BLOCK_FACING = new HashSet<>(Set.of(
NamespaceID.from("minecraft:glow_lichen"),
NamespaceID.from("minecraft:cocoa"),
NamespaceID.from("minecraft:dead_tube_coral_wall_fan"),
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
*/
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -84,6 +81,19 @@ public final class HCPlacementRules {
.map(PlayerBlockPlaceEvent.class, BlockPlaceMechanicAxis::onPlace)
.build();

private static final EventBinding<BlockEvent> ANVIL_BINDING = EventBinding.filtered(EventFilter.BLOCK, HCPlacementRules::isAnvil)
.map(PlayerBlockPlaceEvent.class, BlockPlaceMechanicAnvil::onPlace)
.build();

private static final EventBinding<BlockEvent> BELL_BINDING = EventBinding.filtered(EventFilter.BLOCK, block -> block.compare(Block.BELL))
.map(PlayerBlockPlaceEvent.class, BlockPlaceMechanicBell::onPlace)
.build();

private static final EventBinding<BlockEvent> DOOR_BINDING = EventBinding.filtered(EventFilter.BLOCK, HCPlacementRules::isDoor)
.map(PlayerBlockPlaceEvent.class, BlockPlaceMechanicDoor::onPlace)
.build();


private static final EventBinding<BlockEvent> HALF_BINDING = EventBinding.filtered(EventFilter.BLOCK, HCPlacementRules::hasHalf)
.map(PlayerBlockPlaceEvent.class, BlockPlaceMechanicHalf::onPlace)
.build();
Expand All @@ -93,6 +103,11 @@ public final class HCPlacementRules {
.map(PlayerBlockPlaceEvent.class, BlockPlaceMechanicWallReplacement::onPlace)
.build();

private static final EventBinding<BlockEvent> 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"));
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -188,6 +215,10 @@ public static void init(EventNode<BlockEvent> 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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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)));
}
}
2 changes: 1 addition & 1 deletion modules/dev/src/main/java/net/hollowcube/dev/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down