d2_stampede/
entity.rs

1use crate::class::Class;
2use crate::field::{FieldPath, FieldState};
3use crate::field_value::FieldValue;
4use crate::serializer::SerializerError;
5use prettytable::{row, Table};
6use std::fmt::{Debug, Display, Formatter};
7use std::rc::Rc;
8
9#[derive(Debug, Clone, Copy, Eq, PartialEq)]
10pub enum EntityEvents {
11    Created,
12    Updated,
13    Deleted,
14}
15
16impl EntityEvents {
17    #[inline]
18    pub(crate) fn from_cmd(cmd: u32) -> Self {
19        match cmd {
20            0 => EntityEvents::Updated,
21            2 => EntityEvents::Created,
22            3 => EntityEvents::Deleted,
23            _ => unreachable!(),
24        }
25    }
26}
27
28#[derive(thiserror::Error, Debug)]
29pub enum EntityError {
30    #[error("No entities found at index {0}")]
31    IndexNotFound(usize),
32
33    #[error("No entities found for handle {0}")]
34    HandleNotFound(usize),
35
36    #[error("No entities found for class with id {0}")]
37    ClassIdNotFound(i32),
38
39    #[error("No entities found for class with name {0}")]
40    ClassNameNotFound(String),
41
42    #[error("No property found for name {0} (Class: {1}, FieldPath: {2})")]
43    PropertyNameNotFound(String, String, String),
44
45    #[error(transparent)]
46    FieldPathNotFound(#[from] SerializerError),
47}
48
49/// Container for entities.
50pub struct Entities {
51    pub(crate) entities_vec: Vec<Option<Entity>>,
52}
53
54impl Default for Entities {
55    fn default() -> Self {
56        Entities {
57            entities_vec: vec![None; 8192],
58        }
59    }
60}
61
62impl Entities {
63    /// Iterator over all entities.
64    /// # Examples
65    ///
66    /// ```
67    /// use d2_stampede::prelude::*;
68    /// use d2_stampede::proto::*;
69    ///
70    /// #[derive(Default)]
71    /// struct MyObs;
72    ///
73    /// impl Observer for MyObs {
74    ///     fn on_tick_start(&mut self, ctx: &Context) -> ObserverResult {
75    ///         let dire_heroes = ctx
76    ///             .entities()
77    ///             .iter()
78    ///             .filter(|&e| {
79    ///                 e.class().name().starts_with("CDOTA_Hero_Unit")
80    ///                     && try_property!(e, u32, "m_iTeamNum") == Some(3)
81    ///                     && try_property!(e, u32, "m_hReplicatingOtherHeroModel") == Some(u32::MAX)
82    ///             })
83    ///             .collect::<Vec<_>>();
84    ///         Ok(())
85    ///     }
86    /// }
87    /// ```
88    pub fn iter(&self) -> impl Iterator<Item = &Entity> {
89        self.entities_vec.iter().flatten()
90    }
91
92    /// Returns [`Entity`] for given index.
93    pub fn get_by_index(&self, index: usize) -> Result<&Entity, EntityError> {
94        self.entities_vec
95            .get(index)
96            .and_then(|x| x.as_ref())
97            .ok_or(EntityError::IndexNotFound(index))
98    }
99
100    /// Returns [`Entity`] for given handle.
101    pub fn get_by_handle(&self, handle: usize) -> Result<&Entity, EntityError> {
102        self.get_by_index(handle & 0x3fff)
103            .map_err(|_| EntityError::HandleNotFound(handle))
104    }
105
106    /// Returns [`Entity`] for given class id.
107    pub fn get_by_class_id(&self, id: i32) -> Result<&Entity, EntityError> {
108        self.iter()
109            .find(|&entity| entity.class().id() == id)
110            .ok_or(EntityError::ClassIdNotFound(id))
111    }
112
113    /// Returns [`Entity`] for given class name.
114    pub fn get_by_class_name(&self, name: &str) -> Result<&Entity, EntityError> {
115        self.iter()
116            .find(|&entity| entity.class().name() == name)
117            .ok_or(EntityError::ClassNameNotFound(name.to_string()))
118    }
119}
120
121#[derive(Clone)]
122pub struct Entity {
123    index: u32,
124    serial: u32,
125    pub(crate) class: Rc<Class>,
126    pub(crate) state: FieldState,
127}
128
129impl Entity {
130    pub(crate) fn new(index: u32, serial: u32, class: Rc<Class>, state: FieldState) -> Self {
131        Entity {
132            index,
133            serial,
134            class,
135            state,
136        }
137    }
138
139    pub fn index(&self) -> u32 {
140        self.index
141    }
142
143    pub fn serial(&self) -> u32 {
144        self.serial
145    }
146
147    pub fn handle(&self) -> u32 {
148        self.serial << 14 | self.index
149    }
150
151    pub fn class(&self) -> &Class {
152        &self.class
153    }
154
155    /// Returns [`FieldValue`] for given property name. You can also use
156    /// [`property!`] and [`try_property!`] macros.
157    ///
158    /// # Examples
159    ///
160    /// ```
161    /// use d2_stampede::prelude::*;
162    ///
163    /// #[derive(Default)]
164    /// struct MyObs;
165    ///
166    /// impl Observer for MyObs {
167    ///     fn on_entity(
168    ///         &mut self,
169    ///         ctx: &Context,
170    ///         event: EntityEvents,
171    ///         entity: &Entity,
172    ///     ) -> ObserverResult {
173    ///         let x: u8 = entity
174    ///             .get_property_by_name("CBodyComponent.m_cellX")?
175    ///             .try_into()?;
176    ///
177    ///         let y: u8 = property!(entity, "CBodyComponent.m_cellY");
178    ///
179    ///         let z = property!(entity, u8, "CBodyComponent.m_cellY");
180    ///
181    ///         Ok(())
182    ///     }
183    /// }
184    /// ```
185    ///
186    /// [`property!`]: crate::property
187    /// [`try_property!`]: crate::try_property
188    pub fn get_property_by_name(&self, name: &str) -> Result<&FieldValue, EntityError> {
189        self.get_property_by_field_path(&self.class.serializer.get_field_path_for_name(name)?)
190    }
191
192    pub(crate) fn get_property_by_field_path(
193        &self,
194        fp: &FieldPath,
195    ) -> Result<&FieldValue, EntityError> {
196        self.state.get_value(fp).ok_or_else(|| {
197            EntityError::PropertyNameNotFound(
198                self.class.serializer.get_name_for_field_path(fp),
199                self.class.name().to_string(),
200                format!("{}", fp),
201            )
202        })
203    }
204}
205
206impl Display for Entities {
207    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
208        let mut table = Table::new();
209        table.add_row(row!["idx", "serial", "handle", "class"]);
210        for e in self.entities_vec.iter().flatten() {
211            table.add_row(row![
212                e.index().to_string(),
213                e.serial().to_string(),
214                e.handle().to_string(),
215                e.class().name(),
216            ]);
217        }
218        write!(f, "{}", table)
219    }
220}
221
222impl Display for Entity {
223    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
224        let mut table = Table::new();
225
226        table.add_row(row!["#", "Field", "Type", "Value"]);
227
228        for fp in self
229            .class
230            .serializer
231            .get_field_paths(&mut FieldPath::new(), &self.state)
232        {
233            let field_type = self.class.serializer.get_type_for_field_path(&fp);
234            let name = self.class.serializer.get_name_for_field_path(&fp);
235            let value = self.state.get_value(&fp);
236            if let Some(v) = value {
237                table.add_row(row![fp, name, field_type.as_string(), format!("{:?}", v)]);
238            } else {
239                table.add_row(row![fp, name, field_type.as_string(), "None"]);
240            }
241        }
242
243        write!(f, "{}", table)
244    }
245}