From 2bffaee1bfea7d5c9fcfd4f69648497a34f09cd6 Mon Sep 17 00:00:00 2001 From: Alexander Medvedev Date: Wed, 12 Aug 2026 21:04:31 +0200 Subject: [PATCH] feat(block): implement smithing table block --- .../src/smithing_table_screen_handler.rs | 113 ++++++++++++++++++ crates/pumpkin/src/block/blocks/mod.rs | 1 + .../src/block/blocks/smithing_table.rs | 57 +++++++++ crates/pumpkin/src/block/registry.rs | 2 + 4 files changed, 173 insertions(+) create mode 100644 crates/pumpkin-inventory/src/smithing_table_screen_handler.rs create mode 100644 crates/pumpkin/src/block/blocks/smithing_table.rs diff --git a/crates/pumpkin-inventory/src/smithing_table_screen_handler.rs b/crates/pumpkin-inventory/src/smithing_table_screen_handler.rs new file mode 100644 index 000000000..f83c55f90 --- /dev/null +++ b/crates/pumpkin-inventory/src/smithing_table_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 SmithingTableScreenHandler { + behaviour: ScreenHandlerBehaviour, + pub input_inventory: Arc, + pub output_inventory: Arc, +} + +impl SmithingTableScreenHandler { + pub fn new(sync_id: u8, player_inventory: &Arc) -> Self { + let behaviour = ScreenHandlerBehaviour::new(sync_id, Some(WindowType::Smithing)); + 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 SmithingTableScreenHandler { + 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/mod.rs b/crates/pumpkin/src/block/blocks/mod.rs index 27496580d..a4905e603 100644 --- a/crates/pumpkin/src/block/blocks/mod.rs +++ b/crates/pumpkin/src/block/blocks/mod.rs @@ -115,6 +115,7 @@ pub mod cartography_table; pub mod creaking_heart; pub mod decorated_pot; pub mod loom; +pub mod smithing_table; pub mod sniffer_egg; pub mod trial_spawner; pub mod turtle_egg; diff --git a/crates/pumpkin/src/block/blocks/smithing_table.rs b/crates/pumpkin/src/block/blocks/smithing_table.rs new file mode 100644 index 000000000..8b1ebde3e --- /dev/null +++ b/crates/pumpkin/src/block/blocks/smithing_table.rs @@ -0,0 +1,57 @@ +use crate::block::registry::BlockActionResult; +use crate::block::{BlockBehaviour, BlockFuture, NormalUseArgs}; + +use pumpkin_data::translation; +use pumpkin_inventory::player::player_inventory::PlayerInventory; +use pumpkin_inventory::screen_handler::{ + BoxFuture, InventoryPlayer, ScreenHandlerFactory, SharedScreenHandler, +}; +use pumpkin_inventory::smithing_table_screen_handler::SmithingTableScreenHandler; +use pumpkin_macros::pumpkin_block; +use pumpkin_util::text::TextComponent; +use std::sync::Arc; +use tokio::sync::Mutex; + +#[pumpkin_block("minecraft:smithing_table")] +pub struct SmithingTableBlock; + +impl BlockBehaviour for SmithingTableBlock { + 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::InteractWithSmithingTable as i32, + 1, + ) + .await; + args.player + .open_handled_screen(&SmithingTableScreenFactory, Some(*args.position)) + .await; + + BlockActionResult::Success + }) + } +} + +struct SmithingTableScreenFactory; + +impl ScreenHandlerFactory for SmithingTableScreenFactory { + 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( + SmithingTableScreenHandler::new(sync_id, player_inventory), + )); + Some(handler) + }) + } + + fn get_display_name(&self) -> TextComponent { + TextComponent::translate(translation::java::CONTAINER_UPGRADE, []) + } +} diff --git a/crates/pumpkin/src/block/registry.rs b/crates/pumpkin/src/block/registry.rs index ef70843a3..13a192ebe 100644 --- a/crates/pumpkin/src/block/registry.rs +++ b/crates/pumpkin/src/block/registry.rs @@ -131,6 +131,7 @@ 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::spawner::SpawnerBlock; @@ -253,6 +254,7 @@ pub fn default_registry() -> Arc { manager.register(StonecutterBlock); manager.register(LoomBlock); manager.register(CartographyTableBlock); + manager.register(SmithingTableBlock); manager.register(ShortPlantBlock); manager.register(DryVegetationBlock); manager.register(LilyPadBlock);