Pumpkin/pumpkin/src/block/registry.rs
2026-05-06 22:29:29 +02:00

1037 lines
34 KiB
Rust

use crate::block::blocks::anvil::AnvilBlock;
use crate::block::blocks::banners::BannerBlock;
use crate::block::blocks::barrel::BarrelBlock;
use crate::block::blocks::barrier::BarrierBlock;
use crate::block::blocks::bed::BedBlock;
use crate::block::blocks::brewing_stand::BrewingStandBlock;
use crate::block::blocks::cake::CakeBlock;
use crate::block::blocks::campfire::CampfireBlock;
use crate::block::blocks::candle_cakes::CandleCakeBlock;
use crate::block::blocks::candles::CandleBlock;
use crate::block::blocks::carpet::{CarpetBlock, MossCarpetBlock, PaleMossCarpetBlock};
use crate::block::blocks::carved_pumpkin::CarvedPumpkinBlock;
use crate::block::blocks::chests::{ChestBlock, CopperChestBlock, TrappedChestBlock};
use crate::block::blocks::chiseled_bookshelf::ChiseledBookshelfBlock;
use crate::block::blocks::command::CommandBlock;
use crate::block::blocks::composter::ComposterBlock;
use crate::block::blocks::conduit::ConduitBlock;
use crate::block::blocks::dirt_path::DirtPathBlock;
use crate::block::blocks::doors::DoorBlock;
use crate::block::blocks::dripstone::DripstoneBlock;
use crate::block::blocks::end_portal::EndPortalBlock;
use crate::block::blocks::end_portal_frame::EndPortalFrameBlock;
use crate::block::blocks::falling::FallingBlock;
use crate::block::blocks::farmland::FarmlandBlock;
use crate::block::blocks::fence_gates::FenceGateBlock;
use crate::block::blocks::fences::FenceBlock;
use crate::block::blocks::fire::fire::FireBlock;
use crate::block::blocks::fire::soul_fire::SoulFireBlock;
use crate::block::blocks::flower_pots::FlowerPotBlock;
use crate::block::blocks::furnace::FurnaceBlock;
use crate::block::blocks::glass_panes::GlassPaneBlock;
use crate::block::blocks::glazed_terracotta::GlazedTerracottaBlock;
use crate::block::blocks::grindstone::GrindstoneBlock;
use crate::block::blocks::hay::HayBlock;
use crate::block::blocks::infested::InfestedBlock;
use crate::block::blocks::iron_bars::IronBarsBlock;
use crate::block::blocks::logs::LogBlock;
use crate::block::blocks::magma::MagmaBlock;
use crate::block::blocks::mangrove_roots::MangroveRootsBlock;
use crate::block::blocks::nether_portal::NetherPortalBlock;
use crate::block::blocks::note::NoteBlock;
use crate::block::blocks::piston::piston::PistonBlock;
use crate::block::blocks::piston::piston_extension::PistonExtensionBlock;
use crate::block::blocks::piston::piston_head::PistonHeadBlock;
use crate::block::blocks::plant::bamboo::BambooBlock;
use crate::block::blocks::plant::bamboo_sapling::BambooSaplingBlock;
use crate::block::blocks::plant::big_dripleaf::BigDripleafBlock;
use crate::block::blocks::plant::big_dripleaf_stem::BigDripleafStemBlock;
use crate::block::blocks::plant::bush::BushBlock;
use crate::block::blocks::plant::cactus::CactusBlock;
use crate::block::blocks::plant::cactus_flower::CactusFlowerBlock;
use crate::block::blocks::plant::chorus_flower::ChorusFlowerBlock;
use crate::block::blocks::plant::chorus_plant::ChorusPlantBlock;
use crate::block::blocks::plant::crop::beetroot::BeetrootBlock;
use crate::block::blocks::plant::crop::carrot::CarrotBlock;
use crate::block::blocks::plant::crop::nether_wart::NetherWartBlock;
use crate::block::blocks::plant::crop::potatoes::PotatoBlock;
use crate::block::blocks::plant::crop::sweet_berry_bush::SweetBerryBushBlock;
use crate::block::blocks::plant::crop::torch_flower::TorchFlowerBlock;
use crate::block::blocks::plant::crop::wheat::WheatBlock;
use crate::block::blocks::plant::dry_vegetation::DryVegetationBlock;
use crate::block::blocks::plant::flower::FlowerBlock;
use crate::block::blocks::plant::flowerbed::FlowerbedBlock;
use crate::block::blocks::plant::fungus::FungusBlock;
use crate::block::blocks::plant::kelp::KelpBlock;
use crate::block::blocks::plant::leaf_litter::LeafLitterBlock;
use crate::block::blocks::plant::lily_pad::LilyPadBlock;
use crate::block::blocks::plant::mushroom_plant::MushroomPlantBlock;
use crate::block::blocks::plant::nether_sprouts::NetherSproutsBlock;
use crate::block::blocks::plant::roots::RootsBlock;
use crate::block::blocks::plant::sapling::SaplingBlock;
use crate::block::blocks::plant::sea_pickles::SeaPickleBlock;
use crate::block::blocks::plant::seagrass::SeaGrassBlock;
use crate::block::blocks::plant::short_plant::ShortPlantBlock;
use crate::block::blocks::plant::small_dripleaf::SmallDripleafBlock;
use crate::block::blocks::plant::spore_blossom::SporeBlossomBlock;
use crate::block::blocks::plant::sugar_cane::SugarCaneBlock;
use crate::block::blocks::plant::tall_plant::TallPlantBlock;
use crate::block::blocks::plant::tall_seagrass::TallSeaGrassBlock;
use crate::block::blocks::plant::twisting_vines::TwistingVinesBlock;
use crate::block::blocks::plant::weeping_vines::WeepingVinesBlock;
use crate::block::blocks::plant::wither_rose::WitherRoseBlock;
use crate::block::blocks::powder_snow::PowderSnowBlock;
use crate::block::blocks::pumpkin::PumpkinBlock;
use crate::block::blocks::redstone::bell::BellBlock;
use crate::block::blocks::redstone::buttons::ButtonBlock;
use crate::block::blocks::redstone::comparator::ComparatorBlock;
use crate::block::blocks::redstone::copper_bulb::CopperBulbBlock;
use crate::block::blocks::redstone::daylight_detector::DaylightDetectorBlock;
use crate::block::blocks::redstone::dispenser::DispenserBlock;
use crate::block::blocks::redstone::dropper::DropperBlock;
use crate::block::blocks::redstone::lever::LeverBlock;
use crate::block::blocks::redstone::observer::ObserverBlock;
use crate::block::blocks::redstone::pressure_plate::plate::PressurePlateBlock;
use crate::block::blocks::redstone::pressure_plate::weighted::WeightedPressurePlateBlock;
use crate::block::blocks::redstone::rails::activator_rail::ActivatorRailBlock;
use crate::block::blocks::redstone::rails::detector_rail::DetectorRailBlock;
use crate::block::blocks::redstone::rails::powered_rail::PoweredRailBlock;
use crate::block::blocks::redstone::rails::rail::RailBlock;
use crate::block::blocks::redstone::redstone_block::RedstoneBlock;
use crate::block::blocks::redstone::redstone_lamp::RedstoneLamp;
use crate::block::blocks::redstone::redstone_torch::RedstoneTorchBlock;
use crate::block::blocks::redstone::redstone_wire::RedstoneWireBlock;
use crate::block::blocks::redstone::repeater::RepeaterBlock;
use crate::block::blocks::redstone::target_block::TargetBlock;
use crate::block::blocks::redstone::tripwire::TripwireBlock;
use crate::block::blocks::redstone::tripwire_hook::TripwireHookBlock;
use crate::block::blocks::shelf::ShelfBlock;
use crate::block::blocks::signs::SignBlock;
use crate::block::blocks::slabs::SlabBlock;
use crate::block::blocks::slime::SlimeBlock;
use crate::block::blocks::snow::LayeredSnowBlock;
use crate::block::blocks::spawner::SpawnerBlock;
use crate::block::blocks::sponge::{SpongeBlock, WetSpongeBlock};
use crate::block::blocks::stairs::StairBlock;
use crate::block::blocks::tnt::TNTBlock;
use crate::block::blocks::torches::TorchBlock;
use crate::block::blocks::trapdoor::TrapDoorBlock;
use crate::block::blocks::vine::VineBlock;
use crate::block::blocks::walls::WallBlock;
use crate::block::blocks::wither_skull::WitherSkeletonSkullBlock;
use crate::block::fluid::lava::FlowingLava;
use crate::block::fluid::water::FlowingWater;
use crate::block::{
BlockBehaviour, BlockHitResult, BlockMetadata, GetInsideCollisionShapeArgs,
OnEntityCollisionArgs, OnLandedUponArgs, UpdateEntityMovementAfterFallOnArgs,
stop_vertical_movement_after_fall,
};
use crate::entity::EntityBase;
use crate::entity::player::Player;
use crate::server::Server;
use crate::world::World;
use pumpkin_data::fluid::Fluid;
use pumpkin_data::item::Item;
use pumpkin_data::item_stack::ItemStack;
use pumpkin_data::{Block, BlockDirection, BlockState};
use pumpkin_protocol::java::server::play::SUseItemOn;
use pumpkin_util::math::boundingbox::BoundingBox;
use pumpkin_util::math::position::BlockPos;
use pumpkin_world::BlockStateId;
use pumpkin_world::world::{BlockAccessor, BlockFlags, BlockRegistryExt};
use rustc_hash::FxHashMap;
use std::sync::Arc;
use tokio::sync::Mutex;
use super::BlockIsReplacing;
use super::blocks::plant::crop::gourds::attached_stem::AttachedStemBlock;
use super::blocks::plant::crop::gourds::stem::StemBlock;
use super::fluid::FluidBehaviour;
use super::{
BrokenArgs, CanPlaceAtArgs, CanUpdateAtArgs, EmitsRedstonePowerArgs, ExplodeArgs,
GetRedstonePowerArgs, GetStateForNeighborUpdateArgs, NormalUseArgs, OnNeighborUpdateArgs,
OnPlaceArgs, OnStateReplacedArgs, OnSyncedBlockEventArgs, PlacedArgs, PlayerPlacedArgs,
PrepareArgs, UseWithItemArgs,
};
use crate::block::OnEntityStepArgs;
use crate::block::blocks::blast_furnace::BlastFurnaceBlock;
use crate::block::blocks::chain::ChainBlock;
use crate::block::blocks::cobweb::CobwebBlock;
use crate::block::blocks::crafting_table::CraftingTableBlock;
use crate::block::blocks::dragon_egg::DragonEggBlock;
use crate::block::blocks::enchanting_table::EnchantingTableBlock;
use crate::block::blocks::end_rod::EndRodBlock;
use crate::block::blocks::ender_chest::EnderChestBlock;
use crate::block::blocks::hopper::HopperBlock;
use crate::block::blocks::jukebox::JukeboxBlock;
use crate::block::blocks::ladder::LadderBlock;
use crate::block::blocks::lanterns::LanternBlock;
use crate::block::blocks::lectern::LecternBlock;
use crate::block::blocks::shulker_box::ShulkerBoxBlock;
use crate::block::blocks::skull_block::SkullBlock;
use crate::block::blocks::smoker::SmokerBlock;
#[must_use]
#[expect(clippy::too_many_lines)]
pub fn default_registry() -> Arc<BlockRegistry> {
let mut manager = BlockRegistry::default();
// Blocks
manager.register(AnvilBlock);
manager.register(BedBlock);
manager.register(SaplingBlock);
manager.register(CactusBlock);
manager.register(ChorusFlowerBlock);
manager.register(ChorusPlantBlock);
manager.register(CarpetBlock);
manager.register(CarvedPumpkinBlock);
manager.register(WitherSkeletonSkullBlock);
manager.register(CampfireBlock);
manager.register(MossCarpetBlock);
manager.register(PaleMossCarpetBlock);
manager.register(ChestBlock);
manager.register(TrappedChestBlock);
manager.register(CopperChestBlock);
manager.register(EnderChestBlock);
manager.register(CraftingTableBlock);
manager.register(EnchantingTableBlock);
manager.register(DirtPathBlock);
manager.register(DoorBlock);
manager.register(FarmlandBlock);
manager.register(FenceGateBlock);
manager.register(FenceBlock);
manager.register(FlowerPotBlock);
manager.register(FurnaceBlock);
manager.register(BrewingStandBlock);
manager.register(BlastFurnaceBlock);
manager.register(SmokerBlock);
manager.register(GlassPaneBlock);
manager.register(GlazedTerracottaBlock);
manager.register(HayBlock);
manager.register(GrindstoneBlock);
manager.register(IronBarsBlock);
manager.register(InfestedBlock);
manager.register(JukeboxBlock);
manager.register(LogBlock);
manager.register(BambooBlock);
manager.register(BambooSaplingBlock);
manager.register(BannerBlock);
manager.register(SignBlock);
manager.register(SlabBlock);
manager.register(SlimeBlock);
manager.register(StairBlock);
manager.register(ShortPlantBlock);
manager.register(DryVegetationBlock);
manager.register(LilyPadBlock);
manager.register(SugarCaneBlock);
manager.register(VineBlock);
manager.register(TNTBlock);
manager.register(BushBlock);
manager.register(FlowerBlock);
manager.register(PotatoBlock);
manager.register(BeetrootBlock);
manager.register(TorchFlowerBlock);
manager.register(CarrotBlock);
manager.register(SweetBerryBushBlock);
manager.register(SeaGrassBlock);
manager.register(TallSeaGrassBlock);
manager.register(KelpBlock);
manager.register(NetherWartBlock);
manager.register(WheatBlock);
manager.register(TorchBlock);
manager.register(TrapDoorBlock);
manager.register(MushroomPlantBlock);
manager.register(FlowerbedBlock);
manager.register(LeafLitterBlock);
manager.register(WallBlock);
manager.register(RootsBlock);
manager.register(NetherPortalBlock);
manager.register(TallPlantBlock);
manager.register(NoteBlock);
manager.register(PowderSnowBlock);
manager.register(SpongeBlock);
manager.register(PumpkinBlock);
manager.register(WetSpongeBlock);
manager.register(CommandBlock);
manager.register(ComposterBlock);
manager.register(PressurePlateBlock);
manager.register(WeightedPressurePlateBlock);
manager.register(EndPortalBlock);
manager.register(SpawnerBlock);
manager.register(EndPortalFrameBlock);
manager.register(CandleBlock);
manager.register(SeaPickleBlock);
manager.register(CakeBlock);
manager.register(CandleCakeBlock);
manager.register(SkullBlock);
manager.register(ChiseledBookshelfBlock);
manager.register(ShelfBlock);
manager.register(LecternBlock);
manager.register(DragonEggBlock);
manager.register(StemBlock);
manager.register(AttachedStemBlock);
manager.register(ChainBlock);
manager.register(LanternBlock);
manager.register(EndRodBlock);
manager.register(BarrierBlock);
manager.register(MangroveRootsBlock);
manager.register(LayeredSnowBlock);
manager.register(CobwebBlock);
manager.register(WitherRoseBlock);
manager.register(FungusBlock);
manager.register(NetherSproutsBlock);
manager.register(SporeBlossomBlock);
manager.register(ConduitBlock);
manager.register(DripstoneBlock);
manager.register(TwistingVinesBlock);
manager.register(WeepingVinesBlock);
manager.register(CactusFlowerBlock);
manager.register(SmallDripleafBlock);
manager.register(BigDripleafStemBlock);
manager.register(BigDripleafBlock);
manager.register(FallingBlock);
// Fire
manager.register(SoulFireBlock);
manager.register(FireBlock);
manager.register(MagmaBlock);
// Redstone
manager.register(ButtonBlock);
manager.register(BellBlock);
manager.register(LeverBlock);
manager.register(ObserverBlock);
manager.register(TripwireBlock);
manager.register(TripwireHookBlock);
// Piston
manager.register(PistonBlock);
manager.register(PistonExtensionBlock);
manager.register(PistonHeadBlock);
manager.register(RedstoneBlock);
manager.register(RedstoneLamp);
manager.register(CopperBulbBlock);
manager.register(RedstoneTorchBlock);
manager.register(RedstoneWireBlock);
manager.register(RepeaterBlock);
manager.register(ComparatorBlock);
manager.register(TargetBlock);
manager.register(BarrelBlock);
manager.register(HopperBlock);
manager.register(ShulkerBoxBlock);
manager.register(DropperBlock);
manager.register(DispenserBlock);
manager.register(LadderBlock);
manager.register(DaylightDetectorBlock);
// Rails
manager.register(RailBlock);
manager.register(ActivatorRailBlock);
manager.register(DetectorRailBlock);
manager.register(PoweredRailBlock);
// Fluids
manager.register_fluid(FlowingWater);
manager.register_fluid(FlowingLava);
Arc::new(manager)
}
// ActionResult.java
#[derive(PartialEq, Eq)]
pub enum BlockActionResult {
/// Action was successful | Same as SUCCESS in vanilla
Success,
/// Action was successful and we should swing the hand for the server | Same as `SUCCESS_SERVER` in vanilla
SuccessServer,
/// Block other actions from being executed | Same as CONSUME in vanilla
Consume,
/// Allow other actions to be executed, but indicate it failed | Same as FAIL in vanilla
Fail,
/// Allow other actions to be executed | Same as PASS in vanilla
Pass,
/// Use default action for the block: `normal_use` | Same as `PASS_TO_DEFAULT_BLOCK_ACTION` in vanilla
PassToDefaultBlockAction,
}
impl BlockActionResult {
#[must_use]
pub const fn consumes_action(&self) -> bool {
matches!(self, Self::Consume | Self::Success | Self::SuccessServer)
}
}
#[derive(Default)]
pub struct BlockRegistry {
blocks: FxHashMap<u16, Arc<dyn BlockBehaviour>>,
fluids: FxHashMap<u16, Arc<dyn FluidBehaviour>>,
}
impl BlockRegistryExt for BlockRegistry {
fn can_place_at(
&self,
block: &pumpkin_data::Block,
state: &BlockState,
block_accessor: &dyn BlockAccessor,
block_pos: &BlockPos,
) -> bool {
futures::executor::block_on(async move {
self.can_place_at(
None,
None,
block_accessor,
None,
block,
state,
block_pos,
None,
None,
)
.await
})
}
}
impl BlockRegistry {
pub fn register<T: BlockBehaviour + BlockMetadata + 'static>(&mut self, block: T) {
let ids = T::ids();
let val = Arc::new(block);
self.blocks.reserve(ids.len());
for i in ids {
self.blocks.insert(i, val.clone());
}
}
pub fn register_fluid<T: FluidBehaviour + BlockMetadata + 'static>(&mut self, fluid: T) {
let ids = T::ids();
let val = Arc::new(fluid);
self.fluids.reserve(ids.len());
for i in ids {
self.fluids.insert(i, val.clone());
}
}
pub async fn on_synced_block_event(
&self,
block: &Block,
world: &Arc<World>,
position: &BlockPos,
r#type: u8,
data: u8,
) -> bool {
let pumpkin_block = self.get_pumpkin_block(block.id);
if let Some(pumpkin_block) = pumpkin_block {
return pumpkin_block
.on_synced_block_event(OnSyncedBlockEventArgs {
world,
block,
position,
r#type,
data,
})
.await;
}
false
}
pub async fn on_entity_collision(
&self,
block: &Block,
world: &Arc<World>,
entity: &dyn EntityBase,
position: &BlockPos,
state: &BlockState,
server: &Server,
) {
let pumpkin_block = self.get_pumpkin_block(block.id);
if let Some(pumpkin_block) = pumpkin_block {
pumpkin_block
.on_entity_collision(OnEntityCollisionArgs {
server,
world,
block,
state,
position,
entity,
})
.await;
}
}
pub async fn on_entity_step(
&self,
block: &Block,
world: &Arc<World>,
entity: &dyn EntityBase,
position: &BlockPos,
state: &BlockState,
below_supporting_block: bool,
) {
if let Some(pumpkin_block) = self.get_pumpkin_block(block.id) {
pumpkin_block
.on_entity_step(OnEntityStepArgs {
world,
block,
state,
position,
entity,
below_supporting_block,
})
.await;
}
}
pub async fn on_entity_collision_fluid(&self, fluid: &Fluid, entity: &dyn EntityBase) {
let pumpkin_fluid = self.get_pumpkin_fluid(fluid.id);
if let Some(pumpkin_fluid) = pumpkin_fluid {
pumpkin_fluid.on_entity_collision(entity).await;
}
}
pub async fn on_use(
&self,
block: &Block,
player: &Arc<Player>,
position: &BlockPos,
hit: &BlockHitResult<'_>,
server: &Server,
world: &Arc<World>,
) -> BlockActionResult {
let pumpkin_block = self.get_pumpkin_block(block.id);
if let Some(pumpkin_block) = pumpkin_block {
return pumpkin_block
.normal_use(NormalUseArgs {
server,
world,
block,
position,
player,
hit,
})
.await;
}
BlockActionResult::Pass
}
pub async fn explode(&self, block: &Block, world: &Arc<World>, position: &BlockPos) {
let pumpkin_block = self.get_pumpkin_block(block.id);
if let Some(pumpkin_block) = pumpkin_block {
pumpkin_block
.explode(ExplodeArgs {
world,
block,
position,
})
.await;
}
}
#[expect(clippy::too_many_arguments)]
pub async fn use_with_item(
&self,
block: &Block,
player: &Arc<Player>,
position: &BlockPos,
hit: &BlockHitResult<'_>,
item_stack: &Arc<Mutex<ItemStack>>,
server: &Server,
world: &Arc<World>,
) -> BlockActionResult {
let pumpkin_block = self.get_pumpkin_block(block.id);
if let Some(pumpkin_block) = pumpkin_block {
return pumpkin_block
.use_with_item(UseWithItemArgs {
server,
world,
block,
position,
player,
hit,
item_stack,
})
.await;
}
BlockActionResult::Pass
}
pub async fn use_with_item_fluid(
&self,
fluid: &Fluid,
player: &Arc<Player>,
position: BlockPos,
item: &Item,
server: &Server,
world: &Arc<World>,
) -> BlockActionResult {
let pumpkin_fluid = self.get_pumpkin_fluid(fluid.id);
if let Some(pumpkin_fluid) = pumpkin_fluid {
return pumpkin_fluid
.use_with_item(fluid, player, position, item, server, world)
.await;
}
BlockActionResult::Pass
}
#[expect(clippy::too_many_arguments)]
pub async fn can_place_at(
&self,
server: Option<&Server>,
world: Option<&World>,
block_accessor: &dyn BlockAccessor,
player: Option<&Player>,
block: &Block,
state: &BlockState,
position: &BlockPos,
direction: Option<BlockDirection>,
use_item_on: Option<&SUseItemOn>,
) -> bool {
let pumpkin_block = self.get_pumpkin_block(block.id);
if let Some(pumpkin_block) = pumpkin_block {
return pumpkin_block
.can_place_at(CanPlaceAtArgs {
server,
world,
block_accessor,
block,
state,
position,
direction,
player,
use_item_on,
})
.await;
}
true
}
#[expect(clippy::too_many_arguments)]
pub async fn can_update_at(
&self,
world: &World,
block: &Block,
state_id: BlockStateId,
position: &BlockPos,
direction: BlockDirection,
use_item_on: &SUseItemOn,
player: &Player,
) -> bool {
let pumpkin_block = self.get_pumpkin_block(block.id);
if let Some(pumpkin_block) = pumpkin_block {
return pumpkin_block
.can_update_at(CanUpdateAtArgs {
world,
block,
state_id,
position,
direction,
player,
use_item_on,
})
.await;
}
false
}
#[expect(clippy::too_many_arguments)]
pub async fn on_place(
&self,
server: &Server,
world: &World,
player: &Player,
block: &Block,
position: &BlockPos,
direction: BlockDirection,
replacing: BlockIsReplacing,
use_item_on: &SUseItemOn,
) -> BlockStateId {
let pumpkin_block = self.get_pumpkin_block(block.id);
if let Some(pumpkin_block) = pumpkin_block {
return pumpkin_block
.on_place(OnPlaceArgs {
server,
world,
block,
position,
direction,
player,
replacing,
use_item_on,
})
.await;
}
block.default_state.id
}
pub async fn player_placed(
&self,
world: &Arc<World>,
block: &Block,
state_id: u16,
position: &BlockPos,
direction: BlockDirection,
player: &Player,
) {
let pumpkin_block = self.get_pumpkin_block(block.id);
if let Some(pumpkin_block) = pumpkin_block {
pumpkin_block
.player_placed(PlayerPlacedArgs {
world,
block,
state_id,
position,
direction,
player,
})
.await;
}
}
pub async fn on_placed(
&self,
world: &Arc<World>,
block: &Block,
state_id: BlockStateId,
position: &BlockPos,
old_state_id: BlockStateId,
notify: bool,
) {
let pumpkin_block = self.get_pumpkin_block(block.id);
if let Some(pumpkin_block) = pumpkin_block {
pumpkin_block
.placed(PlacedArgs {
world,
block,
state_id,
old_state_id,
position,
notify,
})
.await;
}
}
pub async fn on_placed_fluid(
&self,
world: &Arc<World>,
fluid: &Fluid,
state_id: BlockStateId,
position: &BlockPos,
old_state_id: BlockStateId,
notify: bool,
) {
let pumpkin_fluid = self.get_pumpkin_fluid(fluid.id);
if let Some(pumpkin_fluid) = pumpkin_fluid {
pumpkin_fluid
.placed(world, fluid, state_id, position, old_state_id, notify)
.await;
}
}
pub async fn on_landed_upon(
&self,
block: &Block,
world: &Arc<World>,
fall_distance: f32,
entity: &dyn EntityBase,
) {
let pumpkin_block = self.get_pumpkin_block(block.id);
if let Some(pumpkin_block) = pumpkin_block {
pumpkin_block
.on_landed_upon(OnLandedUponArgs {
world,
fall_distance,
entity,
})
.await;
}
}
pub async fn update_entity_movement_after_fall_on(
&self,
block: &Block,
entity: &dyn EntityBase,
) {
if let Some(pumpkin_block) = self.get_pumpkin_block(block.id) {
pumpkin_block
.update_entity_movement_after_fall_on(UpdateEntityMovementAfterFallOnArgs {
entity,
})
.await;
} else {
stop_vertical_movement_after_fall(entity);
}
}
pub async fn broken(
&self,
world: &Arc<World>,
block: &Block,
player: &Arc<Player>,
position: &BlockPos,
server: &Server,
state: &BlockState,
) {
let pumpkin_block = self.get_pumpkin_block(block.id);
if let Some(pumpkin_block) = pumpkin_block {
pumpkin_block
.broken(BrokenArgs {
block,
player,
position,
server,
world,
state,
})
.await;
}
}
pub async fn on_state_replaced(
&self,
world: &Arc<World>,
block: &Block,
position: &BlockPos,
old_state_id: BlockStateId,
moved: bool,
) {
let pumpkin_block = self.get_pumpkin_block(block.id);
if let Some(pumpkin_block) = pumpkin_block {
pumpkin_block
.on_state_replaced(OnStateReplacedArgs {
world,
block,
old_state_id,
position,
moved,
})
.await;
}
}
/// Updates state of all neighbors of the block
pub async fn post_process_state(
&self,
world: &Arc<World>,
position: &BlockPos,
block: &Block,
flags: BlockFlags,
) {
let state_id = world.get_block_state_id(position).await;
for direction in BlockDirection::all() {
let neighbor_pos = position.offset(direction.to_offset());
let neighbor_state_id = world.get_block_state_id(&neighbor_pos).await;
let pumpkin_block = self.get_pumpkin_block(block.id);
if let Some(pumpkin_block) = pumpkin_block {
let new_state = pumpkin_block
.get_state_for_neighbor_update(GetStateForNeighborUpdateArgs {
world,
block,
state_id,
position,
direction: direction.opposite(),
neighbor_position: &neighbor_pos,
neighbor_state_id,
})
.await;
world.set_block_state(&neighbor_pos, new_state, flags).await;
}
}
}
pub async fn prepare(
&self,
world: &Arc<World>,
position: &BlockPos,
block: &Block,
state_id: BlockStateId,
flags: BlockFlags,
) {
let pumpkin_block = self.get_pumpkin_block(block.id);
if let Some(pumpkin_block) = pumpkin_block {
pumpkin_block
.prepare(PrepareArgs {
world,
block,
state_id,
position,
flags,
})
.await;
}
}
#[expect(clippy::too_many_arguments)]
pub async fn get_state_for_neighbor_update(
&self,
world: &Arc<World>,
block: &Block,
state_id: BlockStateId,
position: &BlockPos,
direction: BlockDirection,
neighbor_location: &BlockPos,
neighbor_state_id: BlockStateId,
) -> BlockStateId {
let pumpkin_block = self.get_pumpkin_block(block.id);
if let Some(pumpkin_block) = pumpkin_block {
return pumpkin_block
.get_state_for_neighbor_update(GetStateForNeighborUpdateArgs {
world,
block,
state_id,
position,
direction,
neighbor_position: neighbor_location,
neighbor_state_id,
})
.await;
}
state_id
}
pub async fn update_neighbors(
&self,
world: &Arc<World>,
position: &BlockPos,
_block: &Block,
flags: BlockFlags,
) {
for direction in BlockDirection::abstract_block_update_order() {
let pos = position.offset(direction.to_offset());
Box::pin(world.replace_with_state_for_neighbor_update(
&pos,
direction.opposite(),
flags,
))
.await;
}
}
pub async fn on_neighbor_update(
&self,
world: &Arc<World>,
block: &Block,
position: &BlockPos,
source_block: &Block,
notify: bool,
) {
let pumpkin_block = self.get_pumpkin_block(block.id);
if let Some(pumpkin_block) = pumpkin_block {
pumpkin_block
.on_neighbor_update(OnNeighborUpdateArgs {
world,
block,
position,
source_block,
notify,
})
.await;
}
}
#[must_use]
pub fn get_pumpkin_block(&self, block: u16) -> Option<&Arc<dyn BlockBehaviour>> {
self.blocks.get(&block)
}
#[must_use]
pub fn get_pumpkin_fluid(&self, fluid_id: u16) -> Option<&Arc<dyn FluidBehaviour>> {
self.fluids.get(&fluid_id).or_else(|| {
// Still fluids share behavior with their flowing counterpart
match fluid_id {
2 => self.fluids.get(&1),
4 => self.fluids.get(&3),
_ => None,
}
})
}
pub async fn emits_redstone_power(
&self,
block: &Block,
state: &BlockState,
direction: BlockDirection,
) -> bool {
let pumpkin_block = self.get_pumpkin_block(block.id);
if let Some(pumpkin_block) = pumpkin_block {
return pumpkin_block
.emits_redstone_power(EmitsRedstonePowerArgs {
block,
state,
direction,
})
.await;
}
false
}
pub async fn get_weak_redstone_power(
&self,
block: &Block,
world: &World,
position: &BlockPos,
state: &BlockState,
direction: BlockDirection,
) -> u8 {
let pumpkin_block = self.get_pumpkin_block(block.id);
if let Some(pumpkin_block) = pumpkin_block {
return pumpkin_block
.get_weak_redstone_power(GetRedstonePowerArgs {
world,
block,
state,
position,
direction,
})
.await;
}
0
}
pub async fn get_strong_redstone_power(
&self,
block: &Block,
world: &World,
position: &BlockPos,
state: &BlockState,
direction: BlockDirection,
) -> u8 {
let pumpkin_block = self.get_pumpkin_block(block.id);
if let Some(pumpkin_block) = pumpkin_block {
return pumpkin_block
.get_strong_redstone_power(GetRedstonePowerArgs {
world,
block,
state,
position,
direction,
})
.await;
}
0
}
pub async fn get_inside_collision_shape(
&self,
block: &Block,
world: &World,
state: &BlockState,
position: &BlockPos,
) -> BoundingBox {
let pumpkin_block = self.get_pumpkin_block(block.id);
if let Some(pumpkin_block) = pumpkin_block {
return pumpkin_block
.get_inside_collision_shape(GetInsideCollisionShapeArgs {
world,
block,
state,
position,
})
.await;
}
BoundingBox::full_block()
}
}