Skip to content

Commit

Permalink
fix mine_while_at_start and move PathfinderDebugParticles to its own …
Browse files Browse the repository at this point in the history
…module
  • Loading branch information
mat-1 committed Dec 15, 2023
1 parent dd58592 commit bcbbcff
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 103 deletions.
113 changes: 113 additions & 0 deletions azalea/src/pathfinder/debug.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
use azalea_client::{chat::SendChatEvent, InstanceHolder};
use azalea_core::position::Vec3;
use bevy_ecs::prelude::*;

use super::ExecutingPath;

/// A component that makes bots run /particle commands while pathfinding to show
/// where they're going. This requires the bots to have server operator
/// permissions, and it'll make them spam *a lot* of commands.
///
/// ```
/// # use azalea::prelude::*;
/// # use azalea::pathfinder::PathfinderDebugParticles;
/// # #[derive(Component, Clone, Default)]
/// # pub struct State;
///
/// async fn handle(mut bot: Client, event: azalea::Event, state: State) -> anyhow::Result<()> {
/// match event {
/// azalea::Event::Init => {
/// bot.ecs
/// .lock()
/// .entity_mut(bot.entity)
/// .insert(PathfinderDebugParticles);
/// }
/// _ => {}
/// }
/// Ok(())
/// }
/// ```
#[derive(Component)]
pub struct PathfinderDebugParticles;

pub fn debug_render_path_with_particles(
mut query: Query<(Entity, &ExecutingPath, &InstanceHolder), With<PathfinderDebugParticles>>,
// chat_events is Option because the tests don't have SendChatEvent
// and we have to use ResMut<Events> because bevy doesn't support Option<EventWriter>
chat_events: Option<ResMut<Events<SendChatEvent>>>,
mut tick_count: Local<usize>,
) {
let Some(mut chat_events) = chat_events else {
return;
};
if *tick_count >= 2 {
*tick_count = 0;
} else {
*tick_count += 1;
return;
}
for (entity, executing_path, instance_holder) in &mut query {
if executing_path.path.is_empty() {
continue;
}

let chunks = &instance_holder.instance.read().chunks;

let mut start = executing_path.last_reached_node;
for (i, movement) in executing_path.path.iter().enumerate() {
// /particle dust 0 1 1 1 ~ ~ ~ 0 0 0.2 0 100

let end = movement.target;

let start_vec3 = start.center();
let end_vec3 = end.center();

let step_count = (start_vec3.distance_to_sqr(&end_vec3).sqrt() * 4.0) as usize;

let target_block_state = chunks.get_block_state(&movement.target).unwrap_or_default();
let above_target_block_state = chunks
.get_block_state(&movement.target.up(1))
.unwrap_or_default();
// this isn't foolproof, there might be another block that could be mined
// depending on the move, but it's good enough for debugging
// purposes
let is_mining = !super::world::is_block_state_passable(target_block_state)
|| !super::world::is_block_state_passable(above_target_block_state);

let (r, g, b): (f64, f64, f64) = if i == 0 {
(0., 1., 0.)
} else if is_mining {
(1., 0., 0.)
} else {
(0., 1., 1.)
};

// interpolate between the start and end positions
for i in 0..step_count {
let percent = i as f64 / step_count as f64;
let pos = Vec3 {
x: start_vec3.x + (end_vec3.x - start_vec3.x) * percent,
y: start_vec3.y + (end_vec3.y - start_vec3.y) * percent,
z: start_vec3.z + (end_vec3.z - start_vec3.z) * percent,
};
let particle_command = format!(
"/particle dust {r} {g} {b} {size} {start_x} {start_y} {start_z} {delta_x} {delta_y} {delta_z} 0 {count}",
size = 1,
start_x = pos.x,
start_y = pos.y,
start_z = pos.z,
delta_x = 0,
delta_y = 0,
delta_z = 0,
count = 1
);
chat_events.send(SendChatEvent {
entity,
content: particle_command,
});
}

start = movement.target;
}
}
}
98 changes: 4 additions & 94 deletions azalea/src/pathfinder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
pub mod astar;
pub mod costs;
mod debug;
pub mod goals;
pub mod mining;
pub mod moves;
Expand All @@ -23,24 +24,21 @@ use crate::ecs::{
};
use crate::pathfinder::moves::PathfinderCtx;
use crate::pathfinder::world::CachedWorld;
use azalea_client::chat::SendChatEvent;
use azalea_client::inventory::{InventoryComponent, InventorySet, SetSelectedHotbarSlotEvent};
use azalea_client::mining::{Mining, StartMiningBlockEvent};
use azalea_client::movement::MoveEventsSet;
use azalea_client::{InstanceHolder, StartSprintEvent, StartWalkEvent};
use azalea_core::position::{BlockPos, Vec3};
use azalea_core::position::BlockPos;
use azalea_core::tick::GameTick;
use azalea_entity::metadata::Player;
use azalea_entity::LocalEntity;
use azalea_entity::{Physics, Position};
use azalea_physics::PhysicsSet;
use azalea_world::{InstanceContainer, InstanceName};
use bevy_app::{PreUpdate, Update};
use bevy_ecs::event::Events;
use bevy_ecs::prelude::Event;
use bevy_ecs::query::Changed;
use bevy_ecs::schedule::IntoSystemConfigs;
use bevy_ecs::system::{Local, ResMut};
use bevy_tasks::{AsyncComputeTaskPool, Task};
use futures_lite::future;
use std::collections::VecDeque;
Expand All @@ -49,6 +47,8 @@ use std::sync::Arc;
use std::time::{Duration, Instant};
use tracing::{debug, error, info, trace, warn};

