mcdata/
entity.rs

1//! Types and traits describing Minecraft entities.
2
3use std::{borrow::Cow, collections::HashMap};
4
5#[cfg(feature = "serde")]
6use std::{fmt, marker::PhantomData};
7
8#[cfg(feature = "entities")]
9#[macro_use]
10mod macros;
11#[cfg(feature = "entities")]
12pub(crate) mod list;
13
14/// Any type that can represent an entity.
15pub trait Entity: Clone {}
16
17/// A generic entity that can represent _any_ possible entity with state by storing its
18/// [id](Self::id), [UUID](Self::uuid), and [raw NBT](Self::properties).
19// TODO: try to make this use `Cow<'a, str>` again
20// TODO: at least replace `String`s with `Cow<'static, str>`s
21#[derive(Debug, Clone, PartialEq)]
22pub struct GenericEntity {
23    /// The id of this entity, e.g. `minecraft:cow`.
24    pub id: Cow<'static, str>,
25    /// The UUID of this entity, stored as a 128-bit integer.
26    pub uuid: u128,
27    /// The raw NBT properties of this entity.
28    pub properties: HashMap<Cow<'static, str>, fastnbt::Value>,
29}
30
31impl Entity for GenericEntity {}
32
33impl Entity for fastnbt::Value {}
34
35#[cfg(feature = "serde")]
36impl<'de> serde::Deserialize<'de> for GenericEntity {
37    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
38    where
39        D: serde::Deserializer<'de>,
40    {
41        struct _Visitor<'de> {
42            marker: PhantomData<GenericEntity>,
43            lifetime: PhantomData<&'de ()>,
44        }
45        impl<'de> serde::de::Visitor<'de> for _Visitor<'de> {
46            type Value = GenericEntity;
47
48            fn expecting(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
49                fmt.write_str("Entity")
50            }
51
52            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
53            where
54                A: serde::de::MapAccess<'de>,
55            {
56                let mut id = None;
57                let mut uuid = None;
58                let mut properties = HashMap::new();
59                while let Some(key) = map.next_key::<Cow<'static, str>>()? {
60                    match key.as_ref() {
61                        "id" => {
62                            if id.is_some() {
63                                return Err(serde::de::Error::duplicate_field("id"));
64                            }
65                            id = Some(map.next_value()?);
66                        }
67                        "UUID" => {
68                            if uuid.is_some() {
69                                return Err(serde::de::Error::duplicate_field("UUID"));
70                            }
71                            uuid = Some(map.next_value()?);
72                        }
73                        _ => {
74                            properties.insert(key, map.next_value()?);
75                        }
76                    }
77                }
78                let id = id.ok_or_else(|| serde::de::Error::missing_field("id"))?;
79                let uuid = uuid.ok_or_else(|| serde::de::Error::missing_field("UUID"))?;
80                Ok(Self::Value {
81                    id,
82                    uuid,
83                    properties,
84                })
85            }
86        }
87
88        deserializer.deserialize_map(_Visitor {
89            marker: PhantomData::<GenericEntity>,
90            lifetime: PhantomData,
91        })
92    }
93}
94
95#[cfg(feature = "serde")]
96impl serde::Serialize for GenericEntity {
97    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
98    where
99        S: serde::Serializer,
100    {
101        use serde::ser::SerializeMap;
102        let mut state = serializer.serialize_map(Some(self.properties.len() + 2))?;
103        state.serialize_entry("id", &self.id)?;
104        state.serialize_entry("UUID", &self.uuid)?;
105        for (key, value) in &self.properties {
106            state.serialize_entry(key, value)?;
107        }
108        state.end()
109    }
110}