diff options
| author | mat <27899617+mat-1@users.noreply.github.com> | 2025-12-28 21:54:12 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-12-28 21:54:12 -0600 |
| commit | 39488a6585ce969af93f43ece1ffb1174dc95e1d (patch) | |
| tree | 49b63b2321b974a7c6425e53b8602a0b4500f092 /azalea/src/entity_ref/mod.rs | |
| parent | 25e441944412038da2be4e64854e59169d58305b (diff) | |
| download | azalea-drasl-39488a6585ce969af93f43ece1ffb1174dc95e1d.tar.xz | |
Implement `EntityRef` (#299)
* start implementing EntityRef struct
* use EntityRef and impl more functions for it
* fix doctests
* typo
* slightly reword some docs
* update changelog
Diffstat (limited to 'azalea/src/entity_ref/mod.rs')
| -rw-r--r-- | azalea/src/entity_ref/mod.rs | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/azalea/src/entity_ref/mod.rs b/azalea/src/entity_ref/mod.rs new file mode 100644 index 00000000..3e09d336 --- /dev/null +++ b/azalea/src/entity_ref/mod.rs @@ -0,0 +1,123 @@ +pub mod shared_impls; + +use std::fmt::Debug; + +use azalea_entity::EntityKindComponent; +use azalea_registry::builtin::EntityKind; +use bevy_ecs::{ + component::Component, + entity::Entity, + query::{QueryData, QueryItem}, +}; +use parking_lot::MappedRwLockReadGuard; + +use crate::Client; + +/// A reference to an entity in a world. +/// +/// This is different from [`Entity`], since you can perform actions with just +/// an `EntityRef` instead of it only being an identifier. +/// +/// Most functions on `EntityRef` that return a value will result in a panic if +/// the client has despawned, so if your code involves waiting, you should check +/// [`Self::is_alive`] before calling those functions. +/// +/// Also, since `EntityRef` stores the [`Client`] alongside the entity, this +/// means that it supports interactions such as [`Self::attack`]. +/// +/// Not to be confused with Bevy's [`EntityRef`](bevy_ecs::world::EntityRef). +#[derive(Clone)] +pub struct EntityRef { + client: Client, + entity: Entity, +} + +impl EntityRef { + pub fn new(client: Client, entity: Entity) -> Self { + Self { client, entity } + } + + /// Returns the ECS identifier for the entity. + pub fn id(&self) -> Entity { + self.entity + } + + /// Get a component on the entity. + /// + /// This allows you to access certain data stored about the entity that + /// isn't accessible in a simpler way. + /// + /// See [`Client::component`] for more details. + /// + /// # Panics + /// + /// This will panic if the component doesn't exist on the client. Use + /// [`Self::get_component`] to avoid this. + /// + /// # Examples + /// + /// ``` + /// # use azalea_world::InstanceName; + /// # fn example(client: &azalea::Client) { + /// let world_name = client.component::<InstanceName>(); + /// # } + pub fn component<T: Component>(&self) -> MappedRwLockReadGuard<'_, T> { + self.client.entity_component(self.entity) + } + + /// Get a component on this client, or `None` if it doesn't exist. + /// + /// If the component is guaranteed to be present, consider using + /// [`Self::component`]. + /// + /// See [`Client::component`] for more details. + pub fn get_component<T: Component>(&self) -> Option<MappedRwLockReadGuard<'_, T>> { + self.client.get_entity_component(self.entity) + } + + /// Query the ECS for data from the entity. + /// + /// You can use this to mutate data on the entity. + /// + /// Also see [`Client::query_self`] and [`Client::query_entity`]. + /// + /// # Panics + /// + /// This will panic if the entity is missing a component required by the + /// query. + pub fn query_self<D: QueryData, R>(&self, f: impl FnOnce(QueryItem<D>) -> R) -> R { + self.client.query_entity(self.entity, f) + } +} + +impl Debug for EntityRef { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("EntityRef") + .field("client", &self.client.entity) + .field("entity", &self.entity) + .finish() + } +} + +impl EntityRef { + /// Returns the type of entity that this is. + pub fn kind(&self) -> EntityKind { + **self.component::<EntityKindComponent>() + } +} + +impl EntityRef { + /// Attack this entity from the client that created this `EntityRef`. + /// + /// Also see [`Client::attack`]. + pub fn attack(&self) { + self.client.attack(self.entity); + } + + /// Right-click this entity from the client that created this `EntityRef`. + /// + /// See [`Client::entity_interact`] for more information. + pub fn interact(&self) { + self.client.entity_interact(self.entity); + } +} |