use self::debug::debug_render_path_with_particles;
pub use self::debug::PathfinderDebugParticles;
use self::mining::MiningCache;
use self::moves::{ExecuteCtx, IsReachedCtx, SuccessorsFn};

Expand Down Expand Up @@ -799,96 +799,6 @@ fn stop_pathfinding_on_instance_change(
}
}

/// A component that makes bots run /particle commands while pathfinding to show
/// where they're going. This requires the bots to have server operator
/// permissions, and it'll make them spam *a lot* of commands.
///
/// ```
/// # use azalea::prelude::*;
/// # use azalea::pathfinder::PathfinderDebugParticles;
/// # #[derive(Component, Clone, Default)]
/// # pub struct State;
///
/// async fn handle(mut bot: Client, event: azalea::Event, state: State) -> anyhow::Result<()> {
/// match event {
/// azalea::Event::Init => {
/// bot.ecs
/// .lock()
/// .entity_mut(bot.entity)
/// .insert(PathfinderDebugParticles);
/// }
/// _ => {}
/// }
/// Ok(())
/// }
/// ```
#[derive(Component)]
pub struct PathfinderDebugParticles;

fn debug_render_path_with_particles(
mut query: Query<(Entity, &ExecutingPath), With<PathfinderDebugParticles>>,
// chat_events is Option because the tests don't have SendChatEvent
// and we have to use ResMut<Events> because bevy doesn't support Option<EventWriter>
chat_events: Option<ResMut<Events<SendChatEvent>>>,
mut tick_count: Local<usize>,
) {
let Some(mut chat_events) = chat_events else {
return;
};
if *tick_count >= 2 {
*tick_count = 0;
} else {
*tick_count += 1;
return;
}
for (entity, executing_path) in &mut query {
if executing_path.path.is_empty() {
continue;
}

let mut start = executing_path.last_reached_node;
for (i, movement) in executing_path.path.iter().enumerate() {
// /particle dust 0 1 1 1 ~ ~ ~ 0 0 0.2 0 100

let end = movement.target;

let start_vec3 = start.center();
let end_vec3 = end.center();

let step_count = (start_vec3.distance_to_sqr(&end_vec3).sqrt() * 4.0) as usize;

let (r, g, b): (f64, f64, f64) = if i == 0 { (0., 1., 0.) } else { (0., 1., 1.) };

// interpolate between the start and end positions
for i in 0..step_count {
let percent = i as f64 / step_count as f64;
let pos = Vec3 {
x: start_vec3.x + (end_vec3.x - start_vec3.x) * percent,
y: start_vec3.y + (end_vec3.y - start_vec3.y) * percent,
z: start_vec3.z + (end_vec3.z - start_vec3.z) * percent,
};
let particle_command = format!(
"/particle dust {r} {g} {b} {size} {start_x} {start_y} {start_z} {delta_x} {delta_y} {delta_z} 0 {count}",
size = 1,
start_x = pos.x,
start_y = pos.y,
start_z = pos.z,
delta_x = 0,
delta_y = 0,
delta_z = 0,
count = 1
);
chat_events.send(SendChatEvent {
entity,
content: particle_command,
});
}

start = movement.target;
}
}
}

pub trait Goal {
#[must_use]
fn heuristic(&self, n: BlockPos) -> f32;
Expand Down
14 changes: 6 additions & 8 deletions azalea/src/pathfinder/moves/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -408,14 +408,12 @@ fn execute_downward_move(mut ctx: ExecuteCtx) {
if horizontal_distance_from_target > 0.25 {
ctx.look_at(target_center);
ctx.walk(WalkDirection::Forward);
} else if ctx.mine_while_at_start(target) {
ctx.walk(WalkDirection::None);
} else if BlockPos::from(position) != target {
ctx.look_at(target_center);
ctx.walk(WalkDirection::Forward);
} else {
if ctx.mine_while_at_start(target) {
ctx.walk(WalkDirection::None);
} else if BlockPos::from(position) != target {
ctx.look_at(target_center);
ctx.walk(WalkDirection::Forward);
} else {
ctx.walk(WalkDirection::None);
}
ctx.walk(WalkDirection::None);
}
}
2 changes: 1 addition & 1 deletion azalea/src/pathfinder/moves/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ impl ExecuteCtx<'_, '_, '_, '_, '_, '_, '_> {
self.mine(block);
} else {
self.look_at(self.start.center());
self.walk(WalkDirection::None);
self.walk(WalkDirection::Forward);
}
true
} else {
Expand Down

0 comments on commit bcbbcff

Please sign in to comment.