166 lines
5.3 KiB
Rust
166 lines
5.3 KiB
Rust
use std::sync::Arc;
|
|
|
|
use crate::{
|
|
block::{
|
|
BlockBehaviour, BlockFuture, GetComparatorOutputArgs, NormalUseArgs, OnScheduledTickArgs,
|
|
UseWithItemArgs, registry::BlockActionResult,
|
|
},
|
|
entity::{Entity, item::ItemEntity},
|
|
world::World,
|
|
};
|
|
use pumpkin_data::{
|
|
Block,
|
|
block_properties::{BlockProperties, ComposterLikeProperties},
|
|
composter_increase_chance::get_composter_increase_chance_from_item_id,
|
|
entity::EntityType,
|
|
item::Item,
|
|
item_stack::ItemStack,
|
|
world::WorldEvent,
|
|
};
|
|
use pumpkin_inventory::screen_handler::InventoryPlayer;
|
|
use pumpkin_macros::pumpkin_block;
|
|
use pumpkin_util::math::position::BlockPos;
|
|
use pumpkin_world::{BlockStateId, tick::TickPriority, world::BlockFlags};
|
|
use rand::RngExt;
|
|
|
|
#[pumpkin_block("minecraft:composter")]
|
|
pub struct ComposterBlock;
|
|
|
|
impl BlockBehaviour for ComposterBlock {
|
|
fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> {
|
|
Box::pin(async move {
|
|
let state_id = args.world.get_block_state_id(args.position);
|
|
let props = ComposterLikeProperties::from_state_id(state_id, args.block);
|
|
if props.level == 8 {
|
|
self.clear_composter(args.world, args.position, state_id, args.block)
|
|
.await;
|
|
}
|
|
|
|
BlockActionResult::Pass
|
|
})
|
|
}
|
|
|
|
fn use_with_item<'a>(
|
|
&'a self,
|
|
args: UseWithItemArgs<'a>,
|
|
) -> BlockFuture<'a, BlockActionResult> {
|
|
Box::pin(async move {
|
|
let state_id = args.world.get_block_state_id(args.position);
|
|
let props = ComposterLikeProperties::from_state_id(state_id, args.block);
|
|
let level = props.level;
|
|
|
|
// Check if the composter is full
|
|
if level == 8 {
|
|
self.clear_composter(args.world, args.position, state_id, args.block)
|
|
.await;
|
|
return BlockActionResult::Consume;
|
|
}
|
|
|
|
let mut item_stack = args.item_stack.lock().await;
|
|
let item_id = item_stack.item.id;
|
|
|
|
// Check if the item is consumable by the composter
|
|
let Some(chance) = get_composter_increase_chance_from_item_id(item_id) else {
|
|
return BlockActionResult::Pass;
|
|
};
|
|
|
|
// Consume one item from the stack (if in survival mode)
|
|
if !args.player.has_infinite_materials() {
|
|
item_stack.decrement(1);
|
|
}
|
|
|
|
// Determine if the composter level should increase
|
|
if level < 7 && (level == 0 || rand::rng().random_bool(f64::from(chance))) {
|
|
self.update_level_composter(
|
|
args.world,
|
|
args.position,
|
|
state_id,
|
|
args.block,
|
|
level + 1,
|
|
)
|
|
.await;
|
|
args.world
|
|
.sync_world_event(WorldEvent::ComposterFill, *args.position, 1);
|
|
}
|
|
|
|
// Consume the item
|
|
BlockActionResult::Consume
|
|
})
|
|
}
|
|
|
|
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
|
|
Box::pin(async move {
|
|
let state_id = args.world.get_block_state_id(args.position);
|
|
let props = ComposterLikeProperties::from_state_id(state_id, args.block);
|
|
let level = props.level;
|
|
if level == 7 {
|
|
self.update_level_composter(
|
|
args.world,
|
|
args.position,
|
|
state_id,
|
|
args.block,
|
|
level + 1,
|
|
)
|
|
.await;
|
|
}
|
|
})
|
|
}
|
|
|
|
fn get_comparator_output<'a>(
|
|
&'a self,
|
|
args: GetComparatorOutputArgs<'a>,
|
|
) -> BlockFuture<'a, Option<u8>> {
|
|
Box::pin(async move {
|
|
let props = ComposterLikeProperties::from_state_id(args.state.id, args.block);
|
|
Some(props.level)
|
|
})
|
|
}
|
|
}
|
|
|
|
impl ComposterBlock {
|
|
pub async fn update_level_composter(
|
|
&self,
|
|
world: &Arc<World>,
|
|
location: &BlockPos,
|
|
state_id: BlockStateId,
|
|
block: &Block,
|
|
level: u8,
|
|
) {
|
|
let mut props = ComposterLikeProperties::from_state_id(state_id, block);
|
|
props.level = level;
|
|
world
|
|
.set_block_state(location, props.to_state_id(block), BlockFlags::NOTIFY_ALL)
|
|
.await;
|
|
if level == 7 {
|
|
world.schedule_block_tick(block, *location, 20, TickPriority::Normal);
|
|
}
|
|
}
|
|
|
|
pub async fn clear_composter(
|
|
&self,
|
|
world: &Arc<World>,
|
|
location: &BlockPos,
|
|
state_id: BlockStateId,
|
|
block: &Block,
|
|
) {
|
|
self.update_level_composter(world, location, state_id, block, 0)
|
|
.await;
|
|
|
|
let item_position = {
|
|
let mut rng = rand::rng();
|
|
location.to_centered_f64().add_raw(
|
|
rng.random_range(-0.35..=0.35),
|
|
rng.random_range(-0.35..=0.35) + 0.51,
|
|
rng.random_range(-0.35..=0.35),
|
|
)
|
|
};
|
|
|
|
let item_entity = ItemEntity::new(
|
|
Entity::new(world.clone(), item_position, &EntityType::ITEM),
|
|
ItemStack::new(1, &Item::BONE_MEAL),
|
|
);
|
|
|
|
world.spawn_entity(Arc::new(item_entity)).await;
|
|
}
|
|
}
|