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

patch pathfinder path on cost increase

This commit is contained in:
mat 2025-05-24 01:20:14 +03:00
parent acd52756be
commit bacb5c0199
3 changed files with 76 additions and 34 deletions

View file

@ -239,6 +239,7 @@ pub struct Node {
pub g_score: f32,
}
#[derive(Clone, Debug)]
pub struct Edge<P: Hash + Copy, M> {
pub movement: Movement<P, M>,
pub cost: f32,

View file

@ -54,7 +54,8 @@ pub fn debug_render_path_with_particles(
let chunks = &instance_holder.instance.read().chunks;
let mut start = executing_path.last_reached_node;
for (i, movement) in executing_path.path.iter().enumerate() {
for (i, edge) in executing_path.path.iter().enumerate() {
let movement = &edge.movement;
let end = movement.target;
let start_vec3 = start.center();

View file

@ -19,7 +19,7 @@ use std::sync::atomic::{self, AtomicUsize};
use std::time::{Duration, Instant};
use std::{cmp, thread};
use astar::PathfinderTimeout;
use astar::{Edge, PathfinderTimeout};
use azalea_client::inventory::{Inventory, InventorySet, SetSelectedHotbarSlotEvent};
use azalea_client::mining::{Mining, StartMiningBlockEvent};
use azalea_client::movement::MoveEventsSet;
@ -116,8 +116,8 @@ pub struct Pathfinder {
/// pathfinder path.
#[derive(Component, Clone)]
pub struct ExecutingPath {
pub path: VecDeque<astar::Movement<BlockPos, moves::MoveData>>,
pub queued_path: Option<VecDeque<astar::Movement<BlockPos, moves::MoveData>>>,
pub path: VecDeque<astar::Edge<BlockPos, moves::MoveData>>,
pub queued_path: Option<VecDeque<astar::Edge<BlockPos, moves::MoveData>>>,
pub last_reached_node: BlockPos,
pub last_node_reached_at: Instant,
pub is_path_partial: bool,
@ -161,7 +161,7 @@ pub struct GotoEvent {
pub struct PathFoundEvent {
pub entity: Entity,
pub start: BlockPos,
pub path: Option<VecDeque<astar::Movement<BlockPos, moves::MoveData>>>,
pub path: Option<VecDeque<astar::Edge<BlockPos, moves::MoveData>>>,
pub is_partial: bool,
pub successors_fn: SuccessorsFn,
pub allow_mining: bool,
@ -313,7 +313,12 @@ pub fn goto_listener(
&& let Some(final_node) = executing_path.path.back()
{
// if we're currently pathfinding and got a goto event, start a little ahead
executing_path.path.get(50).unwrap_or(final_node).target
executing_path
.path
.get(50)
.unwrap_or(final_node)
.movement
.target
} else {
BlockPos::from(position)
};
@ -448,13 +453,39 @@ pub fn calculate_path(opts: CalculatePathOpts) -> Option<PathFoundEvent> {
}
// replace the RelBlockPos types with BlockPos
let mapped_path = path
.into_iter()
.map(|movement| astar::Movement {
target: movement.target.apply(origin),
data: movement.data,
})
.collect();
// let mapped_path = path
// .into_iter()
// .map(|movement| astar::Movement {
// target: movement.target.apply(origin),
// data: movement.data,
// })
// .collect();
let mut mapped_path = VecDeque::with_capacity(path.len());
let mut current_position = RelBlockPos::get_origin(origin);
for movement in path {
let mut found_edge = None;
for edge in successors(current_position) {
if edge.movement.target == movement.target {
found_edge = Some(edge);
break;
}
}
let found_edge = found_edge.expect(
"path should always still be possible because we're using the same world cache",
);
current_position = found_edge.movement.target;
// we don't just copy the found_edge because we're using BlockPos instead of
// RelBlockPos as the target type
mapped_path.push_back(Edge {
movement: astar::Movement {
target: movement.target.apply(origin),
data: movement.data,
},
cost: found_edge.cost,
});
}
Some(PathFoundEvent {
entity: opts.entity,
@ -523,10 +554,14 @@ pub fn path_found_listener(
};
if let Some(first_node_of_new_path) = path.front() {
let last_target_of_current_path =
RelBlockPos::from_origin(origin, last_node_of_current_path.target);
let first_target_of_new_path =
RelBlockPos::from_origin(origin, first_node_of_new_path.target);
let last_target_of_current_path = RelBlockPos::from_origin(
origin,
last_node_of_current_path.movement.target,
);
let first_target_of_new_path = RelBlockPos::from_origin(
origin,
first_node_of_new_path.movement.target,
);
if successors(last_target_of_current_path)
.iter()
@ -654,7 +689,7 @@ pub fn check_node_reached(
// we don't unnecessarily execute a movement when it wasn't necessary
// see if we already reached any future nodes and can skip ahead
for (i, movement) in executing_path
for (i, edge) in executing_path
.path
.clone()
.into_iter()
@ -662,6 +697,7 @@ pub fn check_node_reached(
.take(20)
.rev()
{
let movement = edge.movement;
let is_reached_ctx = IsReachedCtx {
target: movement.target,
start: executing_path.last_reached_node,
@ -825,10 +861,12 @@ fn patch_path(
let patch_start = if *patch_nodes.start() == 0 {
executing_path.last_reached_node
} else {
executing_path.path[*patch_nodes.start() - 1].target
executing_path.path[*patch_nodes.start() - 1]
.movement
.target
};
let patch_end = executing_path.path[*patch_nodes.end()].target;
let patch_end = executing_path.path[*patch_nodes.end()].movement.target;
// this doesn't override the main goal, it's just the goal for this A*
// calculation
@ -996,10 +1034,10 @@ pub fn tick_execute_path(
for (entity, executing_path, position, physics, mining, instance_holder, inventory_component) in
&mut query
{
if let Some(movement) = executing_path.path.front() {
if let Some(edge) = executing_path.path.front() {
let ctx = ExecuteCtx {
entity,
target: movement.target,
target: edge.movement.target,
position: **position,
start: executing_path.last_reached_node,
physics,
@ -1018,7 +1056,7 @@ pub fn tick_execute_path(
"executing move, position: {}, last_reached_node: {}",
**position, executing_path.last_reached_node
);
(movement.data.execute)(ctx);
(edge.movement.data.execute)(ctx);
}
}
}
@ -1110,26 +1148,28 @@ pub fn stop_pathfinding_on_instance_change(
pub fn check_path_obstructed<SuccessorsFn>(
origin: BlockPos,
mut current_position: RelBlockPos,
path: &VecDeque<astar::Movement<BlockPos, moves::MoveData>>,
path: &VecDeque<astar::Edge<BlockPos, moves::MoveData>>,
successors_fn: SuccessorsFn,
) -> Option<usize>
where
SuccessorsFn: Fn(RelBlockPos) -> Vec<astar::Edge<RelBlockPos, moves::MoveData>>,
{
for (i, movement) in path.iter().enumerate() {
let movement_target = RelBlockPos::from_origin(origin, movement.target);
for (i, edge) in path.iter().enumerate() {
let movement_target = RelBlockPos::from_origin(origin, edge.movement.target);
let mut found_obstruction = false;
for edge in successors_fn(current_position) {
if edge.movement.target == movement_target {
current_position = movement_target;
found_obstruction = false;
let mut found_edge = None;
for candidate_edge in successors_fn(current_position) {
if candidate_edge.movement.target == movement_target {
found_edge = Some(candidate_edge);
break;
} else {
found_obstruction = true;
}
}
if found_obstruction {
if let Some(found_edge) = found_edge
&& found_edge.cost <= edge.cost
{
current_position = found_edge.movement.target;
} else {
return Some(i);
}
}