use std::{any::Any, sync::Arc}; use pumpkin_data::{item_stack::ItemStack, screen::WindowType}; use pumpkin_world::inventory::Inventory; use crate::{ player::player_inventory::PlayerInventory, screen_handler::{ InventoryPlayer, ItemStackFuture, ScreenHandler, ScreenHandlerBehaviour, ScreenHandlerFuture, }, slot::NormalSlot, }; /// Creates a beacon container screen handler. /// /// Beacons feature a single payment slot and a specialized UI for selecting status effects. pub async fn create_beacon_handler( sync_id: u8, player_inventory: &Arc, inventory: Arc, ) -> BeaconScreenHandler { BeaconScreenHandler::new(sync_id, player_inventory, inventory).await } /// Screen handler specifically for Beacon blocks. pub struct BeaconScreenHandler { /// The beacon's inventory (contains exactly 1 slot for payment). pub inventory: Arc, /// Core screen handler behavior (slots, sync ID, listeners). behaviour: ScreenHandlerBehaviour, } impl BeaconScreenHandler { /// Creates a new beacon screen handler. async fn new( sync_id: u8, player_inventory: &Arc, inventory: Arc, ) -> Self { let mut handler = Self { inventory: inventory.clone(), behaviour: ScreenHandlerBehaviour::new(sync_id, Some(WindowType::Beacon)), }; inventory.on_open().await; // Add the single payment slot for the beacon (slot 0) handler.add_slot(Arc::new(NormalSlot::new(handler.inventory.clone(), 0))); // Add the player's inventory slots (27 slots + 9 hotbar) let player_inventory_arc: Arc = player_inventory.clone(); handler.add_player_slots(&player_inventory_arc); handler } } impl ScreenHandler for BeaconScreenHandler { fn as_any(&self) -> &dyn Any { self } fn as_any_mut(&mut self) -> &mut dyn Any { self } fn get_behaviour(&self) -> &ScreenHandlerBehaviour { &self.behaviour } fn get_behaviour_mut(&mut self) -> &mut ScreenHandlerBehaviour { &mut self.behaviour } fn on_closed<'a>(&'a mut self, player: &'a dyn InventoryPlayer) -> ScreenHandlerFuture<'a, ()> { Box::pin(async move { self.default_on_closed(player).await; self.inventory.on_close().await; }) } /// Quick move logic specifically for the beacon UI. /// /// - From beacon payment slot (0): Move to player inventory /// - From player inventory (1+): Move to beacon payment slot fn quick_move<'a>( &'a mut self, _player: &'a dyn InventoryPlayer, slot_index: i32, ) -> ItemStackFuture<'a> { Box::pin(async move { let mut stack_left = ItemStack::EMPTY.clone(); let slot = self.get_behaviour().slots[slot_index as usize].clone(); if slot.has_stack().await { let slot_stack_lock = slot.get_stack().await; let slot_stack_guard = slot_stack_lock.lock().await; stack_left = slot_stack_guard.clone(); drop(slot_stack_guard); let mut slot_stack_mut = slot_stack_lock.lock().await; if slot_index == 0 { // Move from the single beacon slot to the player inventory (slots 1 to end) if !self .insert_item( &mut slot_stack_mut, 1, self.get_behaviour().slots.len() as i32, true, ) .await { return ItemStack::EMPTY.clone(); } } else { // Move from player inventory into the beacon payment slot (slot 0) if !self.insert_item(&mut slot_stack_mut, 0, 1, false).await { return ItemStack::EMPTY.clone(); } } if slot_stack_mut.is_empty() { drop(slot_stack_mut); slot.set_stack(ItemStack::EMPTY.clone()).await; } else { drop(slot_stack_mut); slot.mark_dirty().await; } } stack_left }) } }