From 4749a819f7c31b11df3f2025ac78dda9217f2ca0 Mon Sep 17 00:00:00 2001 From: Outspending Date: Thu, 9 Jan 2025 07:54:20 -0700 Subject: [PATCH] Item Components :eyes: --- src/bin/src/packet_handlers/containers.rs | 6 +- src/lib/inventory/src/contents.rs | 2 +- src/lib/inventory/src/slot.rs | 4 +- src/lib/net/src/lib.rs | 2 + .../src/packets/incoming/click_container.rs | 2 +- .../incoming/set_creative_mode_slot.rs | 5 +- .../packets/outgoing/set_container_content.rs | 3 +- .../packets/outgoing/set_container_slot.rs | 42 +---- .../net/src/packets/outgoing/set_equipment.rs | 2 +- src/lib/net/src/slot.rs | 157 +++++++++++++++++- 10 files changed, 167 insertions(+), 58 deletions(-) diff --git a/src/bin/src/packet_handlers/containers.rs b/src/bin/src/packet_handlers/containers.rs index 84bdbcc4..fe9fdc73 100644 --- a/src/bin/src/packet_handlers/containers.rs +++ b/src/bin/src/packet_handlers/containers.rs @@ -45,7 +45,7 @@ async fn handle_container_click( let slot_num = changed_slot.slot_number; inventory - .set_slot(slot_num, Slot::from_network_slot(changed_slot.slot)) + .set_slot(slot_num, Slot::from_network_slot(&changed_slot.slot)) .sync_inventory(conn_id, &InventorySyncType::Single(slot_num), state) .await .map_err(|err| NetError::Other(err.to_string()))?; @@ -54,7 +54,7 @@ async fn handle_container_click( changed_slots.iter().for_each(|changed_slot| { inventory.set_slot( changed_slot.slot_number, - Slot::from_network_slot(changed_slot.slot), + Slot::from_network_slot(&changed_slot.slot), ); }); @@ -79,7 +79,7 @@ async fn set_creative_mode_slot( let mut inventory = state.universe.get_mut::(conn_id)?; inventory.set_slot( creative_mode_slot.slot, - Slot::from_network_slot(creative_mode_slot.clicked_item), + Slot::from_network_slot(&creative_mode_slot.clicked_item), ); Ok(creative_mode_slot) diff --git a/src/lib/inventory/src/contents.rs b/src/lib/inventory/src/contents.rs index a9333d4c..693806e0 100644 --- a/src/lib/inventory/src/contents.rs +++ b/src/lib/inventory/src/contents.rs @@ -1,5 +1,5 @@ use crate::{inventory::InventoryType, slot::Slot}; -use ferrumc_net::packets::outgoing::set_container_slot::NetworkSlot; +use ferrumc_net::slot::NetworkSlot; use ferrumc_net_codec::net_types::length_prefixed_vec::LengthPrefixedVec; use std::collections::BTreeMap; diff --git a/src/lib/inventory/src/slot.rs b/src/lib/inventory/src/slot.rs index 2ae501be..1eee48f0 100644 --- a/src/lib/inventory/src/slot.rs +++ b/src/lib/inventory/src/slot.rs @@ -1,4 +1,4 @@ -use ferrumc_net::packets::outgoing::set_container_slot::NetworkSlot; +use ferrumc_net::slot::NetworkSlot; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Slot { @@ -37,7 +37,7 @@ impl Slot { Self::new(0, 0) } - pub fn from_network_slot(slot: NetworkSlot) -> Self { + pub fn from_network_slot(slot: &NetworkSlot) -> Self { match slot.item_id { Some(item) => Self::new(*slot.item_count, *item), None => Self::empty(), diff --git a/src/lib/net/src/lib.rs b/src/lib/net/src/lib.rs index dcea638d..8f5b7d58 100644 --- a/src/lib/net/src/lib.rs +++ b/src/lib/net/src/lib.rs @@ -7,7 +7,9 @@ pub mod connection; pub mod errors; pub mod packets; pub mod server; +pub mod slot; pub mod utils; + pub type NetResult = Result; bake_packet_registry!("\\src\\packets\\incoming"); diff --git a/src/lib/net/src/packets/incoming/click_container.rs b/src/lib/net/src/packets/incoming/click_container.rs index 57b2c6e2..b0e5e934 100644 --- a/src/lib/net/src/packets/incoming/click_container.rs +++ b/src/lib/net/src/packets/incoming/click_container.rs @@ -1,5 +1,5 @@ -use crate::packets::outgoing::set_container_slot::NetworkSlot; use crate::packets::IncomingPacket; +use crate::slot::NetworkSlot; use crate::NetResult; use ferrumc_events::infrastructure::Event; use ferrumc_macros::{packet, Event, NetDecode}; diff --git a/src/lib/net/src/packets/incoming/set_creative_mode_slot.rs b/src/lib/net/src/packets/incoming/set_creative_mode_slot.rs index e8aea661..265896d1 100644 --- a/src/lib/net/src/packets/incoming/set_creative_mode_slot.rs +++ b/src/lib/net/src/packets/incoming/set_creative_mode_slot.rs @@ -4,10 +4,7 @@ use ferrumc_events::infrastructure::Event; use ferrumc_macros::{packet, Event, NetDecode}; use ferrumc_state::ServerState; -use crate::{ - packets::{outgoing::set_container_slot::NetworkSlot, IncomingPacket}, - NetResult, -}; +use crate::{packets::IncomingPacket, slot::NetworkSlot, NetResult}; #[derive(NetDecode, Debug)] #[packet(packet_id = "set_creative_mode_slot", state = "play")] diff --git a/src/lib/net/src/packets/outgoing/set_container_content.rs b/src/lib/net/src/packets/outgoing/set_container_content.rs index 85c9c2ea..537332d9 100644 --- a/src/lib/net/src/packets/outgoing/set_container_content.rs +++ b/src/lib/net/src/packets/outgoing/set_container_content.rs @@ -1,8 +1,9 @@ -use super::set_container_slot::NetworkSlot; use ferrumc_macros::{packet, NetEncode}; use ferrumc_net_codec::net_types::{length_prefixed_vec::LengthPrefixedVec, var_int::VarInt}; use std::io::Write; +use crate::slot::NetworkSlot; + #[derive(NetEncode, Debug)] #[packet(packet_id = "container_set_content", state_id = "play")] pub struct SetContainerContentPacket { diff --git a/src/lib/net/src/packets/outgoing/set_container_slot.rs b/src/lib/net/src/packets/outgoing/set_container_slot.rs index f43879de..e540723e 100644 --- a/src/lib/net/src/packets/outgoing/set_container_slot.rs +++ b/src/lib/net/src/packets/outgoing/set_container_slot.rs @@ -1,46 +1,8 @@ -use ferrumc_macros::{packet, NetDecode, NetEncode}; +use ferrumc_macros::{packet, NetEncode}; use ferrumc_net_codec::net_types::var_int::VarInt; use std::io::Write; -#[derive(NetDecode, NetEncode, Debug, Clone, Copy)] -pub struct NetworkSlot { - pub item_count: VarInt, - #[net(optional_trigger = *item_count > 0)] - pub item_id: Option, - #[net(optional_trigger = *item_count > 0)] - pub num_of_components_to_add: Option, - #[net(optional_trigger = *item_count > 0)] - pub num_of_components_to_remove: Option, -} - -impl NetworkSlot { - pub fn new(item_count: i32, item_id: i32) -> Self { - let components = if item_count == 0 { - None - } else { - Some(VarInt::new(0)) - }; - Self { - item_count: VarInt::new(item_count), - item_id: if item_count == 0 { - None - } else { - Some(VarInt::new(item_id)) - }, - num_of_components_to_add: components, - num_of_components_to_remove: components, - } - } - - pub fn empty() -> Self { - Self::new(0, 0) - } - - pub fn item_id(&mut self, item_id: VarInt) -> &mut Self { - self.item_id = Some(item_id); - self - } -} +use crate::slot::NetworkSlot; #[derive(NetEncode)] #[packet(packet_id = "container_set_slot", state_id = "play")] diff --git a/src/lib/net/src/packets/outgoing/set_equipment.rs b/src/lib/net/src/packets/outgoing/set_equipment.rs index 34ef7740..dd1338ee 100644 --- a/src/lib/net/src/packets/outgoing/set_equipment.rs +++ b/src/lib/net/src/packets/outgoing/set_equipment.rs @@ -5,7 +5,7 @@ use ferrumc_net_codec::{ }; use std::io::Write; -use super::set_container_slot::NetworkSlot; +use crate::slot::NetworkSlot; #[derive(Debug, Clone, PartialEq, Eq)] pub enum EquipmentSlot { diff --git a/src/lib/net/src/slot.rs b/src/lib/net/src/slot.rs index 8f522219..d4bc7390 100644 --- a/src/lib/net/src/slot.rs +++ b/src/lib/net/src/slot.rs @@ -1,17 +1,68 @@ -use std::io::Read; +use std::io::{Read, Write}; -use ferrumc_macros::{NetDecode, NetEncode}; use ferrumc_net_codec::{ - decode::{NetDecode, NetDecodeOpts, NetDecodeResult}, + decode::{errors::NetDecodeError, NetDecode, NetDecodeOpts, NetDecodeResult}, + encode::{NetEncode, NetEncodeOpts, NetEncodeResult}, net_types::{length_prefixed_vec::LengthPrefixedVec, var_int::VarInt}, }; +use tokio::io::AsyncWrite; -#[derive(NetEncode, Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy)] pub enum SlotComponent { MaxStackSize { max_stack_size: VarInt }, } -#[derive(Debug, Clone, Copy)] +impl NetEncode for SlotComponent { + fn encode(&self, writer: &mut W, opts: &NetEncodeOpts) -> NetEncodeResult<()> { + VarInt::new(self.get_type()).encode(writer, opts)?; + match self { + SlotComponent::MaxStackSize { max_stack_size } => { + max_stack_size.encode(writer, opts)?; + } + }; + + Ok(()) + } + + async fn encode_async( + &self, + writer: &mut W, + opts: &NetEncodeOpts, + ) -> NetEncodeResult<()> { + VarInt::new(self.get_type()) + .encode_async(writer, opts) + .await?; + match self { + SlotComponent::MaxStackSize { max_stack_size } => { + max_stack_size.encode_async(writer, opts).await?; + } + }; + + Ok(()) + } +} + +impl NetDecode for SlotComponent { + fn decode(reader: &mut R, opts: &NetDecodeOpts) -> NetDecodeResult { + let id = VarInt::decode(reader, opts)?; + match *id { + 1 => Ok(SlotComponent::MaxStackSize { + max_stack_size: VarInt::decode(reader, opts)?, + }), + _ => Err(NetDecodeError::InvalidEnumVariant), + } + } +} + +impl SlotComponent { + pub fn get_type(&self) -> i32 { + match self { + SlotComponent::MaxStackSize { .. } => 1, + } + } +} + +#[derive(Debug)] pub struct NetworkSlot { pub item_count: VarInt, pub item_id: Option, @@ -19,6 +70,102 @@ pub struct NetworkSlot { pub components_to_remove: Option>, } +impl NetEncode for NetworkSlot { + fn encode(&self, writer: &mut W, opts: &NetEncodeOpts) -> NetEncodeResult<()> { + self.item_count.encode(writer, opts)?; + + if let Some(id) = self.item_id { + id.encode(writer, opts)?; + } + + match (&self.components_to_add, &self.components_to_remove) { + (Some(components_add), Some(components_remove)) => { + components_add.length.encode(writer, opts)?; + components_remove.length.encode(writer, opts)?; + + for component in &components_add.data { + component.encode(writer, opts)?; + } + + for component in &components_remove.data { + component.encode(writer, opts)?; + } + } + _ => {} // Do nothing if both components are None + } + + Ok(()) + } + + async fn encode_async( + &self, + writer: &mut W, + opts: &NetEncodeOpts, + ) -> NetEncodeResult<()> { + self.item_count.encode_async(writer, opts).await?; + + if let Some(id) = self.item_id { + id.encode_async(writer, opts).await?; + } + + match (&self.components_to_add, &self.components_to_remove) { + (Some(components_add), Some(components_remove)) => { + components_add.length.encode_async(writer, opts).await?; + components_remove.length.encode_async(writer, opts).await?; + + for component in &components_add.data { + component.encode_async(writer, opts).await?; + } + + for component in &components_remove.data { + component.encode_async(writer, opts).await?; + } + } + _ => {} // Do nothing if both components are None + } + + Ok(()) + } +} + +impl NetDecode for NetworkSlot { + fn decode(reader: &mut R, opts: &NetDecodeOpts) -> NetDecodeResult { + let item_count = VarInt::decode(reader, opts)?; + + if item_count == 0 { + return Ok(NetworkSlot::empty()); + } + + let item_id = VarInt::decode(reader, opts)?; + + let mut components_to_add = Vec::with_capacity(*VarInt::decode(reader, opts)? as usize); + let mut components_to_remove = Vec::with_capacity(*VarInt::decode(reader, opts)? as usize); + + for _ in 0..components_to_add.capacity() { + components_to_add.push(SlotComponent::decode(reader, opts)?); + } + + for _ in 0..components_to_remove.capacity() { + components_to_remove.push(VarInt::decode(reader, opts)?); + } + + Ok(Self { + item_count, + item_id: Some(item_id), + components_to_add: if components_to_add.is_empty() { + None + } else { + Some(LengthPrefixedVec::new(components_to_add)) + }, + components_to_remove: if components_to_remove.is_empty() { + None + } else { + Some(LengthPrefixedVec::new(components_to_remove)) + }, + }) + } +} + impl NetworkSlot { pub fn new(item_count: i32, item_id: i32) -> Self { Self::with_components(item_count, item_id, vec![])