mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 23:44:38 +00:00
update movement code for 1.21.5 changes
fixes grim flags
This commit is contained in:
parent
45f89b48e4
commit
302752860c
7 changed files with 156 additions and 31 deletions
|
@ -1,6 +1,9 @@
|
||||||
use std::{backtrace::Backtrace, io};
|
use std::{backtrace::Backtrace, io};
|
||||||
|
|
||||||
use azalea_core::{position::Vec3, tick::GameTick};
|
use azalea_core::{
|
||||||
|
position::{Vec2, Vec3},
|
||||||
|
tick::GameTick,
|
||||||
|
};
|
||||||
use azalea_entity::{
|
use azalea_entity::{
|
||||||
Attributes, InLoadedChunk, Jumping, LastSentPosition, LookDirection, Physics, Position,
|
Attributes, InLoadedChunk, Jumping, LastSentPosition, LookDirection, Physics, Position,
|
||||||
metadata::Sprinting,
|
metadata::Sprinting,
|
||||||
|
@ -137,8 +140,7 @@ pub struct PhysicsState {
|
||||||
pub trying_to_sprint: bool,
|
pub trying_to_sprint: bool,
|
||||||
|
|
||||||
pub move_direction: WalkDirection,
|
pub move_direction: WalkDirection,
|
||||||
pub forward_impulse: f32,
|
pub move_vector: Vec2,
|
||||||
pub left_impulse: f32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
|
@ -308,12 +310,10 @@ pub fn send_sprinting_if_needed(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the impulse from self.move_direction. The multiplier is used for
|
/// Updates the [`PhysicsState::move_vector`] based on the
|
||||||
/// sneaking.
|
/// [`PhysicsState::move_direction`].
|
||||||
pub(crate) fn tick_controls(mut query: Query<&mut PhysicsState>) {
|
pub(crate) fn tick_controls(mut query: Query<&mut PhysicsState>) {
|
||||||
for mut physics_state in query.iter_mut() {
|
for mut physics_state in query.iter_mut() {
|
||||||
let multiplier: Option<f32> = None;
|
|
||||||
|
|
||||||
let mut forward_impulse: f32 = 0.;
|
let mut forward_impulse: f32 = 0.;
|
||||||
let mut left_impulse: f32 = 0.;
|
let mut left_impulse: f32 = 0.;
|
||||||
let move_direction = physics_state.move_direction;
|
let move_direction = physics_state.move_direction;
|
||||||
|
@ -337,13 +337,9 @@ pub(crate) fn tick_controls(mut query: Query<&mut PhysicsState>) {
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
physics_state.forward_impulse = forward_impulse;
|
|
||||||
physics_state.left_impulse = left_impulse;
|
|
||||||
|
|
||||||
if let Some(multiplier) = multiplier {
|
let move_vector = Vec2::new(left_impulse, forward_impulse).normalized();
|
||||||
physics_state.forward_impulse *= multiplier;
|
physics_state.move_vector = move_vector;
|
||||||
physics_state.left_impulse *= multiplier;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,8 +353,12 @@ pub fn local_player_ai_step(
|
||||||
) {
|
) {
|
||||||
for (physics_state, mut physics, mut sprinting, mut attributes) in query.iter_mut() {
|
for (physics_state, mut physics, mut sprinting, mut attributes) in query.iter_mut() {
|
||||||
// server ai step
|
// server ai step
|
||||||
physics.x_acceleration = physics_state.left_impulse;
|
|
||||||
physics.z_acceleration = physics_state.forward_impulse;
|
// TODO: replace those booleans when using items, passengers, and sneaking are
|
||||||
|
// properly implemented
|
||||||
|
let move_vector = modify_input(physics_state.move_vector, false, false, false, &attributes);
|
||||||
|
physics.x_acceleration = move_vector.x;
|
||||||
|
physics.z_acceleration = move_vector.y;
|
||||||
|
|
||||||
// TODO: food data and abilities
|
// TODO: food data and abilities
|
||||||
// let has_enough_food_to_sprint = self.food_data().food_level ||
|
// let has_enough_food_to_sprint = self.food_data().food_level ||
|
||||||
|
@ -385,6 +385,47 @@ pub fn local_player_ai_step(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LocalPlayer.modifyInput
|
||||||
|
fn modify_input(
|
||||||
|
mut move_vector: Vec2,
|
||||||
|
is_using_item: bool,
|
||||||
|
is_passenger: bool,
|
||||||
|
moving_slowly: bool,
|
||||||
|
attributes: &Attributes,
|
||||||
|
) -> Vec2 {
|
||||||
|
if move_vector.length_squared() == 0. {
|
||||||
|
return move_vector;
|
||||||
|
}
|
||||||
|
|
||||||
|
move_vector *= 0.98;
|
||||||
|
if is_using_item && !is_passenger {
|
||||||
|
move_vector *= 0.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if moving_slowly {
|
||||||
|
let sneaking_speed = attributes.sneaking_speed.calculate() as f32;
|
||||||
|
move_vector *= sneaking_speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
modify_input_speed_for_square_movement(move_vector)
|
||||||
|
}
|
||||||
|
fn modify_input_speed_for_square_movement(move_vector: Vec2) -> Vec2 {
|
||||||
|
let length = move_vector.length();
|
||||||
|
if length == 0. {
|
||||||
|
return move_vector;
|
||||||
|
}
|
||||||
|
let scaled_to_inverse_length = move_vector * (1. / length);
|
||||||
|
let dist = distance_to_unit_square(scaled_to_inverse_length);
|
||||||
|
let scale = (length * dist).min(1.);
|
||||||
|
scaled_to_inverse_length * scale
|
||||||
|
}
|
||||||
|
fn distance_to_unit_square(v: Vec2) -> f32 {
|
||||||
|
let x = v.x.abs();
|
||||||
|
let y = v.y.abs();
|
||||||
|
let ratio = if y > x { x / y } else { y / x };
|
||||||
|
(1.0 + ratio * ratio).sqrt()
|
||||||
|
}
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
/// Start walking in the given direction. To sprint, use
|
/// Start walking in the given direction. To sprint, use
|
||||||
/// [`Client::sprint`]. To stop walking, call walk with
|
/// [`Client::sprint`]. To stop walking, call walk with
|
||||||
|
@ -508,7 +549,7 @@ fn has_enough_impulse_to_start_sprinting(physics_state: &PhysicsState) -> bool {
|
||||||
// if self.underwater() {
|
// if self.underwater() {
|
||||||
// self.has_forward_impulse()
|
// self.has_forward_impulse()
|
||||||
// } else {
|
// } else {
|
||||||
physics_state.forward_impulse > 0.8
|
physics_state.move_vector.y > 0.8
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -151,6 +151,10 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const fn new_with_data(data: [u8; bits_to_bytes(N)]) -> Self {
|
||||||
|
FixedBitSet { data }
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn index(&self, index: usize) -> bool {
|
pub fn index(&self, index: usize) -> bool {
|
||||||
(self.data[index / 8] & (1u8 << (index % 8))) != 0
|
(self.data[index / 8] & (1u8 << (index % 8))) != 0
|
||||||
|
|
|
@ -818,6 +818,66 @@ impl fmt::Display for Vec3 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A 2D vector.
|
||||||
|
#[derive(Clone, Copy, Debug, Default, PartialEq, AzBuf)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
|
pub struct Vec2 {
|
||||||
|
pub x: f32,
|
||||||
|
pub y: f32,
|
||||||
|
}
|
||||||
|
impl Vec2 {
|
||||||
|
const ZERO: Vec2 = Vec2 { x: 0.0, y: 0.0 };
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn new(x: f32, y: f32) -> Self {
|
||||||
|
Vec2 { x, y }
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn scale(&self, amount: f32) -> Self {
|
||||||
|
Vec2 {
|
||||||
|
x: self.x * amount,
|
||||||
|
y: self.y * amount,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn dot(&self, other: Vec2) -> f32 {
|
||||||
|
self.x * other.x + self.y * other.y
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn normalized(&self) -> Self {
|
||||||
|
let length = (self.x * self.x + self.y * self.y).sqrt();
|
||||||
|
if length < 1e-4 {
|
||||||
|
return Vec2::ZERO;
|
||||||
|
}
|
||||||
|
Vec2 {
|
||||||
|
x: self.x / length,
|
||||||
|
y: self.y / length,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn length_squared(&self) -> f32 {
|
||||||
|
self.x * self.x + self.y * self.y
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn length(&self) -> f32 {
|
||||||
|
self.length_squared().sqrt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Mul<f32> for Vec2 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn mul(self, rhs: f32) -> Self::Output {
|
||||||
|
self.scale(rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl MulAssign<f32> for Vec2 {
|
||||||
|
#[inline]
|
||||||
|
fn mul_assign(&mut self, rhs: f32) {
|
||||||
|
*self = self.scale(rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const PACKED_X_LENGTH: u64 = 1 + 25; // minecraft does something a bit more complicated to get this 25
|
const PACKED_X_LENGTH: u64 = 1 + 25; // minecraft does something a bit more complicated to get this 25
|
||||||
const PACKED_Z_LENGTH: u64 = PACKED_X_LENGTH;
|
const PACKED_Z_LENGTH: u64 = PACKED_X_LENGTH;
|
||||||
const PACKED_Y_LENGTH: u64 = 64 - PACKED_X_LENGTH - PACKED_Z_LENGTH;
|
const PACKED_Y_LENGTH: u64 = 64 - PACKED_X_LENGTH - PACKED_Z_LENGTH;
|
||||||
|
|
|
@ -10,6 +10,7 @@ use thiserror::Error;
|
||||||
#[derive(Clone, Debug, Component)]
|
#[derive(Clone, Debug, Component)]
|
||||||
pub struct Attributes {
|
pub struct Attributes {
|
||||||
pub speed: AttributeInstance,
|
pub speed: AttributeInstance,
|
||||||
|
pub sneaking_speed: AttributeInstance,
|
||||||
pub attack_speed: AttributeInstance,
|
pub attack_speed: AttributeInstance,
|
||||||
pub water_movement_efficiency: AttributeInstance,
|
pub water_movement_efficiency: AttributeInstance,
|
||||||
|
|
||||||
|
@ -92,7 +93,7 @@ pub enum AttributeModifierOperation {
|
||||||
pub fn sprinting_modifier() -> AttributeModifier {
|
pub fn sprinting_modifier() -> AttributeModifier {
|
||||||
AttributeModifier {
|
AttributeModifier {
|
||||||
id: ResourceLocation::new("sprinting"),
|
id: ResourceLocation::new("sprinting"),
|
||||||
amount: 0.30000001192092896,
|
amount: 0.3f32 as f64,
|
||||||
operation: AttributeModifierOperation::MultiplyTotal,
|
operation: AttributeModifierOperation::MultiplyTotal,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,10 +50,10 @@ pub fn move_relative(
|
||||||
|
|
||||||
pub fn input_vector(direction: LookDirection, speed: f32, acceleration: Vec3) -> Vec3 {
|
pub fn input_vector(direction: LookDirection, speed: f32, acceleration: Vec3) -> Vec3 {
|
||||||
let distance = acceleration.length_squared();
|
let distance = acceleration.length_squared();
|
||||||
if distance < 1.0E-7 {
|
if distance < 1.0e-7 {
|
||||||
return Vec3::ZERO;
|
return Vec3::ZERO;
|
||||||
}
|
}
|
||||||
let acceleration = if distance > 1.0 {
|
let acceleration = if distance > 1. {
|
||||||
acceleration.normalize()
|
acceleration.normalize()
|
||||||
} else {
|
} else {
|
||||||
acceleration
|
acceleration
|
||||||
|
@ -492,6 +492,7 @@ pub fn default_attributes(_entity_kind: EntityKind) -> Attributes {
|
||||||
// entities have different defaults
|
// entities have different defaults
|
||||||
Attributes {
|
Attributes {
|
||||||
speed: AttributeInstance::new(0.1),
|
speed: AttributeInstance::new(0.1),
|
||||||
|
sneaking_speed: AttributeInstance::new(0.3),
|
||||||
attack_speed: AttributeInstance::new(4.0),
|
attack_speed: AttributeInstance::new(4.0),
|
||||||
water_movement_efficiency: AttributeInstance::new(0.0),
|
water_movement_efficiency: AttributeInstance::new(0.0),
|
||||||
block_interaction_range: AttributeInstance::new(4.5),
|
block_interaction_range: AttributeInstance::new(4.5),
|
||||||
|
|
|
@ -15,10 +15,10 @@ use azalea_core::{
|
||||||
tick::GameTick,
|
tick::GameTick,
|
||||||
};
|
};
|
||||||
use azalea_entity::{
|
use azalea_entity::{
|
||||||
Attributes, InLoadedChunk, Jumping, LocalEntity, LookDirection, OnClimbable, Physics, Pose,
|
Attributes, EntityKindComponent, InLoadedChunk, Jumping, LocalEntity, LookDirection,
|
||||||
Position, metadata::Sprinting, move_relative,
|
OnClimbable, Physics, Pose, Position, metadata::Sprinting, move_relative,
|
||||||
};
|
};
|
||||||
use azalea_registry::Block;
|
use azalea_registry::{Block, EntityKind};
|
||||||
use azalea_world::{Instance, InstanceContainer, InstanceName};
|
use azalea_world::{Instance, InstanceContainer, InstanceName};
|
||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
|
@ -66,12 +66,17 @@ pub fn ai_step(
|
||||||
&LookDirection,
|
&LookDirection,
|
||||||
&Sprinting,
|
&Sprinting,
|
||||||
&InstanceName,
|
&InstanceName,
|
||||||
|
&EntityKindComponent,
|
||||||
),
|
),
|
||||||
(With<LocalEntity>, With<InLoadedChunk>),
|
(With<LocalEntity>, With<InLoadedChunk>),
|
||||||
>,
|
>,
|
||||||
instance_container: Res<InstanceContainer>,
|
instance_container: Res<InstanceContainer>,
|
||||||
) {
|
) {
|
||||||
for (mut physics, jumping, position, look_direction, sprinting, instance_name) in &mut query {
|
for (mut physics, jumping, position, look_direction, sprinting, instance_name, entity_kind) in
|
||||||
|
&mut query
|
||||||
|
{
|
||||||
|
let is_player = **entity_kind == EntityKind::Player;
|
||||||
|
|
||||||
// vanilla does movement interpolation here, doesn't really matter much for a
|
// vanilla does movement interpolation here, doesn't really matter much for a
|
||||||
// bot though
|
// bot though
|
||||||
|
|
||||||
|
@ -79,14 +84,29 @@ pub fn ai_step(
|
||||||
physics.no_jump_delay -= 1;
|
physics.no_jump_delay -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if physics.velocity.x.abs() < 0.003 {
|
if is_player {
|
||||||
physics.velocity.x = 0.;
|
if physics.velocity.horizontal_distance_squared() < 9.0e-6 {
|
||||||
|
physics.velocity.x = 0.;
|
||||||
|
physics.velocity.z = 0.;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if physics.velocity.x.abs() < 0.003 {
|
||||||
|
physics.velocity.x = 0.;
|
||||||
|
}
|
||||||
|
if physics.velocity.z.abs() < 0.003 {
|
||||||
|
physics.velocity.z = 0.;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if physics.velocity.y.abs() < 0.003 {
|
if physics.velocity.y.abs() < 0.003 {
|
||||||
physics.velocity.y = 0.;
|
physics.velocity.y = 0.;
|
||||||
}
|
}
|
||||||
if physics.velocity.z.abs() < 0.003 {
|
|
||||||
physics.velocity.z = 0.;
|
if is_player {
|
||||||
|
// handled in local_player_ai_step
|
||||||
|
} else {
|
||||||
|
physics.x_acceleration *= 0.98;
|
||||||
|
physics.z_acceleration *= 0.98;
|
||||||
}
|
}
|
||||||
|
|
||||||
if jumping == Some(&Jumping(true)) {
|
if jumping == Some(&Jumping(true)) {
|
||||||
|
@ -128,9 +148,6 @@ pub fn ai_step(
|
||||||
physics.no_jump_delay = 0;
|
physics.no_jump_delay = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
physics.x_acceleration *= 0.98;
|
|
||||||
physics.z_acceleration *= 0.98;
|
|
||||||
|
|
||||||
// TODO: freezing, pushEntities, drowning damage (in their own systems,
|
// TODO: freezing, pushEntities, drowning damage (in their own systems,
|
||||||
// after `travel`)
|
// after `travel`)
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,8 @@ fn apply_change<T: Add<Output = T>>(base: T, condition: bool, change: T) -> T {
|
||||||
impl AzaleaRead for RelativeMovements {
|
impl AzaleaRead for RelativeMovements {
|
||||||
fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
||||||
// yes minecraft seriously wastes that many bits, smh
|
// yes minecraft seriously wastes that many bits, smh
|
||||||
let set = FixedBitSet::<32>::azalea_read(buf)?;
|
let set = u32::azalea_read(buf)?;
|
||||||
|
let set = FixedBitSet::<32>::new_with_data(set.swap_bytes().to_be_bytes());
|
||||||
Ok(RelativeMovements {
|
Ok(RelativeMovements {
|
||||||
x: set.index(0),
|
x: set.index(0),
|
||||||
y: set.index(1),
|
y: set.index(1),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue