1470 lines
51 KiB
Rust
1470 lines
51 KiB
Rust
use crate::block::blocks::amethyst::{AmethystBlock, BuddingAmethystBlock};
|
|
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::beacon::BeaconBlock;
|
|
use crate::block::blocks::bed::BedBlock;
|
|
use crate::block::blocks::beehive::BeehiveBlock;
|
|
use crate::block::blocks::brewing_stand::BrewingStandBlock;
|
|
use crate::block::blocks::brushable_block::BrushableBlock;
|
|
use crate::block::blocks::bubble_column::BubbleColumnBlock;
|
|
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::cartography_table::CartographyTableBlock;
|
|
use crate::block::blocks::carved_pumpkin::CarvedPumpkinBlock;
|
|
use crate::block::blocks::cauldron::CauldronBlock;
|
|
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::coral::coral_block::CoralBlock;
|
|
use crate::block::blocks::coral::coral_fan::CoralFanBlock;
|
|
use crate::block::blocks::coral::coral_plant::CoralPlantBlock;
|
|
use crate::block::blocks::creaking_heart::CreakingHeartBlock;
|
|
use crate::block::blocks::decorated_pot::DecoratedPotBlock;
|
|
use crate::block::blocks::dirt_path::DirtPathBlock;
|
|
use crate::block::blocks::doors::DoorBlock;
|
|
use crate::block::blocks::dripstone::DripstoneBlock;
|
|
use crate::block::blocks::end_gateway::EndGatewayBlock;
|
|
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::fletching_table::FletchingTableBlock;
|
|
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::grass_block::GrassBlock;
|
|
use crate::block::blocks::grindstone::GrindstoneBlock;
|
|
use crate::block::blocks::hay::HayBlock;
|
|
use crate::block::blocks::honey::HoneyBlock;
|
|
use crate::block::blocks::ice::{FrostedIceBlock, IceBlock};
|
|
use crate::block::blocks::infested::InfestedBlock;
|
|
use crate::block::blocks::iron_bars::IronBarsBlock;
|
|
use crate::block::blocks::jigsaw::JigsawBlock;
|
|
use crate::block::blocks::leaves::LeavesBlock;
|
|
use crate::block::blocks::light::LightBlock;
|
|
use crate::block::blocks::logs::LogBlock;
|
|
use crate::block::blocks::loom::LoomBlock;
|
|
use crate::block::blocks::magma::MagmaBlock;
|
|
use crate::block::blocks::mangrove_roots::MangroveRootsBlock;
|
|
use crate::block::blocks::mud::MudBlock;
|
|
use crate::block::blocks::nether_portal::NetherPortalBlock;
|
|
use crate::block::blocks::note::NoteBlock;
|
|
use crate::block::blocks::nylium::NyliumBlock;
|
|
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::azalea::AzaleaBlock;
|
|
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::cave_vines::CaveVinesBlock;
|
|
use crate::block::blocks::plant::chorus_flower::ChorusFlowerBlock;
|
|
use crate::block::blocks::plant::chorus_plant::ChorusPlantBlock;
|
|
use crate::block::blocks::plant::cocoa::CocoaBlock;
|
|
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::pitcher_crop::PitcherCropBlock;
|
|
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::eyeblossom::EyeblossomBlock;
|
|
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::hanging_roots::HangingRootsBlock;
|
|
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::mangrove_propagule::MangrovePropaguleBlock;
|
|
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::crafter::CrafterBlock;
|
|
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::lightning_rod::LightningRodBlock;
|
|
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_ore::RedstoneOreBlock;
|
|
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::sculk_sensor::SculkSensorBlock;
|
|
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::scaffolding::ScaffoldingBlock;
|
|
use crate::block::blocks::sculk::sculk_catalyst::SculkCatalystBlock;
|
|
use crate::block::blocks::sculk::sculk_shrieker::SculkShriekerBlock;
|
|
use crate::block::blocks::sculk::sculk_vein::MultifaceBlock;
|
|
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::smithing_table::SmithingTableBlock;
|
|
use crate::block::blocks::sniffer_egg::SnifferEggBlock;
|
|
use crate::block::blocks::snow::LayeredSnowBlock;
|
|
use crate::block::blocks::soul_sand::SoulSandBlock;
|
|
use crate::block::blocks::spawner::SpawnerBlock;
|
|
use crate::block::blocks::sponge::{SpongeBlock, WetSpongeBlock};
|
|
use crate::block::blocks::stairs::StairBlock;
|
|
use crate::block::blocks::structure_block::StructureBlock;
|
|
use crate::block::blocks::structure_void::StructureVoidBlock;
|
|
use crate::block::blocks::test_block::{TestBlock, TestInstanceBlock};
|
|
use crate::block::blocks::tinted_glass::TintedGlassBlock;
|
|
use crate::block::blocks::tnt::TNTBlock;
|
|
use crate::block::blocks::torches::TorchBlock;
|
|
use crate::block::blocks::trapdoor::TrapDoorBlock;
|
|
use crate::block::blocks::trial_spawner::TrialSpawnerBlock;
|
|
use crate::block::blocks::turtle_egg::TurtleEggBlock;
|
|
use crate::block::blocks::vault::VaultBlock;
|
|
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, BonemealArgs, FluidMetadata,
|
|
GetInsideCollisionShapeArgs, GetScreenHandlerFactoryArgs, OnEntityCollisionArgs,
|
|
OnEntityStepArgs, OnLandedUponArgs, OnProjectileHitArgs, PathComputationType,
|
|
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::BlockStateId;
|
|
use pumpkin_data::block_rotation::{Mirror, Rotation};
|
|
use pumpkin_data::data_component_impl::EquipmentSlot;
|
|
use pumpkin_data::fluid::Fluid;
|
|
use pumpkin_data::item::Item;
|
|
use pumpkin_data::item_stack::ItemStack;
|
|
use pumpkin_data::tag::{self, Taggable};
|
|
use pumpkin_data::{Block, BlockDirection, BlockId, BlockState};
|
|
use pumpkin_inventory::screen_handler::ScreenHandlerFactory;
|
|
use pumpkin_protocol::java::server::play::SUseItemOn;
|
|
use pumpkin_util::math::boundingbox::BoundingBox;
|
|
use pumpkin_util::math::position::BlockPos;
|
|
use pumpkin_util::math::vector3::Vector3;
|
|
use pumpkin_world::world::{BlockAccessor, BlockFlags};
|
|
use rustc_hash::FxHashMap;
|
|
use std::sync::Arc;
|
|
|
|
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::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::respawn_anchor::RespawnAnchorBlock;
|
|
use crate::block::blocks::rooted_dirt::RootedDirtBlock;
|
|
use crate::block::blocks::shulker_box::ShulkerBoxBlock;
|
|
use crate::block::blocks::skull_block::SkullBlock;
|
|
use crate::block::blocks::smoker::SmokerBlock;
|
|
use crate::block::blocks::stonecutter::StonecutterBlock;
|
|
use crate::block::blocks::weathering_copper::{
|
|
WeatheringCopperBlock, WeatheringCopperDoorBlock, WeatheringCopperGrateBlock,
|
|
WeatheringCopperSlabBlock, WeatheringCopperStairBlock, WeatheringCopperTrapDoorBlock,
|
|
};
|
|
|
|
#[must_use]
|
|
#[expect(clippy::too_many_lines)]
|
|
pub fn default_registry() -> Arc<BlockRegistry> {
|
|
let mut manager = BlockRegistry::default();
|
|
|
|
// Blocks
|
|
manager.register(AnvilBlock);
|
|
manager.register(BeaconBlock);
|
|
manager.register(BedBlock);
|
|
manager.register(SaplingBlock);
|
|
manager.register(MangrovePropaguleBlock);
|
|
manager.register(CactusBlock);
|
|
manager.register(ChorusFlowerBlock);
|
|
manager.register(ChorusPlantBlock);
|
|
manager.register(CocoaBlock);
|
|
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(IceBlock);
|
|
manager.register(FrostedIceBlock);
|
|
manager.register(IronBarsBlock);
|
|
manager.register(InfestedBlock);
|
|
manager.register(JukeboxBlock);
|
|
manager.register(LogBlock);
|
|
manager.register(LeavesBlock);
|
|
manager.register(BambooBlock);
|
|
manager.register(BambooSaplingBlock);
|
|
manager.register(BannerBlock);
|
|
manager.register(SignBlock);
|
|
manager.register(SlabBlock);
|
|
manager.register(SlimeBlock);
|
|
manager.register(HoneyBlock);
|
|
manager.register(MudBlock);
|
|
manager.register(SoulSandBlock);
|
|
manager.register(ScaffoldingBlock);
|
|
manager.register(LightBlock);
|
|
manager.register(StructureVoidBlock);
|
|
manager.register(TintedGlassBlock);
|
|
manager.register(StairBlock);
|
|
manager.register(StonecutterBlock);
|
|
manager.register(LoomBlock);
|
|
manager.register(CartographyTableBlock);
|
|
manager.register(SmithingTableBlock);
|
|
manager.register(FletchingTableBlock);
|
|
manager.register(StructureBlock);
|
|
manager.register(TestBlock);
|
|
manager.register(TestInstanceBlock);
|
|
manager.register(ShortPlantBlock);
|
|
manager.register(DryVegetationBlock);
|
|
manager.register(LilyPadBlock);
|
|
manager.register(SugarCaneBlock);
|
|
manager.register(VineBlock);
|
|
manager.register(TNTBlock);
|
|
manager.register(TrialSpawnerBlock);
|
|
manager.register(VaultBlock);
|
|
manager.register(DecoratedPotBlock);
|
|
manager.register(CreakingHeartBlock);
|
|
manager.register(SnifferEggBlock);
|
|
manager.register(TurtleEggBlock);
|
|
manager.register(BrushableBlock);
|
|
manager.register(BushBlock);
|
|
manager.register(FlowerBlock);
|
|
manager.register(EyeblossomBlock);
|
|
manager.register(PotatoBlock);
|
|
manager.register(BeetrootBlock);
|
|
manager.register(TorchFlowerBlock);
|
|
manager.register(PitcherCropBlock);
|
|
manager.register(CaveVinesBlock);
|
|
manager.register(AzaleaBlock);
|
|
manager.register(HangingRootsBlock);
|
|
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);
|
|
|
|
// Weathering copper blocks
|
|
manager.register(WeatheringCopperBlock);
|
|
manager.register(WeatheringCopperDoorBlock);
|
|
manager.register(WeatheringCopperGrateBlock);
|
|
manager.register(WeatheringCopperSlabBlock);
|
|
manager.register(WeatheringCopperStairBlock);
|
|
manager.register(WeatheringCopperTrapDoorBlock);
|
|
manager.register(CommandBlock);
|
|
manager.register(JigsawBlock);
|
|
manager.register(ComposterBlock);
|
|
manager.register(CauldronBlock);
|
|
manager.register(BeehiveBlock);
|
|
manager.register(PressurePlateBlock);
|
|
manager.register(WeightedPressurePlateBlock);
|
|
manager.register(EndGatewayBlock);
|
|
manager.register(EndPortalBlock);
|
|
manager.register(SpawnerBlock);
|
|
manager.register(EndPortalFrameBlock);
|
|
manager.register(RespawnAnchorBlock);
|
|
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(CoralFanBlock);
|
|
manager.register(CoralPlantBlock);
|
|
manager.register(CoralBlock);
|
|
manager.register(AmethystBlock);
|
|
manager.register(BuddingAmethystBlock);
|
|
manager.register(GrassBlock);
|
|
manager.register(RootedDirtBlock);
|
|
manager.register(NyliumBlock);
|
|
manager.register(BubbleColumnBlock);
|
|
|
|
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(LightningRodBlock);
|
|
manager.register(SculkSensorBlock);
|
|
manager.register(MultifaceBlock);
|
|
manager.register(SculkCatalystBlock);
|
|
manager.register(SculkShriekerBlock);
|
|
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(RedstoneOreBlock);
|
|
manager.register(CopperBulbBlock);
|
|
manager.register(RedstoneTorchBlock);
|
|
manager.register(RedstoneWireBlock);
|
|
manager.register(RepeaterBlock);
|
|
manager.register(ComparatorBlock);
|
|
manager.register(CrafterBlock);
|
|
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)
|
|
}
|
|
}
|
|
|
|
pub struct BlockRegistry {
|
|
block_indices: [u8; pumpkin_data::BlockId::COUNT as usize],
|
|
behaviours: Vec<Arc<dyn BlockBehaviour>>,
|
|
fluids: FxHashMap<u16, Arc<dyn FluidBehaviour>>,
|
|
}
|
|
|
|
impl Default for BlockRegistry {
|
|
fn default() -> Self {
|
|
Self {
|
|
block_indices: [0xFF; pumpkin_data::BlockId::COUNT as usize],
|
|
behaviours: Vec::new(),
|
|
fluids: FxHashMap::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum BlockPlacingError {
|
|
InvalidGamemode,
|
|
BlockOutOfWorld,
|
|
}
|
|
|
|
impl BlockRegistry {
|
|
pub fn bone_meal(
|
|
&self,
|
|
block: &Block,
|
|
world: &Arc<World>,
|
|
position: &BlockPos,
|
|
state_id: BlockStateId,
|
|
) -> bool {
|
|
let Some(behaviour) = self.get_pumpkin_block(block.id) else {
|
|
return false;
|
|
};
|
|
let args = BonemealArgs {
|
|
world,
|
|
block,
|
|
position,
|
|
state_id,
|
|
};
|
|
if !behaviour.is_valid_bonemeal_target(args) {
|
|
return false;
|
|
}
|
|
if behaviour.is_bonemeal_success(args) {
|
|
if let Some(server) = world.server.upgrade() {
|
|
let mut event =
|
|
crate::plugin::api::events::block::block_fertilize::BlockFertilizeEvent::new(
|
|
*position,
|
|
world.clone(),
|
|
None,
|
|
vec![],
|
|
);
|
|
server.plugin_manager.fire_blocking(&server, &mut event);
|
|
if event.cancelled {
|
|
return false;
|
|
}
|
|
}
|
|
behaviour.perform_bonemeal(args);
|
|
}
|
|
true
|
|
}
|
|
|
|
fn entity_blocks_block_placement(entity: &dyn EntityBase) -> bool {
|
|
let base_entity = entity.get_entity();
|
|
if base_entity.is_removed()
|
|
|| base_entity
|
|
.no_physics
|
|
.load(std::sync::atomic::Ordering::Relaxed)
|
|
|| entity.is_spectator()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if entity.get_living_entity().is_some() {
|
|
return true;
|
|
}
|
|
|
|
let entity_type = base_entity.entity_type;
|
|
let resource_name = entity_type.resource_name;
|
|
entity_type == &pumpkin_data::entity::EntityType::END_CRYSTAL
|
|
|| entity_type == &pumpkin_data::entity::EntityType::FALLING_BLOCK
|
|
|| entity_type == &pumpkin_data::entity::EntityType::TNT
|
|
|| resource_name.ends_with("_minecart")
|
|
|| resource_name.ends_with("_boat")
|
|
|| resource_name.ends_with("_raft")
|
|
}
|
|
|
|
fn has_blocking_entity_in_box(world: &World, placed_box: &BoundingBox) -> bool {
|
|
let players = world.players.load();
|
|
if players.iter().any(|player| {
|
|
Self::entity_blocks_block_placement(player.as_ref())
|
|
&& player
|
|
.get_entity()
|
|
.bounding_box
|
|
.load()
|
|
.intersects(placed_box)
|
|
}) {
|
|
return true;
|
|
}
|
|
|
|
world.entities.load().iter().any(|entity| {
|
|
Self::entity_blocks_block_placement(entity.as_ref())
|
|
&& entity
|
|
.get_entity()
|
|
.bounding_box
|
|
.load()
|
|
.intersects(placed_box)
|
|
})
|
|
}
|
|
|
|
#[expect(clippy::too_many_lines)]
|
|
pub fn place_block(
|
|
&self,
|
|
player: &Arc<Player>,
|
|
placed_block: &'static Block,
|
|
server: &Arc<Server>,
|
|
use_item_on: &SUseItemOn,
|
|
location: BlockPos,
|
|
face: BlockDirection,
|
|
) -> Result<Option<(BlockPos, BlockStateId)>, BlockPlacingError> {
|
|
let entity = &player.get_entity();
|
|
|
|
match player.gamemode.load() {
|
|
pumpkin_util::GameMode::Spectator | pumpkin_util::GameMode::Adventure => {
|
|
return Err(BlockPlacingError::InvalidGamemode);
|
|
}
|
|
_ => {}
|
|
}
|
|
|
|
let clicked_block_pos = BlockPos(location.0);
|
|
let world = entity.world.load_full();
|
|
|
|
if location.0.y + face.to_offset().y < world.get_bottom_y() {
|
|
return Err(BlockPlacingError::BlockOutOfWorld);
|
|
}
|
|
|
|
if location.0.y + face.to_offset().y > world.get_top_y() {
|
|
player.send_system_message_raw(
|
|
&pumpkin_util::text::TextComponent::translate_cross(
|
|
pumpkin_data::translation::java::BUILD_TOOHIGH,
|
|
pumpkin_data::translation::bedrock::BUILD_TOOHIGH,
|
|
vec![pumpkin_util::text::TextComponent::text(
|
|
(world.get_top_y()).to_string(),
|
|
)],
|
|
)
|
|
.color_named(pumpkin_util::text::color::NamedColor::Red),
|
|
true,
|
|
);
|
|
return Err(BlockPlacingError::BlockOutOfWorld);
|
|
}
|
|
|
|
let (clicked_block, clicked_block_state) = world.get_block_and_state(&clicked_block_pos);
|
|
|
|
let replace_clicked_block = if clicked_block == placed_block {
|
|
self.can_update_at(
|
|
&world,
|
|
clicked_block,
|
|
clicked_block_state.id,
|
|
&clicked_block_pos,
|
|
face,
|
|
use_item_on,
|
|
player,
|
|
)
|
|
.then_some(BlockIsReplacing::Itself(clicked_block_state.id))
|
|
} else if clicked_block_state.replaceable() {
|
|
if clicked_block == &Block::WATER {
|
|
use pumpkin_data::block_properties::WaterLikeProperties;
|
|
let water_props = WaterLikeProperties::from_state_id(clicked_block_state.id);
|
|
Some(BlockIsReplacing::Water(water_props.level))
|
|
} else {
|
|
Some(BlockIsReplacing::Other)
|
|
}
|
|
} else {
|
|
None
|
|
};
|
|
|
|
let (final_block_pos, final_face, replacing) =
|
|
if let Some(replacing) = replace_clicked_block {
|
|
(clicked_block_pos, face.opposite(), replacing)
|
|
} else {
|
|
let block_pos = BlockPos(location.0 + face.to_offset());
|
|
let (previous_block, previous_block_state) = world.get_block_and_state(&block_pos);
|
|
|
|
let replace_previous_block = if previous_block == placed_block {
|
|
self.can_update_at(
|
|
&world,
|
|
previous_block,
|
|
previous_block_state.id,
|
|
&block_pos,
|
|
face.opposite(),
|
|
use_item_on,
|
|
player,
|
|
)
|
|
.then_some(BlockIsReplacing::Itself(previous_block_state.id))
|
|
} else {
|
|
previous_block_state.replaceable().then(|| {
|
|
if previous_block == &Block::WATER {
|
|
use pumpkin_data::block_properties::WaterLikeProperties;
|
|
let water_props =
|
|
WaterLikeProperties::from_state_id(previous_block_state.id);
|
|
BlockIsReplacing::Water(water_props.level)
|
|
} else {
|
|
BlockIsReplacing::None
|
|
}
|
|
})
|
|
};
|
|
|
|
match replace_previous_block {
|
|
Some(replacing) => (block_pos, face.opposite(), replacing),
|
|
None => {
|
|
return Ok(None);
|
|
}
|
|
}
|
|
};
|
|
|
|
if !self.can_place_at(
|
|
Some(server),
|
|
Some(&*world),
|
|
&*world,
|
|
Some(player),
|
|
placed_block,
|
|
placed_block.default_state,
|
|
&final_block_pos,
|
|
Some(final_face),
|
|
Some(use_item_on),
|
|
) {
|
|
return Ok(None);
|
|
}
|
|
|
|
let new_state = self.on_place(
|
|
server,
|
|
&world,
|
|
player,
|
|
placed_block,
|
|
&final_block_pos,
|
|
final_face,
|
|
replacing,
|
|
use_item_on,
|
|
);
|
|
|
|
// Mirror vanilla obstruction checks: only entities that block building should prevent
|
|
// placement. (e.g. arrows/xp orbs/displays/markers should not)
|
|
let state = BlockState::from_id(new_state);
|
|
let mut buildable = true;
|
|
for shape in state.get_block_collision_shapes_at(&final_block_pos) {
|
|
let placed_box = shape.at_pos(final_block_pos);
|
|
|
|
if Self::has_blocking_entity_in_box(world.as_ref(), &placed_box) {
|
|
buildable = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
let mut can_build_event = crate::plugin::block::block_can_build::BlockCanBuildEvent {
|
|
block_to_build: placed_block,
|
|
buildable,
|
|
player: player.clone(),
|
|
block: clicked_block,
|
|
cancelled: false,
|
|
};
|
|
server
|
|
.plugin_manager
|
|
.fire_blocking(server, &mut can_build_event);
|
|
if can_build_event.cancelled || !can_build_event.buildable {
|
|
return Ok(None);
|
|
}
|
|
|
|
let mut event = crate::plugin::block::block_place::BlockPlaceEvent::new(
|
|
player.clone(),
|
|
placed_block,
|
|
clicked_block,
|
|
final_block_pos,
|
|
true,
|
|
);
|
|
server.plugin_manager.fire_blocking(server, &mut event);
|
|
if event.cancelled {
|
|
return Ok(None);
|
|
}
|
|
|
|
let _replaced_id =
|
|
world.set_block_state(&final_block_pos, new_state, BlockFlags::NOTIFY_ALL);
|
|
|
|
self.player_placed(
|
|
&world,
|
|
placed_block,
|
|
new_state,
|
|
&final_block_pos,
|
|
face,
|
|
player,
|
|
);
|
|
|
|
player.trigger_advancement(
|
|
crate::entity::player::advancement::trigger::AdvancementTrigger::PlacedBlock {
|
|
block_id: format!("minecraft:{}", placed_block.name),
|
|
},
|
|
);
|
|
|
|
Ok(Some((final_block_pos, new_state)))
|
|
}
|
|
#[allow(clippy::expect_used)]
|
|
pub fn register<T: BlockBehaviour + BlockMetadata + 'static>(&mut self, block: T) {
|
|
let ids = T::ids();
|
|
let idx = u8::try_from(self.behaviours.len())
|
|
.expect("Too many block behaviours for u8 index table");
|
|
self.behaviours.push(Arc::new(block));
|
|
for i in ids {
|
|
self.block_indices[i.as_u16() as usize] = idx;
|
|
}
|
|
}
|
|
|
|
pub fn register_fluid<T: FluidBehaviour + FluidMetadata + '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 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,
|
|
});
|
|
}
|
|
false
|
|
}
|
|
|
|
pub 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,
|
|
});
|
|
}
|
|
}
|
|
|
|
pub 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,
|
|
});
|
|
}
|
|
}
|
|
|
|
#[allow(clippy::too_many_arguments)]
|
|
pub fn on_projectile_hit(
|
|
&self,
|
|
block: &Block,
|
|
world: &Arc<World>,
|
|
projectile: &dyn EntityBase,
|
|
position: &BlockPos,
|
|
state: &BlockState,
|
|
hit_pos: &Vector3<f64>,
|
|
server: &Server,
|
|
) {
|
|
if let Some(pumpkin_block) = self.get_pumpkin_block(block.id) {
|
|
pumpkin_block.on_projectile_hit(OnProjectileHitArgs {
|
|
server,
|
|
world,
|
|
block,
|
|
state,
|
|
position,
|
|
projectile,
|
|
hit_pos,
|
|
});
|
|
}
|
|
}
|
|
|
|
pub 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);
|
|
}
|
|
}
|
|
|
|
pub 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,
|
|
});
|
|
}
|
|
BlockActionResult::Pass
|
|
}
|
|
|
|
pub fn get_screen_handler_factory(
|
|
&self,
|
|
block: &Block,
|
|
player: &Arc<Player>,
|
|
position: &BlockPos,
|
|
server: &Server,
|
|
world: &Arc<World>,
|
|
) -> Option<Box<dyn ScreenHandlerFactory>> {
|
|
let pumpkin_block = self.get_pumpkin_block(block.id);
|
|
if let Some(pumpkin_block) = pumpkin_block {
|
|
return pumpkin_block.get_screen_handler_factory(GetScreenHandlerFactoryArgs {
|
|
server,
|
|
world,
|
|
block,
|
|
position,
|
|
player,
|
|
});
|
|
}
|
|
None
|
|
}
|
|
|
|
pub 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,
|
|
});
|
|
}
|
|
}
|
|
|
|
#[expect(clippy::too_many_arguments)]
|
|
pub fn use_with_item(
|
|
&self,
|
|
block: &Block,
|
|
player: &Arc<Player>,
|
|
position: &BlockPos,
|
|
hit: &BlockHitResult<'_>,
|
|
item_stack: &mut ItemStack,
|
|
equipment_slot: &EquipmentSlot,
|
|
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,
|
|
equipment_slot,
|
|
});
|
|
}
|
|
BlockActionResult::Pass
|
|
}
|
|
|
|
pub 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);
|
|
}
|
|
BlockActionResult::Pass
|
|
}
|
|
|
|
#[expect(clippy::too_many_arguments)]
|
|
pub 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,
|
|
});
|
|
}
|
|
true
|
|
}
|
|
|
|
#[expect(clippy::too_many_arguments)]
|
|
pub 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,
|
|
});
|
|
}
|
|
false
|
|
}
|
|
|
|
#[expect(clippy::too_many_arguments)]
|
|
pub 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,
|
|
});
|
|
}
|
|
block.default_state.id
|
|
}
|
|
|
|
pub fn player_placed(
|
|
&self,
|
|
world: &Arc<World>,
|
|
block: &Block,
|
|
state_id: BlockStateId,
|
|
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,
|
|
});
|
|
}
|
|
}
|
|
|
|
pub fn on_placed(
|
|
&self,
|
|
world: &Arc<World>,
|
|
block: &Block,
|
|
state_id: BlockStateId,
|
|
position: &BlockPos,
|
|
old_state_id: BlockStateId,
|
|
notify: bool,
|
|
) {
|
|
let state = world.get_block_state(position);
|
|
if state.block_entity_type != u16::MAX
|
|
&& world.get_block_entity(position).is_none()
|
|
&& let Some(entity) =
|
|
crate::block::entities::create_block_entity(state.block_entity_type, *position)
|
|
{
|
|
world.add_block_entity(entity);
|
|
}
|
|
|
|
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,
|
|
});
|
|
}
|
|
}
|
|
|
|
pub 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);
|
|
}
|
|
}
|
|
|
|
pub 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,
|
|
});
|
|
}
|
|
}
|
|
|
|
pub 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 },
|
|
);
|
|
} else {
|
|
stop_vertical_movement_after_fall(entity);
|
|
}
|
|
}
|
|
|
|
pub 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,
|
|
});
|
|
}
|
|
}
|
|
|
|
pub 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,
|
|
});
|
|
}
|
|
}
|
|
|
|
/// Updates state of all neighbors of the block
|
|
pub fn post_process_state(
|
|
&self,
|
|
world: &Arc<World>,
|
|
position: &BlockPos,
|
|
block: &Block,
|
|
flags: BlockFlags,
|
|
) {
|
|
let state_id = world.get_block_state_id(position);
|
|
for direction in BlockDirection::all() {
|
|
let neighbor_pos = position.offset(direction.to_offset());
|
|
let neighbor_state_id = world.get_block_state_id(&neighbor_pos);
|
|
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,
|
|
});
|
|
world.set_block_state(&neighbor_pos, new_state, flags);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub 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,
|
|
});
|
|
}
|
|
}
|
|
|
|
#[expect(clippy::too_many_arguments)]
|
|
pub fn get_state_for_neighbor_update(
|
|
&self,
|
|
world: &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,
|
|
});
|
|
}
|
|
state_id
|
|
}
|
|
|
|
pub fn update_neighbors(&self, world: &Arc<World>, position: &BlockPos, flags: BlockFlags) {
|
|
for direction in BlockDirection::abstract_block_update_order() {
|
|
let pos = position.offset(direction.to_offset());
|
|
|
|
world.replace_with_state_for_neighbor_update(&pos, direction.opposite(), flags);
|
|
}
|
|
}
|
|
|
|
pub 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,
|
|
});
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
#[must_use]
|
|
pub fn get_pumpkin_block(&self, block: BlockId) -> Option<&Arc<dyn BlockBehaviour>> {
|
|
let idx = self.block_indices[block.as_u16() as usize];
|
|
if idx == 0xFF {
|
|
None
|
|
} else {
|
|
self.behaviours.get(idx as usize)
|
|
}
|
|
}
|
|
|
|
#[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,
|
|
}
|
|
})
|
|
}
|
|
|
|
#[must_use]
|
|
pub 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,
|
|
});
|
|
}
|
|
false
|
|
}
|
|
|
|
pub 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,
|
|
});
|
|
}
|
|
0
|
|
}
|
|
|
|
pub 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,
|
|
});
|
|
}
|
|
0
|
|
}
|
|
|
|
pub 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,
|
|
});
|
|
}
|
|
BoundingBox::full_block()
|
|
}
|
|
|
|
#[must_use]
|
|
pub fn mirror(
|
|
&self,
|
|
block: &Block,
|
|
state_id: BlockStateId,
|
|
mirror: Mirror,
|
|
) -> &'static BlockState {
|
|
self.get_pumpkin_block(block.id).map_or_else(
|
|
|| block.mirror(state_id, mirror),
|
|
|pumpkin_block| pumpkin_block.mirror(block, state_id, mirror),
|
|
)
|
|
}
|
|
|
|
#[must_use]
|
|
pub fn rotate(
|
|
&self,
|
|
block: &Block,
|
|
state_id: BlockStateId,
|
|
rotation: Rotation,
|
|
) -> &'static BlockState {
|
|
self.get_pumpkin_block(block.id).map_or_else(
|
|
|| block.rotate(state_id, rotation),
|
|
|pumpkin_block| pumpkin_block.rotate(block, state_id, rotation),
|
|
)
|
|
}
|
|
|
|
#[must_use]
|
|
pub fn is_pathfindable(
|
|
&self,
|
|
block: &Block,
|
|
state: &BlockState,
|
|
computation_type: PathComputationType,
|
|
) -> bool {
|
|
self.get_pumpkin_block(block.id).map_or_else(
|
|
|| match computation_type {
|
|
PathComputationType::Water => {
|
|
state.is_waterlogged()
|
|
|| Fluid::from_state_id(state.id)
|
|
.is_some_and(|f| f.has_tag(&tag::Fluid::MINECRAFT_WATER))
|
|
}
|
|
PathComputationType::Land | PathComputationType::Air => !state.is_full_cube(),
|
|
},
|
|
|pumpkin_block| pumpkin_block.is_pathfindable(state, computation_type),
|
|
)
|
|
}
|
|
}
|