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 b57ed418d..06005e340 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 @@ -63,7 +63,8 @@ default void updateBlockProperty(BlockPropertyType property void onRandomUpdate(BlockStateWithPos blockState); - static void checkParam(EntityPlayer player, Dimension dimension, BlockState blockState, Vector3ic targetBlockPos, Vector3ic placeBlockPos, Vector3fc clickPos, BlockFace blockFace) { + default void checkPlaceMethodParam(EntityPlayer player, Dimension dimension, BlockState blockState, Vector3ic targetBlockPos, Vector3ic placeBlockPos, Vector3fc clickPos, BlockFace blockFace) { + Preconditions.checkState(getBlockType() == blockState.getBlockType()); // player is nullable Preconditions.checkNotNull(dimension); Preconditions.checkNotNull(blockState); @@ -73,8 +74,27 @@ static void checkParam(EntityPlayer player, Dimension dimension, BlockState bloc Preconditions.checkNotNull(blockFace); } - boolean place(EntityPlayer player, Dimension dimension, BlockState blockState, Vector3ic targetBlockPos, Vector3ic placeBlockPos, Vector3fc clickPos, BlockFace blockFace); + /** + * Try to place a block + * @param player The player who is placing the block, can be null + * @param dimension The dimension where the block is placed + * @param blockState The block that is being placed + * @param targetBlockPos The block that the player clicked on + * @param placeBlockPos The pos that the player is trying to place the block on + * @param clickPos The precise pos where the player clicked + * @param blockFace The face of the block that the player clicked on + * @return true if the block is placed successfully, false if failed + */ + boolean place( + EntityPlayer player, Dimension dimension, BlockState blockState, + Vector3ic targetBlockPos, Vector3ic placeBlockPos, Vector3fc clickPos, + BlockFace blockFace); + /** + * Called when a block is placed. + * @param currentBlockState The block that is being replaced + * @param newBlockState The block that is replacing the current block + */ void onPlace(BlockStateWithPos currentBlockState, BlockState newBlockState); /** @@ -91,11 +111,25 @@ static void checkParam(EntityPlayer player, Dimension dimension, BlockState bloc */ boolean onInteract(EntityPlayer player, ItemStack itemStack, Dimension dimension, Vector3ic blockPos, Vector3ic placeBlockPos, Vector3fc clickPos, BlockFace blockFace); + /** + * Called when a block is replaced. + * @param currentBlockState The block that is being replaced + * @param newBlockState The block that is replacing the current block + */ void onReplace(BlockStateWithPos currentBlockState, BlockState newBlockState); + /** + * Called when a block is broken by non-creative game mode player + * @param blockState The block that was broken + * @param usedItem The item that was used to break the block + * @param player The player who broke the block, can be null + */ + void onBreak(BlockStateWithPos blockState, ItemStack usedItem, EntityPlayer player); + void onScheduledUpdate(BlockStateWithPos blockState); default ItemStack[] getDrops(ItemStack itemStack) { + // TODO: needs more works if (getBlockType().getItemType() != null) { return new ItemStack[] {getBlockType().getItemType().createItemStack()}; } diff --git a/Allay-API/src/main/java/org/allaymc/api/entity/init/SimpleEntityInitInfo.java b/Allay-API/src/main/java/org/allaymc/api/entity/init/SimpleEntityInitInfo.java index a8e1c68bd..6e3f4db93 100644 --- a/Allay-API/src/main/java/org/allaymc/api/entity/init/SimpleEntityInitInfo.java +++ b/Allay-API/src/main/java/org/allaymc/api/entity/init/SimpleEntityInitInfo.java @@ -57,6 +57,10 @@ public Builder loc(Location3fc loc) { return this; } + public Builder pos(Vector3fc pos) { + return pos(pos.x(), pos.y(), pos.z()); + } + public Builder pos(float x, float y, float z) { nbtBuilder.putCompound("Pos", NbtMap.builder() diff --git a/Allay-API/src/main/java/org/allaymc/api/entity/interfaces/EntityPlayer.java b/Allay-API/src/main/java/org/allaymc/api/entity/interfaces/EntityPlayer.java index 3fe5a70d1..d1d76704f 100644 --- a/Allay-API/src/main/java/org/allaymc/api/entity/interfaces/EntityPlayer.java +++ b/Allay-API/src/main/java/org/allaymc/api/entity/interfaces/EntityPlayer.java @@ -86,16 +86,7 @@ default void forceDropItem(Container container, int slot, int count) { default void dropItemInPlayerPos(ItemStack itemStack) { var playerLoc = getLocation(); var dimension = playerLoc.dimension(); - var entityItem = EntityTypes.ITEM_TYPE.createEntity( - SimpleEntityInitInfo.builder() - .dimension(dimension) - .pos(playerLoc.x(), playerLoc.y() + this.getEyeHeight() - 0.25f, playerLoc.z()) - .motion(MathUtils.getDirectionVector(playerLoc.yaw(), playerLoc.pitch()).mul(0.5f)) - .build() - ); - entityItem.setItemStack(itemStack); - entityItem.setPickupDelay(40); - dimension.getEntityService().addEntity(entityItem); + dimension.dropItem(itemStack, playerLoc, MathUtils.getDirectionVector(playerLoc.yaw(), playerLoc.pitch()).mul(0.5f), 40); } default void sendItemInHandUpdate() { 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 27b142a50..2367ededf 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 @@ -7,7 +7,9 @@ import org.allaymc.api.block.type.BlockState; import org.allaymc.api.blockentity.BlockEntity; import org.allaymc.api.entity.Entity; +import org.allaymc.api.entity.init.SimpleEntityInitInfo; import org.allaymc.api.entity.interfaces.EntityPlayer; +import org.allaymc.api.entity.type.EntityTypes; import org.allaymc.api.item.ItemStack; import org.allaymc.api.math.position.Position3i; import org.allaymc.api.utils.MathUtils; @@ -34,6 +36,7 @@ import java.util.Collections; import java.util.Map; import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; import static org.allaymc.api.block.type.BlockTypes.AIR_TYPE; @@ -411,7 +414,21 @@ default void addSound(float x, float y, float z, String sound, float volume, flo getChunkService().getChunkByLevelPos((int) x, (int) z).addChunkPacket(packet); } - default void dropItem(ItemStack itemStack, float x, float y, float z) { + default void dropItem(ItemStack itemStack, Vector3fc pos) { + var rand = ThreadLocalRandom.current(); + dropItem(itemStack, pos, new org.joml.Vector3f(rand.nextFloat(0.2f) - 0.1f, 0.2f, rand.nextFloat(0.2f) - 0.1f), 10); + } + default void dropItem(ItemStack itemStack, Vector3fc pos, Vector3fc motion, int pickupDelay) { + var entityItem = EntityTypes.ITEM_TYPE.createEntity( + SimpleEntityInitInfo.builder() + .dimension(this) + .pos(pos) + .motion(motion) + .build() + ); + entityItem.setItemStack(itemStack); + entityItem.setPickupDelay(pickupDelay); + getEntityService().addEntity(entityItem); } } diff --git a/Allay-Server/src/main/java/org/allaymc/server/block/component/barrel/BlockBarrelBaseComponentImpl.java b/Allay-Server/src/main/java/org/allaymc/server/block/component/barrel/BlockBarrelBaseComponentImpl.java index b8a506906..e56ef4558 100644 --- a/Allay-Server/src/main/java/org/allaymc/server/block/component/barrel/BlockBarrelBaseComponentImpl.java +++ b/Allay-Server/src/main/java/org/allaymc/server/block/component/barrel/BlockBarrelBaseComponentImpl.java @@ -3,7 +3,6 @@ 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.function.Place; import org.allaymc.api.block.property.type.BlockPropertyType; import org.allaymc.api.block.type.BlockState; import org.allaymc.api.block.type.BlockType; @@ -30,7 +29,7 @@ public BlockBarrelBaseComponentImpl(BlockType blockType @Override public boolean place(EntityPlayer player, Dimension dimension, BlockState blockState, Vector3ic targetBlockPos, Vector3ic placeBlockPos, Vector3fc clickPos, BlockFace blockFace) { - Place.checkParam(player, dimension, blockState, targetBlockPos, placeBlockPos, clickPos, blockFace); + checkPlaceMethodParam(player, dimension, blockState, targetBlockPos, placeBlockPos, clickPos, blockFace); if (player != null) { if (abs(player.getLocation().x() - placeBlockPos.x()) < 2 && abs(player.getLocation().z() - placeBlockPos.z()) < 2) { var y = player.getLocation().y() + player.getEyeHeight(); diff --git a/Allay-Server/src/main/java/org/allaymc/server/block/component/chest/BlockChestBaseComponentImpl.java b/Allay-Server/src/main/java/org/allaymc/server/block/component/chest/BlockChestBaseComponentImpl.java index bde54444a..20b0904a5 100644 --- a/Allay-Server/src/main/java/org/allaymc/server/block/component/chest/BlockChestBaseComponentImpl.java +++ b/Allay-Server/src/main/java/org/allaymc/server/block/component/chest/BlockChestBaseComponentImpl.java @@ -29,6 +29,7 @@ public BlockChestBaseComponentImpl(BlockType blockType) @Override public boolean place(EntityPlayer player, Dimension dimension, BlockState blockState, Vector3ic targetBlockPos, Vector3ic placeBlockPos, Vector3fc clickPos, BlockFace blockFace) { + checkPlaceMethodParam(player, dimension, blockState, targetBlockPos, placeBlockPos, clickPos, blockFace); var face = MinecraftCardinalDirection.EAST; if (player != null) { face = toMinecraftCardinalDirection(player.getHorizontalFace().opposite()); 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 ac7b330f9..cd3edbd6d 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 @@ -8,7 +8,6 @@ import org.allaymc.api.block.component.event.BlockOnReplaceEvent; import org.allaymc.api.block.data.BlockFace; import org.allaymc.api.block.data.BlockStateWithPos; -import org.allaymc.api.block.function.Place; import org.allaymc.api.block.type.BlockState; import org.allaymc.api.block.type.BlockType; import org.allaymc.api.utils.Identifier; @@ -18,6 +17,7 @@ import org.allaymc.api.entity.interfaces.EntityPlayer; import org.allaymc.api.item.ItemStack; import org.allaymc.api.world.Dimension; +import org.joml.Vector3f; import org.joml.Vector3fc; import org.joml.Vector3ic; @@ -60,7 +60,7 @@ public void onScheduledUpdate(BlockStateWithPos blockState) { @Override public boolean place(EntityPlayer player, Dimension dimension, BlockState blockState, Vector3ic targetBlockPos, Vector3ic placeBlockPos, Vector3fc clickPos, BlockFace blockFace) { - Place.checkParam(player, dimension, blockState, targetBlockPos, placeBlockPos, clickPos, blockFace); + checkPlaceMethodParam(player, dimension, blockState, targetBlockPos, placeBlockPos, clickPos, blockFace); // TODO: check whether the old block can be replaced dimension.setBlockState(placeBlockPos.x(), placeBlockPos.y(), placeBlockPos.z(), blockState); return true; @@ -76,6 +76,16 @@ public void onReplace(BlockStateWithPos currentBlockState, BlockState newBlockSt manager.callEvent(new BlockOnReplaceEvent(currentBlockState, newBlockState)); } + @Override + public void onBreak(BlockStateWithPos blockState, ItemStack usedItem, EntityPlayer player) { + if (!blockState.blockState().getBlockType().getMaterial().isAlwaysDestroyable() && !usedItem.isCorrectToolFor(blockState.blockState())) return; + var drops = getDrops(usedItem); + if (drops.length == 0) return; + for (var drop : drops) { + player.getDimension().dropItem(drop, new Vector3f(blockState.pos()).add(0.5f, 0.5f, 0.5f)); + } + } + @Override public boolean onInteract(EntityPlayer player, ItemStack itemStack, Dimension dimension, Vector3ic blockPos, Vector3ic placeBlockPos, Vector3fc clickPos, BlockFace blockFace) { var event = new BlockOnInteractEvent(player, itemStack, dimension, blockPos, placeBlockPos, clickPos, blockFace, false); diff --git a/Allay-Server/src/main/java/org/allaymc/server/block/component/stairs/BlockStairsBaseComponentImpl.java b/Allay-Server/src/main/java/org/allaymc/server/block/component/stairs/BlockStairsBaseComponentImpl.java index dc1488286..5fe598553 100644 --- a/Allay-Server/src/main/java/org/allaymc/server/block/component/stairs/BlockStairsBaseComponentImpl.java +++ b/Allay-Server/src/main/java/org/allaymc/server/block/component/stairs/BlockStairsBaseComponentImpl.java @@ -3,7 +3,6 @@ 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.function.Place; import org.allaymc.api.block.property.type.BlockPropertyType; import org.allaymc.api.block.type.BlockState; import org.allaymc.api.block.type.BlockType; @@ -28,7 +27,7 @@ public BlockStairsBaseComponentImpl(BlockType blockType @Override public boolean place(EntityPlayer player, Dimension dimension, BlockState blockState, Vector3ic targetBlockPos, Vector3ic placeBlockPos, Vector3fc clickPos, BlockFace blockFace) { - Place.checkParam(player, dimension, blockState, targetBlockPos, placeBlockPos, clickPos, blockFace); + checkPlaceMethodParam(player, dimension, blockState, targetBlockPos, placeBlockPos, clickPos, blockFace); if (player != null) { var stairFace = player.getHorizontalFace(); blockState = blockState.setProperty(VanillaBlockPropertyTypes.WEIRDO_DIRECTION, stairFace.toStairDirectionValue()); diff --git a/Allay-Server/src/main/java/org/allaymc/server/block/component/torch/BlockTorchBaseComponentImpl.java b/Allay-Server/src/main/java/org/allaymc/server/block/component/torch/BlockTorchBaseComponentImpl.java index 0dd7b1a87..554cae5e3 100644 --- a/Allay-Server/src/main/java/org/allaymc/server/block/component/torch/BlockTorchBaseComponentImpl.java +++ b/Allay-Server/src/main/java/org/allaymc/server/block/component/torch/BlockTorchBaseComponentImpl.java @@ -5,7 +5,6 @@ import org.allaymc.api.block.component.annotation.RequireBlockProperty; import org.allaymc.api.block.component.common.BlockLiquidComponent; import org.allaymc.api.block.data.BlockFace; -import org.allaymc.api.block.function.Place; import org.allaymc.api.block.property.enums.TorchFacingDirection; import org.allaymc.api.block.property.type.BlockPropertyType; import org.allaymc.api.block.type.BlockState; @@ -39,7 +38,7 @@ private static TorchFacingDirection computeTorchFacingDirection(BlockFace blockF @Override public boolean place(EntityPlayer player, Dimension dimension, BlockState blockState, Vector3ic targetBlockPos, Vector3ic placeBlockPos, Vector3fc clickPos, BlockFace blockFace) { - Place.checkParam(player, dimension, blockState, targetBlockPos, placeBlockPos, clickPos, blockFace); + checkPlaceMethodParam(player, dimension, blockState, targetBlockPos, placeBlockPos, clickPos, blockFace); var oldBlock = dimension.getBlockState(placeBlockPos); var torchFace = computeTorchFacingDirection(blockFace); diff --git a/Allay-Server/src/main/java/org/allaymc/server/blockentity/component/common/BlockEntityContainerHolderComponentImpl.java b/Allay-Server/src/main/java/org/allaymc/server/blockentity/component/common/BlockEntityContainerHolderComponentImpl.java index ee4982bbc..48106162d 100644 --- a/Allay-Server/src/main/java/org/allaymc/server/blockentity/component/common/BlockEntityContainerHolderComponentImpl.java +++ b/Allay-Server/src/main/java/org/allaymc/server/blockentity/component/common/BlockEntityContainerHolderComponentImpl.java @@ -15,6 +15,7 @@ import org.allaymc.api.entity.type.EntityTypes; import org.allaymc.api.eventbus.EventHandler; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; +import org.joml.Vector3f; import java.util.Objects; import java.util.concurrent.ThreadLocalRandom; @@ -77,19 +78,8 @@ private void onReplace(BlockOnReplaceEvent event) { var dimension = pos.dimension(); var rand = ThreadLocalRandom.current(); for (var itemStack : container.getItemStacks()) { - if (itemStack != Container.EMPTY_SLOT_PLACE_HOLDER) { - var entity = EntityTypes.ITEM_TYPE.createEntity( - SimpleEntityInitInfo - .builder() - .pos(pos.x() + rand.nextFloat(0.5f) + 0.25f, pos.y() + rand.nextFloat(0.5f) + 0.25f, pos.z() + rand.nextFloat(0.5f) + 0.25f) - .dimension(dimension) - .motion(rand.nextFloat(0.2f) - 0.1f, 0.2f, rand.nextFloat(0.2f) - 0.1f) - .build() - ); - entity.setItemStack(itemStack); - entity.setPickupDelay(10); - dimension.getEntityService().addEntity(entity); - } + if (itemStack == Container.EMPTY_SLOT_PLACE_HOLDER) continue; + dimension.dropItem(itemStack, new Vector3f(pos.x() + rand.nextFloat(0.5f) + 0.25f, pos.y() + rand.nextFloat(0.5f) + 0.25f, pos.z() + rand.nextFloat(0.5f) + 0.25f)); } } diff --git a/Allay-Server/src/main/java/org/allaymc/server/network/processor/PlayerActionPacketProcessor.java b/Allay-Server/src/main/java/org/allaymc/server/network/processor/PlayerActionPacketProcessor.java index fdac7d6e3..6866b0771 100644 --- a/Allay-Server/src/main/java/org/allaymc/server/network/processor/PlayerActionPacketProcessor.java +++ b/Allay-Server/src/main/java/org/allaymc/server/network/processor/PlayerActionPacketProcessor.java @@ -1,8 +1,11 @@ package org.allaymc.server.network.processor; import lombok.extern.slf4j.Slf4j; +import org.allaymc.api.block.data.BlockStateWithPos; +import org.allaymc.api.container.FullContainerType; import org.allaymc.api.entity.interfaces.EntityPlayer; import org.allaymc.api.math.location.Location3f; +import org.allaymc.api.math.position.Position3i; import org.allaymc.api.network.processor.PacketProcessor; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.GameType; 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 bfe539a7d..034d5f15f 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 @@ -2,10 +2,13 @@ import lombok.extern.slf4j.Slf4j; import org.allaymc.api.block.data.BlockFace; +import org.allaymc.api.block.data.BlockStateWithPos; import org.allaymc.api.block.type.BlockState; import org.allaymc.api.container.FullContainerType; import org.allaymc.api.entity.interfaces.EntityPlayer; import org.allaymc.api.math.location.Location3f; +import org.allaymc.api.math.position.Position3i; +import org.allaymc.api.math.position.Position3ic; import org.allaymc.api.network.processor.PacketProcessor; import org.allaymc.api.utils.MathUtils; import org.cloudburstmc.math.vector.Vector3f; @@ -164,9 +167,12 @@ protected void completeBreak(EntityPlayer player, int x, int y, int z) { pk.setPosition(Vector3f.from(breakBlockX + 0.5f, breakBlockY + 0.5f, breakBlockZ + 0.5f)); pk.setData(oldState.blockStateHash()); player.getCurrentChunk().addChunkPacket(pk); - // TODO: on break + breakBlock.getBehavior().onBreak( + new BlockStateWithPos(breakBlock, new Position3i(breakBlockX, breakBlockY, breakBlockZ, player.getDimension()), 0), + player.getContainer(FullContainerType.PLAYER_INVENTORY).getItemInHand(), + player + ); world.setBlockState(breakBlockX, breakBlockY, breakBlockZ, AIR_TYPE.getDefaultState()); - // TODO: drop items } else { log.warn("Mismatch block breaking complete time! Expected: {}gt, actual: {}gt", stopBreakingTime, currentTime); }