From fbe8a9314c7f11d043b22d6476de38c19847da5b Mon Sep 17 00:00:00 2001 From: OfficialKris <37947442+OfficialKris@users.noreply.github.com> Date: Thu, 26 Dec 2024 19:53:26 -0800 Subject: [PATCH 1/3] Added basic chest opening and closing --- .../src/client/play/c_block_event.rs | 31 +++++++++++++++++++ pumpkin-protocol/src/client/play/mod.rs | 2 ++ pumpkin/src/block/blocks/chest.rs | 17 ++++++++-- 3 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 pumpkin-protocol/src/client/play/c_block_event.rs diff --git a/pumpkin-protocol/src/client/play/c_block_event.rs b/pumpkin-protocol/src/client/play/c_block_event.rs new file mode 100644 index 00000000..c1b2e6e0 --- /dev/null +++ b/pumpkin-protocol/src/client/play/c_block_event.rs @@ -0,0 +1,31 @@ +use pumpkin_core::math::position::WorldPosition; + +use pumpkin_macros::client_packet; +use serde::Serialize; + +use crate::VarInt; + +#[derive(Serialize)] +#[client_packet("play:block_event")] +pub struct CBlockAction<'a> { + location: &'a WorldPosition, + action_id: u8, + action_parameter: u8, + block_type: VarInt, +} + +impl<'a> CBlockAction<'a> { + pub fn new( + location: &'a WorldPosition, + action_id: u8, + action_parameter: u8, + block_type: VarInt, + ) -> Self { + Self { + location, + action_id, + action_parameter, + block_type, + } + } +} diff --git a/pumpkin-protocol/src/client/play/mod.rs b/pumpkin-protocol/src/client/play/mod.rs index 79f7e3ea..68a7cc57 100644 --- a/pumpkin-protocol/src/client/play/mod.rs +++ b/pumpkin-protocol/src/client/play/mod.rs @@ -2,6 +2,7 @@ mod bossevent_action; mod c_acknowledge_block; mod c_actionbar; mod c_block_destroy_stage; +mod c_block_event; mod c_block_update; mod c_boss_event; mod c_center_chunk; @@ -72,6 +73,7 @@ pub use bossevent_action::*; pub use c_acknowledge_block::*; pub use c_actionbar::*; pub use c_block_destroy_stage::*; +pub use c_block_event::*; pub use c_block_update::*; pub use c_boss_event::*; pub use c_center_chunk::*; diff --git a/pumpkin/src/block/blocks/chest.rs b/pumpkin/src/block/blocks/chest.rs index 1600bb09..470c4610 100644 --- a/pumpkin/src/block/blocks/chest.rs +++ b/pumpkin/src/block/blocks/chest.rs @@ -2,6 +2,7 @@ use async_trait::async_trait; use pumpkin_core::math::position::WorldPosition; use pumpkin_inventory::{Chest, OpenContainer, WindowType}; use pumpkin_macros::{pumpkin_block, sound}; +use pumpkin_protocol::{client::play::CBlockAction, codec::var_int::VarInt}; use pumpkin_world::{block::block_registry::get_block, item::item_registry::Item}; use crate::{ @@ -34,11 +35,17 @@ impl PumpkinBlock for ChestBlock { BlockActionResult::Consume } - async fn on_close<'a>(&self, player: &Player, _location: WorldPosition, _server: &Server) { + async fn on_close<'a>(&self, player: &Player, location: WorldPosition, server: &Server) { player .world() - .play_block_sound(sound!("block.chest.close"), _location) + .play_block_sound(sound!("block.chest.close"), location) .await; + + if let Some(e) = get_block("minecraft:chest").cloned() { + server + .broadcast_packet_all(&CBlockAction::new(&location, 1, 0, VarInt(e.id.into()))) + .await; + } } } @@ -66,5 +73,11 @@ impl ChestBlock { } } player.open_container(server, WindowType::Generic9x3).await; + + if let Some(e) = get_block("minecraft:chest").cloned() { + server + .broadcast_packet_all(&CBlockAction::new(&location, 1, 1, VarInt(e.id.into()))) + .await; + } } } From 3b895994de5c830543e5e7f95d9b9e94899d477d Mon Sep 17 00:00:00 2001 From: OfficialKris <37947442+OfficialKris@users.noreply.github.com> Date: Fri, 27 Dec 2024 15:42:47 -0800 Subject: [PATCH 2/3] Added number tracking --- pumpkin-inventory/src/open_container.rs | 4 +++ pumpkin/src/block/blocks/chest.rs | 29 +++++++++++++++++----- pumpkin/src/block/blocks/crafting_table.rs | 4 ++- pumpkin/src/block/pumpkin_block.rs | 2 +- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/pumpkin-inventory/src/open_container.rs b/pumpkin-inventory/src/open_container.rs index 3025ed92..c563ee47 100644 --- a/pumpkin-inventory/src/open_container.rs +++ b/pumpkin-inventory/src/open_container.rs @@ -76,6 +76,10 @@ impl OpenContainer { self.players.clone() } + pub fn get_number_of_players(&self) -> usize { + self.players.len() + } + pub fn get_location(&self) -> Option { self.location } diff --git a/pumpkin/src/block/blocks/chest.rs b/pumpkin/src/block/blocks/chest.rs index 1be42eca..9baf687d 100644 --- a/pumpkin/src/block/blocks/chest.rs +++ b/pumpkin/src/block/blocks/chest.rs @@ -63,16 +63,23 @@ impl PumpkinBlock for ChestBlock { player: &Player, location: WorldPosition, server: &Server, - _container: &OpenContainer, + container: &mut OpenContainer, ) { player .world() .play_block_sound(sound!("block.chest.close"), location) .await; + container.remove_player(player.entity_id()); + if let Some(e) = get_block("minecraft:chest").cloned() { server - .broadcast_packet_all(&CBlockAction::new(&location, 1, 0, VarInt(e.id.into()))) + .broadcast_packet_all(&CBlockAction::new( + &location, + 1, + container.get_number_of_players() as u8, + VarInt(e.id.into()), + )) .await; } } @@ -96,10 +103,20 @@ impl ChestBlock { ) .await; - if let Some(e) = get_block("minecraft:chest").cloned() { - server - .broadcast_packet_all(&CBlockAction::new(&location, 1, 1, VarInt(e.id.into()))) - .await; + if let Some(container_id) = server.get_container_id(location, block.clone()).await { + let open_containers = server.open_containers.read().await; + if let Some(container) = open_containers.get(&u64::from(container_id)) { + if let Some(e) = get_block("minecraft:chest").cloned() { + server + .broadcast_packet_all(&CBlockAction::new( + &location, + 1, + container.get_number_of_players() as u8, + VarInt(e.id.into()), + )) + .await; + } + } } } } diff --git a/pumpkin/src/block/blocks/crafting_table.rs b/pumpkin/src/block/blocks/crafting_table.rs index 01ad4179..c879f060 100644 --- a/pumpkin/src/block/blocks/crafting_table.rs +++ b/pumpkin/src/block/blocks/crafting_table.rs @@ -53,7 +53,7 @@ impl PumpkinBlock for CraftingTableBlock { player: &Player, _location: WorldPosition, _server: &Server, - container: &OpenContainer, + container: &mut OpenContainer, ) { let entity_id = player.entity_id(); for player_id in container.all_player_ids() { @@ -62,6 +62,8 @@ impl PumpkinBlock for CraftingTableBlock { } } + container.remove_player(entity_id); + // TODO: items should be re-added to player inventory or dropped dependending on if they are in movement. // TODO: unique containers should be implemented as a separate stack internally (optimizes large player servers for example) // TODO: ephemeral containers (crafting tables) might need to be separate data structure than stored (ender chest) diff --git a/pumpkin/src/block/pumpkin_block.rs b/pumpkin/src/block/pumpkin_block.rs index c0a65c31..90de5718 100644 --- a/pumpkin/src/block/pumpkin_block.rs +++ b/pumpkin/src/block/pumpkin_block.rs @@ -60,7 +60,7 @@ pub trait PumpkinBlock: Send + Sync { _player: &Player, _location: WorldPosition, _server: &Server, - _container: &OpenContainer, + _container: &mut OpenContainer, ) { } } From 15754e3f6e3c84c511b191cfd90a0dbdea1f9832 Mon Sep 17 00:00:00 2001 From: OfficialKris <37947442+OfficialKris@users.noreply.github.com> Date: Fri, 27 Dec 2024 21:55:11 -0800 Subject: [PATCH 3/3] Added play chest action function --- pumpkin/src/block/blocks/chest.rs | 72 ++++++++++++++++++------------- 1 file changed, 43 insertions(+), 29 deletions(-) diff --git a/pumpkin/src/block/blocks/chest.rs b/pumpkin/src/block/blocks/chest.rs index 9baf687d..5a83570e 100644 --- a/pumpkin/src/block/blocks/chest.rs +++ b/pumpkin/src/block/blocks/chest.rs @@ -14,6 +14,12 @@ use crate::{ server::Server, }; +#[derive(PartialEq)] +pub enum ChestState { + IsOpened, + IsClosed, +} + #[pumpkin_block("minecraft:chest")] pub struct ChestBlock; @@ -28,10 +34,6 @@ impl PumpkinBlock for ChestBlock { ) { self.open_chest_block(block, player, _location, server) .await; - player - .world() - .play_block_sound(sound!("block.chest.open"), _location) - .await; } async fn on_use_with_item<'a>( @@ -65,23 +67,10 @@ impl PumpkinBlock for ChestBlock { server: &Server, container: &mut OpenContainer, ) { - player - .world() - .play_block_sound(sound!("block.chest.close"), location) - .await; - container.remove_player(player.entity_id()); - if let Some(e) = get_block("minecraft:chest").cloned() { - server - .broadcast_packet_all(&CBlockAction::new( - &location, - 1, - container.get_number_of_players() as u8, - VarInt(e.id.into()), - )) - .await; - } + self.play_chest_action(container, player, location, server, ChestState::IsClosed) + .await; } } @@ -106,17 +95,42 @@ impl ChestBlock { if let Some(container_id) = server.get_container_id(location, block.clone()).await { let open_containers = server.open_containers.read().await; if let Some(container) = open_containers.get(&u64::from(container_id)) { - if let Some(e) = get_block("minecraft:chest").cloned() { - server - .broadcast_packet_all(&CBlockAction::new( - &location, - 1, - container.get_number_of_players() as u8, - VarInt(e.id.into()), - )) - .await; - } + self.play_chest_action(container, player, location, server, ChestState::IsOpened) + .await; } } } + + pub async fn play_chest_action( + &self, + container: &OpenContainer, + player: &Player, + location: WorldPosition, + server: &Server, + state: ChestState, + ) { + let num_players = container.get_number_of_players() as u8; + if state == ChestState::IsClosed && num_players == 0 { + player + .world() + .play_block_sound(sound!("block.chest.close"), location) + .await; + } else if state == ChestState::IsOpened && num_players == 1 { + player + .world() + .play_block_sound(sound!("block.chest.open"), location) + .await; + } + + if let Some(e) = get_block("minecraft:chest").cloned() { + server + .broadcast_packet_all(&CBlockAction::new( + &location, + 1, + num_players, + VarInt(e.id.into()), + )) + .await; + } + } }