diff --git a/pumpkin-inventory/src/lib.rs b/pumpkin-inventory/src/lib.rs index 1ab7cba1c..2b5730afb 100644 --- a/pumpkin-inventory/src/lib.rs +++ b/pumpkin-inventory/src/lib.rs @@ -3,7 +3,7 @@ use num_derive::ToPrimitive; pub mod player; /// https://wiki.vg/Inventory -#[derive(Debug, ToPrimitive)] +#[derive(Debug, ToPrimitive, Clone)] pub enum WindowType { // not used Generic9x1, @@ -41,3 +41,11 @@ pub enum WindowType { CartographyTable, Stonecutter, } + +impl WindowType { + pub const fn default_title(&self) -> &'static str { + match self { + _ => "WINDOW TITLE" + } + } +} \ No newline at end of file diff --git a/pumpkin-inventory/src/player.rs b/pumpkin-inventory/src/player.rs index f7147f181..fe01acc98 100644 --- a/pumpkin-inventory/src/player.rs +++ b/pumpkin-inventory/src/player.rs @@ -95,4 +95,13 @@ impl PlayerInventory { debug_assert!((0..9).contains(&self.selected)); self.items[self.selected + 36 - 9].as_ref() } + + pub fn slots(&self) -> Vec> { + let mut slots = vec![self.crafting_output.as_ref()]; + slots.extend(self.crafting.iter().map(|c|c.as_ref())); + slots.extend(self.armor.iter().map(|c|c.as_ref())); + slots.extend(self.items.iter().map(|c|c.as_ref())); + slots.push(self.offhand.as_ref()); + slots + } } diff --git a/pumpkin-protocol/src/client/play/c_set_container_content.rs b/pumpkin-protocol/src/client/play/c_set_container_content.rs new file mode 100644 index 000000000..39a298d47 --- /dev/null +++ b/pumpkin-protocol/src/client/play/c_set_container_content.rs @@ -0,0 +1,27 @@ +use pumpkin_macros::packet; +use serde::Serialize; +use crate::slot::Slot; +use crate::VarInt; + +#[derive(Serialize)] +#[packet(0x13)] +pub struct CSetContainerContent<'a> { + window_id: u8, + state_id: VarInt, + count: VarInt, + slot_data: &'a [Slot], + carried_item: Slot +} + + +impl<'a> CSetContainerContent<'a> { + pub fn new(window_id: u8,state_id: VarInt, slots: &'a [Slot], carried_item: Slot) -> Self { + Self { + window_id, + state_id, + count: slots.len().try_into().unwrap(), + slot_data: slots, + carried_item + } + } +} diff --git a/pumpkin-protocol/src/client/play/mod.rs b/pumpkin-protocol/src/client/play/mod.rs index 2ff20e4c0..6437e23a5 100644 --- a/pumpkin-protocol/src/client/play/mod.rs +++ b/pumpkin-protocol/src/client/play/mod.rs @@ -33,6 +33,7 @@ mod c_update_entity_pos; mod c_update_entity_rot; mod c_worldevent; mod player_action; +mod c_set_container_content; pub use c_acknowledge_block::*; pub use c_actionbar::*; @@ -69,3 +70,4 @@ pub use c_update_entity_pos::*; pub use c_update_entity_rot::*; pub use c_worldevent::*; pub use player_action::*; +pub use c_set_container_content::*; \ No newline at end of file diff --git a/pumpkin-protocol/src/slot.rs b/pumpkin-protocol/src/slot.rs index 22223f3b4..84ffd662d 100644 --- a/pumpkin-protocol/src/slot.rs +++ b/pumpkin-protocol/src/slot.rs @@ -3,9 +3,10 @@ use pumpkin_world::item::Item; use serde::{ de::{self, SeqAccess, Visitor}, Deserialize, + Serialize }; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize)] #[allow(dead_code)] pub struct Slot { item_count: VarInt, @@ -83,12 +84,29 @@ impl Slot { item_count: self.item_count.0.try_into().unwrap(), }) } -} -impl From for Item { - fn from(slot: Slot) -> Self { - Item { - item_count: slot.item_count.0.try_into().unwrap(), - item_id: slot.item_id.unwrap().0.try_into().unwrap(), + + pub const fn empty() -> Self { + Slot { + item_count: VarInt(0), + item_id: None, + num_components_to_add: None, + num_components_to_remove: None, + components_to_add: None, + components_to_remove: None, } } } + +impl From<&Item> for Slot { + fn from(item: &Item) -> Self { + Slot { + item_count: item.item_count.into(), + item_id: Some(item.item_id.into()), + // TODO: add these + num_components_to_add: None, + num_components_to_remove: None, + components_to_add: None, + components_to_remove: None, + } + } +} \ No newline at end of file diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index 837976873..59e38e0f0 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -18,7 +18,7 @@ use pumpkin_protocol::{ client::{ config::CConfigDisconnect, login::CLoginDisconnect, - play::{CGameEvent, CPlayDisconnect, CSyncPlayerPostion, CSystemChatMessge}, + play::{CGameEvent, CPlayDisconnect, CSyncPlayerPostion, CSystemChatMessge, CSetContainerContent}, }, packet_decoder::PacketDecoder, packet_encoder::PacketEncoder, @@ -40,6 +40,10 @@ use pumpkin_text::TextComponent; use std::io::Read; use thiserror::Error; +use pumpkin_inventory::WindowType; +use pumpkin_protocol::client::play::COpenScreen; +use pumpkin_protocol::slot::Slot; +use pumpkin_world::item::Item; pub mod authentication; mod client_packet; @@ -174,6 +178,46 @@ impl Client { player.gamemode = gamemode; 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>) { + 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)); + let temp_item = Item { + item_id: 91, // Diamond block + item_count: 64 + }; + self.set_container_content(window_type, Some([Some(&temp_item);27].to_vec()), None); + } + + 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, 10.into(), &slots, carried_item)) + } pub async fn process_packets(&mut self, server: &mut Server) { let mut i = 0; @@ -359,7 +403,7 @@ impl Client { } } } - + pub fn send_system_message(&mut self, text: TextComponent) { self.send_packet(&CSystemChatMessge::new(text, false)); }