1037 lines
34 KiB
Rust
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()
|
|
}
|
|
}
|