Pumpkin/pumpkin/src/block/blocks/plant/crop/mod.rs
2026-05-14 12:28:43 +02:00

128 lines
4.1 KiB
Rust

use std::sync::Arc;
use pumpkin_data::{
Block,
BlockDirection::{East, North, South, West},
block_properties::{BlockProperties, FarmlandLikeProperties, WheatLikeProperties},
};
use pumpkin_util::math::{position::BlockPos, vector3::Vector3};
use pumpkin_world::{
BlockStateId,
world::{BlockAccessor, BlockFlags},
};
use rand::RngExt;
use crate::{
block::blocks::plant::PlantBlockBase, plugin::api::events::block::block_grow::BlockGrowEvent,
world::World,
};
type CropProperties = WheatLikeProperties;
type FarmlandProperties = FarmlandLikeProperties;
pub mod beetroot;
pub mod carrot;
pub mod gourds;
pub mod nether_wart;
pub mod potatoes;
pub mod sweet_berry_bush;
pub mod torch_flower;
pub mod wheat;
trait CropBlockBase: PlantBlockBase {
fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
let block = block_accessor.get_block(pos);
block == &Block::FARMLAND
}
fn max_age(&self) -> i32 {
7
}
fn get_age(&self, state: u16, block: &Block) -> i32 {
let props = CropProperties::from_state_id(state, block);
i32::from(props.age)
}
fn state_with_age(&self, block: &Block, state: u16, age: i32) -> BlockStateId {
let mut props = CropProperties::from_state_id(state, block);
props.age = age as u8;
props.to_state_id(block)
}
async fn random_tick(&self, world: &Arc<World>, pos: &BlockPos) {
let (block, state) = world.get_block_and_state_id(pos);
let age = self.get_age(state, block);
if age < self.max_age() {
let f = get_available_moisture(world, pos, block).await;
if rand::rng().random_range(0..=(25.0 / f).floor() as i64) == 0 {
let mut new_state_id = self.state_with_age(block, state, age + 1);
if let Some(server) = world.server.upgrade() {
let event = BlockGrowEvent::new(
world.clone(),
block,
state,
Block::from_state_id(new_state_id),
new_state_id,
*pos,
);
let event = server.plugin_manager.fire(event).await;
if event.cancelled {
return;
}
new_state_id = event.new_state_id;
}
world
.set_block_state(pos, new_state_id, BlockFlags::NOTIFY_NEIGHBORS)
.await;
}
}
}
//TODO add impl for light level
}
pub async fn get_available_moisture(world: &Arc<World>, pos: &BlockPos, block: &Block) -> f32 {
let mut moisture = 1.0;
let down_pos = pos.down();
for dx in -1..=1 {
for dz in -1..=1 {
let mut local_moisture = 0.0;
let (block, block_state) =
world.get_block_and_state_id(&down_pos.offset(Vector3 { x: dx, y: 0, z: dz }));
if block == &Block::FARMLAND {
local_moisture = 1.0;
let props = FarmlandProperties::from_state_id(block_state, block);
if props.moisture != 0 {
local_moisture = 3.0;
}
}
if dx != 0 || dz != 0 {
local_moisture /= 4.0;
}
moisture += local_moisture;
}
}
let north = pos.offset(North.to_offset());
let south = pos.offset(South.to_offset());
let west = pos.offset(West.to_offset());
let east = pos.offset(East.to_offset());
let horizontal = world.get_block(&west) == block || world.get_block(&east) == block;
let vertical = world.get_block(&north) == block || world.get_block(&south) == block;
if (horizontal && vertical)
|| world.get_block(&west.offset(North.to_offset())) == block
|| world.get_block(&east.offset(North.to_offset())) == block
|| world.get_block(&east.offset(South.to_offset())) == block
|| world.get_block(&west.offset(South.to_offset())) == block
{
moisture /= 2.0;
}
moisture
}