1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 23:44:38 +00:00

make physicsstate its own component

This commit is contained in:
Ubuntu 2023-01-12 02:24:18 +00:00
commit 473b9f9297
5 changed files with 141 additions and 104 deletions

View file

@ -1,6 +1,6 @@
pub use crate::chat::ChatPacket; pub use crate::chat::ChatPacket;
use crate::{ use crate::{
local_player::{death_event, send_tick_event, update_in_loaded_chunk, LocalPlayer}, local_player::{death_event, send_tick_event, update_in_loaded_chunk, LocalPlayer, PhysicsState},
movement::{local_player_ai_step, send_position}, movement::{local_player_ai_step, send_position},
packet_handling, packet_handling,
plugins::PluginStates, plugins::PluginStates,
@ -223,7 +223,7 @@ impl Client {
local_player.tasks.push(write_packets_task); local_player.tasks.push(write_packets_task);
ecs.entity_mut(entity) ecs.entity_mut(entity)
.insert((local_player, packet_receiver)); .insert((local_player, packet_receiver, PhysicsState::default()));
// just start up the game loop and we're ready! // just start up the game loop and we're ready!

View file

@ -22,8 +22,6 @@ pub struct LocalPlayer {
pub packet_writer: mpsc::UnboundedSender<ServerboundGamePacket>, pub packet_writer: mpsc::UnboundedSender<ServerboundGamePacket>,
// pub world: Arc<RwLock<PartialWorld>>,
pub physics_state: PhysicsState,
pub client_information: ClientInformation, pub client_information: ClientInformation,
/// A map of player uuids to their information in the tab list /// A map of player uuids to their information in the tab list
pub players: HashMap<Uuid, PlayerInfo>, pub players: HashMap<Uuid, PlayerInfo>,
@ -43,7 +41,9 @@ pub struct LocalPlayer {
pub(crate) tasks: Vec<JoinHandle<()>>, pub(crate) tasks: Vec<JoinHandle<()>>,
} }
#[derive(Default)] /// Component for entities that can move and sprint. Usually only in
/// [`LocalPlayer`] entities.
#[derive(Default, Component)]
pub struct PhysicsState { pub struct PhysicsState {
/// Minecraft only sends a movement packet either after 20 ticks or if the /// Minecraft only sends a movement packet either after 20 ticks or if the
/// player moved enough. This is that tick counter. /// player moved enough. This is that tick counter.
@ -83,7 +83,6 @@ impl LocalPlayer {
packet_writer, packet_writer,
physics_state: PhysicsState::default(),
client_information: ClientInformation::default(), client_information: ClientInformation::default(),
players: HashMap::new(), players: HashMap::new(),

View file

@ -7,7 +7,8 @@ use azalea_protocol::packets::game::{
serverbound_move_player_rot_packet::ServerboundMovePlayerRotPacket, serverbound_move_player_rot_packet::ServerboundMovePlayerRotPacket,
serverbound_move_player_status_only_packet::ServerboundMovePlayerStatusOnlyPacket, serverbound_move_player_status_only_packet::ServerboundMovePlayerStatusOnlyPacket,
}; };
use azalea_world::entity::MinecraftEntityId; use azalea_world::entity::metadata::Sprinting;
use azalea_world::entity::{Attributes, MinecraftEntityId};
use azalea_world::{entity, MoveEntityError}; use azalea_world::{entity, MoveEntityError};
use bevy_ecs::system::Query; use bevy_ecs::system::Query;
use std::backtrace::Backtrace; use std::backtrace::Backtrace;
@ -39,7 +40,7 @@ impl Client {
/// recommended. /// recommended.
pub fn set_jumping(&mut self, jumping: bool) { pub fn set_jumping(&mut self, jumping: bool) {
let mut ecs = self.ecs.lock(); let mut ecs = self.ecs.lock();
let mut physics = self.query::<&mut entity::Physics>(&mut ecs).into_inner(); let mut physics = self.query::<&mut entity::Physics>(&mut ecs);
physics.jumping = jumping; physics.jumping = jumping;
} }
@ -67,6 +68,7 @@ pub(crate) fn send_position(
( (
&MinecraftEntityId, &MinecraftEntityId,
&mut LocalPlayer, &mut LocalPlayer,
&mut PhysicsState,
&entity::Position, &entity::Position,
&mut entity::LastSentPosition, &mut entity::LastSentPosition,
&mut entity::Physics, &mut entity::Physics,
@ -75,10 +77,17 @@ pub(crate) fn send_position(
&LocalPlayerInLoadedChunk, &LocalPlayerInLoadedChunk,
>, >,
) { ) {
for (id, mut local_player, position, mut last_sent_position, mut physics, sprinting) in for (
query.iter_mut() id,
mut local_player,
mut physics_state,
position,
mut last_sent_position,
mut physics,
sprinting,
) in query.iter_mut()
{ {
local_player.send_sprinting_if_needed(id, sprinting); local_player.send_sprinting_if_needed(id, sprinting, &mut physics_state);
let packet = { let packet = {
// TODO: the camera being able to be controlled by other entities isn't // TODO: the camera being able to be controlled by other entities isn't
@ -90,13 +99,13 @@ pub(crate) fn send_position(
let y_rot_delta = (physics.y_rot - physics.y_rot_last) as f64; let y_rot_delta = (physics.y_rot - physics.y_rot_last) as f64;
let x_rot_delta = (physics.x_rot - physics.x_rot_last) as f64; let x_rot_delta = (physics.x_rot - physics.x_rot_last) as f64;
local_player.physics_state.position_remainder += 1; physics_state.position_remainder += 1;
// boolean sendingPosition = Mth.lengthSquared(xDelta, yDelta, zDelta) > // boolean sendingPosition = Mth.lengthSquared(xDelta, yDelta, zDelta) >
// Mth.square(2.0E-4D) || this.positionReminder >= 20; // Mth.square(2.0E-4D) || this.positionReminder >= 20;
let sending_position = ((x_delta.powi(2) + y_delta.powi(2) + z_delta.powi(2)) let sending_position = ((x_delta.powi(2) + y_delta.powi(2) + z_delta.powi(2))
> 2.0e-4f64.powi(2)) > 2.0e-4f64.powi(2))
|| local_player.physics_state.position_remainder >= 20; || physics_state.position_remainder >= 20;
let sending_rotation = y_rot_delta != 0.0 || x_rot_delta != 0.0; let sending_rotation = y_rot_delta != 0.0 || x_rot_delta != 0.0;
// if self.is_passenger() { // if self.is_passenger() {
@ -146,7 +155,7 @@ pub(crate) fn send_position(
if sending_position { if sending_position {
**last_sent_position = **position; **last_sent_position = **position;
local_player.physics_state.position_remainder = 0; physics_state.position_remainder = 0;
} }
if sending_rotation { if sending_rotation {
physics.y_rot_last = physics.y_rot; physics.y_rot_last = physics.y_rot;
@ -170,8 +179,9 @@ impl LocalPlayer {
&mut self, &mut self,
id: &MinecraftEntityId, id: &MinecraftEntityId,
sprinting: &entity::metadata::Sprinting, sprinting: &entity::metadata::Sprinting,
physics_state: &mut PhysicsState,
) { ) {
let was_sprinting = self.physics_state.was_sprinting; let was_sprinting = physics_state.was_sprinting;
if **sprinting != was_sprinting { if **sprinting != was_sprinting {
let sprinting_action = if **sprinting { let sprinting_action = if **sprinting {
azalea_protocol::packets::game::serverbound_player_command_packet::Action::StartSprinting azalea_protocol::packets::game::serverbound_player_command_packet::Action::StartSprinting
@ -186,7 +196,7 @@ impl LocalPlayer {
} }
.get(), .get(),
); );
self.physics_state.was_sprinting = **sprinting; physics_state.was_sprinting = **sprinting;
} }
} }
@ -224,84 +234,6 @@ impl LocalPlayer {
physics_state.left_impulse *= multiplier; physics_state.left_impulse *= multiplier;
} }
} }
/// Start walking in the given direction. To sprint, use
/// [`Client::sprint`]. To stop walking, call walk with
/// `WalkDirection::None`.
///
/// # Examples
///
/// Walk for 1 second
/// ```rust,no_run
/// # use azalea_client::{Client, WalkDirection};
/// # use std::time::Duration;
/// # async fn example(mut bot: Client) {
/// bot.walk(WalkDirection::Forward);
/// tokio::time::sleep(Duration::from_secs(1)).await;
/// bot.walk(WalkDirection::None);
/// # }
/// ```
pub fn walk(
direction: WalkDirection,
physics_state: &mut PhysicsState,
sprinting: &mut entity::metadata::Sprinting,
attributes: &mut entity::Attributes,
) {
physics_state.move_direction = direction;
Self::set_sprinting(false, sprinting, attributes);
}
/// Start sprinting in the given direction. To stop moving, call
/// [`Client::walk(WalkDirection::None)`]
///
/// # Examples
///
/// Sprint for 1 second
/// ```rust,no_run
/// # use azalea_client::{Client, WalkDirection, SprintDirection};
/// # use std::time::Duration;
/// # async fn example(mut bot: Client) {
/// bot.sprint(SprintDirection::Forward);
/// tokio::time::sleep(Duration::from_secs(1)).await;
/// bot.walk(WalkDirection::None);
/// # }
/// ```
pub fn sprint(&mut self, direction: SprintDirection, physics_state: &mut PhysicsState) {
physics_state.move_direction = WalkDirection::from(direction);
physics_state.trying_to_sprint = true;
}
/// 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(
sprinting: bool,
currently_sprinting: &mut entity::metadata::Sprinting,
attributes: &mut entity::Attributes,
) -> bool {
**currently_sprinting = sprinting;
if sprinting {
attributes
.speed
.insert(entity::attributes::sprinting_modifier())
.is_ok()
} else {
attributes
.speed
.remove(&entity::attributes::sprinting_modifier().uuid)
.is_none()
}
}
// Whether the player is moving fast enough to be able to start sprinting.
fn has_enough_impulse_to_start_sprinting(physics_state: &PhysicsState) -> bool {
// if self.underwater() {
// self.has_forward_impulse()
// } else {
physics_state.forward_impulse > 0.8
// }
}
} }
/// Makes the bot do one physics tick. Note that this is already handled /// Makes the bot do one physics tick. Note that this is already handled
@ -310,6 +242,7 @@ pub fn local_player_ai_step(
mut query: Query< mut query: Query<
( (
&mut LocalPlayer, &mut LocalPlayer,
&mut PhysicsState,
&mut entity::Physics, &mut entity::Physics,
&mut entity::Position, &mut entity::Position,
&mut entity::metadata::Sprinting, &mut entity::metadata::Sprinting,
@ -319,12 +252,16 @@ pub fn local_player_ai_step(
>, >,
) { ) {
println!("local_player_ai_step"); println!("local_player_ai_step");
for (mut local_player, mut physics, mut position, mut sprinting, mut attributes) in for (
query.iter_mut() local_player,
mut physics_state,
mut physics,
mut position,
mut sprinting,
mut attributes,
) in query.iter_mut()
{ {
let physics_state = &mut local_player.physics_state; LocalPlayer::tick_controls(None, &mut physics_state);
LocalPlayer::tick_controls(None, physics_state);
// server ai step // server ai step
physics.xxa = physics_state.left_impulse; physics.xxa = physics_state.left_impulse;
@ -343,14 +280,14 @@ pub fn local_player_ai_step(
&& ( && (
// !self.is_in_water() // !self.is_in_water()
// || self.is_underwater() && // || self.is_underwater() &&
LocalPlayer::has_enough_impulse_to_start_sprinting(physics_state) has_enough_impulse_to_start_sprinting(&physics_state)
&& has_enough_food_to_sprint && has_enough_food_to_sprint
// && !self.using_item() // && !self.using_item()
// && !self.has_effect(MobEffects.BLINDNESS) // && !self.has_effect(MobEffects.BLINDNESS)
&& trying_to_sprint && trying_to_sprint
) )
{ {
LocalPlayer::set_sprinting(true, &mut sprinting, &mut attributes); set_sprinting(true, &mut sprinting, &mut attributes);
} }
azalea_physics::ai_step( azalea_physics::ai_step(
@ -363,6 +300,107 @@ pub fn local_player_ai_step(
} }
} }
impl Client {
/// Start walking in the given direction. To sprint, use
/// [`Client::sprint`]. To stop walking, call walk with
/// `WalkDirection::None`.
///
/// # Examples
///
/// Walk for 1 second
/// ```rust,no_run
/// # use azalea_client::{Client, WalkDirection};
/// # use std::time::Duration;
/// # async fn example(mut bot: Client) {
/// bot.walk(WalkDirection::Forward);
/// tokio::time::sleep(Duration::from_secs(1)).await;
/// bot.walk(WalkDirection::None);
/// # }
/// ```
pub fn walk(&mut self, direction: WalkDirection) {
let mut ecs = self.ecs.lock();
let (mut physics_state, mut sprinting, mut attributes) =
self.query::<(&mut PhysicsState, &mut Sprinting, &mut Attributes)>(&mut ecs);
walk(
direction,
&mut physics_state,
&mut sprinting,
&mut attributes,
)
}
/// Start sprinting in the given direction. To stop moving, call
/// [`Client::walk(WalkDirection::None)`]
///
/// # Examples
///
/// Sprint for 1 second
/// ```rust,no_run
/// # use azalea_client::{Client, WalkDirection, SprintDirection};
/// # use std::time::Duration;
/// # async fn example(mut bot: Client) {
/// bot.sprint(SprintDirection::Forward);
/// tokio::time::sleep(Duration::from_secs(1)).await;
/// bot.walk(WalkDirection::None);
/// # }
/// ```
pub fn sprint(&mut self, direction: SprintDirection) {
let mut ecs = self.ecs.lock();
let mut physics_state = self.query::<&mut PhysicsState>(&mut ecs);
sprint(direction, &mut physics_state);
}
}
/// Start walking in the given direction. To sprint, use
/// [`Client::sprint`]. To stop walking, call walk with
/// `WalkDirection::None`.
pub fn walk(
direction: WalkDirection,
physics_state: &mut PhysicsState,
sprinting: &mut entity::metadata::Sprinting,
attributes: &mut entity::Attributes,
) {
physics_state.move_direction = direction;
set_sprinting(false, sprinting, attributes);
}
/// Start sprinting in the given direction.
pub fn sprint(direction: SprintDirection, physics_state: &mut PhysicsState) {
physics_state.move_direction = WalkDirection::from(direction);
physics_state.trying_to_sprint = true;
}
/// 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(
sprinting: bool,
currently_sprinting: &mut entity::metadata::Sprinting,
attributes: &mut entity::Attributes,
) -> bool {
**currently_sprinting = sprinting;
if sprinting {
attributes
.speed
.insert(entity::attributes::sprinting_modifier())
.is_ok()
} else {
attributes
.speed
.remove(&entity::attributes::sprinting_modifier().uuid)
.is_none()
}
}
// Whether the player is moving fast enough to be able to start sprinting.
fn has_enough_impulse_to_start_sprinting(physics_state: &PhysicsState) -> bool {
// if self.underwater() {
// self.has_forward_impulse()
// } else {
physics_state.forward_impulse > 0.8
// }
}
#[derive(Clone, Copy, Debug, Default)] #[derive(Clone, Copy, Debug, Default)]
pub enum WalkDirection { pub enum WalkDirection {
#[default] #[default]

View file

@ -61,7 +61,7 @@ fn handle_packets(
mut mut_local_player_query: Query<&mut LocalPlayer>, mut mut_local_player_query: Query<&mut LocalPlayer>,
mut mut_health_query: Query<&mut Health>, mut mut_health_query: Query<&mut Health>,
mut mut_position_query: Query<&mut Position>, mut mut_position_query: Query<&mut Position>,
combat_kill_query: Query<(&MinecraftEntityId, Option<&Dead>)>, combat_kill_query: Query<(&MinecraftEntityId, Option<&Dead>)>,
mut position_query: Query<( mut position_query: Query<(
&mut LocalPlayer, &mut LocalPlayer,
@ -279,7 +279,7 @@ fn handle_packets(
// we call a function instead of setting the fields ourself since the // we call a function instead of setting the fields ourself since the
// function makes sure the rotations stay in their // function makes sure the rotations stay in their
// ranges // ranges
set_rotation(physics.into_inner(), y_rot, x_rot); set_rotation(&mut physics, y_rot, x_rot);
// TODO: minecraft sets "xo", "yo", and "zo" here but idk what that means // TODO: minecraft sets "xo", "yo", and "zo" here but idk what that means
// so investigate that ig // so investigate that ig
let new_pos = Vec3 { let new_pos = Vec3 {

View file

@ -432,7 +432,7 @@ where
/// } /// }
/// ``` /// ```
fn into_iter(self) -> Self::IntoIter { fn into_iter(self) -> Self::IntoIter {
self.bot_datas.lock().clone().into_iter() self.bot_datas.clone().lock().into_iter()
} }
} }