From 4d5527ae999241f0aa82973194f6626515fa87e2 Mon Sep 17 00:00:00 2001 From: Outspending Date: Sun, 29 Dec 2024 16:07:32 -0700 Subject: [PATCH 01/38] Simple Inventory Implementation --- Cargo.toml | 3 +- src/bin/Cargo.toml | 1 + src/bin/src/packet_handlers/login_process.rs | 8 ++ src/lib/inventory/Cargo.toml | 14 +++ src/lib/inventory/src/contents.rs | 22 ++++ src/lib/inventory/src/inventory.rs | 106 ++++++++++++++++++ src/lib/inventory/src/lib.rs | 2 + src/lib/net/src/packets/outgoing/mod.rs | 2 + .../net/src/packets/outgoing/open_screen.rs | 30 +++++ .../packets/outgoing/set_container_slot.rs | 56 +++++++++ 10 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 src/lib/inventory/Cargo.toml create mode 100644 src/lib/inventory/src/contents.rs create mode 100644 src/lib/inventory/src/inventory.rs create mode 100644 src/lib/inventory/src/lib.rs create mode 100644 src/lib/net/src/packets/outgoing/open_screen.rs create mode 100644 src/lib/net/src/packets/outgoing/set_container_slot.rs diff --git a/Cargo.toml b/Cargo.toml index b79853e4..7bc96ce9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ members = [ "src/lib/derive_macros", "src/lib/derive_macros", "src/lib/ecs", - "src/lib/events", + "src/lib/events", "src/lib/inventory", "src/lib/net", "src/lib/net/crates/codec", "src/lib/net/crates/encryption", @@ -93,6 +93,7 @@ ferrumc-logging = { path = "src/lib/utils/logging" } ferrumc-macros = { path = "src/lib/derive_macros" } ferrumc-nbt = { path = "src/lib/adapters/nbt" } ferrumc-net = { path = "src/lib/net" } +ferrumc-inventory = { path = "src/lib/inventory" } ferrumc-net-codec = { path = "src/lib/net/crates/codec" } ferrumc-net-encryption = { path = "src/lib/net/crates/encryption" } ferrumc-plugins = { path = "src/lib/plugins" } diff --git a/src/bin/Cargo.toml b/src/bin/Cargo.toml index 803db5a7..7d28672a 100644 --- a/src/bin/Cargo.toml +++ b/src/bin/Cargo.toml @@ -19,6 +19,7 @@ ferrumc-plugins = { workspace = true } ferrumc-storage = { workspace = true } ferrumc-utils = { workspace = true } ferrumc-config = { workspace = true } +ferrumc-inventory = { workspace = true } ferrumc-profiling = { workspace = true } ferrumc-logging = { workspace = true } ferrumc-world = { workspace = true } diff --git a/src/bin/src/packet_handlers/login_process.rs b/src/bin/src/packet_handlers/login_process.rs index c26609aa..c45286b7 100644 --- a/src/bin/src/packet_handlers/login_process.rs +++ b/src/bin/src/packet_handlers/login_process.rs @@ -3,6 +3,7 @@ use ferrumc_core::transform::grounded::OnGround; use ferrumc_core::transform::position::Position; use ferrumc_core::transform::rotation::Rotation; use ferrumc_ecs::components::storage::ComponentRefMut; +use ferrumc_inventory::inventory::{Inventory, InventoryType}; use ferrumc_macros::event_handler; use ferrumc_net::connection::{ConnectionState, StreamWriter}; use ferrumc_net::errors::NetError; @@ -17,12 +18,15 @@ use ferrumc_net::packets::outgoing::game_event::GameEventPacket; use ferrumc_net::packets::outgoing::keep_alive::OutgoingKeepAlivePacket; use ferrumc_net::packets::outgoing::login_play::LoginPlayPacket; use ferrumc_net::packets::outgoing::login_success::LoginSuccessPacket; +use ferrumc_net::packets::outgoing::open_screen::OpenScreenPacket; use ferrumc_net::packets::outgoing::registry_data::get_registry_packets; use ferrumc_net::packets::outgoing::set_center_chunk::SetCenterChunk; +use ferrumc_net::packets::outgoing::set_container_slot::{SetContainerSlotPacket, Slot}; use ferrumc_net::packets::outgoing::set_default_spawn_position::SetDefaultSpawnPositionPacket; use ferrumc_net::packets::outgoing::set_render_distance::SetRenderDistance; use ferrumc_net::packets::outgoing::synchronize_player_position::SynchronizePlayerPositionPacket; use ferrumc_net_codec::encode::NetEncodeOpts; +use ferrumc_net_codec::net_types::var_int::VarInt; use ferrumc_state::GlobalState; use tracing::{debug, trace}; @@ -168,6 +172,10 @@ async fn handle_ack_finish_configuration( &NetEncodeOpts::WithLength, ) .await?; + + let inventory = Inventory::new(1, "Outspending's Inventory", InventoryType::Chest(4)); + inventory.send_packet(&mut *writer).await?; + send_keep_alive(conn_id, state, &mut writer).await?; Ok(ack_finish_configuration_event) diff --git a/src/lib/inventory/Cargo.toml b/src/lib/inventory/Cargo.toml new file mode 100644 index 00000000..09619e60 --- /dev/null +++ b/src/lib/inventory/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "ferrumc-inventory" +description = "Implements Inventory Capablities to FerrumC" +version = "0.1.0" +edition = "2024" + +[dependencies] +ferrumc-net = { workspace = true } +ferrumc-net-codec = { workspace = true } +ferrumc-text = { workspace = true } +dashmap = { workspace = true } + +[lints] +workspace = true diff --git a/src/lib/inventory/src/contents.rs b/src/lib/inventory/src/contents.rs new file mode 100644 index 00000000..628e81e9 --- /dev/null +++ b/src/lib/inventory/src/contents.rs @@ -0,0 +1,22 @@ +use dashmap::DashMap; + +pub struct InventoryContents { + pub contents: DashMap, +} + +impl InventoryContents { + pub fn empty() -> Self { + Self { + contents: DashMap::new(), + } + } + + pub fn set_slot(&mut self, slot: i32, item: i32) -> &mut Self { + self.contents.insert(slot, item); + self + } + + pub fn get_slot(&self, item: i32) -> Option { + self.contents.get(&item).map(|v| *v) + } +} diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs new file mode 100644 index 00000000..05a96220 --- /dev/null +++ b/src/lib/inventory/src/inventory.rs @@ -0,0 +1,106 @@ +use crate::contents::InventoryContents; +use ferrumc_net::connection::StreamWriter; +use ferrumc_net::errors::NetError; +use ferrumc_net::packets::outgoing::open_screen::OpenScreenPacket; +use ferrumc_net::packets::outgoing::set_container_slot::{SetContainerSlotPacket, Slot}; +use ferrumc_net_codec::encode::NetEncodeOpts; +use ferrumc_net_codec::net_types::var_int::VarInt; +use ferrumc_text::{TextComponent, TextComponentBuilder}; +use std::ops::Deref; +use std::sync::Arc; + +pub enum InventoryType { + Chest(i8), + Anvil, + Beacon, + BlastFurnace, + BrewingStand, + CraftingTable, + EnchantmentTable, + Furnace, + Grindstone, + Hopper, + Lectern, + Loom, + Merchant, + ShulkerBox, + SmithingTable, + Smoker, + Cartography, + Stonecutter, +} + +impl InventoryType { + pub fn get_id(&self) -> VarInt { + let id = match self { + InventoryType::Chest(i) => { + let value = *i as i32; + if value >= 1 && value <= 6 { + value - 1 + } else { + 0 // defaults to 1 row chest + } + } + InventoryType::Anvil => 8, + InventoryType::Beacon => 9, + InventoryType::BlastFurnace => 10, + InventoryType::BrewingStand => 11, + InventoryType::CraftingTable => 12, + InventoryType::EnchantmentTable => 13, + InventoryType::Furnace => 14, + InventoryType::Grindstone => 15, + InventoryType::Hopper => 16, + InventoryType::Lectern => 17, + InventoryType::Loom => 18, + InventoryType::Merchant => 19, + InventoryType::ShulkerBox => 20, + InventoryType::SmithingTable => 21, + InventoryType::Smoker => 22, + InventoryType::Cartography => 23, + InventoryType::Stonecutter => 24, + }; + + VarInt::new(id) + } +} + +pub struct Inventory { + pub id: VarInt, + pub inventory_type: InventoryType, + pub contents: InventoryContents, + pub title: TextComponent, +} + +impl Inventory { + pub fn new>(id: i32, title: S, inventory_type: InventoryType) -> Self { + Self { + id: VarInt::new(id), + inventory_type, + contents: InventoryContents::empty(), + title: TextComponentBuilder::new(title).build(), + } + } + + pub async fn send_packet(self, writer: &mut StreamWriter) -> Result<(), NetError> { + let id = self.id; + let packet = OpenScreenPacket::new(id.clone(), self.inventory_type.get_id(), self.title); + + writer + .send_packet(&packet, &NetEncodeOpts::WithLength) + .await?; + + // Temporary until i get container content setup + for slot in self.contents.contents.iter() { + let slot_packet = SetContainerSlotPacket::new( + id.clone(), + *slot.key() as i16, + Slot::with_item(1, *slot.value()), + ); + writer + .send_packet(&slot_packet, &NetEncodeOpts::SizePrefixed) + .await?; + } + + Ok(()) + } +} diff --git a/src/lib/inventory/src/lib.rs b/src/lib/inventory/src/lib.rs new file mode 100644 index 00000000..214fd6b8 --- /dev/null +++ b/src/lib/inventory/src/lib.rs @@ -0,0 +1,2 @@ +pub mod contents; +pub mod inventory; \ No newline at end of file diff --git a/src/lib/net/src/packets/outgoing/mod.rs b/src/lib/net/src/packets/outgoing/mod.rs index 9c63db7c..9356775f 100644 --- a/src/lib/net/src/packets/outgoing/mod.rs +++ b/src/lib/net/src/packets/outgoing/mod.rs @@ -6,9 +6,11 @@ pub mod game_event; pub mod keep_alive; pub mod login_play; pub mod login_success; +pub mod open_screen; pub mod ping_response; pub mod registry_data; pub mod set_center_chunk; +pub mod set_container_slot; pub mod set_default_spawn_position; pub mod set_render_distance; pub mod status_response; diff --git a/src/lib/net/src/packets/outgoing/open_screen.rs b/src/lib/net/src/packets/outgoing/open_screen.rs new file mode 100644 index 00000000..e4b82a4d --- /dev/null +++ b/src/lib/net/src/packets/outgoing/open_screen.rs @@ -0,0 +1,30 @@ +use ferrumc_macros::{packet, NetEncode}; +use ferrumc_net_codec::net_types::var_int::VarInt; +use ferrumc_text::{TextComponent, TextComponentBuilder}; +use std::io::Write; + +#[derive(NetEncode)] +#[packet(packet_id = 0x33)] +pub struct OpenScreenPacket { + pub window_id: VarInt, + pub window_type: VarInt, + pub window_title: TextComponent, +} + +impl OpenScreenPacket { + pub fn new(window_id: VarInt, window_type: VarInt, window_title: TextComponent) -> Self { + Self { + window_id, + window_type, + window_title, + } + } + + pub fn with_empty_title(window_id: VarInt, window_type: VarInt) -> Self { + Self::new( + window_id, + window_type, + TextComponentBuilder::new("Inventory").build(), + ) + } +} diff --git a/src/lib/net/src/packets/outgoing/set_container_slot.rs b/src/lib/net/src/packets/outgoing/set_container_slot.rs new file mode 100644 index 00000000..e1f20dec --- /dev/null +++ b/src/lib/net/src/packets/outgoing/set_container_slot.rs @@ -0,0 +1,56 @@ +use ferrumc_macros::{packet, NetEncode}; +use ferrumc_net_codec::net_types::var_int::VarInt; +use std::io::Write; + +#[derive(NetEncode)] +pub struct Slot { + pub item_count: VarInt, + pub item_id: Option, + pub num_of_components_to_add: Option, + pub num_of_components_to_remove: Option, +} + +impl Slot { + pub fn new(item_count: VarInt) -> Self { + Self { + item_count, + item_id: None, + num_of_components_to_add: None, + num_of_components_to_remove: None, + } + } + + pub fn with_item(item_count: i32, item_id: i32) -> Self { + Self { + item_count: VarInt::new(item_count), + item_id: Some(VarInt::new(item_id)), + num_of_components_to_add: Some(VarInt::new(0)), + num_of_components_to_remove: Some(VarInt::new(0)), + } + } + + pub fn item_id(&mut self, item_id: VarInt) -> &mut Self { + self.item_id = Some(item_id); + self + } +} + +#[derive(NetEncode)] +#[packet(packet_id = 0x15)] +pub struct SetContainerSlotPacket { + pub window_id: VarInt, + pub state_id: VarInt, + pub slot: i16, + pub slot_data: Slot, +} + +impl SetContainerSlotPacket { + pub fn new(window_id: VarInt, slot: i16, slot_data: Slot) -> Self { + Self { + window_id, + state_id: VarInt::new(0), + slot, + slot_data, + } + } +} From 06899a88705d21572bf1dfe112b11e6d196b8c72 Mon Sep 17 00:00:00 2001 From: Outspending Date: Sun, 29 Dec 2024 16:42:28 -0700 Subject: [PATCH 02/38] better slot system + sized inventories --- src/bin/src/packet_handlers/login_process.rs | 8 +-- src/lib/inventory/src/contents.rs | 9 +-- src/lib/inventory/src/inventory.rs | 57 +++++++++++++++---- src/lib/inventory/src/lib.rs | 3 +- src/lib/inventory/src/slot.rs | 21 +++++++ .../packets/outgoing/set_container_slot.rs | 19 ++----- 6 files changed, 83 insertions(+), 34 deletions(-) create mode 100644 src/lib/inventory/src/slot.rs diff --git a/src/bin/src/packet_handlers/login_process.rs b/src/bin/src/packet_handlers/login_process.rs index c45286b7..1babf614 100644 --- a/src/bin/src/packet_handlers/login_process.rs +++ b/src/bin/src/packet_handlers/login_process.rs @@ -4,6 +4,7 @@ use ferrumc_core::transform::position::Position; use ferrumc_core::transform::rotation::Rotation; use ferrumc_ecs::components::storage::ComponentRefMut; use ferrumc_inventory::inventory::{Inventory, InventoryType}; +use ferrumc_inventory::slot::Slot; use ferrumc_macros::event_handler; use ferrumc_net::connection::{ConnectionState, StreamWriter}; use ferrumc_net::errors::NetError; @@ -18,15 +19,12 @@ use ferrumc_net::packets::outgoing::game_event::GameEventPacket; use ferrumc_net::packets::outgoing::keep_alive::OutgoingKeepAlivePacket; use ferrumc_net::packets::outgoing::login_play::LoginPlayPacket; use ferrumc_net::packets::outgoing::login_success::LoginSuccessPacket; -use ferrumc_net::packets::outgoing::open_screen::OpenScreenPacket; use ferrumc_net::packets::outgoing::registry_data::get_registry_packets; use ferrumc_net::packets::outgoing::set_center_chunk::SetCenterChunk; -use ferrumc_net::packets::outgoing::set_container_slot::{SetContainerSlotPacket, Slot}; use ferrumc_net::packets::outgoing::set_default_spawn_position::SetDefaultSpawnPositionPacket; use ferrumc_net::packets::outgoing::set_render_distance::SetRenderDistance; use ferrumc_net::packets::outgoing::synchronize_player_position::SynchronizePlayerPositionPacket; use ferrumc_net_codec::encode::NetEncodeOpts; -use ferrumc_net_codec::net_types::var_int::VarInt; use ferrumc_state::GlobalState; use tracing::{debug, trace}; @@ -173,7 +171,9 @@ async fn handle_ack_finish_configuration( ) .await?; - let inventory = Inventory::new(1, "Outspending's Inventory", InventoryType::Chest(4)); + let mut inventory = Inventory::new(1, "Outspending's Inventory", InventoryType::Chest(4)); + inventory.set_slot(0, Slot::new(1, 94)); + inventory.send_packet(&mut *writer).await?; send_keep_alive(conn_id, state, &mut writer).await?; diff --git a/src/lib/inventory/src/contents.rs b/src/lib/inventory/src/contents.rs index 628e81e9..60defa53 100644 --- a/src/lib/inventory/src/contents.rs +++ b/src/lib/inventory/src/contents.rs @@ -1,7 +1,8 @@ +use crate::slot::Slot; use dashmap::DashMap; pub struct InventoryContents { - pub contents: DashMap, + pub contents: DashMap, } impl InventoryContents { @@ -11,12 +12,12 @@ impl InventoryContents { } } - pub fn set_slot(&mut self, slot: i32, item: i32) -> &mut Self { - self.contents.insert(slot, item); + pub fn set_slot(&mut self, slot_id: i32, slot: Slot) -> &mut Self { + self.contents.insert(slot_id, slot); self } - pub fn get_slot(&self, item: i32) -> Option { + pub fn get_slot(&self, item: i32) -> Option { self.contents.get(&item).map(|v| *v) } } diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs index 05a96220..579397e3 100644 --- a/src/lib/inventory/src/inventory.rs +++ b/src/lib/inventory/src/inventory.rs @@ -1,13 +1,12 @@ use crate::contents::InventoryContents; +use crate::slot::Slot; use ferrumc_net::connection::StreamWriter; use ferrumc_net::errors::NetError; use ferrumc_net::packets::outgoing::open_screen::OpenScreenPacket; -use ferrumc_net::packets::outgoing::set_container_slot::{SetContainerSlotPacket, Slot}; +use ferrumc_net::packets::outgoing::set_container_slot::SetContainerSlotPacket; use ferrumc_net_codec::encode::NetEncodeOpts; use ferrumc_net_codec::net_types::var_int::VarInt; use ferrumc_text::{TextComponent, TextComponentBuilder}; -use std::ops::Deref; -use std::sync::Arc; pub enum InventoryType { Chest(i8), @@ -20,9 +19,10 @@ pub enum InventoryType { Furnace, Grindstone, Hopper, + Dispenser, + Dropper, Lectern, Loom, - Merchant, ShulkerBox, SmithingTable, Smoker, @@ -50,9 +50,9 @@ impl InventoryType { InventoryType::Furnace => 14, InventoryType::Grindstone => 15, InventoryType::Hopper => 16, + InventoryType::Dispenser | InventoryType::Dropper => 6, InventoryType::Lectern => 17, InventoryType::Loom => 18, - InventoryType::Merchant => 19, InventoryType::ShulkerBox => 20, InventoryType::SmithingTable => 21, InventoryType::Smoker => 22, @@ -62,12 +62,32 @@ impl InventoryType { VarInt::new(id) } + + pub fn get_size(&self) -> i32 { + match self { + InventoryType::Chest(i) => *i as i32 * 9, + InventoryType::Anvil + | InventoryType::BlastFurnace + | InventoryType::Furnace + | InventoryType::Smoker + | InventoryType::Cartography + | InventoryType::Grindstone => 2, + InventoryType::Stonecutter | InventoryType::EnchantmentTable => 1, + InventoryType::Dispenser | InventoryType::Dropper => 8, + InventoryType::Loom | InventoryType::SmithingTable => 3, + InventoryType::Beacon => 0, + InventoryType::Hopper => 4, + InventoryType::ShulkerBox => 26, + InventoryType::CraftingTable => 9, + _ => 0, + } + } } pub struct Inventory { pub id: VarInt, pub inventory_type: InventoryType, - pub contents: InventoryContents, + pub(crate) contents: InventoryContents, pub title: TextComponent, } @@ -81,6 +101,24 @@ impl Inventory { } } + pub fn set_slot(&mut self, slot_id: i32, slot: Slot) -> &mut Self { + let size = self.inventory_type.get_size(); + if size >= 0 && size <= slot_id { + self.contents.set_slot(slot_id, slot); + } + + self + } + + pub fn get_slot(&self, slot_id: i32) -> Option { + let size = self.inventory_type.get_size(); + if size >= 0 && size <= slot_id { + self.contents.get_slot(slot_id) + } else { + None + } + } + pub async fn send_packet(self, writer: &mut StreamWriter) -> Result<(), NetError> { let id = self.id; let packet = OpenScreenPacket::new(id.clone(), self.inventory_type.get_id(), self.title); @@ -91,11 +129,8 @@ impl Inventory { // Temporary until i get container content setup for slot in self.contents.contents.iter() { - let slot_packet = SetContainerSlotPacket::new( - id.clone(), - *slot.key() as i16, - Slot::with_item(1, *slot.value()), - ); + let slot_packet = + SetContainerSlotPacket::new(id.clone(), *slot.key() as i16, slot.to_network_slot()); writer .send_packet(&slot_packet, &NetEncodeOpts::SizePrefixed) .await?; diff --git a/src/lib/inventory/src/lib.rs b/src/lib/inventory/src/lib.rs index 214fd6b8..c93bc831 100644 --- a/src/lib/inventory/src/lib.rs +++ b/src/lib/inventory/src/lib.rs @@ -1,2 +1,3 @@ pub mod contents; -pub mod inventory; \ No newline at end of file +pub mod inventory; +pub mod slot; diff --git a/src/lib/inventory/src/slot.rs b/src/lib/inventory/src/slot.rs new file mode 100644 index 00000000..aebedf63 --- /dev/null +++ b/src/lib/inventory/src/slot.rs @@ -0,0 +1,21 @@ +use ferrumc_net::packets::outgoing::set_container_slot::NetworkSlot; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Slot { + pub count: i32, + pub item: i32, +} + +impl Slot { + pub fn new(count: i32, item: i32) -> Self { + Self { count, item } + } + + pub fn with_item(item: i32) -> Self { + Self::new(1, item) + } + + pub fn to_network_slot(&self) -> NetworkSlot { + NetworkSlot::new(self.count, self.item) + } +} 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 e1f20dec..5dc7f6cf 100644 --- a/src/lib/net/src/packets/outgoing/set_container_slot.rs +++ b/src/lib/net/src/packets/outgoing/set_container_slot.rs @@ -3,24 +3,15 @@ use ferrumc_net_codec::net_types::var_int::VarInt; use std::io::Write; #[derive(NetEncode)] -pub struct Slot { +pub struct NetworkSlot { pub item_count: VarInt, pub item_id: Option, pub num_of_components_to_add: Option, pub num_of_components_to_remove: Option, } -impl Slot { - pub fn new(item_count: VarInt) -> Self { - Self { - item_count, - item_id: None, - num_of_components_to_add: None, - num_of_components_to_remove: None, - } - } - - pub fn with_item(item_count: i32, item_id: i32) -> Self { +impl NetworkSlot { + pub fn new(item_count: i32, item_id: i32) -> Self { Self { item_count: VarInt::new(item_count), item_id: Some(VarInt::new(item_id)), @@ -41,11 +32,11 @@ pub struct SetContainerSlotPacket { pub window_id: VarInt, pub state_id: VarInt, pub slot: i16, - pub slot_data: Slot, + pub slot_data: NetworkSlot, } impl SetContainerSlotPacket { - pub fn new(window_id: VarInt, slot: i16, slot_data: Slot) -> Self { + pub fn new(window_id: VarInt, slot: i16, slot_data: NetworkSlot) -> Self { Self { window_id, state_id: VarInt::new(0), From 5cfaa0a00085ab18b4372ca20d87fb78443ae5e4 Mon Sep 17 00:00:00 2001 From: Outspending Date: Sun, 29 Dec 2024 17:06:14 -0700 Subject: [PATCH 03/38] Simple Viewer System --- src/bin/src/packet_handlers/login_process.rs | 5 -- src/lib/inventory/Cargo.toml | 1 + src/lib/inventory/src/inventory.rs | 24 +----- src/lib/inventory/src/lib.rs | 1 + src/lib/inventory/src/viewers.rs | 85 +++++++++++++++++++ .../net/crates/codec/src/net_types/var_int.rs | 15 ++++ .../src/packets/outgoing/close_container.rs | 14 +++ src/lib/net/src/packets/outgoing/mod.rs | 1 + 8 files changed, 121 insertions(+), 25 deletions(-) create mode 100644 src/lib/inventory/src/viewers.rs create mode 100644 src/lib/net/src/packets/outgoing/close_container.rs diff --git a/src/bin/src/packet_handlers/login_process.rs b/src/bin/src/packet_handlers/login_process.rs index 1babf614..1aa7b73f 100644 --- a/src/bin/src/packet_handlers/login_process.rs +++ b/src/bin/src/packet_handlers/login_process.rs @@ -171,11 +171,6 @@ async fn handle_ack_finish_configuration( ) .await?; - let mut inventory = Inventory::new(1, "Outspending's Inventory", InventoryType::Chest(4)); - inventory.set_slot(0, Slot::new(1, 94)); - - inventory.send_packet(&mut *writer).await?; - send_keep_alive(conn_id, state, &mut writer).await?; Ok(ack_finish_configuration_event) diff --git a/src/lib/inventory/Cargo.toml b/src/lib/inventory/Cargo.toml index 09619e60..4869d36b 100644 --- a/src/lib/inventory/Cargo.toml +++ b/src/lib/inventory/Cargo.toml @@ -8,6 +8,7 @@ edition = "2024" ferrumc-net = { workspace = true } ferrumc-net-codec = { workspace = true } ferrumc-text = { workspace = true } +ferrumc-ecs = { workspace = true } dashmap = { workspace = true } [lints] diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs index 579397e3..d4812589 100644 --- a/src/lib/inventory/src/inventory.rs +++ b/src/lib/inventory/src/inventory.rs @@ -1,5 +1,6 @@ use crate::contents::InventoryContents; use crate::slot::Slot; +use crate::viewers::InventoryView; use ferrumc_net::connection::StreamWriter; use ferrumc_net::errors::NetError; use ferrumc_net::packets::outgoing::open_screen::OpenScreenPacket; @@ -84,10 +85,12 @@ impl InventoryType { } } +#[derive()] pub struct Inventory { pub id: VarInt, pub inventory_type: InventoryType, pub(crate) contents: InventoryContents, + pub view: InventoryView, pub title: TextComponent, } @@ -97,6 +100,7 @@ impl Inventory { id: VarInt::new(id), inventory_type, contents: InventoryContents::empty(), + view: InventoryView::new(), title: TextComponentBuilder::new(title).build(), } } @@ -118,24 +122,4 @@ impl Inventory { None } } - - pub async fn send_packet(self, writer: &mut StreamWriter) -> Result<(), NetError> { - let id = self.id; - let packet = OpenScreenPacket::new(id.clone(), self.inventory_type.get_id(), self.title); - - writer - .send_packet(&packet, &NetEncodeOpts::WithLength) - .await?; - - // Temporary until i get container content setup - for slot in self.contents.contents.iter() { - let slot_packet = - SetContainerSlotPacket::new(id.clone(), *slot.key() as i16, slot.to_network_slot()); - writer - .send_packet(&slot_packet, &NetEncodeOpts::SizePrefixed) - .await?; - } - - Ok(()) - } } diff --git a/src/lib/inventory/src/lib.rs b/src/lib/inventory/src/lib.rs index c93bc831..9524d899 100644 --- a/src/lib/inventory/src/lib.rs +++ b/src/lib/inventory/src/lib.rs @@ -1,3 +1,4 @@ pub mod contents; pub mod inventory; pub mod slot; +mod viewers; diff --git a/src/lib/inventory/src/viewers.rs b/src/lib/inventory/src/viewers.rs new file mode 100644 index 00000000..311efd6c --- /dev/null +++ b/src/lib/inventory/src/viewers.rs @@ -0,0 +1,85 @@ +use crate::inventory::Inventory; +use ferrumc_ecs::entities::Entity; +use ferrumc_ecs::errors::ECSError; +use ferrumc_net::connection::StreamWriter; +use ferrumc_net::errors::NetError; +use ferrumc_net::packets::outgoing::close_container::CloseContainerPacket; +use ferrumc_net::packets::outgoing::open_screen::OpenScreenPacket; +use ferrumc_net::packets::outgoing::set_container_slot::SetContainerSlotPacket; +use ferrumc_net_codec::encode::NetEncodeOpts; + +pub struct InventoryView { + pub viewers: Vec, +} + +impl InventoryView { + pub fn new() -> Self { + Self { + viewers: Vec::new(), + } + } + + pub async fn add_viewer( + &mut self, + inventory: &Inventory, + mut entity: (Entity, &mut StreamWriter), + ) -> Result<&mut Self, NetError> { + let mut viewers = &self.viewers; + if viewers.contains(&entity.0) { + return Ok(self); + } + + self.viewers.push(entity.0); + self.send_packet(inventory, &mut entity.1).await?; + Ok(self) + } + + pub async fn remove_viewer( + &mut self, + inventory: &Inventory, + mut entity: (Entity, &mut StreamWriter), + ) -> Result<&mut Self, NetError> { + let mut viewers = &mut self.viewers; + if let Some(index) = viewers.iter().position(|&viewer| viewer == entity.0) { + viewers.remove(index); + entity + .1 + .send_packet( + &CloseContainerPacket::new(*inventory.id as u8), + &NetEncodeOpts::WithLength, + ) + .await?; + Ok(self) + } else { + Err(NetError::ECSError(ECSError::ComponentNotFound))? + } + } + + async fn send_packet( + &mut self, + inventory: &Inventory, + writer: &mut StreamWriter, + ) -> Result<(), NetError> { + let id = &inventory.id; + let packet = OpenScreenPacket::new( + id.clone(), + inventory.inventory_type.get_id(), + inventory.title.clone(), + ); + + writer + .send_packet(&packet, &NetEncodeOpts::WithLength) + .await?; + + // Temporary until i get container content setup + for slot in inventory.contents.contents.iter() { + let slot_packet = + SetContainerSlotPacket::new(id.clone(), *slot.key() as i16, slot.to_network_slot()); + writer + .send_packet(&slot_packet, &NetEncodeOpts::SizePrefixed) + .await?; + } + + Ok(()) + } +} diff --git a/src/lib/net/crates/codec/src/net_types/var_int.rs b/src/lib/net/crates/codec/src/net_types/var_int.rs index 33231791..6a390a97 100644 --- a/src/lib/net/crates/codec/src/net_types/var_int.rs +++ b/src/lib/net/crates/codec/src/net_types/var_int.rs @@ -6,6 +6,7 @@ use crate::net_types::NetTypesError; use bitcode::{Decode, Encode}; use deepsize::DeepSizeOf; use std::io::{Read, Write}; +use std::ops::{Deref, DerefMut}; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; #[derive(Debug, Encode, Decode, Clone, DeepSizeOf)] @@ -16,6 +17,20 @@ pub struct VarInt { pub len: usize, } +impl Deref for VarInt { + type Target = i32; + + fn deref(&self) -> &Self::Target { + &self.val + } +} + +impl DerefMut for VarInt { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.val + } +} + mod adapters { use crate::net_types::var_int::VarInt; diff --git a/src/lib/net/src/packets/outgoing/close_container.rs b/src/lib/net/src/packets/outgoing/close_container.rs new file mode 100644 index 00000000..2157254d --- /dev/null +++ b/src/lib/net/src/packets/outgoing/close_container.rs @@ -0,0 +1,14 @@ +use ferrumc_macros::{packet, NetEncode}; +use std::io::Write; + +#[derive(NetEncode)] +#[packet(packet_id = 0x12)] +pub struct CloseContainerPacket { + pub window_id: u8, +} + +impl CloseContainerPacket { + pub fn new(window_id: u8) -> Self { + Self { window_id } + } +} diff --git a/src/lib/net/src/packets/outgoing/mod.rs b/src/lib/net/src/packets/outgoing/mod.rs index 9356775f..efad2930 100644 --- a/src/lib/net/src/packets/outgoing/mod.rs +++ b/src/lib/net/src/packets/outgoing/mod.rs @@ -1,5 +1,6 @@ pub mod chunk_and_light_data; pub mod client_bound_known_packs; +pub mod close_container; pub mod disconnect; pub mod finish_configuration; pub mod game_event; From 7dbdab0d454e4c4e4b2f546992fd98d21c163102 Mon Sep 17 00:00:00 2001 From: Outspending Date: Sun, 29 Dec 2024 18:47:26 -0700 Subject: [PATCH 04/38] QOL Changes --- src/lib/inventory/src/contents.rs | 1 + src/lib/inventory/src/inventory.rs | 59 +++++++++++++++++-- src/lib/inventory/src/lib.rs | 3 +- src/lib/inventory/src/types/mod.rs | 1 + src/lib/inventory/src/viewers.rs | 40 +++++++++---- .../net/crates/codec/src/net_types/var_int.rs | 2 +- 6 files changed, 88 insertions(+), 18 deletions(-) create mode 100644 src/lib/inventory/src/types/mod.rs diff --git a/src/lib/inventory/src/contents.rs b/src/lib/inventory/src/contents.rs index 60defa53..1f508579 100644 --- a/src/lib/inventory/src/contents.rs +++ b/src/lib/inventory/src/contents.rs @@ -1,6 +1,7 @@ use crate::slot::Slot; use dashmap::DashMap; +#[derive(Debug, Clone)] pub struct InventoryContents { pub contents: DashMap, } diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs index d4812589..cc8c86ed 100644 --- a/src/lib/inventory/src/inventory.rs +++ b/src/lib/inventory/src/inventory.rs @@ -1,14 +1,12 @@ use crate::contents::InventoryContents; use crate::slot::Slot; use crate::viewers::InventoryView; -use ferrumc_net::connection::StreamWriter; -use ferrumc_net::errors::NetError; -use ferrumc_net::packets::outgoing::open_screen::OpenScreenPacket; -use ferrumc_net::packets::outgoing::set_container_slot::SetContainerSlotPacket; -use ferrumc_net_codec::encode::NetEncodeOpts; +use dashmap::DashMap; +use ferrumc_ecs::entities::Entity; use ferrumc_net_codec::net_types::var_int::VarInt; use ferrumc_text::{TextComponent, TextComponentBuilder}; +#[derive(Debug, Clone, Copy)] pub enum InventoryType { Chest(i8), Anvil, @@ -85,7 +83,7 @@ impl InventoryType { } } -#[derive()] +#[derive(Debug, Clone)] pub struct Inventory { pub id: VarInt, pub inventory_type: InventoryType, @@ -122,4 +120,53 @@ impl Inventory { None } } + + pub fn get_viewers(&self) -> &Vec { + &self.view.viewers + } + + pub fn get_contents(&self) -> &DashMap { + &self.contents.contents + } + + pub fn clear(&mut self) { + self.get_contents().clear(); + } + + pub fn contains(&self, item: i32) -> bool { + self.get_contents() + .iter() + .any(|slot| slot.value().item == item) + } + + pub fn contains_slot(&self, slot: Slot) -> bool { + self.contains(slot.item) + } + + pub fn get_first_empty(&self) -> i32 { + let contents = self.get_contents(); + for i in 0..self.get_size() { + if let None = contents.get(&i) { + return i; + } + } + + return 0; + } + + pub fn get_size(&self) -> i32 { + self.inventory_type.get_size() + } + + pub fn is_empty(&self) -> bool { + self.get_contents().is_empty() + } + + pub fn is_full(&self) -> bool { + if self.get_contents().len() == self.get_size() as usize { + true + } else { + false + } + } } diff --git a/src/lib/inventory/src/lib.rs b/src/lib/inventory/src/lib.rs index 9524d899..ffc6142e 100644 --- a/src/lib/inventory/src/lib.rs +++ b/src/lib/inventory/src/lib.rs @@ -1,4 +1,5 @@ pub mod contents; pub mod inventory; pub mod slot; -mod viewers; +pub mod types; +pub mod viewers; diff --git a/src/lib/inventory/src/types/mod.rs b/src/lib/inventory/src/types/mod.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/lib/inventory/src/types/mod.rs @@ -0,0 +1 @@ + diff --git a/src/lib/inventory/src/viewers.rs b/src/lib/inventory/src/viewers.rs index 311efd6c..9b9aa339 100644 --- a/src/lib/inventory/src/viewers.rs +++ b/src/lib/inventory/src/viewers.rs @@ -1,4 +1,4 @@ -use crate::inventory::Inventory; +use crate::{inventory::Inventory, slot::Slot}; use ferrumc_ecs::entities::Entity; use ferrumc_ecs::errors::ECSError; use ferrumc_net::connection::StreamWriter; @@ -6,14 +6,15 @@ use ferrumc_net::errors::NetError; use ferrumc_net::packets::outgoing::close_container::CloseContainerPacket; use ferrumc_net::packets::outgoing::open_screen::OpenScreenPacket; use ferrumc_net::packets::outgoing::set_container_slot::SetContainerSlotPacket; -use ferrumc_net_codec::encode::NetEncodeOpts; +use ferrumc_net_codec::encode::{NetEncode, NetEncodeOpts}; +#[derive(Debug, Clone)] pub struct InventoryView { pub viewers: Vec, } impl InventoryView { - pub fn new() -> Self { + pub(crate) fn new() -> Self { Self { viewers: Vec::new(), } @@ -24,7 +25,7 @@ impl InventoryView { inventory: &Inventory, mut entity: (Entity, &mut StreamWriter), ) -> Result<&mut Self, NetError> { - let mut viewers = &self.viewers; + let viewers = &self.viewers; if viewers.contains(&entity.0) { return Ok(self); } @@ -37,9 +38,9 @@ impl InventoryView { pub async fn remove_viewer( &mut self, inventory: &Inventory, - mut entity: (Entity, &mut StreamWriter), + entity: (Entity, &mut StreamWriter), ) -> Result<&mut Self, NetError> { - let mut viewers = &mut self.viewers; + let viewers = &mut self.viewers; if let Some(index) = viewers.iter().position(|&viewer| viewer == entity.0) { viewers.remove(index); entity @@ -55,14 +56,30 @@ impl InventoryView { } } + pub async fn send_slot_update_packet( + &self, + inventory: &Inventory, + slot: (i16, Slot), + ) -> Result<(), NetError> { + self.send_packet_to_viewers(&SetContainerSlotPacket::new( + inventory.id, + slot.0, + slot.1.to_network_slot(), + )) + .await + } + + async fn send_packet_to_viewers(&self, _packet: &impl NetEncode) -> Result<(), NetError> { + Ok(()) + } + async fn send_packet( &mut self, inventory: &Inventory, writer: &mut StreamWriter, ) -> Result<(), NetError> { - let id = &inventory.id; let packet = OpenScreenPacket::new( - id.clone(), + inventory.id, inventory.inventory_type.get_id(), inventory.title.clone(), ); @@ -73,8 +90,11 @@ impl InventoryView { // Temporary until i get container content setup for slot in inventory.contents.contents.iter() { - let slot_packet = - SetContainerSlotPacket::new(id.clone(), *slot.key() as i16, slot.to_network_slot()); + let slot_packet = SetContainerSlotPacket::new( + inventory.id, + *slot.key() as i16, + slot.to_network_slot(), + ); writer .send_packet(&slot_packet, &NetEncodeOpts::SizePrefixed) .await?; diff --git a/src/lib/net/crates/codec/src/net_types/var_int.rs b/src/lib/net/crates/codec/src/net_types/var_int.rs index 6a390a97..3c4e6202 100644 --- a/src/lib/net/crates/codec/src/net_types/var_int.rs +++ b/src/lib/net/crates/codec/src/net_types/var_int.rs @@ -9,7 +9,7 @@ use std::io::{Read, Write}; use std::ops::{Deref, DerefMut}; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; -#[derive(Debug, Encode, Decode, Clone, DeepSizeOf)] +#[derive(Debug, Encode, Decode, Clone, Copy, DeepSizeOf)] pub struct VarInt { /// The value of the VarInt. pub val: i32, From e542d665f7ebbffdf79f0af223bb5ccdf408d20f Mon Sep 17 00:00:00 2001 From: Outspending Date: Sun, 29 Dec 2024 18:55:47 -0700 Subject: [PATCH 05/38] tests --- src/lib/inventory/src/inventory.rs | 2 +- src/lib/inventory/src/lib.rs | 2 ++ src/lib/inventory/src/tests.rs | 7 +++++++ 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 src/lib/inventory/src/tests.rs diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs index cc8c86ed..6ca243ee 100644 --- a/src/lib/inventory/src/inventory.rs +++ b/src/lib/inventory/src/inventory.rs @@ -169,4 +169,4 @@ impl Inventory { false } } -} +} \ No newline at end of file diff --git a/src/lib/inventory/src/lib.rs b/src/lib/inventory/src/lib.rs index ffc6142e..952d9154 100644 --- a/src/lib/inventory/src/lib.rs +++ b/src/lib/inventory/src/lib.rs @@ -3,3 +3,5 @@ pub mod inventory; pub mod slot; pub mod types; pub mod viewers; + +mod tests; \ No newline at end of file diff --git a/src/lib/inventory/src/tests.rs b/src/lib/inventory/src/tests.rs new file mode 100644 index 00000000..04f43325 --- /dev/null +++ b/src/lib/inventory/src/tests.rs @@ -0,0 +1,7 @@ +#[test] +fn create_inventory() { + let mut inventory = crate::inventory::Inventory::new(1, "Something", crate::inventory::InventoryType::Chest(4)); + inventory.set_slot(0, crate::slot::Slot::with_item(9)); + + inventory.clear(); +} \ No newline at end of file From 0acaa1b1835691b0c1f3748f5d2489d5f1187aa6 Mon Sep 17 00:00:00 2001 From: Outspending Date: Sun, 29 Dec 2024 19:13:57 -0700 Subject: [PATCH 06/38] Added all related container packets --- src/lib/inventory/src/inventory.rs | 2 +- src/lib/inventory/src/lib.rs | 2 +- src/lib/inventory/src/tests.rs | 5 ++-- src/lib/net/src/packets/outgoing/mod.rs | 2 ++ .../packets/outgoing/set_container_content.rs | 29 +++++++++++++++++++ .../outgoing/set_container_property.rs | 20 +++++++++++++ 6 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 src/lib/net/src/packets/outgoing/set_container_content.rs create mode 100644 src/lib/net/src/packets/outgoing/set_container_property.rs diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs index 6ca243ee..cc8c86ed 100644 --- a/src/lib/inventory/src/inventory.rs +++ b/src/lib/inventory/src/inventory.rs @@ -169,4 +169,4 @@ impl Inventory { false } } -} \ No newline at end of file +} diff --git a/src/lib/inventory/src/lib.rs b/src/lib/inventory/src/lib.rs index 952d9154..917f62e7 100644 --- a/src/lib/inventory/src/lib.rs +++ b/src/lib/inventory/src/lib.rs @@ -4,4 +4,4 @@ pub mod slot; pub mod types; pub mod viewers; -mod tests; \ No newline at end of file +mod tests; diff --git a/src/lib/inventory/src/tests.rs b/src/lib/inventory/src/tests.rs index 04f43325..1788f9ab 100644 --- a/src/lib/inventory/src/tests.rs +++ b/src/lib/inventory/src/tests.rs @@ -1,7 +1,8 @@ #[test] fn create_inventory() { - let mut inventory = crate::inventory::Inventory::new(1, "Something", crate::inventory::InventoryType::Chest(4)); + let mut inventory = + crate::inventory::Inventory::new(1, "Something", crate::inventory::InventoryType::Chest(4)); inventory.set_slot(0, crate::slot::Slot::with_item(9)); inventory.clear(); -} \ No newline at end of file +} diff --git a/src/lib/net/src/packets/outgoing/mod.rs b/src/lib/net/src/packets/outgoing/mod.rs index efad2930..5012f61a 100644 --- a/src/lib/net/src/packets/outgoing/mod.rs +++ b/src/lib/net/src/packets/outgoing/mod.rs @@ -11,6 +11,8 @@ pub mod open_screen; pub mod ping_response; pub mod registry_data; pub mod set_center_chunk; +pub mod set_container_content; +pub mod set_container_property; pub mod set_container_slot; pub mod set_default_spawn_position; pub mod set_render_distance; diff --git a/src/lib/net/src/packets/outgoing/set_container_content.rs b/src/lib/net/src/packets/outgoing/set_container_content.rs new file mode 100644 index 00000000..969dcc20 --- /dev/null +++ b/src/lib/net/src/packets/outgoing/set_container_content.rs @@ -0,0 +1,29 @@ +use ferrumc_macros::{packet, NetEncode}; +use ferrumc_net_codec::net_types::{length_prefixed_vec::LengthPrefixedVec, var_int::VarInt}; +use std::io::Write; + +use super::set_container_slot::NetworkSlot; + +#[derive(NetEncode)] +#[packet(packet_id = 0x13)] +pub struct SetContainerContentPacket { + pub window_id: u8, + pub state_id: VarInt, + pub slot_data: LengthPrefixedVec, + pub carried_item: NetworkSlot, +} + +impl SetContainerContentPacket { + pub fn new( + window_id: u8, + slot_data: LengthPrefixedVec, + carried_item: NetworkSlot, + ) -> Self { + Self { + window_id, + state_id: VarInt::new(0), + slot_data, + carried_item, + } + } +} diff --git a/src/lib/net/src/packets/outgoing/set_container_property.rs b/src/lib/net/src/packets/outgoing/set_container_property.rs new file mode 100644 index 00000000..45d00c84 --- /dev/null +++ b/src/lib/net/src/packets/outgoing/set_container_property.rs @@ -0,0 +1,20 @@ +use ferrumc_macros::{packet, NetEncode}; +use std::io::Write; + +#[derive(NetEncode)] +#[packet(packet_id = 0x14)] +pub struct SetContainerPropertyPacket { + pub window_id: u8, + pub property: u16, + pub value: u16, +} + +impl SetContainerPropertyPacket { + pub fn new(window_id: u8, property: u16, value: u16) -> Self { + Self { + window_id, + property, + value, + } + } +} From bd973c4ed605a50b1e366033c203c92b33f07bf5 Mon Sep 17 00:00:00 2001 From: Outspending Date: Sun, 29 Dec 2024 19:26:50 -0700 Subject: [PATCH 07/38] container content --- src/lib/inventory/src/contents.rs | 16 ++++++++++ src/lib/inventory/src/slot.rs | 3 ++ src/lib/inventory/src/viewers.rs | 29 ++++++++++--------- .../packets/outgoing/set_container_slot.rs | 4 +++ 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/src/lib/inventory/src/contents.rs b/src/lib/inventory/src/contents.rs index 1f508579..ec94d2fb 100644 --- a/src/lib/inventory/src/contents.rs +++ b/src/lib/inventory/src/contents.rs @@ -1,5 +1,7 @@ use crate::slot::Slot; use dashmap::DashMap; +use ferrumc_net::packets::outgoing::set_container_slot::NetworkSlot; +use ferrumc_net_codec::net_types::length_prefixed_vec::LengthPrefixedVec; #[derive(Debug, Clone)] pub struct InventoryContents { @@ -21,4 +23,18 @@ impl InventoryContents { pub fn get_slot(&self, item: i32) -> Option { self.contents.get(&item).map(|v| *v) } + + pub(crate) fn construct_container_vec(&self, size: usize) -> LengthPrefixedVec { + let mut vec = LengthPrefixedVec::new(Vec::with_capacity(size)); + for i in 0..(size as i32) { + let slot = match self.contents.get(&i) { + Some(data) => data.value().to_network_slot(), + None => NetworkSlot::empty(), + }; + + vec.data.insert(i as usize, slot); + } + + vec + } } diff --git a/src/lib/inventory/src/slot.rs b/src/lib/inventory/src/slot.rs index aebedf63..5175bd45 100644 --- a/src/lib/inventory/src/slot.rs +++ b/src/lib/inventory/src/slot.rs @@ -15,6 +15,9 @@ impl Slot { Self::new(1, item) } + pub fn empty() -> Self { + Self::new(0, 0) + } pub fn to_network_slot(&self) -> NetworkSlot { NetworkSlot::new(self.count, self.item) } diff --git a/src/lib/inventory/src/viewers.rs b/src/lib/inventory/src/viewers.rs index 9b9aa339..10c707d7 100644 --- a/src/lib/inventory/src/viewers.rs +++ b/src/lib/inventory/src/viewers.rs @@ -1,11 +1,13 @@ use crate::{inventory::Inventory, slot::Slot}; use ferrumc_ecs::entities::Entity; use ferrumc_ecs::errors::ECSError; -use ferrumc_net::connection::StreamWriter; use ferrumc_net::errors::NetError; use ferrumc_net::packets::outgoing::close_container::CloseContainerPacket; use ferrumc_net::packets::outgoing::open_screen::OpenScreenPacket; -use ferrumc_net::packets::outgoing::set_container_slot::SetContainerSlotPacket; +use ferrumc_net::packets::outgoing::set_container_slot::{NetworkSlot, SetContainerSlotPacket}; +use ferrumc_net::{ + connection::StreamWriter, packets::outgoing::set_container_content::SetContainerContentPacket, +}; use ferrumc_net_codec::encode::{NetEncode, NetEncodeOpts}; #[derive(Debug, Clone)] @@ -88,17 +90,18 @@ impl InventoryView { .send_packet(&packet, &NetEncodeOpts::WithLength) .await?; - // Temporary until i get container content setup - for slot in inventory.contents.contents.iter() { - let slot_packet = SetContainerSlotPacket::new( - inventory.id, - *slot.key() as i16, - slot.to_network_slot(), - ); - writer - .send_packet(&slot_packet, &NetEncodeOpts::SizePrefixed) - .await?; - } + let inventory_size = inventory.inventory_type.get_size() as usize; + let container_content = inventory.contents.construct_container_vec(inventory_size); + writer + .send_packet( + &SetContainerContentPacket::new( + *inventory.id as u8, + container_content, + NetworkSlot::empty(), + ), + &NetEncodeOpts::SizePrefixed, + ) + .await?; Ok(()) } 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 5dc7f6cf..85c58fcf 100644 --- a/src/lib/net/src/packets/outgoing/set_container_slot.rs +++ b/src/lib/net/src/packets/outgoing/set_container_slot.rs @@ -20,6 +20,10 @@ impl NetworkSlot { } } + 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 From d47862bc96296cc28e160c5bf91e3080593d46af Mon Sep 17 00:00:00 2001 From: Outspending Date: Sun, 29 Dec 2024 19:42:20 -0700 Subject: [PATCH 08/38] InventoryData + viewer support --- src/lib/inventory/src/inventory.rs | 46 ++++++++++++++++++++++-------- src/lib/inventory/src/slot.rs | 1 + src/lib/inventory/src/viewers.rs | 9 +++--- 3 files changed, 40 insertions(+), 16 deletions(-) diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs index cc8c86ed..b5f1bf33 100644 --- a/src/lib/inventory/src/inventory.rs +++ b/src/lib/inventory/src/inventory.rs @@ -3,6 +3,7 @@ use crate::slot::Slot; use crate::viewers::InventoryView; use dashmap::DashMap; use ferrumc_ecs::entities::Entity; +use ferrumc_net::connection::StreamWriter; use ferrumc_net_codec::net_types::var_int::VarInt; use ferrumc_text::{TextComponent, TextComponentBuilder}; @@ -84,49 +85,70 @@ impl InventoryType { } #[derive(Debug, Clone)] -pub struct Inventory { +pub struct InventoryData { pub id: VarInt, pub inventory_type: InventoryType, + pub title: TextComponent, pub(crate) contents: InventoryContents, +} + +impl InventoryData { + fn new(id: VarInt, inventory_type: InventoryType, title: TextComponent) -> Self { + Self { + id, + inventory_type, + title, + contents: InventoryContents::empty() + } + } +} + +#[derive(Debug, Clone)] +pub struct Inventory { + pub data: InventoryData, pub view: InventoryView, - pub title: TextComponent, } impl Inventory { pub fn new>(id: i32, title: S, inventory_type: InventoryType) -> Self { Self { - id: VarInt::new(id), - inventory_type, - contents: InventoryContents::empty(), + data: InventoryData::new(VarInt::new(id), inventory_type, TextComponentBuilder::new(title).build()), view: InventoryView::new(), - title: TextComponentBuilder::new(title).build(), } } pub fn set_slot(&mut self, slot_id: i32, slot: Slot) -> &mut Self { - let size = self.inventory_type.get_size(); + let size = self.data.inventory_type.get_size(); if size >= 0 && size <= slot_id { - self.contents.set_slot(slot_id, slot); + self.data.contents.set_slot(slot_id, slot); } self } pub fn get_slot(&self, slot_id: i32) -> Option { - let size = self.inventory_type.get_size(); + let size = self.data.inventory_type.get_size(); if size >= 0 && size <= slot_id { - self.contents.get_slot(slot_id) + self.data.contents.get_slot(slot_id) } else { None } } + pub async fn add_viewer(&mut self, viewer: (Entity, &mut StreamWriter)) { + self.view.add_viewer(&self.data, viewer).await.unwrap(); + } + + pub async fn remove_viewer(&mut self, viewer: (Entity, &mut StreamWriter)) { + self.view.remove_viewer(&self.data, viewer).await.unwrap(); + } + pub fn get_viewers(&self) -> &Vec { &self.view.viewers } pub fn get_contents(&self) -> &DashMap { - &self.contents.contents + &self.data.contents.contents } pub fn clear(&mut self) { @@ -155,7 +177,7 @@ impl Inventory { } pub fn get_size(&self) -> i32 { - self.inventory_type.get_size() + self.data.inventory_type.get_size() } pub fn is_empty(&self) -> bool { diff --git a/src/lib/inventory/src/slot.rs b/src/lib/inventory/src/slot.rs index 5175bd45..42e13b51 100644 --- a/src/lib/inventory/src/slot.rs +++ b/src/lib/inventory/src/slot.rs @@ -18,6 +18,7 @@ impl Slot { pub fn empty() -> Self { Self::new(0, 0) } + pub fn to_network_slot(&self) -> NetworkSlot { NetworkSlot::new(self.count, self.item) } diff --git a/src/lib/inventory/src/viewers.rs b/src/lib/inventory/src/viewers.rs index 10c707d7..542854d7 100644 --- a/src/lib/inventory/src/viewers.rs +++ b/src/lib/inventory/src/viewers.rs @@ -1,3 +1,4 @@ +use crate::inventory::InventoryData; use crate::{inventory::Inventory, slot::Slot}; use ferrumc_ecs::entities::Entity; use ferrumc_ecs::errors::ECSError; @@ -24,7 +25,7 @@ impl InventoryView { pub async fn add_viewer( &mut self, - inventory: &Inventory, + inventory: &InventoryData, mut entity: (Entity, &mut StreamWriter), ) -> Result<&mut Self, NetError> { let viewers = &self.viewers; @@ -39,7 +40,7 @@ impl InventoryView { pub async fn remove_viewer( &mut self, - inventory: &Inventory, + inventory: &InventoryData, entity: (Entity, &mut StreamWriter), ) -> Result<&mut Self, NetError> { let viewers = &mut self.viewers; @@ -60,7 +61,7 @@ impl InventoryView { pub async fn send_slot_update_packet( &self, - inventory: &Inventory, + inventory: &InventoryData, slot: (i16, Slot), ) -> Result<(), NetError> { self.send_packet_to_viewers(&SetContainerSlotPacket::new( @@ -77,7 +78,7 @@ impl InventoryView { async fn send_packet( &mut self, - inventory: &Inventory, + inventory: &InventoryData, writer: &mut StreamWriter, ) -> Result<(), NetError> { let packet = OpenScreenPacket::new( From 802c8b82b9fedc2e86a035a7f9c1ff025eb0fa61 Mon Sep 17 00:00:00 2001 From: Outspending Date: Sun, 29 Dec 2024 19:45:33 -0700 Subject: [PATCH 09/38] updated viewers --- src/lib/inventory/src/inventory.rs | 28 ++++++++++++++++++++-------- src/lib/inventory/src/slot.rs | 2 +- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs index b5f1bf33..4f87d2c4 100644 --- a/src/lib/inventory/src/inventory.rs +++ b/src/lib/inventory/src/inventory.rs @@ -3,7 +3,7 @@ use crate::slot::Slot; use crate::viewers::InventoryView; use dashmap::DashMap; use ferrumc_ecs::entities::Entity; -use ferrumc_net::connection::StreamWriter; +use ferrumc_net::{connection::StreamWriter, errors::NetError}; use ferrumc_net_codec::net_types::var_int::VarInt; use ferrumc_text::{TextComponent, TextComponentBuilder}; @@ -95,10 +95,10 @@ pub struct InventoryData { impl InventoryData { fn new(id: VarInt, inventory_type: InventoryType, title: TextComponent) -> Self { Self { - id, + id, inventory_type, title, - contents: InventoryContents::empty() + contents: InventoryContents::empty(), } } } @@ -112,7 +112,11 @@ pub struct Inventory { impl Inventory { pub fn new>(id: i32, title: S, inventory_type: InventoryType) -> Self { Self { - data: InventoryData::new(VarInt::new(id), inventory_type, TextComponentBuilder::new(title).build()), + data: InventoryData::new( + VarInt::new(id), + inventory_type, + TextComponentBuilder::new(title).build(), + ), view: InventoryView::new(), } } @@ -135,12 +139,20 @@ impl Inventory { } } - pub async fn add_viewer(&mut self, viewer: (Entity, &mut StreamWriter)) { - self.view.add_viewer(&self.data, viewer).await.unwrap(); + pub async fn add_viewer( + &mut self, + viewer: (Entity, &mut StreamWriter), + ) -> Result<(), NetError> { + self.view.add_viewer(&self.data, viewer).await?; + Ok(()) } - pub async fn remove_viewer(&mut self, viewer: (Entity, &mut StreamWriter)) { - self.view.remove_viewer(&self.data, viewer).await.unwrap(); + pub async fn remove_viewer( + &mut self, + viewer: (Entity, &mut StreamWriter), + ) -> Result<(), NetError> { + self.view.remove_viewer(&self.data, viewer).await?; + Ok(()) } pub fn get_viewers(&self) -> &Vec { diff --git a/src/lib/inventory/src/slot.rs b/src/lib/inventory/src/slot.rs index 42e13b51..6ebac983 100644 --- a/src/lib/inventory/src/slot.rs +++ b/src/lib/inventory/src/slot.rs @@ -18,7 +18,7 @@ impl Slot { pub fn empty() -> Self { Self::new(0, 0) } - + pub fn to_network_slot(&self) -> NetworkSlot { NetworkSlot::new(self.count, self.item) } From b9831f98e792b4a6f55d37cb191b2ae44c9f4c7b Mon Sep 17 00:00:00 2001 From: Outspending Date: Sun, 29 Dec 2024 21:53:24 -0700 Subject: [PATCH 10/38] clippy fix --- src/bin/src/packet_handlers/login_process.rs | 5 +++++ src/lib/inventory/src/inventory.rs | 16 ++++++---------- src/lib/inventory/src/viewers.rs | 6 +++--- src/lib/storage/src/lib.rs | 1 - 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/bin/src/packet_handlers/login_process.rs b/src/bin/src/packet_handlers/login_process.rs index 1aa7b73f..24a4f493 100644 --- a/src/bin/src/packet_handlers/login_process.rs +++ b/src/bin/src/packet_handlers/login_process.rs @@ -171,10 +171,15 @@ async fn handle_ack_finish_configuration( ) .await?; + let mut inventory = Inventory::new(1, "Testing", InventoryType::Chest(6)); + inventory.set_slot(0, Slot::with_item(9)); + inventory.add_viewer((conn_id, &mut writer)).await?; + send_keep_alive(conn_id, state, &mut writer).await?; Ok(ack_finish_configuration_event) } + async fn send_keep_alive( conn_id: usize, state: GlobalState, diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs index 4f87d2c4..4653c453 100644 --- a/src/lib/inventory/src/inventory.rs +++ b/src/lib/inventory/src/inventory.rs @@ -34,8 +34,8 @@ impl InventoryType { pub fn get_id(&self) -> VarInt { let id = match self { InventoryType::Chest(i) => { - let value = *i as i32; - if value >= 1 && value <= 6 { + let value = i32::from(*i); + if (1..=6).contains(&value) { value - 1 } else { 0 // defaults to 1 row chest @@ -65,7 +65,7 @@ impl InventoryType { pub fn get_size(&self) -> i32 { match self { - InventoryType::Chest(i) => *i as i32 * 9, + InventoryType::Chest(i) => i32::from(*i) * 9, InventoryType::Anvil | InventoryType::BlastFurnace | InventoryType::Furnace @@ -180,12 +180,12 @@ impl Inventory { pub fn get_first_empty(&self) -> i32 { let contents = self.get_contents(); for i in 0..self.get_size() { - if let None = contents.get(&i) { + if contents.get(&i).is_none() { return i; } } - return 0; + 0 } pub fn get_size(&self) -> i32 { @@ -197,10 +197,6 @@ impl Inventory { } pub fn is_full(&self) -> bool { - if self.get_contents().len() == self.get_size() as usize { - true - } else { - false - } + self.get_contents().len() == self.get_size() as usize } } diff --git a/src/lib/inventory/src/viewers.rs b/src/lib/inventory/src/viewers.rs index 542854d7..b823db54 100644 --- a/src/lib/inventory/src/viewers.rs +++ b/src/lib/inventory/src/viewers.rs @@ -1,5 +1,5 @@ use crate::inventory::InventoryData; -use crate::{inventory::Inventory, slot::Slot}; +use crate::slot::Slot; use ferrumc_ecs::entities::Entity; use ferrumc_ecs::errors::ECSError; use ferrumc_net::errors::NetError; @@ -26,7 +26,7 @@ impl InventoryView { pub async fn add_viewer( &mut self, inventory: &InventoryData, - mut entity: (Entity, &mut StreamWriter), + entity: (Entity, &mut StreamWriter), ) -> Result<&mut Self, NetError> { let viewers = &self.viewers; if viewers.contains(&entity.0) { @@ -34,7 +34,7 @@ impl InventoryView { } self.viewers.push(entity.0); - self.send_packet(inventory, &mut entity.1).await?; + self.send_packet(inventory, entity.1).await?; Ok(self) } diff --git a/src/lib/storage/src/lib.rs b/src/lib/storage/src/lib.rs index 91a57a7f..4bbb6e3d 100644 --- a/src/lib/storage/src/lib.rs +++ b/src/lib/storage/src/lib.rs @@ -1,4 +1,3 @@ -#![feature(async_closure)] pub mod compressors; pub mod errors; pub mod lmdb; From 09bbcc42d88e210865595b32fedce40019e025cb Mon Sep 17 00:00:00 2001 From: Outspending Date: Mon, 30 Dec 2024 07:28:42 -0700 Subject: [PATCH 11/38] clippy + fmt check fixed --- src/bin/src/packet_handlers/login_process.rs | 2 -- src/lib/inventory/src/inventory.rs | 20 ++++++++------------ src/lib/inventory/src/lib.rs | 1 + src/lib/inventory/src/viewers.rs | 6 +++--- src/lib/storage/src/lib.rs | 1 - 5 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/bin/src/packet_handlers/login_process.rs b/src/bin/src/packet_handlers/login_process.rs index 1aa7b73f..ea1ddfa8 100644 --- a/src/bin/src/packet_handlers/login_process.rs +++ b/src/bin/src/packet_handlers/login_process.rs @@ -3,8 +3,6 @@ use ferrumc_core::transform::grounded::OnGround; use ferrumc_core::transform::position::Position; use ferrumc_core::transform::rotation::Rotation; use ferrumc_ecs::components::storage::ComponentRefMut; -use ferrumc_inventory::inventory::{Inventory, InventoryType}; -use ferrumc_inventory::slot::Slot; use ferrumc_macros::event_handler; use ferrumc_net::connection::{ConnectionState, StreamWriter}; use ferrumc_net::errors::NetError; diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs index 4f87d2c4..edb50c6a 100644 --- a/src/lib/inventory/src/inventory.rs +++ b/src/lib/inventory/src/inventory.rs @@ -34,8 +34,8 @@ impl InventoryType { pub fn get_id(&self) -> VarInt { let id = match self { InventoryType::Chest(i) => { - let value = *i as i32; - if value >= 1 && value <= 6 { + let value = i32::from(*i); + if (1..=6).contains(&value) { value - 1 } else { 0 // defaults to 1 row chest @@ -65,7 +65,7 @@ impl InventoryType { pub fn get_size(&self) -> i32 { match self { - InventoryType::Chest(i) => *i as i32 * 9, + InventoryType::Chest(i) => i32::from(*i) * 9, InventoryType::Anvil | InventoryType::BlastFurnace | InventoryType::Furnace @@ -123,7 +123,7 @@ impl Inventory { pub fn set_slot(&mut self, slot_id: i32, slot: Slot) -> &mut Self { let size = self.data.inventory_type.get_size(); - if size >= 0 && size <= slot_id { + if (0..=size).contains(&slot_id) { self.data.contents.set_slot(slot_id, slot); } @@ -132,7 +132,7 @@ impl Inventory { pub fn get_slot(&self, slot_id: i32) -> Option { let size = self.data.inventory_type.get_size(); - if size >= 0 && size <= slot_id { + if (0..=size).contains(&slot_id) { self.data.contents.get_slot(slot_id) } else { None @@ -180,12 +180,12 @@ impl Inventory { pub fn get_first_empty(&self) -> i32 { let contents = self.get_contents(); for i in 0..self.get_size() { - if let None = contents.get(&i) { + if contents.get(&i).is_none() { return i; } } - return 0; + 0 } pub fn get_size(&self) -> i32 { @@ -197,10 +197,6 @@ impl Inventory { } pub fn is_full(&self) -> bool { - if self.get_contents().len() == self.get_size() as usize { - true - } else { - false - } + self.get_contents().len() == self.get_size() as usize } } diff --git a/src/lib/inventory/src/lib.rs b/src/lib/inventory/src/lib.rs index 917f62e7..87ca26f4 100644 --- a/src/lib/inventory/src/lib.rs +++ b/src/lib/inventory/src/lib.rs @@ -4,4 +4,5 @@ pub mod slot; pub mod types; pub mod viewers; +#[cfg(test)] mod tests; diff --git a/src/lib/inventory/src/viewers.rs b/src/lib/inventory/src/viewers.rs index 542854d7..b823db54 100644 --- a/src/lib/inventory/src/viewers.rs +++ b/src/lib/inventory/src/viewers.rs @@ -1,5 +1,5 @@ use crate::inventory::InventoryData; -use crate::{inventory::Inventory, slot::Slot}; +use crate::slot::Slot; use ferrumc_ecs::entities::Entity; use ferrumc_ecs::errors::ECSError; use ferrumc_net::errors::NetError; @@ -26,7 +26,7 @@ impl InventoryView { pub async fn add_viewer( &mut self, inventory: &InventoryData, - mut entity: (Entity, &mut StreamWriter), + entity: (Entity, &mut StreamWriter), ) -> Result<&mut Self, NetError> { let viewers = &self.viewers; if viewers.contains(&entity.0) { @@ -34,7 +34,7 @@ impl InventoryView { } self.viewers.push(entity.0); - self.send_packet(inventory, &mut entity.1).await?; + self.send_packet(inventory, entity.1).await?; Ok(self) } diff --git a/src/lib/storage/src/lib.rs b/src/lib/storage/src/lib.rs index 91a57a7f..4bbb6e3d 100644 --- a/src/lib/storage/src/lib.rs +++ b/src/lib/storage/src/lib.rs @@ -1,4 +1,3 @@ -#![feature(async_closure)] pub mod compressors; pub mod errors; pub mod lmdb; From 767f8fa916fe147a6d240a058d20eb37abf0b0fd Mon Sep 17 00:00:00 2001 From: Outspending Date: Mon, 30 Dec 2024 07:40:48 -0700 Subject: [PATCH 12/38] Update login_process.rs --- src/bin/src/packet_handlers/login_process.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/bin/src/packet_handlers/login_process.rs b/src/bin/src/packet_handlers/login_process.rs index 23242a52..40cbe6ac 100644 --- a/src/bin/src/packet_handlers/login_process.rs +++ b/src/bin/src/packet_handlers/login_process.rs @@ -169,10 +169,6 @@ async fn handle_ack_finish_configuration( ) .await?; - let mut inventory = Inventory::new(1, "Testing", InventoryType::Chest(6)); - inventory.set_slot(0, Slot::with_item(9)); - inventory.add_viewer((conn_id, &mut writer)).await?; - send_keep_alive(conn_id, state, &mut writer).await?; Ok(ack_finish_configuration_event) From 26e47945508348d2ca081994b79361a8f1f38fd7 Mon Sep 17 00:00:00 2001 From: Outspending Date: Mon, 30 Dec 2024 08:01:36 -0700 Subject: [PATCH 13/38] inventory events --- src/bin/src/packet_handlers/login_process.rs | 1 - src/lib/derive_macros/src/events/mod.rs | 3 ++- src/lib/inventory/Cargo.toml | 3 +++ .../inventory/src/events/inventory_close.rs | 19 +++++++++++++++++++ .../inventory/src/events/inventory_open.rs | 19 +++++++++++++++++++ src/lib/inventory/src/events/mod.rs | 2 ++ src/lib/inventory/src/lib.rs | 1 + 7 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 src/lib/inventory/src/events/inventory_close.rs create mode 100644 src/lib/inventory/src/events/inventory_open.rs create mode 100644 src/lib/inventory/src/events/mod.rs diff --git a/src/bin/src/packet_handlers/login_process.rs b/src/bin/src/packet_handlers/login_process.rs index 40cbe6ac..5cb64743 100644 --- a/src/bin/src/packet_handlers/login_process.rs +++ b/src/bin/src/packet_handlers/login_process.rs @@ -168,7 +168,6 @@ async fn handle_ack_finish_configuration( &NetEncodeOpts::WithLength, ) .await?; - send_keep_alive(conn_id, state, &mut writer).await?; Ok(ack_finish_configuration_event) diff --git a/src/lib/derive_macros/src/events/mod.rs b/src/lib/derive_macros/src/events/mod.rs index ac4e0f95..184989c5 100644 --- a/src/lib/derive_macros/src/events/mod.rs +++ b/src/lib/derive_macros/src/events/mod.rs @@ -123,7 +123,8 @@ pub(crate) fn derive(input: TokenStream) -> TokenStream { quote! {crate} } FoundCrate::Name(name) => { - quote! {::#name} + let name = syn::Ident::new(&name, proc_macro2::Span::call_site()); + quote! {#name} } }; diff --git a/src/lib/inventory/Cargo.toml b/src/lib/inventory/Cargo.toml index 4869d36b..bb2b3c00 100644 --- a/src/lib/inventory/Cargo.toml +++ b/src/lib/inventory/Cargo.toml @@ -9,6 +9,9 @@ ferrumc-net = { workspace = true } ferrumc-net-codec = { workspace = true } ferrumc-text = { workspace = true } ferrumc-ecs = { workspace = true } +ferrumc-events = { workspace = true } +ferrumc-macros = { workspace = true } +ferrumc-state = { workspace = true } dashmap = { workspace = true } [lints] diff --git a/src/lib/inventory/src/events/inventory_close.rs b/src/lib/inventory/src/events/inventory_close.rs new file mode 100644 index 00000000..4c50e9aa --- /dev/null +++ b/src/lib/inventory/src/events/inventory_close.rs @@ -0,0 +1,19 @@ +use ferrumc_macros::Event; +use crate::inventory::Inventory; + +#[derive(Event, Debug)] +pub struct InventoryCloseEvent { + pub conn_id: usize, + pub inventory: Option +} + +impl InventoryCloseEvent { + pub fn new(conn_id: usize) -> Self { + Self { conn_id, inventory: None } + } + + pub fn inventory(mut self, inventory: Inventory) -> Self { + self.inventory = Some(inventory); + self + } +} \ No newline at end of file diff --git a/src/lib/inventory/src/events/inventory_open.rs b/src/lib/inventory/src/events/inventory_open.rs new file mode 100644 index 00000000..35b20d70 --- /dev/null +++ b/src/lib/inventory/src/events/inventory_open.rs @@ -0,0 +1,19 @@ +use ferrumc_macros::Event; +use crate::inventory::Inventory; + +#[derive(Event, Debug)] +pub struct OpenInventoryEvent { + pub conn_id: usize, + pub inventory: Option, +} + +impl OpenInventoryEvent { + pub fn new(conn_id: usize) -> Self { + Self { conn_id, inventory: None } + } + + pub fn inventory(mut self, inventory: Inventory) -> Self { + self.inventory = Some(inventory); + self + } +} \ No newline at end of file diff --git a/src/lib/inventory/src/events/mod.rs b/src/lib/inventory/src/events/mod.rs new file mode 100644 index 00000000..1aec82db --- /dev/null +++ b/src/lib/inventory/src/events/mod.rs @@ -0,0 +1,2 @@ +pub mod inventory_open; +pub mod inventory_close; \ No newline at end of file diff --git a/src/lib/inventory/src/lib.rs b/src/lib/inventory/src/lib.rs index 87ca26f4..f10ded41 100644 --- a/src/lib/inventory/src/lib.rs +++ b/src/lib/inventory/src/lib.rs @@ -3,6 +3,7 @@ pub mod inventory; pub mod slot; pub mod types; pub mod viewers; +pub mod events; #[cfg(test)] mod tests; From cd492a7425e5f072feb5e7b7a87672a7d828704a Mon Sep 17 00:00:00 2001 From: Outspending Date: Mon, 30 Dec 2024 08:46:08 -0700 Subject: [PATCH 14/38] Simple ECS Implementation --- src/lib/inventory/Cargo.toml | 2 + .../inventory/src/events/inventory_close.rs | 20 +++--- .../inventory/src/events/inventory_open.rs | 14 ++-- src/lib/inventory/src/events/mod.rs | 2 +- src/lib/inventory/src/inventory.rs | 14 ++-- src/lib/inventory/src/lib.rs | 2 +- src/lib/inventory/src/viewers.rs | 64 ++++++++++++------- 7 files changed, 72 insertions(+), 46 deletions(-) diff --git a/src/lib/inventory/Cargo.toml b/src/lib/inventory/Cargo.toml index bb2b3c00..b94323eb 100644 --- a/src/lib/inventory/Cargo.toml +++ b/src/lib/inventory/Cargo.toml @@ -12,6 +12,8 @@ ferrumc-ecs = { workspace = true } ferrumc-events = { workspace = true } ferrumc-macros = { workspace = true } ferrumc-state = { workspace = true } + +tokio = {workspace = true } dashmap = { workspace = true } [lints] diff --git a/src/lib/inventory/src/events/inventory_close.rs b/src/lib/inventory/src/events/inventory_close.rs index 4c50e9aa..d5f5dad4 100644 --- a/src/lib/inventory/src/events/inventory_close.rs +++ b/src/lib/inventory/src/events/inventory_close.rs @@ -1,19 +1,21 @@ use ferrumc_macros::Event; -use crate::inventory::Inventory; #[derive(Event, Debug)] -pub struct InventoryCloseEvent { +pub struct CloseInventoryEvent { pub conn_id: usize, - pub inventory: Option + pub inventory_id: Option, } -impl InventoryCloseEvent { +impl CloseInventoryEvent { pub fn new(conn_id: usize) -> Self { - Self { conn_id, inventory: None } + Self { + conn_id, + inventory_id: None, + } } - - pub fn inventory(mut self, inventory: Inventory) -> Self { - self.inventory = Some(inventory); + + pub fn inventory_id(mut self, inventory_id: i32) -> Self { + self.inventory_id = Some(inventory_id); self } -} \ No newline at end of file +} diff --git a/src/lib/inventory/src/events/inventory_open.rs b/src/lib/inventory/src/events/inventory_open.rs index 35b20d70..46a4daed 100644 --- a/src/lib/inventory/src/events/inventory_open.rs +++ b/src/lib/inventory/src/events/inventory_open.rs @@ -1,19 +1,21 @@ use ferrumc_macros::Event; -use crate::inventory::Inventory; #[derive(Event, Debug)] pub struct OpenInventoryEvent { pub conn_id: usize, - pub inventory: Option, + pub inventory_id: Option, } impl OpenInventoryEvent { pub fn new(conn_id: usize) -> Self { - Self { conn_id, inventory: None } + Self { + conn_id, + inventory_id: None, + } } - pub fn inventory(mut self, inventory: Inventory) -> Self { - self.inventory = Some(inventory); + pub fn inventory_id(mut self, inventory_id: i32) -> Self { + self.inventory_id = Some(inventory_id); self } -} \ No newline at end of file +} diff --git a/src/lib/inventory/src/events/mod.rs b/src/lib/inventory/src/events/mod.rs index 1aec82db..2aa3d85b 100644 --- a/src/lib/inventory/src/events/mod.rs +++ b/src/lib/inventory/src/events/mod.rs @@ -1,2 +1,2 @@ +pub mod inventory_close; pub mod inventory_open; -pub mod inventory_close; \ No newline at end of file diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs index edb50c6a..334a127a 100644 --- a/src/lib/inventory/src/inventory.rs +++ b/src/lib/inventory/src/inventory.rs @@ -3,9 +3,11 @@ use crate::slot::Slot; use crate::viewers::InventoryView; use dashmap::DashMap; use ferrumc_ecs::entities::Entity; -use ferrumc_net::{connection::StreamWriter, errors::NetError}; +use ferrumc_net::errors::NetError; use ferrumc_net_codec::net_types::var_int::VarInt; +use ferrumc_state::ServerState; use ferrumc_text::{TextComponent, TextComponentBuilder}; +use std::sync::Arc; #[derive(Debug, Clone, Copy)] pub enum InventoryType { @@ -141,17 +143,19 @@ impl Inventory { pub async fn add_viewer( &mut self, - viewer: (Entity, &mut StreamWriter), + state: Arc, + viewer: Entity, ) -> Result<(), NetError> { - self.view.add_viewer(&self.data, viewer).await?; + self.view.add_viewer(&self.data, state, viewer).await?; Ok(()) } pub async fn remove_viewer( &mut self, - viewer: (Entity, &mut StreamWriter), + state: Arc, + viewer: Entity, ) -> Result<(), NetError> { - self.view.remove_viewer(&self.data, viewer).await?; + self.view.remove_viewer(&self.data, state, viewer).await?; Ok(()) } diff --git a/src/lib/inventory/src/lib.rs b/src/lib/inventory/src/lib.rs index f10ded41..27861f5d 100644 --- a/src/lib/inventory/src/lib.rs +++ b/src/lib/inventory/src/lib.rs @@ -1,9 +1,9 @@ pub mod contents; +pub mod events; pub mod inventory; pub mod slot; pub mod types; pub mod viewers; -pub mod events; #[cfg(test)] mod tests; diff --git a/src/lib/inventory/src/viewers.rs b/src/lib/inventory/src/viewers.rs index b823db54..d37354b0 100644 --- a/src/lib/inventory/src/viewers.rs +++ b/src/lib/inventory/src/viewers.rs @@ -1,15 +1,19 @@ +use crate::events::inventory_close::CloseInventoryEvent; +use crate::events::inventory_open::OpenInventoryEvent; use crate::inventory::InventoryData; -use crate::slot::Slot; use ferrumc_ecs::entities::Entity; use ferrumc_ecs::errors::ECSError; +use ferrumc_events::infrastructure::Event; use ferrumc_net::errors::NetError; use ferrumc_net::packets::outgoing::close_container::CloseContainerPacket; use ferrumc_net::packets::outgoing::open_screen::OpenScreenPacket; -use ferrumc_net::packets::outgoing::set_container_slot::{NetworkSlot, SetContainerSlotPacket}; +use ferrumc_net::packets::outgoing::set_container_slot::NetworkSlot; use ferrumc_net::{ connection::StreamWriter, packets::outgoing::set_container_content::SetContainerContentPacket, }; use ferrumc_net_codec::encode::{NetEncode, NetEncodeOpts}; +use ferrumc_state::ServerState; +use std::sync::Arc; #[derive(Debug, Clone)] pub struct InventoryView { @@ -26,50 +30,62 @@ impl InventoryView { pub async fn add_viewer( &mut self, inventory: &InventoryData, - entity: (Entity, &mut StreamWriter), + state: Arc, + entity: Entity, ) -> Result<&mut Self, NetError> { + let universe = &state.universe; + let mut writer = universe.get_mut::<&mut StreamWriter>(entity)?; + let viewers = &self.viewers; - if viewers.contains(&entity.0) { + if viewers.contains(&entity) { return Ok(self); } - self.viewers.push(entity.0); - self.send_packet(inventory, entity.1).await?; + self.viewers.push(entity); + self.send_packet(inventory, *writer).await?; + + // handle event + let event = OpenInventoryEvent::new(entity).inventory_id(*inventory.id); + OpenInventoryEvent::trigger(event, state).await?; + Ok(self) } pub async fn remove_viewer( &mut self, inventory: &InventoryData, - entity: (Entity, &mut StreamWriter), + state: Arc, + entity: Entity, ) -> Result<&mut Self, NetError> { + let universe = &state.universe; + let mut writer = universe.get_mut::<&mut StreamWriter>(entity)?; + let viewers = &mut self.viewers; - if let Some(index) = viewers.iter().position(|&viewer| viewer == entity.0) { + if let Some(index) = viewers.iter().position(|&viewer| viewer == entity) { viewers.remove(index); - entity - .1 - .send_packet( - &CloseContainerPacket::new(*inventory.id as u8), - &NetEncodeOpts::WithLength, - ) - .await?; + self.send_close_packet(*inventory.id, *writer).await?; + + // handle event + let event = CloseInventoryEvent::new(entity).inventory_id(*inventory.id); + CloseInventoryEvent::trigger(event, state).await?; + Ok(self) } else { Err(NetError::ECSError(ECSError::ComponentNotFound))? } } - pub async fn send_slot_update_packet( + async fn send_close_packet( &self, - inventory: &InventoryData, - slot: (i16, Slot), + inventory_id: i32, + writer: &mut StreamWriter, ) -> Result<(), NetError> { - self.send_packet_to_viewers(&SetContainerSlotPacket::new( - inventory.id, - slot.0, - slot.1.to_network_slot(), - )) - .await + writer + .send_packet( + &CloseContainerPacket::new(inventory_id as u8), + &NetEncodeOpts::WithLength, + ) + .await } async fn send_packet_to_viewers(&self, _packet: &impl NetEncode) -> Result<(), NetError> { From 7f61449c0b7f265b6e84dbd83d52c6b942ed0643 Mon Sep 17 00:00:00 2001 From: Outspending Date: Mon, 30 Dec 2024 11:13:56 -0700 Subject: [PATCH 15/38] Fixed Inventories + More Packets --- src/bin/src/packet_handlers/login_process.rs | 90 ++++++++++--------- src/lib/events/src/infrastructure.rs | 6 +- src/lib/inventory/Cargo.toml | 1 + src/lib/inventory/src/contents.rs | 18 +--- src/lib/inventory/src/viewers.rs | 57 ++++++------ .../codec/src/net_types/network_position.rs | 15 +++- src/lib/net/src/packets/incoming/mod.rs | 1 + .../net/src/packets/incoming/use_item_on.rs | 41 +++++++++ .../packets/outgoing/set_container_slot.rs | 19 ++-- src/lib/storage/src/lmdb.rs | 1 + 10 files changed, 156 insertions(+), 93 deletions(-) create mode 100644 src/lib/net/src/packets/incoming/use_item_on.rs diff --git a/src/bin/src/packet_handlers/login_process.rs b/src/bin/src/packet_handlers/login_process.rs index 569021cc..4c315da0 100644 --- a/src/bin/src/packet_handlers/login_process.rs +++ b/src/bin/src/packet_handlers/login_process.rs @@ -5,6 +5,8 @@ use ferrumc_core::transform::grounded::OnGround; use ferrumc_core::transform::position::Position; use ferrumc_core::transform::rotation::Rotation; use ferrumc_ecs::components::storage::ComponentRefMut; +use ferrumc_inventory::inventory::{Inventory, InventoryType}; +use ferrumc_inventory::slot::Slot; use ferrumc_macros::event_handler; use ferrumc_net::connection::{ConnectionState, StreamWriter}; use ferrumc_net::errors::NetError; @@ -160,48 +162,56 @@ async fn handle_ack_finish_configuration( .add_component::(conn_id, Rotation::default())? .add_component::(conn_id, OnGround::default())?; - let mut writer = state.universe.get_mut::(conn_id)?; - - writer // 21 - .send_packet(&LoginPlayPacket::new(conn_id), &NetEncodeOpts::WithLength) - .await?; - writer // 29 - .send_packet( - &SynchronizePlayerPositionPacket::default(), // The coordinates here should be used for the center chunk. - &NetEncodeOpts::WithLength, - ) - .await?; - writer // 37 - .send_packet( - &SetDefaultSpawnPositionPacket::default(), // Player specific, aka. home, bed, where it would respawn. - &NetEncodeOpts::WithLength, - ) - .await?; - writer // 38 - .send_packet( - &GameEventPacket::start_waiting_for_level_chunks(), - &NetEncodeOpts::WithLength, - ) - .await?; - writer // 41 - .send_packet( - &SetCenterChunk::new(0, 0), // TODO - Dependent on the player spawn position. - &NetEncodeOpts::WithLength, - ) - .await?; - writer // other - .send_packet( - &SetRenderDistance::new(5), // TODO - &NetEncodeOpts::WithLength, - ) - .await?; + { + let mut writer = state.universe.get_mut::(conn_id)?; + + writer // 21 + .send_packet(&LoginPlayPacket::new(conn_id), &NetEncodeOpts::WithLength) + .await?; + writer // 29 + .send_packet( + &SynchronizePlayerPositionPacket::default(), // The coordinates here should be used for the center chunk. + &NetEncodeOpts::WithLength, + ) + .await?; + writer // 37 + .send_packet( + &SetDefaultSpawnPositionPacket::default(), // Player specific, aka. home, bed, where it would respawn. + &NetEncodeOpts::WithLength, + ) + .await?; + writer // 38 + .send_packet( + &GameEventPacket::start_waiting_for_level_chunks(), + &NetEncodeOpts::WithLength, + ) + .await?; + writer // 41 + .send_packet( + &SetCenterChunk::new(0, 0), // TODO - Dependent on the player spawn position. + &NetEncodeOpts::WithLength, + ) + .await?; + writer // other + .send_packet( + &SetRenderDistance::new(5), // TODO + &NetEncodeOpts::WithLength, + ) + .await?; + + let pos = state.universe.get_mut::(conn_id)?; + let mut chunk_recv = state.universe.get_mut::(conn_id)?; + chunk_recv.last_chunk = Some((pos.x as i32, pos.z as i32, String::from("overworld"))); + chunk_recv.calculate_chunks().await; + + send_keep_alive(conn_id, state.clone(), &mut writer).await?; + } - let pos = state.universe.get_mut::(conn_id)?; - let mut chunk_recv = state.universe.get_mut::(conn_id)?; - chunk_recv.last_chunk = Some((pos.x as i32, pos.z as i32, String::from("overworld"))); - chunk_recv.calculate_chunks().await; + let mut inventory = Inventory::new(1, "Outspending's Inventory", InventoryType::Chest(6)); + inventory.set_slot(0, Slot::with_item(1)); + inventory.set_slot(1, Slot::with_item(2)); - send_keep_alive(conn_id, state, &mut writer).await?; + inventory.add_viewer(state, conn_id).await?; Ok(ack_finish_configuration_event) } diff --git a/src/lib/events/src/infrastructure.rs b/src/lib/events/src/infrastructure.rs index 25f612ce..f4815658 100644 --- a/src/lib/events/src/infrastructure.rs +++ b/src/lib/events/src/infrastructure.rs @@ -73,9 +73,9 @@ pub trait Event: Sized + Send + Sync + 'static { /// /// Returns `Ok(())` if the execution succeeded. `Err(EventsError)` ifa listener failed. async fn trigger(event: Self::Data, state: Self::State) -> Result<(), Self::Error> { - let listeners = EVENTS_LISTENERS - .get(Self::name()) - .expect("Failed to find event listeners. Impossible;"); + let Some(listeners) = EVENTS_LISTENERS.get(Self::name()) else { + return Ok(()); + }; // Convert listeners iterator into Stream stream::iter(listeners.iter()) diff --git a/src/lib/inventory/Cargo.toml b/src/lib/inventory/Cargo.toml index b94323eb..8ad0e644 100644 --- a/src/lib/inventory/Cargo.toml +++ b/src/lib/inventory/Cargo.toml @@ -15,6 +15,7 @@ ferrumc-state = { workspace = true } tokio = {workspace = true } dashmap = { workspace = true } +log = { workspace = true } [lints] workspace = true diff --git a/src/lib/inventory/src/contents.rs b/src/lib/inventory/src/contents.rs index ec94d2fb..16dc87b1 100644 --- a/src/lib/inventory/src/contents.rs +++ b/src/lib/inventory/src/contents.rs @@ -1,7 +1,5 @@ use crate::slot::Slot; use dashmap::DashMap; -use ferrumc_net::packets::outgoing::set_container_slot::NetworkSlot; -use ferrumc_net_codec::net_types::length_prefixed_vec::LengthPrefixedVec; #[derive(Debug, Clone)] pub struct InventoryContents { @@ -24,17 +22,7 @@ impl InventoryContents { self.contents.get(&item).map(|v| *v) } - pub(crate) fn construct_container_vec(&self, size: usize) -> LengthPrefixedVec { - let mut vec = LengthPrefixedVec::new(Vec::with_capacity(size)); - for i in 0..(size as i32) { - let slot = match self.contents.get(&i) { - Some(data) => data.value().to_network_slot(), - None => NetworkSlot::empty(), - }; - - vec.data.insert(i as usize, slot); - } - - vec - } + //to store in chunk metadata: TAG 44: byte + //to show: starts at slot 0 ALWAYS - > 26/53 smalll/large. + //other inventories are to be implemented after. } diff --git a/src/lib/inventory/src/viewers.rs b/src/lib/inventory/src/viewers.rs index d37354b0..55b6a2c5 100644 --- a/src/lib/inventory/src/viewers.rs +++ b/src/lib/inventory/src/viewers.rs @@ -4,14 +4,12 @@ use crate::inventory::InventoryData; use ferrumc_ecs::entities::Entity; use ferrumc_ecs::errors::ECSError; use ferrumc_events::infrastructure::Event; +use ferrumc_net::connection::StreamWriter; use ferrumc_net::errors::NetError; use ferrumc_net::packets::outgoing::close_container::CloseContainerPacket; use ferrumc_net::packets::outgoing::open_screen::OpenScreenPacket; -use ferrumc_net::packets::outgoing::set_container_slot::NetworkSlot; -use ferrumc_net::{ - connection::StreamWriter, packets::outgoing::set_container_content::SetContainerContentPacket, -}; -use ferrumc_net_codec::encode::{NetEncode, NetEncodeOpts}; +use ferrumc_net::packets::outgoing::set_container_slot::SetContainerSlotPacket; +use ferrumc_net_codec::encode::NetEncodeOpts; use ferrumc_state::ServerState; use std::sync::Arc; @@ -33,8 +31,7 @@ impl InventoryView { state: Arc, entity: Entity, ) -> Result<&mut Self, NetError> { - let universe = &state.universe; - let mut writer = universe.get_mut::<&mut StreamWriter>(entity)?; + let mut writer = state.universe.get_mut::(entity)?; let viewers = &self.viewers; if viewers.contains(&entity) { @@ -42,7 +39,8 @@ impl InventoryView { } self.viewers.push(entity); - self.send_packet(inventory, *writer).await?; + self.send_inventory_data_packets(inventory, &mut writer) + .await?; // handle event let event = OpenInventoryEvent::new(entity).inventory_id(*inventory.id); @@ -58,12 +56,12 @@ impl InventoryView { entity: Entity, ) -> Result<&mut Self, NetError> { let universe = &state.universe; - let mut writer = universe.get_mut::<&mut StreamWriter>(entity)?; + let mut writer = universe.get_mut::(entity)?; let viewers = &mut self.viewers; if let Some(index) = viewers.iter().position(|&viewer| viewer == entity) { viewers.remove(index); - self.send_close_packet(*inventory.id, *writer).await?; + self.send_close_packet(*inventory.id, &mut writer).await?; // handle event let event = CloseInventoryEvent::new(entity).inventory_id(*inventory.id); @@ -88,11 +86,7 @@ impl InventoryView { .await } - async fn send_packet_to_viewers(&self, _packet: &impl NetEncode) -> Result<(), NetError> { - Ok(()) - } - - async fn send_packet( + async fn send_inventory_data_packets( &mut self, inventory: &InventoryData, writer: &mut StreamWriter, @@ -107,19 +101,24 @@ impl InventoryView { .send_packet(&packet, &NetEncodeOpts::WithLength) .await?; - let inventory_size = inventory.inventory_type.get_size() as usize; - let container_content = inventory.contents.construct_container_vec(inventory_size); - writer - .send_packet( - &SetContainerContentPacket::new( - *inventory.id as u8, - container_content, - NetworkSlot::empty(), - ), - &NetEncodeOpts::SizePrefixed, - ) - .await?; - - Ok(()) + let contents = &inventory.contents.contents; + if contents.is_empty() { + Ok(()) + } else { + for slot in contents.iter() { + writer + .send_packet( + &SetContainerSlotPacket::new( + inventory.id, + *slot.key() as i16, + slot.value().to_network_slot(), + ), + &NetEncodeOpts::WithLength, + ) + .await?; + } + + Ok(()) + } } } diff --git a/src/lib/net/crates/codec/src/net_types/network_position.rs b/src/lib/net/crates/codec/src/net_types/network_position.rs index dd138782..b7cf57c3 100644 --- a/src/lib/net/crates/codec/src/net_types/network_position.rs +++ b/src/lib/net/crates/codec/src/net_types/network_position.rs @@ -1,8 +1,9 @@ // I have no clue why it is saving i32 and i16. There is no precision. The actual player position is saved in f32. +use crate::decode::{NetDecode, NetDecodeOpts, NetDecodeResult}; use crate::encode::{NetEncode, NetEncodeOpts, NetEncodeResult}; use std::fmt::Display; -use std::io::Write; +use std::io::{Read, Write}; use tokio::io::AsyncWrite; /// The definition of a "Position" in the Minecraft protocol. @@ -46,6 +47,18 @@ impl NetEncode for NetworkPosition { Ok(()) } } + +impl NetDecode for NetworkPosition { + fn decode(reader: &mut R, opts: &NetDecodeOpts) -> NetDecodeResult { + let value = u64::decode(reader, opts)?; + Ok(Self { + x: (value >> 38) as i32, + y: (value << 54 >> 52) as i16, + z: (value << 26 >> 38) as i32, + }) + } +} + impl NetworkPosition { pub fn as_u64(&self) -> u64 { ((self.x as u64 & 0x3FFFFFF) << 38) diff --git a/src/lib/net/src/packets/incoming/mod.rs b/src/lib/net/src/packets/incoming/mod.rs index 2f5254a1..26c9742a 100644 --- a/src/lib/net/src/packets/incoming/mod.rs +++ b/src/lib/net/src/packets/incoming/mod.rs @@ -14,3 +14,4 @@ pub mod packet_skeleton; pub mod set_player_position; pub mod set_player_position_and_rotation; pub mod set_player_rotation; +pub mod use_item_on; diff --git a/src/lib/net/src/packets/incoming/use_item_on.rs b/src/lib/net/src/packets/incoming/use_item_on.rs new file mode 100644 index 00000000..3a8f888d --- /dev/null +++ b/src/lib/net/src/packets/incoming/use_item_on.rs @@ -0,0 +1,41 @@ +use crate::packets::IncomingPacket; +use crate::NetResult; +use ferrumc_events::infrastructure::Event; +use ferrumc_macros::{packet, Event, NetDecode}; +use ferrumc_net_codec::net_types::network_position::NetworkPosition; +use ferrumc_net_codec::net_types::var_int::VarInt; +use ferrumc_state::ServerState; +use std::sync::Arc; + +#[derive(NetDecode, Debug)] +#[packet(packet_id = 0x38, state = "play")] +pub struct UseItemOnPacket { + pub hand: VarInt, + pub location: NetworkPosition, + pub face: VarInt, + pub cursor_pos_x: f32, + pub cursor_pos_y: f32, + pub cursor_pos_z: f32, + pub inside_block: bool, + pub sequence: VarInt, +} + +impl IncomingPacket for UseItemOnPacket { + async fn handle(self, conn_id: usize, state: Arc) -> NetResult<()> { + let event = UseItemOnEvent::new(self, conn_id); + UseItemOnEvent::trigger(event, state).await?; + Ok(()) + } +} + +#[derive(Event, Debug)] +pub struct UseItemOnEvent { + pub conn_id: usize, + pub packet: UseItemOnPacket, +} + +impl UseItemOnEvent { + pub fn new(packet: UseItemOnPacket, conn_id: usize) -> Self { + Self { conn_id, packet } + } +} 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 85c58fcf..160b6fc6 100644 --- a/src/lib/net/src/packets/outgoing/set_container_slot.rs +++ b/src/lib/net/src/packets/outgoing/set_container_slot.rs @@ -12,11 +12,20 @@ pub struct NetworkSlot { impl NetworkSlot { pub fn new(item_count: i32, item_id: i32) -> Self { - Self { - item_count: VarInt::new(item_count), - item_id: Some(VarInt::new(item_id)), - num_of_components_to_add: Some(VarInt::new(0)), - num_of_components_to_remove: Some(VarInt::new(0)), + if item_count == 0 { + Self { + item_count: VarInt::new(0), + item_id: None, + num_of_components_to_add: None, + num_of_components_to_remove: None, + } + } else { + Self { + item_count: VarInt::new(item_count), + item_id: Some(VarInt::new(item_id)), + num_of_components_to_add: Some(VarInt::new(0)), + num_of_components_to_remove: Some(VarInt::new(0)), + } } } diff --git a/src/lib/storage/src/lmdb.rs b/src/lib/storage/src/lmdb.rs index bc9c5960..654b59fb 100644 --- a/src/lib/storage/src/lmdb.rs +++ b/src/lib/storage/src/lmdb.rs @@ -1,3 +1,4 @@ + use crate::errors::StorageError; use heed; use heed::byteorder::BigEndian; From 1d127c4ff984a58f7e5bb159092b69e55d73e1dd Mon Sep 17 00:00:00 2001 From: Outspending Date: Mon, 30 Dec 2024 11:59:32 -0700 Subject: [PATCH 16/38] ECS Compatibility --- src/bin/src/packet_handlers/containers.rs | 17 +++ src/bin/src/packet_handlers/mod.rs | 1 + .../inventory/src/events/inventory_close.rs | 21 --- src/lib/inventory/src/events/mod.rs | 1 - src/lib/inventory/src/inventory.rs | 108 +++++++++------ src/lib/inventory/src/lib.rs | 1 - src/lib/inventory/src/viewers.rs | 124 ------------------ .../src/packets/incoming/close_container.rs | 38 ++++++ src/lib/net/src/packets/incoming/mod.rs | 1 + src/lib/storage/src/lmdb.rs | 1 - 10 files changed, 125 insertions(+), 188 deletions(-) create mode 100644 src/bin/src/packet_handlers/containers.rs delete mode 100644 src/lib/inventory/src/events/inventory_close.rs delete mode 100644 src/lib/inventory/src/viewers.rs create mode 100644 src/lib/net/src/packets/incoming/close_container.rs diff --git a/src/bin/src/packet_handlers/containers.rs b/src/bin/src/packet_handlers/containers.rs new file mode 100644 index 00000000..ecc5248e --- /dev/null +++ b/src/bin/src/packet_handlers/containers.rs @@ -0,0 +1,17 @@ +use tracing::info; +use ferrumc_inventory::inventory::Inventory; +use ferrumc_macros::event_handler; +use ferrumc_net::errors::NetError; +use ferrumc_net::packets::incoming::close_container::InventoryCloseEvent; +use ferrumc_state::GlobalState; + +#[event_handler] +async fn container_close( + container_close_event: InventoryCloseEvent, + state: GlobalState, +) -> Result { + let conn_id = container_close_event.conn_id; + + state.universe.remove_component::(conn_id)?; + Ok(container_close_event) +} \ No newline at end of file diff --git a/src/bin/src/packet_handlers/mod.rs b/src/bin/src/packet_handlers/mod.rs index 32983a54..3e7524a0 100644 --- a/src/bin/src/packet_handlers/mod.rs +++ b/src/bin/src/packet_handlers/mod.rs @@ -2,3 +2,4 @@ mod handshake; mod login_process; mod tick_handler; mod transform; +mod containers; diff --git a/src/lib/inventory/src/events/inventory_close.rs b/src/lib/inventory/src/events/inventory_close.rs deleted file mode 100644 index d5f5dad4..00000000 --- a/src/lib/inventory/src/events/inventory_close.rs +++ /dev/null @@ -1,21 +0,0 @@ -use ferrumc_macros::Event; - -#[derive(Event, Debug)] -pub struct CloseInventoryEvent { - pub conn_id: usize, - pub inventory_id: Option, -} - -impl CloseInventoryEvent { - pub fn new(conn_id: usize) -> Self { - Self { - conn_id, - inventory_id: None, - } - } - - pub fn inventory_id(mut self, inventory_id: i32) -> Self { - self.inventory_id = Some(inventory_id); - self - } -} diff --git a/src/lib/inventory/src/events/mod.rs b/src/lib/inventory/src/events/mod.rs index 2aa3d85b..7302598d 100644 --- a/src/lib/inventory/src/events/mod.rs +++ b/src/lib/inventory/src/events/mod.rs @@ -1,2 +1 @@ -pub mod inventory_close; pub mod inventory_open; diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs index 334a127a..d3e00141 100644 --- a/src/lib/inventory/src/inventory.rs +++ b/src/lib/inventory/src/inventory.rs @@ -1,9 +1,16 @@ use crate::contents::InventoryContents; +use crate::events::inventory_open::OpenInventoryEvent; use crate::slot::Slot; -use crate::viewers::InventoryView; use dashmap::DashMap; use ferrumc_ecs::entities::Entity; +use ferrumc_events::infrastructure::Event; +use ferrumc_net::connection::StreamWriter; use ferrumc_net::errors::NetError; +use ferrumc_net::packets::incoming::close_container::InventoryCloseEvent; +use ferrumc_net::packets::outgoing::close_container::CloseContainerPacket; +use ferrumc_net::packets::outgoing::open_screen::OpenScreenPacket; +use ferrumc_net::packets::outgoing::set_container_slot::SetContainerSlotPacket; +use ferrumc_net_codec::encode::NetEncodeOpts; use ferrumc_net_codec::net_types::var_int::VarInt; use ferrumc_state::ServerState; use ferrumc_text::{TextComponent, TextComponentBuilder}; @@ -87,84 +94,105 @@ impl InventoryType { } #[derive(Debug, Clone)] -pub struct InventoryData { +pub struct Inventory { pub id: VarInt, pub inventory_type: InventoryType, pub title: TextComponent, pub(crate) contents: InventoryContents, } -impl InventoryData { - fn new(id: VarInt, inventory_type: InventoryType, title: TextComponent) -> Self { - Self { - id, - inventory_type, - title, - contents: InventoryContents::empty(), - } - } -} - -#[derive(Debug, Clone)] -pub struct Inventory { - pub data: InventoryData, - pub view: InventoryView, -} - impl Inventory { pub fn new>(id: i32, title: S, inventory_type: InventoryType) -> Self { Self { - data: InventoryData::new( - VarInt::new(id), - inventory_type, - TextComponentBuilder::new(title).build(), - ), - view: InventoryView::new(), + id: VarInt::new(id), + inventory_type, + title: TextComponentBuilder::new(title).build(), + contents: InventoryContents::empty(), } } pub fn set_slot(&mut self, slot_id: i32, slot: Slot) -> &mut Self { - let size = self.data.inventory_type.get_size(); + let size = self.inventory_type.get_size(); if (0..=size).contains(&slot_id) { - self.data.contents.set_slot(slot_id, slot); + self.contents.set_slot(slot_id, slot); } self } pub fn get_slot(&self, slot_id: i32) -> Option { - let size = self.data.inventory_type.get_size(); + let size = self.inventory_type.get_size(); if (0..=size).contains(&slot_id) { - self.data.contents.get_slot(slot_id) + self.contents.get_slot(slot_id) } else { None } } pub async fn add_viewer( - &mut self, + self, state: Arc, - viewer: Entity, + entity_id: Entity, ) -> Result<(), NetError> { - self.view.add_viewer(&self.data, state, viewer).await?; + let universe = &state.universe; + let mut writer = universe.get_mut::(entity_id)?; + + let packet = + OpenScreenPacket::new(self.id, self.inventory_type.get_id(), self.title.clone()); + + writer + .send_packet(&packet, &NetEncodeOpts::WithLength) + .await?; + + let id = self.id; + let contents = self.get_contents(); + if !contents.is_empty() { + for slot in contents.iter() { + writer + .send_packet( + &SetContainerSlotPacket::new( + id, + *slot.key() as i16, + slot.value().to_network_slot(), + ), + &NetEncodeOpts::WithLength, + ) + .await?; + } + } + + // handle event + let event = OpenInventoryEvent::new(entity_id).inventory_id(*id); + OpenInventoryEvent::trigger(event, state.clone()).await?; + + universe.add_component::(entity_id, self)?; Ok(()) } pub async fn remove_viewer( &mut self, state: Arc, - viewer: Entity, + entity_id: Entity, ) -> Result<(), NetError> { - self.view.remove_viewer(&self.data, state, viewer).await?; + let universe = &state.universe; + let mut writer = universe.get_mut::(entity_id)?; + let inventory = universe.get::(entity_id)?; + + writer + .send_packet( + &CloseContainerPacket::new(*self.id as u8), + &NetEncodeOpts::WithLength, + ) + .await?; + + // handle event + let event = InventoryCloseEvent::new(entity_id, *inventory.id as u8); + InventoryCloseEvent::trigger(event, state.clone()).await?; Ok(()) } - pub fn get_viewers(&self) -> &Vec { - &self.view.viewers - } - pub fn get_contents(&self) -> &DashMap { - &self.data.contents.contents + &self.contents.contents } pub fn clear(&mut self) { @@ -193,7 +221,7 @@ impl Inventory { } pub fn get_size(&self) -> i32 { - self.data.inventory_type.get_size() + self.inventory_type.get_size() } pub fn is_empty(&self) -> bool { diff --git a/src/lib/inventory/src/lib.rs b/src/lib/inventory/src/lib.rs index 27861f5d..634d6ce5 100644 --- a/src/lib/inventory/src/lib.rs +++ b/src/lib/inventory/src/lib.rs @@ -3,7 +3,6 @@ pub mod events; pub mod inventory; pub mod slot; pub mod types; -pub mod viewers; #[cfg(test)] mod tests; diff --git a/src/lib/inventory/src/viewers.rs b/src/lib/inventory/src/viewers.rs deleted file mode 100644 index 55b6a2c5..00000000 --- a/src/lib/inventory/src/viewers.rs +++ /dev/null @@ -1,124 +0,0 @@ -use crate::events::inventory_close::CloseInventoryEvent; -use crate::events::inventory_open::OpenInventoryEvent; -use crate::inventory::InventoryData; -use ferrumc_ecs::entities::Entity; -use ferrumc_ecs::errors::ECSError; -use ferrumc_events::infrastructure::Event; -use ferrumc_net::connection::StreamWriter; -use ferrumc_net::errors::NetError; -use ferrumc_net::packets::outgoing::close_container::CloseContainerPacket; -use ferrumc_net::packets::outgoing::open_screen::OpenScreenPacket; -use ferrumc_net::packets::outgoing::set_container_slot::SetContainerSlotPacket; -use ferrumc_net_codec::encode::NetEncodeOpts; -use ferrumc_state::ServerState; -use std::sync::Arc; - -#[derive(Debug, Clone)] -pub struct InventoryView { - pub viewers: Vec, -} - -impl InventoryView { - pub(crate) fn new() -> Self { - Self { - viewers: Vec::new(), - } - } - - pub async fn add_viewer( - &mut self, - inventory: &InventoryData, - state: Arc, - entity: Entity, - ) -> Result<&mut Self, NetError> { - let mut writer = state.universe.get_mut::(entity)?; - - let viewers = &self.viewers; - if viewers.contains(&entity) { - return Ok(self); - } - - self.viewers.push(entity); - self.send_inventory_data_packets(inventory, &mut writer) - .await?; - - // handle event - let event = OpenInventoryEvent::new(entity).inventory_id(*inventory.id); - OpenInventoryEvent::trigger(event, state).await?; - - Ok(self) - } - - pub async fn remove_viewer( - &mut self, - inventory: &InventoryData, - state: Arc, - entity: Entity, - ) -> Result<&mut Self, NetError> { - let universe = &state.universe; - let mut writer = universe.get_mut::(entity)?; - - let viewers = &mut self.viewers; - if let Some(index) = viewers.iter().position(|&viewer| viewer == entity) { - viewers.remove(index); - self.send_close_packet(*inventory.id, &mut writer).await?; - - // handle event - let event = CloseInventoryEvent::new(entity).inventory_id(*inventory.id); - CloseInventoryEvent::trigger(event, state).await?; - - Ok(self) - } else { - Err(NetError::ECSError(ECSError::ComponentNotFound))? - } - } - - async fn send_close_packet( - &self, - inventory_id: i32, - writer: &mut StreamWriter, - ) -> Result<(), NetError> { - writer - .send_packet( - &CloseContainerPacket::new(inventory_id as u8), - &NetEncodeOpts::WithLength, - ) - .await - } - - async fn send_inventory_data_packets( - &mut self, - inventory: &InventoryData, - writer: &mut StreamWriter, - ) -> Result<(), NetError> { - let packet = OpenScreenPacket::new( - inventory.id, - inventory.inventory_type.get_id(), - inventory.title.clone(), - ); - - writer - .send_packet(&packet, &NetEncodeOpts::WithLength) - .await?; - - let contents = &inventory.contents.contents; - if contents.is_empty() { - Ok(()) - } else { - for slot in contents.iter() { - writer - .send_packet( - &SetContainerSlotPacket::new( - inventory.id, - *slot.key() as i16, - slot.value().to_network_slot(), - ), - &NetEncodeOpts::WithLength, - ) - .await?; - } - - Ok(()) - } - } -} diff --git a/src/lib/net/src/packets/incoming/close_container.rs b/src/lib/net/src/packets/incoming/close_container.rs new file mode 100644 index 00000000..c1fb1a21 --- /dev/null +++ b/src/lib/net/src/packets/incoming/close_container.rs @@ -0,0 +1,38 @@ +use crate::packets::IncomingPacket; +use crate::NetResult; +use ferrumc_events::infrastructure::Event; +use ferrumc_macros::{packet, Event, NetDecode}; +use ferrumc_state::ServerState; +use std::sync::Arc; + +#[derive(NetDecode, Debug)] +#[packet(packet_id = 0x0F, state = "play")] +pub struct IncomingCloseContainerPacket { + pub window_id: u8, +} + +impl IncomingCloseContainerPacket { + pub fn new(window_id: u8) -> Self { + IncomingCloseContainerPacket { window_id } + } +} + +impl IncomingPacket for IncomingCloseContainerPacket { + async fn handle(self, conn_id: usize, state: Arc) -> NetResult<()> { + let event = InventoryCloseEvent::new(conn_id, self.window_id); + InventoryCloseEvent::trigger(event, state).await?; + Ok(()) + } +} + +#[derive(Event, Debug)] +pub struct InventoryCloseEvent { + pub conn_id: usize, + pub window_id: u8, +} + +impl InventoryCloseEvent { + pub fn new(conn_id: usize, window_id: u8) -> Self { + InventoryCloseEvent { conn_id, window_id } + } +} diff --git a/src/lib/net/src/packets/incoming/mod.rs b/src/lib/net/src/packets/incoming/mod.rs index 26c9742a..4a47366d 100644 --- a/src/lib/net/src/packets/incoming/mod.rs +++ b/src/lib/net/src/packets/incoming/mod.rs @@ -11,6 +11,7 @@ pub mod status_request; pub mod keep_alive; pub mod packet_skeleton; +pub mod close_container; pub mod set_player_position; pub mod set_player_position_and_rotation; pub mod set_player_rotation; diff --git a/src/lib/storage/src/lmdb.rs b/src/lib/storage/src/lmdb.rs index 654b59fb..bc9c5960 100644 --- a/src/lib/storage/src/lmdb.rs +++ b/src/lib/storage/src/lmdb.rs @@ -1,4 +1,3 @@ - use crate::errors::StorageError; use heed; use heed::byteorder::BigEndian; From cd09d0f8f8e1fd650cd6b901386c98434317d1bd Mon Sep 17 00:00:00 2001 From: Outspending Date: Mon, 30 Dec 2024 12:12:45 -0700 Subject: [PATCH 17/38] better error handling --- src/bin/src/packet_handlers/containers.rs | 3 +-- src/bin/src/packet_handlers/login_process.rs | 2 +- src/bin/src/packet_handlers/mod.rs | 2 +- src/lib/inventory/Cargo.toml | 1 + src/lib/inventory/src/inventory.rs | 25 ++++++++++++++++++-- 5 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/bin/src/packet_handlers/containers.rs b/src/bin/src/packet_handlers/containers.rs index ecc5248e..ac8fa93a 100644 --- a/src/bin/src/packet_handlers/containers.rs +++ b/src/bin/src/packet_handlers/containers.rs @@ -1,4 +1,3 @@ -use tracing::info; use ferrumc_inventory::inventory::Inventory; use ferrumc_macros::event_handler; use ferrumc_net::errors::NetError; @@ -14,4 +13,4 @@ async fn container_close( state.universe.remove_component::(conn_id)?; Ok(container_close_event) -} \ No newline at end of file +} diff --git a/src/bin/src/packet_handlers/login_process.rs b/src/bin/src/packet_handlers/login_process.rs index 4c315da0..4640d147 100644 --- a/src/bin/src/packet_handlers/login_process.rs +++ b/src/bin/src/packet_handlers/login_process.rs @@ -211,7 +211,7 @@ async fn handle_ack_finish_configuration( inventory.set_slot(0, Slot::with_item(1)); inventory.set_slot(1, Slot::with_item(2)); - inventory.add_viewer(state, conn_id).await?; + inventory.add_viewer(state, conn_id).await.unwrap(); Ok(ack_finish_configuration_event) } diff --git a/src/bin/src/packet_handlers/mod.rs b/src/bin/src/packet_handlers/mod.rs index 3e7524a0..7a157e29 100644 --- a/src/bin/src/packet_handlers/mod.rs +++ b/src/bin/src/packet_handlers/mod.rs @@ -1,5 +1,5 @@ +mod containers; mod handshake; mod login_process; mod tick_handler; mod transform; -mod containers; diff --git a/src/lib/inventory/Cargo.toml b/src/lib/inventory/Cargo.toml index 8ad0e644..a366c25a 100644 --- a/src/lib/inventory/Cargo.toml +++ b/src/lib/inventory/Cargo.toml @@ -16,6 +16,7 @@ ferrumc-state = { workspace = true } tokio = {workspace = true } dashmap = { workspace = true } log = { workspace = true } +thiserror = { workspace = true } [lints] workspace = true diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs index d3e00141..0313e274 100644 --- a/src/lib/inventory/src/inventory.rs +++ b/src/lib/inventory/src/inventory.rs @@ -3,6 +3,7 @@ use crate::events::inventory_open::OpenInventoryEvent; use crate::slot::Slot; use dashmap::DashMap; use ferrumc_ecs::entities::Entity; +use ferrumc_ecs::errors::ECSError; use ferrumc_events::infrastructure::Event; use ferrumc_net::connection::StreamWriter; use ferrumc_net::errors::NetError; @@ -15,6 +16,7 @@ use ferrumc_net_codec::net_types::var_int::VarInt; use ferrumc_state::ServerState; use ferrumc_text::{TextComponent, TextComponentBuilder}; use std::sync::Arc; +use thiserror::Error; #[derive(Debug, Clone, Copy)] pub enum InventoryType { @@ -93,6 +95,21 @@ impl InventoryType { } } +#[derive(Error, Debug)] +pub enum InventoryError { + #[error("Entity [{0}] already has an open inventory. Cannot open another one.")] + AlreadyOpenedInventory(Entity), + + #[error("Net error: [{0}].")] + NetError(#[from] NetError), + + #[error("ECS error: [{0}].")] + ECSError(#[from] ECSError), + + #[error("Unknown error occurred with inventories...")] + Unknown, +} + #[derive(Debug, Clone)] pub struct Inventory { pub id: VarInt, @@ -133,10 +150,14 @@ impl Inventory { self, state: Arc, entity_id: Entity, - ) -> Result<(), NetError> { + ) -> Result<(), InventoryError> { let universe = &state.universe; let mut writer = universe.get_mut::(entity_id)?; + if universe.get::(entity_id).is_ok() { + return Err(InventoryError::AlreadyOpenedInventory(entity_id)); + } + let packet = OpenScreenPacket::new(self.id, self.inventory_type.get_id(), self.title.clone()); @@ -173,7 +194,7 @@ impl Inventory { &mut self, state: Arc, entity_id: Entity, - ) -> Result<(), NetError> { + ) -> Result<(), InventoryError> { let universe = &state.universe; let mut writer = universe.get_mut::(entity_id)?; let inventory = universe.get::(entity_id)?; From 816391bc91b9b5fe3fb1c18b9e03dff621e688d5 Mon Sep 17 00:00:00 2001 From: Outspending Date: Mon, 30 Dec 2024 12:42:13 -0700 Subject: [PATCH 18/38] Inventory Clicking --- src/bin/src/packet_handlers/login_process.rs | 3 +- src/lib/inventory/src/inventory.rs | 6 ++ .../src/packets/incoming/click_container.rs | 84 +++++++++++++++++++ src/lib/net/src/packets/incoming/mod.rs | 1 + .../packets/outgoing/set_container_slot.rs | 16 +++- 5 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 src/lib/net/src/packets/incoming/click_container.rs diff --git a/src/bin/src/packet_handlers/login_process.rs b/src/bin/src/packet_handlers/login_process.rs index 4640d147..cbcff5d3 100644 --- a/src/bin/src/packet_handlers/login_process.rs +++ b/src/bin/src/packet_handlers/login_process.rs @@ -208,8 +208,7 @@ async fn handle_ack_finish_configuration( } let mut inventory = Inventory::new(1, "Outspending's Inventory", InventoryType::Chest(6)); - inventory.set_slot(0, Slot::with_item(1)); - inventory.set_slot(1, Slot::with_item(2)); + inventory.set_all(Slot::with_item(9)); inventory.add_viewer(state, conn_id).await.unwrap(); diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs index 0313e274..9ff4c30a 100644 --- a/src/lib/inventory/src/inventory.rs +++ b/src/lib/inventory/src/inventory.rs @@ -220,6 +220,12 @@ impl Inventory { self.get_contents().clear(); } + pub fn set_all(&mut self, slot: Slot) { + for i in 0..self.get_size() { + self.set_slot(i, slot); + } + } + pub fn contains(&self, item: i32) -> bool { self.get_contents() .iter() diff --git a/src/lib/net/src/packets/incoming/click_container.rs b/src/lib/net/src/packets/incoming/click_container.rs new file mode 100644 index 00000000..f9dadb8c --- /dev/null +++ b/src/lib/net/src/packets/incoming/click_container.rs @@ -0,0 +1,84 @@ +use crate::packets::outgoing::set_container_slot::NetworkSlot; +use crate::packets::IncomingPacket; +use crate::NetResult; +use ferrumc_events::infrastructure::Event; +use ferrumc_macros::{packet, Event, NetDecode}; +use ferrumc_net_codec::net_types::length_prefixed_vec::LengthPrefixedVec; +use ferrumc_net_codec::net_types::var_int::VarInt; +use ferrumc_state::ServerState; +use std::sync::Arc; + +#[derive(NetDecode, Debug)] +pub struct ChangedSlots { + pub slot_number: u16, + pub slot: NetworkSlot, +} + +impl ChangedSlots { + pub fn new(slot_number: u16, slot: NetworkSlot) -> Self { + Self { slot_number, slot } + } +} + +#[derive(NetDecode, Debug)] +#[packet(packet_id = 0x0E, state = "play")] +pub struct ClickContainerPacket { + pub window_id: u8, + pub state_id: VarInt, + pub slot: u16, + pub button: u8, + pub mode: VarInt, + pub changed_slots: LengthPrefixedVec, + pub carried_item: NetworkSlot, +} + +impl IncomingPacket for ClickContainerPacket { + async fn handle(self, conn_id: usize, state: Arc) -> NetResult<()> { + let event = InventoryClickEvent::new(conn_id, self); + InventoryClickEvent::trigger(event, state).await?; + Ok(()) + } +} + +impl ClickContainerPacket { + pub fn new( + window_id: u8, + state_id: VarInt, + slot: u16, + button: u8, + mode: VarInt, + changed_slots: LengthPrefixedVec, + carried_item: NetworkSlot, + ) -> Self { + Self { + window_id, + state_id, + slot, + button, + mode, + changed_slots, + carried_item, + } + } +} + +#[derive(Event, Debug)] +pub struct InventoryClickEvent { + pub conn_id: usize, + pub packet: ClickContainerPacket, + pub is_cancelled: bool, +} + +impl InventoryClickEvent { + pub fn new(conn_id: usize, packet: ClickContainerPacket) -> Self { + Self { + conn_id, + packet, + is_cancelled: false, + } + } + + pub fn set_cancelled(&mut self, is_cancelled: bool) { + self.is_cancelled = is_cancelled; + } +} diff --git a/src/lib/net/src/packets/incoming/mod.rs b/src/lib/net/src/packets/incoming/mod.rs index 4a47366d..836b971a 100644 --- a/src/lib/net/src/packets/incoming/mod.rs +++ b/src/lib/net/src/packets/incoming/mod.rs @@ -11,6 +11,7 @@ pub mod status_request; pub mod keep_alive; pub mod packet_skeleton; +pub mod click_container; pub mod close_container; pub mod set_player_position; pub mod set_player_position_and_rotation; 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 160b6fc6..b9781a2f 100644 --- a/src/lib/net/src/packets/outgoing/set_container_slot.rs +++ b/src/lib/net/src/packets/outgoing/set_container_slot.rs @@ -1,8 +1,9 @@ use ferrumc_macros::{packet, NetEncode}; +use ferrumc_net_codec::decode::{NetDecode, NetDecodeOpts, NetDecodeResult}; use ferrumc_net_codec::net_types::var_int::VarInt; -use std::io::Write; +use std::io::{Read, Write}; -#[derive(NetEncode)] +#[derive(NetEncode, Debug)] pub struct NetworkSlot { pub item_count: VarInt, pub item_id: Option, @@ -10,6 +11,17 @@ pub struct NetworkSlot { pub num_of_components_to_remove: Option, } +impl NetDecode for NetworkSlot { + fn decode(reader: &mut R, opts: &NetDecodeOpts) -> NetDecodeResult { + let item_count = VarInt::decode(reader, opts)?; + if *item_count == 0 { + Ok(Self::empty()) + } else { + Ok(Self::new(item_count.val, *VarInt::decode(reader, opts)?)) + } + } +} + impl NetworkSlot { pub fn new(item_count: i32, item_id: i32) -> Self { if item_count == 0 { From 63ad32eb9558dbc4edf5acb9e64c6691ee81eebc Mon Sep 17 00:00:00 2001 From: Outspending Date: Mon, 30 Dec 2024 20:02:22 -0700 Subject: [PATCH 19/38] better inventory packets --- src/lib/inventory/src/contents.rs | 30 ++++++++++++++++++-- src/lib/inventory/src/inventory.rs | 45 +++++++++++++++++++----------- 2 files changed, 55 insertions(+), 20 deletions(-) diff --git a/src/lib/inventory/src/contents.rs b/src/lib/inventory/src/contents.rs index 16dc87b1..d824f27b 100644 --- a/src/lib/inventory/src/contents.rs +++ b/src/lib/inventory/src/contents.rs @@ -1,5 +1,7 @@ use crate::slot::Slot; use dashmap::DashMap; +use ferrumc_net::packets::outgoing::set_container_slot::NetworkSlot; +use ferrumc_net_codec::net_types::length_prefixed_vec::LengthPrefixedVec; #[derive(Debug, Clone)] pub struct InventoryContents { @@ -7,9 +9,18 @@ pub struct InventoryContents { } impl InventoryContents { - pub fn empty() -> Self { - Self { - contents: DashMap::new(), + pub fn empty(size: usize) -> Self { + let mut empty = Self { + contents: DashMap::with_capacity(size), + }; + + empty.fill(0); + empty + } + + pub fn fill(&mut self, item: i32) { + for i in 0..(self.contents.capacity() as i32) { + self.contents.insert(i, Slot::new(1, item)); } } @@ -22,6 +33,19 @@ impl InventoryContents { self.contents.get(&item).map(|v| *v) } + pub fn get_size(&self) -> usize { + self.contents.capacity() + } + + pub(crate) fn construct_packet_contents(&self) -> LengthPrefixedVec { + let mut contents = LengthPrefixedVec::new(Vec::with_capacity(self.get_size())); + self.contents.iter().for_each(|slot| { + contents.data.push(slot.value().to_network_slot()); + }); + + contents + } + //to store in chunk metadata: TAG 44: byte //to show: starts at slot 0 ALWAYS - > 26/53 smalll/large. //other inventories are to be implemented after. diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs index 9ff4c30a..d04d3076 100644 --- a/src/lib/inventory/src/inventory.rs +++ b/src/lib/inventory/src/inventory.rs @@ -10,7 +10,8 @@ use ferrumc_net::errors::NetError; use ferrumc_net::packets::incoming::close_container::InventoryCloseEvent; use ferrumc_net::packets::outgoing::close_container::CloseContainerPacket; use ferrumc_net::packets::outgoing::open_screen::OpenScreenPacket; -use ferrumc_net::packets::outgoing::set_container_slot::SetContainerSlotPacket; +use ferrumc_net::packets::outgoing::set_container_content::SetContainerContentPacket; +use ferrumc_net::packets::outgoing::set_container_slot::{NetworkSlot, SetContainerSlotPacket}; use ferrumc_net_codec::encode::NetEncodeOpts; use ferrumc_net_codec::net_types::var_int::VarInt; use ferrumc_state::ServerState; @@ -124,7 +125,7 @@ impl Inventory { id: VarInt::new(id), inventory_type, title: TextComponentBuilder::new(title).build(), - contents: InventoryContents::empty(), + contents: InventoryContents::empty(inventory_type.get_size() as usize), } } @@ -166,21 +167,31 @@ impl Inventory { .await?; let id = self.id; - let contents = self.get_contents(); - if !contents.is_empty() { - for slot in contents.iter() { - writer - .send_packet( - &SetContainerSlotPacket::new( - id, - *slot.key() as i16, - slot.value().to_network_slot(), - ), - &NetEncodeOpts::WithLength, - ) - .await?; - } - } + writer + .send_packet( + &SetContainerContentPacket::new( + *id as u8, + self.contents.construct_packet_contents(), + NetworkSlot::empty(), + ), + &NetEncodeOpts::WithLength, + ) + .await?; + + // if !contents.is_empty() { + // for slot in contents.iter() { + // writer + // .send_packet( + // &SetContainerSlotPacket::new( + // id, + // *slot.key() as i16, + // slot.value().to_network_slot(), + // ), + // &NetEncodeOpts::WithLength, + // ) + // .await?; + // } + // } // handle event let event = OpenInventoryEvent::new(entity_id).inventory_id(*id); From f2acd8d6d24118b3913551501ab088c2ffc24aeb Mon Sep 17 00:00:00 2001 From: Outspending Date: Tue, 31 Dec 2024 09:28:51 -0700 Subject: [PATCH 20/38] content packet --- src/bin/src/packet_handlers/login_process.rs | 7 +++- src/lib/derive_macros/Cargo.toml | 3 +- src/lib/derive_macros/src/net/decode.rs | 33 ++++++++-------- src/lib/inventory/Cargo.toml | 2 +- src/lib/inventory/src/contents.rs | 26 ++++++------- src/lib/inventory/src/inventory.rs | 22 +++++++---- src/lib/net/src/packets/incoming/mod.rs | 4 ++ .../packets/outgoing/set_container_content.rs | 4 +- .../packets/outgoing/set_container_slot.rs | 39 ++++++------------- 9 files changed, 70 insertions(+), 70 deletions(-) diff --git a/src/bin/src/packet_handlers/login_process.rs b/src/bin/src/packet_handlers/login_process.rs index cbcff5d3..1f659877 100644 --- a/src/bin/src/packet_handlers/login_process.rs +++ b/src/bin/src/packet_handlers/login_process.rs @@ -29,7 +29,7 @@ use ferrumc_net::packets::outgoing::set_render_distance::SetRenderDistance; use ferrumc_net::packets::outgoing::synchronize_player_position::SynchronizePlayerPositionPacket; use ferrumc_net_codec::encode::NetEncodeOpts; use ferrumc_state::GlobalState; -use tracing::{debug, trace}; +use tracing::{debug, info, trace}; #[event_handler] async fn handle_login_start( @@ -208,7 +208,10 @@ async fn handle_ack_finish_configuration( } let mut inventory = Inventory::new(1, "Outspending's Inventory", InventoryType::Chest(6)); - inventory.set_all(Slot::with_item(9)); + + inventory.set_slot(0, Slot::with_item(1)); + + info!("{:?}", inventory.get_contents().len()); inventory.add_viewer(state, conn_id).await.unwrap(); diff --git a/src/lib/derive_macros/Cargo.toml b/src/lib/derive_macros/Cargo.toml index fb0a2c61..a736bfc4 100644 --- a/src/lib/derive_macros/Cargo.toml +++ b/src/lib/derive_macros/Cargo.toml @@ -16,4 +16,5 @@ quote = { workspace = true } syn = { workspace = true, features = ["full"] } thiserror = { workspace = true } proc-macro2 = { workspace = true } -proc-macro-crate = { workspace = true } \ No newline at end of file +proc-macro-crate = { workspace = true } +regex = { workspace = true } \ No newline at end of file diff --git a/src/lib/derive_macros/src/net/decode.rs b/src/lib/derive_macros/src/net/decode.rs index b3407f27..8d79c7e4 100644 --- a/src/lib/derive_macros/src/net/decode.rs +++ b/src/lib/derive_macros/src/net/decode.rs @@ -154,6 +154,8 @@ pub(crate) fn derive(input: TokenStream) -> TokenStream { let mut decode_statements = Vec::new(); let mut field_names = Vec::new(); + let optional_type_regex = regex::Regex::new(r"Option\s*<\s*(.+?)\s*>").unwrap(); + for field in fields { let field_name = field .ident @@ -168,24 +170,16 @@ pub(crate) fn derive(input: TokenStream) -> TokenStream { // Check the `net(...)` attributes on this field for attr in &field.attrs { if attr.path().is_ident("net") { - // e.g., #[net(optional_trigger = { some_field == true })] - attr.parse_nested_meta(|meta| { if let Some(ident) = meta.path.get_ident() { if ident.to_string().as_str() == "optional_trigger" { - meta.parse_nested_meta(|meta| { - if let Some(expr) = meta.path.get_ident() { - let val = syn::parse_str::(&expr.to_string()) - .expect("Failed to parse optional_trigger expression"); + let value = meta.value().expect("Missing optional_trigger value"); - optional_trigger_expr = Some(val); - } else { - panic!("Expected an expression for optional_trigger"); - } + let value = value + .parse::() + .expect("Failed to parse optional_trigger"); - Ok(()) - }) - .expect("Failed to parse optional_trigger expression"); + optional_trigger_expr = Some(value); } } Ok(()) @@ -196,9 +190,16 @@ pub(crate) fn derive(input: TokenStream) -> TokenStream { // Generate decoding code depending on whether there's an optional trigger if let Some(expr) = optional_trigger_expr { - // For an optional field, we decode it only if `expr` is true at runtime. - // We'll store the result in a local variable `field_name` which will be an Option. - // Then at the end, we can build the struct using those local variables. + let field_type = quote! { #field_ty }.to_string(); + + let inner = optional_type_regex + .captures(&field_type) + .expect("Field must be Option") + .get(1) + .unwrap() + .as_str(); + let field_ty = syn::parse_str::(inner).expect("Failed to parse field type"); + decode_statements.push(quote! { let #field_name = { if #expr { diff --git a/src/lib/inventory/Cargo.toml b/src/lib/inventory/Cargo.toml index a366c25a..53eec712 100644 --- a/src/lib/inventory/Cargo.toml +++ b/src/lib/inventory/Cargo.toml @@ -15,8 +15,8 @@ ferrumc-state = { workspace = true } tokio = {workspace = true } dashmap = { workspace = true } -log = { workspace = true } thiserror = { workspace = true } +tracing = { workspace = true } [lints] workspace = true diff --git a/src/lib/inventory/src/contents.rs b/src/lib/inventory/src/contents.rs index d824f27b..caa7a87b 100644 --- a/src/lib/inventory/src/contents.rs +++ b/src/lib/inventory/src/contents.rs @@ -1,26 +1,27 @@ +use std::collections::HashMap; use crate::slot::Slot; -use dashmap::DashMap; +use tracing::info; use ferrumc_net::packets::outgoing::set_container_slot::NetworkSlot; use ferrumc_net_codec::net_types::length_prefixed_vec::LengthPrefixedVec; #[derive(Debug, Clone)] pub struct InventoryContents { - pub contents: DashMap, + pub contents: HashMap, } impl InventoryContents { pub fn empty(size: usize) -> Self { let mut empty = Self { - contents: DashMap::with_capacity(size), + contents: HashMap::with_capacity(size), }; - empty.fill(0); + empty.fill(Slot::empty()); empty } - pub fn fill(&mut self, item: i32) { - for i in 0..(self.contents.capacity() as i32) { - self.contents.insert(i, Slot::new(1, item)); + pub fn fill(&mut self, slot: Slot) { + for i in 0..self.contents.len() as i32 { + self.contents.insert(i, slot); } } @@ -33,16 +34,13 @@ impl InventoryContents { self.contents.get(&item).map(|v| *v) } - pub fn get_size(&self) -> usize { - self.contents.capacity() - } - pub(crate) fn construct_packet_contents(&self) -> LengthPrefixedVec { - let mut contents = LengthPrefixedVec::new(Vec::with_capacity(self.get_size())); - self.contents.iter().for_each(|slot| { - contents.data.push(slot.value().to_network_slot()); + let mut contents = LengthPrefixedVec::new(Vec::with_capacity(self.contents.len())); + self.contents.iter().for_each(|(_, slot)| { + contents.data.push(slot.to_network_slot()); }); + info!("{:?}", contents); contents } diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs index d04d3076..be2fef24 100644 --- a/src/lib/inventory/src/inventory.rs +++ b/src/lib/inventory/src/inventory.rs @@ -1,7 +1,8 @@ +use std::collections::HashMap; use crate::contents::InventoryContents; use crate::events::inventory_open::OpenInventoryEvent; use crate::slot::Slot; -use dashmap::DashMap; + use ferrumc_ecs::entities::Entity; use ferrumc_ecs::errors::ECSError; use ferrumc_events::infrastructure::Event; @@ -17,6 +18,7 @@ use ferrumc_net_codec::net_types::var_int::VarInt; use ferrumc_state::ServerState; use ferrumc_text::{TextComponent, TextComponentBuilder}; use std::sync::Arc; +use tracing::info; use thiserror::Error; #[derive(Debug, Clone, Copy)] @@ -178,14 +180,15 @@ impl Inventory { ) .await?; + // let contents = self.get_contents(); // if !contents.is_empty() { - // for slot in contents.iter() { + // for (&slot_num, &slot) in contents.iter() { // writer // .send_packet( // &SetContainerSlotPacket::new( // id, - // *slot.key() as i16, - // slot.value().to_network_slot(), + // slot_num as i16, + // slot.to_network_slot(), // ), // &NetEncodeOpts::WithLength, // ) @@ -223,12 +226,17 @@ impl Inventory { Ok(()) } - pub fn get_contents(&self) -> &DashMap { + pub fn get_contents(&self) -> &HashMap { &self.contents.contents } + pub fn get_contents_mut(&mut self) -> &mut HashMap { + &mut self.contents.contents + } + + pub fn clear(&mut self) { - self.get_contents().clear(); + self.get_contents_mut().clear(); } pub fn set_all(&mut self, slot: Slot) { @@ -240,7 +248,7 @@ impl Inventory { pub fn contains(&self, item: i32) -> bool { self.get_contents() .iter() - .any(|slot| slot.value().item == item) + .any(|slot| slot.1.item == item) } pub fn contains_slot(&self, slot: Slot) -> bool { diff --git a/src/lib/net/src/packets/incoming/mod.rs b/src/lib/net/src/packets/incoming/mod.rs index 257e3bc5..c0711cd4 100644 --- a/src/lib/net/src/packets/incoming/mod.rs +++ b/src/lib/net/src/packets/incoming/mod.rs @@ -16,3 +16,7 @@ pub mod set_player_position_and_rotation; pub mod set_player_rotation; pub mod swing_arm; + +pub mod click_container; +pub mod close_container; +pub mod use_item_on; 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 969dcc20..d3abc735 100644 --- a/src/lib/net/src/packets/outgoing/set_container_content.rs +++ b/src/lib/net/src/packets/outgoing/set_container_content.rs @@ -1,9 +1,9 @@ +use super::set_container_slot::NetworkSlot; use ferrumc_macros::{packet, NetEncode}; +use ferrumc_net_codec::encode::NetEncode; use ferrumc_net_codec::net_types::{length_prefixed_vec::LengthPrefixedVec, var_int::VarInt}; use std::io::Write; -use super::set_container_slot::NetworkSlot; - #[derive(NetEncode)] #[packet(packet_id = 0x13)] 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 b9781a2f..908b67a1 100644 --- a/src/lib/net/src/packets/outgoing/set_container_slot.rs +++ b/src/lib/net/src/packets/outgoing/set_container_slot.rs @@ -1,43 +1,28 @@ -use ferrumc_macros::{packet, NetEncode}; +use ferrumc_macros::{packet, NetDecode, NetEncode}; use ferrumc_net_codec::decode::{NetDecode, NetDecodeOpts, NetDecodeResult}; use ferrumc_net_codec::net_types::var_int::VarInt; use std::io::{Read, Write}; +use ferrumc_net_codec::encode::{NetEncode, NetEncodeOpts, NetEncodeResult}; -#[derive(NetEncode, Debug)] +#[derive(NetDecode, NetEncode, Debug)] 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 NetDecode for NetworkSlot { - fn decode(reader: &mut R, opts: &NetDecodeOpts) -> NetDecodeResult { - let item_count = VarInt::decode(reader, opts)?; - if *item_count == 0 { - Ok(Self::empty()) - } else { - Ok(Self::new(item_count.val, *VarInt::decode(reader, opts)?)) - } - } -} - impl NetworkSlot { pub fn new(item_count: i32, item_id: i32) -> Self { - if item_count == 0 { - Self { - item_count: VarInt::new(0), - item_id: None, - num_of_components_to_add: None, - num_of_components_to_remove: None, - } - } else { - Self { - item_count: VarInt::new(item_count), - item_id: Some(VarInt::new(item_id)), - num_of_components_to_add: Some(VarInt::new(0)), - num_of_components_to_remove: Some(VarInt::new(0)), - } + 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, } } From 7d404b224464d490b8ac94fd6aa8a615892ec672 Mon Sep 17 00:00:00 2001 From: Outspending Date: Tue, 31 Dec 2024 10:07:57 -0700 Subject: [PATCH 21/38] Fixed Container Content Packet --- src/bin/src/packet_handlers/login_process.rs | 5 +---- src/lib/inventory/src/contents.rs | 20 +++++++++---------- src/lib/inventory/src/inventory.rs | 14 +++++-------- .../packets/outgoing/set_container_content.rs | 3 +-- .../packets/outgoing/set_container_slot.rs | 16 ++++++++++----- 5 files changed, 28 insertions(+), 30 deletions(-) diff --git a/src/bin/src/packet_handlers/login_process.rs b/src/bin/src/packet_handlers/login_process.rs index 1f659877..58926d89 100644 --- a/src/bin/src/packet_handlers/login_process.rs +++ b/src/bin/src/packet_handlers/login_process.rs @@ -29,7 +29,7 @@ use ferrumc_net::packets::outgoing::set_render_distance::SetRenderDistance; use ferrumc_net::packets::outgoing::synchronize_player_position::SynchronizePlayerPositionPacket; use ferrumc_net_codec::encode::NetEncodeOpts; use ferrumc_state::GlobalState; -use tracing::{debug, info, trace}; +use tracing::{debug, trace}; #[event_handler] async fn handle_login_start( @@ -208,11 +208,8 @@ async fn handle_ack_finish_configuration( } let mut inventory = Inventory::new(1, "Outspending's Inventory", InventoryType::Chest(6)); - inventory.set_slot(0, Slot::with_item(1)); - info!("{:?}", inventory.get_contents().len()); - inventory.add_viewer(state, conn_id).await.unwrap(); Ok(ack_finish_configuration_event) diff --git a/src/lib/inventory/src/contents.rs b/src/lib/inventory/src/contents.rs index caa7a87b..31443bf2 100644 --- a/src/lib/inventory/src/contents.rs +++ b/src/lib/inventory/src/contents.rs @@ -1,18 +1,19 @@ -use std::collections::HashMap; use crate::slot::Slot; -use tracing::info; use ferrumc_net::packets::outgoing::set_container_slot::NetworkSlot; use ferrumc_net_codec::net_types::length_prefixed_vec::LengthPrefixedVec; +use std::collections::BTreeMap; #[derive(Debug, Clone)] pub struct InventoryContents { - pub contents: HashMap, + pub contents: BTreeMap, + pub size: usize, } impl InventoryContents { pub fn empty(size: usize) -> Self { let mut empty = Self { - contents: HashMap::with_capacity(size), + contents: BTreeMap::new(), + size, }; empty.fill(Slot::empty()); @@ -20,7 +21,7 @@ impl InventoryContents { } pub fn fill(&mut self, slot: Slot) { - for i in 0..self.contents.len() as i32 { + for i in 0..self.size as i32 { self.contents.insert(i, slot); } } @@ -31,17 +32,16 @@ impl InventoryContents { } pub fn get_slot(&self, item: i32) -> Option { - self.contents.get(&item).map(|v| *v) + self.contents.get(&item).copied() } pub(crate) fn construct_packet_contents(&self) -> LengthPrefixedVec { - let mut contents = LengthPrefixedVec::new(Vec::with_capacity(self.contents.len())); + let mut contents = vec![]; self.contents.iter().for_each(|(_, slot)| { - contents.data.push(slot.to_network_slot()); + contents.push(slot.to_network_slot()); }); - info!("{:?}", contents); - contents + LengthPrefixedVec::new(contents) } //to store in chunk metadata: TAG 44: byte diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs index be2fef24..351dbfee 100644 --- a/src/lib/inventory/src/inventory.rs +++ b/src/lib/inventory/src/inventory.rs @@ -1,7 +1,7 @@ -use std::collections::HashMap; use crate::contents::InventoryContents; use crate::events::inventory_open::OpenInventoryEvent; use crate::slot::Slot; +use std::collections::BTreeMap; use ferrumc_ecs::entities::Entity; use ferrumc_ecs::errors::ECSError; @@ -12,13 +12,12 @@ use ferrumc_net::packets::incoming::close_container::InventoryCloseEvent; use ferrumc_net::packets::outgoing::close_container::CloseContainerPacket; use ferrumc_net::packets::outgoing::open_screen::OpenScreenPacket; use ferrumc_net::packets::outgoing::set_container_content::SetContainerContentPacket; -use ferrumc_net::packets::outgoing::set_container_slot::{NetworkSlot, SetContainerSlotPacket}; +use ferrumc_net::packets::outgoing::set_container_slot::NetworkSlot; use ferrumc_net_codec::encode::NetEncodeOpts; use ferrumc_net_codec::net_types::var_int::VarInt; use ferrumc_state::ServerState; use ferrumc_text::{TextComponent, TextComponentBuilder}; use std::sync::Arc; -use tracing::info; use thiserror::Error; #[derive(Debug, Clone, Copy)] @@ -226,15 +225,14 @@ impl Inventory { Ok(()) } - pub fn get_contents(&self) -> &HashMap { + pub fn get_contents(&self) -> &BTreeMap { &self.contents.contents } - pub fn get_contents_mut(&mut self) -> &mut HashMap { + pub fn get_contents_mut(&mut self) -> &mut BTreeMap { &mut self.contents.contents } - pub fn clear(&mut self) { self.get_contents_mut().clear(); } @@ -246,9 +244,7 @@ impl Inventory { } pub fn contains(&self, item: i32) -> bool { - self.get_contents() - .iter() - .any(|slot| slot.1.item == item) + self.get_contents().iter().any(|slot| slot.1.item == item) } pub fn contains_slot(&self, slot: Slot) -> bool { 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 d3abc735..bc9ead26 100644 --- a/src/lib/net/src/packets/outgoing/set_container_content.rs +++ b/src/lib/net/src/packets/outgoing/set_container_content.rs @@ -1,10 +1,9 @@ use super::set_container_slot::NetworkSlot; use ferrumc_macros::{packet, NetEncode}; -use ferrumc_net_codec::encode::NetEncode; use ferrumc_net_codec::net_types::{length_prefixed_vec::LengthPrefixedVec, var_int::VarInt}; use std::io::Write; -#[derive(NetEncode)] +#[derive(NetEncode, Debug)] #[packet(packet_id = 0x13)] pub struct SetContainerContentPacket { pub window_id: u8, 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 908b67a1..a867cc2d 100644 --- a/src/lib/net/src/packets/outgoing/set_container_slot.rs +++ b/src/lib/net/src/packets/outgoing/set_container_slot.rs @@ -1,8 +1,6 @@ use ferrumc_macros::{packet, NetDecode, NetEncode}; -use ferrumc_net_codec::decode::{NetDecode, NetDecodeOpts, NetDecodeResult}; use ferrumc_net_codec::net_types::var_int::VarInt; -use std::io::{Read, Write}; -use ferrumc_net_codec::encode::{NetEncode, NetEncodeOpts, NetEncodeResult}; +use std::io::Write; #[derive(NetDecode, NetEncode, Debug)] pub struct NetworkSlot { @@ -17,10 +15,18 @@ pub struct NetworkSlot { impl NetworkSlot { pub fn new(item_count: i32, item_id: i32) -> Self { - let components = if item_count == 0 { None } else { Some(VarInt::new(0)) }; + 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)) }, + 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, } From dd1b152c293f706df6c99171d3ed7b12657608f0 Mon Sep 17 00:00:00 2001 From: Outspending Date: Tue, 31 Dec 2024 11:04:52 -0700 Subject: [PATCH 22/38] inventory syncing --- src/lib/inventory/Cargo.toml | 1 + src/lib/inventory/src/inventory.rs | 47 ++++++++++++++++++++---------- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/lib/inventory/Cargo.toml b/src/lib/inventory/Cargo.toml index 53eec712..5136c8be 100644 --- a/src/lib/inventory/Cargo.toml +++ b/src/lib/inventory/Cargo.toml @@ -11,6 +11,7 @@ ferrumc-text = { workspace = true } ferrumc-ecs = { workspace = true } ferrumc-events = { workspace = true } ferrumc-macros = { workspace = true } +ferrumc-core = { workspace = true } ferrumc-state = { workspace = true } tokio = {workspace = true } diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs index 351dbfee..23242129 100644 --- a/src/lib/inventory/src/inventory.rs +++ b/src/lib/inventory/src/inventory.rs @@ -3,6 +3,7 @@ use crate::events::inventory_open::OpenInventoryEvent; use crate::slot::Slot; use std::collections::BTreeMap; +use ferrumc_core::chunks::chunk_receiver::ChunkReceiver; use ferrumc_ecs::entities::Entity; use ferrumc_ecs::errors::ECSError; use ferrumc_events::infrastructure::Event; @@ -148,6 +149,36 @@ impl Inventory { } } + pub async fn sync_inventory(&mut self, state: Arc) -> Result<(), InventoryError> { + let universe = &state.universe; + let query = universe + .get_component_manager() + .get_entities_with::(); + + for entity_id in query { + let inventory_result = universe.get_mut::(entity_id); + match inventory_result { + Ok(inventory) => { + let mut writer = universe.get_mut::(entity_id)?; + let contents = inventory.contents.construct_packet_contents(); + writer + .send_packet( + &SetContainerContentPacket::new( + *inventory.id as u8, + contents, + NetworkSlot::empty(), + ), + &NetEncodeOpts::WithLength, + ) + .await?; + } + Err(err) => return Err(InventoryError::ECSError(err)), + } + } + + Ok(()) + } + pub async fn add_viewer( self, state: Arc, @@ -179,22 +210,6 @@ impl Inventory { ) .await?; - // let contents = self.get_contents(); - // if !contents.is_empty() { - // for (&slot_num, &slot) in contents.iter() { - // writer - // .send_packet( - // &SetContainerSlotPacket::new( - // id, - // slot_num as i16, - // slot.to_network_slot(), - // ), - // &NetEncodeOpts::WithLength, - // ) - // .await?; - // } - // } - // handle event let event = OpenInventoryEvent::new(entity_id).inventory_id(*id); OpenInventoryEvent::trigger(event, state.clone()).await?; From 1e0dbab402d45b346640c513eb46178b7e832ae5 Mon Sep 17 00:00:00 2001 From: Outspending Date: Tue, 31 Dec 2024 11:06:02 -0700 Subject: [PATCH 23/38] inventory sync check --- src/lib/inventory/src/inventory.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs index 23242129..07924475 100644 --- a/src/lib/inventory/src/inventory.rs +++ b/src/lib/inventory/src/inventory.rs @@ -159,6 +159,10 @@ impl Inventory { let inventory_result = universe.get_mut::(entity_id); match inventory_result { Ok(inventory) => { + if *self.id != *inventory.id { + continue; + } + let mut writer = universe.get_mut::(entity_id)?; let contents = inventory.contents.construct_packet_contents(); writer From 5619a6370997c1e0a7ffcf69897c82e32b9a1a50 Mon Sep 17 00:00:00 2001 From: Outspending Date: Sat, 4 Jan 2025 07:33:49 -0700 Subject: [PATCH 24/38] Player / Creative Inventory Support --- src/bin/src/packet_handlers/containers.rs | 40 +++++- src/bin/src/packet_handlers/login_process.rs | 95 +++++++-------- src/bin/src/packet_handlers/mod.rs | 1 + src/lib/inventory/src/inventory.rs | 115 +++++++++++------- src/lib/inventory/src/lib.rs | 1 + src/lib/inventory/src/player_inventory.rs | 89 ++++++++++++++ src/lib/inventory/src/slot.rs | 13 ++ .../src/packets/incoming/click_container.rs | 3 + src/lib/net/src/packets/incoming/mod.rs | 2 + .../incoming/set_creative_mode_slot.rs | 37 ++++++ .../net/src/packets/incoming/set_held_item.rs | 34 ++++++ src/lib/net/src/packets/outgoing/mod.rs | 1 + .../net/src/packets/outgoing/open_screen.rs | 8 +- .../packets/outgoing/set_container_slot.rs | 2 +- .../net/src/packets/outgoing/set_equipment.rs | 60 +++++++++ 15 files changed, 398 insertions(+), 103 deletions(-) create mode 100644 src/lib/inventory/src/player_inventory.rs create mode 100644 src/lib/net/src/packets/incoming/set_creative_mode_slot.rs create mode 100644 src/lib/net/src/packets/incoming/set_held_item.rs create mode 100644 src/lib/net/src/packets/outgoing/set_equipment.rs diff --git a/src/bin/src/packet_handlers/containers.rs b/src/bin/src/packet_handlers/containers.rs index ac8fa93a..b103f138 100644 --- a/src/bin/src/packet_handlers/containers.rs +++ b/src/bin/src/packet_handlers/containers.rs @@ -1,7 +1,11 @@ use ferrumc_inventory::inventory::Inventory; +use ferrumc_inventory::player_inventory::PlayerInventory; +use ferrumc_inventory::slot::Slot; use ferrumc_macros::event_handler; use ferrumc_net::errors::NetError; use ferrumc_net::packets::incoming::close_container::InventoryCloseEvent; +use ferrumc_net::packets::incoming::set_creative_mode_slot::SetCreativeModeSlotEvent; +use ferrumc_net::packets::incoming::set_held_item::ChangeSlotEvent; use ferrumc_state::GlobalState; #[event_handler] @@ -11,6 +15,40 @@ async fn container_close( ) -> Result { let conn_id = container_close_event.conn_id; - state.universe.remove_component::(conn_id)?; + let window_id = container_close_event.window_id; + if window_id != 0 { + state.universe.remove_component::(conn_id)?; + } + Ok(container_close_event) } + +#[event_handler] +async fn set_creative_mode_slot( + creative_mode_slot: SetCreativeModeSlotEvent, + state: GlobalState, +) -> Result { + let conn_id = creative_mode_slot.conn_id; + let packet = &creative_mode_slot.packet; + + let mut inventory = state.universe.get_mut::(conn_id)?; + inventory.set_slot( + packet.slot as i32, + Slot::from_network_slot(packet.clicked_item), + ); + + Ok(creative_mode_slot) +} + +#[event_handler] +async fn handle_carried_item( + change_slot_event: ChangeSlotEvent, + state: GlobalState, +) -> Result { + let conn_id = change_slot_event.conn_id; + + let mut inventory = state.universe.get_mut::(conn_id)?; + inventory.set_carried_item(change_slot_event.packet.slot); + + Ok(change_slot_event) +} diff --git a/src/bin/src/packet_handlers/login_process.rs b/src/bin/src/packet_handlers/login_process.rs index 58926d89..7597dea2 100644 --- a/src/bin/src/packet_handlers/login_process.rs +++ b/src/bin/src/packet_handlers/login_process.rs @@ -5,8 +5,7 @@ use ferrumc_core::transform::grounded::OnGround; use ferrumc_core::transform::position::Position; use ferrumc_core::transform::rotation::Rotation; use ferrumc_ecs::components::storage::ComponentRefMut; -use ferrumc_inventory::inventory::{Inventory, InventoryType}; -use ferrumc_inventory::slot::Slot; +use ferrumc_inventory::player_inventory::PlayerInventory; use ferrumc_macros::event_handler; use ferrumc_net::connection::{ConnectionState, StreamWriter}; use ferrumc_net::errors::NetError; @@ -160,57 +159,51 @@ async fn handle_ack_finish_configuration( .universe .add_component::(conn_id, Position::default())? .add_component::(conn_id, Rotation::default())? - .add_component::(conn_id, OnGround::default())?; - - { - let mut writer = state.universe.get_mut::(conn_id)?; - - writer // 21 - .send_packet(&LoginPlayPacket::new(conn_id), &NetEncodeOpts::WithLength) - .await?; - writer // 29 - .send_packet( - &SynchronizePlayerPositionPacket::default(), // The coordinates here should be used for the center chunk. - &NetEncodeOpts::WithLength, - ) - .await?; - writer // 37 - .send_packet( - &SetDefaultSpawnPositionPacket::default(), // Player specific, aka. home, bed, where it would respawn. - &NetEncodeOpts::WithLength, - ) - .await?; - writer // 38 - .send_packet( - &GameEventPacket::start_waiting_for_level_chunks(), - &NetEncodeOpts::WithLength, - ) - .await?; - writer // 41 - .send_packet( - &SetCenterChunk::new(0, 0), // TODO - Dependent on the player spawn position. - &NetEncodeOpts::WithLength, - ) - .await?; - writer // other - .send_packet( - &SetRenderDistance::new(5), // TODO - &NetEncodeOpts::WithLength, - ) - .await?; - - let pos = state.universe.get_mut::(conn_id)?; - let mut chunk_recv = state.universe.get_mut::(conn_id)?; - chunk_recv.last_chunk = Some((pos.x as i32, pos.z as i32, String::from("overworld"))); - chunk_recv.calculate_chunks().await; - - send_keep_alive(conn_id, state.clone(), &mut writer).await?; - } + .add_component::(conn_id, OnGround::default())? + .add_component::(conn_id, PlayerInventory::default())?; + + let mut writer = state.universe.get_mut::(conn_id)?; + + writer // 21 + .send_packet(&LoginPlayPacket::new(conn_id), &NetEncodeOpts::WithLength) + .await?; + writer // 29 + .send_packet( + &SynchronizePlayerPositionPacket::default(), // The coordinates here should be used for the center chunk. + &NetEncodeOpts::WithLength, + ) + .await?; + writer // 37 + .send_packet( + &SetDefaultSpawnPositionPacket::default(), // Player specific, aka. home, bed, where it would respawn. + &NetEncodeOpts::WithLength, + ) + .await?; + writer // 38 + .send_packet( + &GameEventPacket::start_waiting_for_level_chunks(), + &NetEncodeOpts::WithLength, + ) + .await?; + writer // 41 + .send_packet( + &SetCenterChunk::new(0, 0), // TODO - Dependent on the player spawn position. + &NetEncodeOpts::WithLength, + ) + .await?; + writer // other + .send_packet( + &SetRenderDistance::new(5), // TODO + &NetEncodeOpts::WithLength, + ) + .await?; - let mut inventory = Inventory::new(1, "Outspending's Inventory", InventoryType::Chest(6)); - inventory.set_slot(0, Slot::with_item(1)); + let pos = state.universe.get_mut::(conn_id)?; + let mut chunk_recv = state.universe.get_mut::(conn_id)?; + chunk_recv.last_chunk = Some((pos.x as i32, pos.z as i32, String::from("overworld"))); + chunk_recv.calculate_chunks().await; - inventory.add_viewer(state, conn_id).await.unwrap(); + send_keep_alive(conn_id, state.clone(), &mut writer).await?; Ok(ack_finish_configuration_event) } diff --git a/src/bin/src/packet_handlers/mod.rs b/src/bin/src/packet_handlers/mod.rs index fbeb1603..8aa414eb 100644 --- a/src/bin/src/packet_handlers/mod.rs +++ b/src/bin/src/packet_handlers/mod.rs @@ -1,4 +1,5 @@ mod animations; +mod containers; mod handshake; mod login_process; mod tick_handler; diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs index 07924475..4af096e9 100644 --- a/src/lib/inventory/src/inventory.rs +++ b/src/lib/inventory/src/inventory.rs @@ -4,8 +4,8 @@ use crate::slot::Slot; use std::collections::BTreeMap; use ferrumc_core::chunks::chunk_receiver::ChunkReceiver; -use ferrumc_ecs::entities::Entity; use ferrumc_ecs::errors::ECSError; +use ferrumc_ecs::{components::storage::ComponentRefMut, entities::Entity}; use ferrumc_events::infrastructure::Event; use ferrumc_net::connection::StreamWriter; use ferrumc_net::errors::NetError; @@ -13,7 +13,6 @@ use ferrumc_net::packets::incoming::close_container::InventoryCloseEvent; use ferrumc_net::packets::outgoing::close_container::CloseContainerPacket; use ferrumc_net::packets::outgoing::open_screen::OpenScreenPacket; use ferrumc_net::packets::outgoing::set_container_content::SetContainerContentPacket; -use ferrumc_net::packets::outgoing::set_container_slot::NetworkSlot; use ferrumc_net_codec::encode::NetEncodeOpts; use ferrumc_net_codec::net_types::var_int::VarInt; use ferrumc_state::ServerState; @@ -103,6 +102,9 @@ pub enum InventoryError { #[error("Entity [{0}] already has an open inventory. Cannot open another one.")] AlreadyOpenedInventory(Entity), + #[error("Invalid equipment slot for PlayerInventory")] + InvalidEquipmentSlot, + #[error("Net error: [{0}].")] NetError(#[from] NetError), @@ -115,38 +117,54 @@ pub enum InventoryError { #[derive(Debug, Clone)] pub struct Inventory { - pub id: VarInt, + pub id: i32, pub inventory_type: InventoryType, pub title: TextComponent, pub(crate) contents: InventoryContents, + pub carried_item: Slot, } impl Inventory { pub fn new>(id: i32, title: S, inventory_type: InventoryType) -> Self { Self { - id: VarInt::new(id), + id, inventory_type, title: TextComponentBuilder::new(title).build(), contents: InventoryContents::empty(inventory_type.get_size() as usize), + carried_item: Slot::empty(), } } - pub fn set_slot(&mut self, slot_id: i32, slot: Slot) -> &mut Self { - let size = self.inventory_type.get_size(); - if (0..=size).contains(&slot_id) { - self.contents.set_slot(slot_id, slot); + pub fn set_carried_item(&mut self, carried_item: u16) { + if !(0..=9).contains(&carried_item) { + return; } - self + let slot = match self.get_slot(36 + i32::from(carried_item)) { + Some(slot) => slot, + None => Slot::empty(), + }; + + self.carried_item = slot; } - pub fn get_slot(&self, slot_id: i32) -> Option { - let size = self.inventory_type.get_size(); - if (0..=size).contains(&slot_id) { - self.contents.get_slot(slot_id) - } else { - None - } + pub(crate) async fn send_inventory_content( + &self, + mut writer: ComponentRefMut<'_, StreamWriter>, + ) -> Result<(), InventoryError> { + let contents = self.contents.construct_packet_contents(); + writer + .send_packet( + &SetContainerContentPacket::new( + self.id as u8, + contents, + self.carried_item.to_network_slot(), + ), + &NetEncodeOpts::WithLength, + ) + .await?; + + Ok(()) } pub async fn sync_inventory(&mut self, state: Arc) -> Result<(), InventoryError> { @@ -159,22 +177,12 @@ impl Inventory { let inventory_result = universe.get_mut::(entity_id); match inventory_result { Ok(inventory) => { - if *self.id != *inventory.id { + if self.id != inventory.id { continue; } - let mut writer = universe.get_mut::(entity_id)?; - let contents = inventory.contents.construct_packet_contents(); - writer - .send_packet( - &SetContainerContentPacket::new( - *inventory.id as u8, - contents, - NetworkSlot::empty(), - ), - &NetEncodeOpts::WithLength, - ) - .await?; + let writer = universe.get_mut::(entity_id)?; + self.send_inventory_content(writer).await?; } Err(err) => return Err(InventoryError::ECSError(err)), } @@ -202,20 +210,10 @@ impl Inventory { .send_packet(&packet, &NetEncodeOpts::WithLength) .await?; - let id = self.id; - writer - .send_packet( - &SetContainerContentPacket::new( - *id as u8, - self.contents.construct_packet_contents(), - NetworkSlot::empty(), - ), - &NetEncodeOpts::WithLength, - ) - .await?; + self.send_inventory_content(writer).await?; // handle event - let event = OpenInventoryEvent::new(entity_id).inventory_id(*id); + let event = OpenInventoryEvent::new(entity_id).inventory_id(self.id); OpenInventoryEvent::trigger(event, state.clone()).await?; universe.add_component::(entity_id, self)?; @@ -233,17 +231,35 @@ impl Inventory { writer .send_packet( - &CloseContainerPacket::new(*self.id as u8), + &CloseContainerPacket::new(self.id as u8), &NetEncodeOpts::WithLength, ) .await?; // handle event - let event = InventoryCloseEvent::new(entity_id, *inventory.id as u8); + let event = InventoryCloseEvent::new(entity_id, inventory.id as u8); InventoryCloseEvent::trigger(event, state.clone()).await?; Ok(()) } + pub fn set_slot(&mut self, slot_id: i32, slot: Slot) -> &mut Self { + let size = self.inventory_type.get_size(); + if (0..=size).contains(&slot_id) { + self.contents.set_slot(slot_id, slot); + } + + self + } + + pub fn get_slot(&self, slot_id: i32) -> Option { + let size = self.inventory_type.get_size(); + if (0..=size).contains(&slot_id) { + self.contents.get_slot(slot_id) + } else { + None + } + } + pub fn get_contents(&self) -> &BTreeMap { &self.contents.contents } @@ -256,7 +272,7 @@ impl Inventory { self.get_contents_mut().clear(); } - pub fn set_all(&mut self, slot: Slot) { + pub fn fill(&mut self, slot: Slot) { for i in 0..self.get_size() { self.set_slot(i, slot); } @@ -266,8 +282,15 @@ impl Inventory { self.get_contents().iter().any(|slot| slot.1.item == item) } - pub fn contains_slot(&self, slot: Slot) -> bool { - self.contains(slot.item) + pub fn contains_atleast(&self, item: i32, amount: usize) -> bool { + let mut container_amount = 0; + self.get_contents().iter().for_each(|(_, slot)| { + if slot.item == item { + container_amount += slot.count; + } + }); + + container_amount >= amount as i32 } pub fn get_first_empty(&self) -> i32 { diff --git a/src/lib/inventory/src/lib.rs b/src/lib/inventory/src/lib.rs index 634d6ce5..87e3278b 100644 --- a/src/lib/inventory/src/lib.rs +++ b/src/lib/inventory/src/lib.rs @@ -1,6 +1,7 @@ pub mod contents; pub mod events; pub mod inventory; +pub mod player_inventory; pub mod slot; pub mod types; diff --git a/src/lib/inventory/src/player_inventory.rs b/src/lib/inventory/src/player_inventory.rs new file mode 100644 index 00000000..3445d418 --- /dev/null +++ b/src/lib/inventory/src/player_inventory.rs @@ -0,0 +1,89 @@ +use std::ops::{Deref, DerefMut}; + +use ferrumc_net::packets::outgoing::set_equipment::EquipmentSlot; + +use crate::{ + inventory::{Inventory, InventoryError, InventoryType}, + slot::Slot, +}; + +#[derive(Default, Debug, Clone)] +pub struct EquipmentContent { + pub helmet: Slot, + pub chestplate: Slot, + pub leggings: Slot, + pub boots: Slot, +} + +#[derive(Debug, Clone)] +pub struct PlayerInventory { + inventory: Inventory, + pub equipment_content: EquipmentContent, + pub main_hand: Slot, + pub off_hand: Slot, +} + +impl Deref for PlayerInventory { + type Target = Inventory; + + fn deref(&self) -> &Self::Target { + &self.inventory + } +} + +impl DerefMut for PlayerInventory { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inventory + } +} + +impl Default for PlayerInventory { + fn default() -> Self { + Self::new( + EquipmentContent::default(), + Slot::default(), + Slot::default(), + ) + } +} + +impl PlayerInventory { + pub fn new(equipment_content: EquipmentContent, main_hand: Slot, off_hand: Slot) -> Self { + Self { + inventory: Inventory::new(0, "", InventoryType::Chest(5)), + equipment_content, + main_hand, + off_hand, + } + } + + pub fn set_equipment_slot( + &mut self, + equipment_slot: EquipmentSlot, + slot: Slot, + ) -> Result<(), InventoryError> { + let slot_id = match equipment_slot { + EquipmentSlot::Boots => { + self.equipment_content.boots = slot; + 8 + } + EquipmentSlot::Leggings => { + self.equipment_content.leggings = slot; + 7 + } + EquipmentSlot::Chestplate => { + self.equipment_content.chestplate = slot; + 6 + } + EquipmentSlot::Helmet => { + self.equipment_content.helmet = slot; + 5 + } + EquipmentSlot::OffHand => 45, + _ => return Err(InventoryError::InvalidEquipmentSlot), + }; + + self.inventory.set_slot(slot_id, slot); + Ok(()) + } +} diff --git a/src/lib/inventory/src/slot.rs b/src/lib/inventory/src/slot.rs index 6ebac983..f5f736ff 100644 --- a/src/lib/inventory/src/slot.rs +++ b/src/lib/inventory/src/slot.rs @@ -6,6 +6,12 @@ pub struct Slot { pub item: i32, } +impl Default for Slot { + fn default() -> Self { + Self::empty() + } +} + impl Slot { pub fn new(count: i32, item: i32) -> Self { Self { count, item } @@ -19,6 +25,13 @@ impl Slot { Self::new(0, 0) } + pub fn from_network_slot(slot: NetworkSlot) -> Self { + match slot.item_id { + Some(item) => Self::new(*slot.item_count, *item), + None => Self::empty(), + } + } + pub fn to_network_slot(&self) -> NetworkSlot { NetworkSlot::new(self.count, self.item) } diff --git a/src/lib/net/src/packets/incoming/click_container.rs b/src/lib/net/src/packets/incoming/click_container.rs index f9dadb8c..6ed0d990 100644 --- a/src/lib/net/src/packets/incoming/click_container.rs +++ b/src/lib/net/src/packets/incoming/click_container.rs @@ -7,6 +7,7 @@ use ferrumc_net_codec::net_types::length_prefixed_vec::LengthPrefixedVec; use ferrumc_net_codec::net_types::var_int::VarInt; use ferrumc_state::ServerState; use std::sync::Arc; +use tracing::info; #[derive(NetDecode, Debug)] pub struct ChangedSlots { @@ -34,6 +35,8 @@ pub struct ClickContainerPacket { impl IncomingPacket for ClickContainerPacket { async fn handle(self, conn_id: usize, state: Arc) -> NetResult<()> { + info!("Clicked Container: {:#?}", self); + let event = InventoryClickEvent::new(conn_id, self); InventoryClickEvent::trigger(event, state).await?; Ok(()) diff --git a/src/lib/net/src/packets/incoming/mod.rs b/src/lib/net/src/packets/incoming/mod.rs index c0711cd4..6510acfb 100644 --- a/src/lib/net/src/packets/incoming/mod.rs +++ b/src/lib/net/src/packets/incoming/mod.rs @@ -19,4 +19,6 @@ pub mod swing_arm; pub mod click_container; pub mod close_container; +pub mod set_creative_mode_slot; +pub mod set_held_item; pub mod use_item_on; 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 new file mode 100644 index 00000000..27e5eeba --- /dev/null +++ b/src/lib/net/src/packets/incoming/set_creative_mode_slot.rs @@ -0,0 +1,37 @@ +use std::sync::Arc; + +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, +}; + +#[derive(NetDecode, Debug)] +#[packet(packet_id = 0x32, state = "play")] +pub struct SetCreativeModeSlotPacket { + pub slot: u16, + pub clicked_item: NetworkSlot, +} + +impl IncomingPacket for SetCreativeModeSlotPacket { + async fn handle(self, conn_id: usize, state: Arc) -> NetResult<()> { + let event = SetCreativeModeSlotEvent::new(conn_id, self); + SetCreativeModeSlotEvent::trigger(event, state).await?; + Ok(()) + } +} + +#[derive(Event, Debug)] +pub struct SetCreativeModeSlotEvent { + pub conn_id: usize, + pub packet: SetCreativeModeSlotPacket, +} + +impl SetCreativeModeSlotEvent { + pub fn new(conn_id: usize, packet: SetCreativeModeSlotPacket) -> Self { + Self { conn_id, packet } + } +} diff --git a/src/lib/net/src/packets/incoming/set_held_item.rs b/src/lib/net/src/packets/incoming/set_held_item.rs new file mode 100644 index 00000000..d71aeec8 --- /dev/null +++ b/src/lib/net/src/packets/incoming/set_held_item.rs @@ -0,0 +1,34 @@ +use std::sync::Arc; + +use ferrumc_events::infrastructure::Event; +use ferrumc_macros::{packet, Event, NetDecode}; +use ferrumc_state::ServerState; + +use crate::{packets::IncomingPacket, NetResult}; + +#[derive(NetDecode, Debug)] +#[packet(packet_id = 0x2F, state = "play")] +pub struct IncomingSetHeldItemPacket { + pub slot: u16, +} + +impl IncomingPacket for IncomingSetHeldItemPacket { + async fn handle(self, conn_id: usize, state: Arc) -> NetResult<()> { + let event = ChangeSlotEvent::new(conn_id, self); + ChangeSlotEvent::trigger(event, state).await?; + + Ok(()) + } +} + +#[derive(Event, Debug)] +pub struct ChangeSlotEvent { + pub conn_id: usize, + pub packet: IncomingSetHeldItemPacket, +} + +impl ChangeSlotEvent { + pub fn new(conn_id: usize, packet: IncomingSetHeldItemPacket) -> Self { + Self { conn_id, packet } + } +} diff --git a/src/lib/net/src/packets/outgoing/mod.rs b/src/lib/net/src/packets/outgoing/mod.rs index f93826db..38b80a95 100644 --- a/src/lib/net/src/packets/outgoing/mod.rs +++ b/src/lib/net/src/packets/outgoing/mod.rs @@ -18,6 +18,7 @@ pub mod set_container_content; pub mod set_container_property; pub mod set_container_slot; pub mod set_default_spawn_position; +pub mod set_equipment; pub mod set_render_distance; pub mod status_response; pub mod synchronize_player_position; diff --git a/src/lib/net/src/packets/outgoing/open_screen.rs b/src/lib/net/src/packets/outgoing/open_screen.rs index e4b82a4d..50a20389 100644 --- a/src/lib/net/src/packets/outgoing/open_screen.rs +++ b/src/lib/net/src/packets/outgoing/open_screen.rs @@ -12,19 +12,19 @@ pub struct OpenScreenPacket { } impl OpenScreenPacket { - pub fn new(window_id: VarInt, window_type: VarInt, window_title: TextComponent) -> Self { + pub fn new(window_id: i32, window_type: VarInt, window_title: TextComponent) -> Self { Self { - window_id, + window_id: VarInt::new(window_id), window_type, window_title, } } - pub fn with_empty_title(window_id: VarInt, window_type: VarInt) -> Self { + pub fn with_empty_title(window_id: i32, window_type: VarInt) -> Self { Self::new( window_id, window_type, - TextComponentBuilder::new("Inventory").build(), + TextComponentBuilder::new("").build(), ) } } 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 a867cc2d..c55bf719 100644 --- a/src/lib/net/src/packets/outgoing/set_container_slot.rs +++ b/src/lib/net/src/packets/outgoing/set_container_slot.rs @@ -2,7 +2,7 @@ use ferrumc_macros::{packet, NetDecode, NetEncode}; use ferrumc_net_codec::net_types::var_int::VarInt; use std::io::Write; -#[derive(NetDecode, NetEncode, Debug)] +#[derive(NetDecode, NetEncode, Debug, Clone, Copy)] pub struct NetworkSlot { pub item_count: VarInt, #[net(optional_trigger = *item_count > 0)] diff --git a/src/lib/net/src/packets/outgoing/set_equipment.rs b/src/lib/net/src/packets/outgoing/set_equipment.rs new file mode 100644 index 00000000..84b655a6 --- /dev/null +++ b/src/lib/net/src/packets/outgoing/set_equipment.rs @@ -0,0 +1,60 @@ +use ferrumc_macros::{packet, NetEncode}; +use ferrumc_net_codec::{ + encode::{NetEncode, NetEncodeOpts, NetEncodeResult}, + net_types::var_int::VarInt, +}; +use std::io::Write; + +use super::set_container_slot::NetworkSlot; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum EquipmentSlot { + MainHand, + OffHand, + Boots, + Leggings, + Chestplate, + Helmet, + Body, +} + +impl NetEncode for EquipmentSlot { + fn encode(&self, writer: &mut W, opts: &NetEncodeOpts) -> NetEncodeResult<()> { + self.get_index().encode(writer, opts) + } + + async fn encode_async( + &self, + writer: &mut W, + opts: &NetEncodeOpts, + ) -> NetEncodeResult<()> { + self.get_index().encode_async(writer, opts).await + } +} + +impl EquipmentSlot { + pub fn get_index(&self) -> u8 { + match self { + Self::MainHand => 0, + Self::OffHand => 1, + Self::Boots => 2, + Self::Leggings => 3, + Self::Chestplate => 4, + Self::Helmet => 5, + Self::Body => 6, + } + } +} + +#[derive(NetEncode)] +pub struct Equipment { + pub equipment: EquipmentSlot, + pub slot: NetworkSlot, +} + +#[derive(NetEncode)] +#[packet(packet_id = 0x5B)] +pub struct SetEquipmentPacket { + pub conn_id: VarInt, + pub equipment: Vec, +} From e39b090246d72081d50102d35b2a5a4bb34109a6 Mon Sep 17 00:00:00 2001 From: Outspending Date: Sat, 4 Jan 2025 08:51:49 -0700 Subject: [PATCH 25/38] Inventory Clicking + Updating --- src/bin/src/packet_handlers/containers.rs | 40 +++++++ src/bin/src/packet_handlers/login_process.rs | 89 +++++++------- src/lib/inventory/src/inventory.rs | 31 ++++- src/lib/net/src/errors.rs | 3 + .../src/packets/incoming/click_container.rs | 111 +++++++++++++++++- 5 files changed, 228 insertions(+), 46 deletions(-) diff --git a/src/bin/src/packet_handlers/containers.rs b/src/bin/src/packet_handlers/containers.rs index b103f138..9edc311c 100644 --- a/src/bin/src/packet_handlers/containers.rs +++ b/src/bin/src/packet_handlers/containers.rs @@ -2,7 +2,9 @@ use ferrumc_inventory::inventory::Inventory; use ferrumc_inventory::player_inventory::PlayerInventory; use ferrumc_inventory::slot::Slot; use ferrumc_macros::event_handler; +use ferrumc_net::connection::StreamWriter; use ferrumc_net::errors::NetError; +use ferrumc_net::packets::incoming::click_container::InventoryClickEvent; use ferrumc_net::packets::incoming::close_container::InventoryCloseEvent; use ferrumc_net::packets::incoming::set_creative_mode_slot::SetCreativeModeSlotEvent; use ferrumc_net::packets::incoming::set_held_item::ChangeSlotEvent; @@ -23,6 +25,44 @@ async fn container_close( Ok(container_close_event) } +#[event_handler] +async fn handle_container_click( + inventory_click_event: InventoryClickEvent, + state: GlobalState, +) -> Result { + let conn_id = inventory_click_event.conn_id; + let packet = &inventory_click_event.packet; + let writer = state.universe.get_mut::(conn_id)?; + let mut inventory = state.universe.get_mut::(conn_id)?; + + match packet.changed_slots.data.as_slice() { + [changed_slot] => { + let slot_num = changed_slot.slot_number as i16; + + inventory.set_slot(slot_num as i32, Slot::from_network_slot(changed_slot.slot)); + inventory + .send_inventory_slot_content(slot_num, writer) + .await + .map_err(|err| NetError::Other(err.to_string()))?; + } + changed_slots => { + changed_slots.iter().for_each(|changed_slot| { + inventory.set_slot( + changed_slot.slot_number as i32, + Slot::from_network_slot(changed_slot.slot), + ); + }); + + inventory + .send_inventory_content(writer) + .await + .map_err(|err| NetError::Other(err.to_string()))?; + } + } + + Ok(inventory_click_event) +} + #[event_handler] async fn set_creative_mode_slot( creative_mode_slot: SetCreativeModeSlotEvent, diff --git a/src/bin/src/packet_handlers/login_process.rs b/src/bin/src/packet_handlers/login_process.rs index 7597dea2..48d7c075 100644 --- a/src/bin/src/packet_handlers/login_process.rs +++ b/src/bin/src/packet_handlers/login_process.rs @@ -5,7 +5,9 @@ use ferrumc_core::transform::grounded::OnGround; use ferrumc_core::transform::position::Position; use ferrumc_core::transform::rotation::Rotation; use ferrumc_ecs::components::storage::ComponentRefMut; +use ferrumc_inventory::inventory::{Inventory, InventoryType}; use ferrumc_inventory::player_inventory::PlayerInventory; +use ferrumc_inventory::slot::Slot; use ferrumc_macros::event_handler; use ferrumc_net::connection::{ConnectionState, StreamWriter}; use ferrumc_net::errors::NetError; @@ -162,48 +164,55 @@ async fn handle_ack_finish_configuration( .add_component::(conn_id, OnGround::default())? .add_component::(conn_id, PlayerInventory::default())?; - let mut writer = state.universe.get_mut::(conn_id)?; - - writer // 21 - .send_packet(&LoginPlayPacket::new(conn_id), &NetEncodeOpts::WithLength) - .await?; - writer // 29 - .send_packet( - &SynchronizePlayerPositionPacket::default(), // The coordinates here should be used for the center chunk. - &NetEncodeOpts::WithLength, - ) - .await?; - writer // 37 - .send_packet( - &SetDefaultSpawnPositionPacket::default(), // Player specific, aka. home, bed, where it would respawn. - &NetEncodeOpts::WithLength, - ) - .await?; - writer // 38 - .send_packet( - &GameEventPacket::start_waiting_for_level_chunks(), - &NetEncodeOpts::WithLength, - ) - .await?; - writer // 41 - .send_packet( - &SetCenterChunk::new(0, 0), // TODO - Dependent on the player spawn position. - &NetEncodeOpts::WithLength, - ) - .await?; - writer // other - .send_packet( - &SetRenderDistance::new(5), // TODO - &NetEncodeOpts::WithLength, - ) - .await?; + { + let mut writer = state.universe.get_mut::(conn_id)?; + + writer // 21 + .send_packet(&LoginPlayPacket::new(conn_id), &NetEncodeOpts::WithLength) + .await?; + writer // 29 + .send_packet( + &SynchronizePlayerPositionPacket::default(), // The coordinates here should be used for the center chunk. + &NetEncodeOpts::WithLength, + ) + .await?; + writer // 37 + .send_packet( + &SetDefaultSpawnPositionPacket::default(), // Player specific, aka. home, bed, where it would respawn. + &NetEncodeOpts::WithLength, + ) + .await?; + writer // 38 + .send_packet( + &GameEventPacket::start_waiting_for_level_chunks(), + &NetEncodeOpts::WithLength, + ) + .await?; + writer // 41 + .send_packet( + &SetCenterChunk::new(0, 0), // TODO - Dependent on the player spawn position. + &NetEncodeOpts::WithLength, + ) + .await?; + writer // other + .send_packet( + &SetRenderDistance::new(5), // TODO + &NetEncodeOpts::WithLength, + ) + .await?; + + let pos = state.universe.get_mut::(conn_id)?; + let mut chunk_recv = state.universe.get_mut::(conn_id)?; + chunk_recv.last_chunk = Some((pos.x as i32, pos.z as i32, String::from("overworld"))); + chunk_recv.calculate_chunks().await; + + send_keep_alive(conn_id, state.clone(), &mut writer).await?; + } - let pos = state.universe.get_mut::(conn_id)?; - let mut chunk_recv = state.universe.get_mut::(conn_id)?; - chunk_recv.last_chunk = Some((pos.x as i32, pos.z as i32, String::from("overworld"))); - chunk_recv.calculate_chunks().await; + let mut inventory = Inventory::new(1, "Something Stupid", InventoryType::Chest(6)); + inventory.set_slot(3, Slot::with_item(3)); - send_keep_alive(conn_id, state.clone(), &mut writer).await?; + inventory.add_viewer(state, conn_id).await.unwrap(); Ok(ack_finish_configuration_event) } diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs index 4af096e9..40583102 100644 --- a/src/lib/inventory/src/inventory.rs +++ b/src/lib/inventory/src/inventory.rs @@ -13,6 +13,7 @@ use ferrumc_net::packets::incoming::close_container::InventoryCloseEvent; use ferrumc_net::packets::outgoing::close_container::CloseContainerPacket; use ferrumc_net::packets::outgoing::open_screen::OpenScreenPacket; use ferrumc_net::packets::outgoing::set_container_content::SetContainerContentPacket; +use ferrumc_net::packets::outgoing::set_container_slot::SetContainerSlotPacket; use ferrumc_net_codec::encode::NetEncodeOpts; use ferrumc_net_codec::net_types::var_int::VarInt; use ferrumc_state::ServerState; @@ -105,6 +106,9 @@ pub enum InventoryError { #[error("Invalid equipment slot for PlayerInventory")] InvalidEquipmentSlot, + #[error("Invalid slot id in Inventory")] + InvalidSlot, + #[error("Net error: [{0}].")] NetError(#[from] NetError), @@ -148,7 +152,32 @@ impl Inventory { self.carried_item = slot; } - pub(crate) async fn send_inventory_content( + pub async fn send_inventory_slot_content( + &self, + slot_num: i16, + mut writer: ComponentRefMut<'_, StreamWriter>, + ) -> Result<(), InventoryError> { + let slot = if let Some(slot) = self.get_slot(i32::from(slot_num)) { + slot + } else { + return Err(InventoryError::InvalidSlot); + }; + + writer + .send_packet( + &SetContainerSlotPacket::new( + VarInt::new(self.id), + slot_num, + slot.to_network_slot(), + ), + &NetEncodeOpts::WithLength, + ) + .await?; + + Ok(()) + } + + pub async fn send_inventory_content( &self, mut writer: ComponentRefMut<'_, StreamWriter>, ) -> Result<(), InventoryError> { diff --git a/src/lib/net/src/errors.rs b/src/lib/net/src/errors.rs index d24d3684..750115d7 100644 --- a/src/lib/net/src/errors.rs +++ b/src/lib/net/src/errors.rs @@ -43,6 +43,9 @@ pub enum NetError { #[error("{0}")] Chunk(#[from] ChunkError), + + #[error("NetError: {0}")] + Other(String), } #[derive(Debug, Error)] diff --git a/src/lib/net/src/packets/incoming/click_container.rs b/src/lib/net/src/packets/incoming/click_container.rs index 6ed0d990..2934ab44 100644 --- a/src/lib/net/src/packets/incoming/click_container.rs +++ b/src/lib/net/src/packets/incoming/click_container.rs @@ -3,12 +3,91 @@ use crate::packets::IncomingPacket; use crate::NetResult; use ferrumc_events::infrastructure::Event; use ferrumc_macros::{packet, Event, NetDecode}; +use ferrumc_net_codec::decode::{NetDecode, NetDecodeOpts, NetDecodeResult}; use ferrumc_net_codec::net_types::length_prefixed_vec::LengthPrefixedVec; use ferrumc_net_codec::net_types::var_int::VarInt; use ferrumc_state::ServerState; +use std::io::Read; use std::sync::Arc; use tracing::info; +#[derive(Debug, Clone, Copy)] +pub enum InventoryClickActions { + // Mode 0 actions + LeftMouseClick, + RightMouseClick, + LeftClickOutsideInventory, + RightClickOutsideInventory, + + // Mode 1 actions + ShiftLeftMouseClick, + ShiftRightMouseClick, + + // Mode 2 actions + NumberKey(u8), // keys 1 through 9. + + // Mode 3 actions + OffhandSwap, + + // Mode 4 actions + MiddleClick, + DropKey, + ControlDropKey, + + // Mode 5 actions + StartMouseDrag { button: u8 }, // Starting drag with a specific button + AddSlotToMouseDrag { button: u8 }, // Adding slot with a specific button + EndMouseDrag { button: u8 }, // Ending drag with a specific button + + // Mode 6 actions + DoubleClick, + ReversePickup, +} + +impl InventoryClickActions { + pub fn get_action(mode: i32, button: u8, slot: i16) -> Option { + match mode { + 0 => match (button, slot) { + (0, -999) => Some(InventoryClickActions::LeftClickOutsideInventory), + (_, -999) => Some(InventoryClickActions::RightClickOutsideInventory), + (0, _) => Some(InventoryClickActions::LeftMouseClick), + _ => Some(InventoryClickActions::RightMouseClick), + }, + 1 => match button { + 0 => Some(InventoryClickActions::ShiftLeftMouseClick), + _ => Some(InventoryClickActions::ShiftRightMouseClick), + }, + 2 => match button { + 1..=9 => Some(InventoryClickActions::NumberKey(button)), + _ => None, + }, + 3 => match button { + 40 => Some(InventoryClickActions::OffhandSwap), + _ => None, + }, + 4 => match button { + 2 => Some(InventoryClickActions::MiddleClick), + 0 => Some(InventoryClickActions::DropKey), + 1 => Some(InventoryClickActions::ControlDropKey), + _ => None, + }, + 5 => match (slot, button) { + (-999, 0) => Some(InventoryClickActions::StartMouseDrag { button }), + (_, 0) => Some(InventoryClickActions::AddSlotToMouseDrag { button }), + (_, 1) => Some(InventoryClickActions::AddSlotToMouseDrag { button }), + (-999, _) => Some(InventoryClickActions::EndMouseDrag { button }), + _ => None, + }, + 6 => match button { + 0 => Some(InventoryClickActions::DoubleClick), + 1 => Some(InventoryClickActions::ReversePickup), + _ => None, + }, + _ => None, + } + } +} + #[derive(NetDecode, Debug)] pub struct ChangedSlots { pub slot_number: u16, @@ -21,18 +100,40 @@ impl ChangedSlots { } } -#[derive(NetDecode, Debug)] +#[derive(Debug)] #[packet(packet_id = 0x0E, state = "play")] pub struct ClickContainerPacket { pub window_id: u8, pub state_id: VarInt, - pub slot: u16, - pub button: u8, + pub slot: i16, + pub button: Option, pub mode: VarInt, pub changed_slots: LengthPrefixedVec, pub carried_item: NetworkSlot, } +impl NetDecode for ClickContainerPacket { + fn decode(reader: &mut R, opts: &NetDecodeOpts) -> NetDecodeResult { + let window_id = u8::decode(reader, opts)?; + let state_id = VarInt::decode(reader, opts)?; + let slot = i16::decode(reader, opts)?; + let button = u8::decode(reader, opts)?; + let mode = VarInt::decode(reader, opts)?; + let changed_slots = LengthPrefixedVec::::decode(reader, opts)?; + let carried_item = NetworkSlot::decode(reader, opts)?; + + Ok(Self::new( + window_id, + state_id, + slot, + InventoryClickActions::get_action(*mode, button, slot), + mode, + changed_slots, + carried_item, + )) + } +} + impl IncomingPacket for ClickContainerPacket { async fn handle(self, conn_id: usize, state: Arc) -> NetResult<()> { info!("Clicked Container: {:#?}", self); @@ -47,8 +148,8 @@ impl ClickContainerPacket { pub fn new( window_id: u8, state_id: VarInt, - slot: u16, - button: u8, + slot: i16, + button: Option, mode: VarInt, changed_slots: LengthPrefixedVec, carried_item: NetworkSlot, From 7628ada3952bd01a0a6a798322fb744401ba22b8 Mon Sep 17 00:00:00 2001 From: Outspending Date: Sat, 4 Jan 2025 12:18:03 -0700 Subject: [PATCH 26/38] InventoryBuilder + type fixes --- src/bin/src/packet_handlers/containers.rs | 59 ++++---- src/bin/src/packet_handlers/login_process.rs | 12 +- src/lib/inventory/src/builder.rs | 66 +++++++++ src/lib/inventory/src/contents.rs | 24 ++-- src/lib/inventory/src/errors.rs | 27 ++++ .../inventory/src/events/inventory_open.rs | 21 --- src/lib/inventory/src/events/mod.rs | 1 - src/lib/inventory/src/inventory.rs | 136 +++++++++--------- src/lib/inventory/src/lib.rs | 7 +- src/lib/inventory/src/tests.rs | 8 -- src/lib/inventory/src/types/mod.rs | 2 +- .../src/{ => types}/player_inventory.rs | 8 +- .../src/packets/incoming/click_container.rs | 16 +-- .../incoming/set_creative_mode_slot.rs | 15 +- .../net/src/packets/incoming/set_held_item.rs | 8 +- .../net/src/packets/outgoing/open_screen.rs | 25 +++- 16 files changed, 265 insertions(+), 170 deletions(-) create mode 100644 src/lib/inventory/src/builder.rs create mode 100644 src/lib/inventory/src/errors.rs delete mode 100644 src/lib/inventory/src/events/inventory_open.rs delete mode 100644 src/lib/inventory/src/events/mod.rs delete mode 100644 src/lib/inventory/src/tests.rs rename src/lib/inventory/src/{ => types}/player_inventory.rs (89%) diff --git a/src/bin/src/packet_handlers/containers.rs b/src/bin/src/packet_handlers/containers.rs index 9edc311c..eb063d72 100644 --- a/src/bin/src/packet_handlers/containers.rs +++ b/src/bin/src/packet_handlers/containers.rs @@ -1,8 +1,7 @@ -use ferrumc_inventory::inventory::Inventory; -use ferrumc_inventory::player_inventory::PlayerInventory; +use ferrumc_inventory::inventory::{Inventory, InventorySyncType}; use ferrumc_inventory::slot::Slot; +use ferrumc_inventory::types::player_inventory::PlayerInventory; use ferrumc_macros::event_handler; -use ferrumc_net::connection::StreamWriter; use ferrumc_net::errors::NetError; use ferrumc_net::packets::incoming::click_container::InventoryClickEvent; use ferrumc_net::packets::incoming::close_container::InventoryCloseEvent; @@ -30,33 +29,38 @@ async fn handle_container_click( inventory_click_event: InventoryClickEvent, state: GlobalState, ) -> Result { + if inventory_click_event.is_canceled { + return Err(NetError::Other(String::default())); + } + let conn_id = inventory_click_event.conn_id; let packet = &inventory_click_event.packet; - let writer = state.universe.get_mut::(conn_id)?; let mut inventory = state.universe.get_mut::(conn_id)?; - match packet.changed_slots.data.as_slice() { - [changed_slot] => { - let slot_num = changed_slot.slot_number as i16; + if inventory.is_synced { + match packet.changed_slots.data.as_slice() { + [changed_slot] => { + let slot_num = changed_slot.slot_number as i16; - inventory.set_slot(slot_num as i32, Slot::from_network_slot(changed_slot.slot)); - inventory - .send_inventory_slot_content(slot_num, writer) - .await - .map_err(|err| NetError::Other(err.to_string()))?; - } - changed_slots => { - changed_slots.iter().for_each(|changed_slot| { - inventory.set_slot( - changed_slot.slot_number as i32, - Slot::from_network_slot(changed_slot.slot), - ); - }); + inventory + .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()))?; + } + changed_slots => { + changed_slots.iter().for_each(|changed_slot| { + inventory.set_slot( + changed_slot.slot_number, + Slot::from_network_slot(changed_slot.slot), + ); + }); - inventory - .send_inventory_content(writer) - .await - .map_err(|err| NetError::Other(err.to_string()))?; + inventory + .sync_inventory(conn_id, &InventorySyncType::All, state) + .await + .map_err(|err| NetError::Other(err.to_string()))?; + } } } @@ -69,12 +73,11 @@ async fn set_creative_mode_slot( state: GlobalState, ) -> Result { let conn_id = creative_mode_slot.conn_id; - let packet = &creative_mode_slot.packet; let mut inventory = state.universe.get_mut::(conn_id)?; inventory.set_slot( - packet.slot as i32, - Slot::from_network_slot(packet.clicked_item), + creative_mode_slot.slot, + Slot::from_network_slot(creative_mode_slot.clicked_item), ); Ok(creative_mode_slot) @@ -88,7 +91,7 @@ async fn handle_carried_item( let conn_id = change_slot_event.conn_id; let mut inventory = state.universe.get_mut::(conn_id)?; - inventory.set_carried_item(change_slot_event.packet.slot); + inventory.set_carried_item(change_slot_event.slot); Ok(change_slot_event) } diff --git a/src/bin/src/packet_handlers/login_process.rs b/src/bin/src/packet_handlers/login_process.rs index 48d7c075..7c494368 100644 --- a/src/bin/src/packet_handlers/login_process.rs +++ b/src/bin/src/packet_handlers/login_process.rs @@ -5,9 +5,10 @@ use ferrumc_core::transform::grounded::OnGround; use ferrumc_core::transform::position::Position; use ferrumc_core::transform::rotation::Rotation; use ferrumc_ecs::components::storage::ComponentRefMut; -use ferrumc_inventory::inventory::{Inventory, InventoryType}; -use ferrumc_inventory::player_inventory::PlayerInventory; +use ferrumc_inventory::builder::InventoryBuilder; +use ferrumc_inventory::inventory::InventoryType; use ferrumc_inventory::slot::Slot; +use ferrumc_inventory::types::player_inventory::PlayerInventory; use ferrumc_macros::event_handler; use ferrumc_net::connection::{ConnectionState, StreamWriter}; use ferrumc_net::errors::NetError; @@ -209,9 +210,12 @@ async fn handle_ack_finish_configuration( send_keep_alive(conn_id, state.clone(), &mut writer).await?; } - let mut inventory = Inventory::new(1, "Something Stupid", InventoryType::Chest(6)); - inventory.set_slot(3, Slot::with_item(3)); + let mut inventory = InventoryBuilder::new(1) + .inventory_type(InventoryType::Chest(6)) + .is_synced(true) + .build(); + inventory.set_slot(3, Slot::with_item(3)); inventory.add_viewer(state, conn_id).await.unwrap(); Ok(ack_finish_configuration_event) diff --git a/src/lib/inventory/src/builder.rs b/src/lib/inventory/src/builder.rs new file mode 100644 index 00000000..a264214e --- /dev/null +++ b/src/lib/inventory/src/builder.rs @@ -0,0 +1,66 @@ +use ferrumc_text::{TextComponent, TextComponentBuilder}; + +use crate::{ + contents::InventoryContents, + inventory::{Inventory, InventoryType}, + slot::Slot, +}; + +pub struct InventoryBuilder { + pub id: u8, + pub inventory_type: InventoryType, + pub title: TextComponent, + pub(crate) contents: InventoryContents, + pub carried_item: Slot, + pub is_synced: bool, +} + +impl InventoryBuilder { + pub fn new(id: u8) -> Self { + let inventory_type = InventoryType::Chest(3); + Self { + id, + inventory_type, + title: TextComponentBuilder::new("").build(), + contents: InventoryContents::empty(inventory_type), + carried_item: Slot::empty(), + is_synced: false, + } + } + + pub fn inventory_type(&mut self, inventory_type: InventoryType) -> &mut Self { + self.inventory_type = inventory_type; + self + } + + pub fn title(&mut self, title: TextComponent) -> &mut Self { + self.title = title; + self + } + + pub fn contents(&mut self, contents: InventoryContents) -> &mut Self { + self.contents = contents; + self + } + + pub fn carried_item(&mut self, carried_item: Slot) -> &mut Self { + self.carried_item = carried_item; + self + } + + pub fn is_synced(&mut self, is_synced: bool) -> &mut Self { + self.is_synced = is_synced; + self + } + + pub fn build(&mut self) -> Inventory { + Inventory { + id: self.id, + inventory_type: self.inventory_type, + title: self.title.clone(), + contents: self.contents.clone(), + carried_item: self.carried_item, + is_synced: self.is_synced, + } + } +} diff --git a/src/lib/inventory/src/contents.rs b/src/lib/inventory/src/contents.rs index 31443bf2..a489d013 100644 --- a/src/lib/inventory/src/contents.rs +++ b/src/lib/inventory/src/contents.rs @@ -1,37 +1,37 @@ -use crate::slot::Slot; +use crate::{inventory::InventoryType, slot::Slot}; use ferrumc_net::packets::outgoing::set_container_slot::NetworkSlot; use ferrumc_net_codec::net_types::length_prefixed_vec::LengthPrefixedVec; use std::collections::BTreeMap; #[derive(Debug, Clone)] pub struct InventoryContents { - pub contents: BTreeMap, - pub size: usize, + pub contents: BTreeMap, + pub size: i16, } impl InventoryContents { - pub fn empty(size: usize) -> Self { - let mut empty = Self { - contents: BTreeMap::new(), - size, - }; - + pub fn empty(inventory_type: InventoryType) -> Self { + let mut empty = Self::new(inventory_type.get_size(), BTreeMap::new()); empty.fill(Slot::empty()); empty } + pub fn new(size: i16, contents: BTreeMap) -> Self { + Self { contents, size } + } + pub fn fill(&mut self, slot: Slot) { - for i in 0..self.size as i32 { + for i in 0..self.size { self.contents.insert(i, slot); } } - pub fn set_slot(&mut self, slot_id: i32, slot: Slot) -> &mut Self { + pub fn set_slot(&mut self, slot_id: i16, slot: Slot) -> &mut Self { self.contents.insert(slot_id, slot); self } - pub fn get_slot(&self, item: i32) -> Option { + pub fn get_slot(&self, item: i16) -> Option { self.contents.get(&item).copied() } diff --git a/src/lib/inventory/src/errors.rs b/src/lib/inventory/src/errors.rs new file mode 100644 index 00000000..f39e2654 --- /dev/null +++ b/src/lib/inventory/src/errors.rs @@ -0,0 +1,27 @@ +use ferrumc_ecs::{entities::Entity, errors::ECSError}; +use ferrumc_net::errors::NetError; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum InventoryError { + #[error("Entity [{0}] already has an open inventory. Cannot open another one.")] + AlreadyOpenedInventory(Entity), + + #[error("Invalid equipment slot for PlayerInventory")] + InvalidEquipmentSlot, + + #[error("Invalid slot id in Inventory")] + InvalidSlot, + + #[error("Trying to sync an inventory that isn't syncable! [ID: {0}]")] + SyncingANonSyncedInventory(u8), + + #[error("Net error: [{0}].")] + NetError(#[from] NetError), + + #[error("ECS error: [{0}].")] + ECSError(#[from] ECSError), + + #[error("Unknown error occurred with inventories...")] + Unknown, +} diff --git a/src/lib/inventory/src/events/inventory_open.rs b/src/lib/inventory/src/events/inventory_open.rs deleted file mode 100644 index 46a4daed..00000000 --- a/src/lib/inventory/src/events/inventory_open.rs +++ /dev/null @@ -1,21 +0,0 @@ -use ferrumc_macros::Event; - -#[derive(Event, Debug)] -pub struct OpenInventoryEvent { - pub conn_id: usize, - pub inventory_id: Option, -} - -impl OpenInventoryEvent { - pub fn new(conn_id: usize) -> Self { - Self { - conn_id, - inventory_id: None, - } - } - - pub fn inventory_id(mut self, inventory_id: i32) -> Self { - self.inventory_id = Some(inventory_id); - self - } -} diff --git a/src/lib/inventory/src/events/mod.rs b/src/lib/inventory/src/events/mod.rs deleted file mode 100644 index 7302598d..00000000 --- a/src/lib/inventory/src/events/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod inventory_open; diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs index 40583102..15ffabde 100644 --- a/src/lib/inventory/src/inventory.rs +++ b/src/lib/inventory/src/inventory.rs @@ -1,25 +1,22 @@ use crate::contents::InventoryContents; -use crate::events::inventory_open::OpenInventoryEvent; +use crate::errors::InventoryError; use crate::slot::Slot; use std::collections::BTreeMap; use ferrumc_core::chunks::chunk_receiver::ChunkReceiver; -use ferrumc_ecs::errors::ECSError; use ferrumc_ecs::{components::storage::ComponentRefMut, entities::Entity}; use ferrumc_events::infrastructure::Event; use ferrumc_net::connection::StreamWriter; -use ferrumc_net::errors::NetError; use ferrumc_net::packets::incoming::close_container::InventoryCloseEvent; use ferrumc_net::packets::outgoing::close_container::CloseContainerPacket; -use ferrumc_net::packets::outgoing::open_screen::OpenScreenPacket; +use ferrumc_net::packets::outgoing::open_screen::{OpenInventoryEvent, OpenScreenPacket}; use ferrumc_net::packets::outgoing::set_container_content::SetContainerContentPacket; use ferrumc_net::packets::outgoing::set_container_slot::SetContainerSlotPacket; use ferrumc_net_codec::encode::NetEncodeOpts; use ferrumc_net_codec::net_types::var_int::VarInt; use ferrumc_state::ServerState; -use ferrumc_text::{TextComponent, TextComponentBuilder}; +use ferrumc_text::TextComponent; use std::sync::Arc; -use thiserror::Error; #[derive(Debug, Clone, Copy)] pub enum InventoryType { @@ -45,8 +42,8 @@ pub enum InventoryType { } impl InventoryType { - pub fn get_id(&self) -> VarInt { - let id = match self { + pub fn get_id(&self) -> i32 { + match self { InventoryType::Chest(i) => { let value = i32::from(*i); if (1..=6).contains(&value) { @@ -72,14 +69,12 @@ impl InventoryType { InventoryType::Smoker => 22, InventoryType::Cartography => 23, InventoryType::Stonecutter => 24, - }; - - VarInt::new(id) + } } - pub fn get_size(&self) -> i32 { + pub fn get_size(&self) -> i16 { match self { - InventoryType::Chest(i) => i32::from(*i) * 9, + InventoryType::Chest(i) => i16::from(*i) * 9, InventoryType::Anvil | InventoryType::BlastFurnace | InventoryType::Furnace @@ -98,53 +93,29 @@ impl InventoryType { } } -#[derive(Error, Debug)] -pub enum InventoryError { - #[error("Entity [{0}] already has an open inventory. Cannot open another one.")] - AlreadyOpenedInventory(Entity), - - #[error("Invalid equipment slot for PlayerInventory")] - InvalidEquipmentSlot, - - #[error("Invalid slot id in Inventory")] - InvalidSlot, - - #[error("Net error: [{0}].")] - NetError(#[from] NetError), - - #[error("ECS error: [{0}].")] - ECSError(#[from] ECSError), - - #[error("Unknown error occurred with inventories...")] - Unknown, +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] +pub enum InventorySyncType { + All, + Single(i16), } #[derive(Debug, Clone)] pub struct Inventory { - pub id: i32, + pub id: u8, pub inventory_type: InventoryType, pub title: TextComponent, pub(crate) contents: InventoryContents, pub carried_item: Slot, + pub is_synced: bool, } impl Inventory { - pub fn new>(id: i32, title: S, inventory_type: InventoryType) -> Self { - Self { - id, - inventory_type, - title: TextComponentBuilder::new(title).build(), - contents: InventoryContents::empty(inventory_type.get_size() as usize), - carried_item: Slot::empty(), - } - } - pub fn set_carried_item(&mut self, carried_item: u16) { if !(0..=9).contains(&carried_item) { return; } - let slot = match self.get_slot(36 + i32::from(carried_item)) { + let slot = match self.get_slot(36 + (carried_item as i16)) { Some(slot) => slot, None => Slot::empty(), }; @@ -152,41 +123,39 @@ impl Inventory { self.carried_item = slot; } - pub async fn send_inventory_slot_content( + pub(crate) async fn send_inventory_slot_content( &self, slot_num: i16, mut writer: ComponentRefMut<'_, StreamWriter>, ) -> Result<(), InventoryError> { - let slot = if let Some(slot) = self.get_slot(i32::from(slot_num)) { - slot - } else { + let Some(slot) = self.get_slot(slot_num) else { return Err(InventoryError::InvalidSlot); }; writer .send_packet( &SetContainerSlotPacket::new( - VarInt::new(self.id), + VarInt::new(i32::from(self.id)), slot_num, slot.to_network_slot(), ), &NetEncodeOpts::WithLength, ) - .await?; + .await + .unwrap(); Ok(()) } - pub async fn send_inventory_content( + pub(crate) async fn send_inventory_content( &self, mut writer: ComponentRefMut<'_, StreamWriter>, ) -> Result<(), InventoryError> { - let contents = self.contents.construct_packet_contents(); writer .send_packet( &SetContainerContentPacket::new( - self.id as u8, - contents, + self.id, + self.contents.construct_packet_contents(), self.carried_item.to_network_slot(), ), &NetEncodeOpts::WithLength, @@ -196,13 +165,40 @@ impl Inventory { Ok(()) } - pub async fn sync_inventory(&mut self, state: Arc) -> Result<(), InventoryError> { + pub async fn sync_inventory_with( + &mut self, + sync_type: &InventorySyncType, + writer: ComponentRefMut<'_, StreamWriter>, + ) -> Result<(), InventoryError> { + match sync_type { + InventorySyncType::All => self.send_inventory_content(writer).await?, + InventorySyncType::Single(slot_num) => { + self.send_inventory_slot_content(*slot_num, writer).await? + } + } + Ok(()) + } + + pub async fn sync_inventory( + &mut self, + without_entity: Entity, + sync_type: &InventorySyncType, + state: Arc, + ) -> Result<(), InventoryError> { + if !self.is_synced { + return Err(InventoryError::SyncingANonSyncedInventory(self.id)); + } + let universe = &state.universe; let query = universe .get_component_manager() .get_entities_with::(); for entity_id in query { + if entity_id == without_entity { + continue; + } + let inventory_result = universe.get_mut::(entity_id); match inventory_result { Ok(inventory) => { @@ -211,9 +207,9 @@ impl Inventory { } let writer = universe.get_mut::(entity_id)?; - self.send_inventory_content(writer).await?; + self.sync_inventory_with(sync_type, writer).await?; } - Err(err) => return Err(InventoryError::ECSError(err)), + _ => {} } } @@ -242,7 +238,7 @@ impl Inventory { self.send_inventory_content(writer).await?; // handle event - let event = OpenInventoryEvent::new(entity_id).inventory_id(self.id); + let event = OpenInventoryEvent::new(entity_id, self.id); OpenInventoryEvent::trigger(event, state.clone()).await?; universe.add_component::(entity_id, self)?; @@ -271,7 +267,7 @@ impl Inventory { Ok(()) } - pub fn set_slot(&mut self, slot_id: i32, slot: Slot) -> &mut Self { + pub fn set_slot(&mut self, slot_id: i16, slot: Slot) -> &mut Self { let size = self.inventory_type.get_size(); if (0..=size).contains(&slot_id) { self.contents.set_slot(slot_id, slot); @@ -280,7 +276,15 @@ impl Inventory { self } - pub fn get_slot(&self, slot_id: i32) -> Option { + pub fn set_slots(&mut self, slots: Vec<(i16, Slot)>) -> &mut Self { + for (slot_num, slot) in slots { + self.set_slot(slot_num, slot); + } + + self + } + + pub fn get_slot(&self, slot_id: i16) -> Option { let size = self.inventory_type.get_size(); if (0..=size).contains(&slot_id) { self.contents.get_slot(slot_id) @@ -289,11 +293,11 @@ impl Inventory { } } - pub fn get_contents(&self) -> &BTreeMap { + pub fn get_contents(&self) -> &BTreeMap { &self.contents.contents } - pub fn get_contents_mut(&mut self) -> &mut BTreeMap { + pub fn get_contents_mut(&mut self) -> &mut BTreeMap { &mut self.contents.contents } @@ -311,7 +315,7 @@ impl Inventory { self.get_contents().iter().any(|slot| slot.1.item == item) } - pub fn contains_atleast(&self, item: i32, amount: usize) -> bool { + pub fn contains_atleast(&self, item: i32, amount: i32) -> bool { let mut container_amount = 0; self.get_contents().iter().for_each(|(_, slot)| { if slot.item == item { @@ -319,10 +323,10 @@ impl Inventory { } }); - container_amount >= amount as i32 + container_amount >= amount } - pub fn get_first_empty(&self) -> i32 { + pub fn get_first_empty(&self) -> i16 { let contents = self.get_contents(); for i in 0..self.get_size() { if contents.get(&i).is_none() { @@ -333,7 +337,7 @@ impl Inventory { 0 } - pub fn get_size(&self) -> i32 { + pub fn get_size(&self) -> i16 { self.inventory_type.get_size() } diff --git a/src/lib/inventory/src/lib.rs b/src/lib/inventory/src/lib.rs index 87e3278b..90c54e33 100644 --- a/src/lib/inventory/src/lib.rs +++ b/src/lib/inventory/src/lib.rs @@ -1,9 +1,6 @@ +pub mod builder; pub mod contents; -pub mod events; +pub mod errors; pub mod inventory; -pub mod player_inventory; pub mod slot; pub mod types; - -#[cfg(test)] -mod tests; diff --git a/src/lib/inventory/src/tests.rs b/src/lib/inventory/src/tests.rs deleted file mode 100644 index 1788f9ab..00000000 --- a/src/lib/inventory/src/tests.rs +++ /dev/null @@ -1,8 +0,0 @@ -#[test] -fn create_inventory() { - let mut inventory = - crate::inventory::Inventory::new(1, "Something", crate::inventory::InventoryType::Chest(4)); - inventory.set_slot(0, crate::slot::Slot::with_item(9)); - - inventory.clear(); -} diff --git a/src/lib/inventory/src/types/mod.rs b/src/lib/inventory/src/types/mod.rs index 8b137891..109bd3ef 100644 --- a/src/lib/inventory/src/types/mod.rs +++ b/src/lib/inventory/src/types/mod.rs @@ -1 +1 @@ - +pub mod player_inventory; diff --git a/src/lib/inventory/src/player_inventory.rs b/src/lib/inventory/src/types/player_inventory.rs similarity index 89% rename from src/lib/inventory/src/player_inventory.rs rename to src/lib/inventory/src/types/player_inventory.rs index 3445d418..7c7bfb10 100644 --- a/src/lib/inventory/src/player_inventory.rs +++ b/src/lib/inventory/src/types/player_inventory.rs @@ -3,7 +3,9 @@ use std::ops::{Deref, DerefMut}; use ferrumc_net::packets::outgoing::set_equipment::EquipmentSlot; use crate::{ - inventory::{Inventory, InventoryError, InventoryType}, + builder::InventoryBuilder, + errors::InventoryError, + inventory::{Inventory, InventoryType}, slot::Slot, }; @@ -50,7 +52,9 @@ impl Default for PlayerInventory { impl PlayerInventory { pub fn new(equipment_content: EquipmentContent, main_hand: Slot, off_hand: Slot) -> Self { Self { - inventory: Inventory::new(0, "", InventoryType::Chest(5)), + inventory: InventoryBuilder::new(0) + .inventory_type(InventoryType::Chest(5)) + .build(), equipment_content, main_hand, off_hand, diff --git a/src/lib/net/src/packets/incoming/click_container.rs b/src/lib/net/src/packets/incoming/click_container.rs index 2934ab44..f0c6d9c0 100644 --- a/src/lib/net/src/packets/incoming/click_container.rs +++ b/src/lib/net/src/packets/incoming/click_container.rs @@ -9,7 +9,7 @@ use ferrumc_net_codec::net_types::var_int::VarInt; use ferrumc_state::ServerState; use std::io::Read; use std::sync::Arc; -use tracing::info; +use tracing::debug; #[derive(Debug, Clone, Copy)] pub enum InventoryClickActions { @@ -90,12 +90,12 @@ impl InventoryClickActions { #[derive(NetDecode, Debug)] pub struct ChangedSlots { - pub slot_number: u16, + pub slot_number: i16, pub slot: NetworkSlot, } impl ChangedSlots { - pub fn new(slot_number: u16, slot: NetworkSlot) -> Self { + pub fn new(slot_number: i16, slot: NetworkSlot) -> Self { Self { slot_number, slot } } } @@ -136,7 +136,7 @@ impl NetDecode for ClickContainerPacket { impl IncomingPacket for ClickContainerPacket { async fn handle(self, conn_id: usize, state: Arc) -> NetResult<()> { - info!("Clicked Container: {:#?}", self); + debug!("{:#?}", self); let event = InventoryClickEvent::new(conn_id, self); InventoryClickEvent::trigger(event, state).await?; @@ -170,7 +170,7 @@ impl ClickContainerPacket { pub struct InventoryClickEvent { pub conn_id: usize, pub packet: ClickContainerPacket, - pub is_cancelled: bool, + pub is_canceled: bool, } impl InventoryClickEvent { @@ -178,11 +178,11 @@ impl InventoryClickEvent { Self { conn_id, packet, - is_cancelled: false, + is_canceled: false, } } - pub fn set_cancelled(&mut self, is_cancelled: bool) { - self.is_cancelled = is_cancelled; + pub fn set_canceled(&mut self, is_cancelled: bool) { + self.is_canceled = is_cancelled; } } 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 27e5eeba..8a601af1 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 @@ -12,13 +12,13 @@ use crate::{ #[derive(NetDecode, Debug)] #[packet(packet_id = 0x32, state = "play")] pub struct SetCreativeModeSlotPacket { - pub slot: u16, + pub slot: i16, pub clicked_item: NetworkSlot, } impl IncomingPacket for SetCreativeModeSlotPacket { async fn handle(self, conn_id: usize, state: Arc) -> NetResult<()> { - let event = SetCreativeModeSlotEvent::new(conn_id, self); + let event = SetCreativeModeSlotEvent::new(conn_id, self.slot, self.clicked_item); SetCreativeModeSlotEvent::trigger(event, state).await?; Ok(()) } @@ -27,11 +27,16 @@ impl IncomingPacket for SetCreativeModeSlotPacket { #[derive(Event, Debug)] pub struct SetCreativeModeSlotEvent { pub conn_id: usize, - pub packet: SetCreativeModeSlotPacket, + pub slot: i16, + pub clicked_item: NetworkSlot, } impl SetCreativeModeSlotEvent { - pub fn new(conn_id: usize, packet: SetCreativeModeSlotPacket) -> Self { - Self { conn_id, packet } + pub fn new(conn_id: usize, slot: i16, clicked_item: NetworkSlot) -> Self { + Self { + conn_id, + slot, + clicked_item, + } } } diff --git a/src/lib/net/src/packets/incoming/set_held_item.rs b/src/lib/net/src/packets/incoming/set_held_item.rs index d71aeec8..5905418a 100644 --- a/src/lib/net/src/packets/incoming/set_held_item.rs +++ b/src/lib/net/src/packets/incoming/set_held_item.rs @@ -14,7 +14,7 @@ pub struct IncomingSetHeldItemPacket { impl IncomingPacket for IncomingSetHeldItemPacket { async fn handle(self, conn_id: usize, state: Arc) -> NetResult<()> { - let event = ChangeSlotEvent::new(conn_id, self); + let event = ChangeSlotEvent::new(conn_id, self.slot); ChangeSlotEvent::trigger(event, state).await?; Ok(()) @@ -24,11 +24,11 @@ impl IncomingPacket for IncomingSetHeldItemPacket { #[derive(Event, Debug)] pub struct ChangeSlotEvent { pub conn_id: usize, - pub packet: IncomingSetHeldItemPacket, + pub slot: u16, } impl ChangeSlotEvent { - pub fn new(conn_id: usize, packet: IncomingSetHeldItemPacket) -> Self { - Self { conn_id, packet } + pub fn new(conn_id: usize, slot: u16) -> Self { + Self { conn_id, slot } } } diff --git a/src/lib/net/src/packets/outgoing/open_screen.rs b/src/lib/net/src/packets/outgoing/open_screen.rs index 50a20389..2f786c98 100644 --- a/src/lib/net/src/packets/outgoing/open_screen.rs +++ b/src/lib/net/src/packets/outgoing/open_screen.rs @@ -1,4 +1,4 @@ -use ferrumc_macros::{packet, NetEncode}; +use ferrumc_macros::{packet, Event, NetEncode}; use ferrumc_net_codec::net_types::var_int::VarInt; use ferrumc_text::{TextComponent, TextComponentBuilder}; use std::io::Write; @@ -12,15 +12,15 @@ pub struct OpenScreenPacket { } impl OpenScreenPacket { - pub fn new(window_id: i32, window_type: VarInt, window_title: TextComponent) -> Self { + pub fn new(window_id: u8, window_type: i32, window_title: TextComponent) -> Self { Self { - window_id: VarInt::new(window_id), - window_type, + window_id: VarInt::new(i32::from(window_id)), + window_type: VarInt::new(window_type), window_title, } } - pub fn with_empty_title(window_id: i32, window_type: VarInt) -> Self { + pub fn with_empty_title(window_id: u8, window_type: i32) -> Self { Self::new( window_id, window_type, @@ -28,3 +28,18 @@ impl OpenScreenPacket { ) } } + +#[derive(Event, Debug)] +pub struct OpenInventoryEvent { + pub conn_id: usize, + pub inventory_id: u8, +} + +impl OpenInventoryEvent { + pub fn new(conn_id: usize, inventory_id: u8) -> Self { + Self { + conn_id, + inventory_id, + } + } +} From 6dd2513cbb7500a6c8cf5f275ebb510ff8976fb7 Mon Sep 17 00:00:00 2001 From: Outspending Date: Sat, 4 Jan 2025 12:19:48 -0700 Subject: [PATCH 27/38] clippy fix + fmt --- src/bin/src/packet_handlers/containers.rs | 2 +- src/lib/inventory/src/inventory.rs | 19 ++++++++----------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/bin/src/packet_handlers/containers.rs b/src/bin/src/packet_handlers/containers.rs index eb063d72..0d7e8e21 100644 --- a/src/bin/src/packet_handlers/containers.rs +++ b/src/bin/src/packet_handlers/containers.rs @@ -40,7 +40,7 @@ async fn handle_container_click( if inventory.is_synced { match packet.changed_slots.data.as_slice() { [changed_slot] => { - let slot_num = changed_slot.slot_number as i16; + let slot_num = changed_slot.slot_number; inventory .set_slot(slot_num, Slot::from_network_slot(changed_slot.slot)) diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs index 15ffabde..3fac4713 100644 --- a/src/lib/inventory/src/inventory.rs +++ b/src/lib/inventory/src/inventory.rs @@ -200,16 +200,13 @@ impl Inventory { } let inventory_result = universe.get_mut::(entity_id); - match inventory_result { - Ok(inventory) => { - if self.id != inventory.id { - continue; - } - - let writer = universe.get_mut::(entity_id)?; - self.sync_inventory_with(sync_type, writer).await?; + if let Ok(inventory) = inventory_result { + if self.id != inventory.id { + continue; } - _ => {} + + let writer = universe.get_mut::(entity_id)?; + self.sync_inventory_with(sync_type, writer).await?; } } @@ -256,13 +253,13 @@ impl Inventory { writer .send_packet( - &CloseContainerPacket::new(self.id as u8), + &CloseContainerPacket::new(self.id), &NetEncodeOpts::WithLength, ) .await?; // handle event - let event = InventoryCloseEvent::new(entity_id, inventory.id as u8); + let event = InventoryCloseEvent::new(entity_id, inventory.id); InventoryCloseEvent::trigger(event, state.clone()).await?; Ok(()) } From 7a9b5189a5de8af8830dabf7bcb1f69e13949ffd Mon Sep 17 00:00:00 2001 From: Outspending Date: Sat, 4 Jan 2025 21:53:55 -0700 Subject: [PATCH 28/38] Inventory Types + Macros --- src/bin/src/packet_handlers/containers.rs | 2 +- src/bin/src/packet_handlers/login_process.rs | 2 +- src/lib/derive_macros/src/inventory/mod.rs | 160 ++++++++++++++++++ src/lib/derive_macros/src/lib.rs | 18 ++ src/lib/inventory/src/inventory.rs | 12 +- src/lib/inventory/src/types/beacon.rs | 11 ++ src/lib/inventory/src/types/enchanting.rs | 13 ++ src/lib/inventory/src/types/mod.rs | 4 +- .../types/{player_inventory.rs => player.rs} | 0 9 files changed, 212 insertions(+), 10 deletions(-) create mode 100644 src/lib/derive_macros/src/inventory/mod.rs create mode 100644 src/lib/inventory/src/types/beacon.rs create mode 100644 src/lib/inventory/src/types/enchanting.rs rename src/lib/inventory/src/types/{player_inventory.rs => player.rs} (100%) diff --git a/src/bin/src/packet_handlers/containers.rs b/src/bin/src/packet_handlers/containers.rs index 0d7e8e21..711dc10f 100644 --- a/src/bin/src/packet_handlers/containers.rs +++ b/src/bin/src/packet_handlers/containers.rs @@ -1,6 +1,6 @@ use ferrumc_inventory::inventory::{Inventory, InventorySyncType}; use ferrumc_inventory::slot::Slot; -use ferrumc_inventory::types::player_inventory::PlayerInventory; +use ferrumc_inventory::types::player::PlayerInventory; use ferrumc_macros::event_handler; use ferrumc_net::errors::NetError; use ferrumc_net::packets::incoming::click_container::InventoryClickEvent; diff --git a/src/bin/src/packet_handlers/login_process.rs b/src/bin/src/packet_handlers/login_process.rs index 7c494368..02637e5e 100644 --- a/src/bin/src/packet_handlers/login_process.rs +++ b/src/bin/src/packet_handlers/login_process.rs @@ -8,7 +8,7 @@ use ferrumc_ecs::components::storage::ComponentRefMut; use ferrumc_inventory::builder::InventoryBuilder; use ferrumc_inventory::inventory::InventoryType; use ferrumc_inventory::slot::Slot; -use ferrumc_inventory::types::player_inventory::PlayerInventory; +use ferrumc_inventory::types::player::PlayerInventory; use ferrumc_macros::event_handler; use ferrumc_net::connection::{ConnectionState, StreamWriter}; use ferrumc_net::errors::NetError; diff --git a/src/lib/derive_macros/src/inventory/mod.rs b/src/lib/derive_macros/src/inventory/mod.rs new file mode 100644 index 00000000..afd59578 --- /dev/null +++ b/src/lib/derive_macros/src/inventory/mod.rs @@ -0,0 +1,160 @@ +use proc_macro::TokenStream; +use proc_macro_crate::{crate_name, FoundCrate}; +use quote::quote; +use syn::{Data, Visibility}; + +pub fn create(input: TokenStream) -> TokenStream { + let input = syn::parse_macro_input!(input as syn::DeriveInput); + let name = &input.ident; + + if let Data::Struct(data_struct) = &input.data { + let mut default_statements = Vec::new(); + let mut field_statements = Vec::new(); + + let found_crate = crate_name("ferrumc-inventory").unwrap(); + + let net_crate = match found_crate { + FoundCrate::Itself => { + quote! { crate } + } + FoundCrate::Name(name) => { + let name = syn::Ident::new(&name, proc_macro2::Span::call_site()); + quote! { #name } + } + }; + + let mut inventory_type_expr: Option = None; + + // Extract inventory_type attribute + for attr in &input.attrs { + if attr.path().is_ident("inventory_type") { + attr.parse_nested_meta(|meta| { + if let Some(ident) = meta.path.get_ident() { + if ident.to_string().as_str() == "value" { + let value = meta.value().expect("Missing value for inventory_type"); + + let value = value + .parse::() + .expect("Failed to parse value in inventory_type"); + inventory_type_expr = Some(value); + } + } + Ok(()) + }) + .unwrap(); + } + } + + // Process fields + for field in &data_struct.fields { + let field_name = &field.ident.clone().expect("Missing field"); + let field_ty = &field.ty; + + let mut id_expr = None; + let mut value_expr = None; + + if let Visibility::Public(_) = &field.vis { + for attr in &field.attrs { + if attr.path().is_ident("slot") { + attr.parse_nested_meta(|meta| { + if let Some(ident) = meta.path.get_ident() { + match ident.to_string().as_str() { + "id" => { + let value = meta.value().expect("Missing value for slot"); + + let value = value + .parse::() + .expect("Failed to parse value in slot"); + + id_expr = Some(value); + } + "default_value" => { + let value = + meta.value().expect("Missing default_value for slot"); + + let value = value + .parse::() + .expect("Failed to parse default_value in slot"); + + value_expr = Some(value); + } + _ => {} + } + } + Ok(()) + }) + .unwrap(); + } + } + } + + // Generate default initialization and setter methods + if let (Some(id), Some(value)) = (id_expr, value_expr) { + default_statements.push(quote! { + #field_name: #value, + }); + + let setter_name = + syn::Ident::new(&format!("set_{}", field_name), field_name.span()); + field_statements.push(quote! { + pub fn #setter_name(&mut self, #field_name: #field_ty) { + self.#field_name = #field_name; + self.set_slot(#id, #net_crate::slot::Slot::with_item(#field_name)); + } + }); + } + } + + // Generate the `new` method + let new_method = if let Some(expr) = inventory_type_expr { + Some(quote! { + pub fn new(id: u8) -> Self { + Self { + inventory: #net_crate::builder::InventoryBuilder::new(id) + .inventory_type(#net_crate::inventory::InventoryType::#expr) + .build(), + #(#default_statements)* + } + } + }) + } else { + None + }; + + // Generate the complete implementation block + // Wacky ass code because rust is retarded + let output = quote! { + impl #name { + #new_method + + #(#field_statements)* + } + + impl std::ops::Deref for #name { + type Target = Inventory; + + fn deref(&self) -> &Self::Target { + &self.inventory + } + } + + impl std::ops::DerefMut for #name { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inventory + } + } + }; + + output.into() + } else { + TokenStream::new() + } +} + +pub fn inventory_type(args: TokenStream, input: TokenStream) -> TokenStream { + input +} + +pub fn slot(args: TokenStream, input: TokenStream) -> TokenStream { + input +} diff --git a/src/lib/derive_macros/src/lib.rs b/src/lib/derive_macros/src/lib.rs index 06fd84f8..b505d737 100644 --- a/src/lib/derive_macros/src/lib.rs +++ b/src/lib/derive_macros/src/lib.rs @@ -4,6 +4,7 @@ use proc_macro::TokenStream; mod events; mod helpers; +mod inventory; mod nbt; mod net; mod profiling; @@ -54,3 +55,20 @@ pub fn bake_packet_registry(input: TokenStream) -> TokenStream { net::packets::bake_registry(input) } // #=================== PACKETS ===================# + +// #=================== INVENTORY ===================# +#[proc_macro_attribute] +pub fn slot(args: TokenStream, input: TokenStream) -> TokenStream { + inventory::slot(args, input) +} + +#[proc_macro_attribute] +pub fn inventory_type(args: TokenStream, input: TokenStream) -> TokenStream { + inventory::inventory_type(args, input) +} + +#[proc_macro_derive(Inventory, attributes(slot))] +pub fn inventory_create(input: TokenStream) -> TokenStream { + inventory::create(input) +} +// #=================== INVENTORY ===================# diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs index 3fac4713..5763234d 100644 --- a/src/lib/inventory/src/inventory.rs +++ b/src/lib/inventory/src/inventory.rs @@ -49,7 +49,7 @@ impl InventoryType { if (1..=6).contains(&value) { value - 1 } else { - 0 // defaults to 1 row chest + 1 // defaults to 1 row chest } } InventoryType::Anvil => 8, @@ -115,10 +115,9 @@ impl Inventory { return; } - let slot = match self.get_slot(36 + (carried_item as i16)) { - Some(slot) => slot, - None => Slot::empty(), - }; + let slot = self + .get_slot(36 + (carried_item as i16)) + .unwrap_or_else(|| Slot::empty()); self.carried_item = slot; } @@ -141,8 +140,7 @@ impl Inventory { ), &NetEncodeOpts::WithLength, ) - .await - .unwrap(); + .await?; Ok(()) } diff --git a/src/lib/inventory/src/types/beacon.rs b/src/lib/inventory/src/types/beacon.rs new file mode 100644 index 00000000..81dc6ad3 --- /dev/null +++ b/src/lib/inventory/src/types/beacon.rs @@ -0,0 +1,11 @@ +use ferrumc_macros::{Inventory, inventory_type}; + +use crate::inventory::Inventory; + +#[derive(Inventory)] +#[inventory_type(value = Beacon)] +pub struct BeaconInventory { + inventory: Inventory, + #[slot(id = 0, default_value = 0)] + pub powered_item: i32, +} diff --git a/src/lib/inventory/src/types/enchanting.rs b/src/lib/inventory/src/types/enchanting.rs new file mode 100644 index 00000000..b667bae4 --- /dev/null +++ b/src/lib/inventory/src/types/enchanting.rs @@ -0,0 +1,13 @@ +use ferrumc_macros::{Inventory, inventory_type}; + +use crate::inventory::Inventory; + +#[derive(Inventory)] +#[inventory_type(value = EnchantmentTable)] +pub struct EnchantingInventory { + inventory: Inventory, + #[slot(id = 0, default_value = 0)] + pub item: i32, + #[slot(id = 1, default_value = 0)] + pub secondary: i32, +} diff --git a/src/lib/inventory/src/types/mod.rs b/src/lib/inventory/src/types/mod.rs index 109bd3ef..9fb1b849 100644 --- a/src/lib/inventory/src/types/mod.rs +++ b/src/lib/inventory/src/types/mod.rs @@ -1 +1,3 @@ -pub mod player_inventory; +pub mod beacon; +pub mod enchanting; +pub mod player; diff --git a/src/lib/inventory/src/types/player_inventory.rs b/src/lib/inventory/src/types/player.rs similarity index 100% rename from src/lib/inventory/src/types/player_inventory.rs rename to src/lib/inventory/src/types/player.rs From 2ff5a8398d3c90c72471663ee3ef7465f606040f Mon Sep 17 00:00:00 2001 From: Outspending Date: Sun, 5 Jan 2025 00:34:02 -0700 Subject: [PATCH 29/38] fixed merge conflicts --- src/lib/derive_macros/src/inventory/mod.rs | 4 +- src/lib/derive_macros/src/lib.rs | 39 +++++++++++++++++++ .../src/packets/incoming/click_container.rs | 2 +- .../src/packets/incoming/close_container.rs | 2 +- .../incoming/set_creative_mode_slot.rs | 2 +- .../net/src/packets/incoming/set_held_item.rs | 2 +- .../net/src/packets/incoming/use_item_on.rs | 2 +- .../src/packets/outgoing/close_container.rs | 2 +- .../net/src/packets/outgoing/open_screen.rs | 2 +- .../packets/outgoing/set_container_content.rs | 2 +- .../outgoing/set_container_property.rs | 2 +- .../packets/outgoing/set_container_slot.rs | 2 +- .../net/src/packets/outgoing/set_equipment.rs | 2 +- 13 files changed, 52 insertions(+), 13 deletions(-) diff --git a/src/lib/derive_macros/src/inventory/mod.rs b/src/lib/derive_macros/src/inventory/mod.rs index afd59578..08f8d534 100644 --- a/src/lib/derive_macros/src/inventory/mod.rs +++ b/src/lib/derive_macros/src/inventory/mod.rs @@ -151,10 +151,10 @@ pub fn create(input: TokenStream) -> TokenStream { } } -pub fn inventory_type(args: TokenStream, input: TokenStream) -> TokenStream { +pub fn inventory_type(_args: TokenStream, input: TokenStream) -> TokenStream { input } -pub fn slot(args: TokenStream, input: TokenStream) -> TokenStream { +pub fn slot(_args: TokenStream, input: TokenStream) -> TokenStream { input } diff --git a/src/lib/derive_macros/src/lib.rs b/src/lib/derive_macros/src/lib.rs index 06fd84f8..5ede0f20 100644 --- a/src/lib/derive_macros/src/lib.rs +++ b/src/lib/derive_macros/src/lib.rs @@ -4,9 +4,11 @@ use proc_macro::TokenStream; mod events; mod helpers; +mod inventory; mod nbt; mod net; mod profiling; +mod static_loading; #[proc_macro_attribute] pub fn profile(attr: TokenStream, item: TokenStream) -> TokenStream { @@ -44,6 +46,11 @@ pub fn net_decode(input: TokenStream) -> TokenStream { } // #=================== PACKETS ===================# +/// You can get the packet_id from: +/// https://protocol.ferrumc.com, +/// In incoming packets (serverbound), +/// You should use the 'resource' value referenced in the packet, +/// e.g. "finish_configuration", which would result in the packet_id being automatically fetched. #[proc_macro_attribute] pub fn packet(args: TokenStream, input: TokenStream) -> TokenStream { net::packets::attribute(args, input) @@ -53,4 +60,36 @@ pub fn packet(args: TokenStream, input: TokenStream) -> TokenStream { pub fn bake_packet_registry(input: TokenStream) -> TokenStream { net::packets::bake_registry(input) } + +/// Get a packet entry from the packets.json file. +/// returns protocol_id (as 0x??) of the specified packet. +/// e.g. get_packet_entry!("play", "clientbound", "add_entity") -> 0x01 +#[proc_macro] +pub fn get_packet_entry(input: TokenStream) -> TokenStream { + static_loading::packets::get(input) +} // #=================== PACKETS ===================# + +/// Get a registry entry from the registries.json file. +/// returns protocol_id (as u64) of the specified entry. +#[proc_macro] +pub fn get_registry_entry(input: TokenStream) -> TokenStream { + static_loading::registry::get(input) +} + +// #=================== INVENTORY ===================# +#[proc_macro_derive(Inventory, attributes(slot))] +pub fn create_inventory(input: TokenStream) -> TokenStream { + inventory::create(input) +} + +#[proc_macro_attribute] +pub fn slot(args: TokenStream, input: TokenStream) -> TokenStream { + inventory::slot(args, input) +} + +#[proc_macro_attribute] +pub fn inventory_type(args: TokenStream, input: TokenStream) -> TokenStream { + inventory::inventory_type(args, input) +} +// #=================== INVENTORY ===================# diff --git a/src/lib/net/src/packets/incoming/click_container.rs b/src/lib/net/src/packets/incoming/click_container.rs index f0c6d9c0..57b2c6e2 100644 --- a/src/lib/net/src/packets/incoming/click_container.rs +++ b/src/lib/net/src/packets/incoming/click_container.rs @@ -101,7 +101,7 @@ impl ChangedSlots { } #[derive(Debug)] -#[packet(packet_id = 0x0E, state = "play")] +#[packet(packet_id = "container_click", state = "play")] pub struct ClickContainerPacket { pub window_id: u8, pub state_id: VarInt, diff --git a/src/lib/net/src/packets/incoming/close_container.rs b/src/lib/net/src/packets/incoming/close_container.rs index c1fb1a21..1dae2986 100644 --- a/src/lib/net/src/packets/incoming/close_container.rs +++ b/src/lib/net/src/packets/incoming/close_container.rs @@ -6,7 +6,7 @@ use ferrumc_state::ServerState; use std::sync::Arc; #[derive(NetDecode, Debug)] -#[packet(packet_id = 0x0F, state = "play")] +#[packet(packet_id = "container_close", state = "play")] pub struct IncomingCloseContainerPacket { pub window_id: u8, } 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 8a601af1..e8aea661 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 @@ -10,7 +10,7 @@ use crate::{ }; #[derive(NetDecode, Debug)] -#[packet(packet_id = 0x32, state = "play")] +#[packet(packet_id = "set_creative_mode_slot", state = "play")] pub struct SetCreativeModeSlotPacket { pub slot: i16, pub clicked_item: NetworkSlot, diff --git a/src/lib/net/src/packets/incoming/set_held_item.rs b/src/lib/net/src/packets/incoming/set_held_item.rs index 5905418a..24fa7b89 100644 --- a/src/lib/net/src/packets/incoming/set_held_item.rs +++ b/src/lib/net/src/packets/incoming/set_held_item.rs @@ -7,7 +7,7 @@ use ferrumc_state::ServerState; use crate::{packets::IncomingPacket, NetResult}; #[derive(NetDecode, Debug)] -#[packet(packet_id = 0x2F, state = "play")] +#[packet(packet_id = "set_carried_item", state = "play")] pub struct IncomingSetHeldItemPacket { pub slot: u16, } diff --git a/src/lib/net/src/packets/incoming/use_item_on.rs b/src/lib/net/src/packets/incoming/use_item_on.rs index 3a8f888d..edaa130a 100644 --- a/src/lib/net/src/packets/incoming/use_item_on.rs +++ b/src/lib/net/src/packets/incoming/use_item_on.rs @@ -8,7 +8,7 @@ use ferrumc_state::ServerState; use std::sync::Arc; #[derive(NetDecode, Debug)] -#[packet(packet_id = 0x38, state = "play")] +#[packet(packet_id = "use_item_on", state = "play")] pub struct UseItemOnPacket { pub hand: VarInt, pub location: NetworkPosition, diff --git a/src/lib/net/src/packets/outgoing/close_container.rs b/src/lib/net/src/packets/outgoing/close_container.rs index 2157254d..d3f8cff9 100644 --- a/src/lib/net/src/packets/outgoing/close_container.rs +++ b/src/lib/net/src/packets/outgoing/close_container.rs @@ -2,7 +2,7 @@ use ferrumc_macros::{packet, NetEncode}; use std::io::Write; #[derive(NetEncode)] -#[packet(packet_id = 0x12)] +#[packet(packet_id = "container_close", state_id = "play")] pub struct CloseContainerPacket { pub window_id: u8, } diff --git a/src/lib/net/src/packets/outgoing/open_screen.rs b/src/lib/net/src/packets/outgoing/open_screen.rs index 2f786c98..a59204a6 100644 --- a/src/lib/net/src/packets/outgoing/open_screen.rs +++ b/src/lib/net/src/packets/outgoing/open_screen.rs @@ -4,7 +4,7 @@ use ferrumc_text::{TextComponent, TextComponentBuilder}; use std::io::Write; #[derive(NetEncode)] -#[packet(packet_id = 0x33)] +#[packet(packet_id = "open_screen", state_id = "play")] pub struct OpenScreenPacket { pub window_id: VarInt, pub window_type: VarInt, 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 bc9ead26..85c9c2ea 100644 --- a/src/lib/net/src/packets/outgoing/set_container_content.rs +++ b/src/lib/net/src/packets/outgoing/set_container_content.rs @@ -4,7 +4,7 @@ use ferrumc_net_codec::net_types::{length_prefixed_vec::LengthPrefixedVec, var_i use std::io::Write; #[derive(NetEncode, Debug)] -#[packet(packet_id = 0x13)] +#[packet(packet_id = "container_set_content", state_id = "play")] pub struct SetContainerContentPacket { pub window_id: u8, pub state_id: VarInt, diff --git a/src/lib/net/src/packets/outgoing/set_container_property.rs b/src/lib/net/src/packets/outgoing/set_container_property.rs index 45d00c84..9129dadd 100644 --- a/src/lib/net/src/packets/outgoing/set_container_property.rs +++ b/src/lib/net/src/packets/outgoing/set_container_property.rs @@ -2,7 +2,7 @@ use ferrumc_macros::{packet, NetEncode}; use std::io::Write; #[derive(NetEncode)] -#[packet(packet_id = 0x14)] +#[packet(packet_id = "container_set_data", state_id = "play")] pub struct SetContainerPropertyPacket { pub window_id: u8, pub property: u16, 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 c55bf719..f43879de 100644 --- a/src/lib/net/src/packets/outgoing/set_container_slot.rs +++ b/src/lib/net/src/packets/outgoing/set_container_slot.rs @@ -43,7 +43,7 @@ impl NetworkSlot { } #[derive(NetEncode)] -#[packet(packet_id = 0x15)] +#[packet(packet_id = "container_set_slot", state_id = "play")] pub struct SetContainerSlotPacket { pub window_id: VarInt, pub state_id: VarInt, diff --git a/src/lib/net/src/packets/outgoing/set_equipment.rs b/src/lib/net/src/packets/outgoing/set_equipment.rs index 84b655a6..48601123 100644 --- a/src/lib/net/src/packets/outgoing/set_equipment.rs +++ b/src/lib/net/src/packets/outgoing/set_equipment.rs @@ -53,7 +53,7 @@ pub struct Equipment { } #[derive(NetEncode)] -#[packet(packet_id = 0x5B)] +#[packet(packet_id = "set_equipment", state_id = "play")] pub struct SetEquipmentPacket { pub conn_id: VarInt, pub equipment: Vec, From 4a59780ddd564b38f4b822eaca1466e60f68eedd Mon Sep 17 00:00:00 2001 From: Outspending Date: Sun, 5 Jan 2025 01:36:33 -0700 Subject: [PATCH 30/38] Inventory Types --- src/lib/derive_macros/src/inventory/mod.rs | 8 +--- src/lib/inventory/src/inventory.rs | 2 +- src/lib/inventory/src/types/anvil.rs | 14 +++++++ src/lib/inventory/src/types/beacon.rs | 2 +- src/lib/inventory/src/types/cartography.rs | 14 +++++++ src/lib/inventory/src/types/enchanting.rs | 2 +- src/lib/inventory/src/types/furnace.rs | 38 +++++++++++++++++++ src/lib/inventory/src/types/grindstone.rs | 14 +++++++ src/lib/inventory/src/types/loom.rs | 16 ++++++++ src/lib/inventory/src/types/mod.rs | 7 ++++ src/lib/inventory/src/types/smithing_table.rs | 16 ++++++++ src/lib/inventory/src/types/stonecutter.rs | 12 ++++++ 12 files changed, 136 insertions(+), 9 deletions(-) create mode 100644 src/lib/inventory/src/types/anvil.rs create mode 100644 src/lib/inventory/src/types/cartography.rs create mode 100644 src/lib/inventory/src/types/furnace.rs create mode 100644 src/lib/inventory/src/types/grindstone.rs create mode 100644 src/lib/inventory/src/types/loom.rs create mode 100644 src/lib/inventory/src/types/smithing_table.rs create mode 100644 src/lib/inventory/src/types/stonecutter.rs diff --git a/src/lib/derive_macros/src/inventory/mod.rs b/src/lib/derive_macros/src/inventory/mod.rs index 08f8d534..31b0ef14 100644 --- a/src/lib/derive_macros/src/inventory/mod.rs +++ b/src/lib/derive_macros/src/inventory/mod.rs @@ -106,8 +106,7 @@ pub fn create(input: TokenStream) -> TokenStream { } // Generate the `new` method - let new_method = if let Some(expr) = inventory_type_expr { - Some(quote! { + let new_method = inventory_type_expr.map(|expr| quote! { pub fn new(id: u8) -> Self { Self { inventory: #net_crate::builder::InventoryBuilder::new(id) @@ -116,10 +115,7 @@ pub fn create(input: TokenStream) -> TokenStream { #(#default_statements)* } } - }) - } else { - None - }; + }); // Generate the complete implementation block // Wacky ass code because rust is retarded diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs index 5763234d..42b58edf 100644 --- a/src/lib/inventory/src/inventory.rs +++ b/src/lib/inventory/src/inventory.rs @@ -117,7 +117,7 @@ impl Inventory { let slot = self .get_slot(36 + (carried_item as i16)) - .unwrap_or_else(|| Slot::empty()); + .unwrap_or_else(Slot::empty); self.carried_item = slot; } diff --git a/src/lib/inventory/src/types/anvil.rs b/src/lib/inventory/src/types/anvil.rs new file mode 100644 index 00000000..0e5e2fa0 --- /dev/null +++ b/src/lib/inventory/src/types/anvil.rs @@ -0,0 +1,14 @@ +use crate::inventory::Inventory; +use ferrumc_macros::{Inventory, inventory_type}; + +#[derive(Inventory, Debug)] +#[inventory_type(value = Anvil)] +pub struct EnchantingInventory { + inventory: Inventory, + #[slot(id = 0, default_value = 0)] + pub first: i32, + #[slot(id = 1, default_value = 0)] + pub second: i32, + #[slot(id = 2, default_value = 0)] + pub result: i32, +} diff --git a/src/lib/inventory/src/types/beacon.rs b/src/lib/inventory/src/types/beacon.rs index 81dc6ad3..4f266643 100644 --- a/src/lib/inventory/src/types/beacon.rs +++ b/src/lib/inventory/src/types/beacon.rs @@ -2,7 +2,7 @@ use ferrumc_macros::{Inventory, inventory_type}; use crate::inventory::Inventory; -#[derive(Inventory)] +#[derive(Inventory, Debug)] #[inventory_type(value = Beacon)] pub struct BeaconInventory { inventory: Inventory, diff --git a/src/lib/inventory/src/types/cartography.rs b/src/lib/inventory/src/types/cartography.rs new file mode 100644 index 00000000..5033b549 --- /dev/null +++ b/src/lib/inventory/src/types/cartography.rs @@ -0,0 +1,14 @@ +use crate::inventory::Inventory; +use ferrumc_macros::{Inventory, inventory_type}; + +#[derive(Inventory, Debug)] +#[inventory_type(value = Cartography)] +pub struct EnchantingInventory { + inventory: Inventory, + #[slot(id = 0, default_value = 0)] + pub map: i32, + #[slot(id = 1, default_value = 0)] + pub paper: i32, + #[slot(id = 2, default_value = 0)] + pub output: i32, +} diff --git a/src/lib/inventory/src/types/enchanting.rs b/src/lib/inventory/src/types/enchanting.rs index b667bae4..37aedb5d 100644 --- a/src/lib/inventory/src/types/enchanting.rs +++ b/src/lib/inventory/src/types/enchanting.rs @@ -2,7 +2,7 @@ use ferrumc_macros::{Inventory, inventory_type}; use crate::inventory::Inventory; -#[derive(Inventory)] +#[derive(Inventory, Debug)] #[inventory_type(value = EnchantmentTable)] pub struct EnchantingInventory { inventory: Inventory, diff --git a/src/lib/inventory/src/types/furnace.rs b/src/lib/inventory/src/types/furnace.rs new file mode 100644 index 00000000..6972bdd5 --- /dev/null +++ b/src/lib/inventory/src/types/furnace.rs @@ -0,0 +1,38 @@ +use crate::inventory::Inventory; +use ferrumc_macros::{Inventory, inventory_type}; + +#[derive(Inventory, Debug)] +#[inventory_type(value = Furnace)] +pub struct FurnaceInventory { + inventory: Inventory, + #[slot(id = 0, default_value = 0)] + pub ingredient: i32, + #[slot(id = 1, default_value = 0)] + pub fuel: i32, + #[slot(id = 2, default_value = 0)] + pub output: i32, +} + +#[derive(Inventory, Debug)] +#[inventory_type(value = BlastFurnace)] +pub struct BlastFurnaceInventory { + inventory: Inventory, + #[slot(id = 0, default_value = 0)] + pub ingredient: i32, + #[slot(id = 1, default_value = 0)] + pub fuel: i32, + #[slot(id = 2, default_value = 0)] + pub output: i32, +} + +#[derive(Inventory, Debug)] +#[inventory_type(value = Smoker)] +pub struct SmokerInventory { + inventory: Inventory, + #[slot(id = 0, default_value = 0)] + pub ingredient: i32, + #[slot(id = 1, default_value = 0)] + pub fuel: i32, + #[slot(id = 2, default_value = 0)] + pub output: i32, +} diff --git a/src/lib/inventory/src/types/grindstone.rs b/src/lib/inventory/src/types/grindstone.rs new file mode 100644 index 00000000..b98d7ff9 --- /dev/null +++ b/src/lib/inventory/src/types/grindstone.rs @@ -0,0 +1,14 @@ +use crate::inventory::Inventory; +use ferrumc_macros::{Inventory, inventory_type}; + +#[derive(Inventory, Debug)] +#[inventory_type(value = Grindstone)] +pub struct GrindstoneInventory { + inventory: Inventory, + #[slot(id = 0, default_value = 0)] + pub first: i32, + #[slot(id = 1, default_value = 0)] + pub second: i32, + #[slot(id = 2, default_value = 0)] + pub result: i32, +} diff --git a/src/lib/inventory/src/types/loom.rs b/src/lib/inventory/src/types/loom.rs new file mode 100644 index 00000000..e8cf7c2f --- /dev/null +++ b/src/lib/inventory/src/types/loom.rs @@ -0,0 +1,16 @@ +use crate::inventory::Inventory; +use ferrumc_macros::{Inventory, inventory_type}; + +#[derive(Inventory, Debug)] +#[inventory_type(value = Loom)] +pub struct LoomInventory { + inventory: Inventory, + #[slot(id = 0, default_value = 0)] + pub banner: i32, + #[slot(id = 1, default_value = 0)] + pub dye: i32, + #[slot(id = 2, default_value = 0)] + pub pattern: i32, + #[slot(id = 3, default_value = 0)] + pub result: i32, +} diff --git a/src/lib/inventory/src/types/mod.rs b/src/lib/inventory/src/types/mod.rs index 9fb1b849..70c6dd00 100644 --- a/src/lib/inventory/src/types/mod.rs +++ b/src/lib/inventory/src/types/mod.rs @@ -1,3 +1,10 @@ +mod anvil; pub mod beacon; +mod cartography; pub mod enchanting; +mod furnace; +mod grindstone; +mod loom; pub mod player; +mod smithing_table; +mod stonecutter; diff --git a/src/lib/inventory/src/types/smithing_table.rs b/src/lib/inventory/src/types/smithing_table.rs new file mode 100644 index 00000000..336de905 --- /dev/null +++ b/src/lib/inventory/src/types/smithing_table.rs @@ -0,0 +1,16 @@ +use crate::inventory::Inventory; +use ferrumc_macros::{Inventory, inventory_type}; + +#[derive(Inventory, Debug)] +#[inventory_type(value = SmithingTable)] +pub struct SmithingTableInventory { + inventory: Inventory, + #[slot(id = 0, default_value = 0)] + pub template: i32, + #[slot(id = 1, default_value = 0)] + pub base: i32, + #[slot(id = 2, default_value = 0)] + pub additional: i32, + #[slot(id = 3, default_value = 0)] + pub result: i32, +} diff --git a/src/lib/inventory/src/types/stonecutter.rs b/src/lib/inventory/src/types/stonecutter.rs new file mode 100644 index 00000000..a199101d --- /dev/null +++ b/src/lib/inventory/src/types/stonecutter.rs @@ -0,0 +1,12 @@ +use crate::inventory::Inventory; +use ferrumc_macros::{Inventory, inventory_type}; + +#[derive(Inventory, Debug)] +#[inventory_type(value = Stonecutter)] +pub struct StoneCutterInventory { + inventory: Inventory, + #[slot(id = 0, default_value = 0)] + pub input: i32, + #[slot(id = 1, default_value = 0)] + pub result: i32, +} From 14788fbf8fec5ce74a304d538c00ae4cc780eef3 Mon Sep 17 00:00:00 2001 From: Outspending Date: Sun, 5 Jan 2025 01:42:34 -0700 Subject: [PATCH 31/38] format fix --- src/lib/derive_macros/src/inventory/mod.rs | 6 ++++-- src/lib/inventory/src/types/anvil.rs | 2 ++ src/lib/inventory/src/types/beacon.rs | 2 ++ src/lib/inventory/src/types/cartography.rs | 1 + src/lib/inventory/src/types/enchanting.rs | 2 ++ src/lib/inventory/src/types/furnace.rs | 2 ++ src/lib/inventory/src/types/grindstone.rs | 2 ++ src/lib/inventory/src/types/loom.rs | 2 ++ src/lib/inventory/src/types/mod.rs | 14 +++++++------- src/lib/inventory/src/types/smithing_table.rs | 2 ++ src/lib/inventory/src/types/stonecutter.rs | 2 ++ 11 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/lib/derive_macros/src/inventory/mod.rs b/src/lib/derive_macros/src/inventory/mod.rs index 31b0ef14..aff230ea 100644 --- a/src/lib/derive_macros/src/inventory/mod.rs +++ b/src/lib/derive_macros/src/inventory/mod.rs @@ -106,7 +106,8 @@ pub fn create(input: TokenStream) -> TokenStream { } // Generate the `new` method - let new_method = inventory_type_expr.map(|expr| quote! { + let new_method = inventory_type_expr.map(|expr| { + quote! { pub fn new(id: u8) -> Self { Self { inventory: #net_crate::builder::InventoryBuilder::new(id) @@ -115,7 +116,8 @@ pub fn create(input: TokenStream) -> TokenStream { #(#default_statements)* } } - }); + } + }); // Generate the complete implementation block // Wacky ass code because rust is retarded diff --git a/src/lib/inventory/src/types/anvil.rs b/src/lib/inventory/src/types/anvil.rs index 0e5e2fa0..9f06b68d 100644 --- a/src/lib/inventory/src/types/anvil.rs +++ b/src/lib/inventory/src/types/anvil.rs @@ -1,3 +1,5 @@ +#![warn(dead_code)] + use crate::inventory::Inventory; use ferrumc_macros::{Inventory, inventory_type}; diff --git a/src/lib/inventory/src/types/beacon.rs b/src/lib/inventory/src/types/beacon.rs index 4f266643..b454af78 100644 --- a/src/lib/inventory/src/types/beacon.rs +++ b/src/lib/inventory/src/types/beacon.rs @@ -1,3 +1,5 @@ +#![warn(dead_code)] + use ferrumc_macros::{Inventory, inventory_type}; use crate::inventory::Inventory; diff --git a/src/lib/inventory/src/types/cartography.rs b/src/lib/inventory/src/types/cartography.rs index 5033b549..f4467a2e 100644 --- a/src/lib/inventory/src/types/cartography.rs +++ b/src/lib/inventory/src/types/cartography.rs @@ -1,3 +1,4 @@ +#![warn(dead_code)] use crate::inventory::Inventory; use ferrumc_macros::{Inventory, inventory_type}; diff --git a/src/lib/inventory/src/types/enchanting.rs b/src/lib/inventory/src/types/enchanting.rs index 37aedb5d..89cc8530 100644 --- a/src/lib/inventory/src/types/enchanting.rs +++ b/src/lib/inventory/src/types/enchanting.rs @@ -1,3 +1,5 @@ +#![warn(dead_code)] + use ferrumc_macros::{Inventory, inventory_type}; use crate::inventory::Inventory; diff --git a/src/lib/inventory/src/types/furnace.rs b/src/lib/inventory/src/types/furnace.rs index 6972bdd5..24caf8e2 100644 --- a/src/lib/inventory/src/types/furnace.rs +++ b/src/lib/inventory/src/types/furnace.rs @@ -1,3 +1,5 @@ +#![warn(dead_code)] + use crate::inventory::Inventory; use ferrumc_macros::{Inventory, inventory_type}; diff --git a/src/lib/inventory/src/types/grindstone.rs b/src/lib/inventory/src/types/grindstone.rs index b98d7ff9..05dc03b2 100644 --- a/src/lib/inventory/src/types/grindstone.rs +++ b/src/lib/inventory/src/types/grindstone.rs @@ -1,3 +1,5 @@ +#![warn(dead_code)] + use crate::inventory::Inventory; use ferrumc_macros::{Inventory, inventory_type}; diff --git a/src/lib/inventory/src/types/loom.rs b/src/lib/inventory/src/types/loom.rs index e8cf7c2f..80aa6879 100644 --- a/src/lib/inventory/src/types/loom.rs +++ b/src/lib/inventory/src/types/loom.rs @@ -1,3 +1,5 @@ +#![warn(dead_code)] + use crate::inventory::Inventory; use ferrumc_macros::{Inventory, inventory_type}; diff --git a/src/lib/inventory/src/types/mod.rs b/src/lib/inventory/src/types/mod.rs index 70c6dd00..6da5b7e2 100644 --- a/src/lib/inventory/src/types/mod.rs +++ b/src/lib/inventory/src/types/mod.rs @@ -1,10 +1,10 @@ -mod anvil; +pub mod anvil; pub mod beacon; -mod cartography; +pub mod cartography; pub mod enchanting; -mod furnace; -mod grindstone; -mod loom; +pub mod furnace; +pub mod grindstone; +pub mod loom; pub mod player; -mod smithing_table; -mod stonecutter; +pub mod smithing_table; +pub mod stonecutter; diff --git a/src/lib/inventory/src/types/smithing_table.rs b/src/lib/inventory/src/types/smithing_table.rs index 336de905..631f2d07 100644 --- a/src/lib/inventory/src/types/smithing_table.rs +++ b/src/lib/inventory/src/types/smithing_table.rs @@ -1,3 +1,5 @@ +#![warn(dead_code)] + use crate::inventory::Inventory; use ferrumc_macros::{Inventory, inventory_type}; diff --git a/src/lib/inventory/src/types/stonecutter.rs b/src/lib/inventory/src/types/stonecutter.rs index a199101d..571e5cfc 100644 --- a/src/lib/inventory/src/types/stonecutter.rs +++ b/src/lib/inventory/src/types/stonecutter.rs @@ -1,3 +1,5 @@ +#![warn(dead_code)] + use crate::inventory::Inventory; use ferrumc_macros::{Inventory, inventory_type}; From 3871f59c79fdd93c2558e10c66799e21dbfd634a Mon Sep 17 00:00:00 2001 From: Outspending Date: Sun, 5 Jan 2025 01:46:58 -0700 Subject: [PATCH 32/38] Update login_process.rs --- src/bin/src/packet_handlers/login_process.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/bin/src/packet_handlers/login_process.rs b/src/bin/src/packet_handlers/login_process.rs index fc166031..c4d2d0fb 100644 --- a/src/bin/src/packet_handlers/login_process.rs +++ b/src/bin/src/packet_handlers/login_process.rs @@ -5,6 +5,7 @@ use ferrumc_core::transform::grounded::OnGround; use ferrumc_core::transform::position::Position; use ferrumc_core::transform::rotation::Rotation; use ferrumc_ecs::components::storage::ComponentRefMut; +use ferrumc_inventory::types::player::PlayerInventory; use ferrumc_macros::event_handler; use ferrumc_net::connection::{ConnectionState, StreamWriter}; use ferrumc_net::errors::NetError; @@ -158,7 +159,8 @@ async fn handle_ack_finish_configuration( .universe .add_component::(conn_id, Position::default())? .add_component::(conn_id, Rotation::default())? - .add_component::(conn_id, OnGround::default())?; + .add_component::(conn_id, OnGround::default())? + .add_component::(conn_id, PlayerInventory::default())?; let mut writer = state.universe.get_mut::(conn_id)?; From 23d624e243676eb1bae7feef915ee0be0f254842 Mon Sep 17 00:00:00 2001 From: Outspending Date: Sun, 5 Jan 2025 09:24:32 -0700 Subject: [PATCH 33/38] Fixed merge issues --- Cargo.toml | 3 +- src/bin/src/packet_handlers/login_process.rs | 189 +++++++++++++------ 2 files changed, 132 insertions(+), 60 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e660a046..9b7b7203 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,8 @@ members = [ "src/lib/derive_macros", "src/lib/derive_macros", "src/lib/ecs", - "src/lib/events", "src/lib/inventory", + "src/lib/events", + "src/lib/inventory", "src/lib/net", "src/lib/net/crates/codec", "src/lib/net/crates/encryption", diff --git a/src/bin/src/packet_handlers/login_process.rs b/src/bin/src/packet_handlers/login_process.rs index c4d2d0fb..a98a9649 100644 --- a/src/bin/src/packet_handlers/login_process.rs +++ b/src/bin/src/packet_handlers/login_process.rs @@ -5,6 +5,7 @@ use ferrumc_core::transform::grounded::OnGround; use ferrumc_core::transform::position::Position; use ferrumc_core::transform::rotation::Rotation; use ferrumc_ecs::components::storage::ComponentRefMut; +use ferrumc_ecs::entities::Entity; use ferrumc_inventory::types::player::PlayerInventory; use ferrumc_macros::event_handler; use ferrumc_net::connection::{ConnectionState, StreamWriter}; @@ -21,13 +22,19 @@ use ferrumc_net::packets::outgoing::keep_alive::OutgoingKeepAlivePacket; use ferrumc_net::packets::outgoing::login_disconnect::LoginDisconnectPacket; use ferrumc_net::packets::outgoing::login_play::LoginPlayPacket; use ferrumc_net::packets::outgoing::login_success::LoginSuccessPacket; +use ferrumc_net::packets::outgoing::player_info_update::PlayerInfoUpdatePacket; use ferrumc_net::packets::outgoing::registry_data::get_registry_packets; use ferrumc_net::packets::outgoing::set_center_chunk::SetCenterChunk; use ferrumc_net::packets::outgoing::set_default_spawn_position::SetDefaultSpawnPositionPacket; use ferrumc_net::packets::outgoing::set_render_distance::SetRenderDistance; +use ferrumc_net::packets::outgoing::spawn_entity::SpawnEntityPacket; use ferrumc_net::packets::outgoing::synchronize_player_position::SynchronizePlayerPositionPacket; +use ferrumc_net::utils::broadcast::{broadcast, get_all_play_players, BroadcastOptions}; +use ferrumc_net::NetResult; use ferrumc_net_codec::encode::NetEncodeOpts; use ferrumc_state::GlobalState; +use futures::StreamExt; +use std::time::Instant; use tracing::{debug, trace}; #[event_handler] @@ -47,7 +54,7 @@ async fn handle_login_start( login_start_event.conn_id, PlayerIdentity::new(username.to_string(), uuid), )? - .add_component::(login_start_event.conn_id, ChunkReceiver::default())?; + /*.add_component::(login_start_event.conn_id, ChunkReceiver::default())?*/; //Send a Login Success Response to further the login sequence let mut writer = state @@ -146,70 +153,74 @@ async fn handle_ack_finish_configuration( state: GlobalState, ) -> Result { trace!("Handling Ack Finish Configuration event"); + let entity_id = ack_finish_configuration_event.conn_id; + { + let mut conn_state = state.universe.get_mut::(entity_id)?; + + *conn_state = ConnectionState::Play; + + // add components to the entity after the connection state has been set to play. + // to avoid wasting resources on entities that are fetching stuff like server status etc. + state + .universe + .add_component::(entity_id, Position::default())? + .add_component::(entity_id, Rotation::default())? + .add_component::(entity_id, OnGround::default())? + .add_component::(entity_id, ChunkReceiver::default())? + .add_component::(entity_id, PlayerInventory::default())?; + + let mut writer = state.universe.get_mut::(entity_id)?; + + writer // 21 + .send_packet(&LoginPlayPacket::new(entity_id), &NetEncodeOpts::WithLength) + .await?; + writer // 29 + .send_packet( + &SynchronizePlayerPositionPacket::default(), // The coordinates here should be used for the center chunk. + &NetEncodeOpts::WithLength, + ) + .await?; + writer // 37 + .send_packet( + &SetDefaultSpawnPositionPacket::default(), // Player specific, aka. home, bed, where it would respawn. + &NetEncodeOpts::WithLength, + ) + .await?; + writer // 38 + .send_packet( + &GameEventPacket::start_waiting_for_level_chunks(), + &NetEncodeOpts::WithLength, + ) + .await?; + writer // 41 + .send_packet( + &SetCenterChunk::new(0, 0), // TODO - Dependent on the player spawn position. + &NetEncodeOpts::WithLength, + ) + .await?; + writer // other + .send_packet( + &SetRenderDistance::new(5), // TODO + &NetEncodeOpts::WithLength, + ) + .await?; + + send_keep_alive(entity_id, &state, &mut writer).await?; + + let pos = state.universe.get_mut::(entity_id)?; + let mut chunk_recv = state.universe.get_mut::(entity_id)?; + chunk_recv.last_chunk = Some((pos.x as i32, pos.z as i32, String::from("overworld"))); + chunk_recv.calculate_chunks().await; + } - let conn_id = ack_finish_configuration_event.conn_id; - - let mut conn_state = state.universe.get_mut::(conn_id)?; - - *conn_state = ConnectionState::Play; - - // add components to the entity after the connection state has been set to play. - // to avoid wasting resources on entities that are fetching stuff like server status etc. - state - .universe - .add_component::(conn_id, Position::default())? - .add_component::(conn_id, Rotation::default())? - .add_component::(conn_id, OnGround::default())? - .add_component::(conn_id, PlayerInventory::default())?; - - let mut writer = state.universe.get_mut::(conn_id)?; - - writer // 21 - .send_packet(&LoginPlayPacket::new(conn_id), &NetEncodeOpts::WithLength) - .await?; - writer // 29 - .send_packet( - &SynchronizePlayerPositionPacket::default(), // The coordinates here should be used for the center chunk. - &NetEncodeOpts::WithLength, - ) - .await?; - writer // 37 - .send_packet( - &SetDefaultSpawnPositionPacket::default(), // Player specific, aka. home, bed, where it would respawn. - &NetEncodeOpts::WithLength, - ) - .await?; - writer // 38 - .send_packet( - &GameEventPacket::start_waiting_for_level_chunks(), - &NetEncodeOpts::WithLength, - ) - .await?; - writer // 41 - .send_packet( - &SetCenterChunk::new(0, 0), // TODO - Dependent on the player spawn position. - &NetEncodeOpts::WithLength, - ) - .await?; - writer // other - .send_packet( - &SetRenderDistance::new(5), // TODO - &NetEncodeOpts::WithLength, - ) - .await?; - - let pos = state.universe.get_mut::(conn_id)?; - let mut chunk_recv = state.universe.get_mut::(conn_id)?; - chunk_recv.last_chunk = Some((pos.x as i32, pos.z as i32, String::from("overworld"))); - chunk_recv.calculate_chunks().await; - - send_keep_alive(conn_id, state, &mut writer).await?; + player_info_update_packets(entity_id, &state).await?; + broadcast_spawn_entity_packet(entity_id, &state).await?; Ok(ack_finish_configuration_event) } async fn send_keep_alive( conn_id: usize, - state: GlobalState, + state: &GlobalState, writer: &mut ComponentRefMut<'_, StreamWriter>, ) -> Result<(), NetError> { let keep_alive_packet = OutgoingKeepAlivePacket::default(); @@ -228,3 +239,63 @@ async fn send_keep_alive( Ok(()) } + +async fn player_info_update_packets(entity_id: Entity, state: &GlobalState) -> NetResult<()> { + // Broadcasts a player info update packet to all players. + { + let packet = PlayerInfoUpdatePacket::new_player_join_packet(entity_id, state); + + let start = Instant::now(); + broadcast( + &packet, + state, + BroadcastOptions::default().except([entity_id]), + ) + .await?; + trace!( + "Broadcasting player info update took: {:?}", + start.elapsed() + ); + } + + // Tell the player about all the other players that are already connected. + { + let packet = PlayerInfoUpdatePacket::existing_player_info_packet(entity_id, state); + + let start = Instant::now(); + let mut writer = state.universe.get_mut::(entity_id)?; + writer + .send_packet(&packet, &NetEncodeOpts::WithLength) + .await?; + debug!("Sending player info update took: {:?}", start.elapsed()); + } + + Ok(()) +} + +async fn broadcast_spawn_entity_packet(entity_id: Entity, state: &GlobalState) -> NetResult<()> { + let packet = SpawnEntityPacket::player(entity_id, state)?; + + let start = Instant::now(); + broadcast( + &packet, + state, + BroadcastOptions::default().except([entity_id]), + ) + .await?; + trace!("Broadcasting spawn entity took: {:?}", start.elapsed()); + + let writer = state.universe.get_mut::(entity_id)?; + futures::stream::iter(get_all_play_players(state)) + .fold(writer, |mut writer, entity| async move { + if let Ok(packet) = SpawnEntityPacket::player(entity, state) { + let _ = writer + .send_packet(&packet, &NetEncodeOpts::WithLength) + .await; + } + writer + }) + .await; + + Ok(()) +} From 70f9cde62b92f837ebc107ea6fa2fda5169ed196 Mon Sep 17 00:00:00 2001 From: Outspending Date: Sun, 5 Jan 2025 14:13:11 -0700 Subject: [PATCH 34/38] Stuff --- src/bin/src/packet_handlers/containers.rs | 14 ++ src/lib/derive_macros/src/inventory/mod.rs | 106 +++++++----- src/lib/derive_macros/src/lib.rs | 7 +- src/lib/inventory/src/contents.rs | 8 +- src/lib/inventory/src/inventory.rs | 38 +++-- src/lib/inventory/src/slot.rs | 12 ++ src/lib/inventory/src/types/anvil.rs | 10 +- src/lib/inventory/src/types/beacon.rs | 6 +- src/lib/inventory/src/types/cartography.rs | 6 +- src/lib/inventory/src/types/enchanting.rs | 6 +- src/lib/inventory/src/types/furnace.rs | 14 +- src/lib/inventory/src/types/grindstone.rs | 6 +- src/lib/inventory/src/types/loom.rs | 4 +- src/lib/inventory/src/types/smithing_table.rs | 6 +- src/lib/inventory/src/types/stonecutter.rs | 6 +- .../packets/outgoing/player_info_update.rs | 4 + .../outgoing/set_container_property.rs | 159 +++++++++++++++++- .../net/src/packets/outgoing/set_equipment.rs | 15 ++ 18 files changed, 331 insertions(+), 96 deletions(-) diff --git a/src/bin/src/packet_handlers/containers.rs b/src/bin/src/packet_handlers/containers.rs index 711dc10f..84bdbcc4 100644 --- a/src/bin/src/packet_handlers/containers.rs +++ b/src/bin/src/packet_handlers/containers.rs @@ -7,6 +7,8 @@ use ferrumc_net::packets::incoming::click_container::InventoryClickEvent; use ferrumc_net::packets::incoming::close_container::InventoryCloseEvent; use ferrumc_net::packets::incoming::set_creative_mode_slot::SetCreativeModeSlotEvent; use ferrumc_net::packets::incoming::set_held_item::ChangeSlotEvent; +use ferrumc_net::packets::outgoing::set_equipment::{Equipment, EquipmentSlot, SetEquipmentPacket}; +use ferrumc_net::utils::broadcast::{broadcast, BroadcastOptions}; use ferrumc_state::GlobalState; #[event_handler] @@ -93,5 +95,17 @@ async fn handle_carried_item( let mut inventory = state.universe.get_mut::(conn_id)?; inventory.set_carried_item(change_slot_event.slot); + let equipment = Equipment::new( + EquipmentSlot::MainHand, + Slot::with_item(change_slot_event.slot as i32).to_network_slot(), + ); + + broadcast( + &SetEquipmentPacket::new(conn_id, vec![equipment]), + &state, + BroadcastOptions::default().except([conn_id]), + ) + .await?; + Ok(change_slot_event) } diff --git a/src/lib/derive_macros/src/inventory/mod.rs b/src/lib/derive_macros/src/inventory/mod.rs index aff230ea..7ed5c8e3 100644 --- a/src/lib/derive_macros/src/inventory/mod.rs +++ b/src/lib/derive_macros/src/inventory/mod.rs @@ -23,25 +23,46 @@ pub fn create(input: TokenStream) -> TokenStream { } }; - let mut inventory_type_expr: Option = None; + let mut inventory_type_creator = quote! {}; // Extract inventory_type attribute for attr in &input.attrs { - if attr.path().is_ident("inventory_type") { + if attr.path().is_ident("inventory") { attr.parse_nested_meta(|meta| { if let Some(ident) = meta.path.get_ident() { - if ident.to_string().as_str() == "value" { - let value = meta.value().expect("Missing value for inventory_type"); - - let value = value - .parse::() - .expect("Failed to parse value in inventory_type"); - inventory_type_expr = Some(value); + let ident_str = ident.to_string(); + let ident_str_ident = syn::Ident::new(&ident_str, proc_macro2::Span::call_site()); + match ident_str.as_str() { + "inventory_type" => { + if let Some(ident) = handle_meta("inventory_type", &meta, true) { + inventory_type_creator = quote! { + #inventory_type_creator + .#ident_str_ident(#net_crate::inventory::InventoryType::#ident) + }; + } + }, + "is_synced" => { + if let Some(expr) = handle_meta("is_synced", &meta, false) { + inventory_type_creator = quote! { + #inventory_type_creator + .#ident_str_ident(#expr) + }; + } + }, + "title" => { + if let Some(expr) = handle_meta("title", &meta, false) { + inventory_type_creator = quote! { + #inventory_type_creator + .#ident_str_ident(ferrumc_text::TextComponent::new(#expr).build()) + }; + } + } + _ => {}, } } Ok(()) }) - .unwrap(); + .unwrap(); } } @@ -58,25 +79,13 @@ pub fn create(input: TokenStream) -> TokenStream { if attr.path().is_ident("slot") { attr.parse_nested_meta(|meta| { if let Some(ident) = meta.path.get_ident() { - match ident.to_string().as_str() { + let ident_str = ident.to_string(); + match ident_str.as_str() { "id" => { - let value = meta.value().expect("Missing value for slot"); - - let value = value - .parse::() - .expect("Failed to parse value in slot"); - - id_expr = Some(value); + id_expr = handle_meta("id", &meta, true); } "default_value" => { - let value = - meta.value().expect("Missing default_value for slot"); - - let value = value - .parse::() - .expect("Failed to parse default_value in slot"); - - value_expr = Some(value); + value_expr = handle_meta("default_value", &meta, true); } _ => {} } @@ -106,18 +115,16 @@ pub fn create(input: TokenStream) -> TokenStream { } // Generate the `new` method - let new_method = inventory_type_expr.map(|expr| { - quote! { - pub fn new(id: u8) -> Self { - Self { - inventory: #net_crate::builder::InventoryBuilder::new(id) - .inventory_type(#net_crate::inventory::InventoryType::#expr) - .build(), - #(#default_statements)* - } + let new_method = quote! { + pub fn new(id: u8) -> Self { + Self { + inventory: #net_crate::builder::InventoryBuilder::new(id) + #inventory_type_creator + .build(), + #(#default_statements)* } } - }); + }; // Generate the complete implementation block // Wacky ass code because rust is retarded @@ -149,10 +156,31 @@ pub fn create(input: TokenStream) -> TokenStream { } } -pub fn inventory_type(_args: TokenStream, input: TokenStream) -> TokenStream { - input +fn handle_meta( + name: &str, + meta: &syn::meta::ParseNestedMeta, + is_required: bool, +) -> Option { + match meta.value() { + Ok(value) => { + if let Ok(value) = value.parse::() { + Some(value) + } else if is_required { + panic!("Failed to parse value for attribute '{}'", name); + } else { + None + } + } + Err(_) => { + if is_required { + panic!("Missing required attribute '{}'", name); + } + + None + } + } } -pub fn slot(_args: TokenStream, input: TokenStream) -> TokenStream { +pub fn inventory_type(_args: TokenStream, input: TokenStream) -> TokenStream { input } diff --git a/src/lib/derive_macros/src/lib.rs b/src/lib/derive_macros/src/lib.rs index 5ede0f20..20198000 100644 --- a/src/lib/derive_macros/src/lib.rs +++ b/src/lib/derive_macros/src/lib.rs @@ -84,12 +84,7 @@ pub fn create_inventory(input: TokenStream) -> TokenStream { } #[proc_macro_attribute] -pub fn slot(args: TokenStream, input: TokenStream) -> TokenStream { - inventory::slot(args, input) -} - -#[proc_macro_attribute] -pub fn inventory_type(args: TokenStream, input: TokenStream) -> TokenStream { +pub fn inventory(args: TokenStream, input: TokenStream) -> TokenStream { inventory::inventory_type(args, input) } // #=================== INVENTORY ===================# diff --git a/src/lib/inventory/src/contents.rs b/src/lib/inventory/src/contents.rs index a489d013..0fc385fd 100644 --- a/src/lib/inventory/src/contents.rs +++ b/src/lib/inventory/src/contents.rs @@ -20,14 +20,14 @@ impl InventoryContents { Self { contents, size } } - pub fn fill(&mut self, slot: Slot) { + pub fn fill + Copy>(&mut self, slot: S) { for i in 0..self.size { - self.contents.insert(i, slot); + self.contents.insert(i, slot.into()); } } - pub fn set_slot(&mut self, slot_id: i16, slot: Slot) -> &mut Self { - self.contents.insert(slot_id, slot); + pub fn set_slot>(&mut self, slot_id: i16, slot: S) -> &mut Self { + self.contents.insert(slot_id, slot.into()); self } diff --git a/src/lib/inventory/src/inventory.rs b/src/lib/inventory/src/inventory.rs index 42b58edf..39274ca5 100644 --- a/src/lib/inventory/src/inventory.rs +++ b/src/lib/inventory/src/inventory.rs @@ -11,6 +11,9 @@ use ferrumc_net::packets::incoming::close_container::InventoryCloseEvent; use ferrumc_net::packets::outgoing::close_container::CloseContainerPacket; use ferrumc_net::packets::outgoing::open_screen::{OpenInventoryEvent, OpenScreenPacket}; use ferrumc_net::packets::outgoing::set_container_content::SetContainerContentPacket; +use ferrumc_net::packets::outgoing::set_container_property::{ + ContainerProperty, SetContainerPropertyPacket, +}; use ferrumc_net::packets::outgoing::set_container_slot::SetContainerSlotPacket; use ferrumc_net_codec::encode::NetEncodeOpts; use ferrumc_net_codec::net_types::var_int::VarInt; @@ -122,7 +125,24 @@ impl Inventory { self.carried_item = slot; } - pub(crate) async fn send_inventory_slot_content( + pub async fn send_inventory_properties( + &self, + properties: Vec, + mut writer: ComponentRefMut<'_, StreamWriter>, + ) -> Result<(), InventoryError> { + for property in properties { + writer + .send_packet( + &SetContainerPropertyPacket::new(self.id, property), + &NetEncodeOpts::WithLength, + ) + .await?; + } + + Ok(()) + } + + pub async fn send_inventory_slot_content( &self, slot_num: i16, mut writer: ComponentRefMut<'_, StreamWriter>, @@ -145,7 +165,7 @@ impl Inventory { Ok(()) } - pub(crate) async fn send_inventory_content( + pub async fn send_inventory_content( &self, mut writer: ComponentRefMut<'_, StreamWriter>, ) -> Result<(), InventoryError> { @@ -212,7 +232,7 @@ impl Inventory { } pub async fn add_viewer( - self, + &self, state: Arc, entity_id: Entity, ) -> Result<(), InventoryError> { @@ -236,7 +256,7 @@ impl Inventory { let event = OpenInventoryEvent::new(entity_id, self.id); OpenInventoryEvent::trigger(event, state.clone()).await?; - universe.add_component::(entity_id, self)?; + universe.add_component::(entity_id, self.clone())?; Ok(()) } @@ -262,7 +282,7 @@ impl Inventory { Ok(()) } - pub fn set_slot(&mut self, slot_id: i16, slot: Slot) -> &mut Self { + pub fn set_slot + Copy>(&mut self, slot_id: i16, slot: S) -> &mut Self { let size = self.inventory_type.get_size(); if (0..=size).contains(&slot_id) { self.contents.set_slot(slot_id, slot); @@ -271,7 +291,7 @@ impl Inventory { self } - pub fn set_slots(&mut self, slots: Vec<(i16, Slot)>) -> &mut Self { + pub fn set_slots + Copy>(&mut self, slots: Vec<(i16, S)>) -> &mut Self { for (slot_num, slot) in slots { self.set_slot(slot_num, slot); } @@ -300,10 +320,8 @@ impl Inventory { self.get_contents_mut().clear(); } - pub fn fill(&mut self, slot: Slot) { - for i in 0..self.get_size() { - self.set_slot(i, slot); - } + pub fn fill + Copy>(&mut self, slot: S) { + self.contents.fill(slot); } pub fn contains(&self, item: i32) -> bool { diff --git a/src/lib/inventory/src/slot.rs b/src/lib/inventory/src/slot.rs index f5f736ff..2ae501be 100644 --- a/src/lib/inventory/src/slot.rs +++ b/src/lib/inventory/src/slot.rs @@ -12,6 +12,18 @@ impl Default for Slot { } } +impl From for Slot { + fn from(value: i32) -> Self { + Self::with_item(value) + } +} + +impl From<(i32, i32)> for Slot { + fn from(value: (i32, i32)) -> Self { + Self::new(value.0, value.1) + } +} + impl Slot { pub fn new(count: i32, item: i32) -> Self { Self { count, item } diff --git a/src/lib/inventory/src/types/anvil.rs b/src/lib/inventory/src/types/anvil.rs index 9f06b68d..b9641e18 100644 --- a/src/lib/inventory/src/types/anvil.rs +++ b/src/lib/inventory/src/types/anvil.rs @@ -1,11 +1,9 @@ -#![warn(dead_code)] - use crate::inventory::Inventory; -use ferrumc_macros::{Inventory, inventory_type}; +use ferrumc_macros::{Inventory, inventory}; -#[derive(Inventory, Debug)] -#[inventory_type(value = Anvil)] -pub struct EnchantingInventory { +#[derive(Inventory, Debug, Clone)] +#[inventory(inventory_type = Anvil)] +pub struct AnvilInventory { inventory: Inventory, #[slot(id = 0, default_value = 0)] pub first: i32, diff --git a/src/lib/inventory/src/types/beacon.rs b/src/lib/inventory/src/types/beacon.rs index b454af78..2a01f655 100644 --- a/src/lib/inventory/src/types/beacon.rs +++ b/src/lib/inventory/src/types/beacon.rs @@ -1,11 +1,11 @@ #![warn(dead_code)] -use ferrumc_macros::{Inventory, inventory_type}; +use ferrumc_macros::{Inventory, inventory}; use crate::inventory::Inventory; -#[derive(Inventory, Debug)] -#[inventory_type(value = Beacon)] +#[derive(Inventory, Debug, Clone)] +#[inventory(inventory_type = Beacon)] pub struct BeaconInventory { inventory: Inventory, #[slot(id = 0, default_value = 0)] diff --git a/src/lib/inventory/src/types/cartography.rs b/src/lib/inventory/src/types/cartography.rs index f4467a2e..71ee6c62 100644 --- a/src/lib/inventory/src/types/cartography.rs +++ b/src/lib/inventory/src/types/cartography.rs @@ -1,9 +1,9 @@ #![warn(dead_code)] use crate::inventory::Inventory; -use ferrumc_macros::{Inventory, inventory_type}; +use ferrumc_macros::{Inventory, inventory}; -#[derive(Inventory, Debug)] -#[inventory_type(value = Cartography)] +#[derive(Inventory, Debug, Clone)] +#[inventory(inventory_type = Cartography)] pub struct EnchantingInventory { inventory: Inventory, #[slot(id = 0, default_value = 0)] diff --git a/src/lib/inventory/src/types/enchanting.rs b/src/lib/inventory/src/types/enchanting.rs index 89cc8530..ad7cb6e4 100644 --- a/src/lib/inventory/src/types/enchanting.rs +++ b/src/lib/inventory/src/types/enchanting.rs @@ -1,11 +1,11 @@ #![warn(dead_code)] -use ferrumc_macros::{Inventory, inventory_type}; +use ferrumc_macros::{Inventory, inventory}; use crate::inventory::Inventory; -#[derive(Inventory, Debug)] -#[inventory_type(value = EnchantmentTable)] +#[derive(Inventory, Debug, Clone)] +#[inventory(inventory_type = EnchantmentTable)] pub struct EnchantingInventory { inventory: Inventory, #[slot(id = 0, default_value = 0)] diff --git a/src/lib/inventory/src/types/furnace.rs b/src/lib/inventory/src/types/furnace.rs index 24caf8e2..3ef6ccfe 100644 --- a/src/lib/inventory/src/types/furnace.rs +++ b/src/lib/inventory/src/types/furnace.rs @@ -1,10 +1,10 @@ #![warn(dead_code)] use crate::inventory::Inventory; -use ferrumc_macros::{Inventory, inventory_type}; +use ferrumc_macros::{Inventory, inventory}; -#[derive(Inventory, Debug)] -#[inventory_type(value = Furnace)] +#[derive(Inventory, Debug, Clone)] +#[inventory(inventory_type = Furnace)] pub struct FurnaceInventory { inventory: Inventory, #[slot(id = 0, default_value = 0)] @@ -15,8 +15,8 @@ pub struct FurnaceInventory { pub output: i32, } -#[derive(Inventory, Debug)] -#[inventory_type(value = BlastFurnace)] +#[derive(Inventory, Debug, Clone)] +#[inventory(inventory_type = BlastFurnace)] pub struct BlastFurnaceInventory { inventory: Inventory, #[slot(id = 0, default_value = 0)] @@ -27,8 +27,8 @@ pub struct BlastFurnaceInventory { pub output: i32, } -#[derive(Inventory, Debug)] -#[inventory_type(value = Smoker)] +#[derive(Inventory, Debug, Clone)] +#[inventory(inventory_type = Smoker)] pub struct SmokerInventory { inventory: Inventory, #[slot(id = 0, default_value = 0)] diff --git a/src/lib/inventory/src/types/grindstone.rs b/src/lib/inventory/src/types/grindstone.rs index 05dc03b2..5f7f527e 100644 --- a/src/lib/inventory/src/types/grindstone.rs +++ b/src/lib/inventory/src/types/grindstone.rs @@ -1,10 +1,10 @@ #![warn(dead_code)] use crate::inventory::Inventory; -use ferrumc_macros::{Inventory, inventory_type}; +use ferrumc_macros::{Inventory, inventory}; -#[derive(Inventory, Debug)] -#[inventory_type(value = Grindstone)] +#[derive(Inventory, Debug, Clone)] +#[inventory(inventory_type = Grindstone)] pub struct GrindstoneInventory { inventory: Inventory, #[slot(id = 0, default_value = 0)] diff --git a/src/lib/inventory/src/types/loom.rs b/src/lib/inventory/src/types/loom.rs index 80aa6879..736ba320 100644 --- a/src/lib/inventory/src/types/loom.rs +++ b/src/lib/inventory/src/types/loom.rs @@ -1,10 +1,10 @@ #![warn(dead_code)] use crate::inventory::Inventory; -use ferrumc_macros::{Inventory, inventory_type}; +use ferrumc_macros::{Inventory, inventory}; #[derive(Inventory, Debug)] -#[inventory_type(value = Loom)] +#[inventory(inventory_type = Loom)] pub struct LoomInventory { inventory: Inventory, #[slot(id = 0, default_value = 0)] diff --git a/src/lib/inventory/src/types/smithing_table.rs b/src/lib/inventory/src/types/smithing_table.rs index 631f2d07..194d2cd3 100644 --- a/src/lib/inventory/src/types/smithing_table.rs +++ b/src/lib/inventory/src/types/smithing_table.rs @@ -1,10 +1,10 @@ #![warn(dead_code)] use crate::inventory::Inventory; -use ferrumc_macros::{Inventory, inventory_type}; +use ferrumc_macros::{Inventory, inventory}; -#[derive(Inventory, Debug)] -#[inventory_type(value = SmithingTable)] +#[derive(Inventory, Debug, Clone)] +#[inventory(inventory_type = SmithingTable)] pub struct SmithingTableInventory { inventory: Inventory, #[slot(id = 0, default_value = 0)] diff --git a/src/lib/inventory/src/types/stonecutter.rs b/src/lib/inventory/src/types/stonecutter.rs index 571e5cfc..dd39d4ae 100644 --- a/src/lib/inventory/src/types/stonecutter.rs +++ b/src/lib/inventory/src/types/stonecutter.rs @@ -1,10 +1,10 @@ #![warn(dead_code)] use crate::inventory::Inventory; -use ferrumc_macros::{Inventory, inventory_type}; +use ferrumc_macros::{Inventory, inventory}; -#[derive(Inventory, Debug)] -#[inventory_type(value = Stonecutter)] +#[derive(Inventory, Debug, Clone)] +#[inventory(inventory_type = Stonecutter)] pub struct StoneCutterInventory { inventory: Inventory, #[slot(id = 0, default_value = 0)] diff --git a/src/lib/net/src/packets/outgoing/player_info_update.rs b/src/lib/net/src/packets/outgoing/player_info_update.rs index 65f6e9db..80d2d88e 100644 --- a/src/lib/net/src/packets/outgoing/player_info_update.rs +++ b/src/lib/net/src/packets/outgoing/player_info_update.rs @@ -91,6 +91,7 @@ impl PlayerWithActions { for action in &self.actions { mask |= match action { PlayerAction::AddPlayer { .. } => 0x01, + PlayerAction::UpdateListed { .. } => 0x08, } } mask @@ -113,6 +114,9 @@ pub enum PlayerAction { name: String, properties: LengthPrefixedVec, }, + UpdateListed { + listed: bool, + }, } #[derive(NetEncode, Debug)] diff --git a/src/lib/net/src/packets/outgoing/set_container_property.rs b/src/lib/net/src/packets/outgoing/set_container_property.rs index 9129dadd..51e701d6 100644 --- a/src/lib/net/src/packets/outgoing/set_container_property.rs +++ b/src/lib/net/src/packets/outgoing/set_container_property.rs @@ -1,20 +1,171 @@ use ferrumc_macros::{packet, NetEncode}; +use ferrumc_net_codec::encode::{NetEncode, NetEncodeOpts, NetEncodeResult}; use std::io::Write; +use tokio::io::AsyncWrite; + +#[derive(Debug, Copy, Clone)] +pub enum ContainerProperty { + // Furnace + FurnaceFireIcon(u16), + FurnaceMaxFuelTime(u16), + FurnaceProgressArrow(u16), + FurnaceMaxProgress(u16), + + // Enchantment + EnchantmentLevelTop(u16), + EnchantmentLevelMiddle(u16), + EnchantmentLevelBottom(u16), + EnchantmentSeed(u16), + EnchantmentIdTop(u16), + EnchantmentIdMiddle(u16), + EnchantmentIdBottom(u16), + EnchantmentLevelIdTop(u16), + EnchantmentLevelIdMiddle(u16), + EnchantmentLevelIdBottom(u16), + + // Beacon + BeaconPowerLevel(u16), + BeaconFirstPotionEffect(u16), + BeaconSecondPotionEffect(u16), + + // Anvil + AnvilRepairCost(u16), + + // Brewing Stand + BrewingStandBrewTime(u16), + BrewingStandFuelTime(u16), + + // Stonecutter + StonecutterSelectedRecipe(u16), + + // Loom + LoomSelectedPattern(u16), + + // Lectern + LecternPageNumber(u16), +} + +impl ContainerProperty { + pub fn get_property_id(&self) -> u16 { + match self { + // Furnace + ContainerProperty::FurnaceFireIcon(_) => 0, + ContainerProperty::FurnaceMaxFuelTime(_) => 1, + ContainerProperty::FurnaceProgressArrow(_) => 2, + ContainerProperty::FurnaceMaxProgress(_) => 3, + + // Enchantment Table + ContainerProperty::EnchantmentLevelTop(_) => 0, + ContainerProperty::EnchantmentLevelMiddle(_) => 1, + ContainerProperty::EnchantmentLevelBottom(_) => 2, + ContainerProperty::EnchantmentSeed(_) => 3, + ContainerProperty::EnchantmentIdTop(_) => 4, + ContainerProperty::EnchantmentIdMiddle(_) => 5, + ContainerProperty::EnchantmentIdBottom(_) => 6, + ContainerProperty::EnchantmentLevelIdTop(_) => 7, + ContainerProperty::EnchantmentLevelIdMiddle(_) => 8, + ContainerProperty::EnchantmentLevelIdBottom(_) => 9, + + // Beacon + ContainerProperty::BeaconPowerLevel(_) => 0, + ContainerProperty::BeaconFirstPotionEffect(_) => 1, + ContainerProperty::BeaconSecondPotionEffect(_) => 2, + + // Anvil + ContainerProperty::AnvilRepairCost(_) => 0, + + // Brewing Stand + ContainerProperty::BrewingStandBrewTime(_) => 0, + ContainerProperty::BrewingStandFuelTime(_) => 1, + + // Stonecutter + ContainerProperty::StonecutterSelectedRecipe(_) => 0, + + // Loom + ContainerProperty::LoomSelectedPattern(_) => 0, + + // Lectern + ContainerProperty::LecternPageNumber(_) => 0, + } + } +} + +impl NetEncode for ContainerProperty { + fn encode(&self, writer: &mut W, opts: &NetEncodeOpts) -> NetEncodeResult<()> { + self.get_property_id().encode(writer, opts)?; + match self { + Self::FurnaceFireIcon(value) + | Self::FurnaceMaxFuelTime(value) + | Self::FurnaceProgressArrow(value) + | Self::FurnaceMaxProgress(value) + | Self::EnchantmentLevelTop(value) + | Self::EnchantmentLevelMiddle(value) + | Self::EnchantmentLevelBottom(value) + | Self::EnchantmentSeed(value) + | Self::EnchantmentIdTop(value) + | Self::EnchantmentIdMiddle(value) + | Self::EnchantmentIdBottom(value) + | Self::EnchantmentLevelIdTop(value) + | Self::EnchantmentLevelIdMiddle(value) + | Self::EnchantmentLevelIdBottom(value) + | Self::BeaconPowerLevel(value) + | Self::BeaconFirstPotionEffect(value) + | Self::BeaconSecondPotionEffect(value) + | Self::AnvilRepairCost(value) + | Self::BrewingStandBrewTime(value) + | Self::BrewingStandFuelTime(value) + | Self::StonecutterSelectedRecipe(value) + | Self::LoomSelectedPattern(value) + | Self::LecternPageNumber(value) => value.encode(writer, opts), + } + } + + async fn encode_async( + &self, + writer: &mut W, + opts: &NetEncodeOpts, + ) -> NetEncodeResult<()> { + self.get_property_id().encode_async(writer, opts).await?; + match self { + Self::FurnaceFireIcon(value) + | Self::FurnaceMaxFuelTime(value) + | Self::FurnaceProgressArrow(value) + | Self::FurnaceMaxProgress(value) + | Self::EnchantmentLevelTop(value) + | Self::EnchantmentLevelMiddle(value) + | Self::EnchantmentLevelBottom(value) + | Self::EnchantmentSeed(value) + | Self::EnchantmentIdTop(value) + | Self::EnchantmentIdMiddle(value) + | Self::EnchantmentIdBottom(value) + | Self::EnchantmentLevelIdTop(value) + | Self::EnchantmentLevelIdMiddle(value) + | Self::EnchantmentLevelIdBottom(value) + | Self::BeaconPowerLevel(value) + | Self::BeaconFirstPotionEffect(value) + | Self::BeaconSecondPotionEffect(value) + | Self::AnvilRepairCost(value) + | Self::BrewingStandBrewTime(value) + | Self::BrewingStandFuelTime(value) + | Self::StonecutterSelectedRecipe(value) + | Self::LoomSelectedPattern(value) + | Self::LecternPageNumber(value) => value.encode_async(writer, opts).await, + } + } +} #[derive(NetEncode)] #[packet(packet_id = "container_set_data", state_id = "play")] pub struct SetContainerPropertyPacket { pub window_id: u8, - pub property: u16, - pub value: u16, + pub property: ContainerProperty, } impl SetContainerPropertyPacket { - pub fn new(window_id: u8, property: u16, value: u16) -> Self { + pub fn new(window_id: u8, property: ContainerProperty) -> Self { Self { window_id, property, - value, } } } diff --git a/src/lib/net/src/packets/outgoing/set_equipment.rs b/src/lib/net/src/packets/outgoing/set_equipment.rs index 48601123..34ef7740 100644 --- a/src/lib/net/src/packets/outgoing/set_equipment.rs +++ b/src/lib/net/src/packets/outgoing/set_equipment.rs @@ -52,9 +52,24 @@ pub struct Equipment { pub slot: NetworkSlot, } +impl Equipment { + pub fn new(equipment: EquipmentSlot, slot: NetworkSlot) -> Self { + Self { equipment, slot } + } +} + #[derive(NetEncode)] #[packet(packet_id = "set_equipment", state_id = "play")] pub struct SetEquipmentPacket { pub conn_id: VarInt, pub equipment: Vec, } + +impl SetEquipmentPacket { + pub fn new(conn_id: usize, equipment: Vec) -> Self { + Self { + conn_id: VarInt::new(conn_id as i32), + equipment, + } + } +} From 6c3a8ba1dff06063777f11790dc25af69fdc9f88 Mon Sep 17 00:00:00 2001 From: Outspending Date: Sun, 5 Jan 2025 16:27:03 -0700 Subject: [PATCH 35/38] All Inventory Types + Better Macro Support --- src/lib/derive_macros/src/inventory/mod.rs | 6 +- src/lib/inventory/src/contents.rs | 4 - src/lib/inventory/src/types/anvil.rs | 14 -- src/lib/inventory/src/types/beacon.rs | 13 -- src/lib/inventory/src/types/cartography.rs | 15 -- src/lib/inventory/src/types/enchanting.rs | 15 -- src/lib/inventory/src/types/furnace.rs | 40 ---- src/lib/inventory/src/types/grindstone.rs | 16 -- src/lib/inventory/src/types/loom.rs | 18 -- src/lib/inventory/src/types/mod.rs | 177 +++++++++++++++++- src/lib/inventory/src/types/smithing_table.rs | 18 -- src/lib/inventory/src/types/stonecutter.rs | 14 -- 12 files changed, 170 insertions(+), 180 deletions(-) delete mode 100644 src/lib/inventory/src/types/anvil.rs delete mode 100644 src/lib/inventory/src/types/beacon.rs delete mode 100644 src/lib/inventory/src/types/cartography.rs delete mode 100644 src/lib/inventory/src/types/enchanting.rs delete mode 100644 src/lib/inventory/src/types/furnace.rs delete mode 100644 src/lib/inventory/src/types/grindstone.rs delete mode 100644 src/lib/inventory/src/types/loom.rs delete mode 100644 src/lib/inventory/src/types/smithing_table.rs delete mode 100644 src/lib/inventory/src/types/stonecutter.rs diff --git a/src/lib/derive_macros/src/inventory/mod.rs b/src/lib/derive_macros/src/inventory/mod.rs index 7ed5c8e3..c5722bbf 100644 --- a/src/lib/derive_macros/src/inventory/mod.rs +++ b/src/lib/derive_macros/src/inventory/mod.rs @@ -106,9 +106,9 @@ pub fn create(input: TokenStream) -> TokenStream { let setter_name = syn::Ident::new(&format!("set_{}", field_name), field_name.span()); field_statements.push(quote! { - pub fn #setter_name(&mut self, #field_name: #field_ty) { - self.#field_name = #field_name; - self.set_slot(#id, #net_crate::slot::Slot::with_item(#field_name)); + pub fn #setter_name + Copy>(&mut self, #field_name: S) { + self.#field_name = #field_name.into(); + self.set_slot(#id, #field_name); } }); } diff --git a/src/lib/inventory/src/contents.rs b/src/lib/inventory/src/contents.rs index 0fc385fd..a9333d4c 100644 --- a/src/lib/inventory/src/contents.rs +++ b/src/lib/inventory/src/contents.rs @@ -43,8 +43,4 @@ impl InventoryContents { LengthPrefixedVec::new(contents) } - - //to store in chunk metadata: TAG 44: byte - //to show: starts at slot 0 ALWAYS - > 26/53 smalll/large. - //other inventories are to be implemented after. } diff --git a/src/lib/inventory/src/types/anvil.rs b/src/lib/inventory/src/types/anvil.rs deleted file mode 100644 index b9641e18..00000000 --- a/src/lib/inventory/src/types/anvil.rs +++ /dev/null @@ -1,14 +0,0 @@ -use crate::inventory::Inventory; -use ferrumc_macros::{Inventory, inventory}; - -#[derive(Inventory, Debug, Clone)] -#[inventory(inventory_type = Anvil)] -pub struct AnvilInventory { - inventory: Inventory, - #[slot(id = 0, default_value = 0)] - pub first: i32, - #[slot(id = 1, default_value = 0)] - pub second: i32, - #[slot(id = 2, default_value = 0)] - pub result: i32, -} diff --git a/src/lib/inventory/src/types/beacon.rs b/src/lib/inventory/src/types/beacon.rs deleted file mode 100644 index 2a01f655..00000000 --- a/src/lib/inventory/src/types/beacon.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![warn(dead_code)] - -use ferrumc_macros::{Inventory, inventory}; - -use crate::inventory::Inventory; - -#[derive(Inventory, Debug, Clone)] -#[inventory(inventory_type = Beacon)] -pub struct BeaconInventory { - inventory: Inventory, - #[slot(id = 0, default_value = 0)] - pub powered_item: i32, -} diff --git a/src/lib/inventory/src/types/cartography.rs b/src/lib/inventory/src/types/cartography.rs deleted file mode 100644 index 71ee6c62..00000000 --- a/src/lib/inventory/src/types/cartography.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![warn(dead_code)] -use crate::inventory::Inventory; -use ferrumc_macros::{Inventory, inventory}; - -#[derive(Inventory, Debug, Clone)] -#[inventory(inventory_type = Cartography)] -pub struct EnchantingInventory { - inventory: Inventory, - #[slot(id = 0, default_value = 0)] - pub map: i32, - #[slot(id = 1, default_value = 0)] - pub paper: i32, - #[slot(id = 2, default_value = 0)] - pub output: i32, -} diff --git a/src/lib/inventory/src/types/enchanting.rs b/src/lib/inventory/src/types/enchanting.rs deleted file mode 100644 index ad7cb6e4..00000000 --- a/src/lib/inventory/src/types/enchanting.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![warn(dead_code)] - -use ferrumc_macros::{Inventory, inventory}; - -use crate::inventory::Inventory; - -#[derive(Inventory, Debug, Clone)] -#[inventory(inventory_type = EnchantmentTable)] -pub struct EnchantingInventory { - inventory: Inventory, - #[slot(id = 0, default_value = 0)] - pub item: i32, - #[slot(id = 1, default_value = 0)] - pub secondary: i32, -} diff --git a/src/lib/inventory/src/types/furnace.rs b/src/lib/inventory/src/types/furnace.rs deleted file mode 100644 index 3ef6ccfe..00000000 --- a/src/lib/inventory/src/types/furnace.rs +++ /dev/null @@ -1,40 +0,0 @@ -#![warn(dead_code)] - -use crate::inventory::Inventory; -use ferrumc_macros::{Inventory, inventory}; - -#[derive(Inventory, Debug, Clone)] -#[inventory(inventory_type = Furnace)] -pub struct FurnaceInventory { - inventory: Inventory, - #[slot(id = 0, default_value = 0)] - pub ingredient: i32, - #[slot(id = 1, default_value = 0)] - pub fuel: i32, - #[slot(id = 2, default_value = 0)] - pub output: i32, -} - -#[derive(Inventory, Debug, Clone)] -#[inventory(inventory_type = BlastFurnace)] -pub struct BlastFurnaceInventory { - inventory: Inventory, - #[slot(id = 0, default_value = 0)] - pub ingredient: i32, - #[slot(id = 1, default_value = 0)] - pub fuel: i32, - #[slot(id = 2, default_value = 0)] - pub output: i32, -} - -#[derive(Inventory, Debug, Clone)] -#[inventory(inventory_type = Smoker)] -pub struct SmokerInventory { - inventory: Inventory, - #[slot(id = 0, default_value = 0)] - pub ingredient: i32, - #[slot(id = 1, default_value = 0)] - pub fuel: i32, - #[slot(id = 2, default_value = 0)] - pub output: i32, -} diff --git a/src/lib/inventory/src/types/grindstone.rs b/src/lib/inventory/src/types/grindstone.rs deleted file mode 100644 index 5f7f527e..00000000 --- a/src/lib/inventory/src/types/grindstone.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![warn(dead_code)] - -use crate::inventory::Inventory; -use ferrumc_macros::{Inventory, inventory}; - -#[derive(Inventory, Debug, Clone)] -#[inventory(inventory_type = Grindstone)] -pub struct GrindstoneInventory { - inventory: Inventory, - #[slot(id = 0, default_value = 0)] - pub first: i32, - #[slot(id = 1, default_value = 0)] - pub second: i32, - #[slot(id = 2, default_value = 0)] - pub result: i32, -} diff --git a/src/lib/inventory/src/types/loom.rs b/src/lib/inventory/src/types/loom.rs deleted file mode 100644 index 736ba320..00000000 --- a/src/lib/inventory/src/types/loom.rs +++ /dev/null @@ -1,18 +0,0 @@ -#![warn(dead_code)] - -use crate::inventory::Inventory; -use ferrumc_macros::{Inventory, inventory}; - -#[derive(Inventory, Debug)] -#[inventory(inventory_type = Loom)] -pub struct LoomInventory { - inventory: Inventory, - #[slot(id = 0, default_value = 0)] - pub banner: i32, - #[slot(id = 1, default_value = 0)] - pub dye: i32, - #[slot(id = 2, default_value = 0)] - pub pattern: i32, - #[slot(id = 3, default_value = 0)] - pub result: i32, -} diff --git a/src/lib/inventory/src/types/mod.rs b/src/lib/inventory/src/types/mod.rs index 6da5b7e2..372a21f8 100644 --- a/src/lib/inventory/src/types/mod.rs +++ b/src/lib/inventory/src/types/mod.rs @@ -1,10 +1,167 @@ -pub mod anvil; -pub mod beacon; -pub mod cartography; -pub mod enchanting; -pub mod furnace; -pub mod grindstone; -pub mod loom; -pub mod player; -pub mod smithing_table; -pub mod stonecutter; +use ferrumc_macros::{Inventory, inventory}; + +use crate::{inventory::Inventory, slot::Slot}; + +#[derive(Inventory, Debug, Clone)] +#[inventory(inventory_type = Anvil)] +pub struct AnvilInventory { + inventory: Inventory, + #[slot(id = 0, default_value = Slot::empty())] + pub first: Slot, + #[slot(id = 1, default_value = Slot::empty())] + pub second: Slot, + #[slot(id = 2, default_value = Slot::empty())] + pub result: Slot, +} + +#[derive(Inventory, Debug, Clone)] +#[inventory(inventory_type = Beacon)] +pub struct BeaconInventory { + inventory: Inventory, + #[slot(id = 0, default_value = Slot::empty())] + pub powered_item: Slot, +} + +#[derive(Inventory, Debug, Clone)] +#[inventory(inventory_type = Cartography)] +pub struct EnchantingInventory { + inventory: Inventory, + #[slot(id = 0, default_value = Slot::empty())] + pub map: Slot, + #[slot(id = 1, default_value = Slot::empty())] + pub paper: Slot, + #[slot(id = 2, default_value = Slot::empty())] + pub output: Slot, +} + +#[derive(Inventory, Debug, Clone)] +#[inventory(inventory_type = Furnace)] +pub struct FurnaceInventory { + inventory: Inventory, + #[slot(id = 0, default_value = Slot::empty())] + pub ingredient: Slot, + #[slot(id = 1, default_value = Slot::empty())] + pub fuel: Slot, + #[slot(id = 2, default_value = Slot::empty())] + pub output: Slot, +} + +#[derive(Inventory, Debug, Clone)] +#[inventory(inventory_type = BlastFurnace)] +pub struct BlastFurnaceInventory { + inventory: Inventory, + #[slot(id = 0, default_value = Slot::empty())] + pub ingredient: Slot, + #[slot(id = 1, default_value = Slot::empty())] + pub fuel: Slot, + #[slot(id = 2, default_value = Slot::empty())] + pub output: Slot, +} + +#[derive(Inventory, Debug, Clone)] +#[inventory(inventory_type = Smoker)] +pub struct SmokerInventory { + inventory: Inventory, + #[slot(id = 0, default_value = Slot::empty())] + pub ingredient: Slot, + #[slot(id = 1, default_value = Slot::empty())] + pub fuel: Slot, + #[slot(id = 2, default_value = Slot::empty())] + pub output: Slot, +} + +#[derive(Inventory, Debug, Clone)] +#[inventory(inventory_type = Grindstone)] +pub struct GrindstoneInventory { + inventory: Inventory, + #[slot(id = 0, default_value = Slot::empty())] + pub first: Slot, + #[slot(id = 1, default_value = Slot::empty())] + pub second: Slot, + #[slot(id = 2, default_value = Slot::empty())] + pub result: Slot, +} + +#[derive(Inventory, Debug)] +#[inventory(inventory_type = Loom)] +pub struct LoomInventory { + inventory: Inventory, + #[slot(id = 0, default_value = Slot::empty())] + pub banner: Slot, + #[slot(id = 1, default_value = Slot::empty())] + pub dye: Slot, + #[slot(id = 2, default_value = Slot::empty())] + pub pattern: Slot, + #[slot(id = 3, default_value = Slot::empty())] + pub result: Slot, +} + +#[derive(Inventory, Debug, Clone)] +#[inventory(inventory_type = SmithingTable)] +pub struct SmithingTableInventory { + inventory: Inventory, + #[slot(id = 0, default_value = Slot::empty())] + pub template: Slot, + #[slot(id = 1, default_value = Slot::empty())] + pub base: Slot, + #[slot(id = 2, default_value = Slot::empty())] + pub additional: Slot, + #[slot(id = 3, default_value = Slot::empty())] + pub result: Slot, +} + +#[derive(Inventory, Debug, Clone)] +#[inventory(inventory_type = Stonecutter)] +pub struct StoneCutterInventory { + inventory: Inventory, + #[slot(id = 0, default_value = Slot::empty())] + pub input: Slot, + #[slot(id = 1, default_value = Slot::empty())] + pub result: Slot, +} + +#[derive(Inventory, Debug, Clone)] +#[inventory(inventory_type = BrewingStand)] +pub struct BrewingStandInventory { + inventory: Inventory, + #[slot(id = 3, default_value = Slot::empty())] + pub potion_ingredient: Slot, + #[slot(id = 4, default_value = Slot::empty())] + pub blaze_powder: Slot, +} + +impl BrewingStandInventory { + pub fn set_potion_slot + Copy>(&mut self, index: i16, slot: S) { + if (0..=2).contains(&index) { + self.set_slot(index, slot); + } + } +} + +#[derive(Inventory, Debug, Clone)] +#[inventory(inventory_type = CraftingTable)] +pub struct CraftingTableInventory { + inventory: Inventory, + #[slot(id = 0, default_value = Slot::empty())] + pub output: Slot, +} + +impl CraftingTableInventory { + pub fn set_crafting_input + Copy>(&mut self, index: i16, slot: S) { + if (0..=8).contains(&index) { + self.set_slot(1 + index, slot); + } + } +} + +#[derive(Inventory, Debug, Clone)] +#[inventory(inventory_type = Hopper)] +pub struct HopperInventory { + inventory: Inventory, +} + +#[derive(Inventory, Debug, Clone)] +#[inventory(inventory_type = ShulkerBox)] +pub struct ShulkerBoxInventory { + inventory: Inventory, +} diff --git a/src/lib/inventory/src/types/smithing_table.rs b/src/lib/inventory/src/types/smithing_table.rs deleted file mode 100644 index 194d2cd3..00000000 --- a/src/lib/inventory/src/types/smithing_table.rs +++ /dev/null @@ -1,18 +0,0 @@ -#![warn(dead_code)] - -use crate::inventory::Inventory; -use ferrumc_macros::{Inventory, inventory}; - -#[derive(Inventory, Debug, Clone)] -#[inventory(inventory_type = SmithingTable)] -pub struct SmithingTableInventory { - inventory: Inventory, - #[slot(id = 0, default_value = 0)] - pub template: i32, - #[slot(id = 1, default_value = 0)] - pub base: i32, - #[slot(id = 2, default_value = 0)] - pub additional: i32, - #[slot(id = 3, default_value = 0)] - pub result: i32, -} diff --git a/src/lib/inventory/src/types/stonecutter.rs b/src/lib/inventory/src/types/stonecutter.rs deleted file mode 100644 index dd39d4ae..00000000 --- a/src/lib/inventory/src/types/stonecutter.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![warn(dead_code)] - -use crate::inventory::Inventory; -use ferrumc_macros::{Inventory, inventory}; - -#[derive(Inventory, Debug, Clone)] -#[inventory(inventory_type = Stonecutter)] -pub struct StoneCutterInventory { - inventory: Inventory, - #[slot(id = 0, default_value = 0)] - pub input: i32, - #[slot(id = 1, default_value = 0)] - pub result: i32, -} From c44ee956d59fedbac02db02eb95eb3dab5e43a6d Mon Sep 17 00:00:00 2001 From: Outspending Date: Sun, 5 Jan 2025 16:27:24 -0700 Subject: [PATCH 36/38] Update mod.rs --- src/lib/inventory/src/types/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/inventory/src/types/mod.rs b/src/lib/inventory/src/types/mod.rs index 372a21f8..fb15eb58 100644 --- a/src/lib/inventory/src/types/mod.rs +++ b/src/lib/inventory/src/types/mod.rs @@ -2,6 +2,8 @@ use ferrumc_macros::{Inventory, inventory}; use crate::{inventory::Inventory, slot::Slot}; +pub mod player; + #[derive(Inventory, Debug, Clone)] #[inventory(inventory_type = Anvil)] pub struct AnvilInventory { From 20ceb406953ae31f2989fa9d405700130f35717e Mon Sep 17 00:00:00 2001 From: Outspending Date: Sun, 5 Jan 2025 16:35:17 -0700 Subject: [PATCH 37/38] clippy fix --- src/lib/derive_macros/src/inventory/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/derive_macros/src/inventory/mod.rs b/src/lib/derive_macros/src/inventory/mod.rs index c5722bbf..b979679e 100644 --- a/src/lib/derive_macros/src/inventory/mod.rs +++ b/src/lib/derive_macros/src/inventory/mod.rs @@ -69,7 +69,6 @@ pub fn create(input: TokenStream) -> TokenStream { // Process fields for field in &data_struct.fields { let field_name = &field.ident.clone().expect("Missing field"); - let field_ty = &field.ty; let mut id_expr = None; let mut value_expr = None; From 2db43480bf84e62ab3b354aa6c197e2627093e6a Mon Sep 17 00:00:00 2001 From: Outspending Date: Sun, 5 Jan 2025 16:46:43 -0700 Subject: [PATCH 38/38] Components (ish) [Wont Compile] --- src/lib/net/src/slot.rs | 56 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 src/lib/net/src/slot.rs diff --git a/src/lib/net/src/slot.rs b/src/lib/net/src/slot.rs new file mode 100644 index 00000000..8f522219 --- /dev/null +++ b/src/lib/net/src/slot.rs @@ -0,0 +1,56 @@ +use std::io::Read; + +use ferrumc_macros::{NetDecode, NetEncode}; +use ferrumc_net_codec::{ + decode::{NetDecode, NetDecodeOpts, NetDecodeResult}, + net_types::{length_prefixed_vec::LengthPrefixedVec, var_int::VarInt}, +}; + +#[derive(NetEncode, Debug, Clone, Copy)] +pub enum SlotComponent { + MaxStackSize { max_stack_size: VarInt }, +} + +#[derive(Debug, Clone, Copy)] +pub struct NetworkSlot { + pub item_count: VarInt, + pub item_id: Option, + pub components_to_add: Option>, + pub components_to_remove: Option>, +} + +impl NetworkSlot { + pub fn new(item_count: i32, item_id: i32) -> Self { + Self::with_components(item_count, item_id, vec![]) + } + + pub fn with_components(item_count: i32, item_id: i32, components: Vec) -> Self { + Self { + item_count: VarInt::new(item_count), + item_id: if item_count == 0 { + None + } else { + Some(VarInt::new(item_id)) + }, + components_to_add: if item_count == 0 { + None + } else { + Some(LengthPrefixedVec::new(components)) + }, + components_to_remove: if item_count == 0 { + None + } else { + Some(LengthPrefixedVec::default()) + }, + } + } + + 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 + } +}