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 fe5e75e6d..d9f715798 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 @@ -14,6 +14,7 @@ import org.allaymc.api.item.ItemStack; import org.allaymc.api.item.enchantment.type.EnchantmentAquaAffinityType; import org.allaymc.api.item.enchantment.type.EnchantmentEfficiencyType; +import org.allaymc.api.item.type.ItemType; import org.allaymc.api.world.Dimension; import static org.allaymc.api.item.ItemHelper.isSword; @@ -45,6 +46,10 @@ default void updateBlockProperty(BlockPropertyType property chunk.sendChunkPacket(Dimension.createBlockUpdatePacket(newBlockState, x, y, z, layer)); } + default boolean canDamageItem(ItemType itemType) { + return true; + } + default double calculateBreakTime(BlockState blockState, ItemStack usedItem, Entity entity) { checkBlockType(blockState); if (usedItem.canInstantBreak(blockState)) return 0; diff --git a/Allay-API/src/main/java/org/allaymc/api/entity/component/common/EntityBaseComponent.java b/Allay-API/src/main/java/org/allaymc/api/entity/component/common/EntityBaseComponent.java index 20617e122..c919dea6d 100644 --- a/Allay-API/src/main/java/org/allaymc/api/entity/component/common/EntityBaseComponent.java +++ b/Allay-API/src/main/java/org/allaymc/api/entity/component/common/EntityBaseComponent.java @@ -12,6 +12,7 @@ import org.allaymc.api.entity.metadata.Metadata; import org.allaymc.api.entity.type.EntityType; import org.allaymc.api.math.location.Location3fc; +import org.allaymc.api.utils.MathUtils; import org.allaymc.api.world.Dimension; import org.allaymc.api.world.World; import org.allaymc.api.world.chunk.Chunk; diff --git a/Allay-API/src/main/java/org/allaymc/api/entity/component/player/EntityPlayerBaseComponent.java b/Allay-API/src/main/java/org/allaymc/api/entity/component/player/EntityPlayerBaseComponent.java index 02675ee95..c8ab4e12e 100644 --- a/Allay-API/src/main/java/org/allaymc/api/entity/component/player/EntityPlayerBaseComponent.java +++ b/Allay-API/src/main/java/org/allaymc/api/entity/component/player/EntityPlayerBaseComponent.java @@ -5,10 +5,12 @@ import org.allaymc.api.client.skin.Skin; import org.allaymc.api.client.storage.PlayerData; import org.allaymc.api.entity.component.common.EntityBaseComponent; +import org.allaymc.api.entity.interfaces.EntityPlayer; import org.allaymc.api.form.type.CustomForm; import org.allaymc.api.form.type.Form; import org.allaymc.api.math.location.Location3ic; import org.allaymc.api.scoreboard.ScoreboardViewer; +import org.allaymc.api.utils.MathUtils; import org.allaymc.api.world.chunk.ChunkLoader; import org.cloudburstmc.protocol.bedrock.data.GameType; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; @@ -123,4 +125,22 @@ default void setAction(boolean value) { CustomForm removeServerSettingForm(int id); void showForm(Form form); + + double BLOCK_INTERACT_MAX_DV_DIFF = 2.0; + + default boolean canInteract(float x, float y, float z) { + var maxDistance = getMaxInteractDistance(); + var location = getLocation(); + if (location.distanceSquared(x, y, z) > maxDistance * maxDistance) return false; + + var dv = MathUtils.JOMLVecToCBVec(MathUtils.getDirectionVector(location.yaw(), location.pitch())); + org.cloudburstmc.math.vector.Vector3f target = org.cloudburstmc.math.vector.Vector3f.from(x - location.x(), y - location.y(), z - location.z()).normalize(); + var delta = dv.sub(target); + var diff = delta.dot(delta); + return diff < BLOCK_INTERACT_MAX_DV_DIFF; + } + + default double getMaxInteractDistance() { + return getGameType() == GameType.CREATIVE ? 13 : 7; + } } 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 14d5919e3..6a116e8d3 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 @@ -7,6 +7,7 @@ import org.allaymc.api.entity.interfaces.EntityPlayer; import org.allaymc.api.math.location.Location3f; import org.allaymc.api.network.processor.PacketProcessor; +import org.allaymc.api.utils.MathUtils; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.GameType; import org.cloudburstmc.protocol.bedrock.data.LevelEvent; @@ -48,6 +49,15 @@ protected void handleBlockAction(EntityPlayer player, List { + if (!player.canInteract(pos.getX(), pos.getY(), pos.getZ())) { + log.warn("Player {} tried to break a block out of reach", player.getOriginName()); + continue; + } + } + } switch (action.getAction()) { case START_BREAK -> { if (isInvalidGameType(player)) continue; @@ -180,6 +190,13 @@ protected void sendBreakingPracticeAndTime(EntityPlayer player) { player.getCurrentChunk().addChunkPacket(pk2); } + protected void checkInteractDistance(EntityPlayer player) { + if (!player.canInteract(breakBlockX, breakBlockY, breakBlockZ)) { + log.warn("Player {} tried to interact with a block out of reach", player.getOriginName()); + stopBreak(player); + } + } + protected void updateBreakingTime(EntityPlayer player) { var newBreakingTime = breakBlock.getBehavior().calculateBreakTime(breakBlock, player.getContainer(FullContainerType.PLAYER_INVENTORY).getItemInHand(), player); if (needBreakingTime == newBreakingTime) return; @@ -218,7 +235,10 @@ public PacketSignal handleAsync(EntityPlayer player, PlayerAuthInputPacket packe // The pos which client sends to the server is higher than the actual coordinates (one base offset) handleMovement(player, packet.getPosition().sub(0, player.getBaseOffset(), 0), packet.getRotation()); handleBlockAction(player, packet.getPlayerActions()); - if (isBreakingBlock()) sendBreakingPracticeAndTime(player); + if (isBreakingBlock()) { + sendBreakingPracticeAndTime(player); + checkInteractDistance(player); + } return PacketSignal.UNHANDLED; }