diff --git a/crates/pumpkin-inventory/src/lib.rs b/crates/pumpkin-inventory/src/lib.rs index 9c94bd891..25ca979bd 100644 --- a/crates/pumpkin-inventory/src/lib.rs +++ b/crates/pumpkin-inventory/src/lib.rs @@ -36,6 +36,7 @@ pub mod anvil; pub mod beacon_screen_handler; pub mod brewing; +pub mod cartography_table_screen_handler; pub mod container_click; pub mod crafting; pub mod double; @@ -47,10 +48,12 @@ pub mod furnace_like; pub mod generic_container_screen_handler; pub mod gui_builder; pub mod lectern_screen_handler; +pub mod loom_screen_handler; pub mod merchant; pub mod player; pub mod screen_handler; pub mod slot; +pub mod smithing_table_screen_handler; pub mod stonecutter_screen_handler; pub mod sync_handler; pub mod window_property; diff --git a/crates/pumpkin-inventory/src/loom_screen_handler.rs b/crates/pumpkin-inventory/src/loom_screen_handler.rs new file mode 100644 index 000000000..8bed70524 --- /dev/null +++ b/crates/pumpkin-inventory/src/loom_screen_handler.rs @@ -0,0 +1,113 @@ +use std::any::Any; +use std::sync::Arc; + +use crate::player::player_inventory::PlayerInventory; +use crate::screen_handler::{ + InventoryPlayer, ScreenHandler, ScreenHandlerBehaviour, ScreenHandlerFuture, +}; +use crate::slot::NormalSlot; + +use pumpkin_data::item_stack::ItemStack; +use pumpkin_data::screen::WindowType; +use pumpkin_protocol::java::server::play::SlotActionType; +use pumpkin_world::inventory::Inventory; +use pumpkin_world::inventory::SimpleInventory; + +pub struct LoomScreenHandler { + behaviour: ScreenHandlerBehaviour, + pub input_inventory: Arc, + pub output_inventory: Arc, +} + +impl LoomScreenHandler { + pub fn new(sync_id: u8, player_inventory: &Arc) -> Self { + let behaviour = ScreenHandlerBehaviour::new(sync_id, Some(WindowType::Loom)); + let input_inventory = Arc::new(SimpleInventory::new(3)); + let output_inventory = Arc::new(SimpleInventory::new(1)); + + let mut handler = Self { + behaviour, + input_inventory: input_inventory.clone(), + output_inventory: output_inventory.clone(), + }; + + for i in 0..3 { + handler.add_slot(Arc::new(NormalSlot::new( + input_inventory.clone() as Arc, + i, + ))); + } + handler.add_slot(Arc::new(NormalSlot::new( + output_inventory as Arc, + 0, + ))); + + let player_inventory: Arc = player_inventory.clone(); + handler.add_player_slots(&player_inventory); + + handler + } +} + +impl ScreenHandler for LoomScreenHandler { + fn get_behaviour(&self) -> &ScreenHandlerBehaviour { + &self.behaviour + } + + fn get_behaviour_mut(&mut self) -> &mut ScreenHandlerBehaviour { + &mut self.behaviour + } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } + + fn on_slot_click<'a>( + &'a mut self, + slot_index: i32, + button: i32, + action_type: SlotActionType, + player: &'a dyn InventoryPlayer, + ) -> ScreenHandlerFuture<'a, ()> { + Box::pin(async move { + self.internal_on_slot_click(slot_index, button, action_type, player) + .await; + }) + } + + fn quick_move<'a>( + &'a mut self, + _player: &'a dyn InventoryPlayer, + slot_index: i32, + ) -> ScreenHandlerFuture<'a, ItemStack> { + Box::pin(async move { + let mut stack = ItemStack::EMPTY.clone(); + let slot = self.get_behaviour().slots.get(slot_index as usize).cloned(); + + if let Some(slot) = slot { + let mut slot_stack = slot.get_cloned_stack().await; + if !slot_stack.is_empty() { + stack = slot_stack.clone(); + if slot_index < 4 { + if !self.insert_item(&mut slot_stack, 4, 40, true).await { + return ItemStack::EMPTY.clone(); + } + } else if !self.insert_item(&mut slot_stack, 0, 3, false).await { + return ItemStack::EMPTY.clone(); + } + + if slot_stack.is_empty() { + slot.set_stack(ItemStack::EMPTY.clone()).await; + } else { + slot.set_stack(slot_stack).await; + } + } + } + stack + }) + } +} diff --git a/crates/pumpkin/src/block/blocks/loom.rs b/crates/pumpkin/src/block/blocks/loom.rs new file mode 100644 index 000000000..3ab041f42 --- /dev/null +++ b/crates/pumpkin/src/block/blocks/loom.rs @@ -0,0 +1,80 @@ +use crate::block::registry::BlockActionResult; +use crate::block::{BlockBehaviour, BlockFuture, NormalUseArgs, OnPlaceArgs}; +use crate::entity::EntityBase; + +use pumpkin_data::FacingExt; +use pumpkin_data::block_properties::{BlockProperties, WallTorchLikeProperties}; +use pumpkin_data::translation; +use pumpkin_inventory::loom_screen_handler::LoomScreenHandler; +use pumpkin_inventory::player::player_inventory::PlayerInventory; +use pumpkin_inventory::screen_handler::{ + BoxFuture, InventoryPlayer, ScreenHandlerFactory, SharedScreenHandler, +}; +use pumpkin_macros::pumpkin_block; +use pumpkin_util::text::TextComponent; +use std::sync::Arc; +use tokio::sync::Mutex; + +#[pumpkin_block("minecraft:loom")] +pub struct LoomBlock; + +impl BlockBehaviour for LoomBlock { + fn on_place<'a>( + &'a self, + args: OnPlaceArgs<'a>, + ) -> BlockFuture<'a, pumpkin_data::BlockStateId> { + Box::pin(async move { + let mut props = WallTorchLikeProperties::default(args.block); + if let Some(facing) = args + .player + .get_entity() + .get_facing() + .opposite() + .to_horizontal_facing() + { + props.facing = facing; + } + props.to_state_id(args.block) + }) + } + + fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> { + Box::pin(async move { + args.player + .increment_stat( + pumpkin_data::statistic::StatisticCategory::Custom, + pumpkin_data::statistic::CustomStatistic::InteractWithLoom as i32, + 1, + ) + .await; + args.player + .open_handled_screen(&LoomScreenFactory, Some(*args.position)) + .await; + + BlockActionResult::Success + }) + } +} + +struct LoomScreenFactory; + +impl ScreenHandlerFactory for LoomScreenFactory { + fn create_screen_handler<'a>( + &'a self, + sync_id: u8, + player_inventory: &'a Arc, + _player: &'a dyn InventoryPlayer, + ) -> BoxFuture<'a, Option> { + Box::pin(async move { + let handler: SharedScreenHandler = Arc::new(Mutex::new(LoomScreenHandler::new( + sync_id, + player_inventory, + ))); + Some(handler) + }) + } + + fn get_display_name(&self) -> TextComponent { + TextComponent::translate(translation::java::CONTAINER_LOOM, []) + } +} diff --git a/crates/pumpkin/src/block/blocks/mod.rs b/crates/pumpkin/src/block/blocks/mod.rs index b19767029..883223bfa 100644 --- a/crates/pumpkin/src/block/blocks/mod.rs +++ b/crates/pumpkin/src/block/blocks/mod.rs @@ -113,6 +113,7 @@ pub mod beacon; pub mod brushable_block; pub mod creaking_heart; pub mod decorated_pot; +pub mod loom; pub mod sniffer_egg; pub mod trial_spawner; pub mod turtle_egg; diff --git a/crates/pumpkin/src/block/registry.rs b/crates/pumpkin/src/block/registry.rs index 9f41da9ab..93b504de8 100644 --- a/crates/pumpkin/src/block/registry.rs +++ b/crates/pumpkin/src/block/registry.rs @@ -48,6 +48,7 @@ use crate::block::blocks::infested::InfestedBlock; use crate::block::blocks::iron_bars::IronBarsBlock; use crate::block::blocks::jigsaw::JigsawBlock; 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::nether_portal::NetherPortalBlock; @@ -128,6 +129,7 @@ use crate::block::blocks::sculk::sculk_vein::SculkVeinBlock; 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::sniffer_egg::SnifferEggBlock; use crate::block::blocks::snow::LayeredSnowBlock; use crate::block::blocks::spawner::SpawnerBlock; @@ -248,6 +250,7 @@ pub fn default_registry() -> Arc { manager.register(SlimeBlock); manager.register(StairBlock); manager.register(StonecutterBlock); + manager.register(LoomBlock); manager.register(ShortPlantBlock); manager.register(DryVegetationBlock); manager.register(LilyPadBlock);