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
85
86
87
88
89
//! Typed calls of `CTFPlayer`'s native script methods, for the condition,
//! effect, meter and taunt wrappers.
//!
//! Each call goes through the game's typed VScript adapter, as
//! [`script_binding::call`] describes, and reads the result's union member
//! for the type the call checked.
use crate::entities::Entity;
use crate::tf2::script_binding::{self, BindingError};
use crate::{Game, Server};
use sdk_raw::tf2::script_binding::{BOOL, FLOAT, INT, VOID};
use std::ffi::CStr;
/// The class whose script bindings declare the player's methods.
const CLASS: &CStr = c"CTFPlayer";
/// Calls a native `CTFPlayer` method that returns a `bool`.
///
/// # Safety
///
/// As for [`script_binding::call`], with `player` a `CTFPlayer`.
pub(crate) unsafe fn call_bool(
player: Entity<'_>,
method: &CStr,
arguments: &mut [sys::ScriptVariant_t],
) -> Result<bool, BindingError> {
// SAFETY: The caller upholds `call`'s contract.
let result = unsafe { script_binding::call(player, CLASS, method, arguments, BOOL) }?;
// SAFETY: `call` checked that the adapter returned a `FIELD_BOOLEAN`
// variant, which it assigns through the bool member.
Ok(unsafe { result.__bindgen_anon_1.m_bool })
}
/// Calls a native `CTFPlayer` method that returns an `f32`.
///
/// # Safety
///
/// As for [`call_bool`].
pub(crate) unsafe fn call_float(
player: Entity<'_>,
method: &CStr,
arguments: &mut [sys::ScriptVariant_t],
) -> Result<f32, BindingError> {
// SAFETY: The caller upholds `call`'s contract.
let result = unsafe { script_binding::call(player, CLASS, method, arguments, FLOAT) }?;
// SAFETY: `call` checked that the adapter returned a `FIELD_FLOAT`
// variant, which it assigns through the float member.
Ok(unsafe { result.__bindgen_anon_1.m_float })
}
/// Calls a native `CTFPlayer` method that returns an `int`.
///
/// # Safety
///
/// As for [`call_bool`].
pub(crate) unsafe fn call_int(
player: Entity<'_>,
method: &CStr,
arguments: &mut [sys::ScriptVariant_t],
) -> Result<i32, BindingError> {
// SAFETY: The caller upholds `call`'s contract.
let result = unsafe { script_binding::call(player, CLASS, method, arguments, INT) }?;
// SAFETY: `call` checked that the adapter returned a `FIELD_INTEGER`
// variant, which it assigns through the int member.
Ok(unsafe { result.__bindgen_anon_1.m_int })
}
/// Calls a native `CTFPlayer` method that returns nothing.
///
/// # Safety
///
/// As for [`call_bool`].
pub(crate) unsafe fn call_void(
player: Entity<'_>,
method: &CStr,
arguments: &mut [sys::ScriptVariant_t],
) -> Result<(), BindingError> {
// SAFETY: The caller upholds `call`'s contract.
unsafe { script_binding::call(player, CLASS, method, arguments, VOID) }.map(drop)
}
/// Whether `player` is a TF2 player: the server runs TF2, and the entity's
/// class name is `player`, which only `CTFPlayer` registers.
pub(crate) fn is_tf_player(server: Server<'_>, player: Entity<'_>) -> bool {
server.game() == Game::TeamFortress2 && player.class_name() == c"player"
}