mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 23:44:38 +00:00
patch pathfinder path on cost increase
This commit is contained in:
parent
acd52756be
commit
bacb5c0199
3 changed files with 76 additions and 34 deletions
|
@ -239,6 +239,7 @@ pub struct Node {
|
||||||
pub g_score: f32,
|
pub g_score: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct Edge<P: Hash + Copy, M> {
|
pub struct Edge<P: Hash + Copy, M> {
|
||||||
pub movement: Movement<P, M>,
|
pub movement: Movement<P, M>,
|
||||||
pub cost: f32,
|
pub cost: f32,
|
||||||
|
|
|
@ -54,7 +54,8 @@ pub fn debug_render_path_with_particles(
|
||||||
let chunks = &instance_holder.instance.read().chunks;
|
let chunks = &instance_holder.instance.read().chunks;
|
||||||
|
|
||||||
let mut start = executing_path.last_reached_node;
|
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 end = movement.target;
|
||||||
|
|
||||||
let start_vec3 = start.center();
|
let start_vec3 = start.center();
|
||||||
|
|
|
@ -19,7 +19,7 @@ use std::sync::atomic::{self, AtomicUsize};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use std::{cmp, thread};
|
use std::{cmp, thread};
|
||||||
|
|
||||||
use astar::PathfinderTimeout;
|
use astar::{Edge, PathfinderTimeout};
|
||||||
use azalea_client::inventory::{Inventory, InventorySet, SetSelectedHotbarSlotEvent};
|
use azalea_client::inventory::{Inventory, InventorySet, SetSelectedHotbarSlotEvent};
|
||||||
use azalea_client::mining::{Mining, StartMiningBlockEvent};
|
use azalea_client::mining::{Mining, StartMiningBlockEvent};
|
||||||
use azalea_client::movement::MoveEventsSet;
|
use azalea_client::movement::MoveEventsSet;
|
||||||
|
@ -116,8 +116,8 @@ pub struct Pathfinder {
|
||||||
/// pathfinder path.
|
/// pathfinder path.
|
||||||
#[derive(Component, Clone)]
|
#[derive(Component, Clone)]
|
||||||
pub struct ExecutingPath {
|
pub struct ExecutingPath {
|
||||||
pub path: VecDeque<astar::Movement<BlockPos, moves::MoveData>>,
|
pub path: VecDeque<astar::Edge<BlockPos, moves::MoveData>>,
|
||||||
pub queued_path: Option<VecDeque<astar::Movement<BlockPos, moves::MoveData>>>,
|
pub queued_path: Option<VecDeque<astar::Edge<BlockPos, moves::MoveData>>>,
|
||||||
pub last_reached_node: BlockPos,
|
pub last_reached_node: BlockPos,
|
||||||
pub last_node_reached_at: Instant,
|
pub last_node_reached_at: Instant,
|
||||||
pub is_path_partial: bool,
|
pub is_path_partial: bool,
|
||||||
|
@ -161,7 +161,7 @@ pub struct GotoEvent {
|
||||||
pub struct PathFoundEvent {
|
pub struct PathFoundEvent {
|
||||||
pub entity: Entity,
|
pub entity: Entity,
|
||||||
pub start: BlockPos,
|
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 is_partial: bool,
|
||||||
pub successors_fn: SuccessorsFn,
|
pub successors_fn: SuccessorsFn,
|
||||||
pub allow_mining: bool,
|
pub allow_mining: bool,
|
||||||
|
@ -313,7 +313,12 @@ pub fn goto_listener(
|
||||||
&& let Some(final_node) = executing_path.path.back()
|
&& let Some(final_node) = executing_path.path.back()
|
||||||
{
|
{
|
||||||
// if we're currently pathfinding and got a goto event, start a little ahead
|
// 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 {
|
} else {
|
||||||
BlockPos::from(position)
|
BlockPos::from(position)
|
||||||
};
|
};
|
||||||
|
@ -448,13 +453,39 @@ pub fn calculate_path(opts: CalculatePathOpts) -> Option<PathFoundEvent> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// replace the RelBlockPos types with BlockPos
|
// replace the RelBlockPos types with BlockPos
|
||||||
let mapped_path = path
|
// let mapped_path = path
|
||||||
.into_iter()
|
// .into_iter()
|
||||||
.map(|movement| astar::Movement {
|
// .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),
|
target: movement.target.apply(origin),
|
||||||
data: movement.data,
|
data: movement.data,
|
||||||
})
|
},
|
||||||
.collect();
|
cost: found_edge.cost,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Some(PathFoundEvent {
|
Some(PathFoundEvent {
|
||||||
entity: opts.entity,
|
entity: opts.entity,
|
||||||
|
@ -523,10 +554,14 @@ pub fn path_found_listener(
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(first_node_of_new_path) = path.front() {
|
if let Some(first_node_of_new_path) = path.front() {
|
||||||
let last_target_of_current_path =
|
let last_target_of_current_path = RelBlockPos::from_origin(
|
||||||
RelBlockPos::from_origin(origin, last_node_of_current_path.target);
|
origin,
|
||||||
let first_target_of_new_path =
|
last_node_of_current_path.movement.target,
|
||||||
RelBlockPos::from_origin(origin, first_node_of_new_path.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)
|
if successors(last_target_of_current_path)
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -654,7 +689,7 @@ pub fn check_node_reached(
|
||||||
// we don't unnecessarily execute a movement when it wasn't necessary
|
// we don't unnecessarily execute a movement when it wasn't necessary
|
||||||
|
|
||||||
// see if we already reached any future nodes and can skip ahead
|
// 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
|
.path
|
||||||
.clone()
|
.clone()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -662,6 +697,7 @@ pub fn check_node_reached(
|
||||||
.take(20)
|
.take(20)
|
||||||
.rev()
|
.rev()
|
||||||
{
|
{
|
||||||
|
let movement = edge.movement;
|
||||||
let is_reached_ctx = IsReachedCtx {
|
let is_reached_ctx = IsReachedCtx {
|
||||||
target: movement.target,
|
target: movement.target,
|
||||||
start: executing_path.last_reached_node,
|
start: executing_path.last_reached_node,
|
||||||
|
@ -825,10 +861,12 @@ fn patch_path(
|
||||||
let patch_start = if *patch_nodes.start() == 0 {
|
let patch_start = if *patch_nodes.start() == 0 {
|
||||||
executing_path.last_reached_node
|
executing_path.last_reached_node
|
||||||
} else {
|
} 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*
|
// this doesn't override the main goal, it's just the goal for this A*
|
||||||
// calculation
|
// calculation
|
||||||
|
@ -996,10 +1034,10 @@ pub fn tick_execute_path(
|
||||||
for (entity, executing_path, position, physics, mining, instance_holder, inventory_component) in
|
for (entity, executing_path, position, physics, mining, instance_holder, inventory_component) in
|
||||||
&mut query
|
&mut query
|
||||||
{
|
{
|
||||||
if let Some(movement) = executing_path.path.front() {
|
if let Some(edge) = executing_path.path.front() {
|
||||||
let ctx = ExecuteCtx {
|
let ctx = ExecuteCtx {
|
||||||
entity,
|
entity,
|
||||||
target: movement.target,
|
target: edge.movement.target,
|
||||||
position: **position,
|
position: **position,
|
||||||
start: executing_path.last_reached_node,
|
start: executing_path.last_reached_node,
|
||||||
physics,
|
physics,
|
||||||
|
@ -1018,7 +1056,7 @@ pub fn tick_execute_path(
|
||||||
"executing move, position: {}, last_reached_node: {}",
|
"executing move, position: {}, last_reached_node: {}",
|
||||||
**position, executing_path.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>(
|
pub fn check_path_obstructed<SuccessorsFn>(
|
||||||
origin: BlockPos,
|
origin: BlockPos,
|
||||||
mut current_position: RelBlockPos,
|
mut current_position: RelBlockPos,
|
||||||
path: &VecDeque<astar::Movement<BlockPos, moves::MoveData>>,
|
path: &VecDeque<astar::Edge<BlockPos, moves::MoveData>>,
|
||||||
successors_fn: SuccessorsFn,
|
successors_fn: SuccessorsFn,
|
||||||
) -> Option<usize>
|
) -> Option<usize>
|
||||||
where
|
where
|
||||||
SuccessorsFn: Fn(RelBlockPos) -> Vec<astar::Edge<RelBlockPos, moves::MoveData>>,
|
SuccessorsFn: Fn(RelBlockPos) -> Vec<astar::Edge<RelBlockPos, moves::MoveData>>,
|
||||||
{
|
{
|
||||||
for (i, movement) in path.iter().enumerate() {
|
for (i, edge) in path.iter().enumerate() {
|
||||||
let movement_target = RelBlockPos::from_origin(origin, movement.target);
|
let movement_target = RelBlockPos::from_origin(origin, edge.movement.target);
|
||||||
|
|
||||||
let mut found_obstruction = false;
|
let mut found_edge = None;
|
||||||
for edge in successors_fn(current_position) {
|
for candidate_edge in successors_fn(current_position) {
|
||||||
if edge.movement.target == movement_target {
|
if candidate_edge.movement.target == movement_target {
|
||||||
current_position = movement_target;
|
found_edge = Some(candidate_edge);
|
||||||
found_obstruction = false;
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(found_edge) = found_edge
|
||||||
|
&& found_edge.cost <= edge.cost
|
||||||
|
{
|
||||||
|
current_position = found_edge.movement.target;
|
||||||
} else {
|
} else {
|
||||||
found_obstruction = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if found_obstruction {
|
|
||||||
return Some(i);
|
return Some(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue