diff --git a/examples/conway.rs b/examples/conway.rs index acf4c55..c21e3bd 100644 --- a/examples/conway.rs +++ b/examples/conway.rs @@ -9,7 +9,7 @@ use num::Integer; use rayon::iter::{IndexedParallelIterator, IntoParallelRefMutIterator, ParallelIterator}; use valence::biome::Biome; use valence::block::BlockState; -use valence::client::{ClientId, Event, GameMode, Hand}; +use valence::client::{ClientId, Event, Hand}; use valence::config::{Config, ServerListPing}; use valence::dimension::{Dimension, DimensionId}; use valence::entity::data::Pose; @@ -131,7 +131,6 @@ impl Config for Game { } client.spawn(world_id); - client.set_game_mode(GameMode::Survival); client.teleport(spawn_pos, 0.0, 0.0); world.meta.player_list_mut().insert( diff --git a/src/client.rs b/src/client.rs index 17fba17..7111b0c 100644 --- a/src/client.rs +++ b/src/client.rs @@ -30,7 +30,7 @@ use crate::protocol_inner::packets::play::s2c::{ MoveEntityRotation, PlayerPosition, PlayerPositionFlags, RegistryCodec, RemoveEntities, Respawn, RotateHead, S2cPlayPacket, SetChunkCacheCenter, SetChunkCacheRadius, SetEntityMetadata, SetEntityMotion, SetSubtitleText, SetTitleText, SpawnPosition, SystemChat, - TeleportEntity, ENTITY_EVENT_MAX_BOUND, + TeleportEntity, UpdateAttributes, UpdateAttributesProperty, ENTITY_EVENT_MAX_BOUND, }; use crate::protocol_inner::{BoundedInt, ByteAngle, Nbt, RawBytes, VarInt}; use crate::server::{C2sPacketChannels, NewClientData, SharedServer}; @@ -195,7 +195,10 @@ pub struct Client { old_game_mode: GameMode, settings: Option, dug_blocks: Vec, + /// Should be sent after login packet. msgs_to_send: Vec, + attack_speed: f64, + movement_speed: f64, flags: ClientFlags, /// The data for the client's own player entity. player_data: Player, @@ -216,7 +219,9 @@ pub(crate) struct ClientFlags { /// If the last sent keepalive got a response. got_keepalive: bool, hardcore: bool, - #[bits(7)] + attack_speed_modified: bool, + movement_speed_modified: bool, + #[bits(5)] _pad: u8, } @@ -256,6 +261,8 @@ impl Client { settings: None, dug_blocks: Vec::new(), msgs_to_send: Vec::new(), + attack_speed: 4.0, + movement_speed: 0.7, flags: ClientFlags::new() .with_modified_spawn_position(true) .with_got_keepalive(true), @@ -423,6 +430,32 @@ impl Client { } } + /// Gets the attack cooldown speed. + pub fn attack_speed(&self) -> f64 { + self.attack_speed + } + + /// Sets the attack cooldown speed. + pub fn set_attack_speed(&mut self, speed: f64) { + if self.attack_speed != speed { + self.attack_speed = speed; + self.flags.set_attack_speed_modified(true); + } + } + + /// Gets the speed at which the client can run on the ground. + pub fn movement_speed(&self) -> f64 { + self.movement_speed + } + + /// Sets the speed at which the client can run on the ground. + pub fn set_movement_speed(&mut self, speed: f64) { + if self.movement_speed != speed { + self.movement_speed = speed; + self.flags.set_movement_speed_modified(true); + } + } + /// Removes the current title from the client's screen. pub fn clear_title(&mut self) { self.send_packet(ClearTitles { reset: true }); @@ -914,6 +947,33 @@ impl Client { .diff_packets(|pkt| self.send_packet(pkt)); } + // Set player attributes + if self.flags.attack_speed_modified() { + self.flags.set_attack_speed_modified(false); + + self.send_packet(UpdateAttributes { + entity_id: VarInt(0), + properties: vec![UpdateAttributesProperty { + key: ident!("generic.attack_speed"), + value: self.attack_speed, + modifiers: Vec::new(), + }], + }); + } + + if self.flags.movement_speed_modified() { + self.flags.set_movement_speed_modified(false); + + self.send_packet(UpdateAttributes { + entity_id: VarInt(0), + properties: vec![UpdateAttributesProperty { + key: ident!("generic.movement_speed"), + value: self.movement_speed, + modifiers: Vec::new(), + }], + }); + } + // Update the players spawn position (compass position) if self.flags.modified_spawn_position() { self.flags.set_modified_spawn_position(false); diff --git a/src/protocol_inner/packets.rs b/src/protocol_inner/packets.rs index 21ee823..3f289e1 100644 --- a/src/protocol_inner/packets.rs +++ b/src/protocol_inner/packets.rs @@ -1233,6 +1233,29 @@ pub mod play { } } + def_struct! { + UpdateAttributes 0x65 { + entity_id: VarInt, + properties: Vec, + } + } + + def_struct! { + UpdateAttributesProperty { + key: Ident, + value: f64, + modifiers: Vec + } + } + + def_struct! { + UpdateAttributesModifiers { + uuid: Uuid, + amount: f64, + operation: u8, + } + } + def_packet_group! { S2cPlayPacket { AddEntity, @@ -1276,6 +1299,7 @@ pub mod play { SystemChat, TabList, TeleportEntity, + UpdateAttributes, } } }