aboutsummaryrefslogtreecommitdiff
path: root/azalea-client/src/movement.rs
diff options
context:
space:
mode:
authormat <27899617+mat-1@users.noreply.github.com>2022-11-12 23:54:05 -0600
committerGitHub <noreply@github.com>2022-11-12 23:54:05 -0600
commit6eee543a3367d38a6f0e9bffb457a2bd76a8f9cc (patch)
treea5e493ccd7ec24293b8d866242c3836146517122 /azalea-client/src/movement.rs
parentfa57d03627aa20b1df44caed7cb025b6db1d9b53 (diff)
downloadazalea-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.rs192
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,
+ }
+ }
+}