Skip to content

Commit

Permalink
Merge pull request #50 from Bryntet/master
Browse files Browse the repository at this point in the history
Add CSetContainerSlot
  • Loading branch information
lukas0008 authored Aug 21, 2024
2 parents bda7a1a + d80bbb7 commit 38931f6
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 8 deletions.
12 changes: 11 additions & 1 deletion pumpkin-inventory/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -41,3 +41,13 @@ pub enum WindowType {
CartographyTable,
Stonecutter,
}

impl WindowType {
pub const fn default_title(&self) -> &'static str {
// TODO: Add titles here:
/*match self {
_ => "WINDOW TITLE",
}*/
"WINDOW TITLE"
}
}
9 changes: 9 additions & 0 deletions pumpkin-inventory/src/player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Option<&Item>> {
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
}
}
26 changes: 26 additions & 0 deletions pumpkin-protocol/src/client/play/c_set_container_content.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use crate::slot::Slot;
use crate::VarInt;
use pumpkin_macros::packet;
use serde::Serialize;

#[derive(Serialize)]
#[packet(0x13)]
pub struct CSetContainerContent<'a> {
window_id: u8,
state_id: VarInt,
count: VarInt,
slot_data: &'a [Slot],
carried_item: &'a Slot,
}

impl<'a> CSetContainerContent<'a> {
pub fn new(window_id: u8, state_id: VarInt, slots: &'a [Slot], carried_item: &'a Slot) -> Self {
Self {
window_id,
state_id,
count: slots.len().into(),
slot_data: slots,
carried_item,
}
}
}
2 changes: 2 additions & 0 deletions pumpkin-protocol/src/client/play/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ mod c_player_chat_message;
mod c_player_info_update;
mod c_player_remove;
mod c_remove_entities;
mod c_set_container_content;
mod c_set_held_item;
mod c_set_title;
mod c_spawn_player;
Expand Down Expand Up @@ -58,6 +59,7 @@ pub use c_player_chat_message::*;
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_held_item::*;
pub use c_set_title::*;
pub use c_spawn_player::*;
Expand Down
82 changes: 76 additions & 6 deletions pumpkin-protocol/src/slot.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::VarInt;
use pumpkin_world::item::Item;
use serde::ser::SerializeSeq;
use serde::{
de::{self, SeqAccess},
Deserialize,
Deserialize, Serialize, Serializer,
};

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -76,6 +77,58 @@ impl<'de> Deserialize<'de> for Slot {
}
}

impl Serialize for Slot {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if self.item_count == 0.into() {
let mut s = serializer.serialize_seq(Some(1))?;
s.serialize_element(&self.item_count)?;
s.end()
} else {
match (&self.num_components_to_add, &self.num_components_to_remove) {
(Some(to_add), Some(to_remove)) => {
let mut s = serializer.serialize_seq(Some(6))?;
s.serialize_element(&self.item_count)?;
s.serialize_element(self.item_id.as_ref().unwrap())?;
s.serialize_element(to_add)?;
s.serialize_element(to_remove)?;
s.serialize_element(self.components_to_add.as_ref().unwrap())?;
s.serialize_element(self.components_to_remove.as_ref().unwrap())?;
s.end()
}
(None, Some(to_remove)) => {
let mut s = serializer.serialize_seq(Some(5))?;
s.serialize_element(&self.item_count)?;
s.serialize_element(self.item_id.as_ref().unwrap())?;
s.serialize_element(&VarInt(0))?;
s.serialize_element(to_remove)?;
s.serialize_element(self.components_to_remove.as_ref().unwrap())?;
s.end()
}
(Some(to_add), None) => {
let mut s = serializer.serialize_seq(Some(5))?;
s.serialize_element(&self.item_count)?;
s.serialize_element(self.item_id.as_ref().unwrap())?;
s.serialize_element(to_add)?;
s.serialize_element(&VarInt(0))?;
s.serialize_element(self.components_to_add.as_ref().unwrap())?;
s.end()
}
(None, None) => {
let mut s = serializer.serialize_seq(Some(4))?;
s.serialize_element(&self.item_count)?;
s.serialize_element(&self.item_id.as_ref().unwrap())?;
s.serialize_element(&VarInt(0))?;
s.serialize_element(&VarInt(0))?;
s.end()
}
}
}
}
}

impl Slot {
pub fn to_item(self) -> Option<Item> {
let item_id = self.item_id?.0.try_into().unwrap();
Expand All @@ -84,12 +137,29 @@ impl Slot {
item_count: self.item_count.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<Slot> 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(),

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,
}
}
}
76 changes: 75 additions & 1 deletion pumpkin/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ use pumpkin_protocol::{
client::{
config::CConfigDisconnect,
login::CLoginDisconnect,
play::{CGameEvent, CPlayDisconnect, CSyncPlayerPostion, CSystemChatMessge},
play::{
CGameEvent, CPlayDisconnect, CSetContainerContent, CSyncPlayerPostion,
CSystemChatMessge,
},
},
packet_decoder::PacketDecoder,
packet_encoder::PacketEncoder,
Expand All @@ -38,6 +41,10 @@ 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;

Expand Down Expand Up @@ -175,6 +182,73 @@ 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<Vec<Option<&Item>>>,
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<Vec<Option<&'a Item>>>,
carried_item: Option<&'a Item>,
) {
let player = self.player.as_ref().unwrap();

let slots: Vec<Slot> = {
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() {
Expand Down

0 comments on commit 38931f6

Please sign in to comment.