1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 06:16:04 +00:00

use better pathfinder costs and also fix relative entity updates breaking sometimes

This commit is contained in:
mat 2023-08-26 22:19:10 -05:00
parent dea717b68e
commit 12118ebfa3
8 changed files with 71 additions and 36 deletions

View file

@ -290,7 +290,7 @@ pub fn remove_despawned_entities_from_indexes(
warn!("Tried to remove entity from chunk {chunk:?} but the entity was not there."); warn!("Tried to remove entity from chunk {chunk:?} but the entity was not there.");
} }
} else { } else {
warn!("Tried to remove entity from chunk {chunk:?} but the chunk was not found."); debug!("Tried to remove entity from chunk {chunk:?} but the chunk was not found.");
} }
// remove it from the uuid index // remove it from the uuid index
if entity_infos.entity_by_uuid.remove(uuid).is_none() { if entity_infos.entity_by_uuid.remove(uuid).is_none() {

View file

@ -59,7 +59,6 @@ impl Plugin for EntityPlugin {
) )
.in_set(EntityUpdateSet::Index), .in_set(EntityUpdateSet::Index),
( (
relative_updates::add_updates_received,
relative_updates::debug_detect_updates_received_on_local_entities, relative_updates::debug_detect_updates_received_on_local_entities,
debug_new_entity, debug_new_entity,
add_dead, add_dead,

View file

@ -20,8 +20,8 @@ use std::sync::Arc;
use azalea_world::{MinecraftEntityId, PartialInstance}; use azalea_world::{MinecraftEntityId, PartialInstance};
use bevy_ecs::{ use bevy_ecs::{
prelude::{Component, Entity}, prelude::{Component, Entity},
query::{Changed, With, Without}, query::With,
system::{Commands, EntityCommand, Query}, system::{EntityCommand, Query},
world::{EntityMut, World}, world::{EntityMut, World},
}; };
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
@ -69,24 +69,29 @@ impl EntityCommand for RelativeEntityUpdate {
}; };
let entity_id = *entity_mut.get::<MinecraftEntityId>().unwrap(); let entity_id = *entity_mut.get::<MinecraftEntityId>().unwrap();
let Some(updates_received) = entity_mut.get_mut::<UpdatesReceived>() else { if entity_mut.contains::<Local>() {
// a client tried to update another client, which isn't allowed // a client tried to update another client, which isn't allowed
return; return;
}; }
let this_client_updates_received = partial_entity_infos let this_client_updates_received = partial_entity_infos
.updates_received .updates_received
.get(&entity_id) .get(&entity_id)
.copied(); .copied();
let can_update = this_client_updates_received.unwrap_or(1) == **updates_received; let can_update = if let Some(updates_received) = entity_mut.get::<UpdatesReceived>() {
this_client_updates_received.unwrap_or(1) == **updates_received
} else {
// no UpdatesReceived means the entity was just spawned
true
};
if can_update { if can_update {
let new_updates_received = this_client_updates_received.unwrap_or(0) + 1; let new_updates_received = this_client_updates_received.unwrap_or(0) + 1;
partial_entity_infos partial_entity_infos
.updates_received .updates_received
.insert(entity_id, new_updates_received); .insert(entity_id, new_updates_received);
**entity_mut.get_mut::<UpdatesReceived>().unwrap() = new_updates_received; entity_mut.insert(UpdatesReceived(new_updates_received));
let mut entity = world.entity_mut(entity); let mut entity = world.entity_mut(entity);
(self.update)(&mut entity); (self.update)(&mut entity);
@ -94,23 +99,6 @@ impl EntityCommand for RelativeEntityUpdate {
} }
} }
#[allow(clippy::type_complexity)]
pub fn add_updates_received(
mut commands: Commands,
query: Query<
Entity,
(
Changed<MinecraftEntityId>,
(Without<UpdatesReceived>, Without<Local>),
),
>,
) {
for entity in query.iter() {
// entities always start with 1 update received
commands.entity(entity).insert(UpdatesReceived(1));
}
}
/// The [`UpdatesReceived`] component should never be on [`Local`] entities. /// The [`UpdatesReceived`] component should never be on [`Local`] entities.
/// This warns if an entity has both components. /// This warns if an entity has both components.
pub fn debug_detect_updates_received_on_local_entities( pub fn debug_detect_updates_received_on_local_entities(

View file

@ -3,6 +3,7 @@
#![allow(incomplete_features)] #![allow(incomplete_features)]
#![feature(async_fn_in_trait)] #![feature(async_fn_in_trait)]
#![feature(type_changing_struct_update)] #![feature(type_changing_struct_update)]
#![feature(lazy_cell)]
mod auto_respawn; mod auto_respawn;
mod bot; mod bot;

View file

@ -0,0 +1,36 @@
use std::sync::LazyLock;
use num_traits::Float;
// based on https://github.com/cabaletta/baritone/blob/1.20.1/src/api/java/baritone/api/pathing/movement/ActionCosts.java
pub const WALK_ONE_BLOCK_COST: f32 = 20. / 4.317;
pub const SPRINT_ONE_BLOCK_COST: f32 = 20. / 5.612;
pub const FALL_ONE_BLOCK_COST: f32 = 0.5;
pub const WALK_OFF_BLOCK_COST: f32 = WALK_ONE_BLOCK_COST * 0.8;
pub const SPRINT_MULTIPLIER: f32 = SPRINT_ONE_BLOCK_COST / WALK_ONE_BLOCK_COST;
pub static FALL_1_25_BLOCKS_COST: LazyLock<f32> = LazyLock::new(|| distance_to_ticks(1.25));
pub static FALL_0_25_BLOCKS_COST: LazyLock<f32> = LazyLock::new(|| distance_to_ticks(0.25));
pub static JUMP_ONE_BLOCK_COST: LazyLock<f32> =
LazyLock::new(|| *FALL_1_25_BLOCKS_COST - *FALL_0_25_BLOCKS_COST);
fn velocity(ticks: usize) -> f32 {
(0.98.powi(ticks.try_into().unwrap()) - 1.) * -3.92
}
fn distance_to_ticks(distance: f32) -> f32 {
if distance == 0. {
// // Avoid 0/0 NaN
return 0.;
}
let mut temp_distance = distance;
let mut tick_count = 0;
loop {
let fall_distance = velocity(tick_count);
if temp_distance <= fall_distance {
return tick_count as f32 + temp_distance / fall_distance;
}
temp_distance -= fall_distance;
tick_count += 1;
}
}

View file

@ -1,4 +1,5 @@
mod astar; mod astar;
pub mod costs;
pub mod goals; pub mod goals;
mod moves; mod moves;
pub mod simulation; pub mod simulation;
@ -156,6 +157,11 @@ fn goto_listener(
debug!("partial: {partial:?}"); debug!("partial: {partial:?}");
debug!("time: {:?}", end_time - start_time); debug!("time: {:?}", end_time - start_time);
println!("Path:");
for movement in &movements {
println!(" {:?}", movement.target);
}
let path = movements.into_iter().collect::<VecDeque<_>>(); let path = movements.into_iter().collect::<VecDeque<_>>();
Some(PathFoundEvent { Some(PathFoundEvent {
entity, entity,

View file

@ -2,11 +2,13 @@ use azalea_client::{SprintDirection, StartSprintEvent};
use azalea_core::{BlockPos, CardinalDirection}; use azalea_core::{BlockPos, CardinalDirection};
use azalea_world::Instance; use azalea_world::Instance;
use crate::{pathfinder::astar, JumpEvent, LookAtEvent}; use crate::{
pathfinder::{astar, costs::*},
JumpEvent, LookAtEvent,
};
use super::{ use super::{
fall_distance, is_block_passable, is_passable, is_standable, Edge, ExecuteCtx, MoveData, fall_distance, is_block_passable, is_passable, is_standable, Edge, ExecuteCtx, MoveData,
FALL_ONE_BLOCK_COST, JUMP_COST, WALK_ONE_BLOCK_COST,
}; };
pub fn basic_move(world: &Instance, node: BlockPos) -> Vec<Edge> { pub fn basic_move(world: &Instance, node: BlockPos) -> Vec<Edge> {
@ -27,7 +29,7 @@ fn forward_move(world: &Instance, pos: BlockPos) -> Vec<Edge> {
continue; continue;
} }
let cost = WALK_ONE_BLOCK_COST; let cost = SPRINT_ONE_BLOCK_COST;
edges.push(Edge { edges.push(Edge {
movement: astar::Movement { movement: astar::Movement {
@ -68,11 +70,14 @@ fn ascend_move(world: &Instance, pos: BlockPos) -> Vec<Edge> {
for dir in CardinalDirection::iter() { for dir in CardinalDirection::iter() {
let offset = BlockPos::new(dir.x(), 1, dir.z()); let offset = BlockPos::new(dir.x(), 1, dir.z());
if !is_block_passable(&pos.up(2), world) || !is_standable(&(pos + offset), world) { if !is_block_passable(&pos.up(2), world) {
continue;
}
if !is_standable(&(pos + offset), world) {
continue; continue;
} }
let cost = WALK_ONE_BLOCK_COST + JUMP_COST; let cost = SPRINT_ONE_BLOCK_COST + *JUMP_ONE_BLOCK_COST;
edges.push(Edge { edges.push(Edge {
movement: astar::Movement { movement: astar::Movement {
@ -121,8 +126,12 @@ fn descend_move(world: &Instance, pos: BlockPos) -> Vec<Edge> {
if !is_passable(&new_horizontal_position, world) { if !is_passable(&new_horizontal_position, world) {
continue; continue;
} }
// check whether we can stand on the target position
if !is_standable(&new_position, world) {
continue;
}
let cost = WALK_ONE_BLOCK_COST + FALL_ONE_BLOCK_COST * fall_distance as f32; let cost = SPRINT_ONE_BLOCK_COST + FALL_ONE_BLOCK_COST * fall_distance as f32;
edges.push(Edge { edges.push(Edge {
movement: astar::Movement { movement: astar::Movement {
@ -174,7 +183,7 @@ fn diagonal_move(world: &Instance, pos: BlockPos) -> Vec<Edge> {
if !is_standable(&(pos + offset), world) { if !is_standable(&(pos + offset), world) {
continue; continue;
} }
let cost = WALK_ONE_BLOCK_COST * 1.4; let cost = SPRINT_ONE_BLOCK_COST * 1.4;
edges.push(Edge { edges.push(Edge {
movement: astar::Movement { movement: astar::Movement {

View file

@ -71,10 +71,6 @@ fn fall_distance(pos: &BlockPos, world: &Instance) -> u32 {
distance distance
} }
const JUMP_COST: f32 = 0.5;
const WALK_ONE_BLOCK_COST: f32 = 1.0;
const FALL_ONE_BLOCK_COST: f32 = 0.5;
pub struct ExecuteCtx<'w1, 'w2, 'w3, 'w4, 'a> { pub struct ExecuteCtx<'w1, 'w2, 'w3, 'w4, 'a> {
pub entity: Entity, pub entity: Entity,
pub target: BlockPos, pub target: BlockPos,