mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 14:26:04 +00:00
sort entities_by by distance and improve some docs
This commit is contained in:
parent
cee64cece3
commit
5c0e5b1eb3
5 changed files with 73 additions and 15 deletions
|
@ -1,5 +1,7 @@
|
||||||
use std::{any, sync::Arc};
|
use std::{any, sync::Arc};
|
||||||
|
|
||||||
|
use azalea_core::position::Vec3;
|
||||||
|
use azalea_entity::Position;
|
||||||
use azalea_world::InstanceName;
|
use azalea_world::InstanceName;
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
component::Component,
|
component::Component,
|
||||||
|
@ -34,13 +36,16 @@ impl Client {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a lightweight [`Entity`] for the first entity that matches the
|
/// Return a lightweight [`Entity`] for an arbitrary entity that matches the
|
||||||
/// given predicate function that is in the same [`Instance`] as the
|
/// given predicate function that is in the same [`Instance`] as the
|
||||||
/// client.
|
/// client.
|
||||||
///
|
///
|
||||||
/// You can then use [`Self::entity_component`] to get components from this
|
/// You can then use [`Self::entity_component`] to get components from this
|
||||||
/// entity.
|
/// entity.
|
||||||
///
|
///
|
||||||
|
/// Also see [`Self::entities_by`] which will return all entities that match
|
||||||
|
/// the predicate and sorts them by distance (unlike `entity_by`).
|
||||||
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// use azalea_client::{Client, player::GameProfileComponent};
|
/// use azalea_client::{Client, player::GameProfileComponent};
|
||||||
|
@ -65,11 +70,14 @@ impl Client {
|
||||||
predicate: impl EntityPredicate<Q, F>,
|
predicate: impl EntityPredicate<Q, F>,
|
||||||
) -> Option<Entity> {
|
) -> Option<Entity> {
|
||||||
let instance_name = self.get_component::<InstanceName>()?;
|
let instance_name = self.get_component::<InstanceName>()?;
|
||||||
predicate.find(self.ecs.clone(), &instance_name)
|
predicate.find_any(self.ecs.clone(), &instance_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as [`Self::entity_by`] but returns a `Vec<Entity>` of all entities
|
/// Similar to [`Self::entity_by`] but returns a `Vec<Entity>` of all
|
||||||
/// in our instance that match the predicate.
|
/// entities in our instance that match the predicate.
|
||||||
|
///
|
||||||
|
/// Unlike `entity_by`, the result is sorted by distance to our client's
|
||||||
|
/// position, so the closest entity is first.
|
||||||
pub fn entities_by<F: QueryFilter, Q: QueryData>(
|
pub fn entities_by<F: QueryFilter, Q: QueryData>(
|
||||||
&self,
|
&self,
|
||||||
predicate: impl EntityPredicate<Q, F>,
|
predicate: impl EntityPredicate<Q, F>,
|
||||||
|
@ -77,7 +85,10 @@ impl Client {
|
||||||
let Some(instance_name) = self.get_component::<InstanceName>() else {
|
let Some(instance_name) = self.get_component::<InstanceName>() else {
|
||||||
return vec![];
|
return vec![];
|
||||||
};
|
};
|
||||||
predicate.find_all(self.ecs.clone(), &instance_name)
|
let Some(position) = self.get_component::<Position>() else {
|
||||||
|
return vec![];
|
||||||
|
};
|
||||||
|
predicate.find_all_sorted(self.ecs.clone(), &instance_name, (&position).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a component from an entity. Note that this will return an owned type
|
/// Get a component from an entity. Note that this will return an owned type
|
||||||
|
@ -109,14 +120,24 @@ impl Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait EntityPredicate<Q: QueryData, Filter: QueryFilter> {
|
pub trait EntityPredicate<Q: QueryData, Filter: QueryFilter> {
|
||||||
fn find(&self, ecs_lock: Arc<Mutex<World>>, instance_name: &InstanceName) -> Option<Entity>;
|
fn find_any(&self, ecs_lock: Arc<Mutex<World>>, instance_name: &InstanceName)
|
||||||
fn find_all(&self, ecs_lock: Arc<Mutex<World>>, instance_name: &InstanceName) -> Vec<Entity>;
|
-> Option<Entity>;
|
||||||
|
fn find_all_sorted(
|
||||||
|
&self,
|
||||||
|
ecs_lock: Arc<Mutex<World>>,
|
||||||
|
instance_name: &InstanceName,
|
||||||
|
nearest_to: Vec3,
|
||||||
|
) -> Vec<Entity>;
|
||||||
}
|
}
|
||||||
impl<F, Q: QueryData, Filter: QueryFilter> EntityPredicate<Q, Filter> for F
|
impl<F, Q: QueryData, Filter: QueryFilter> EntityPredicate<Q, Filter> for F
|
||||||
where
|
where
|
||||||
F: Fn(&ROQueryItem<Q>) -> bool,
|
F: Fn(&ROQueryItem<Q>) -> bool,
|
||||||
{
|
{
|
||||||
fn find(&self, ecs_lock: Arc<Mutex<World>>, instance_name: &InstanceName) -> Option<Entity> {
|
fn find_any(
|
||||||
|
&self,
|
||||||
|
ecs_lock: Arc<Mutex<World>>,
|
||||||
|
instance_name: &InstanceName,
|
||||||
|
) -> Option<Entity> {
|
||||||
let mut ecs = ecs_lock.lock();
|
let mut ecs = ecs_lock.lock();
|
||||||
let mut query = ecs.query_filtered::<(Entity, &InstanceName, Q), Filter>();
|
let mut query = ecs.query_filtered::<(Entity, &InstanceName, Q), Filter>();
|
||||||
query
|
query
|
||||||
|
@ -125,13 +146,28 @@ where
|
||||||
.map(|(e, _, _)| e)
|
.map(|(e, _, _)| e)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_all(&self, ecs_lock: Arc<Mutex<World>>, instance_name: &InstanceName) -> Vec<Entity> {
|
fn find_all_sorted(
|
||||||
|
&self,
|
||||||
|
ecs_lock: Arc<Mutex<World>>,
|
||||||
|
instance_name: &InstanceName,
|
||||||
|
nearest_to: Vec3,
|
||||||
|
) -> Vec<Entity> {
|
||||||
let mut ecs = ecs_lock.lock();
|
let mut ecs = ecs_lock.lock();
|
||||||
let mut query = ecs.query_filtered::<(Entity, &InstanceName, Q), Filter>();
|
let mut query = ecs.query_filtered::<(Entity, &InstanceName, &Position, Q), Filter>();
|
||||||
query
|
let mut entities = query
|
||||||
.iter(&ecs)
|
.iter(&ecs)
|
||||||
.filter(|(_, e_instance_name, q)| *e_instance_name == instance_name && (self)(q))
|
.filter(|(_, e_instance_name, _, q)| *e_instance_name == instance_name && (self)(q))
|
||||||
.map(|(e, _, _)| e)
|
.map(|(e, _, position, _)| (e, Vec3::from(position)))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<(Entity, Vec3)>>();
|
||||||
|
|
||||||
|
entities.sort_by_cached_key(|(_, position)| {
|
||||||
|
// to_bits is fine here as long as the number is positive
|
||||||
|
position.distance_squared_to(&nearest_to).to_bits()
|
||||||
|
});
|
||||||
|
|
||||||
|
entities
|
||||||
|
.into_iter()
|
||||||
|
.map(|(e, _)| e)
|
||||||
|
.collect::<Vec<Entity>>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use azalea_world::{InstanceContainer, InstanceName};
|
||||||
use bevy_app::{App, Plugin, Update};
|
use bevy_app::{App, Plugin, Update};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
use tracing::{info, trace};
|
use tracing::trace;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Client,
|
Client,
|
||||||
|
|
|
@ -389,6 +389,8 @@ pub struct Dead;
|
||||||
///
|
///
|
||||||
/// This is used to calculate the camera position for players, when spectating
|
/// This is used to calculate the camera position for players, when spectating
|
||||||
/// an entity, and when raycasting from the entity.
|
/// an entity, and when raycasting from the entity.
|
||||||
|
///
|
||||||
|
/// The default eye height for a player is 1.62 blocks.
|
||||||
#[derive(Component, Clone, Copy, Debug, PartialEq, Deref, DerefMut)]
|
#[derive(Component, Clone, Copy, Debug, PartialEq, Deref, DerefMut)]
|
||||||
pub struct EyeHeight(f32);
|
pub struct EyeHeight(f32);
|
||||||
impl EyeHeight {
|
impl EyeHeight {
|
||||||
|
|
|
@ -1883,6 +1883,16 @@ enum IntProviderKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
registry! {
|
registry! {
|
||||||
|
/// Every type of item in the game.
|
||||||
|
///
|
||||||
|
/// You might find it useful in some cases to check for categories of items
|
||||||
|
/// with [`azalea_registry::tags::items`](crate::tags::items), like this
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let item = azalea_registry::Item::OakLog;
|
||||||
|
/// let is_log = azalea_registry::tags::items::LOGS.contains(&item);
|
||||||
|
/// assert!(is_log);
|
||||||
|
/// ```
|
||||||
enum Item {
|
enum Item {
|
||||||
Air => "minecraft:air",
|
Air => "minecraft:air",
|
||||||
Stone => "minecraft:stone",
|
Stone => "minecraft:stone",
|
||||||
|
|
|
@ -551,6 +551,16 @@ pub fn is_block_state_passable(block: BlockState) -> bool {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if registry_block == azalea_registry::Block::PowderSnow {
|
||||||
|
// we can't jump out of powder snow
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if registry_block == azalea_registry::Block::SweetBerryBush {
|
||||||
|
// these hurt us
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue