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 { 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>, fluids: FxHashMap>, } 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(&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(&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, 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, 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, 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, position: &BlockPos, hit: &BlockHitResult<'_>, server: &Server, world: &Arc, ) -> 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, 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, position: &BlockPos, hit: &BlockHitResult<'_>, item_stack: &Arc>, server: &Server, world: &Arc, ) -> 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, position: BlockPos, item: &Item, server: &Server, world: &Arc, ) -> 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, 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, 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, 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, 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, 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, block: &Block, player: &Arc, 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, 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, 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, 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, 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, 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, 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> { self.blocks.get(&block) } #[must_use] pub fn get_pumpkin_fluid(&self, fluid_id: u16) -> Option<&Arc> { 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() } }