aboutsummaryrefslogtreecommitdiff
path: root/azalea/src/entity_ref/mod.rs
diff options
context:
space:
mode:
authormat <27899617+mat-1@users.noreply.github.com>2025-12-28 21:54:12 -0600
committerGitHub <noreply@github.com>2025-12-28 21:54:12 -0600
commit39488a6585ce969af93f43ece1ffb1174dc95e1d (patch)
tree49b63b2321b974a7c6425e53b8602a0b4500f092 /azalea/src/entity_ref/mod.rs
parent25e441944412038da2be4e64854e59169d58305b (diff)
downloadazalea-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.rs123
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);
+ }
+}