first steps towards making containers openable
This commit is contained in:
parent
b0df1a74d4
commit
99116190d9
@ -3,7 +3,7 @@ use num_derive::ToPrimitive;
|
|||||||
pub mod player;
|
pub mod player;
|
||||||
|
|
||||||
/// https://wiki.vg/Inventory
|
/// https://wiki.vg/Inventory
|
||||||
#[derive(Debug, ToPrimitive)]
|
#[derive(Debug, ToPrimitive, Clone)]
|
||||||
pub enum WindowType {
|
pub enum WindowType {
|
||||||
// not used
|
// not used
|
||||||
Generic9x1,
|
Generic9x1,
|
||||||
@ -41,3 +41,11 @@ pub enum WindowType {
|
|||||||
CartographyTable,
|
CartographyTable,
|
||||||
Stonecutter,
|
Stonecutter,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl WindowType {
|
||||||
|
pub const fn default_title(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
_ => "WINDOW TITLE"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -95,4 +95,13 @@ impl PlayerInventory {
|
|||||||
debug_assert!((0..9).contains(&self.selected));
|
debug_assert!((0..9).contains(&self.selected));
|
||||||
self.items[self.selected + 36 - 9].as_ref()
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
27
pumpkin-protocol/src/client/play/c_set_container_content.rs
Normal file
27
pumpkin-protocol/src/client/play/c_set_container_content.rs
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -33,6 +33,7 @@ mod c_update_entity_pos;
|
|||||||
mod c_update_entity_rot;
|
mod c_update_entity_rot;
|
||||||
mod c_worldevent;
|
mod c_worldevent;
|
||||||
mod player_action;
|
mod player_action;
|
||||||
|
mod c_set_container_content;
|
||||||
|
|
||||||
pub use c_acknowledge_block::*;
|
pub use c_acknowledge_block::*;
|
||||||
pub use c_actionbar::*;
|
pub use c_actionbar::*;
|
||||||
@ -69,3 +70,4 @@ pub use c_update_entity_pos::*;
|
|||||||
pub use c_update_entity_rot::*;
|
pub use c_update_entity_rot::*;
|
||||||
pub use c_worldevent::*;
|
pub use c_worldevent::*;
|
||||||
pub use player_action::*;
|
pub use player_action::*;
|
||||||
|
pub use c_set_container_content::*;
|
||||||
@ -3,9 +3,10 @@ use pumpkin_world::item::Item;
|
|||||||
use serde::{
|
use serde::{
|
||||||
de::{self, SeqAccess, Visitor},
|
de::{self, SeqAccess, Visitor},
|
||||||
Deserialize,
|
Deserialize,
|
||||||
|
Serialize
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub struct Slot {
|
pub struct Slot {
|
||||||
item_count: VarInt,
|
item_count: VarInt,
|
||||||
@ -83,12 +84,29 @@ impl Slot {
|
|||||||
item_count: self.item_count.0.try_into().unwrap(),
|
item_count: self.item_count.0.try_into().unwrap(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
impl From<Slot> for Item {
|
pub const fn empty() -> Self {
|
||||||
fn from(slot: Slot) -> Self {
|
Slot {
|
||||||
Item {
|
item_count: VarInt(0),
|
||||||
item_count: slot.item_count.0.try_into().unwrap(),
|
item_id: None,
|
||||||
item_id: slot.item_id.unwrap().0.try_into().unwrap(),
|
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -18,7 +18,7 @@ use pumpkin_protocol::{
|
|||||||
client::{
|
client::{
|
||||||
config::CConfigDisconnect,
|
config::CConfigDisconnect,
|
||||||
login::CLoginDisconnect,
|
login::CLoginDisconnect,
|
||||||
play::{CGameEvent, CPlayDisconnect, CSyncPlayerPostion, CSystemChatMessge},
|
play::{CGameEvent, CPlayDisconnect, CSyncPlayerPostion, CSystemChatMessge, CSetContainerContent},
|
||||||
},
|
},
|
||||||
packet_decoder::PacketDecoder,
|
packet_decoder::PacketDecoder,
|
||||||
packet_encoder::PacketEncoder,
|
packet_encoder::PacketEncoder,
|
||||||
@ -40,6 +40,10 @@ use pumpkin_text::TextComponent;
|
|||||||
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use thiserror::Error;
|
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;
|
pub mod authentication;
|
||||||
mod client_packet;
|
mod client_packet;
|
||||||
@ -175,6 +179,46 @@ impl Client {
|
|||||||
self.send_packet(&CGameEvent::new(3, gamemode.to_f32().unwrap()));
|
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<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, 10.into(), &slots, carried_item))
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn process_packets(&mut self, server: &mut Server) {
|
pub async fn process_packets(&mut self, server: &mut Server) {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < self.client_packets_queue.len() {
|
while i < self.client_packets_queue.len() {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user