diff options
| author | mat <git@matdoes.dev> | 2026-03-27 13:49:18 -0600 |
|---|---|---|
| committer | mat <git@matdoes.dev> | 2026-03-28 01:49:34 +0600 |
| commit | 2d3e4194b885ec499826812da52c965f5a7235cf (patch) | |
| tree | 9cffc73bb9c5ffa29591392f060816b2c9f321a6 | |
| parent | eeaf1435e81d9cbd8daa0efa22029c1f259a64b5 (diff) | |
| download | azalea-drasl-2d3e4194b885ec499826812da52c965f5a7235cf.tar.xz | |
instant path updates for simple paths, and add follow command to testbot
| -rw-r--r-- | Cargo.lock | 42 | ||||
| -rw-r--r-- | azalea-world/src/chunk/mod.rs | 2 | ||||
| -rw-r--r-- | azalea-world/src/chunk/partial.rs | 8 | ||||
| -rw-r--r-- | azalea/benches/checks.rs | 2 | ||||
| -rw-r--r-- | azalea/examples/testbot/commands/movement.rs | 18 | ||||
| -rw-r--r-- | azalea/examples/testbot/main.rs | 36 | ||||
| -rw-r--r-- | azalea/src/pathfinder/astar/mod.rs | 5 | ||||
| -rw-r--r-- | azalea/src/pathfinder/execute/mod.rs | 27 | ||||
| -rw-r--r-- | azalea/src/pathfinder/execute/simulation.rs | 12 | ||||
| -rw-r--r-- | azalea/src/pathfinder/goto_event.rs | 8 | ||||
| -rw-r--r-- | azalea/src/pathfinder/mod.rs | 166 |
11 files changed, 234 insertions, 92 deletions
@@ -235,7 +235,7 @@ dependencies = [ [[package]] name = "azalea" -version = "0.15.0+mc26.1-rc-2" +version = "0.15.0+mc26.1" dependencies = [ "azalea-auth", "azalea-block", @@ -275,7 +275,7 @@ dependencies = [ [[package]] name = "azalea-auth" -version = "0.15.0+mc26.1-rc-2" +version = "0.15.0+mc26.1" dependencies = [ "azalea-buf", "azalea-crypto", @@ -295,7 +295,7 @@ dependencies = [ [[package]] name = "azalea-block" -version = "0.15.0+mc26.1-rc-2" +version = "0.15.0+mc26.1" dependencies = [ "azalea-block-macros", "azalea-buf", @@ -304,7 +304,7 @@ dependencies = [ [[package]] name = "azalea-block-macros" -version = "0.15.0+mc26.1-rc-2" +version = "0.15.0+mc26.1" dependencies = [ "proc-macro2", "quote", @@ -313,7 +313,7 @@ dependencies = [ [[package]] name = "azalea-brigadier" -version = "0.15.0+mc26.1-rc-2" +version = "0.15.0+mc26.1" dependencies = [ "azalea-buf", "azalea-chat", @@ -324,7 +324,7 @@ dependencies = [ [[package]] name = "azalea-buf" -version = "0.15.0+mc26.1-rc-2" +version = "0.15.0+mc26.1" dependencies = [ "azalea-buf-macros", "byteorder", @@ -338,7 +338,7 @@ dependencies = [ [[package]] name = "azalea-buf-macros" -version = "0.15.0+mc26.1-rc-2" +version = "0.15.0+mc26.1" dependencies = [ "proc-macro2", "quote", @@ -347,7 +347,7 @@ dependencies = [ [[package]] name = "azalea-chat" -version = "0.15.0+mc26.1-rc-2" +version = "0.15.0+mc26.1" dependencies = [ "azalea-buf", "azalea-language", @@ -360,7 +360,7 @@ dependencies = [ [[package]] name = "azalea-client" -version = "0.15.0+mc26.1-rc-2" +version = "0.15.0+mc26.1" dependencies = [ "async-compat", "azalea-auth", @@ -398,7 +398,7 @@ dependencies = [ [[package]] name = "azalea-core" -version = "0.15.0+mc26.1-rc-2" +version = "0.15.0+mc26.1" dependencies = [ "azalea-buf", "azalea-chat", @@ -418,7 +418,7 @@ dependencies = [ [[package]] name = "azalea-crypto" -version = "0.15.0+mc26.1-rc-2" +version = "0.15.0+mc26.1" dependencies = [ "aes", "azalea-buf", @@ -437,7 +437,7 @@ dependencies = [ [[package]] name = "azalea-entity" -version = "0.15.0+mc26.1-rc-2" +version = "0.15.0+mc26.1" dependencies = [ "azalea-block", "azalea-buf", @@ -467,7 +467,7 @@ dependencies = [ [[package]] name = "azalea-inventory" -version = "0.15.0+mc26.1-rc-2" +version = "0.15.0+mc26.1" dependencies = [ "azalea-auth", "azalea-buf", @@ -484,7 +484,7 @@ dependencies = [ [[package]] name = "azalea-inventory-macros" -version = "0.15.0+mc26.1-rc-2" +version = "0.15.0+mc26.1" dependencies = [ "proc-macro2", "quote", @@ -493,7 +493,7 @@ dependencies = [ [[package]] name = "azalea-language" -version = "0.15.0+mc26.1-rc-2" +version = "0.15.0+mc26.1" dependencies = [ "compact_str", "serde_json", @@ -501,7 +501,7 @@ dependencies = [ [[package]] name = "azalea-physics" -version = "0.15.0+mc26.1-rc-2" +version = "0.15.0+mc26.1" dependencies = [ "azalea-block", "azalea-core", @@ -518,7 +518,7 @@ dependencies = [ [[package]] name = "azalea-protocol" -version = "0.15.0+mc26.1-rc-2" +version = "0.15.0+mc26.1" dependencies = [ "azalea-auth", "azalea-block", @@ -555,7 +555,7 @@ dependencies = [ [[package]] name = "azalea-protocol-macros" -version = "0.15.0+mc26.1-rc-2" +version = "0.15.0+mc26.1" dependencies = [ "proc-macro2", "quote", @@ -564,7 +564,7 @@ dependencies = [ [[package]] name = "azalea-registry" -version = "0.15.0+mc26.1-rc-2" +version = "0.15.0+mc26.1" dependencies = [ "azalea-buf", "azalea-registry-macros", @@ -574,7 +574,7 @@ dependencies = [ [[package]] name = "azalea-registry-macros" -version = "0.15.0+mc26.1-rc-2" +version = "0.15.0+mc26.1" dependencies = [ "quote", "syn", @@ -582,7 +582,7 @@ dependencies = [ [[package]] name = "azalea-world" -version = "0.15.0+mc26.1-rc-2" +version = "0.15.0+mc26.1" dependencies = [ "azalea-block", "azalea-buf", diff --git a/azalea-world/src/chunk/mod.rs b/azalea-world/src/chunk/mod.rs index 48cb202c..66b2434b 100644 --- a/azalea-world/src/chunk/mod.rs +++ b/azalea-world/src/chunk/mod.rs @@ -26,6 +26,8 @@ const SECTION_HEIGHT: u32 = 16; /// This only contains blocks and biomes. You can derive the height of the chunk /// from the number of sections, but you need a [`ChunkStorage`] to get the /// minimum Y coordinate. +/// +/// [`ChunkStorage`]: crate::ChunkStorage #[derive(Debug)] pub struct Chunk { pub sections: Box<[Section]>, diff --git a/azalea-world/src/chunk/partial.rs b/azalea-world/src/chunk/partial.rs index e0f4912b..e476f075 100644 --- a/azalea-world/src/chunk/partial.rs +++ b/azalea-world/src/chunk/partial.rs @@ -140,7 +140,9 @@ impl PartialChunkStorage { } /// Get a [`Chunk`] within render distance, or `None` if it's not loaded. - /// Use [`ChunkStorage::get`] to get a chunk from the shared storage. + /// Use [`ChunkStorageTrait::get`] to get a chunk from the shared storage. + /// + /// [`ChunkStorageTrait::get`]: crate::chunk::storage::ChunkStorageTrait::get pub fn limited_get(&self, pos: &ChunkPos) -> Option<&Arc<RwLock<Chunk>>> { if !self.in_range(pos) { warn!( @@ -156,7 +158,9 @@ impl PartialChunkStorage { /// Get a mutable reference to a [`Chunk`] within render distance, or /// `None` if it's not loaded. /// - /// Use [`ChunkStorage::get`] to get a chunk from the shared storage. + /// Use [`ChunkStorageTrait::get`] to get a chunk from the shared storage. + /// + /// [`ChunkStorageTrait::get`]: crate::chunk::storage::ChunkStorageTrait::get pub fn limited_get_mut(&mut self, pos: &ChunkPos) -> Option<&mut Option<Arc<RwLock<Chunk>>>> { if !self.in_range(pos) { return None; diff --git a/azalea/benches/checks.rs b/azalea/benches/checks.rs index bd1b9085..61f1f07d 100644 --- a/azalea/benches/checks.rs +++ b/azalea/benches/checks.rs @@ -23,7 +23,7 @@ fn benchmark(c: &mut Criterion) { }); let waterlogged_slab = azalea_block::blocks::OakSlab { - kind: azalea_block::properties::Type::Bottom, + kind: azalea_block::properties::SlabKind::Bottom, waterlogged: true, } .into(); diff --git a/azalea/examples/testbot/commands/movement.rs b/azalea/examples/testbot/commands/movement.rs index 3f015f2c..500e17b0 100644 --- a/azalea/examples/testbot/commands/movement.rs +++ b/azalea/examples/testbot/commands/movement.rs @@ -9,7 +9,6 @@ use azalea::{ use parking_lot::Mutex; use super::{CommandSource, Ctx}; -use crate::BotTask; pub fn register(commands: &mut CommandDispatcher<Mutex<CommandSource>>) { commands.register( @@ -72,6 +71,19 @@ pub fn register(commands: &mut CommandDispatcher<Mutex<CommandSource>>) { ))), ); + commands.register(literal("follow").executes(|ctx: &Ctx| { + let source = ctx.source.lock(); + println!("got follow"); + // look for the sender + let Some(entity) = source.entity() else { + source.reply("I can't see you!"); + return 0; + }; + source.reply("ok"); + *source.state.following_entity.lock() = Some(entity); + 1 + })); + commands.register(literal("down").executes(|ctx: &Ctx| { let source = ctx.source.clone(); tokio::spawn(async move { @@ -207,14 +219,14 @@ pub fn register(commands: &mut CommandDispatcher<Mutex<CommandSource>>) { let source = ctx.source.lock(); source.bot.stop_pathfinding(); source.reply("ok"); - *source.state.task.lock() = BotTask::None; + *source.state.following_entity.lock() = None; 1 })); commands.register(literal("forcestop").executes(|ctx: &Ctx| { let source = ctx.source.lock(); source.bot.force_stop_pathfinding(); source.reply("ok"); - *source.state.task.lock() = BotTask::None; + *source.state.following_entity.lock() = None; 1 })); } diff --git a/azalea/examples/testbot/main.rs b/azalea/examples/testbot/main.rs index 57bdcc72..173f2b8c 100644 --- a/azalea/examples/testbot/main.rs +++ b/azalea/examples/testbot/main.rs @@ -29,11 +29,14 @@ pub mod mspt; use std::{env, process, sync::Arc, thread, time::Duration}; use azalea::{ - ClientInformation, + ClientInformation, EntityRef, brigadier::command_dispatcher::CommandDispatcher, ecs::prelude::*, pathfinder::{ - debug::PathfinderDebugParticles, execute::simulation::SimulationPathfinderExecutionPlugin, + PathfinderOpts, + debug::PathfinderDebugParticles, + execute::simulation::SimulationPathfinderExecutionPlugin, + goals::{Goal, RadiusGoal}, }, prelude::*, swarm::prelude::*, @@ -105,23 +108,17 @@ fn deadlock_detection_thread() { } } -#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] -pub enum BotTask { - #[default] - None, -} - #[derive(Clone, Component, Default)] pub struct State { pub killaura: bool, - pub task: Arc<Mutex<BotTask>>, + pub following_entity: Arc<Mutex<Option<EntityRef>>>, } impl State { fn new() -> Self { Self { killaura: false, - task: Arc::new(Mutex::new(BotTask::None)), + following_entity: Default::default(), } } } @@ -188,9 +185,22 @@ async fn handle(bot: Client, event: azalea::Event, state: State) -> eyre::Result azalea::Event::Tick => { killaura::tick(bot.clone(), state.clone())?; - let task = *state.task.lock(); - match task { - BotTask::None => {} + if bot.ticks_connected().is_multiple_of(5) { + if let Some(following) = &*state.following_entity.lock() { + let goal = RadiusGoal::new(following.position(), 3.); + if bot.is_calculating_path() { + // keep waiting + } else if !goal.success(bot.position().into()) || bot.is_executing_path() { + bot.start_goto_with_opts( + goal, + PathfinderOpts::new() + .retry_on_no_path(false) + .max_timeout(Duration::from_secs(1)), + ); + } else { + following.look_at(); + } + } } } azalea::Event::Login => { diff --git a/azalea/src/pathfinder/astar/mod.rs b/azalea/src/pathfinder/astar/mod.rs index e6118bc0..077ce13a 100644 --- a/azalea/src/pathfinder/astar/mod.rs +++ b/azalea/src/pathfinder/astar/mod.rs @@ -313,3 +313,8 @@ impl Default for PathfinderTimeout { Self::Time(Duration::from_secs(1)) } } +impl From<Duration> for PathfinderTimeout { + fn from(duration: Duration) -> Self { + Self::Time(duration) + } +} diff --git a/azalea/src/pathfinder/execute/mod.rs b/azalea/src/pathfinder/execute/mod.rs index f4214054..a06d1c0f 100644 --- a/azalea/src/pathfinder/execute/mod.rs +++ b/azalea/src/pathfinder/execute/mod.rs @@ -157,7 +157,10 @@ pub fn check_node_reached( position: **position, physics, }; - let extra_check = if i == executing_path.path.len() - 1 { + let extra_check = if i == executing_path.path.len() - 1 + // only do the extra check if we don't have a new path immediately queued up + && executing_path.is_empty_queued_path() + { // be extra strict about the velocity and centering if we're on the last node so // we don't fall off @@ -257,7 +260,7 @@ pub fn timeout_movement( &WorldName, &Inventory, Option<&CustomPathfinderState>, - Option<&SimulatingPathState>, + Option<&mut SimulatingPathState>, )>, worlds: Res<Worlds>, ) { @@ -274,8 +277,8 @@ pub fn timeout_movement( ) in &mut query { if !executing_path.path.is_empty() { - let (start, end) = if let Some(SimulatingPathState::Simulated(simulating_path_state)) = - simulating_path_state + let (start, end) = if let Some(s) = &simulating_path_state + && let SimulatingPathState::Simulated(simulating_path_state) = &**s { (simulating_path_state.start, simulating_path_state.target) } else { @@ -302,6 +305,12 @@ pub fn timeout_movement( "pathfinder went too far from path (xz_distance={xz_distance}/{xz_tolerance}, y_distance={y_distance}/{y_tolerance}, line is {start} to {end}, point at {}), trying to patch!", **position ); + + if let Some(mut simulating_path_state) = simulating_path_state { + // don't keep executing the simulation + *simulating_path_state = SimulatingPathState::Fail; + } + patch_path_from_timeout( entity, &mut executing_path, @@ -410,7 +419,11 @@ pub fn recalculate_near_end_of_path( continue; }; - // start recalculating if the path ends soon + // start recalculating if the path ends soon. 50 is arbitrary, that's just to + // make us recalculate once when we start nearing the end. this doesn't account + // for skipping nodes, though... + // TODO: have a variable to store whether we've recalculated, and then check + // that `&& path.len() <= 50` to see if we should recalculate. if (executing_path.path.len() == 50 || executing_path.path.len() < 5) && !pathfinder.is_calculating && executing_path.is_path_partial @@ -513,7 +526,9 @@ pub fn point_line_distance_1d(point: f64, (start, end): (f64, f64)) -> f64 { let max = start.max(end); if point < min { min - point - } else { + } else if point > max { point - max + } else { + 0. } } diff --git a/azalea/src/pathfinder/execute/simulation.rs b/azalea/src/pathfinder/execute/simulation.rs index 7287587b..1b010cca 100644 --- a/azalea/src/pathfinder/execute/simulation.rs +++ b/azalea/src/pathfinder/execute/simulation.rs @@ -79,7 +79,7 @@ pub enum SimulatingPathState { Fail, Simulated(SimulatingPathOpts), } -#[derive(Clone, Component, Debug)] +#[derive(Clone, Debug)] pub struct SimulatingPathOpts { pub start: BlockPos, pub target: BlockPos, @@ -89,6 +89,14 @@ pub struct SimulatingPathOpts { pub sprinting: bool, pub y_rot: f32, } +impl SimulatingPathState { + pub fn as_simulated(&self) -> Option<&SimulatingPathOpts> { + match self { + Self::Fail => None, + Self::Simulated(s) => Some(s), + } + } +} #[allow(clippy::type_complexity)] pub fn tick_execute_path( @@ -249,6 +257,8 @@ fn run_simulations( let mut sim = Simulation::new(world_holder.shared.read().chunks.clone(), player.clone()); + // note that we can't skip more than 50 nodes without causing issues with the + // executing_path_limit in goto_listener for nodes_ahead in [20, 15, 10, 5, 4, 3, 2, 1, 0] { if nodes_ahead + 1 >= executing_path.path.len() { // don't simulate to the last node since it has stricter checks diff --git a/azalea/src/pathfinder/goto_event.rs b/azalea/src/pathfinder/goto_event.rs index e4f934f2..7d112f28 100644 --- a/azalea/src/pathfinder/goto_event.rs +++ b/azalea/src/pathfinder/goto_event.rs @@ -101,8 +101,8 @@ impl PathfinderOpts { /// Defaults to `PathfinderTimeout::Time(Duration::from_secs(1))`. /// /// Also see [`PathfinderTimeout::Nodes`] - pub fn min_timeout(mut self, min_timeout: PathfinderTimeout) -> Self { - self.min_timeout = min_timeout; + pub fn min_timeout(mut self, min_timeout: impl Into<PathfinderTimeout>) -> Self { + self.min_timeout = min_timeout.into(); self } /// The absolute maximum amount of time that the pathfinder function can @@ -112,8 +112,8 @@ impl PathfinderOpts { /// impossible). /// /// Defaults to `PathfinderTimeout::Time(Duration::from_secs(5))`. - pub fn max_timeout(mut self, max_timeout: PathfinderTimeout) -> Self { - self.max_timeout = max_timeout; + pub fn max_timeout(mut self, max_timeout: impl Into<PathfinderTimeout>) -> Self { + self.max_timeout = max_timeout.into(); self } } diff --git a/azalea/src/pathfinder/mod.rs b/azalea/src/pathfinder/mod.rs index 0269389b..c577b8e3 100644 --- a/azalea/src/pathfinder/mod.rs +++ b/azalea/src/pathfinder/mod.rs @@ -70,7 +70,9 @@ use crate::{ system::{Commands, Query, Res}, }, pathfinder::{ - astar::a_star, execute::DefaultPathfinderExecutionPlugin, moves::MovesCtx, + astar::{PathfinderTimeout, a_star}, + execute::{DefaultPathfinderExecutionPlugin, simulation::SimulatingPathState}, + moves::MovesCtx, world::CachedWorld, }, }; @@ -130,6 +132,11 @@ pub struct ExecutingPath { pub ticks_since_last_node_reached: usize, pub is_path_partial: bool, } +impl ExecutingPath { + pub fn is_empty_queued_path(&self) -> bool { + self.queued_path.is_none() || self.queued_path.as_ref().is_some_and(|p| p.is_empty()) + } +} #[derive(Clone, Debug, Message)] #[non_exhaustive] @@ -293,9 +300,11 @@ pub struct ComputePath(Task<Option<PathFoundEvent>>); pub fn goto_listener( mut commands: Commands, mut events: MessageReader<GotoEvent>, + mut path_found_events: MessageWriter<PathFoundEvent>, mut query: Query<( &mut Pathfinder, Option<&mut ExecutingPath>, + Option<&SimulatingPathState>, &Position, &WorldName, &Inventory, @@ -306,8 +315,15 @@ pub fn goto_listener( let thread_pool = AsyncComputeTaskPool::get(); for event in events.read() { - let Ok((mut pathfinder, executing_path, position, world_name, inventory, custom_state)) = - query.get_mut(event.entity) + let Ok(( + mut pathfinder, + executing_path, + simulating_path_state, + position, + world_name, + inventory, + custom_state, + )) = query.get_mut(event.entity) else { warn!("got goto event for an entity that can't pathfind"); continue; @@ -339,34 +355,6 @@ pub fn goto_listener( pathfinder.opts = Some(event.opts.clone()); pathfinder.is_calculating = true; - let start = if let Some(mut executing_path) = executing_path - && { !executing_path.path.is_empty() } - { - // if we're currently pathfinding and got a goto event, start a little ahead - - let executing_path_limit = 50; - // truncate the executing path so we can cleanly combine the two paths later - executing_path.path.truncate(executing_path_limit); - - executing_path - .path - .back() - .expect("path was just checked to not be empty") - .movement - .target - } else { - cur_pos - }; - - if start == cur_pos { - info!("got goto {:?}, starting from {start:?}", event.goal); - } else { - info!( - "got goto {:?}, starting from {start:?} (currently at {cur_pos:?})", - event.goal, - ); - } - let world_lock = worlds .get(world_name) .expect("Entity tried to pathfind but the entity isn't in a valid world"); @@ -377,14 +365,104 @@ pub fn goto_listener( let goto_id_atomic = pathfinder.goto_id.clone(); let allow_mining = event.opts.allow_mining; - let mining_cache = MiningCache::new(if allow_mining { + let inventory_menu = if allow_mining { Some(inventory.inventory_menu.clone()) } else { None - }); + }; let custom_state = custom_state.cloned().unwrap_or_default(); let opts = event.opts.clone(); + + // if we're executing a path, this might get replaced with something else + let mut start = cur_pos; + + if let Some(mut executing_path) = executing_path { + // first try calculating the path instantly, which allows us to react quickly + // for easy paths (but we'll fall back to spawning a thread if this fails) + + // first, try starting at the node that we're going to + let instant_path_start = simulating_path_state + .and_then(|s| s.as_simulated().map(|s| s.target)) + .unwrap_or_else(|| { + executing_path + .path + .iter() + .next() + .map(|e| e.movement.target) + .unwrap_or(cur_pos) + }); + + let path_found_event = calculate_path(CalculatePathCtx { + entity, + start: instant_path_start, + goal: goal.clone(), + world_lock: world_lock.clone(), + goto_id_atomic: goto_id_atomic.clone(), + mining_cache: MiningCache::new(inventory_menu.clone()), + custom_state: custom_state.clone(), + opts: PathfinderOpts { + min_timeout: PathfinderTimeout::Nodes(2_000), + max_timeout: PathfinderTimeout::Nodes(2_000), + ..opts + }, + }); + + if let Some(path_found_event) = path_found_event + && !path_found_event.is_partial + { + debug!("Found path instantly!"); + + // instant_path_start needs to be equal to executing_path.path.back() for the + // path merging in path_found_listener to work correctly + let instant_path_start_index = executing_path + .path + .iter() + .position(|e| e.movement.target == instant_path_start); + if let Some(instant_path_start_index) = instant_path_start_index { + let truncate_to_len = instant_path_start_index + 1; + debug!("truncating to {truncate_to_len} for instant path"); + executing_path.path.truncate(truncate_to_len); + + path_found_events.write(path_found_event); + + // we found the path instantly, so we're done here :) + continue; + } else { + warn!( + "we just calculated an instant path, but the start of it isn't in the current path? instant_path_start: {instant_path_start:?}, simulating_path_state: {simulating_path_state:?}, executing_path.path: {:?}", + executing_path.path + ) + } + } + + if !executing_path.path.is_empty() { + // if we're currently pathfinding and got a goto event, start a little ahead + + let executing_path_limit = 50; + + // truncate the executing path so we can cleanly combine the two paths later + executing_path.path.truncate(executing_path_limit); + + start = executing_path + .path + .back() + .expect("path was just checked to not be empty") + .movement + .target; + } + } + + if start == cur_pos { + info!("got goto {:?}, starting from {start:?}", event.goal); + } else { + info!( + "got goto {:?}, starting from {start:?} (currently at {cur_pos:?})", + event.goal, + ); + } + + let mining_cache = MiningCache::new(inventory_menu); let task = thread_pool.spawn(async move { calculate_path(CalculatePathCtx { entity, @@ -434,7 +512,7 @@ pub struct CalculatePathCtx { /// calling this function. `None` will be returned if the pathfinding was /// interrupted by another path calculation. pub fn calculate_path(ctx: CalculatePathCtx) -> Option<PathFoundEvent> { - debug!("start: {:?}", ctx.start); + debug!("start: {}", ctx.start); let goto_id = ctx.goto_id_atomic.fetch_add(1, atomic::Ordering::SeqCst) + 1; @@ -573,7 +651,7 @@ pub fn path_found_listener( debug!("got path found event for an entity that can't pathfind"); continue; }; - if let Some(path) = &event.path { + if let Some(found_path) = &event.path { if let Some(mut executing_path) = executing_path { let mut new_path = VecDeque::new(); @@ -603,7 +681,7 @@ pub fn path_found_listener( ) }; - if let Some(first_node_of_new_path) = path.front() { + if let Some(first_node_of_new_path) = found_path.front() { let last_target_of_current_path = RelBlockPos::from_origin( origin, last_node_of_current_path.movement.target, @@ -622,7 +700,10 @@ pub fn path_found_listener( "old path: {:?}", executing_path.path.iter().collect::<Vec<_>>() ); - debug!("new path: {:?}", path.iter().take(10).collect::<Vec<_>>()); + debug!( + "new path: {:?}", + found_path.iter().take(10).collect::<Vec<_>>() + ); new_path.extend(executing_path.path.iter().cloned()); } } else { @@ -630,7 +711,7 @@ pub fn path_found_listener( } } - new_path.extend(path.to_owned()); + new_path.extend(found_path.to_owned()); debug!( "set queued path to {:?}", @@ -638,7 +719,7 @@ pub fn path_found_listener( ); executing_path.queued_path = Some(new_path); executing_path.is_path_partial = event.is_partial; - } else if path.is_empty() { + } else if found_path.is_empty() { debug!("calculated path is empty, so didn't add ExecutingPath"); if !pathfinder.opts.as_ref().is_some_and(|o| o.retry_on_no_path) { debug!("retry_on_no_path is set to false, removing goal"); @@ -646,13 +727,16 @@ pub fn path_found_listener( } } else { commands.entity(event.entity).insert(ExecutingPath { - path: path.to_owned(), + path: found_path.to_owned(), queued_path: None, last_reached_node: event.start, ticks_since_last_node_reached: 0, is_path_partial: event.is_partial, }); - debug!("set path to {:?}", path.iter().take(10).collect::<Vec<_>>()); + debug!( + "set path to {:?}", + found_path.iter().take(10).collect::<Vec<_>>() + ); debug!("partial: {}", event.is_partial); } } else { |
