Skip to main content

yog_event/
handles.rs

1//! Handles: one entity, player or dimension held by its key, each method
2//! the action of that domain with the key put in first (generated by
3//! `actions!` from the actions themselves — nothing here repeats them).
4//!
5//! ```ignore
6//! let me = Player::new(&e.player_name);
7//! me.give_item("minecraft:diamond", 1u32);
8//! if let Some(body) = me.entity() {
9//!     body.teleport((0.5, 100.0, 0.5));
10//! }
11//! ```
12
13use yog_core::{BlockPos, join_state, split_state};
14use yog_ids::sep::{PROPERTY_IS, PROPERTY_SEP};
15
16/// An entity, by its uuid: every action whose first field is `uuid`.
17#[derive(Debug, Clone, PartialEq, Eq, Hash)]
18pub struct Entity {
19    pub uuid: String,
20}
21
22impl Entity {
23    pub fn new(uuid: impl Into<String>) -> Self {
24        Self { uuid: uuid.into() }
25    }
26}
27
28/// An online player, by name: every action whose first field is `player`.
29#[derive(Debug, Clone, PartialEq, Eq, Hash)]
30pub struct Player {
31    pub name: String,
32}
33
34impl Player {
35    pub fn new(name: impl Into<String>) -> Self {
36        Self { name: name.into() }
37    }
38
39    /// The player as an entity (its uuid asked of the server); `None` offline.
40    pub fn entity(&self) -> Option<Entity> {
41        self.info().map(|i| Entity::new(i.uuid))
42    }
43}
44
45/// A dimension (`minecraft:overworld`): every action whose first field is `dim`.
46#[derive(Debug, Clone, PartialEq, Eq, Hash)]
47pub struct World {
48    pub dim: String,
49}
50
51impl World {
52    pub fn new(dim: impl Into<String>) -> Self {
53        Self { dim: dim.into() }
54    }
55
56    pub fn overworld() -> Self {
57        Self::new(yog_ids::game::OVERWORLD)
58    }
59
60    /// Property `name` of the block at `pos` (`"energized"` → `"true"`).
61    pub fn property(&self, pos: BlockPos, name: &str) -> Option<String> {
62        let state = self.state(pos)?;
63        split_state(&state)
64            .1
65            .into_iter()
66            .find(|(k, _)| *k == name)
67            .map(|(_, v)| v.to_owned())
68    }
69
70    /// Sets some properties of the block at `pos` (`"energized=true,powered=false"`),
71    /// keeping the rest; `false` if there's no block or the state doesn't take.
72    pub fn set_properties(&self, pos: BlockPos, properties: &str) -> bool {
73        let Some(state) = self.state(pos) else {
74            return false;
75        };
76        let (id, mut props) = split_state(&state);
77        for pair in properties.split(PROPERTY_SEP).filter(|p| !p.is_empty()) {
78            let Some((k, v)) = pair.split_once(PROPERTY_IS) else {
79                return false;
80            };
81            match props.iter_mut().find(|(n, _)| *n == k) {
82                Some(p) => p.1 = v,
83                None => props.push((k, v)),
84            }
85        }
86        self.set_state(pos, join_state(id, &props))
87    }
88}