From bb6677dd19163b73015a3bb3552af301457f2130 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Thu, 5 Sep 2024 14:54:28 +0200 Subject: [PATCH] add drag and error handling for containers --- Cargo.lock | 2 + pumpkin-inventory/Cargo.toml | 3 +- pumpkin-inventory/src/container_click.rs | 73 ++-------- pumpkin-inventory/src/drag_handler.rs | 178 +++++++++++++++++++++++ pumpkin-inventory/src/error.rs | 33 +++++ pumpkin-inventory/src/lib.rs | 18 ++- pumpkin-inventory/src/open_container.rs | 16 +- pumpkin-inventory/src/player.rs | 25 ++-- pumpkin-world/src/item/mod.rs | 6 + pumpkin/src/client/container.rs | 137 +++++++++++------ pumpkin/src/server.rs | 10 +- 11 files changed, 367 insertions(+), 134 deletions(-) create mode 100644 pumpkin-inventory/src/drag_handler.rs create mode 100644 pumpkin-inventory/src/error.rs diff --git a/Cargo.lock b/Cargo.lock index fd53bd141..40d338ca4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1967,9 +1967,11 @@ dependencies = [ name = "pumpkin-inventory" version = "0.1.0" dependencies = [ + "itertools 0.13.0", "num-derive", "num-traits", "pumpkin-world", + "thiserror", ] [[package]] diff --git a/pumpkin-inventory/Cargo.toml b/pumpkin-inventory/Cargo.toml index 83f80a194..ccbb61f69 100644 --- a/pumpkin-inventory/Cargo.toml +++ b/pumpkin-inventory/Cargo.toml @@ -6,6 +6,7 @@ edition.workspace = true [dependencies] num-traits = "0.2" num-derive = "0.4" - +thiserror = "1.0.63" +itertools = "0.13.0" # For items pumpkin-world = { path = "../pumpkin-world"} diff --git a/pumpkin-inventory/src/container_click.rs b/pumpkin-inventory/src/container_click.rs index 2e739d12a..cd5559dcb 100644 --- a/pumpkin-inventory/src/container_click.rs +++ b/pumpkin-inventory/src/container_click.rs @@ -83,63 +83,21 @@ impl Click { } fn new_drag_item(button: i8, slot: i16) -> Self { - let (mouse_type, state, slot) = match button { - 0 => ( - MouseDragType::Left, - MouseDragState::Start, - Slot::OutsideInventory, - ), - 1 => ( - MouseDragType::Left, - MouseDragState::AddSlot, - Slot::Normal(slot.try_into().unwrap()), - ), - 2 => ( - MouseDragType::Left, - MouseDragState::End, - Slot::OutsideInventory, - ), - 4 => ( - MouseDragType::Right, - MouseDragState::Start, - Slot::OutsideInventory, - ), - 5 => ( - MouseDragType::Right, - MouseDragState::AddSlot, - Slot::Normal(slot.try_into().unwrap()), - ), - 6 => ( - MouseDragType::Right, - MouseDragState::End, - Slot::OutsideInventory, - ), - - // ONLY FOR CREATIVE - 8 => ( - MouseDragType::Middle, - MouseDragState::Start, - Slot::OutsideInventory, - ), - 9 => ( - MouseDragType::Middle, - MouseDragState::AddSlot, - Slot::Normal(slot.try_into().unwrap()), - ), - 10 => ( - MouseDragType::Middle, - MouseDragState::End, - Slot::OutsideInventory, - ), + let state = match button { + 0 => MouseDragState::Start(MouseDragType::Left), + 4 => MouseDragState::Start(MouseDragType::Right), + 8 => MouseDragState::Start(MouseDragType::Middle), + 1 | 5 | 9 => MouseDragState::AddSlot(slot.try_into().unwrap()), + 2 | 6 | 10 => MouseDragState::End, // TODO: Error handling _ => unreachable!(), }; Self { - click_type: ClickType::MouseDrag { - drag_state: state, - drag_type: mouse_type, + slot: match &state { + MouseDragState::AddSlot(slot) => Slot::Normal(*slot), + _ => Slot::OutsideInventory, }, - slot, + click_type: ClickType::MouseDrag { drag_state: state }, } } } @@ -150,10 +108,7 @@ pub enum ClickType { KeyClick(KeyClick), CreativePickItem, DropType(DropType), - MouseDrag { - drag_state: MouseDragState, - drag_type: MouseDragType, - }, + MouseDrag { drag_state: MouseDragState }, DoubleClick, } #[derive(Debug, PartialEq, Eq)] @@ -176,7 +131,7 @@ pub enum DropType { SingleItem, FullStack, } - +#[derive(Debug)] pub enum MouseDragType { Left, Right, @@ -184,8 +139,8 @@ pub enum MouseDragType { } pub enum MouseDragState { - Start, - AddSlot, + Start(MouseDragType), + AddSlot(usize), End, } diff --git a/pumpkin-inventory/src/drag_handler.rs b/pumpkin-inventory/src/drag_handler.rs new file mode 100644 index 000000000..8ac7198fc --- /dev/null +++ b/pumpkin-inventory/src/drag_handler.rs @@ -0,0 +1,178 @@ +use crate::container_click::MouseDragType; +use crate::{Container, InventoryError}; +use itertools::Itertools; +use num_traits::Euclid; +use pumpkin_world::item::ItemStack; +use std::collections::HashMap; +use std::iter::{Enumerate, Filter, TakeWhile}; +use std::sync::{Arc, Mutex, RwLock}; +use std::vec::IntoIter; +#[derive(Debug, Default)] +pub struct DragHandler(RwLock>>>); + +impl DragHandler { + pub fn new() -> Self { + Self(RwLock::new(HashMap::new())) + } + pub fn new_drag( + &self, + container_id: u64, + player: i32, + drag_type: MouseDragType, + ) -> Result<(), InventoryError> { + let drag = Drag { + player, + drag_type, + slots: vec![], + }; + let mut drags = match self.0.write() { + Ok(drags) => drags, + Err(_) => Err(InventoryError::LockError)?, + }; + drags.insert(container_id, Arc::new(Mutex::new(drag))); + Ok(()) + } + + pub fn add_slot( + &self, + container_id: u64, + player: i32, + slot: usize, + ) -> Result<(), InventoryError> { + let drags = match self.0.read() { + Ok(drags) => drags, + Err(_) => Err(InventoryError::LockError)?, + }; + match drags.get(&container_id) { + Some(drag) => { + let mut drag = drag.lock().unwrap(); + if drag.player != player { + Err(InventoryError::MultiplePlayersDragging)? + } + if !drag.slots.contains(&slot) { + drag.slots.push(slot); + } + } + None => Err(InventoryError::OutOfOrderDragging)?, + } + Ok(()) + } + + pub fn apply_drag( + &self, + carried_item: &mut Option, + container: &mut T, + container_id: &u64, + player: i32, + ) -> Result<(), InventoryError> { + // Minecraft client does still send dragging packets when not carrying an item! + if carried_item.is_none() { + return Ok(()); + } + + let Ok(mut drags) = self.0.write() else { + Err(InventoryError::LockError)? + }; + let Some((_, drag)) = drags.remove_entry(container_id) else { + Err(InventoryError::OutOfOrderDragging)? + }; + let mut drag = drag.lock().unwrap(); + + if player != drag.player { + Err(InventoryError::MultiplePlayersDragging)? + } + let mut slots = container.all_slots(); + let slots_cloned = slots + .iter() + .map(|stack| stack.map(|item| item.to_owned())) + .collect_vec(); + match drag.drag_type { + // This is only valid in Creative GameMode. + // Checked in any function that uses this function. + MouseDragType::Middle => { + for slot in &drag.slots { + *slots[*slot] = carried_item.clone(); + } + } + MouseDragType::Right => { + let amount_of_items = carried_item.unwrap().item_count as usize; + let mut single_item = carried_item.clone().unwrap(); + single_item.item_count = 1; + let changing_slots = drag.changing_slots( + amount_of_items, + &slots_cloned, + carried_item.as_ref().unwrap(), + ); + let mut amount_removed = 0; + changing_slots.for_each(|slot| { + amount_removed += 1; + *slots[slot] = Some(single_item.clone()) + }); + + let mut remaining = carried_item.unwrap(); + if remaining.item_count == amount_removed { + *carried_item = None + } else { + remaining.item_count -= amount_removed; + *carried_item = Some(remaining) + } + } + MouseDragType::Left => { + let amount_of_items = carried_item.unwrap().item_count as usize; + // TODO: Handle dragging a stack with greater amount than item allows as max unstackable + // In that specific case, follow MouseDragType::Right behaviours instead! + + let changing_slots = drag.changing_slots( + amount_of_items, + &slots_cloned, + carried_item.as_ref().unwrap(), + ); + let amount_of_slots = changing_slots.clone().count(); + let (amount_per_slot, remainder) = + (carried_item.unwrap().item_count as usize).div_rem_euclid(&amount_of_slots); + let mut item_in_each_slot = carried_item.unwrap().clone(); + item_in_each_slot.item_count = amount_per_slot as u8; + changing_slots.for_each(|slot| *slots[slot] = Some(item_in_each_slot.clone())); + + if remainder > 0 { + let mut remaining = carried_item.unwrap().clone(); + remaining.item_count = remainder as u8; + *carried_item = Some(remaining) + } else { + *carried_item = None + } + } + } + Ok(()) + } +} +#[derive(Debug)] +struct Drag { + player: i32, + drag_type: MouseDragType, + slots: Vec, +} + +impl Drag { + fn changing_slots<'a>( + &'a self, + amount_of_items: usize, + slots: &'a [Option], + carried_item: &'a ItemStack, + ) -> impl Iterator + 'a + Clone { + self.slots + .iter() + .enumerate() + .take_while(move |(slot_number, _)| *slot_number <= amount_of_items) + .filter_map(move |(_, slot)| match &slots[*slot] { + Some(item_slot) => { + if *item_slot == *carried_item { + Some(*slot) + } else { + None + } + } + None => Some(*slot), + }) + } +} diff --git a/pumpkin-inventory/src/error.rs b/pumpkin-inventory/src/error.rs new file mode 100644 index 000000000..e74ece87e --- /dev/null +++ b/pumpkin-inventory/src/error.rs @@ -0,0 +1,33 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum InventoryError { + #[error("Unable to lock")] + LockError, + #[error("Invalid slot")] + InvalidSlot, + #[error("Player '{0}' tried to interact with a closed container")] + ClosedContainerInteract(i32), + #[error("Multiple players dragging in a container at once")] + MultiplePlayersDragging, + #[error("Out of order dragging")] + OutOfOrderDragging, + #[error("Invalid inventory packet")] + InvalidPacket, + #[error("Player does not have enough permissions")] + PermissionError, +} + +impl InventoryError { + pub fn should_kick(&self) -> bool { + match self { + InventoryError::InvalidSlot + | InventoryError::ClosedContainerInteract(..) + | InventoryError::InvalidPacket + | InventoryError::PermissionError => true, + InventoryError::LockError + | InventoryError::OutOfOrderDragging + | InventoryError::MultiplePlayersDragging => false, + } + } +} diff --git a/pumpkin-inventory/src/lib.rs b/pumpkin-inventory/src/lib.rs index 654d2352e..e90884da8 100644 --- a/pumpkin-inventory/src/lib.rs +++ b/pumpkin-inventory/src/lib.rs @@ -1,13 +1,16 @@ -use crate::container_click::MouseClick; +use crate::container_click::{MouseClick, MouseDragState, MouseDragType}; use crate::player::PlayerInventory; use num_derive::{FromPrimitive, ToPrimitive}; use pumpkin_world::item::ItemStack; pub mod container_click; +pub mod drag_handler; +mod error; mod open_container; pub mod player; pub mod window_property; +pub use error::InventoryError; pub use open_container::OpenContainer; /// https://wiki.vg/Inventory @@ -68,8 +71,13 @@ pub trait Container: Sync + Send { carried_item: &mut Option, slot: usize, mouse_click: MouseClick, - ) { - handle_item_change(carried_item, self.all_slots()[slot], mouse_click) + ) -> Result<(), InventoryError> { + let mut all_slots = self.all_slots(); + if slot < all_slots.len() { + Err(InventoryError::InvalidSlot)? + } + handle_item_change(carried_item, all_slots[slot], mouse_click); + Ok(()) } fn all_slots(&mut self) -> Vec<&mut Option>; @@ -98,6 +106,10 @@ pub trait Container: Sync + Send { dbg!(slot, item); }); } + + fn internal_pumpkin_id(&self) -> u64 { + 0 + } } pub fn handle_item_take( diff --git a/pumpkin-inventory/src/open_container.rs b/pumpkin-inventory/src/open_container.rs index 601262384..3789575c7 100644 --- a/pumpkin-inventory/src/open_container.rs +++ b/pumpkin-inventory/src/open_container.rs @@ -1,6 +1,7 @@ +use crate::drag_handler::DragHandler; use crate::{Container, WindowType}; use pumpkin_world::item::ItemStack; -use std::sync::{Mutex, MutexGuard}; +use std::sync::{Arc, Mutex}; pub struct OpenContainer { players: Vec, @@ -8,21 +9,12 @@ pub struct OpenContainer { } impl OpenContainer { - pub fn try_open(&self, player_id: i32) -> Option>> { + pub fn try_open(&self, player_id: i32) -> Option<&Mutex>> { if !self.players.contains(&player_id) { dbg!("couldn't open container"); return None; } - let container = self.container.lock().unwrap(); - container - .all_slots_ref() - .iter() - .enumerate() - .for_each(|(slot, item)| { - if let Some(item) = item { - dbg!(slot, item); - } - }); + let container = &self.container; Some(container) } diff --git a/pumpkin-inventory/src/player.rs b/pumpkin-inventory/src/player.rs index 355fea173..96e7a8907 100644 --- a/pumpkin-inventory/src/player.rs +++ b/pumpkin-inventory/src/player.rs @@ -1,5 +1,6 @@ use crate::container_click::MouseClick; -use crate::{handle_item_change, Container, WindowType}; +use crate::drag_handler::DragHandler; +use crate::{handle_item_change, Container, InventoryError, WindowType}; use pumpkin_world::item::ItemStack; #[allow(dead_code)] @@ -92,17 +93,17 @@ impl PlayerInventory { _ => unreachable!(), } } - pub fn get_slot(&mut self, slot: usize) -> &mut Option { + pub fn get_slot(&mut self, slot: usize) -> Result<&mut Option, InventoryError> { match slot { 0 => { // TODO: Add crafting check here - &mut self.crafting_output + Ok(&mut self.crafting_output) } - 1..=4 => &mut self.crafting[slot - 1], - 5..=8 => &mut self.armor[slot - 5], - 9..=44 => &mut self.items[slot - 9], - 45 => &mut self.offhand, - _ => unreachable!(), + 1..=4 => Ok(&mut self.crafting[slot - 1]), + 5..=8 => Ok(&mut self.armor[slot - 5]), + 9..=44 => Ok(&mut self.items[slot - 9]), + 45 => Ok(&mut self.offhand), + _ => Err(InventoryError::InvalidSlot), } } pub fn set_selected(&mut self, slot: usize) { @@ -144,9 +145,11 @@ impl Container for PlayerInventory { carried_slot: &mut Option, slot: usize, mouse_click: MouseClick, - ) { - let item_slot = self.get_slot(slot); - handle_item_change(carried_slot, item_slot, mouse_click) + ) -> Result<(), InventoryError> { + let item_slot = self.get_slot(slot)?; + + handle_item_change(carried_slot, item_slot, mouse_click); + Ok(()) } fn all_slots(&mut self) -> Vec<&mut Option> { diff --git a/pumpkin-world/src/item/mod.rs b/pumpkin-world/src/item/mod.rs index 5f5a588d3..8625a9023 100644 --- a/pumpkin-world/src/item/mod.rs +++ b/pumpkin-world/src/item/mod.rs @@ -18,3 +18,9 @@ pub struct ItemStack { pub item_id: u32, // TODO: Add Item Components } + +impl PartialEq for ItemStack { + fn eq(&self, other: &Self) -> bool { + self.item_id == other.item_id + } +} diff --git a/pumpkin/src/client/container.rs b/pumpkin/src/client/container.rs index d681c9676..d34fa9982 100644 --- a/pumpkin/src/client/container.rs +++ b/pumpkin/src/client/container.rs @@ -1,8 +1,12 @@ +use crate::entity::player::Player; +use crate::server::Server; use itertools::Itertools; use pumpkin_core::text::TextComponent; -use pumpkin_inventory::container_click::{KeyClick, MouseClick}; +use pumpkin_core::GameMode; +use pumpkin_inventory::container_click::{KeyClick, MouseClick, MouseDragState, MouseDragType}; +use pumpkin_inventory::drag_handler::DragHandler; use pumpkin_inventory::window_property::{WindowProperty, WindowPropertyTrait}; -use pumpkin_inventory::{container_click, OptionallyCombinedContainer}; +use pumpkin_inventory::{container_click, InventoryError, OptionallyCombinedContainer}; use pumpkin_inventory::{Container, WindowType}; use pumpkin_protocol::client::play::{ CCloseContainer, COpenScreen, CSetContainerContent, CSetContainerProperty, CSetContainerSlot, @@ -10,10 +14,7 @@ use pumpkin_protocol::client::play::{ use pumpkin_protocol::server::play::SClickContainer; use pumpkin_protocol::slot::Slot; use pumpkin_world::item::ItemStack; -use std::sync::MutexGuard; - -use crate::entity::player::Player; -use crate::server::Server; +use std::sync::{Arc, Mutex, MutexGuard}; impl Player { pub fn open_container( @@ -22,8 +23,11 @@ impl Player { minecraft_menu_id: &str, window_title: Option<&str>, ) { - let mut container = self.get_open_container(server); - let container = container.as_deref_mut(); + self.inventory.reset_state_id(); + let total_opened_containers = self.inventory.total_opened_containers; + let mut container = self + .get_open_container(server) + .map(|container| container.lock().unwrap()); let menu_protocol_id = (*pumpkin_world::global_registry::REGISTRY .get("minecraft:menu") .unwrap() @@ -40,14 +44,12 @@ impl Player { .to_owned(); let title = TextComponent::text(window_title.unwrap_or(window_type.default_title())); - self.inventory.reset_state_id(); - self.client.send_packet(&COpenScreen::new( - self.inventory.total_opened_containers.into(), + total_opened_containers.into(), menu_protocol_id, title, )); - self.set_container_content(container); + self.set_container_content(container.as_deref_mut()); } pub fn set_container_content(&mut self, container: Option<&mut Box>) { @@ -113,33 +115,35 @@ impl Player { )); } - pub fn handle_click_container(&mut self, server: &mut Server, packet: SClickContainer) { + pub fn handle_click_container( + &mut self, + server: &mut Server, + packet: SClickContainer, + ) -> Result<(), InventoryError> { use container_click::*; - let mut opened_container = self.get_open_container(server); - let opened_container = opened_container.as_deref_mut(); + let mut opened_container = self + .get_open_container(server) + .map(|container| container.lock().unwrap()); + let mut opened_container = opened_container.as_deref_mut(); + let drag_handler = &server.drag_handler; let current_state_id = if let Some(container) = opened_container.as_ref() { container.state_id() } else { self.inventory.state_id() }; + // This is just checking for regular desync, client hasn't done anything malicious if current_state_id != packet.state_id.0 { - dbg!(current_state_id, packet.state_id.0); - //self.set_container_content(opened_container.as_deref_mut()); - //return; + self.set_container_content(opened_container.as_deref_mut()); + return Ok(()); } if opened_container.is_some() { if packet.window_id != self.inventory.total_opened_containers { - dbg!( - self.inventory.total_opened_containers, - opened_container.unwrap().window_type() - ); - return; + return Err(InventoryError::ClosedContainerInteract(self.entity_id())); } } else if packet.window_id != 0 { - dbg!("weird"); - return; + return Err(InventoryError::ClosedContainerInteract(self.entity_id())); } let click = Click::new( @@ -160,26 +164,27 @@ impl Player { container_click::Slot::Normal(slot) => { self.number_button_pressed(opened_container, key_click, slot) } - container_click::Slot::OutsideInventory => { - unimplemented!("This is not a valid state") - } + container_click::Slot::OutsideInventory => Err(InventoryError::InvalidPacket), }, ClickType::CreativePickItem => { if let container_click::Slot::Normal(slot) = click.slot { self.creative_pick_item(opened_container, slot) + } else { + Err(InventoryError::InvalidPacket) } } ClickType::DoubleClick => { if let container_click::Slot::Normal(slot) = click.slot { self.double_click(slot) + } else { + Err(InventoryError::InvalidPacket) } } - ClickType::MouseDrag { - drag_state: _, - drag_type: _, - } => (), - ClickType::DropType(_drop_type) => (), - }; + ClickType::MouseDrag { drag_state } => { + self.mouse_drag(drag_handler, opened_container, drag_state) + } + ClickType::DropType(_drop_type) => todo!(), + } } fn mouse_click( @@ -187,22 +192,22 @@ impl Player { opened_container: Option<&mut Box>, mouse_click: MouseClick, slot: container_click::Slot, - ) { + ) -> Result<(), InventoryError> { let mut container = OptionallyCombinedContainer::new(&mut self.inventory, opened_container); match slot { container_click::Slot::Normal(slot) => { container.handle_item_change(&mut self.carried_item, slot, mouse_click) } - container_click::Slot::OutsideInventory => (), - }; + container_click::Slot::OutsideInventory => todo!(), + } } fn shift_mouse_click( &mut self, opened_container: Option<&mut Box>, slot: container_click::Slot, - ) { + ) -> Result<(), InventoryError> { let mut container = OptionallyCombinedContainer::new(&mut self.inventory, opened_container); match slot { @@ -235,13 +240,14 @@ impl Player { if let Some(slot) = slots { let mut item_slot = container.all_slots()[slot].map(|i| i.to_owned()); - container.handle_item_change(&mut item_slot, slot, MouseClick::Left); + container.handle_item_change(&mut item_slot, slot, MouseClick::Left)?; *container.all_slots()[slot] = item_slot; } } } container_click::Slot::OutsideInventory => (), }; + Ok(()) } fn number_button_pressed( @@ -249,35 +255,74 @@ impl Player { opened_container: Option<&mut Box>, key_click: KeyClick, slot: usize, - ) { + ) -> Result<(), InventoryError> { let changing_slot = match key_click { KeyClick::Slot(slot) => slot, KeyClick::Offhand => 45, }; - let mut changing_item_slot = self.inventory.get_slot(changing_slot as usize).to_owned(); + let mut changing_item_slot = self.inventory.get_slot(changing_slot as usize)?.to_owned(); let mut container = OptionallyCombinedContainer::new(&mut self.inventory, opened_container); - container.handle_item_change(&mut changing_item_slot, slot, MouseClick::Left); - *self.inventory.get_slot(changing_slot as usize) = changing_item_slot + container.handle_item_change(&mut changing_item_slot, slot, MouseClick::Left)?; + *self.inventory.get_slot(changing_slot as usize)? = changing_item_slot; + Ok(()) } fn creative_pick_item( &mut self, opened_container: Option<&mut Box>, slot: usize, - ) { + ) -> Result<(), InventoryError> { + if self.gamemode != GameMode::Creative { + return Err(InventoryError::PermissionError); + } let mut container = OptionallyCombinedContainer::new(&mut self.inventory, opened_container); if let Some(Some(item)) = container.all_slots().get_mut(slot) { self.carried_item = Some(item.to_owned()) } + Ok(()) } - fn double_click(&mut self, _slot: usize) {} + fn double_click(&mut self, _slot: usize) -> Result<(), InventoryError> { + Ok(()) + } + + fn mouse_drag( + &mut self, + drag_handler: &DragHandler, + opened_container: Option<&mut Box>, + mouse_drag_state: MouseDragState, + ) -> Result<(), InventoryError> { + let player_id = self.entity_id(); + let container_id = opened_container + .as_ref() + .map(|container| container.internal_pumpkin_id()) + .unwrap_or(player_id as u64); + match mouse_drag_state { + MouseDragState::Start(drag_type) => { + drag_handler.new_drag(container_id, player_id, drag_type)? + } + MouseDragState::AddSlot(slot) => { + drag_handler.add_slot(container_id, player_id, slot)? + } + MouseDragState::End => { + let mut container = + OptionallyCombinedContainer::new(&mut self.inventory, opened_container); + drag_handler.apply_drag( + &mut self.carried_item, + &mut container, + &container_id, + player_id, + )? + } + } + Ok(()) + } pub fn get_open_container<'a>( &self, server: &'a Server, - ) -> Option>> { + ) -> Option<&'a Mutex>> { if let Some(id) = self.open_container { server.try_get_container(self.entity_id(), id) } else { diff --git a/pumpkin/src/server.rs b/pumpkin/src/server.rs index f83f3f421..d36f05a47 100644 --- a/pumpkin/src/server.rs +++ b/pumpkin/src/server.rs @@ -22,6 +22,7 @@ use std::{ }; use crate::{client::Client, entity::player::Player, world::World}; +use pumpkin_inventory::drag_handler::DragHandler; use pumpkin_inventory::{Container, OpenContainer}; use pumpkin_registry::Registry; use rsa::{traits::PublicKeyParts, RsaPrivateKey, RsaPublicKey}; @@ -48,6 +49,7 @@ pub struct Server { pub cached_registry: Vec, pub open_containers: HashMap, + pub drag_handler: DragHandler, entity_id: AtomicI32, /// Used for Authentication, None is Online mode is disabled @@ -94,6 +96,7 @@ impl Server { plugin_loader, cached_registry: Registry::get_static(), open_containers: HashMap::new(), + drag_handler: DragHandler::new(), // 0 is invalid entity_id: 2.into(), worlds: vec![Arc::new(tokio::sync::Mutex::new(world))], @@ -134,8 +137,11 @@ impl Server { &self, player_id: EntityId, container_id: u64, - ) -> Option>> { - self.open_containers.get(&container_id)?.try_open(player_id) + ) -> Option<&Mutex>> { + self.open_containers + .get(&container_id)? + .try_open(player_id) + .map(|container| container) } /// Sends a Packet to all Players in all worlds