diff --git a/azalea-client/src/movement.rs b/azalea-client/src/movement.rs index 7eb7b958..351d91be 100644 --- a/azalea-client/src/movement.rs +++ b/azalea-client/src/movement.rs @@ -405,6 +405,7 @@ pub fn walk_listener( if let Ok((mut physics_state, mut sprinting, mut attributes)) = query.get_mut(event.entity) { physics_state.move_direction = event.direction; + physics_state.trying_to_sprint = false; set_sprinting(false, &mut sprinting, &mut attributes); } } diff --git a/azalea-core/src/lib.rs b/azalea-core/src/lib.rs index 8ed62b06..6554d71d 100755 --- a/azalea-core/src/lib.rs +++ b/azalea-core/src/lib.rs @@ -1,6 +1,7 @@ #![doc = include_str!("../README.md")] #![feature(int_roundings)] #![feature(const_for)] +#![feature(lazy_cell)] #![allow(incomplete_features)] #![feature(generic_const_exprs)] diff --git a/azalea-core/src/math.rs b/azalea-core/src/math.rs index 2e5e78f6..40d147e4 100644 --- a/azalea-core/src/math.rs +++ b/azalea-core/src/math.rs @@ -1,3 +1,27 @@ +use std::sync::LazyLock; + +pub static SIN: LazyLock<[f32; 65536]> = LazyLock::new(|| { + let mut sin = [0.0; 65536]; + for i in 0..65536 { + sin[i] = f64::sin((i as f64) * 3.141592653589793 * 2.0 / 65536.0) as f32; + } + sin +}); + +/// A sine function that uses a lookup table. +pub fn sin(var0: f32) -> f32 { + let var0 = var0 * 10430.378; + let var0 = var0 as usize; + SIN[var0 & 65535] +} + +/// A cosine function that uses a lookup table. +pub fn cos(var0: f32) -> f32 { + let var0 = var0 * 10430.378 + 16384.0; + let var0 = var0 as usize; + SIN[var0 & 65535] +} + // TODO: make this generic pub fn binary_search(mut min: i32, max: i32, predicate: &dyn Fn(i32) -> bool) -> i32 { let mut diff = max - min; diff --git a/azalea-entity/src/lib.rs b/azalea-entity/src/lib.rs index fc312f79..e13ec2f0 100644 --- a/azalea-entity/src/lib.rs +++ b/azalea-entity/src/lib.rs @@ -12,7 +12,7 @@ mod plugin; use self::attributes::AttributeInstance; pub use attributes::Attributes; use azalea_block::BlockState; -use azalea_core::{BlockPos, ChunkPos, ResourceLocation, Vec3, AABB}; +use azalea_core::{math, BlockPos, ChunkPos, ResourceLocation, Vec3, AABB}; use azalea_world::{ChunkStorage, InstanceName}; use bevy_ecs::{bundle::Bundle, component::Component}; pub use data::*; @@ -44,8 +44,8 @@ pub fn input_vector(direction: &LookDirection, speed: f32, acceleration: &Vec3) *acceleration } .scale(speed as f64); - let y_rot = f32::sin(direction.y_rot * 0.017453292f32); - let x_rot = f32::cos(direction.y_rot * 0.017453292f32); + let y_rot = math::sin(direction.y_rot * 0.017453292f32); + let x_rot = math::cos(direction.y_rot * 0.017453292f32); Vec3 { x: acceleration.x * (x_rot as f64) - acceleration.z * (y_rot as f64), y: acceleration.y, @@ -56,10 +56,10 @@ pub fn input_vector(direction: &LookDirection, speed: f32, acceleration: &Vec3) pub fn view_vector(look_direction: &LookDirection) -> Vec3 { let x_rot = look_direction.x_rot * 0.017453292; let y_rot = -look_direction.y_rot * 0.017453292; - let y_rot_cos = f32::cos(y_rot); - let y_rot_sin = f32::sin(y_rot); - let x_rot_cos = f32::cos(x_rot); - let x_rot_sin = f32::sin(x_rot); + let y_rot_cos = math::cos(y_rot); + let y_rot_sin = math::sin(y_rot); + let x_rot_cos = math::cos(x_rot); + let x_rot_sin = math::sin(x_rot); Vec3 { x: (y_rot_sin * x_rot_cos) as f64, y: (-x_rot_sin) as f64, diff --git a/azalea-physics/src/lib.rs b/azalea-physics/src/lib.rs index 673c425e..cad1c15f 100644 --- a/azalea-physics/src/lib.rs +++ b/azalea-physics/src/lib.rs @@ -5,7 +5,7 @@ pub mod clip; pub mod collision; use azalea_block::{Block, BlockState}; -use azalea_core::{BlockPos, Vec3}; +use azalea_core::{math, BlockPos, Vec3}; use azalea_entity::{ metadata::Sprinting, move_relative, Attributes, Jumping, Local, LookDirection, Physics, Position, @@ -30,8 +30,7 @@ pub struct PhysicsSet; pub struct PhysicsPlugin; impl Plugin for PhysicsPlugin { fn build(&self, app: &mut App) { - app.add_event::() - .add_systems(FixedUpdate, (ai_step, travel).chain().in_set(PhysicsSet)); + app.add_systems(FixedUpdate, (ai_step, travel).chain().in_set(PhysicsSet)); } } @@ -43,6 +42,7 @@ fn travel( &mut Physics, &mut LookDirection, &mut Position, + Option<&Sprinting>, &Attributes, &InstanceName, ), @@ -50,7 +50,7 @@ fn travel( >, instance_container: Res, ) { - for (mut physics, direction, mut position, attributes, world_name) in &mut query { + for (mut physics, direction, mut position, sprinting, attributes, world_name) in &mut query { let world_lock = instance_container .get(world_name) .expect("All entities should be in a valid world"); @@ -92,6 +92,7 @@ fn travel( &direction, &mut position, attributes, + sprinting.map(|s| **s).unwrap_or(false), ); movement.y -= gravity; @@ -108,7 +109,7 @@ fn travel( } else { physics.delta = Vec3 { x: movement.x * inertia as f64, - y: movement.y * 0.98f64, + y: movement.y * 0.9800000190734863f64, z: movement.z * inertia as f64, }; } @@ -120,7 +121,6 @@ fn travel( pub fn ai_step( mut query: Query< ( - Entity, &mut Physics, Option<&Jumping>, &Position, @@ -142,9 +142,7 @@ pub fn ai_step( // )>, instance_container: Res, ) { - for (entity, mut physics, jumping, position, look_direction, sprinting, instance_name) in - &mut query - { + for (mut physics, jumping, position, look_direction, sprinting, instance_name) in &mut query { // vanilla does movement interpolation here, doesn't really matter much for a // bot though @@ -183,10 +181,6 @@ pub fn ai_step( } } -/// Jump even if we aren't on the ground. -#[derive(Event)] -pub struct ForceJumpEvent(pub Entity); - pub fn jump_from_ground( physics: &mut Physics, position: &Position, @@ -211,9 +205,9 @@ pub fn jump_from_ground( // sprint jumping gives some extra velocity let y_rot = look_direction.y_rot * 0.017453292; physics.delta += Vec3 { - x: (-f32::sin(y_rot) * 0.2) as f64, + x: (-math::sin(y_rot) * 0.2) as f64, y: 0., - z: (f32::cos(y_rot) * 0.2) as f64, + z: (math::cos(y_rot) * 0.2) as f64, }; } @@ -236,11 +230,12 @@ fn handle_relative_friction_and_calculate_movement( direction: &LookDirection, position: &mut Position, attributes: &Attributes, + is_sprinting: bool, ) -> Vec3 { move_relative( physics, direction, - get_friction_influenced_speed(physics, attributes, block_friction), + get_friction_influenced_speed(physics, attributes, block_friction, is_sprinting), &Vec3 { x: physics.xxa as f64, y: physics.yya as f64, @@ -270,14 +265,23 @@ fn handle_relative_friction_and_calculate_movement( // private float getFrictionInfluencedSpeed(float friction) { // return this.onGround ? this.getSpeed() * (0.21600002F / (friction * // friction * friction)) : this.flyingSpeed; } -fn get_friction_influenced_speed(physics: &Physics, attributes: &Attributes, friction: f32) -> f32 { +fn get_friction_influenced_speed( + physics: &Physics, + attributes: &Attributes, + friction: f32, + is_sprinting: bool, +) -> f32 { // TODO: have speed & flying_speed fields in entity if physics.on_ground { let speed: f32 = attributes.speed.calculate() as f32; speed * (0.216f32 / (friction * friction * friction)) } else { // entity.flying_speed - 0.02 + if is_sprinting { + 0.025999999f32 + } else { + 0.02 + } } } diff --git a/azalea/examples/testbot.rs b/azalea/examples/testbot.rs index 14800e9c..630ddf00 100644 --- a/azalea/examples/testbot.rs +++ b/azalea/examples/testbot.rs @@ -11,6 +11,7 @@ use azalea::pathfinder::goals::BlockPosGoal; use azalea::protocol::packets::game::ClientboundGamePacket; use azalea::{prelude::*, swarm::prelude::*, BlockPos, GameProfileComponent, WalkDirection}; use azalea::{Account, Client, Event}; +use azalea_client::SprintDirection; use azalea_core::Vec3; use azalea_world::{InstanceName, MinecraftEntityId}; use std::time::Duration; @@ -145,6 +146,9 @@ async fn handle(mut bot: Client, event: Event, _state: State) -> anyhow::Result< "walk" => { bot.walk(WalkDirection::Forward); } + "sprint" => { + bot.sprint(SprintDirection::Forward); + } "stop" => { bot.set_jumping(false); bot.walk(WalkDirection::None);