Skip to main content

yog_entity/
lib.rs

1//! Entity access — a universal handle to *any* entity by UUID.
2//!
3//! In Minecraft most actions are entity-level (Player → LivingEntity → Entity):
4//! teleport, position, health... So Yog exposes them here, by UUID, for any
5//! entity. `Player` (in `yog-player`) is a thin wrapper that adds player-only
6//! things (inventory, networking) on top.
7
8use yog_core::Server;
9
10/// A handle to one entity by UUID, bound to a [`Server`].
11pub struct Entity<'a> {
12    server: &'a dyn Server,
13    uuid: String,
14}
15
16impl<'a> Entity<'a> {
17    /// Bind to the entity with this UUID on `server`.
18    pub fn new(server: &'a dyn Server, uuid: impl Into<String>) -> Self {
19        Self {
20            server,
21            uuid: uuid.into(),
22        }
23    }
24
25    pub fn uuid(&self) -> &str {
26        &self.uuid
27    }
28
29    /// Teleport to `(x, y, z)` within the entity's current world.
30    pub fn teleport(&self, x: f64, y: f64, z: f64) -> bool {
31        self.server.entity_teleport(&self.uuid, x, y, z)
32    }
33
34    /// Current position, or `None` if the entity isn't loaded.
35    /// Yaw and pitch in degrees, or `None` if the entity does not exist.
36    pub fn rotation(&self) -> Option<(f32, f32)> {
37        self.server.entity_rotation(&self.uuid)
38    }
39
40    /// Unit look vector derived from yaw/pitch (Minecraft convention).
41    pub fn look_vector(&self) -> Option<(f64, f64, f64)> {
42        let (yaw, pitch) = self.rotation()?;
43        let (yaw, pitch) = ((yaw as f64).to_radians(), (pitch as f64).to_radians());
44        let cos_p = pitch.cos();
45        Some((-yaw.sin() * cos_p, -pitch.sin(), yaw.cos() * cos_p))
46    }
47
48    pub fn position(&self) -> Option<(f64, f64, f64)> {
49        self.server.entity_position(&self.uuid)
50    }
51
52    /// Health (living entities only), or `None`.
53    pub fn health(&self) -> Option<f32> {
54        self.server.entity_health(&self.uuid)
55    }
56
57    /// Set health (living entities only); returns whether it applied.
58    pub fn set_health(&self, health: f32) -> bool {
59        self.server.entity_set_health(&self.uuid, health)
60    }
61
62    /// Remove/kill the entity.
63    pub fn kill(&self) -> bool {
64        self.server.entity_kill(&self.uuid)
65    }
66
67    // ── status effects ──────────────────────────────────────────────────────
68
69    /// Apply a status effect. `effect_id` is a registry id like
70    /// `"minecraft:speed"`. `amplifier` is 0-based (0 = level I).
71    pub fn add_effect(
72        &self,
73        effect_id: &str,
74        duration_ticks: i32,
75        amplifier: u8,
76        show_particles: bool,
77    ) -> bool {
78        self.server.entity_add_effect(&self.uuid, effect_id, duration_ticks, amplifier, show_particles)
79    }
80
81    /// Remove a single status effect.
82    pub fn remove_effect(&self, effect_id: &str) -> bool {
83        self.server.entity_remove_effect(&self.uuid, effect_id)
84    }
85
86    /// Clear all active status effects.
87    pub fn clear_effects(&self) -> bool {
88        self.server.entity_clear_effects(&self.uuid)
89    }
90
91    // ── velocity ────────────────────────────────────────────────────────────
92
93    /// Current velocity `(vx, vy, vz)`, or `None` if not loaded.
94    pub fn velocity(&self) -> Option<(f64, f64, f64)> {
95        self.server.entity_velocity(&self.uuid)
96    }
97
98    /// Set velocity directly (replaces current velocity).
99    pub fn set_velocity(&self, vx: f64, vy: f64, vz: f64) -> bool {
100        self.server.entity_set_velocity(&self.uuid, vx, vy, vz)
101    }
102
103    /// Add an impulse to the current velocity (e.g. launch upward: `add_velocity(0, 1, 0)`).
104    pub fn add_velocity(&self, vx: f64, vy: f64, vz: f64) -> bool {
105        self.server.entity_add_velocity(&self.uuid, vx, vy, vz)
106    }
107
108    // ── NBT ─────────────────────────────────────────────────────────────────
109
110    /// SNBT string of the entity's persistent NBT, or `None` if not found.
111    pub fn get_nbt(&self) -> Option<String> {
112        self.server.entity_get_nbt(&self.uuid)
113    }
114
115    /// Merge SNBT data into the entity's persistent NBT. Returns `false` if not found.
116    pub fn set_nbt(&self, snbt: &str) -> bool {
117        self.server.entity_set_nbt(&self.uuid, snbt)
118    }
119
120    // ── attributes ───────────────────────────────────────────────────────────
121
122    /// Base value of an attribute (e.g. `"minecraft:generic.max_health"`), or `None`.
123    pub fn attribute_get(&self, attribute_id: &str) -> Option<f64> {
124        self.server.entity_attribute_get(&self.uuid, attribute_id)
125    }
126
127    /// Set the base value of an attribute. Returns `false` if not found.
128    pub fn attribute_set(&self, attribute_id: &str, value: f64) -> bool {
129        self.server.entity_attribute_set(&self.uuid, attribute_id, value)
130    }
131}