Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CSetContainerSlot #50

Merged
merged 10 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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