1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
//! What an entity is: its classes, its name and its parent's, its team, and
//! the spawn flags its map gave it.
#[cfg(test)]
#[path = "../tests/entities/identity.rs"]
mod tests;
use crate::entities::Entity;
use crate::entities::fields::{BaseField, FieldError, PooledString};
use crate::interfaces::ValveEngine;
use sdk_raw::util::cstr::borrow_cstr;
use std::ffi::{CStr, c_int};
/// `m_iParent`, the `parentname` key value.
static PARENT_NAME: BaseField<PooledString> =
BaseField::new(c"m_iParent", sys::_fieldtypes_FIELD_STRING);
/// `m_spawnflags`, the `spawnflags` key value.
static SPAWN_FLAGS: BaseField<c_int> =
BaseField::new(c"m_spawnflags", sys::_fieldtypes_FIELD_INTEGER);
/// `m_iTeamNum`, the `teamnumber` key value.
static TEAM: BaseField<c_int> = BaseField::new(c"m_iTeamNum", sys::_fieldtypes_FIELD_INTEGER);
impl<'s> Entity<'s> {
/// Whether a datamap of the entity's class or one of its bases is named
/// `class`, such as `CBaseAnimating` or `CTFPlayer`: whether the entity's
/// class is `class` or derives from it, as far as datamaps tell.
///
/// Classes without a datamap of their own share their base's, so this
/// never finds them.
#[doc(alias("HasEntProp", "dynamic_cast"))]
pub fn is_a(self, class: &CStr) -> bool {
self.has_data_map_class(class)
}
/// The entity's name (`m_iName`), which the `targetname` key value sets,
/// and by which inputs and outputs find it, or `None` if it has none.
#[doc(alias("GetEntityName", "targetname", "m_iName"))]
pub fn name(self) -> Option<&'s CStr> {
let field = self.name_field()?;
// SAFETY: The field is the entity's `m_iName`, read without forming a
// reference. Its string is pooled, and pooled strings live until the
// level ends, past `'s`.
unsafe { borrow_cstr(field.read().pszValue) }.filter(|name| !name.is_empty())
}
/// The name of the entity the map parents this one to (`m_iParent`), the
/// `parentname` key value, or `None` if it has none.
///
/// The game parents the entity as it activates, so this only says which
/// entity it was asked to follow, not what [`Self::move_parent`] it has.
#[doc(alias("parentname", "m_iParent"))]
pub fn parent_name(self) -> Result<Option<&'s CStr>, FieldError> {
let name = PARENT_NAME.read(self)?;
// SAFETY: As for `name`.
Ok(unsafe { borrow_cstr(name.0) }.filter(|name| !name.is_empty()))
}
/// Sets the entity's spawn flags (`m_spawnflags`).
///
/// Classes read their flags as they spawn, and some as they run, such as
/// a trigger checking which entities may touch it.
#[doc(alias("AddSpawnFlags", "RemoveSpawnFlags", "m_spawnflags"))]
pub fn set_spawn_flags(self, engine: ValveEngine<'_>, flags: c_int) -> Result<(), FieldError> {
SPAWN_FLAGS.write(engine, self, flags)
}
/// The entity's spawn flags (`m_spawnflags`), the `spawnflags` key value,
/// whose meaning each class gives.
#[doc(alias("GetSpawnFlags", "HasSpawnFlags", "m_spawnflags"))]
pub fn spawn_flags(self) -> Result<c_int, FieldError> {
SPAWN_FLAGS.read(self)
}
/// The number of the entity's team (`m_iTeamNum`), such as TF2's
/// `TF_TEAM_RED`, or 0 for none.
#[doc(alias("GetTeamNumber", "m_iTeamNum"))]
pub fn team(self) -> Result<c_int, FieldError> {
TEAM.read(self)
}
}