diff --git a/pumpkin-protocol/src/client/play/c_block_destroy_stage.rs b/pumpkin-protocol/src/client/play/c_block_destroy_stage.rs index 0b6a1e94d..d671f985f 100644 --- a/pumpkin-protocol/src/client/play/c_block_destroy_stage.rs +++ b/pumpkin-protocol/src/client/play/c_block_destroy_stage.rs @@ -12,9 +12,11 @@ pub struct CSetBlockDestroyStage { } impl CSetBlockDestroyStage { - pub fn new(entity_id: VarInt, - location: WorldPosition, - destroy_stage: u8) -> Self { - Self { entity_id, location, destroy_stage } + pub fn new(entity_id: VarInt, location: WorldPosition, destroy_stage: u8) -> Self { + Self { + entity_id, + location, + destroy_stage, + } } -} \ No newline at end of file +} diff --git a/pumpkin-protocol/src/client/play/c_worldevent.rs b/pumpkin-protocol/src/client/play/c_worldevent.rs index 71bf5f02e..c9447b71c 100644 --- a/pumpkin-protocol/src/client/play/c_worldevent.rs +++ b/pumpkin-protocol/src/client/play/c_worldevent.rs @@ -5,18 +5,25 @@ use crate::position::WorldPosition; #[derive(Serialize)] #[packet(0x28)] -pub struct CWorldEvent { +pub struct CWorldEvent<'a> { event: i32, - location: WorldPosition, + location: &'a WorldPosition, data: i32, disable_relative_volume: bool, } -impl CWorldEvent { - pub fn new(event: i32, - location: WorldPosition, - data: i32, - disable_relative_volume: bool) -> Self { - Self { event, location, data, disable_relative_volume } +impl<'a> CWorldEvent<'a> { + pub fn new( + event: i32, + location: &'a WorldPosition, + data: i32, + disable_relative_volume: bool, + ) -> Self { + Self { + event, + location, + data, + disable_relative_volume, + } } -} \ No newline at end of file +} diff --git a/pumpkin-protocol/src/client/play/mod.rs b/pumpkin-protocol/src/client/play/mod.rs index 8f38f39bd..38ccd947a 100644 --- a/pumpkin-protocol/src/client/play/mod.rs +++ b/pumpkin-protocol/src/client/play/mod.rs @@ -1,4 +1,5 @@ mod c_actionbar; +mod c_block_destroy_stage; mod c_block_update; mod c_center_chunk; mod c_change_difficulty; @@ -29,11 +30,10 @@ mod c_update_entitiy_pos_rot; mod c_update_entity_pos; mod c_update_entity_rot; mod c_worldevent; -mod c_block_destroy_stage; mod player_action; -pub use c_block_destroy_stage::*; pub use c_actionbar::*; +pub use c_block_destroy_stage::*; pub use c_block_update::*; pub use c_center_chunk::*; pub use c_change_difficulty::*; diff --git a/pumpkin-protocol/src/server/play/s_player_action.rs b/pumpkin-protocol/src/server/play/s_player_action.rs index a217a2b8f..3753ee22a 100644 --- a/pumpkin-protocol/src/server/play/s_player_action.rs +++ b/pumpkin-protocol/src/server/play/s_player_action.rs @@ -1,13 +1,32 @@ +use num_derive::FromPrimitive; use pumpkin_macros::packet; use crate::{position::WorldPosition, VarInt}; #[derive(serde::Deserialize)] -#[allow(dead_code)] #[packet(0x24)] pub struct SPlayerAction { - status: VarInt, - location: WorldPosition, - face: u8, - sequence: VarInt, + pub status: VarInt, + pub location: WorldPosition, + pub face: u8, + pub sequence: VarInt, +} + +#[derive(FromPrimitive)] +pub enum Status { + /// Sent when the player starts digging a block. If the block was instamined or the player is in creative mode, the client will not send Status = Finished digging, and will assume the server completed the destruction. To detect this, it is necessary to calculate the block destruction speed server-side. + StartedDigging = 0, + /// Sent when the player lets go of the Mine Block key (default: left click). Face is always set to -Y. + CancelledDigging, + /// Sent when the client thinks it is finished. + FinishedDigging, + /// Triggered by using the Drop Item key (default: Q) with the modifier to drop the entire selected stack (default: Control or Command, depending on OS). Location is always set to 0/0/0, Face is always set to -Y. Sequence is always set to 0. + DropItemStack, + /// Triggered by using the Drop Item key (default: Q). Location is always set to 0/0/0, Face is always set to -Y. Sequence is always set to 0. + DropItem, + /// I didn't make that up + /// Indicates that the currently held item should have its state updated such as eating food, pulling back bows, using buckets, etc. Location is always set to 0/0/0, Face is always set to -Y. Sequence is always set to 0. + ShootArrowOrFinishEating, + /// Used to swap or assign an item to the second hand. Location is always set to 0/0/0, Face is always set to -Y. Sequence is always set to 0. + SwapItem, } diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 45d8c67ae..a53fa586b 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -11,13 +11,14 @@ use pumpkin_entity::EntityId; use pumpkin_protocol::{ client::play::{ Animation, CBlockUpdate, CEntityAnimation, CEntityVelocity, CHeadRot, CHurtAnimation, - CPlayerChatMessage, CUpdateEntityPos, CUpdateEntityPosRot, CUpdateEntityRot, FilterType, + CPlayerChatMessage, CUpdateEntityPos, CUpdateEntityPosRot, CUpdateEntityRot, CWorldEvent, + FilterType, }, position::WorldPosition, server::play::{ Action, ActionType, SChatCommand, SChatMessage, SClientInformationPlay, SConfirmTeleport, SInteract, SPlayerAction, SPlayerCommand, SPlayerPosition, SPlayerPositionRotation, - SPlayerRotation, SSetCreativeSlot, SSetHeldItem, SSwingArm, SUseItemOn, + SPlayerRotation, SSetCreativeSlot, SSetHeldItem, SSwingArm, SUseItemOn, Status, }, }; use pumpkin_text::TextComponent; @@ -315,7 +316,46 @@ impl Client { } } } - pub fn handle_player_action(&mut self, _server: &mut Server, _player_action: SPlayerAction) {} + pub fn handle_player_action(&mut self, server: &mut Server, player_action: SPlayerAction) { + match Status::from_i32(player_action.status.0).unwrap() { + Status::StartedDigging => { + let player = self.player.as_mut().unwrap(); + // TODO: Config + if player.gamemode == GameMode::Creative { + let location = player_action.location; + // Block break & block break sound + // TODO: currently this is always dirt replace it + server.broadcast_packet(self, &CWorldEvent::new(2001, &location, 11, false)); + // AIR + server.broadcast_packet(self, &CBlockUpdate::new(location, 0.into())); + } + } + Status::CancelledDigging => { + let player = self.player.as_mut().unwrap(); + player.current_block_destroy_stage = 0; + } + Status::FinishedDigging => { + let location = player_action.location; + // Block break & block break sound + // TODO: currently this is always dirt replace it + server.broadcast_packet(self, &CWorldEvent::new(2001, &location, 11, false)); + // AIR + server.broadcast_packet(self, &CBlockUpdate::new(location, 0.into())); + } + Status::DropItemStack => { + dbg!("todo"); + } + Status::DropItem => { + dbg!("todo"); + } + Status::ShootArrowOrFinishEating => { + dbg!("todo"); + } + Status::SwapItem => { + dbg!("todo"); + } + } + } pub fn handle_use_item_on(&mut self, server: &mut Server, use_item_on: SUseItemOn) { let location = use_item_on.location; diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index 35c7758bd..939c7b8e2 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -23,6 +23,9 @@ pub struct Player { pub sneaking: bool, pub sprinting: bool, + // TODO: This is currently unused, We have to calculate the block breaking speed our own and then break the block our own if its done + pub current_block_destroy_stage: u8, + // TODO: prbly should put this into an Living Entitiy or something pub velocity: Vector3, @@ -42,6 +45,7 @@ impl Player { health: 20.0, food: 20, food_saturation: 20.0, + current_block_destroy_stage: 0, velocity: Vector3::new(0.0, 0.0, 0.0), inventory: PlayerInventory::new(), gamemode,