Pumpkin/pumpkin/src/block/mod.rs
Alexander Medvedev e055dd740c Check if player can destroy block using an tool
Prevents players to destroy blocks when holding a sword or trident in creative
2025-03-04 19:45:39 +01:00

135 lines
4.1 KiB
Rust

use blocks::{chest::ChestBlock, furnace::FurnaceBlock, lever::LeverBlock, tnt::TNTBlock};
use properties::{
BlockPropertiesManager,
age::Age,
attachment::Attachment,
axis::Axis,
cardinal::{Down, East, North, South, Up, West},
face::Face,
facing::Facing,
half::Half,
layers::Layers,
open::Open,
powered::Powered,
signal_fire::SignalFire,
slab_type::SlabType,
stair_shape::StairShape,
unstable::Unstable,
waterlog::Waterlogged,
};
use pumpkin_data::entity::EntityType;
use pumpkin_util::math::position::BlockPos;
use pumpkin_util::math::vector3::Vector3;
use pumpkin_world::{
block::registry::{Block, State},
item::ItemStack,
};
use rand::Rng;
use crate::block::registry::BlockRegistry;
use crate::entity::item::ItemEntity;
use crate::world::World;
use crate::{block::blocks::crafting_table::CraftingTableBlock, entity::player::Player};
use crate::{block::blocks::jukebox::JukeboxBlock, entity::experience_orb::ExperienceOrbEntity};
use std::sync::Arc;
mod blocks;
pub mod properties;
pub mod pumpkin_block;
pub mod registry;
#[must_use]
pub fn default_registry() -> Arc<BlockRegistry> {
let mut manager = BlockRegistry::default();
manager.register(JukeboxBlock);
manager.register(CraftingTableBlock);
manager.register(FurnaceBlock);
manager.register(ChestBlock);
manager.register(TNTBlock);
manager.register(LeverBlock);
Arc::new(manager)
}
pub async fn drop_loot(world: &Arc<World>, block: &Block, pos: &BlockPos, experience: bool) {
if let Some(table) = &block.loot_table {
let loot = table.get_loot();
for item in loot {
drop_stack(world, pos, item).await;
}
}
if experience {
if let Some(experience) = &block.experience {
let amount = experience.experience.get();
// TODO: Silk touch gives no exp
if amount > 0 {
ExperienceOrbEntity::spawn(world, pos.to_f64(), amount as u32).await;
}
}
}
}
async fn drop_stack(world: &Arc<World>, pos: &BlockPos, stack: ItemStack) {
let height = EntityType::ITEM.dimension[1] / 2.0;
let pos = Vector3::new(
f64::from(pos.0.x) + 0.5 + rand::thread_rng().gen_range(-0.25..0.25),
f64::from(pos.0.y) + 0.5 + rand::thread_rng().gen_range(-0.25..0.25) - f64::from(height),
f64::from(pos.0.z) + 0.5 + rand::thread_rng().gen_range(-0.25..0.25),
);
let entity = world.create_entity(pos, EntityType::ITEM);
let item_entity =
Arc::new(ItemEntity::new(entity, stack.item.id, u32::from(stack.item_count)).await);
world.spawn_entity(item_entity.clone()).await;
item_entity.send_meta_packet().await;
}
pub async fn calc_block_breaking(player: &Player, state: &State, block_name: &str) -> f32 {
let hardness = state.hardness;
#[expect(clippy::float_cmp)]
if hardness == -1.0 {
// unbreakable
return 0.0;
}
let i = if player.can_harvest(state, block_name).await {
30
} else {
100
};
player.get_mining_speed(block_name).await / hardness / i as f32
}
#[must_use]
pub fn default_block_properties_manager() -> Arc<BlockPropertiesManager> {
let mut manager = BlockPropertiesManager::default();
// This is the default state of the blocks
manager.register(Age::Age0);
manager.register(Attachment::Floor);
manager.register(Axis::Y);
manager.register(Down::False);
manager.register(East::False);
manager.register(Face::Floor);
manager.register(Facing::North);
manager.register(Half::Bottom);
manager.register(Layers::Lay1);
manager.register(North::False);
manager.register(Open::False());
manager.register(Powered::False());
manager.register(Unstable::False());
manager.register(SignalFire::False());
manager.register(SlabType::Bottom);
manager.register(South::False);
manager.register(StairShape::Straight);
manager.register(Up::False);
manager.register(Waterlogged::False());
manager.register(West::False);
manager.build_properties_registry();
Arc::new(manager)
}