diff --git a/README.md b/README.md index e919bfafd..b0608e17e 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ Pumpkin is currently under heavy development. - [x] Player Client brand - [x] Player Teleport - [x] Player Movement - - [ ] Player Animation + - [x] Player Animation - [ ] Player Inventory - [ ] Player Attack - Server diff --git a/pumpkin-protocol/src/client/play/c_entity_animation.rs b/pumpkin-protocol/src/client/play/c_entity_animation.rs new file mode 100644 index 000000000..a4c7f36da --- /dev/null +++ b/pumpkin-protocol/src/client/play/c_entity_animation.rs @@ -0,0 +1,31 @@ +use num_derive::ToPrimitive; +use pumpkin_macros::packet; +use serde::Serialize; + +use crate::VarInt; + +#[derive(Serialize, Clone)] +#[packet(0x03)] +pub struct CEntityAnimation { + entity_id: VarInt, + /// See `Animation` + animation: u8, +} + +impl CEntityAnimation { + pub fn new(entity_id: VarInt, animation: u8) -> Self { + Self { + entity_id, + animation, + } + } +} + +#[derive(ToPrimitive)] +pub enum Animation { + SwingMainArm, + LeaveBed, + SwingOffhand, + CriticalEffect, + MagicCriticaleffect, +} diff --git a/pumpkin-protocol/src/client/play/c_player_abilities.rs b/pumpkin-protocol/src/client/play/c_player_abilities.rs index c7f50cb35..a74139fac 100644 --- a/pumpkin-protocol/src/client/play/c_player_abilities.rs +++ b/pumpkin-protocol/src/client/play/c_player_abilities.rs @@ -1,7 +1,6 @@ use pumpkin_macros::packet; use serde::Serialize; - #[derive(Serialize)] #[packet(0x38)] pub struct CPlayerAbilities { diff --git a/pumpkin-protocol/src/client/play/mod.rs b/pumpkin-protocol/src/client/play/mod.rs index 4d0f2231f..e7aa90e77 100644 --- a/pumpkin-protocol/src/client/play/mod.rs +++ b/pumpkin-protocol/src/client/play/mod.rs @@ -1,5 +1,6 @@ mod c_change_difficulty; mod c_chunk_data_update_light; +mod c_entity_animation; mod c_entity_metadata; mod c_game_event; mod c_head_rot; @@ -19,6 +20,7 @@ mod player_action; pub use c_change_difficulty::*; pub use c_chunk_data_update_light::*; +pub use c_entity_animation::*; pub use c_entity_metadata::*; pub use c_game_event::*; pub use c_head_rot::*; diff --git a/pumpkin-protocol/src/server/play/mod.rs b/pumpkin-protocol/src/server/play/mod.rs index 62782c7cd..76193a3c5 100644 --- a/pumpkin-protocol/src/server/play/mod.rs +++ b/pumpkin-protocol/src/server/play/mod.rs @@ -51,6 +51,20 @@ impl ServerPacket for SPlayerPosition { } } +pub struct SSwingArm { + pub hand: VarInt, +} + +impl ServerPacket for SSwingArm { + const PACKET_ID: VarInt = VarInt(0x36); + + fn read(bytebuf: &mut crate::bytebuf::ByteBuffer) -> Self { + Self { + hand: bytebuf.get_var_int(), + } + } +} + pub struct SPlayerCommand { pub entitiy_id: VarInt, pub action: Action, diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index 99fc0c2c4..90da622b2 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -27,7 +27,7 @@ use pumpkin_protocol::{ login::{SEncryptionResponse, SLoginAcknowledged, SLoginPluginResponse, SLoginStart}, play::{ SChatCommand, SConfirmTeleport, SPlayerCommand, SPlayerPosition, - SPlayerPositionRotation, SPlayerRotation, + SPlayerPositionRotation, SPlayerRotation, SSwingArm, }, status::{SPingRequest, SStatusRequest}, }, @@ -256,6 +256,7 @@ impl Client { SPlayerCommand::PACKET_ID => { self.handle_player_command(server, SPlayerCommand::read(bytebuf)) } + SSwingArm::PACKET_ID => self.handle_swing_arm(server, SSwingArm::read(bytebuf)), _ => log::error!("Failed to handle player packet id {}", packet.id.0), } } diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 7801580f5..1850fd345 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -1,13 +1,18 @@ +use num_traits::FromPrimitive; use pumpkin_protocol::{ - client::play::{CHeadRot, CUpdateEntityPos, CUpdateEntityPosRot, CUpdateEntityRot}, + client::play::{ + Animation, CEntityAnimation, CHeadRot, CUpdateEntityPos, CUpdateEntityPosRot, + CUpdateEntityRot, + }, server::play::{ SChatCommand, SConfirmTeleport, SPlayerCommand, SPlayerPosition, SPlayerPositionRotation, - SPlayerRotation, + SPlayerRotation, SSwingArm, }, }; use crate::{ commands::{handle_command, CommandSender}, + entity::player::Hand, server::Server, }; @@ -156,4 +161,14 @@ impl Client { pumpkin_protocol::server::play::Action::StartFlyingElytra => todo!(), } } + + pub fn handle_swing_arm(&mut self, server: &mut Server, swing_arm: SSwingArm) { + let animation = match Hand::from_i32(swing_arm.hand.0).unwrap() { + Hand::Main => Animation::SwingMainArm, + Hand::Off => Animation::SwingOffhand, + }; + let player = self.player.as_mut().unwrap(); + let id = player.entity_id(); + server.broadcast_packet_expect(self, CEntityAnimation::new(id.into(), animation as u8)) + } } diff --git a/pumpkin/src/config/configuration.rs b/pumpkin/src/config/configuration.rs deleted file mode 100644 index 9f28a0f72..000000000 --- a/pumpkin/src/config/configuration.rs +++ /dev/null @@ -1,153 +0,0 @@ -use std::path::Path; - -use serde::{Deserialize, Serialize}; - -use crate::{entity::player::GameMode, server::Difficulty}; - -use super::auth_config::Authentication; - -/// Current Config version of the Base Config -const CURRENT_BASE_VERSION: &str = "1.0.0"; - -#[derive(Deserialize, Serialize)] -/// The idea is that Pumpkin should very customizable, You can Enable or Disable Features depning on your needs. -/// This also allows you get some Performance or Resource boosts. -/// Important: The Configuration should match Vanilla by default -pub struct AdvancedConfiguration { - pub commands: Commands, - pub authentication: Authentication, -} - -#[derive(Deserialize, Serialize)] -pub struct Commands { - /// Are commands from the Console accepted ? - pub use_console: bool, - // todo commands... -} - -impl Default for Commands { - fn default() -> Self { - Self { use_console: true } - } -} - -/// Important: The Configuration should match Vanilla by default -impl Default for AdvancedConfiguration { - fn default() -> Self { - Self { - authentication: Authentication::default(), - commands: Commands::default(), - } - } -} - -#[derive(Serialize, Deserialize)] -pub struct BasicConfiguration { - /// A version identifier for the configuration format. - pub config_version: String, - /// The address to bind the server to. - pub server_address: String, - /// The port to listen on. - pub server_port: u16, - /// The seed for world generation. - pub seed: String, - /// The maximum number of players allowed on the server. - pub max_players: u32, - /// The maximum view distance for players. - pub view_distance: u8, - /// The maximum simulated view distance. - pub simulation_distance: u8, - /// The path to the resource pack. - pub resource_pack: String, - /// The SHA1 hash of the resource pack. - pub resource_pack_sha1: String, - /// The default game difficulty. - pub default_difficulty: Difficulty, - /// Whether the Nether dimension is enabled. - pub allow_nether: bool, - /// Whether the server is in hardcore mode. - pub hardcore: bool, - /// Whether online mode is enabled. Requires valid Minecraft accounts. - pub online_mode: bool, - /// Whether packet encryption is enabled. Required when online mode is enabled. - pub encryption: bool, - /// The server's description displayed on the status screen. - pub motd: String, - /// The default game mode for players. - pub default_gamemode: GameMode, -} - -impl Default for BasicConfiguration { - fn default() -> Self { - Self { - config_version: CURRENT_BASE_VERSION.to_string(), - server_address: "127.0.0.1".to_string(), - server_port: 25565, - seed: "".to_string(), - max_players: 100000, - view_distance: 10, - simulation_distance: 10, - resource_pack: "".to_string(), - resource_pack_sha1: "".to_string(), - default_difficulty: Difficulty::Normal, - allow_nether: true, - hardcore: false, - online_mode: true, - encryption: true, - motd: "A Blazing fast Pumpkin Server!".to_string(), - default_gamemode: GameMode::Survival, - } - } -} - -impl AdvancedConfiguration { - pub fn load>(path: P) -> AdvancedConfiguration { - if path.as_ref().exists() { - let toml = std::fs::read_to_string(path).expect("Couldn't read configuration"); - toml::from_str(toml.as_str()).expect("Couldn't parse, Proberbly old config") - } else { - let config = AdvancedConfiguration::default(); - let toml = toml::to_string(&config).expect("Couldn't create toml!"); - std::fs::write(path, toml).expect("Couldn't save configuration"); - config - } - } -} - -impl BasicConfiguration { - pub fn load>(path: P) -> BasicConfiguration { - if path.as_ref().exists() { - let toml = std::fs::read_to_string(path).expect("Couldn't read configuration"); - toml::from_str(toml.as_str()).expect("Couldn't parse") - } else { - let config = BasicConfiguration::default(); - let toml = toml::to_string(&config).expect("Couldn't create toml!"); - std::fs::write(path, toml).expect("Couldn't save configuration"); - config.validate(); - config - } - } - - pub fn validate(&self) { - assert_eq!( - self.config_version, CURRENT_BASE_VERSION, - "Config version does not match used Config version. Please update your config" - ); - assert!(self.view_distance >= 2, "View distance must be atleast 2"); - assert!( - self.view_distance <= 32, - "View distance must be less than 32" - ); - if self.online_mode { - assert!( - self.encryption, - "When Online Mode is enabled, Encryption must be enabled" - ) - } - assert_eq!( - !self.resource_pack.is_empty(), - !self.resource_pack_sha1.is_empty(), - "Resource Pack path or Sha1 hash is missing" - ); - } -} diff --git a/pumpkin/src/server.rs b/pumpkin/src/server.rs index 0fc80f42f..dd7b19235 100644 --- a/pumpkin/src/server.rs +++ b/pumpkin/src/server.rs @@ -14,7 +14,8 @@ use pumpkin_protocol::{ client::{ config::CPluginMessage, play::{ - CChunkDataUpdateLight, CGameEvent, CLogin, CPlayerAbilities, CPlayerInfoUpdate, CSpawnEntity, PlayerAction, + CChunkDataUpdateLight, CGameEvent, CLogin, CPlayerAbilities, CPlayerInfoUpdate, + CSpawnEntity, PlayerAction, }, }, BitSet, ClientPacket, Players, Sample, StatusResponse, VarInt, Version, CURRENT_MC_PROTOCOL,