Add some vanilla placement rules, add a scheduleNextTick method for instances and entities, make changes to BlockPlacementRule, make BlockFace its own class.

This commit is contained in:
Eoghanmc22 2020-06-28 17:11:40 -04:00
parent 7d59347873
commit 061db7c8de
17 changed files with 249 additions and 42 deletions

View File

@ -101,6 +101,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
protected boolean noGravity;
protected Pose pose = Pose.STANDING;
protected final List<Consumer<Entity>> nextTick = Collections.synchronizedList(new ArrayList<>());
private long velocityUpdatePeriod;
protected boolean onGround;
@ -123,6 +124,10 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
setVelocityUpdatePeriod(5);
}
public void scheduleNextTick(Consumer<Entity> callback) {
nextTick.add(callback);
}
public Entity(int entityType) {
this(entityType, new Position());
}
@ -329,6 +334,12 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
return;
}
synchronized (nextTick) {
for (final Consumer<Entity> e : nextTick) {
e.accept(this);
}
nextTick.clear();
}
// Synchronization with updated fields in #getPosition()
{
// X/Y/Z axis

View File

@ -2,6 +2,7 @@ package net.minestom.server.entity.fakeplayer;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.Player;
import net.minestom.server.instance.block.BlockFace;
import net.minestom.server.inventory.Inventory;
import net.minestom.server.inventory.InventoryModifier;
import net.minestom.server.inventory.PlayerInventory;
@ -117,7 +118,7 @@ public class FakePlayerController {
ClientPlayerDiggingPacket playerDiggingPacket = new ClientPlayerDiggingPacket();
playerDiggingPacket.status = ClientPlayerDiggingPacket.Status.STARTED_DIGGING;
playerDiggingPacket.blockPosition = blockPosition;
playerDiggingPacket.blockFace = ClientPlayerDiggingPacket.BlockFace.BOTTOM; // TODO not hardcode
playerDiggingPacket.blockFace = BlockFace.BOTTOM; // TODO not hardcode
addToQueue(playerDiggingPacket);
}
@ -125,7 +126,7 @@ public class FakePlayerController {
ClientPlayerDiggingPacket playerDiggingPacket = new ClientPlayerDiggingPacket();
playerDiggingPacket.status = ClientPlayerDiggingPacket.Status.CANCELLED_DIGGING;
playerDiggingPacket.blockPosition = blockPosition;
playerDiggingPacket.blockFace = ClientPlayerDiggingPacket.BlockFace.BOTTOM; // TODO not hardcode
playerDiggingPacket.blockFace = BlockFace.BOTTOM; // TODO not hardcode
addToQueue(playerDiggingPacket);
}
@ -133,7 +134,7 @@ public class FakePlayerController {
ClientPlayerDiggingPacket playerDiggingPacket = new ClientPlayerDiggingPacket();
playerDiggingPacket.status = ClientPlayerDiggingPacket.Status.FINISHED_DIGGING;
playerDiggingPacket.blockPosition = blockPosition;
playerDiggingPacket.blockFace = ClientPlayerDiggingPacket.BlockFace.BOTTOM; // TODO not hardcode
playerDiggingPacket.blockFace = BlockFace.BOTTOM; // TODO not hardcode
addToQueue(playerDiggingPacket);
}

View File

@ -0,0 +1,54 @@
package net.minestom.server.extras;
import net.minestom.server.MinecraftServer;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockManager;
import net.minestom.server.instance.block.rule.vanilla.AxisPlacementRule;
import net.minestom.server.instance.block.rule.vanilla.RedstonePlacementRule;
import net.minestom.server.instance.block.rule.vanilla.WallPlacementRule;
public class PlacementRules {
public static void init() {
BlockManager blockManager = MinecraftServer.getBlockManager();
blockManager.registerBlockPlacementRule(new RedstonePlacementRule());
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.BONE_BLOCK));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.HAY_BLOCK));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.OAK_LOG));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.SPRUCE_LOG));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.BIRCH_LOG));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.JUNGLE_LOG));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.ACACIA_LOG));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.DARK_OAK_LOG));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.CRIMSON_STEM));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.WARPED_STEM));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_OAK_LOG));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_SPRUCE_LOG));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_BIRCH_LOG));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_JUNGLE_LOG));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_ACACIA_LOG));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_DARK_OAK_LOG));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_CRIMSON_STEM));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_WARPED_STEM));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.PURPUR_PILLAR));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.QUARTZ_PILLAR));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.OAK_WOOD));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.SPRUCE_WOOD));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.BIRCH_WOOD));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.JUNGLE_WOOD));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.ACACIA_WOOD));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.DARK_OAK_WOOD));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.CRIMSON_STEM));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.WARPED_STEM));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_OAK_WOOD));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_SPRUCE_WOOD));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_BIRCH_WOOD));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_JUNGLE_WOOD));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_ACACIA_WOOD));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_DARK_OAK_WOOD));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_CRIMSON_STEM));
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_WARPED_STEM));
blockManager.registerBlockPlacementRule(new WallPlacementRule(Block.COBBLESTONE_WALL));
blockManager.registerBlockPlacementRule(new WallPlacementRule(Block.MOSSY_COBBLESTONE_WALL));
}
}

