diff options
Diffstat (limited to 'azalea/src/bot.rs')
| -rw-r--r-- | azalea/src/bot.rs | 131 |
1 files changed, 101 insertions, 30 deletions
diff --git a/azalea/src/bot.rs b/azalea/src/bot.rs index 0674c692..510449d3 100644 --- a/azalea/src/bot.rs +++ b/azalea/src/bot.rs @@ -1,56 +1,115 @@ -use crate::{Client, Event}; -use async_trait::async_trait; use azalea_core::Vec3; -use parking_lot::Mutex; -use std::{f64::consts::PI, sync::Arc}; +use azalea_ecs::{ + app::{App, Plugin, PluginGroup, PluginGroupBuilder}, + component::Component, + entity::Entity, + event::EventReader, + query::{With, Without}, + schedule::IntoSystemDescriptor, + system::{Commands, Query}, + AppTickExt, +}; +use azalea_world::{ + entity::{metadata::Player, set_rotation, Jumping, Physics, Position}, + Local, +}; +use std::f64::consts::PI; -#[derive(Clone, Default)] -pub struct Plugin; -impl crate::Plugin for Plugin { - type State = State; +use crate::pathfinder::PathfinderPlugin; - fn build(&self) -> State { - State::default() +#[derive(Clone, Default)] +pub struct BotPlugin; +impl Plugin for BotPlugin { + fn build(&self, app: &mut App) { + app.add_event::<LookAtEvent>() + .add_event::<JumpEvent>() + .add_system(insert_bot.before("deduplicate_entities")) + .add_system(look_at_listener) + .add_system(jump_listener.label("jump_listener").before("ai_step")) + .add_tick_system(stop_jumping.after("ai_step")); } } -#[derive(Default, Clone)] -pub struct State { - jumping_once: Arc<Mutex<bool>>, +/// Component for all bots. +#[derive(Default, Component)] +pub struct Bot { + jumping_once: bool, +} + +/// Insert the [`Bot`] component for any local players that don't have it. +#[allow(clippy::type_complexity)] +fn insert_bot( + mut commands: Commands, + mut query: Query<Entity, (Without<Bot>, With<Local>, With<Player>)>, +) { + for entity in &mut query { + commands.entity(entity).insert(Bot::default()); + } } -#[async_trait] -impl crate::PluginState for State { - async fn handle(self: Box<Self>, event: Event, mut bot: Client) { - if let Event::Tick = event { - if *self.jumping_once.lock() && bot.jumping() { - *self.jumping_once.lock() = false; - bot.set_jumping(false); - } +fn stop_jumping(mut query: Query<(&mut Jumping, &mut Bot)>) { + for (mut jumping, mut bot) in &mut query { + if bot.jumping_once && **jumping { + bot.jumping_once = false; + **jumping = false; } } } -pub trait BotTrait { +pub trait BotClientExt { fn jump(&mut self); - fn look_at(&mut self, pos: &Vec3); + fn look_at(&mut self, pos: Vec3); } -impl BotTrait for azalea_client::Client { +impl BotClientExt for azalea_client::Client { /// Queue a jump for the next tick. fn jump(&mut self) { - self.set_jumping(true); - let state = self.plugins.get::<State>().unwrap().clone(); - *state.jumping_once.lock() = true; + let mut ecs = self.ecs.lock(); + ecs.send_event(JumpEvent(self.entity)); } /// Turn the bot's head to look at the coordinate in the world. - fn look_at(&mut self, pos: &Vec3) { - let (y_rot, x_rot) = direction_looking_at(self.entity().pos(), pos); - self.set_rotation(y_rot, x_rot); + fn look_at(&mut self, position: Vec3) { + let mut ecs = self.ecs.lock(); + ecs.send_event(LookAtEvent { + entity: self.entity, + position, + }); + } +} + +/// Event to jump once. +pub struct JumpEvent(pub Entity); + +fn jump_listener(mut query: Query<(&mut Jumping, &mut Bot)>, mut events: EventReader<JumpEvent>) { + for event in events.iter() { + if let Ok((mut jumping, mut bot)) = query.get_mut(event.0) { + **jumping = true; + bot.jumping_once = true; + } } } +/// Make an entity look towards a certain position in the world. +pub struct LookAtEvent { + pub entity: Entity, + /// The position we want the entity to be looking at. + pub position: Vec3, +} +fn look_at_listener( + mut events: EventReader<LookAtEvent>, + mut query: Query<(&Position, &mut Physics)>, +) { + for event in events.iter() { + if let Ok((position, mut physics)) = query.get_mut(event.entity) { + let (y_rot, x_rot) = direction_looking_at(position, &event.position); + set_rotation(&mut physics, y_rot, x_rot); + } + } +} + +/// Return the (`y_rot`, `x_rot`) that would make a client at `current` be +/// looking at `target`. fn direction_looking_at(current: &Vec3, target: &Vec3) -> (f32, f32) { // borrowed from mineflayer's Bot.lookAt because i didn't want to do math let delta = target - current; @@ -59,3 +118,15 @@ fn direction_looking_at(current: &Vec3, target: &Vec3) -> (f32, f32) { let x_rot = f64::atan2(delta.y, ground_distance) * -(180.0 / PI); (y_rot as f32, x_rot as f32) } + +/// A [`PluginGroup`] for the plugins that add extra bot functionality to the +/// client. +pub struct DefaultBotPlugins; + +impl PluginGroup for DefaultBotPlugins { + fn build(self) -> PluginGroupBuilder { + PluginGroupBuilder::start::<Self>() + .add(BotPlugin) + .add(PathfinderPlugin) + } +} |
