use std::sync::Arc; use std::sync::Mutex; use crate::block::{ GetComparatorOutputArgs, GetScreenHandlerFactoryArgs, OnPlaceArgs, OnSyncedBlockEventArgs, PlacedArgs, }; use crate::block::{ registry::BlockActionResult, {BlockBehaviour, NormalUseArgs}, }; use crate::block::entities::shulker_box::ShulkerBoxBlockEntity; use pumpkin_data::BlockStateId; use pumpkin_data::translation; use pumpkin_inventory::generic_container_screen_handler::create_generic_9x3; use pumpkin_inventory::player::player_inventory::PlayerInventory; use pumpkin_inventory::screen_handler::{ InventoryPlayer, ScreenHandlerFactory, SharedScreenHandler, }; use pumpkin_macros::pumpkin_block_from_tag; use pumpkin_util::text::TextComponent; use pumpkin_world::inventory::Inventory; struct ShulkerBoxScreenFactory(Arc); impl ScreenHandlerFactory for ShulkerBoxScreenFactory { fn create_screen_handler( &self, sync_id: u8, player_inventory: &Arc, player: &dyn InventoryPlayer, ) -> Option { let handler = create_generic_9x3(sync_id, player_inventory, self.0.clone(), player); let screen_handler_arc = Arc::new(Mutex::new(handler)); Some(screen_handler_arc as SharedScreenHandler) } fn get_display_name(&self) -> TextComponent { pumpkin_macros::translate_cross!( translation::java::CONTAINER_SHULKERBOX, translation::bedrock::CONTAINER_SHULKERBOX ) } } #[pumpkin_block_from_tag("minecraft:shulker_boxes")] pub struct ShulkerBoxBlock; type EndRodLikeProperties = pumpkin_data::block_properties::EndRodLikeProperties; impl BlockBehaviour for ShulkerBoxBlock { fn on_place(&self, args: OnPlaceArgs<'_>) -> BlockStateId { let mut props = EndRodLikeProperties::default(args.block); props.facing = args.direction.to_facing().opposite(); props.to_state_id(args.block) } fn on_synced_block_event(&self, args: OnSyncedBlockEventArgs<'_>) -> bool { // On the server, we don't need the Animation steps for now, because the client is responsible for that. // TODO: Do not open the shulker box when it is currently closing args.r#type == Self::OPEN_ANIMATION_EVENT_TYPE } fn placed(&self, args: PlacedArgs<'_>) { { let barrel_block_entity = ShulkerBoxBlockEntity::new(*args.position); args.world.add_block_entity(Arc::new(barrel_block_entity)); } } fn normal_use(&self, args: NormalUseArgs<'_>) -> BlockActionResult { if let Some(factory) = self.get_screen_handler_factory(GetScreenHandlerFactoryArgs { server: args.server, world: args.world, block: args.block, position: args.position, player: args.player, }) { args.player.increment_stat( pumpkin_data::statistic::StatisticCategory::Custom, pumpkin_data::statistic::CustomStatistic::OpenShulkerBox as i32, 1, ); args.player .open_handled_screen(factory.as_ref(), Some(*args.position)); } BlockActionResult::Success } fn get_screen_handler_factory( &self, args: GetScreenHandlerFactoryArgs<'_>, ) -> Option> { let block_entity = args.world.get_block_entity(args.position)?; let inventory = block_entity.get_inventory()?; Some(Box::new(ShulkerBoxScreenFactory(inventory))) } fn get_comparator_output(&self, args: GetComparatorOutputArgs<'_>) -> Option { if let Some(block_entity) = args.world.get_block_entity(args.position) && let Some(inventory) = block_entity.get_inventory() { Some(crate::block::calculate_comparator_output( inventory.as_ref(), )) } else { None } } } impl ShulkerBoxBlock { pub const OPEN_ANIMATION_EVENT_TYPE: u8 = 1; }