View File

@ -46,7 +46,7 @@ public final class Chunk implements Viewable {
private int chunkX, chunkZ;
// blocks id based on coord, see Chunk#getBlockIndex
private short[] blocksId = new short[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z];
public short[] blocksId = new short[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z];
private short[] customBlocksId = new short[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z];
// Used to get all blocks with data (no null)

View File

@ -53,6 +53,8 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
protected Map<Long, Set<Entity>> chunkEntities = new ConcurrentHashMap<>();
protected UUID uniqueId;
protected List<Consumer<Instance>> nextTick = Collections.synchronizedList(new ArrayList<>());
private Data data;
private ExplosionSupplier explosionSupplier;
@ -63,6 +65,10 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
this.worldBorder = new WorldBorder(this);
}
public void scheduleNextTick(Consumer<Instance> callback) {
nextTick.add(callback);
}
/**
* Used to change the id of the block in a specific position.
* <p>
@ -619,6 +625,12 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
* @param time the current time
*/
public void tick(long time) {
synchronized (nextTick) {
for (final Consumer<Instance> e : nextTick) {
e.accept(this);
}
nextTick.clear();
}
worldBorder.update();
}

View File

@ -100,12 +100,10 @@ public class InstanceContainer extends Instance {
return;
}
setAlreadyChanged(blockPosition, blockId);
int index = ChunkUtils.getBlockIndex(x, y, z);
// Call the destroy listener if previous block was a custom block
callBlockDestroy(chunk, index, blockPosition);
// Change id based on neighbors
blockId = executeBlockPlacementRule(blockId, blockPosition);
@ -176,7 +174,7 @@ public class InstanceContainer extends Instance {
private short executeBlockPlacementRule(short blockId, BlockPosition blockPosition) {
BlockPlacementRule blockPlacementRule = BLOCK_MANAGER.getBlockPlacementRule(blockId);
if (blockPlacementRule != null) {
return blockPlacementRule.blockRefresh(this, blockPosition);
return blockPlacementRule.blockRefresh(this, blockPosition, blockId);
}
return blockId;
}
@ -194,7 +192,7 @@ public class InstanceContainer extends Instance {
BlockPlacementRule neighborBlockPlacementRule = BLOCK_MANAGER.getBlockPlacementRule(neighborId);
if (neighborBlockPlacementRule != null) {
short newNeighborId = neighborBlockPlacementRule.blockRefresh(this,
new BlockPosition(neighborX, neighborY, neighborZ));
new BlockPosition(neighborX, neighborY, neighborZ), neighborId);
if (neighborId != newNeighborId) {
refreshBlockId(neighborX, neighborY, neighborZ, newNeighborId);
}

View File

@ -1366,6 +1366,7 @@ public enum Block {
case SPAWNER:
case COMMAND_BLOCK:
case BEACON:
case CHEST:
case CREEPER_HEAD:
case CREEPER_WALL_HEAD:
case DRAGON_HEAD:

View File

@ -0,0 +1,22 @@
package net.minestom.server.instance.block;
import net.minestom.server.utils.Direction;
public enum BlockFace {
BOTTOM(Direction.DOWN),
TOP(Direction.UP),
NORTH(Direction.NORTH),
SOUTH(Direction.SOUTH),
WEST(Direction.WEST),
EAST(Direction.EAST);
private final Direction direction;
BlockFace(Direction direction) {
this.direction = direction;
}
public Direction toDirection() {
return direction;
}
}

View File

@ -1,7 +1,9 @@
package net.minestom.server.instance.block.rule;
import net.minestom.server.entity.Player;
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.BlockPosition;
public abstract class BlockPlacementRule {
@ -18,7 +20,9 @@ public abstract class BlockPlacementRule {
public abstract boolean canPlace(Instance instance, BlockPosition blockPosition);
public abstract short blockRefresh(Instance instance, BlockPosition blockPosition);
public abstract short blockRefresh(Instance instance, BlockPosition blockPosition, short currentID);
public abstract short blockPlace(Instance instance, Block block, BlockFace blockFace, Player pl);
public short getBlockId() {
return blockId;

View File

@ -0,0 +1,40 @@
package net.minestom.server.instance.block.rule.vanilla;
import net.minestom.server.entity.Player;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockFace;
import net.minestom.server.instance.block.rule.BlockPlacementRule;
import net.minestom.server.utils.BlockPosition;
public class AxisPlacementRule extends BlockPlacementRule {
Block block;
public AxisPlacementRule(Block block) {
super(block);
this.block = block;
}
@Override
public boolean canPlace(Instance instance, BlockPosition blockPosition) {
return true;
}
@Override
public short blockRefresh(Instance instance, BlockPosition blockPosition, short currentId) {
return currentId;
}
@Override
public short blockPlace(Instance instance, Block block, BlockFace blockFace, Player pl) {
String axis = "y";
if (blockFace == BlockFace.WEST || blockFace == BlockFace.EAST) {
axis = "x";
} else if (blockFace == BlockFace.SOUTH || blockFace == BlockFace.NORTH) {
axis = "z";
}
return block.withProperties("axis="+axis);
}
}

View File

@ -1,7 +1,9 @@
package net.minestom.server.instance.block.rule.vanilla;
import net.minestom.server.entity.Player;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockFace;
import net.minestom.server.instance.block.rule.BlockPlacementRule;
import net.minestom.server.utils.BlockPosition;
@ -18,7 +20,7 @@ public class RedstonePlacementRule extends BlockPlacementRule {
}
@Override
public short blockRefresh(Instance instance, BlockPosition blockPosition) {
public short blockRefresh(Instance instance, BlockPosition blockPosition, short currentId) {
int x = blockPosition.getX();
int y = blockPosition.getY();
int z = blockPosition.getZ();
@ -73,6 +75,11 @@ public class RedstonePlacementRule extends BlockPlacementRule {
"power=" + power, "south=" + south, "west=" + west);
}
@Override
public short blockPlace(Instance instance, Block block, BlockFace blockFace, Player pl) {
return getBlockId();
}
private boolean isRedstone(Instance instance, int x, int y, int z) {
short blockId = instance.getBlockId(x, y, z);
return Block.fromId(blockId) == Block.REDSTONE_WIRE;

View File

@ -0,0 +1,68 @@
package net.minestom.server.instance.block.rule.vanilla;
import net.minestom.server.entity.Player;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockFace;
import net.minestom.server.instance.block.rule.BlockPlacementRule;
import net.minestom.server.utils.BlockPosition;
public class WallPlacementRule extends BlockPlacementRule {
Block block;
public WallPlacementRule(Block block) {
super(block);
this.block = block;
}
@Override
public boolean canPlace(Instance instance, BlockPosition blockPosition) {
return true;
}
@Override
public short blockRefresh(Instance instance, BlockPosition blockPosition, short currentId) {
int x = blockPosition.getX();
int y = blockPosition.getY();
int z = blockPosition.getZ();
String east = "none";
String north = "none";
String south = "none";
String up = "true";
String waterlogged = "false";
String west = "none";
if (isBlock(instance, x + 1, y, z)) {
east = "low";
}
if (isBlock(instance, x - 1, y, z)) {
west = "low";
}
if (isBlock(instance, x, y, z + 1)) {
south = "low";
}
if (isBlock(instance, x, y, z - 1)) {
north = "low";
}
return block.withProperties("east=" + east, "north=" + north, "south=" + south, "up=" + up,
"waterlogged=" + waterlogged, "west=" + west);
}
@Override
public short blockPlace(Instance instance, Block block, BlockFace blockFace, Player pl) {
return getBlockId();
}
private boolean isBlock(Instance instance, int x, int y, int z) {
short blockId = instance.getBlockId(x, y, z);
return Block.fromId(blockId).isSolid();
}
}

View File

@ -11,6 +11,7 @@ import net.minestom.server.event.player.PlayerUseItemOnBlockEvent;
import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockFace;
import net.minestom.server.instance.block.BlockManager;
import net.minestom.server.instance.block.CustomBlock;
import net.minestom.server.instance.block.rule.BlockPlacementRule;
@ -19,7 +20,6 @@ import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.item.StackingRule;
import net.minestom.server.network.packet.client.play.ClientPlayerBlockPlacementPacket;
import net.minestom.server.network.packet.client.play.ClientPlayerDiggingPacket;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.chunk.ChunkUtils;
@ -30,7 +30,7 @@ public class BlockPlacementListener {
public static void listener(ClientPlayerBlockPlacementPacket packet, Player player) {
PlayerInventory playerInventory = player.getInventory();
Player.Hand hand = packet.hand;
ClientPlayerDiggingPacket.BlockFace blockFace = packet.blockFace;
BlockFace blockFace = packet.blockFace;
BlockPosition blockPosition = packet.blockPosition;
Instance instance = player.getInstance();
@ -62,9 +62,9 @@ public class BlockPlacementListener {
}
// Get the newly placed block position
int offsetX = blockFace == ClientPlayerDiggingPacket.BlockFace.WEST ? -1 : blockFace == ClientPlayerDiggingPacket.BlockFace.EAST ? 1 : 0;
int offsetY = blockFace == ClientPlayerDiggingPacket.BlockFace.BOTTOM ? -1 : blockFace == ClientPlayerDiggingPacket.BlockFace.TOP ? 1 : 0;
int offsetZ = blockFace == ClientPlayerDiggingPacket.BlockFace.NORTH ? -1 : blockFace == ClientPlayerDiggingPacket.BlockFace.SOUTH ? 1 : 0;
int offsetX = blockFace == BlockFace.WEST ? -1 : blockFace == BlockFace.EAST ? 1 : 0;
int offsetY = blockFace == BlockFace.BOTTOM ? -1 : blockFace == BlockFace.TOP ? 1 : 0;
int offsetZ = blockFace == BlockFace.NORTH ? -1 : blockFace == BlockFace.SOUTH ? 1 : 0;
blockPosition.add(offsetX, offsetY, offsetZ);
@ -74,7 +74,6 @@ public class BlockPlacementListener {
if (material.isBlock()) {
Block block = material.getBlock();
Set<Entity> entities = instance.getChunkEntities(chunk);
boolean intersect = false;
if (block.isSolid()) {
@ -86,12 +85,17 @@ public class BlockPlacementListener {
}
if (!intersect) {
PlayerBlockPlaceEvent playerBlockPlaceEvent = new PlayerBlockPlaceEvent(player, block.getBlockId(), (short) 0, blockPosition, packet.hand);
playerBlockPlaceEvent.consumeBlock(player.getGameMode() != GameMode.CREATIVE);
// BlockPlacementRule check
BlockManager blockManager = MinecraftServer.getBlockManager();
BlockPlacementRule blockPlacementRule = blockManager.getBlockPlacementRule(block);
short blockid = block.getBlockId();
if (blockPlacementRule != null) {
blockid = blockPlacementRule.blockPlace(instance, block, blockFace, player);
}
PlayerBlockPlaceEvent playerBlockPlaceEvent = new PlayerBlockPlaceEvent(player, blockid, (short) 0, blockPosition, packet.hand);
playerBlockPlaceEvent.consumeBlock(player.getGameMode() != GameMode.CREATIVE);
// BlockPlacementRule check
boolean canPlace = true;
if (blockPlacementRule != null) {
canPlace = blockPlacementRule.canPlace(instance, blockPosition);

View File

@ -1,6 +1,7 @@
package net.minestom.server.network.packet.client.play;
import net.minestom.server.entity.Player;
import net.minestom.server.instance.block.BlockFace;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.client.ClientPlayPacket;
import net.minestom.server.utils.BlockPosition;
@ -9,7 +10,7 @@ public class ClientPlayerBlockPlacementPacket extends ClientPlayPacket {
public Player.Hand hand;
public BlockPosition blockPosition;
public ClientPlayerDiggingPacket.BlockFace blockFace;
public BlockFace blockFace;
public float cursorPositionX, cursorPositionY, cursorPositionZ;
public boolean insideBlock;
@ -17,7 +18,7 @@ public class ClientPlayerBlockPlacementPacket extends ClientPlayPacket {
public void read(PacketReader reader) {
this.hand = Player.Hand.values()[reader.readVarInt()];
this.blockPosition = reader.readBlockPosition();
this.blockFace = ClientPlayerDiggingPacket.BlockFace.values()[reader.readVarInt()];
this.blockFace = BlockFace.values()[reader.readVarInt()];
this.cursorPositionX = reader.readFloat();
this.cursorPositionY = reader.readFloat();
this.cursorPositionZ = reader.readFloat();

View File

@ -1,9 +1,9 @@
package net.minestom.server.network.packet.client.play;
import net.minestom.server.instance.block.BlockFace;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.client.ClientPlayPacket;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.Direction;
public class ClientPlayerDiggingPacket extends ClientPlayPacket {
@ -28,23 +28,4 @@ public class ClientPlayerDiggingPacket extends ClientPlayPacket {
SWAP_ITEM_HAND
}
public enum BlockFace {
BOTTOM(Direction.DOWN),
TOP(Direction.UP),
NORTH(Direction.NORTH),
SOUTH(Direction.SOUTH),
WEST(Direction.WEST),
EAST(Direction.EAST);
private final Direction direction;
BlockFace(Direction direction) {
this.direction = direction;
}
public Direction toDirection() {
return direction;
}
}
}

View File

@ -85,4 +85,8 @@ public class StorageManager {
}
this.defaultStorageSystemSupplier = storageSystemSupplier;
}
public boolean isDefaultStorageSystemDefined() {
return defaultStorageSystemSupplier != null;
}
}

View File

@ -24,7 +24,6 @@ public enum Direction {
return SOUTH;
case SOUTH:
return NORTH;
default:
throw new IllegalArgumentException();
}