diff --git a/pumpkin-inventory/src/lib.rs b/pumpkin-inventory/src/lib.rs index 799e68a9f..3f854db60 100644 --- a/pumpkin-inventory/src/lib.rs +++ b/pumpkin-inventory/src/lib.rs @@ -4,11 +4,14 @@ use num_derive::{FromPrimitive, ToPrimitive}; use pumpkin_world::item::ItemStack; pub mod container_click; +mod open_container; pub mod player; pub mod window_property; +pub use open_container::OpenContainer; + /// https://wiki.vg/Inventory -#[derive(Debug, ToPrimitive, FromPrimitive, Clone, Eq, PartialEq)] +#[derive(Debug, ToPrimitive, FromPrimitive, Clone, Copy, Eq, PartialEq)] pub enum WindowType { // not used Generic9x1, @@ -56,8 +59,8 @@ impl WindowType { "WINDOW TITLE" } } - -pub trait Container { +// Container needs Sync + Send to be able to be in async Server +pub trait Container: Sync + Send { fn window_type(&self) -> &WindowType; fn handle_item_change( @@ -65,9 +68,13 @@ pub trait Container { carried_item: &mut Option, slot: usize, mouse_click: MouseClick, - ); + ) { + handle_item_take(carried_item, self.all_slots()[slot], mouse_click) + } fn all_slots(&mut self) -> Vec<&mut Option>; + + fn all_slots_ref(&self) -> Vec>; } pub fn handle_item_take( @@ -180,6 +187,10 @@ impl Container for ContainerStruct { fn all_slots(&mut self) -> Vec<&mut Option> { self.slots.iter_mut().collect() } + + fn all_slots_ref(&self) -> Vec> { + self.slots.iter().map(|slot| slot.as_ref()).collect() + } } pub struct OptionallyCombinedContainer<'a> { @@ -217,11 +228,13 @@ impl<'a> Container for OptionallyCombinedContainer<'a> { slots } - fn handle_item_change( - &mut self, - carried_item: &mut Option, - slot: usize, - mouse_click: MouseClick, - ) { + fn all_slots_ref(&self) -> Vec> { + let mut slots = if let Some(container) = &self.container { + container.all_slots_ref() + } else { + vec![] + }; + slots.extend(self.inventory.all_slots_ref()); + slots } } diff --git a/pumpkin-inventory/src/open_container.rs b/pumpkin-inventory/src/open_container.rs new file mode 100644 index 000000000..35a24b9a5 --- /dev/null +++ b/pumpkin-inventory/src/open_container.rs @@ -0,0 +1,46 @@ +use crate::container_click::MouseClick; +use crate::{handle_item_change, Container, WindowType}; +use pumpkin_world::item::ItemStack; +use std::sync::{Mutex, MutexGuard}; + +pub struct OpenContainer { + players: Vec, + container: Mutex>, +} + +impl OpenContainer { + pub fn try_open(&self, player_id: i32) -> Option>> { + if !self.players.contains(&player_id) { + return None; + } + Some(self.container.lock().unwrap()) + } + + pub fn empty(player_id: i32) -> Self { + Self { + players: vec![player_id], + container: Mutex::new(Box::new(Chest::new())), + } + } +} + +struct Chest([Option; 27]); + +impl Chest { + pub fn new() -> Self { + Self([None; 27]) + } +} +impl Container for Chest { + fn window_type(&self) -> &WindowType { + &WindowType::Generic9x3 + } + + fn all_slots(&mut self) -> Vec<&mut Option> { + self.0.iter_mut().collect() + } + + fn all_slots_ref(&self) -> Vec> { + self.0.iter().map(|slot| slot.as_ref()).collect() + } +} diff --git a/pumpkin-inventory/src/player.rs b/pumpkin-inventory/src/player.rs index 4da9ac73c..ca7150920 100644 --- a/pumpkin-inventory/src/player.rs +++ b/pumpkin-inventory/src/player.rs @@ -148,4 +148,8 @@ impl Container for PlayerInventory { fn all_slots(&mut self) -> Vec<&mut Option> { self.slots_mut() } + + fn all_slots_ref(&self) -> Vec> { + self.slots() + } } diff --git a/pumpkin/src/client/container.rs b/pumpkin/src/client/container.rs index a32d9b26f..02cb84893 100644 --- a/pumpkin/src/client/container.rs +++ b/pumpkin/src/client/container.rs @@ -15,11 +15,12 @@ use pumpkin_protocol::slot::Slot; use pumpkin_world::item::ItemStack; use crate::entity::player::Player; +use crate::server::Server; impl Player { pub fn open_container( &mut self, - window_type: WindowType, + window_type: &WindowType, minecraft_menu_id: &str, window_title: Option<&str>, items: Option>>, @@ -45,7 +46,7 @@ impl Player { pub fn set_container_content<'a>( &mut self, - window_type: WindowType, + window_type: &WindowType, items: Option>>, carried_item: Option<&'a ItemStack>, ) { @@ -75,7 +76,7 @@ impl Player { } }; let packet = - CSetContainerContent::new(window_type as u8 + 1, 0.into(), &slots, &carried_item); + CSetContainerContent::new(*window_type as u8 + 1, 0.into(), &slots, &carried_item); self.client.send_packet(&packet); } @@ -109,8 +110,15 @@ impl Player { .send_packet(&CSetContainerProperty::new(window_type as u8, id, value)); } - pub fn handle_click_container(&mut self, packet: SClickContainer) { + pub fn handle_click_container(&mut self, server: &mut Server, packet: SClickContainer) { use container_click::*; + let mut opened_container = if let Some(id) = self.open_container { + server.try_get_container(self.entity_id(), self.open_container.unwrap()) + } else { + None + }; + let opened_container = opened_container.as_deref_mut(); + let click = Click { state_id: packet.state_id.0.try_into().unwrap(), changed_items: packet @@ -137,15 +145,19 @@ impl Player { packet.slot, ), }; - match click.mode.click_type { - ClickType::MouseClick(mouse_click) => { - self.mouse_click(mouse_click, click.window_type, click.mode.slot) + ClickType::MouseClick(mouse_click) => self.mouse_click( + opened_container, + mouse_click, + click.window_type, + click.mode.slot, + ), + ClickType::ShiftClick => { + self.shift_mouse_click(opened_container, click.window_type, click.mode.slot) } - ClickType::ShiftClick => self.shift_mouse_click(click.window_type, click.mode.slot), ClickType::KeyClick(key_click) => match click.mode.slot { container_click::Slot::Normal(slot) => { - self.number_button_pressed(click.window_type, key_click, slot) + self.number_button_pressed(opened_container, click.window_type, key_click, slot) } container_click::Slot::OutsideInventory => { unimplemented!("This is not a valid state") @@ -153,7 +165,7 @@ impl Player { }, ClickType::CreativePickItem => { if let container_click::Slot::Normal(slot) = click.mode.slot { - self.creative_pick_item(slot) + self.creative_pick_item(opened_container, slot) } } ClickType::DoubleClick => {} @@ -178,11 +190,12 @@ impl Player { fn mouse_click( &mut self, + opened_container: Option<&mut Box>, mouse_click: MouseClick, window_type: WindowType, slot: container_click::Slot, ) { - let mut container = get_full_container(&mut self.inventory, self.open_container.as_mut()); + let mut container = OptionallyCombinedContainer::new(&mut self.inventory, opened_container); if container.window_type() != &window_type { return; } @@ -195,8 +208,13 @@ impl Player { }; } - fn shift_mouse_click(&mut self, window_type: WindowType, slot: container_click::Slot) { - let mut container = get_full_container(&mut self.inventory, self.open_container.as_mut()); + fn shift_mouse_click( + &mut self, + opened_container: Option<&mut Box>, + window_type: WindowType, + slot: container_click::Slot, + ) { + let mut container = OptionallyCombinedContainer::new(&mut self.inventory, opened_container); if container.window_type() != &window_type { return; } @@ -235,13 +253,19 @@ impl Player { }; } - fn number_button_pressed(&mut self, window_type: WindowType, key_click: KeyClick, slot: usize) { + fn number_button_pressed( + &mut self, + opened_container: Option<&mut Box>, + window_type: WindowType, + key_click: KeyClick, + slot: usize, + ) { 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 container = get_full_container(&mut self.inventory, self.open_container.as_mut()); + let mut container = OptionallyCombinedContainer::new(&mut self.inventory, opened_container); if container.window_type() != &window_type { return; } @@ -253,34 +277,16 @@ impl Player { } } - fn creative_pick_item(&mut self, slot: usize) { - let mut container = get_full_container(&mut self.inventory, self.open_container.as_mut()); - + fn creative_pick_item( + &mut self, + mut opened_container: Option<&mut Box>, + slot: usize, + ) { + 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()) } } fn double_click(&mut self, slot: usize) {} - - fn get_container_type(&mut self) -> &WindowType { - match &self.open_container { - Some(container) => container.window_type(), - // This is the one the inventory uses for some stupid reason - None => &WindowType::Generic9x1, - } - } -} - -/*impl ContainerStruct { - pub fn opened_by_players(&mut self, server: Server) -> Vec<&Player> { - - } -}*/ - -fn get_full_container<'a>( - inventory: &'a mut PlayerInventory, - open_container: Option<&'a mut Box>, -) -> OptionallyCombinedContainer<'a> { - OptionallyCombinedContainer::new(inventory, open_container) } diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index 9fd2e0dad..b734ff3a8 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -15,10 +15,10 @@ use pumpkin_protocol::{ }, position::WorldPosition, server::play::{ - SChatCommand, SChatMessage, SClientInformationPlay, SConfirmTeleport, SInteract, - SPlayPingRequest, SPlayerAction, SPlayerCommand, SPlayerPosition, SPlayerPositionRotation, - SPlayerRotation, SSetCreativeSlot, SSetHeldItem, SSetPlayerGround, SSwingArm, SUseItem, - SUseItemOn, + SChatCommand, SChatMessage, SClickContainer, SClientInformationPlay, SConfirmTeleport, + SInteract, SPlayPingRequest, SPlayerAction, SPlayerCommand, SPlayerPosition, + SPlayerPositionRotation, SPlayerRotation, SSetCreativeSlot, SSetHeldItem, SSetPlayerGround, + SSwingArm, SUseItem, SUseItemOn, }, ConnectionState, RawPacket, ServerPacket, VarInt, }; @@ -26,11 +26,7 @@ use pumpkin_world::item::ItemStack; use pumpkin_world::vector3::Vector3; use serde::{Deserialize, Serialize}; -use crate::{ - client::{authentication::GameProfile, Client}, - server::Server, - util::boundingbox::BoundingBox, -}; +use crate::{client::authentication::GameProfile, util::boundingbox::BoundingBox}; pub struct PlayerAbilities { pub invulnerable: bool, @@ -65,7 +61,7 @@ pub struct Player { pub food: i32, pub food_saturation: f32, pub inventory: PlayerInventory, - pub open_container: Option>, + pub open_container: Option, pub carried_item: Option, /// send `send_abilties_update` when changed @@ -406,9 +402,13 @@ impl Player { Ok(()) } SClickContainer::PACKET_ID => { - self.handle_click_container(SClickContainer::read(bytebuf).unwrap()) + self.handle_click_container(server, SClickContainer::read(bytebuf)?); + Ok(()) + } + _ => { + log::error!("Failed to handle player packet id {:#04x}", packet.id.0); + Ok(()) } - _ => log::error!("Failed to handle player packet id {:#04x}", packet.id.0), } } } diff --git a/pumpkin/src/server.rs b/pumpkin/src/server.rs index c673cbc9c..6d5b008f8 100644 --- a/pumpkin/src/server.rs +++ b/pumpkin/src/server.rs @@ -29,16 +29,16 @@ use pumpkin_protocol::{ }; use pumpkin_world::{dimension::Dimension, radial_chunk_iterator::RadialIterator, World}; -use pumpkin_registry::Registry; -use rsa::{traits::PublicKeyParts, RsaPrivateKey, RsaPublicKey}; -use serde::{Deserialize, Serialize}; -use tokio::sync::mpsc; - use crate::{ client::Client, config::{AdvancedConfiguration, BasicConfiguration}, entity::player::{GameMode, Player}, }; +use pumpkin_inventory::{Container, OpenContainer}; +use pumpkin_registry::Registry; +use rsa::{traits::PublicKeyParts, RsaPrivateKey, RsaPublicKey}; +use serde::{Deserialize, Serialize}; +use tokio::sync::mpsc; pub const CURRENT_MC_VERSION: &str = "1.21.1"; @@ -63,6 +63,7 @@ pub struct Server { // TODO: place this into every world pub current_players: HashMap, Arc>>, + pub open_containers: HashMap, entity_id: AtomicI32, pub base_config: BasicConfiguration, @@ -120,6 +121,7 @@ impl Server { status_response_json, public_key_der, current_players: HashMap::new(), + open_containers: HashMap::new(), base_config: config.0, auth_client, advanced_config: config.1, @@ -315,6 +317,14 @@ impl Server { None } + pub fn try_get_container( + &self, + player_id: EntityId, + container_id: u64, + ) -> Option>> { + self.open_containers.get(&container_id)?.try_open(player_id) + } + /// Sends a Packet to all Players pub fn broadcast_packet

(&self, from: &mut Player, packet: &P) where