azalea/entity_ref/mod.rs
1pub mod shared_impls;
2
3use std::fmt::Debug;
4
5use azalea_entity::{EntityKindComponent, EntityUuid};
6use azalea_registry::builtin::EntityKind;
7use bevy_ecs::{
8 component::Component,
9 entity::Entity,
10 query::{QueryData, QueryEntityError, QueryItem},
11};
12use parking_lot::MappedRwLockReadGuard;
13use uuid::Uuid;
14
15use crate::{
16 Client,
17 client_impl::error::{AzaleaResult, MissingComponentError},
18};
19
20/// A reference to an entity in a world.
21///
22/// This is different from [`Entity`], since you can perform actions with just
23/// an `EntityRef` instead of it only being an identifier.
24///
25/// Most functions on `EntityRef` that return a value will result in a panic if
26/// the client has despawned, so if your code involves waiting, you should check
27/// [`Self::is_alive`] or [`Self::exists`] before calling those functions.
28///
29/// Also, since `EntityRef` stores the [`Client`] alongside the entity, this
30/// means that it supports interactions such as [`Self::attack`].
31///
32/// Not to be confused with Bevy's [`EntityRef`](bevy_ecs::world::EntityRef).
33#[derive(Clone)]
34pub struct EntityRef {
35 client: Client,
36 entity: Entity,
37}
38
39impl EntityRef {
40 pub fn new(client: Client, entity: Entity) -> Self {
41 Self { client, entity }
42 }
43
44 /// Returns the ECS identifier for the entity.
45 pub fn id(&self) -> Entity {
46 self.entity
47 }
48
49 /// Get a component on the entity.
50 ///
51 /// This allows you to access certain data stored about the entity that
52 /// isn't accessible in a simpler way.
53 ///
54 /// See [`Client::component`] for more details.
55 ///
56 /// # Panics
57 ///
58 /// This will panic if the component doesn't exist on the client. Use
59 /// [`Self::get_component`] to avoid this.
60 ///
61 /// # Examples
62 ///
63 /// ```
64 /// # use azalea_world::WorldName;
65 /// # fn example(client: &azalea::Client) {
66 /// let world_name = client.component::<WorldName>();
67 /// # }
68 pub fn component<T: Component>(
69 &self,
70 ) -> Result<MappedRwLockReadGuard<'_, T>, MissingComponentError> {
71 self.client.entity_component(self.entity)
72 }
73
74 /// Get a component on this client, or `None` if it doesn't exist.
75 ///
76 /// If the component is guaranteed to be present, consider using
77 /// [`Self::component`].
78 ///
79 /// See [`Client::component`] for more details.
80 pub fn get_component<T: Component>(&self) -> Option<MappedRwLockReadGuard<'_, T>> {
81 self.client.get_entity_component(self.entity)
82 }
83
84 /// Query the ECS for data from the entity.
85 ///
86 /// You can use this to mutate data on the entity.
87 ///
88 /// Also see [`Client::query_self`] and [`Client::query_entity`].
89 ///
90 /// # Errors
91 ///
92 /// This will return an error if the entity doesn't exist or is missing a
93 /// component required by the query.
94 pub fn query_self<D: QueryData, R>(
95 &self,
96 f: impl FnOnce(QueryItem<D>) -> R,
97 ) -> AzaleaResult<R> {
98 self.client.query_entity(self.entity, f)
99 }
100
101 #[doc(hidden)]
102 #[deprecated = "replaced with `Self::query_self`."]
103 pub fn try_query_self<D: QueryData, R>(
104 &self,
105 f: impl FnOnce(QueryItem<D>) -> R,
106 ) -> Result<R, QueryEntityError> {
107 #[allow(deprecated)]
108 self.client.try_query_entity(self.entity, f)
109 }
110}
111
112impl Debug for EntityRef {
113 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
114 f.debug_struct("EntityRef")
115 .field("client", &self.client.entity)
116 .field("entity", &self.entity)
117 .finish()
118 }
119}
120
121impl EntityRef {
122 /// Returns the type of entity that this is.
123 pub fn kind(&self) -> AzaleaResult<EntityKind> {
124 Ok(**self.component::<EntityKindComponent>()?)
125 }
126
127 /// Get the Minecraft UUID of this entity.
128 ///
129 /// Also see [`Client::uuid`].
130 pub fn uuid(&self) -> AzaleaResult<Uuid> {
131 // note: this isn't in shared_impls because the Client counterpart isn't
132 // fallible
133 Ok(**self.component::<EntityUuid>()?)
134 }
135}
136
137impl EntityRef {
138 /// Attack this entity from the client that created this `EntityRef`.
139 ///
140 /// Also see [`Client::attack`].
141 pub fn attack(&self) {
142 self.client.attack(self.entity);
143 }
144
145 /// Right-click this entity from the client that created this `EntityRef`.
146 ///
147 /// See [`Client::entity_interact`] for more information.
148 pub fn interact(&self) {
149 self.client.entity_interact(self.entity);
150 }
151
152 /// Look at this entity from the client that created the `EntityRef`.
153 pub fn look_at(&self) -> AzaleaResult<()> {
154 self.client.look_at(self.eye_position()?);
155 Ok(())
156 }
157
158 /// Returns the distance between the client's feet position and this
159 /// entity's feet position.
160 pub fn distance_to_client(&self) -> AzaleaResult<f64> {
161 Ok(self.position()?.distance_to(self.client.position()?))
162 }
163}