diff --git a/pumpkin-protocol/src/client/play/c_set_container_slot.rs b/pumpkin-protocol/src/client/play/c_set_container_slot.rs new file mode 100644 index 000000000..e07d07d82 --- /dev/null +++ b/pumpkin-protocol/src/client/play/c_set_container_slot.rs @@ -0,0 +1,23 @@ +use crate::slot::Slot; +use crate::VarInt; +use pumpkin_macros::packet; +use serde::Serialize; +#[derive(Serialize)] +#[packet(0x15)] +pub struct CSetContainerSlot<'a> { + window_id: i8, + state_id: VarInt, + slot: i16, + slot_data: &'a Slot, +} + +impl<'a> CSetContainerSlot<'a> { + pub fn new(window_id: i8, state_id: i32, slot: usize, slot_data: &'a Slot) -> Self { + Self { + window_id, + state_id: state_id.into(), + slot: slot.try_into().unwrap(), + slot_data, + } + } +} diff --git a/pumpkin-protocol/src/client/play/mod.rs b/pumpkin-protocol/src/client/play/mod.rs index df63734c9..a732f2ccb 100644 --- a/pumpkin-protocol/src/client/play/mod.rs +++ b/pumpkin-protocol/src/client/play/mod.rs @@ -23,6 +23,7 @@ mod c_player_info_update; mod c_player_remove; mod c_remove_entities; mod c_set_container_content; +mod c_set_container_slot; mod c_set_held_item; mod c_set_title; mod c_spawn_player; @@ -60,6 +61,7 @@ pub use c_player_info_update::*; pub use c_player_remove::*; pub use c_remove_entities::*; pub use c_set_container_content::*; +pub use c_set_container_slot::*; pub use c_set_held_item::*; pub use c_set_title::*; pub use c_spawn_player::*; diff --git a/pumpkin-protocol/src/slot.rs b/pumpkin-protocol/src/slot.rs index 053813fc7..2ccab79b9 100644 --- a/pumpkin-protocol/src/slot.rs +++ b/pumpkin-protocol/src/slot.rs @@ -163,3 +163,9 @@ impl From<&Item> for Slot { } } } + +impl From> for Slot { + fn from(item: Option<&Item>) -> Self { + item.map(Slot::from).unwrap_or(Slot::empty()) + } +} diff --git a/pumpkin/src/client/container.rs b/pumpkin/src/client/container.rs new file mode 100644 index 000000000..b8a242dbd --- /dev/null +++ b/pumpkin/src/client/container.rs @@ -0,0 +1,85 @@ +use pumpkin_core::text::TextComponent; +use pumpkin_inventory::WindowType; +use pumpkin_protocol::client::play::{COpenScreen, CSetContainerContent, CSetContainerSlot}; +use pumpkin_protocol::slot::Slot; +use pumpkin_world::item::Item; + +impl super::Client { + pub fn open_container( + &mut self, + window_type: WindowType, + minecraft_menu_id: &str, + window_title: Option<&str>, + items: Option>>, + carried_item: Option<&Item>, + ) { + let menu_protocol_id = (*pumpkin_world::global_registry::REGISTRY + .get("minecraft:menu") + .unwrap() + .entries + .get(minecraft_menu_id) + .expect("Should be a valid menu id") + .get("protocol_id") + .unwrap()) + .into(); + let title = TextComponent::text(window_title.unwrap_or(window_type.default_title())); + self.send_packet(&COpenScreen::new( + (window_type.clone() as u8 + 1).into(), + menu_protocol_id, + title, + )); + self.set_container_content(window_type, items, carried_item); + } + + pub fn set_container_content<'a>( + &mut self, + window_type: WindowType, + items: Option>>, + carried_item: Option<&'a Item>, + ) { + let player = self.player.as_ref().unwrap(); + + let slots: Vec = { + if let Some(mut items) = items { + items.extend(player.inventory.slots()); + items + } else { + player.inventory.slots() + } + .into_iter() + .map(|item| { + if let Some(item) = item { + Slot::from(item) + } else { + Slot::empty() + } + }) + .collect() + }; + + let carried_item = { + if let Some(item) = carried_item { + item.into() + } else { + Slot::empty() + } + }; + let packet = + CSetContainerContent::new(window_type as u8 + 1, 0.into(), &slots, &carried_item); + self.send_packet(&packet); + } + + pub fn set_container_slot( + &mut self, + window_type: WindowType, + slot: usize, + item: Option<&Item>, + ) { + self.send_packet(&CSetContainerSlot::new( + window_type as i8, + 0, + slot, + &item.into(), + )) + } +} diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index 0e1083a3e..282f4381a 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -19,10 +19,7 @@ use pumpkin_protocol::{ client::{ config::CConfigDisconnect, login::CLoginDisconnect, - play::{ - CGameEvent, CPlayDisconnect, CSetContainerContent, CSyncPlayerPostion, - CSystemChatMessge, - }, + play::{CGameEvent, CPlayDisconnect, CSyncPlayerPostion, CSystemChatMessge}, }, packet_decoder::PacketDecoder, packet_encoder::PacketEncoder, @@ -41,15 +38,12 @@ use pumpkin_protocol::{ ClientPacket, ConnectionState, PacketError, RawPacket, ServerPacket, }; -use pumpkin_inventory::WindowType; -use pumpkin_protocol::client::play::COpenScreen; -use pumpkin_protocol::slot::Slot; -use pumpkin_world::item::Item; use std::io::Read; use thiserror::Error; pub mod authentication; mod client_packet; +mod container; pub mod player_packet; pub struct PlayerConfig { @@ -182,73 +176,6 @@ impl Client { self.send_packet(&CGameEvent::new(3, gamemode.to_f32().unwrap())); } - pub fn open_container( - &mut self, - window_type: WindowType, - minecraft_menu_id: &str, - window_title: Option<&str>, - items: Option>>, - carried_item: Option<&Item>, - ) { - let menu_protocol_id = (*pumpkin_world::global_registry::REGISTRY - .get("minecraft:menu") - .unwrap() - .entries - .get(minecraft_menu_id) - .expect("Should be a valid menu id") - .get("protocol_id") - .unwrap()) - .into(); - let title = TextComponent::text(window_title.unwrap_or(window_type.default_title())); - self.send_packet(&COpenScreen::new( - (window_type.clone() as u8 + 1).into(), - menu_protocol_id, - title, - )); - self.set_container_content(window_type, items, carried_item); - } - - pub fn set_container_content<'a>( - &mut self, - window_type: WindowType, - items: Option>>, - carried_item: Option<&'a Item>, - ) { - let player = self.player.as_ref().unwrap(); - - let slots: Vec = { - if let Some(mut items) = items { - items.extend(player.inventory.slots()); - items - } else { - player.inventory.slots() - } - .into_iter() - .map(|item| { - if let Some(item) = item { - Slot::from(item) - } else { - Slot::empty() - } - }) - .collect() - }; - - let carried_item = { - if let Some(item) = carried_item { - item.into() - } else { - Slot::empty() - } - }; - self.send_packet(&CSetContainerContent::new( - window_type as u8 + 1, - 0.into(), - &slots, - &carried_item, - )); - } - pub async fn process_packets(&mut self, server: &mut Server) { let mut i = 0; while i < self.client_packets_queue.len() {