111 lines
4.1 KiB
Rust
111 lines
4.1 KiB
Rust
use crate::entity::Entity;
|
|
use crate::entity::item::ItemEntity;
|
|
use crate::entity::player::Player;
|
|
use crate::item::{ItemBehaviour, ItemMetadata};
|
|
use crate::server::Server;
|
|
use pumpkin_data::BlockDirection;
|
|
use pumpkin_data::entity::EntityType;
|
|
use pumpkin_data::item::Item;
|
|
use pumpkin_data::item_stack::ItemStack;
|
|
use pumpkin_data::{Block, tag};
|
|
use pumpkin_util::GameMode;
|
|
use pumpkin_util::math::position::BlockPos;
|
|
use pumpkin_util::math::vector3::Vector3;
|
|
use pumpkin_world::world::BlockFlags;
|
|
use std::pin::Pin;
|
|
use std::sync::Arc;
|
|
|
|
pub struct HoeItem;
|
|
|
|
impl ItemMetadata for HoeItem {
|
|
fn ids() -> Box<[u16]> {
|
|
tag::Item::MINECRAFT_HOES.1.to_vec().into_boxed_slice()
|
|
}
|
|
}
|
|
|
|
impl ItemBehaviour for HoeItem {
|
|
fn use_on_block<'a>(
|
|
&'a self,
|
|
item: &'a mut ItemStack,
|
|
player: &'a Player,
|
|
location: BlockPos,
|
|
face: BlockDirection,
|
|
_cursor_pos: Vector3<f32>,
|
|
block: &'a Block,
|
|
_server: &'a Server,
|
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
|
Box::pin(async move {
|
|
// Yes, Minecraft does hardcode these
|
|
if block == &Block::GRASS_BLOCK
|
|
|| block == &Block::DIRT_PATH
|
|
|| block == &Block::DIRT
|
|
|| block == &Block::COARSE_DIRT
|
|
|| block == &Block::ROOTED_DIRT
|
|
{
|
|
let mut future_block = block;
|
|
let world = player.world();
|
|
let mut changed = false;
|
|
|
|
//Only rooted can be right-clicked on the bottom of the block
|
|
if face == BlockDirection::Down {
|
|
if block == &Block::ROOTED_DIRT {
|
|
future_block = &Block::DIRT;
|
|
changed = true;
|
|
}
|
|
} else {
|
|
// grass, dirt && dirt path become farmland
|
|
if (block == &Block::GRASS_BLOCK
|
|
|| block == &Block::DIRT_PATH
|
|
|| block == &Block::DIRT)
|
|
&& world.get_block_state(&location.up()).is_air()
|
|
{
|
|
future_block = &Block::FARMLAND;
|
|
changed = true;
|
|
}
|
|
//Coarse dirt and rooted dirt become dirt
|
|
else if block == &Block::COARSE_DIRT || block == &Block::ROOTED_DIRT {
|
|
future_block = &Block::DIRT;
|
|
changed = true;
|
|
}
|
|
}
|
|
|
|
world
|
|
.set_block_state(
|
|
&location,
|
|
future_block.default_state.id,
|
|
BlockFlags::NOTIFY_ALL,
|
|
)
|
|
.await;
|
|
|
|
//Also rooted_dirt drop a hanging_root
|
|
if block == &Block::ROOTED_DIRT {
|
|
let location = match face {
|
|
BlockDirection::Up => location.up().to_f64(),
|
|
BlockDirection::Down => location.down().to_f64(),
|
|
BlockDirection::North => location.up().to_f64().add_raw(0.0, -0.4, -1.0),
|
|
BlockDirection::South => location.up().to_f64().add_raw(0.0, -0.4, 1.0),
|
|
BlockDirection::West => location.up().to_f64().add_raw(-1.0, -0.4, 0.0),
|
|
BlockDirection::East => location.up().to_f64().add_raw(1.0, -0.4, 0.0),
|
|
};
|
|
let entity = Entity::new(world.clone(), location, &EntityType::ITEM);
|
|
// TODO: Merge stacks together
|
|
let item_entity = Arc::new(ItemEntity::new(
|
|
entity,
|
|
ItemStack::new(1, &Item::HANGING_ROOTS),
|
|
));
|
|
world.spawn_entity(item_entity).await;
|
|
}
|
|
|
|
if changed && player.gamemode.load() != GameMode::Creative {
|
|
// TODO: Handle DamageResult::Broken to broadcast item break and update player slot.
|
|
let _ = item.damage_item(1);
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
fn as_any(&self) -> &dyn std::any::Any {
|
|
self
|
|
}
|
|
}
|