diff options
| author | mat <27899617+mat-1@users.noreply.github.com> | 2022-11-12 23:54:05 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-11-12 23:54:05 -0600 |
| commit | 6eee543a3367d38a6f0e9bffb457a2bd76a8f9cc (patch) | |
| tree | a5e493ccd7ec24293b8d866242c3836146517122 /azalea-client/src/movement.rs | |
| parent | fa57d03627aa20b1df44caed7cb025b6db1d9b53 (diff) | |
| download | azalea-drasl-6eee543a3367d38a6f0e9bffb457a2bd76a8f9cc.tar.xz | |
Pathfinder (#25)
Pathfinding is very much not done, but it works enough and I want to get this merged.
TODO: fast replanning, goals that aren't a single node, falling moves (it should be able to play the dropper), parkour moves
Diffstat (limited to 'azalea-client/src/movement.rs')
| -rwxr-xr-x[-rw-r--r--] | azalea-client/src/movement.rs | 192 |
1 files changed, 154 insertions, 38 deletions
diff --git a/azalea-client/src/movement.rs b/azalea-client/src/movement.rs index 93acf36f..145513c0 100644..100755 --- a/azalea-client/src/movement.rs +++ b/azalea-client/src/movement.rs @@ -2,6 +2,7 @@ use crate::Client; use azalea_core::Vec3; use azalea_physics::collision::{MovableEntity, MoverType}; use azalea_physics::HasPhysics; +use azalea_protocol::packets::game::serverbound_player_command_packet::ServerboundPlayerCommandPacket; use azalea_protocol::packets::game::{ serverbound_move_player_pos_packet::ServerboundMovePlayerPosPacket, serverbound_move_player_pos_rot_packet::ServerboundMovePlayerPosRotPacket, @@ -28,24 +29,19 @@ impl From<MoveEntityError> for MovePlayerError { } impl Client { - /// This gets called every tick. - pub async fn send_position(&mut self) -> Result<(), MovePlayerError> { + /// This gets called automatically every tick. + pub(crate) async fn send_position(&mut self) -> Result<(), MovePlayerError> { let packet = { - let player_lock = self.player.lock(); + self.send_sprinting_if_needed().await?; + // TODO: the camera being able to be controlled by other entities isn't implemented yet + // if !self.is_controlled_camera() { return }; + let mut physics_state = self.physics_state.lock(); - let mut dimension_lock = self.dimension.lock(); - let mut player_entity = player_lock - .entity_mut(&mut dimension_lock) - .expect("Player must exist"); + let player_entity = self.entity(); let player_pos = player_entity.pos(); let player_old_pos = player_entity.last_pos; - // TODO: send sprinting and sneaking packets here if they changed - - // TODO: the camera being able to be controlled by other entities isn't implemented yet - // if !self.is_controlled_camera() { return }; - let x_delta = player_pos.x - player_old_pos.x; let y_delta = player_pos.y - player_old_pos.y; let z_delta = player_pos.z - player_old_pos.z; @@ -105,6 +101,9 @@ impl Client { None }; + drop(player_entity); + let mut player_entity = self.entity_mut(); + if sending_position { player_entity.last_pos = *player_entity.pos(); physics_state.position_remainder = 0; @@ -127,10 +126,35 @@ impl Client { Ok(()) } + async fn send_sprinting_if_needed(&mut self) -> Result<(), MovePlayerError> { + let is_sprinting = self.entity().metadata.sprinting; + let was_sprinting = self.physics_state.lock().was_sprinting; + if is_sprinting != was_sprinting { + let sprinting_action = if is_sprinting { + azalea_protocol::packets::game::serverbound_player_command_packet::Action::StartSprinting + } else { + azalea_protocol::packets::game::serverbound_player_command_packet::Action::StopSprinting + }; + let player_entity_id = self.entity().id; + self.write_packet( + ServerboundPlayerCommandPacket { + id: player_entity_id, + action: sprinting_action, + data: 0, + } + .get(), + ) + .await?; + self.physics_state.lock().was_sprinting = is_sprinting; + } + + Ok(()) + } + // Set our current position to the provided Vec3, potentially clipping through blocks. pub async fn set_pos(&mut self, new_pos: Vec3) -> Result<(), MovePlayerError> { - let player_lock = self.player.lock(); - let mut dimension_lock = self.dimension.lock(); + let player_lock = self.player.write(); + let mut dimension_lock = self.dimension.write(); dimension_lock.set_entity_pos(player_lock.entity_id, new_pos)?; @@ -138,8 +162,8 @@ impl Client { } pub async fn move_entity(&mut self, movement: &Vec3) -> Result<(), MovePlayerError> { - let mut dimension_lock = self.dimension.lock(); - let player = self.player.lock(); + let mut dimension_lock = self.dimension.write(); + let player = self.player.write(); let mut entity = player .entity_mut(&mut dimension_lock) @@ -160,19 +184,38 @@ impl Client { pub fn ai_step(&mut self) { self.tick_controls(None); - let player_lock = self.player.lock(); - let mut dimension_lock = self.dimension.lock(); - let mut player_entity = player_lock - .entity_mut(&mut dimension_lock) - .expect("Player must exist"); - // server ai step { + let mut player_entity = self.entity_mut(); + let physics_state = self.physics_state.lock(); player_entity.xxa = physics_state.left_impulse; player_entity.zza = physics_state.forward_impulse; } + // TODO: food data and abilities + // let has_enough_food_to_sprint = self.food_data().food_level || self.abilities().may_fly; + let has_enough_food_to_sprint = true; + + // TODO: double tapping w to sprint i think + + let trying_to_sprint = self.physics_state.lock().trying_to_sprint; + + if !self.sprinting() + && ( + // !self.is_in_water() + // || self.is_underwater() && + self.has_enough_impulse_to_start_sprinting() + && has_enough_food_to_sprint + // && !self.using_item() + // && !self.has_effect(MobEffects.BLINDNESS) + && trying_to_sprint + ) + { + self.set_sprinting(true); + } + + let mut player_entity = self.entity_mut(); player_entity.ai_step(); } @@ -184,21 +227,21 @@ impl Client { let mut left_impulse: f32 = 0.; let move_direction = physics_state.move_direction; match move_direction { - MoveDirection::Forward | MoveDirection::ForwardRight | MoveDirection::ForwardLeft => { + WalkDirection::Forward | WalkDirection::ForwardRight | WalkDirection::ForwardLeft => { forward_impulse += 1.; } - MoveDirection::Backward - | MoveDirection::BackwardRight - | MoveDirection::BackwardLeft => { + WalkDirection::Backward + | WalkDirection::BackwardRight + | WalkDirection::BackwardLeft => { forward_impulse -= 1.; } _ => {} }; match move_direction { - MoveDirection::Right | MoveDirection::ForwardRight | MoveDirection::BackwardRight => { + WalkDirection::Right | WalkDirection::ForwardRight | WalkDirection::BackwardRight => { left_impulse += 1.; } - MoveDirection::Left | MoveDirection::ForwardLeft | MoveDirection::BackwardLeft => { + WalkDirection::Left | WalkDirection::ForwardLeft | WalkDirection::BackwardLeft => { left_impulse -= 1.; } _ => {} @@ -212,35 +255,90 @@ impl Client { } } - /// Start walking in the given direction. - pub fn walk(&mut self, direction: MoveDirection) { + /// Start walking in the given direction. To sprint, use + /// [`Client::sprint`]. To stop walking, call walk with + /// `WalkDirection::None`. + pub fn walk(&mut self, direction: WalkDirection) { + { + let mut physics_state = self.physics_state.lock(); + physics_state.move_direction = direction; + } + + self.set_sprinting(false); + } + + /// Start sprinting in the given direction. To stop moving, call + /// [`Client::walk(WalkDirection::None)`] + pub fn sprint(&mut self, direction: SprintDirection) { let mut physics_state = self.physics_state.lock(); - physics_state.move_direction = direction; + physics_state.move_direction = WalkDirection::from(direction); + physics_state.trying_to_sprint = true; + } + + // Whether we're currently sprinting. + pub fn sprinting(&self) -> bool { + self.entity().metadata.sprinting + } + + /// Change whether we're sprinting by adding an attribute modifier to the + /// player. You should use the [`walk`] and [`sprint`] methods instead. + /// Returns if the operation was successful. + fn set_sprinting(&mut self, sprinting: bool) -> bool { + let mut player_entity = self.entity_mut(); + player_entity.metadata.sprinting = sprinting; + if sprinting { + player_entity + .attributes + .speed + .insert(azalea_world::entity::attributes::sprinting_modifier()) + .is_ok() + } else { + player_entity + .attributes + .speed + .remove(&azalea_world::entity::attributes::sprinting_modifier().uuid) + .is_none() + } } - /// Toggle whether we're jumping. This acts as if you held space in + /// Set whether we're jumping. This acts as if you held space in /// vanilla. If you want to jump once, use the `jump` function. /// /// If you're making a realistic client, calling this function every tick is /// recommended. pub fn set_jumping(&mut self, jumping: bool) { - let mut dimension = self.dimension.lock(); - let mut player_entity = self.entity_mut(&mut dimension); - + let mut player_entity = self.entity_mut(); player_entity.jumping = jumping; } /// Returns whether the player will try to jump next tick. pub fn jumping(&self) -> bool { - let dimension = self.dimension.lock(); - let player_entity = self.entity(&dimension); + let player_entity = self.entity(); player_entity.jumping } + + /// Sets your rotation. `y_rot` is yaw (looking to the side), `x_rot` is + /// pitch (looking up and down). You can get these numbers from the vanilla + /// f3 screen. + pub fn set_rotation(&mut self, y_rot: f32, x_rot: f32) { + let mut player_entity = self.entity_mut(); + player_entity.set_rotation(y_rot, x_rot); + } + + // Whether the player is moving fast enough to be able to start sprinting. + fn has_enough_impulse_to_start_sprinting(&self) -> bool { + // if self.underwater() { + // self.has_forward_impulse() + // } else { + let physics_state = self.physics_state.lock(); + physics_state.forward_impulse > 0.8 + // } + } } #[derive(Clone, Copy, Debug, Default)] -pub enum MoveDirection { +pub enum WalkDirection { #[default] None, Forward, @@ -252,3 +350,21 @@ pub enum MoveDirection { BackwardRight, BackwardLeft, } + +/// The directions that we can sprint in. It's a subset of [`WalkDirection`]. +#[derive(Clone, Copy, Debug)] +pub enum SprintDirection { + Forward, + ForwardRight, + ForwardLeft, +} + +impl From<SprintDirection> for WalkDirection { + fn from(d: SprintDirection) -> Self { + match d { + SprintDirection::Forward => WalkDirection::Forward, + SprintDirection::ForwardRight => WalkDirection::ForwardRight, + SprintDirection::ForwardLeft => WalkDirection::ForwardLeft, + } + } +} |
