mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 14:26:04 +00:00
use better pathfinder costs and also fix relative entity updates breaking sometimes
This commit is contained in:
parent
dea717b68e
commit
12118ebfa3
8 changed files with 71 additions and 36 deletions
|
@ -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() {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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;
|
||||||
|
|
36
azalea/src/pathfinder/costs.rs
Normal file
36
azalea/src/pathfinder/costs.rs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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,
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Add table
Reference in a new issue