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

Created nearest_entity system param (#102)

* Created nearest_entity system param

Signed-off-by: TheDudeFromCI <thedudefromci@gmail.com>

* Added nearby item iterators.

Signed-off-by: TheDudeFromCI <thedudefromci@gmail.com>

* Export bot.rs (#101)

* Removed .vscode settings (#104)

Signed-off-by: TheDudeFromCI <thedudefromci@gmail.com>

* raycasting not raytracing

* don't panic if TranslatableComponent::to_string fails

* Food/saturation component support (#97)

* modified for food stuff

* moved food/saturation to a separate file

* hunger component

* simplify some logic

---------

Co-authored-by: mat <git@matdoes.dev>

* Created nearest_entity system param

Signed-off-by: TheDudeFromCI <thedudefromci@gmail.com>

* Added nearby item iterators.

Signed-off-by: TheDudeFromCI <thedudefromci@gmail.com>

* Applied tweaks from PR review

Signed-off-by: TheDudeFromCI <thedudefromci@gmail.com>

* Fixed doctests

Signed-off-by: TheDudeFromCI <thedudefromci@gmail.com>

---------

Signed-off-by: TheDudeFromCI <thedudefromci@gmail.com>
Co-authored-by: mat <git@matdoes.dev>
Co-authored-by: Luuk van Oijen <lazyluuk.channel@gmail.com>
This commit is contained in:
TheDudeFromCI 2023-08-21 23:46:54 -07:00 committed by GitHub
parent a81c4c060b
commit 47a280212a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 263 additions and 0 deletions

View file

@ -0,0 +1,73 @@
use azalea::nearest_entity::EntityFinder;
use azalea::ClientBuilder;
use azalea::{Bot, LookAtEvent};
use azalea_client::Account;
use azalea_entity::metadata::{ItemItem, Player};
use azalea_entity::{EyeHeight, Local, Position};
use bevy_app::{FixedUpdate, Plugin};
use bevy_ecs::{
prelude::{Entity, EventWriter},
query::With,
system::Query,
};
#[tokio::main]
async fn main() {
let account = Account::offline("bot");
ClientBuilder::new()
.add_plugins(LookAtStuffPlugin)
.start(account, "localhost")
.await
.unwrap();
}
pub struct LookAtStuffPlugin;
impl Plugin for LookAtStuffPlugin {
fn build(&self, app: &mut bevy_app::App) {
app.add_systems(FixedUpdate, (look_at_everything, log_nearby_item_drops));
}
}
fn look_at_everything(
bots: Query<Entity, (With<Local>, With<Player>)>,
entities: EntityFinder,
entity_positions: Query<(&Position, Option<&EyeHeight>)>,
mut look_at_event: EventWriter<LookAtEvent>,
) {
for bot_id in bots.iter() {
let Some(entity) = entities.nearest_to_entity(bot_id, 16.0) else {
continue;
};
let (position, eye_height) = entity_positions.get(entity).unwrap();
let mut look_target = **position;
if let Some(eye_height) = eye_height {
look_target.y += **eye_height as f64;
}
look_at_event.send(LookAtEvent {
entity: bot_id,
position: look_target,
});
}
}
fn log_nearby_item_drops(
bots: Query<Entity, With<Bot>>,
entities: EntityFinder<With<ItemItem>>,
item_drops: Query<&ItemItem>,
) {
for bot_id in bots.iter() {
for (entity, distance) in entities.nearby_entities_to_entity(bot_id, 8.0) {
let item_drop = item_drops.get(entity).unwrap();
let kind = item_drop.kind();
println!(
"Bot {:?} can see an {:?} {:.1} meters away.",
bot_id, kind, distance
);
}
}
}

View file

@ -7,6 +7,7 @@
mod auto_respawn;
mod bot;
pub mod container;
pub mod nearest_entity;
pub mod pathfinder;
pub mod prelude;
pub mod swarm;

View file

@ -0,0 +1,189 @@
use azalea_entity::Position;
use azalea_world::{InstanceName, MinecraftEntityId};
use bevy_ecs::{
prelude::Entity,
query::{ReadOnlyWorldQuery, With},
system::{Query, SystemParam},
};
/// This system parameter can be used as a shorthand for quickly finding an
/// entity, (or several) close to a given position.
///
/// This system parameter allows for additional filtering of entities based off
/// of ECS marker components, such as `With<>`, `Without<>`, or `Added<>`, etc.
/// All functions used by this system parameter instance will respect the
/// applied filter.
///
/// ```
/// use azalea::chat::SendChatEvent;
/// use azalea::nearest_entity::EntityFinder;
/// use azalea_entity::metadata::{Player, AbstractMonster};
/// use azalea_entity::Local;
/// use bevy_ecs::system::Query;
/// use bevy_ecs::prelude::{Entity, EventWriter};
/// use bevy_ecs::query::With;
///
/// /// All bots near aggressive mobs will scream in chat.
/// pub fn bots_near_aggressive_mobs(
/// bots: Query<Entity, (With<Local>, With<Player>)>,
/// entity_finder: EntityFinder<With<AbstractMonster>>,
/// mut chat_events: EventWriter<SendChatEvent>,
/// ) {
/// for bot_id in bots.iter() {
/// let Some(nearest) = entity_finder.nearest_to_entity(bot_id, 16.0) else {
/// continue;
/// };
///
/// chat_events.send(SendChatEvent {
/// entity: bot_id,
/// content: String::from("Ahhh!"),
/// });
/// }
/// }
/// ```
#[derive(SystemParam)]
pub struct EntityFinder<'w, 's, F = ()>
where
F: ReadOnlyWorldQuery + 'static,
{
all_entities:
Query<'w, 's, (&'static Position, &'static InstanceName), With<MinecraftEntityId>>,
filtered_entities: Query<
'w,
's,
(Entity, &'static InstanceName, &'static Position),
(With<MinecraftEntityId>, F),
>,
}
impl<'w, 's, 'a, F> EntityFinder<'w, 's, F>
where
F: ReadOnlyWorldQuery + 'static,
{
/// Gets the nearest entity to the given position and world instance name.
/// This method will return `None` if there are no entities within range. If
/// multiple entities are within range, only the closest one is returned.
pub fn nearest_to_position(
&'a self,
position: &Position,
instance_name: &InstanceName,
max_distance: f64,
) -> Option<Entity> {
let mut nearest_entity = None;
let mut min_distance = max_distance;
for (target_entity, e_instance, e_pos) in self.filtered_entities.iter() {
if e_instance != instance_name {
continue;
}
let target_distance = position.distance_to(e_pos);
if target_distance < min_distance {
nearest_entity = Some(target_entity);
min_distance = target_distance;
}
}
nearest_entity
}
/// Gets the nearest entity to the given entity. This method will return
/// `None` if there are no entities within range. If multiple entities are
/// within range, only the closest one is returned.
pub fn nearest_to_entity(&'a self, entity: Entity, max_distance: f64) -> Option<Entity> {
let Ok((position, instance_name)) = self.all_entities.get(entity) else {
return None;
};
let mut nearest_entity = None;
let mut min_distance = max_distance;
for (target_entity, e_instance, e_pos) in self.filtered_entities.iter() {
if entity == target_entity {
continue;
};
if e_instance != instance_name {
continue;
}
let target_distance = position.distance_to(e_pos);
if target_distance < min_distance {
nearest_entity = Some(target_entity);
min_distance = target_distance;
}
}
nearest_entity
}
/// This function get an iterator over all nearby entities to the given
/// position within the given maximum distance. The entities in this
/// iterator are not returned in any specific order.
///
/// This function returns the Entity ID of nearby entities and their
/// distance away.
pub fn nearby_entities_to_position(
&'a self,
position: &'a Position,
instance_name: &'a InstanceName,
max_distance: f64,
) -> impl Iterator<Item = (Entity, f64)> + '_ {
self.filtered_entities
.iter()
.filter_map(move |(target_entity, e_instance, e_pos)| {
if e_instance != instance_name {
return None;
}
let distance = position.distance_to(e_pos);
if distance < max_distance {
Some((target_entity, distance))
} else {
None
}
})
}
/// This function get an iterator over all nearby entities to the given
/// entity within the given maximum distance. The entities in this iterator
/// are not returned in any specific order.
///
/// This function returns the Entity ID of nearby entities and their
/// distance away.
pub fn nearby_entities_to_entity(
&'a self,
entity: Entity,
max_distance: f64,
) -> impl Iterator<Item = (Entity, f64)> + '_ {
let position;
let instance_name;
if let Ok((pos, instance)) = self.all_entities.get(entity) {
position = *pos;
instance_name = Some(instance);
} else {
position = Position::default();
instance_name = None;
};
self.filtered_entities
.iter()
.filter_map(move |(target_entity, e_instance, e_pos)| {
if entity == target_entity {
return None;
}
if Some(e_instance) != instance_name {
return None;
}
let distance = position.distance_to(e_pos);
if distance < max_distance {
Some((target_entity, distance))
} else {
None
}
})
}
}