137 lines
4.4 KiB
Rust
137 lines
4.4 KiB
Rust
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<PlayerInventory>,
|
|
inventory: Arc<dyn Inventory>,
|
|
) -> 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<dyn Inventory>,
|
|
/// 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<PlayerInventory>,
|
|
inventory: Arc<dyn Inventory>,
|
|
) -> 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<dyn Inventory> = 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
|
|
})
|
|
}
|
|
}
|