diff --git a/Allay-API/src/main/java/org/allaymc/api/block/component/common/BlockBaseComponent.java b/Allay-API/src/main/java/org/allaymc/api/block/component/common/BlockBaseComponent.java index 88da33777..b2f7cc513 100644 --- a/Allay-API/src/main/java/org/allaymc/api/block/component/common/BlockBaseComponent.java +++ b/Allay-API/src/main/java/org/allaymc/api/block/component/common/BlockBaseComponent.java @@ -54,12 +54,11 @@ default void updateBlockProperty(BlockPropertyType property /** * Call when a blockState causes another blockState to update. * - * @param updated The vec of the updated block - * @param neighbor The vec of the block that triggered the update - * @param face The neighbor block is on the side of the current updated block - * @param dimension the dimension + * @param current The current block + * @param neighbor The neighbor block that triggered the update + * @param face The face of the current block */ - void onNeighborUpdate(Vector3ic updated, Vector3ic neighbor, BlockFace face, Dimension dimension); + void onNeighborUpdate(BlockStateWithPos current, BlockStateWithPos neighbor, BlockFace face); void onRandomUpdate(BlockStateWithPos blockState); diff --git a/Allay-API/src/main/java/org/allaymc/api/block/component/event/BlockOnNeighborUpdateEvent.java b/Allay-API/src/main/java/org/allaymc/api/block/component/event/BlockOnNeighborUpdateEvent.java index 302806693..9101adf75 100644 --- a/Allay-API/src/main/java/org/allaymc/api/block/component/event/BlockOnNeighborUpdateEvent.java +++ b/Allay-API/src/main/java/org/allaymc/api/block/component/event/BlockOnNeighborUpdateEvent.java @@ -3,6 +3,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; import org.allaymc.api.block.data.BlockFace; +import org.allaymc.api.block.data.BlockStateWithPos; import org.allaymc.api.eventbus.event.Event; import org.allaymc.api.world.Dimension; import org.joml.Vector3ic; @@ -15,8 +16,7 @@ @Getter @AllArgsConstructor public class BlockOnNeighborUpdateEvent extends Event { - private final Vector3ic updated; - private final Vector3ic neighbor; + private final BlockStateWithPos current; + private final BlockStateWithPos neighbor; private final BlockFace face; - private final Dimension dimension; } diff --git a/Allay-API/src/main/java/org/allaymc/api/command/tree/CommandNode.java b/Allay-API/src/main/java/org/allaymc/api/command/tree/CommandNode.java index d5bb0799f..b8022f8d2 100644 --- a/Allay-API/src/main/java/org/allaymc/api/command/tree/CommandNode.java +++ b/Allay-API/src/main/java/org/allaymc/api/command/tree/CommandNode.java @@ -82,7 +82,6 @@ default CommandNode root() { boolean match(CommandContext context); - CommandNode nextNode(CommandContext context); boolean isLeaf(); diff --git a/Allay-API/src/main/java/org/allaymc/api/world/Dimension.java b/Allay-API/src/main/java/org/allaymc/api/world/Dimension.java index b12e9cfce..c9f00759b 100644 --- a/Allay-API/src/main/java/org/allaymc/api/world/Dimension.java +++ b/Allay-API/src/main/java/org/allaymc/api/world/Dimension.java @@ -435,4 +435,18 @@ default void dropItem(ItemStack itemStack, Vector3fc pos, Vector3fc motion, int entityItem.setPickupDelay(pickupDelay); getEntityService().addEntity(entityItem); } + + default void breakBlock(Vector3ic pos, ItemStack usedItem, EntityPlayer player) { + breakBlock(pos.x(), pos.y(), pos.z(), usedItem, player); + } + + /** + * Break a block at the specified position + * @param x The x coordinate of the block + * @param y The y coordinate of the block + * @param z The z coordinate of the block + * @param usedItem The item used to break the block, can be null + * @param player The player who breaks the block, can be null + */ + void breakBlock(int x, int y, int z, ItemStack usedItem, EntityPlayer player); } diff --git a/Allay-Server/src/main/java/org/allaymc/server/block/component/common/BlockBaseComponentImpl.java b/Allay-Server/src/main/java/org/allaymc/server/block/component/common/BlockBaseComponentImpl.java index 44b463ea8..ce72b9031 100644 --- a/Allay-Server/src/main/java/org/allaymc/server/block/component/common/BlockBaseComponentImpl.java +++ b/Allay-Server/src/main/java/org/allaymc/server/block/component/common/BlockBaseComponentImpl.java @@ -22,8 +22,6 @@ import org.joml.Vector3fc; import org.joml.Vector3ic; -import java.util.Arrays; - /** * Allay Project 2023/4/8 * @@ -49,8 +47,8 @@ public BlockType getBlockType() { } @Override - public void onNeighborUpdate(Vector3ic updated, Vector3ic neighbor, BlockFace face, Dimension dimension) { - manager.callEvent(new BlockOnNeighborUpdateEvent(updated, neighbor, face, dimension)); + public void onNeighborUpdate(BlockStateWithPos current, BlockStateWithPos neighbor, BlockFace face) { + manager.callEvent(new BlockOnNeighborUpdateEvent(current, neighbor, face)); } @Override @@ -83,14 +81,15 @@ public void onReplace(BlockStateWithPos currentBlockState, BlockState newBlockSt public void onBreak(BlockStateWithPos blockState, ItemStack usedItem, EntityPlayer player) { if (!blockState.blockState().getBlockType().getMaterial().isAlwaysDestroyable() && !usedItem.isCorrectToolFor(blockState.blockState())) return; var dropPos = new Vector3f(blockState.pos()).add(0.5f, 0.5f, 0.5f); - if (usedItem.hasEnchantment(EnchantmentSilkTouchType.SILK_TOUCH_TYPE)) { + var dimension = blockState.pos().dimension(); + if (usedItem != null && usedItem.hasEnchantment(EnchantmentSilkTouchType.SILK_TOUCH_TYPE)) { // 精准采集, 直接掉落方块本身 - player.getDimension().dropItem(blockState.blockState().toItemStack(), dropPos); + dimension.dropItem(blockState.blockState().toItemStack(), dropPos); return; } var drops = getDrops(blockState.blockState(), usedItem); for (var drop : drops) { - player.getDimension().dropItem(drop, dropPos); + dimension.dropItem(drop, dropPos); } } diff --git a/Allay-Server/src/main/java/org/allaymc/server/block/component/common/BlockEntityHolderComponentImpl.java b/Allay-Server/src/main/java/org/allaymc/server/block/component/common/BlockEntityHolderComponentImpl.java index 9bc2c99a0..79362b0b3 100644 --- a/Allay-Server/src/main/java/org/allaymc/server/block/component/common/BlockEntityHolderComponentImpl.java +++ b/Allay-Server/src/main/java/org/allaymc/server/block/component/common/BlockEntityHolderComponentImpl.java @@ -51,7 +51,7 @@ private void onBlockRemove(BlockOnReplaceEvent event) { @EventHandler private void onNeighborChanged(BlockOnNeighborUpdateEvent event) { - var pos = new Position3i(event.getUpdated(), event.getDimension()); + var pos = new Position3i(event.getCurrent().pos()); var blockEntity = getBlockEntity(pos); blockEntity.onNeighborUpdate(event); } diff --git a/Allay-Server/src/main/java/org/allaymc/server/block/component/doubleplant/BlockDoublePlantBaseComponentImpl.java b/Allay-Server/src/main/java/org/allaymc/server/block/component/doubleplant/BlockDoublePlantBaseComponentImpl.java index 08635ab31..0e112c2ce 100644 --- a/Allay-Server/src/main/java/org/allaymc/server/block/component/doubleplant/BlockDoublePlantBaseComponentImpl.java +++ b/Allay-Server/src/main/java/org/allaymc/server/block/component/doubleplant/BlockDoublePlantBaseComponentImpl.java @@ -2,9 +2,13 @@ import org.allaymc.api.block.BlockBehavior; import org.allaymc.api.block.component.annotation.RequireBlockProperty; +import org.allaymc.api.block.data.BlockFace; +import org.allaymc.api.block.data.BlockStateWithPos; +import org.allaymc.api.block.property.enums.DoublePlantType; import org.allaymc.api.block.property.type.BlockPropertyType; import org.allaymc.api.block.type.BlockState; import org.allaymc.api.block.type.BlockType; +import org.allaymc.api.block.type.BlockTypes; import org.allaymc.api.data.VanillaBlockPropertyTypes; import org.allaymc.api.item.ItemStack; import org.allaymc.api.item.type.ItemTypes; @@ -41,4 +45,26 @@ public ItemStack[] getDrops(BlockState blockState, ItemStack usedItem) { default -> super.getDrops(blockState, usedItem); }; } + + @Override + public void onNeighborUpdate(BlockStateWithPos current, BlockStateWithPos neighbor, BlockFace face) { + if (face != BlockFace.UP && face != BlockFace.DOWN) return; + var dimension = current.pos().dimension(); + var isUpperBlock = current.blockState().getPropertyValue(VanillaBlockPropertyTypes.UPPER_BLOCK_BIT); + var plantType = current.blockState().getPropertyValue(VanillaBlockPropertyTypes.DOUBLE_PLANT_TYPE); + var willBreak = false; + if (isUpperBlock) { + var downBlock = dimension.getBlockState(BlockFace.DOWN.offsetPos(current.pos())); + willBreak = notSamePlant(downBlock, plantType); + } else { + var upperBlock = dimension.getBlockState(BlockFace.UP.offsetPos(current.pos())); + willBreak = notSamePlant(upperBlock, plantType); + } + if (willBreak) dimension.breakBlock(current.pos(), null, null); + } + + protected boolean notSamePlant(BlockState downBlock, DoublePlantType plantType) { + return downBlock.getBlockType() != BlockTypes.DOUBLE_PLANT_TYPE || + downBlock.getPropertyValue(VanillaBlockPropertyTypes.DOUBLE_PLANT_TYPE) != plantType; + } } diff --git a/Allay-Server/src/main/java/org/allaymc/server/network/processor/PlayerAuthInputPacketProcessor.java b/Allay-Server/src/main/java/org/allaymc/server/network/processor/PlayerAuthInputPacketProcessor.java index ff6ad04fd..f933565bb 100644 --- a/Allay-Server/src/main/java/org/allaymc/server/network/processor/PlayerAuthInputPacketProcessor.java +++ b/Allay-Server/src/main/java/org/allaymc/server/network/processor/PlayerAuthInputPacketProcessor.java @@ -156,18 +156,7 @@ protected void completeBreak(EntityPlayer player, int x, int y, int z) { var currentTime = player.getWorld().getTick(); if (Math.abs(currentTime - stopBreakingTime) <= BLOCK_BREAKING_TIME_FAULT_TOLERANCE) { var world = player.getDimension(); - var oldState = world.getBlockState(breakBlockX, breakBlockY, breakBlockZ); - var pk = new LevelEventPacket(); - pk.setType(LevelEvent.PARTICLE_DESTROY_BLOCK); - pk.setPosition(Vector3f.from(breakBlockX + 0.5f, breakBlockY + 0.5f, breakBlockZ + 0.5f)); - pk.setData(oldState.blockStateHash()); - player.getCurrentChunk().addChunkPacket(pk); - breakBlock.getBehavior().onBreak( - new BlockStateWithPos(breakBlock, new Position3i(breakBlockX, breakBlockY, breakBlockZ, player.getDimension()), 0), - player.getItemInHand(), - player - ); - world.setBlockState(breakBlockX, breakBlockY, breakBlockZ, AIR_TYPE.getDefaultState()); + world.breakBlock(breakBlockX, breakBlockY, breakBlockZ, player.getItemInHand(), player); } else { log.warn("Mismatch block breaking complete time! Expected: {}gt, actual: {}gt", stopBreakingTime, currentTime); } diff --git a/Allay-Server/src/main/java/org/allaymc/server/world/AllayDimension.java b/Allay-Server/src/main/java/org/allaymc/server/world/AllayDimension.java index cdc85fc7b..30a8fae0f 100644 --- a/Allay-Server/src/main/java/org/allaymc/server/world/AllayDimension.java +++ b/Allay-Server/src/main/java/org/allaymc/server/world/AllayDimension.java @@ -2,7 +2,10 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import org.allaymc.api.block.data.BlockStateWithPos; import org.allaymc.api.entity.interfaces.EntityPlayer; +import org.allaymc.api.item.ItemStack; +import org.allaymc.api.math.position.Position3i; import org.allaymc.api.world.Dimension; import org.allaymc.api.world.DimensionInfo; import org.allaymc.api.world.World; @@ -15,12 +18,17 @@ import org.allaymc.server.world.service.AllayChunkService; import org.allaymc.server.world.service.AllayEntityPhysicsService; import org.allaymc.server.world.service.AllayEntityService; +import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.protocol.bedrock.data.LevelEvent; +import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; import org.jetbrains.annotations.UnmodifiableView; import java.util.Collections; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import static org.allaymc.api.block.type.BlockTypes.AIR_TYPE; + /** * Allay Project 11/12/2023 * @@ -84,6 +92,26 @@ public Set getPlayers() { return unmodifiablePlayersView; } + @Override + public void breakBlock(int x, int y, int z, ItemStack usedItem, EntityPlayer player) { + var block = getBlockState(x, y, z); + if (block.getBlockType() == AIR_TYPE) { + log.warn("Trying to break air block at x={}, y={}, z={}", x, y, z); + return; + } + var pk = new LevelEventPacket(); + pk.setType(LevelEvent.PARTICLE_DESTROY_BLOCK); + pk.setPosition(Vector3f.from(x + 0.5f, y + 0.5f, z + 0.5f)); + pk.setData(block.blockStateHash()); + getChunkService().getChunkByLevelPos(x ,z).addChunkPacket(pk); + block.getBehavior().onBreak( + new BlockStateWithPos(block, new Position3i(x, y, z, this), 0), + usedItem, + player + ); + setBlockState(x, y, z, AIR_TYPE.getDefaultState()); + } + @Override public String toString() { return "world=" + this.world.getWorldData().getName() + " dimId=" + this.dimensionInfo.dimensionId(); diff --git a/Allay-Server/src/main/java/org/allaymc/server/world/service/AllayBlockUpdateService.java b/Allay-Server/src/main/java/org/allaymc/server/world/service/AllayBlockUpdateService.java index 90b7a0b27..37bfa2a37 100644 --- a/Allay-Server/src/main/java/org/allaymc/server/world/service/AllayBlockUpdateService.java +++ b/Allay-Server/src/main/java/org/allaymc/server/world/service/AllayBlockUpdateService.java @@ -52,12 +52,19 @@ public void tick(long tick) { var u = neighborUpdates.poll(); var pos = u.pos; var neighborPos = u.neighborPos; + var neighborBlockStateWithPos = new BlockStateWithPos(dimension.getBlockState(neighborPos), new Position3i(neighborPos, dimension), 0); var blockFace = u.blockFace; BlockState layer0 = dimension.getBlockState(pos); BlockState layer1 = dimension.getBlockState(pos, 1); - layer0.getBehavior().onNeighborUpdate(pos, neighborPos, blockFace, dimension); + layer0.getBehavior().onNeighborUpdate( + new BlockStateWithPos(layer0, new Position3i(pos, dimension), 0), + neighborBlockStateWithPos, + blockFace); if (layer1.getBehavior() instanceof BlockLiquidComponent) { - layer1.getBehavior().onNeighborUpdate(pos, neighborPos, blockFace, dimension); + layer1.getBehavior().onNeighborUpdate( + new BlockStateWithPos(layer1, new Position3i(pos, dimension), 0), + neighborBlockStateWithPos, + blockFace); } c++; }