Skip to main content

source_sdk_2013/tf2/
player.rs

1//! TF2's players: their class, team and state, their view, what they see of
2//! the HUD and of the game's menus, their custom models, and the game's own
3//! ways to change these.
4//!
5//! [`TfPlayer`] wraps a player within one engine callback. It reads the
6//! player's networked variables, and changes the player through the members
7//! `CTFPlayer` exposes to VScript, whose native bindings are found by name and
8//! checked against the SDK's signatures before each call, or through the
9//! player's vtable, at the slots [`sdk_raw::tf2::player`] checks.
10//!
11//! Other parts of a player have modules of their own:
12//! [`weapons`](crate::tf2::weapons) and [`ammo`](crate::tf2::ammo) for what
13//! they carry, [`buildings`](crate::tf2::buildings) for an Engineer's
14//! buildings, [`conditions`](crate::tf2::conditions) for their conditions,
15//! [`observer`](crate::tf2::observer) for spectating, and
16//! [`respawn`](crate::tf2::respawn).
17//!
18//! # Unverified
19//!
20//! No running server has tested this module yet. Its vtable slots agree with
21//! SourceMod's TF2 gamedata, and its bindings are checked by name and
22//! signature as they are called.
23
24#[cfg(test)]
25#[path = "../tests/tf2/player.rs"]
26mod tests;
27
28use crate::datatables::{NetProp, NetPropError};
29use crate::entities::{Entity, EntityHandle};
30use crate::math::{QAngle, Vector};
31use crate::tf2::PlayerClass;
32use crate::tf2::observer::VIEW_OFFSET;
33use crate::tf2::ragdolls::TfRagdoll;
34use crate::tf2::script_binding::{self as binding, BindingError};
35use crate::tf2::teams::Team;
36use crate::user_messages::messages::VguiMenu;
37use crate::user_messages::{self, Recipients, UserMessageError};
38use crate::{Game, InterfaceError, Server};
39use sdk_raw::tf2::player as raw;
40use sdk_raw::tf2::script_binding::{BOOL, INT, boolean, int, qangle, vector};
41use sdk_raw::{vcall, vcall_by_value};
42use std::ffi::{CStr, c_int};
43
44/// The bounds of a crouching player, relative to their origin at their feet
45/// (`VEC_DUCK_HULL_MIN` and `VEC_DUCK_HULL_MAX` in TF2's view vectors,
46/// `game/shared/tf/tf_gamerules.cpp`): as wide and deep as standing, and 62
47/// units tall.
48#[doc(alias("VEC_DUCK_HULL_MIN", "VEC_DUCK_HULL_MAX"))]
49pub const PLAYER_DUCK_HULL: (Vector, Vector) = (
50	Vector::new(-24.0, -24.0, 0.0),
51	Vector::new(24.0, 24.0, 62.0),
52);
53
54/// The bounds of a standing player of any class, relative to their origin
55/// at their feet (`VEC_HULL_MIN` and `VEC_HULL_MAX` in TF2's view vectors,
56/// `game/shared/tf/tf_gamerules.cpp`): 48 units wide and deep, and 82 tall.
57#[doc(alias("VEC_HULL_MIN", "VEC_HULL_MAX"))]
58pub const PLAYER_HULL: (Vector, Vector) = (
59	Vector::new(-24.0, -24.0, 0.0),
60	Vector::new(24.0, 24.0, 82.0),
61);
62
63/// The script class that declares the members [`TfPlayer`] calls.
64const SCRIPT_CLASS: &CStr = c"CTFPlayer";
65
66/// The script class that declares the members every player has, such as
67/// `SnapEyeAngles`.
68const BASE_SCRIPT_CLASS: &CStr = c"CBasePlayer";
69
70/// Whether a player's view is forced into third person, as taunts force it
71/// (`m_nForceTauntCam`).
72#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ForcedTauntCam {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                ForcedTauntCam::Off => "Off",
                ForcedTauntCam::WhileAlive => "WhileAlive",
                ForcedTauntCam::Always => "Always",
            })
    }
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for ForcedTauntCam { }
#[automatically_derived]
impl ::core::clone::Clone for ForcedTauntCam {
    #[inline]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for ForcedTauntCam { }Copy, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for ForcedTauntCam { }
#[automatically_derived]
impl ::core::cmp::PartialEq for ForcedTauntCam {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        ::core::intrinsics::discriminant_value(self) ==
            ::core::intrinsics::discriminant_value(other)
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for ForcedTauntCam { }Eq, #[automatically_derived]
impl ::core::hash::Hash for ForcedTauntCam {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&::core::intrinsics::discriminant_value(self),
            state)
    }
}Hash, #[automatically_derived]
impl ::core::default::Default for ForcedTauntCam {
    #[inline]
    fn default() -> Self { Self::Off }
}Default)]
73pub enum ForcedTauntCam {
74	/// The player chooses their own view.
75	#[default]
76	Off,
77
78	/// Third person while the player is alive.
79	WhileAlive,
80
81	/// Third person, even while the player is dead.
82	Always,
83}
84
85impl ForcedTauntCam {
86	/// The value of `m_nForceTauntCam`.
87	pub const fn to_raw(self) -> c_int {
88		match self {
89			Self::Off => 0,
90			Self::WhileAlive => 1,
91			Self::Always => 2,
92		}
93	}
94}
95
96#[doc = r" The parts of the HUD a player's `m_iHideHUD` hides (`HIDEHUD_*`)."]
#[doc = r""]
#[doc =
r" Clients receive only the low [`HIDEHUD_BITCOUNT`](raw::HIDEHUD_BITCOUNT)"]
#[doc =
r" bits, which the named flags cover. Others read back as set, but no"]
#[doc = r" client sees them."]
pub struct HideHud(<HideHud as ::bitflags::__private::PublicFlags>::Internal);
#[automatically_derived]
impl ::core::fmt::Debug for HideHud {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "HideHud",
            &&self.0)
    }
}
#[automatically_derived]
impl ::core::default::Default for HideHud {
    #[inline]
    fn default() -> Self { HideHud(::core::default::Default::default()) }
}
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for HideHud { }
#[automatically_derived]
impl ::core::clone::Clone for HideHud {
    #[inline]
    fn clone(&self) -> Self {
        let _:
                ::core::clone::AssertParamIsClone<<HideHud as
                ::bitflags::__private::PublicFlags>::Internal>;
        *self
    }
}
#[automatically_derived]
impl ::core::marker::Copy for HideHud { }
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for HideHud { }
#[automatically_derived]
impl ::core::cmp::PartialEq for HideHud {
    #[inline]
    fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
}
#[automatically_derived]
impl ::core::cmp::Eq for HideHud {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _:
                ::core::cmp::AssertParamIsEq<<HideHud as
                ::bitflags::__private::PublicFlags>::Internal>;
    }
}
#[automatically_derived]
impl ::core::hash::Hash for HideHud {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.0, state)
    }
}
#[allow(dead_code, deprecated, unused_doc_comments, unused_attributes,
unused_mut, unused_imports, non_upper_case_globals, clippy :: min_ident_chars,
clippy :: assign_op_pattern, clippy :: indexing_slicing, clippy ::
same_name_method, clippy :: iter_without_into_iter,)]
impl HideHud {
    #[doc = r" The whole HUD."]
    #[doc(alias("HIDEHUD_ALL"))]
    pub const ALL: Self = Self::from_bits_retain(raw::HIDEHUD_ALL as u32);
    #[doc = r" The bonus progress display of other Source games."]
    #[doc(alias("HIDEHUD_BONUS_PROGRESS"))]
    pub const BONUS_PROGRESS: Self =
        Self::from_bits_retain(raw::HIDEHUD_BONUS_PROGRESS as u32);
    #[doc = r" The Engineer's building status."]
    #[doc(alias("HIDEHUD_BUILDING_STATUS"))]
    pub const BUILDING_STATUS: Self =
        Self::from_bits_retain(raw::HIDEHUD_BUILDING_STATUS as u32);
    #[doc = r" Chat, and the other communication elements, such as the voice"]
    #[doc = r" icons."]
    #[doc(alias("HIDEHUD_CHAT"))]
    pub const CHAT: Self = Self::from_bits_retain(raw::HIDEHUD_CHAT as u32);
    #[doc = r" The item effect meters, such as the Spy's cloak."]
    #[doc(alias("HIDEHUD_CLOAK_AND_FEIGN"))]
    pub const CLOAK_AND_FEIGN: Self =
        Self::from_bits_retain(raw::HIDEHUD_CLOAK_AND_FEIGN as u32);
    #[doc = r" The crosshair."]
    #[doc(alias("HIDEHUD_CROSSHAIR"))]
    pub const CROSSHAIR: Self =
        Self::from_bits_retain(raw::HIDEHUD_CROSSHAIR as u32);
    #[doc = r" The flashlight meter of other Source games."]
    #[doc(alias("HIDEHUD_FLASHLIGHT"))]
    pub const FLASHLIGHT: Self =
        Self::from_bits_retain(raw::HIDEHUD_FLASHLIGHT as u32);
    #[doc = r" The health display."]
    #[doc(alias("HIDEHUD_HEALTH"))]
    pub const HEALTH: Self =
        Self::from_bits_retain(raw::HIDEHUD_HEALTH as u32);
    #[doc = r" What a player in a vehicle should not see."]
    #[doc(alias("HIDEHUD_INVEHICLE"))]
    pub const IN_VEHICLE: Self =
        Self::from_bits_retain(raw::HIDEHUD_INVEHICLE as u32);
    #[doc =
    r" The match status, such as the round timer and the team status at"]
    #[doc = r" the top of the screen."]
    #[doc(alias("HIDEHUD_MATCH_STATUS"))]
    pub const MATCH_STATUS: Self =
        Self::from_bits_retain(raw::HIDEHUD_MATCH_STATUS as u32);
    #[doc = r" The Engineer's metal display."]
    #[doc(alias("HIDEHUD_METAL"))]
    pub const METAL: Self = Self::from_bits_retain(raw::HIDEHUD_METAL as u32);
    #[doc =
    r" Miscellaneous status elements, such as the pickup history and the"]
    #[doc = r" kill feed."]
    #[doc(alias("HIDEHUD_MISCSTATUS"))]
    pub const MISC_STATUS: Self =
        Self::from_bits_retain(raw::HIDEHUD_MISCSTATUS as u32);
    #[doc = r" What a player without Half-Life 2's HEV suit should not see."]
    #[doc(alias("HIDEHUD_NEEDSUIT"))]
    pub const NEED_SUIT: Self =
        Self::from_bits_retain(raw::HIDEHUD_NEEDSUIT as u32);
    #[doc = r" The Demoman's sticky bomb count and shield charge meter."]
    #[doc(alias("HIDEHUD_PIPES_AND_CHARGE"))]
    pub const PIPES_AND_CHARGE: Self =
        Self::from_bits_retain(raw::HIDEHUD_PIPES_AND_CHARGE as u32);
    #[doc = r" What a dead player should not see."]
    #[doc(alias("HIDEHUD_PLAYERDEAD"))]
    pub const PLAYER_DEAD: Self =
        Self::from_bits_retain(raw::HIDEHUD_PLAYERDEAD as u32);
    #[doc = r" The target ID: the name and health of the player under the"]
    #[doc = r" crosshair."]
    #[doc(alias("HIDEHUD_TARGET_ID"))]
    pub const TARGET_ID: Self =
        Self::from_bits_retain(raw::HIDEHUD_TARGET_ID as u32);
    #[doc = r" The vehicle crosshair of other Source games."]
    #[doc(alias("HIDEHUD_VEHICLE_CROSSHAIR"))]
    pub const VEHICLE_CROSSHAIR: Self =
        Self::from_bits_retain(raw::HIDEHUD_VEHICLE_CROSSHAIR as u32);
    #[doc = r" The ammo count and the weapon selection."]
    #[doc(alias("HIDEHUD_WEAPONSELECTION"))]
    pub const WEAPON_SELECTION: Self =
        Self::from_bits_retain(raw::HIDEHUD_WEAPONSELECTION as u32);
}
#[allow(dead_code, deprecated, unused_doc_comments, unused_attributes,
unused_mut, unused_imports, non_upper_case_globals, clippy :: min_ident_chars,
clippy :: assign_op_pattern, clippy :: indexing_slicing, clippy ::
same_name_method, clippy :: iter_without_into_iter,)]
impl ::bitflags::Flags for HideHud {
    const FLAGS: &'static [::bitflags::Flag<HideHud>] =
        {
            mod __bitflags_flag_names {
                #[allow(unused_imports)]
                use super::*;
                pub(super) const ALL: &'static str = "ALL";
                pub(super) const BONUS_PROGRESS: &'static str =
                    "BONUS_PROGRESS";
                pub(super) const BUILDING_STATUS: &'static str =
                    "BUILDING_STATUS";
                pub(super) const CHAT: &'static str = "CHAT";
                pub(super) const CLOAK_AND_FEIGN: &'static str =
                    "CLOAK_AND_FEIGN";
                pub(super) const CROSSHAIR: &'static str = "CROSSHAIR";
                pub(super) const FLASHLIGHT: &'static str = "FLASHLIGHT";
                pub(super) const HEALTH: &'static str = "HEALTH";
                pub(super) const IN_VEHICLE: &'static str = "IN_VEHICLE";
                pub(super) const MATCH_STATUS: &'static str = "MATCH_STATUS";
                pub(super) const METAL: &'static str = "METAL";
                pub(super) const MISC_STATUS: &'static str = "MISC_STATUS";
                pub(super) const NEED_SUIT: &'static str = "NEED_SUIT";
                pub(super) const PIPES_AND_CHARGE: &'static str =
                    "PIPES_AND_CHARGE";
                pub(super) const PLAYER_DEAD: &'static str = "PLAYER_DEAD";
                pub(super) const TARGET_ID: &'static str = "TARGET_ID";
                pub(super) const VEHICLE_CROSSHAIR: &'static str =
                    "VEHICLE_CROSSHAIR";
                pub(super) const WEAPON_SELECTION: &'static str =
                    "WEAPON_SELECTION";
            }
            &[{
                            ::bitflags::Flag::new(__bitflags_flag_names::ALL,
                                HideHud::ALL)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::BONUS_PROGRESS,
                                HideHud::BONUS_PROGRESS)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::BUILDING_STATUS,
                                HideHud::BUILDING_STATUS)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::CHAT,
                                HideHud::CHAT)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::CLOAK_AND_FEIGN,
                                HideHud::CLOAK_AND_FEIGN)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::CROSSHAIR,
                                HideHud::CROSSHAIR)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::FLASHLIGHT,
                                HideHud::FLASHLIGHT)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::HEALTH,
                                HideHud::HEALTH)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::IN_VEHICLE,
                                HideHud::IN_VEHICLE)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::MATCH_STATUS,
                                HideHud::MATCH_STATUS)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::METAL,
                                HideHud::METAL)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::MISC_STATUS,
                                HideHud::MISC_STATUS)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::NEED_SUIT,
                                HideHud::NEED_SUIT)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::PIPES_AND_CHARGE,
                                HideHud::PIPES_AND_CHARGE)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::PLAYER_DEAD,
                                HideHud::PLAYER_DEAD)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::TARGET_ID,
                                HideHud::TARGET_ID)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::VEHICLE_CROSSHAIR,
                                HideHud::VEHICLE_CROSSHAIR)
                        },
                        {
                            ::bitflags::Flag::new(__bitflags_flag_names::WEAPON_SELECTION,
                                HideHud::WEAPON_SELECTION)
                        }]
        };
    type Bits = u32;
    fn bits(&self) -> u32 { HideHud::bits(self) }
    fn from_bits_retain(bits: u32) -> HideHud {
        HideHud::from_bits_retain(bits)
    }
    fn all_named() -> HideHud {
        const ALL_NAMED: u32 =
            {
                let mut truncated = <u32 as ::bitflags::Bits>::EMPTY;
                let mut i = 0;
                {
                    {
                        let flag = &<HideHud as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag = &<HideHud as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag = &<HideHud as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag = &<HideHud as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag = &<HideHud as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag = &<HideHud as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag = &<HideHud as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag = &<HideHud as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag = &<HideHud as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag = &<HideHud as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag = &<HideHud as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag = &<HideHud as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag = &<HideHud as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag = &<HideHud as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag = &<HideHud as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag = &<HideHud as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag = &<HideHud as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                {
                    {
                        let flag = &<HideHud as ::bitflags::Flags>::FLAGS[i];
                        if flag.is_named() {
                            truncated = truncated | flag.value().bits();
                        }
                        i += 1;
                    }
                };
                let _ = i;
                truncated
            };
        HideHud::from_bits_retain(ALL_NAMED)
    }
}
#[allow(dead_code, deprecated, unused_doc_comments, unused_attributes,
unused_mut, unused_imports, non_upper_case_globals, clippy :: min_ident_chars,
clippy :: assign_op_pattern, clippy :: indexing_slicing, clippy ::
same_name_method, clippy :: iter_without_into_iter,)]
const _: () =
    {
        #[repr(transparent)]
        pub struct InternalBitFlags(u32);
        #[automatically_derived]
        #[doc(hidden)]
        unsafe impl ::core::clone::TrivialClone for InternalBitFlags { }
        #[automatically_derived]
        impl ::core::clone::Clone for InternalBitFlags {
            #[inline]
            fn clone(&self) -> Self {
                let _: ::core::clone::AssertParamIsClone<u32>;
                *self
            }
        }
        #[automatically_derived]
        impl ::core::marker::Copy for InternalBitFlags { }
        #[automatically_derived]
        impl ::core::marker::StructuralPartialEq for InternalBitFlags { }
        #[automatically_derived]
        impl ::core::cmp::PartialEq for InternalBitFlags {
            #[inline]
            fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
        }
        #[automatically_derived]
        impl ::core::cmp::Eq for InternalBitFlags {
            #[inline]
            #[doc(hidden)]
            #[coverage(off)]
            fn assert_fields_are_eq(&self) {
                let _: ::core::cmp::AssertParamIsEq<u32>;
            }
        }
        #[automatically_derived]
        impl ::core::cmp::PartialOrd for InternalBitFlags {
            #[inline]
            fn partial_cmp(&self, other: &Self)
                -> ::core::option::Option<::core::cmp::Ordering> {
                ::core::option::Option::Some(::core::cmp::Ord::cmp(self,
                        other))
            }
        }
        #[automatically_derived]
        impl ::core::cmp::Ord for InternalBitFlags {
            #[inline]
            fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
                ::core::cmp::Ord::cmp(&self.0, &other.0)
            }
        }
        #[automatically_derived]
        impl ::core::hash::Hash for InternalBitFlags {
            #[inline]
            fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
                ::core::hash::Hash::hash(&self.0, state)
            }
        }
        impl ::bitflags::__private::PublicFlags for HideHud {
            type Primitive = u32;
            type Internal = InternalBitFlags;
        }
        impl ::bitflags::__private::core::default::Default for
            InternalBitFlags {
            #[inline]
            fn default() -> Self { InternalBitFlags::empty() }
        }
        impl ::bitflags::__private::core::fmt::Debug for InternalBitFlags {
            fn fmt(&self,
                f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
                -> ::bitflags::__private::core::fmt::Result {
                if self.is_empty() {
                    f.write_fmt(format_args!("{0:#x}",
                            <u32 as ::bitflags::Bits>::EMPTY))
                } else {
                    ::bitflags::__private::core::fmt::Display::fmt(self, f)
                }
            }
        }
        impl ::bitflags::__private::core::fmt::Display for InternalBitFlags {
            fn fmt(&self,
                f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
                -> ::bitflags::__private::core::fmt::Result {
                ::bitflags::parser::to_writer(&HideHud(*self), f)
            }
        }
        impl ::bitflags::__private::core::str::FromStr for InternalBitFlags {
            type Err = ::bitflags::parser::ParseError;
            fn from_str(s: &str)
                ->
                    ::bitflags::__private::core::result::Result<Self,
                    Self::Err> {
                ::bitflags::parser::from_str::<HideHud>(s).map(|flags|
                        flags.0)
            }
        }
        impl ::bitflags::__private::core::convert::AsRef<u32> for
            InternalBitFlags {
            fn as_ref(&self) -> &u32 { &self.0 }
        }
        impl ::bitflags::__private::core::convert::From<u32> for
            InternalBitFlags {
            fn from(bits: u32) -> Self { Self::from_bits_retain(bits) }
        }
        impl InternalBitFlags {
            /// Get a flags value with all bits unset.
            #[inline]
            pub const fn empty() -> Self {
                Self(<u32 as ::bitflags::Bits>::EMPTY)
            }
            /// Get a flags value with all known bits set.
            #[inline]
            pub const fn all() -> Self {
                const ALL: InternalBitFlags =
                    {
                        let mut truncated = <u32 as ::bitflags::Bits>::EMPTY;
                        let mut _i = 0;
                        {
                            {
                                truncated |=
                                    <HideHud as ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <HideHud as ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <HideHud as ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <HideHud as ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <HideHud as ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <HideHud as ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <HideHud as ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <HideHud as ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <HideHud as ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <HideHud as ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <HideHud as ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <HideHud as ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <HideHud as ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <HideHud as ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <HideHud as ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <HideHud as ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <HideHud as ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <HideHud as ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        InternalBitFlags(truncated)
                    };
                ALL
            }
            /// Get the underlying bits value.
            ///
            /// The returned value is exactly the bits set in this flags value.
            #[inline]
            pub const fn bits(&self) -> u32 { self.0 }
            /// Convert from a bits value.
            ///
            /// This method will return `None` if any unknown bits are set.
            #[inline]
            pub const fn from_bits(bits: u32)
                -> ::bitflags::__private::core::option::Option<Self> {
                let truncated = Self::from_bits_truncate(bits).0;
                if truncated == bits {
                    ::bitflags::__private::core::option::Option::Some(Self(bits))
                } else { ::bitflags::__private::core::option::Option::None }
            }
            /// Convert from a bits value, unsetting any unknown bits.
            #[inline]
            pub const fn from_bits_truncate(bits: u32) -> Self {
                Self(bits & Self::all().0)
            }
            /// Convert from a bits value exactly.
            #[inline]
            pub const fn from_bits_retain(bits: u32) -> Self { Self(bits) }
            /// Get a flags value with the bits of a flag with the given name set.
            ///
            /// This method will return `None` if `name` is empty or doesn't
            /// correspond to any named flag.
            #[inline]
            pub fn from_name(name: &str)
                -> ::bitflags::__private::core::option::Option<Self> {
                mod __bitflags_flag_names {
                    #[allow(unused_imports)]
                    use super::*;
                    pub(super) const ALL: &'static str = "ALL";
                    pub(super) const BONUS_PROGRESS: &'static str =
                        "BONUS_PROGRESS";
                    pub(super) const BUILDING_STATUS: &'static str =
                        "BUILDING_STATUS";
                    pub(super) const CHAT: &'static str = "CHAT";
                    pub(super) const CLOAK_AND_FEIGN: &'static str =
                        "CLOAK_AND_FEIGN";
                    pub(super) const CROSSHAIR: &'static str = "CROSSHAIR";
                    pub(super) const FLASHLIGHT: &'static str = "FLASHLIGHT";
                    pub(super) const HEALTH: &'static str = "HEALTH";
                    pub(super) const IN_VEHICLE: &'static str = "IN_VEHICLE";
                    pub(super) const MATCH_STATUS: &'static str =
                        "MATCH_STATUS";
                    pub(super) const METAL: &'static str = "METAL";
                    pub(super) const MISC_STATUS: &'static str = "MISC_STATUS";
                    pub(super) const NEED_SUIT: &'static str = "NEED_SUIT";
                    pub(super) const PIPES_AND_CHARGE: &'static str =
                        "PIPES_AND_CHARGE";
                    pub(super) const PLAYER_DEAD: &'static str = "PLAYER_DEAD";
                    pub(super) const TARGET_ID: &'static str = "TARGET_ID";
                    pub(super) const VEHICLE_CROSSHAIR: &'static str =
                        "VEHICLE_CROSSHAIR";
                    pub(super) const WEAPON_SELECTION: &'static str =
                        "WEAPON_SELECTION";
                }
                {
                    {
                        if name == __bitflags_flag_names::ALL {
                            return ::bitflags::__private::core::option::Option::Some(Self(HideHud::ALL.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::BONUS_PROGRESS {
                            return ::bitflags::__private::core::option::Option::Some(Self(HideHud::BONUS_PROGRESS.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::BUILDING_STATUS {
                            return ::bitflags::__private::core::option::Option::Some(Self(HideHud::BUILDING_STATUS.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::CHAT {
                            return ::bitflags::__private::core::option::Option::Some(Self(HideHud::CHAT.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::CLOAK_AND_FEIGN {
                            return ::bitflags::__private::core::option::Option::Some(Self(HideHud::CLOAK_AND_FEIGN.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::CROSSHAIR {
                            return ::bitflags::__private::core::option::Option::Some(Self(HideHud::CROSSHAIR.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::FLASHLIGHT {
                            return ::bitflags::__private::core::option::Option::Some(Self(HideHud::FLASHLIGHT.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::HEALTH {
                            return ::bitflags::__private::core::option::Option::Some(Self(HideHud::HEALTH.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::IN_VEHICLE {
                            return ::bitflags::__private::core::option::Option::Some(Self(HideHud::IN_VEHICLE.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::MATCH_STATUS {
                            return ::bitflags::__private::core::option::Option::Some(Self(HideHud::MATCH_STATUS.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::METAL {
                            return ::bitflags::__private::core::option::Option::Some(Self(HideHud::METAL.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::MISC_STATUS {
                            return ::bitflags::__private::core::option::Option::Some(Self(HideHud::MISC_STATUS.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::NEED_SUIT {
                            return ::bitflags::__private::core::option::Option::Some(Self(HideHud::NEED_SUIT.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::PIPES_AND_CHARGE {
                            return ::bitflags::__private::core::option::Option::Some(Self(HideHud::PIPES_AND_CHARGE.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::PLAYER_DEAD {
                            return ::bitflags::__private::core::option::Option::Some(Self(HideHud::PLAYER_DEAD.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::TARGET_ID {
                            return ::bitflags::__private::core::option::Option::Some(Self(HideHud::TARGET_ID.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::VEHICLE_CROSSHAIR {
                            return ::bitflags::__private::core::option::Option::Some(Self(HideHud::VEHICLE_CROSSHAIR.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::WEAPON_SELECTION {
                            return ::bitflags::__private::core::option::Option::Some(Self(HideHud::WEAPON_SELECTION.bits()));
                        }
                    };
                };
                let _ = name;
                ::bitflags::__private::core::option::Option::None
            }
            /// Whether all bits in `self` are unset.
            #[inline]
            pub const fn is_empty(&self) -> bool {
                self.0 == <u32 as ::bitflags::Bits>::EMPTY
            }
            /// Whether all known bits in this flags value are set.
            #[inline]
            pub const fn is_all(&self) -> bool {
                Self::all().0 | self.0 == self.0
            }
            /// Whether any set bits in `other` are also set in `self`.
            #[inline]
            pub const fn intersects(&self, other: Self) -> bool {
                self.0 & other.0 != <u32 as ::bitflags::Bits>::EMPTY
            }
            /// Whether all set bits in `other` are also set in `self`.
            #[inline]
            pub const fn contains(&self, other: Self) -> bool {
                self.0 & other.0 == other.0
            }
            /// The bitwise or (`|`) of the bits in `self` and `other`.
            #[inline]
            pub fn insert(&mut self, other: Self) {
                *self = Self(self.0).union(other);
            }
            /// The intersection of `self` with the complement of `other` (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `remove` won't truncate `other`, but the `!` operator will.
            #[inline]
            pub fn remove(&mut self, other: Self) {
                *self = Self(self.0).difference(other);
            }
            /// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
            #[inline]
            pub fn toggle(&mut self, other: Self) {
                *self = Self(self.0).symmetric_difference(other);
            }
            /// Call `insert` when `value` is `true` or `remove` when `value` is `false`.
            #[inline]
            pub fn set(&mut self, other: Self, value: bool) {
                if value { self.insert(other); } else { self.remove(other); }
            }
            /// The bitwise and (`&`) of the bits in `self` and `other`.
            #[inline]
            #[must_use]
            pub const fn intersection(self, other: Self) -> Self {
                Self(self.0 & other.0)
            }
            /// The bitwise or (`|`) of the bits in `self` and `other`.
            #[inline]
            #[must_use]
            pub const fn union(self, other: Self) -> Self {
                Self(self.0 | other.0)
            }
            /// The intersection of `self` with the complement of `other` (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            #[must_use]
            pub const fn difference(self, other: Self) -> Self {
                Self(self.0 & !other.0)
            }
            /// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
            #[inline]
            #[must_use]
            pub const fn symmetric_difference(self, other: Self) -> Self {
                Self(self.0 ^ other.0)
            }
            /// The bitwise negation (`!`) of the bits in `self`, truncating the result.
            #[inline]
            #[must_use]
            pub const fn complement(self) -> Self {
                Self::from_bits_truncate(!self.0)
            }
        }
        impl ::bitflags::__private::core::fmt::Binary for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::Octal for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::LowerHex for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::UpperHex for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::ops::BitOr for InternalBitFlags {
            type Output = Self;
            /// The bitwise or (`|`) of the bits in `self` and `other`.
            #[inline]
            fn bitor(self, other: InternalBitFlags) -> Self {
                self.union(other)
            }
        }
        impl ::bitflags::__private::core::ops::BitOrAssign for
            InternalBitFlags {
            /// The bitwise or (`|`) of the bits in `self` and `other`.
            #[inline]
            fn bitor_assign(&mut self, other: Self) { self.insert(other); }
        }
        impl ::bitflags::__private::core::ops::BitXor for InternalBitFlags {
            type Output = Self;
            /// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
            #[inline]
            fn bitxor(self, other: Self) -> Self {
                self.symmetric_difference(other)
            }
        }
        impl ::bitflags::__private::core::ops::BitXorAssign for
            InternalBitFlags {
            /// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
            #[inline]
            fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
        }
        impl ::bitflags::__private::core::ops::BitAnd for InternalBitFlags {
            type Output = Self;
            /// The bitwise and (`&`) of the bits in `self` and `other`.
            #[inline]
            fn bitand(self, other: Self) -> Self { self.intersection(other) }
        }
        impl ::bitflags::__private::core::ops::BitAndAssign for
            InternalBitFlags {
            /// The bitwise and (`&`) of the bits in `self` and `other`.
            #[inline]
            fn bitand_assign(&mut self, other: Self) {
                *self =
                    Self::from_bits_retain(self.bits()).intersection(other);
            }
        }
        impl ::bitflags::__private::core::ops::Sub for InternalBitFlags {
            type Output = Self;
            /// The intersection of `self` with the complement of `other` (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub(self, other: Self) -> Self { self.difference(other) }
        }
        impl ::bitflags::__private::core::ops::SubAssign for InternalBitFlags
            {
            /// The intersection of `self` with the complement of `other` (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub_assign(&mut self, other: Self) { self.remove(other); }
        }
        impl ::bitflags::__private::core::ops::Not for InternalBitFlags {
            type Output = Self;
            /// The bitwise negation (`!`) of the bits in `self`, truncating the result.
            #[inline]
            fn not(self) -> Self { self.complement() }
        }
        impl ::bitflags::__private::core::iter::Extend<InternalBitFlags> for
            InternalBitFlags {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(&mut self, iterator: T) {
                for item in iterator { self.insert(item) }
            }
        }
        impl ::bitflags::__private::core::iter::FromIterator<InternalBitFlags>
            for InternalBitFlags {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(iterator: T) -> Self {
                use ::bitflags::__private::core::iter::Extend;
                let mut result = Self::empty();
                result.extend(iterator);
                result
            }
        }
        impl InternalBitFlags {
            /// Yield a set of contained flags values.
            ///
            /// Each yielded flags value will correspond to a defined named flag. Any unknown bits
            /// will be yielded together as a final flags value.
            #[inline]
            pub const fn iter(&self) -> ::bitflags::iter::Iter<HideHud> {
                ::bitflags::iter::Iter::__private_const_new(<HideHud as
                        ::bitflags::Flags>::FLAGS,
                    HideHud::from_bits_retain(self.bits()),
                    HideHud::from_bits_retain(self.bits()))
            }
            /// Yield a set of contained named flags values.
            ///
            /// This method is like [`iter`](#method.iter), except only yields bits in contained named flags.
            /// Any unknown bits, or bits not corresponding to a contained flag will not be yielded.
            #[inline]
            pub const fn iter_names(&self)
                -> ::bitflags::iter::IterNames<HideHud> {
                ::bitflags::iter::IterNames::__private_const_new(<HideHud as
                        ::bitflags::Flags>::FLAGS,
                    HideHud::from_bits_retain(self.bits()),
                    HideHud::from_bits_retain(self.bits()))
            }
        }
        impl ::bitflags::__private::core::iter::IntoIterator for
            InternalBitFlags {
            type Item = HideHud;
            type IntoIter = ::bitflags::iter::Iter<HideHud>;
            fn into_iter(self) -> Self::IntoIter { self.iter() }
        }
        impl InternalBitFlags {
            /// Returns a mutable reference to the raw value of the flags currently stored.
            #[inline]
            pub fn bits_mut(&mut self) -> &mut u32 { &mut self.0 }
        }
        impl HideHud {
            /// Get a flags value with all bits unset.
            #[inline]
            pub const fn empty() -> Self { Self(InternalBitFlags::empty()) }
            /// Get a flags value with all known bits set.
            #[inline]
            pub const fn all() -> Self { Self(InternalBitFlags::all()) }
            /// Get the underlying bits value.
            ///
            /// The returned value is exactly the bits set in this flags value.
            #[inline]
            pub const fn bits(&self) -> u32 { self.0.bits() }
            /// Convert from a bits value.
            ///
            /// This method will return `None` if any unknown bits are set.
            #[inline]
            pub const fn from_bits(bits: u32)
                -> ::bitflags::__private::core::option::Option<Self> {
                match InternalBitFlags::from_bits(bits) {
                    ::bitflags::__private::core::option::Option::Some(bits) =>
                        ::bitflags::__private::core::option::Option::Some(Self(bits)),
                    ::bitflags::__private::core::option::Option::None =>
                        ::bitflags::__private::core::option::Option::None,
                }
            }
            /// Convert from a bits value, unsetting any unknown bits.
            #[inline]
            pub const fn from_bits_truncate(bits: u32) -> Self {
                Self(InternalBitFlags::from_bits_truncate(bits))
            }
            /// Convert from a bits value exactly.
            #[inline]
            pub const fn from_bits_retain(bits: u32) -> Self {
                Self(InternalBitFlags::from_bits_retain(bits))
            }
            /// Get a flags value with the bits of a flag with the given name set.
            ///
            /// This method will return `None` if `name` is empty or doesn't
            /// correspond to any named flag.
            #[inline]
            pub fn from_name(name: &str)
                -> ::bitflags::__private::core::option::Option<Self> {
                match InternalBitFlags::from_name(name) {
                    ::bitflags::__private::core::option::Option::Some(bits) =>
                        ::bitflags::__private::core::option::Option::Some(Self(bits)),
                    ::bitflags::__private::core::option::Option::None =>
                        ::bitflags::__private::core::option::Option::None,
                }
            }
            /// Whether all bits in `self` are unset.
            #[inline]
            pub const fn is_empty(&self) -> bool { self.0.is_empty() }
            /// Whether all known bits in this flags value are set.
            #[inline]
            pub const fn is_all(&self) -> bool { self.0.is_all() }
            /// Whether any set bits in `other` are also set in `self`.
            #[inline]
            pub const fn intersects(&self, other: Self) -> bool {
                self.0.intersects(other.0)
            }
            /// Whether all set bits in `other` are also set in `self`.
            #[inline]
            pub const fn contains(&self, other: Self) -> bool {
                self.0.contains(other.0)
            }
            /// The bitwise or (`|`) of the bits in `self` and `other`.
            #[inline]
            pub fn insert(&mut self, other: Self) { self.0.insert(other.0) }
            /// The intersection of `self` with the complement of `other` (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `remove` won't truncate `other`, but the `!` operator will.
            #[inline]
            pub fn remove(&mut self, other: Self) { self.0.remove(other.0) }
            /// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
            #[inline]
            pub fn toggle(&mut self, other: Self) { self.0.toggle(other.0) }
            /// Call `insert` when `value` is `true` or `remove` when `value` is `false`.
            #[inline]
            pub fn set(&mut self, other: Self, value: bool) {
                self.0.set(other.0, value)
            }
            /// The bitwise and (`&`) of the bits in `self` and `other`.
            #[inline]
            #[must_use]
            pub const fn intersection(self, other: Self) -> Self {
                Self(self.0.intersection(other.0))
            }
            /// The bitwise or (`|`) of the bits in `self` and `other`.
            #[inline]
            #[must_use]
            pub const fn union(self, other: Self) -> Self {
                Self(self.0.union(other.0))
            }
            /// The intersection of `self` with the complement of `other` (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            #[must_use]
            pub const fn difference(self, other: Self) -> Self {
                Self(self.0.difference(other.0))
            }
            /// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
            #[inline]
            #[must_use]
            pub const fn symmetric_difference(self, other: Self) -> Self {
                Self(self.0.symmetric_difference(other.0))
            }
            /// The bitwise negation (`!`) of the bits in `self`, truncating the result.
            #[inline]
            #[must_use]
            pub const fn complement(self) -> Self {
                Self(self.0.complement())
            }
        }
        impl ::bitflags::__private::core::fmt::Binary for HideHud {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::Octal for HideHud {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::LowerHex for HideHud {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::UpperHex for HideHud {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::ops::BitOr for HideHud {
            type Output = Self;
            /// The bitwise or (`|`) of the bits in `self` and `other`.
            #[inline]
            fn bitor(self, other: HideHud) -> Self { self.union(other) }
        }
        impl ::bitflags::__private::core::ops::BitOrAssign for HideHud {
            /// The bitwise or (`|`) of the bits in `self` and `other`.
            #[inline]
            fn bitor_assign(&mut self, other: Self) { self.insert(other); }
        }
        impl ::bitflags::__private::core::ops::BitXor for HideHud {
            type Output = Self;
            /// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
            #[inline]
            fn bitxor(self, other: Self) -> Self {
                self.symmetric_difference(other)
            }
        }
        impl ::bitflags::__private::core::ops::BitXorAssign for HideHud {
            /// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
            #[inline]
            fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
        }
        impl ::bitflags::__private::core::ops::BitAnd for HideHud {
            type Output = Self;
            /// The bitwise and (`&`) of the bits in `self` and `other`.
            #[inline]
            fn bitand(self, other: Self) -> Self { self.intersection(other) }
        }
        impl ::bitflags::__private::core::ops::BitAndAssign for HideHud {
            /// The bitwise and (`&`) of the bits in `self` and `other`.
            #[inline]
            fn bitand_assign(&mut self, other: Self) {
                *self =
                    Self::from_bits_retain(self.bits()).intersection(other);
            }
        }
        impl ::bitflags::__private::core::ops::Sub for HideHud {
            type Output = Self;
            /// The intersection of `self` with the complement of `other` (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub(self, other: Self) -> Self { self.difference(other) }
        }
        impl ::bitflags::__private::core::ops::SubAssign for HideHud {
            /// The intersection of `self` with the complement of `other` (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub_assign(&mut self, other: Self) { self.remove(other); }
        }
        impl ::bitflags::__private::core::ops::Not for HideHud {
            type Output = Self;
            /// The bitwise negation (`!`) of the bits in `self`, truncating the result.
            #[inline]
            fn not(self) -> Self { self.complement() }
        }
        impl ::bitflags::__private::core::iter::Extend<HideHud> for HideHud {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(&mut self, iterator: T) {
                for item in iterator { self.insert(item) }
            }
        }
        impl ::bitflags::__private::core::iter::FromIterator<HideHud> for
            HideHud {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(iterator: T) -> Self {
                use ::bitflags::__private::core::iter::Extend;
                let mut result = Self::empty();
                result.extend(iterator);
                result
            }
        }
        impl HideHud {
            /// Yield a set of contained flags values.
            ///
            /// Each yielded flags value will correspond to a defined named flag. Any unknown bits
            /// will be yielded together as a final flags value.
            #[inline]
            pub const fn iter(&self) -> ::bitflags::iter::Iter<HideHud> {
                ::bitflags::iter::Iter::__private_const_new(<HideHud as
                        ::bitflags::Flags>::FLAGS,
                    HideHud::from_bits_retain(self.bits()),
                    HideHud::from_bits_retain(self.bits()))
            }
            /// Yield a set of contained named flags values.
            ///
            /// This method is like [`iter`](#method.iter), except only yields bits in contained named flags.
            /// Any unknown bits, or bits not corresponding to a contained flag will not be yielded.
            #[inline]
            pub const fn iter_names(&self)
                -> ::bitflags::iter::IterNames<HideHud> {
                ::bitflags::iter::IterNames::__private_const_new(<HideHud as
                        ::bitflags::Flags>::FLAGS,
                    HideHud::from_bits_retain(self.bits()),
                    HideHud::from_bits_retain(self.bits()))
            }
        }
        impl ::bitflags::__private::core::iter::IntoIterator for HideHud {
            type Item = HideHud;
            type IntoIter = ::bitflags::iter::Iter<HideHud>;
            fn into_iter(self) -> Self::IntoIter { self.iter() }
        }
    };bitflags::bitflags! {
97	/// The parts of the HUD a player's `m_iHideHUD` hides (`HIDEHUD_*`).
98	///
99	/// Clients receive only the low [`HIDEHUD_BITCOUNT`](raw::HIDEHUD_BITCOUNT)
100	/// bits, which the named flags cover. Others read back as set, but no
101	/// client sees them.
102	#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
103	pub struct HideHud: u32 {
104		/// The whole HUD.
105		#[doc(alias("HIDEHUD_ALL"))]
106		const ALL = raw::HIDEHUD_ALL as u32;
107
108		/// The bonus progress display of other Source games.
109		#[doc(alias("HIDEHUD_BONUS_PROGRESS"))]
110		const BONUS_PROGRESS = raw::HIDEHUD_BONUS_PROGRESS as u32;
111
112		/// The Engineer's building status.
113		#[doc(alias("HIDEHUD_BUILDING_STATUS"))]
114		const BUILDING_STATUS = raw::HIDEHUD_BUILDING_STATUS as u32;
115
116		/// Chat, and the other communication elements, such as the voice
117		/// icons.
118		#[doc(alias("HIDEHUD_CHAT"))]
119		const CHAT = raw::HIDEHUD_CHAT as u32;
120
121		/// The item effect meters, such as the Spy's cloak.
122		#[doc(alias("HIDEHUD_CLOAK_AND_FEIGN"))]
123		const CLOAK_AND_FEIGN = raw::HIDEHUD_CLOAK_AND_FEIGN as u32;
124
125		/// The crosshair.
126		#[doc(alias("HIDEHUD_CROSSHAIR"))]
127		const CROSSHAIR = raw::HIDEHUD_CROSSHAIR as u32;
128
129		/// The flashlight meter of other Source games.
130		#[doc(alias("HIDEHUD_FLASHLIGHT"))]
131		const FLASHLIGHT = raw::HIDEHUD_FLASHLIGHT as u32;
132
133		/// The health display.
134		#[doc(alias("HIDEHUD_HEALTH"))]
135		const HEALTH = raw::HIDEHUD_HEALTH as u32;
136
137		/// What a player in a vehicle should not see.
138		#[doc(alias("HIDEHUD_INVEHICLE"))]
139		const IN_VEHICLE = raw::HIDEHUD_INVEHICLE as u32;
140
141		/// The match status, such as the round timer and the team status at
142		/// the top of the screen.
143		#[doc(alias("HIDEHUD_MATCH_STATUS"))]
144		const MATCH_STATUS = raw::HIDEHUD_MATCH_STATUS as u32;
145
146		/// The Engineer's metal display.
147		#[doc(alias("HIDEHUD_METAL"))]
148		const METAL = raw::HIDEHUD_METAL as u32;
149
150		/// Miscellaneous status elements, such as the pickup history and the
151		/// kill feed.
152		#[doc(alias("HIDEHUD_MISCSTATUS"))]
153		const MISC_STATUS = raw::HIDEHUD_MISCSTATUS as u32;
154
155		/// What a player without Half-Life 2's HEV suit should not see.
156		#[doc(alias("HIDEHUD_NEEDSUIT"))]
157		const NEED_SUIT = raw::HIDEHUD_NEEDSUIT as u32;
158
159		/// The Demoman's sticky bomb count and shield charge meter.
160		#[doc(alias("HIDEHUD_PIPES_AND_CHARGE"))]
161		const PIPES_AND_CHARGE = raw::HIDEHUD_PIPES_AND_CHARGE as u32;
162
163		/// What a dead player should not see.
164		#[doc(alias("HIDEHUD_PLAYERDEAD"))]
165		const PLAYER_DEAD = raw::HIDEHUD_PLAYERDEAD as u32;
166
167		/// The target ID: the name and health of the player under the
168		/// crosshair.
169		#[doc(alias("HIDEHUD_TARGET_ID"))]
170		const TARGET_ID = raw::HIDEHUD_TARGET_ID as u32;
171
172		/// The vehicle crosshair of other Source games.
173		#[doc(alias("HIDEHUD_VEHICLE_CROSSHAIR"))]
174		const VEHICLE_CROSSHAIR = raw::HIDEHUD_VEHICLE_CROSSHAIR as u32;
175
176		/// The ammo count and the weapon selection.
177		#[doc(alias("HIDEHUD_WEAPONSELECTION"))]
178		const WEAPON_SELECTION = raw::HIDEHUD_WEAPONSELECTION as u32;
179	}
180}
181
182/// Why a [`TfPlayer`] operation failed.
183#[derive(#[automatically_derived]
impl ::core::fmt::Debug for PlayerError {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Self::Interface(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Interface", &__self_0),
            Self::MarkedForDeletion =>
                ::core::fmt::Formatter::write_str(f, "MarkedForDeletion"),
            Self::NetProp(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "NetProp", &__self_0),
            Self::NonFinite =>
                ::core::fmt::Formatter::write_str(f, "NonFinite"),
            Self::NotAlive =>
                ::core::fmt::Formatter::write_str(f, "NotAlive"),
            Self::NotNetworked =>
                ::core::fmt::Formatter::write_str(f, "NotNetworked"),
            Self::NotPlaying =>
                ::core::fmt::Formatter::write_str(f, "NotPlaying"),
            Self::NotTfPlayer =>
                ::core::fmt::Formatter::write_str(f, "NotTfPlayer"),
            Self::Rejected =>
                ::core::fmt::Formatter::write_str(f, "Rejected"),
            Self::UnknownClass(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "UnknownClass", &__self_0),
            Self::UnknownState(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "UnknownState", &__self_0),
            Self::UnknownTeam(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "UnknownTeam", &__self_0),
            Self::UnsupportedMethod =>
                ::core::fmt::Formatter::write_str(f, "UnsupportedMethod"),
            Self::UserMessage(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "UserMessage", &__self_0),
        }
    }
}Debug, #[allow(unused_qualifications)]
#[automatically_derived]
impl ::thiserror::__private21::Error for PlayerError {
    fn source(&self)
        ->
            ::core::option::Option<&(dyn ::thiserror::__private21::Error +
            'static)> {
        use ::thiserror::__private21::AsDynError as _;

        #[allow(deprecated)]
        match self {
            PlayerError::Interface { 0: transparent } =>
                ::thiserror::__private21::Error::source(transparent.as_dyn_error()),
            PlayerError::MarkedForDeletion { .. } =>
                ::core::option::Option::None,
            PlayerError::NetProp { 0: transparent } =>
                ::thiserror::__private21::Error::source(transparent.as_dyn_error()),
            PlayerError::NonFinite { .. } => ::core::option::Option::None,
            PlayerError::NotAlive { .. } => ::core::option::Option::None,
            PlayerError::NotNetworked { .. } => ::core::option::Option::None,
            PlayerError::NotPlaying { .. } => ::core::option::Option::None,
            PlayerError::NotTfPlayer { .. } => ::core::option::Option::None,
            PlayerError::Rejected { .. } => ::core::option::Option::None,
            PlayerError::UnknownClass { .. } => ::core::option::Option::None,
            PlayerError::UnknownState { .. } => ::core::option::Option::None,
            PlayerError::UnknownTeam { .. } => ::core::option::Option::None,
            PlayerError::UnsupportedMethod { .. } =>
                ::core::option::Option::None,
            PlayerError::UserMessage { 0: transparent } =>
                ::thiserror::__private21::Error::source(transparent.as_dyn_error()),
        }
    }
}
#[allow(unused_qualifications)]
#[automatically_derived]
impl ::core::fmt::Display for PlayerError {
    fn fmt(&self, __formatter: &mut ::core::fmt::Formatter)
        -> ::core::fmt::Result {
        use ::thiserror::__private21::AsDisplay as _;

        #[allow(unused_variables, deprecated, clippy ::
        used_underscore_binding)]
        match self {
            PlayerError::Interface(_0) =>
                ::core::fmt::Display::fmt(_0, __formatter),
            PlayerError::MarkedForDeletion {} =>
                __formatter.write_str("the player is marked for deletion"),
            PlayerError::NetProp(_0) =>
                ::core::fmt::Display::fmt(_0, __formatter),
            PlayerError::NonFinite {} =>
                __formatter.write_str("a value given is NaN or infinite"),
            PlayerError::NotAlive {} =>
                __formatter.write_str("the player is not alive"),
            PlayerError::NotNetworked {} =>
                __formatter.write_str("the player is not networked"),
            PlayerError::NotPlaying {} =>
                __formatter.write_str("the player is not on a playing team"),
            PlayerError::NotTfPlayer {} =>
                __formatter.write_str("player operations require a TF2 player"),
            PlayerError::Rejected {} =>
                __formatter.write_str("the native method rejected its arguments"),
            PlayerError::UnknownClass(_0) =>
                match (_0.as_display(),) {
                    (__display0,) =>
                        __formatter.write_fmt(format_args!("the player\'s class {0} is not one of TF2\'s playable classes",
                                __display0)),
                },
            PlayerError::UnknownState(_0) =>
                match (_0.as_display(),) {
                    (__display0,) =>
                        __formatter.write_fmt(format_args!("the player\'s state {0} is not one of TF2\'s",
                                __display0)),
                },
            PlayerError::UnknownTeam(_0) =>
                match (_0.as_display(),) {
                    (__display0,) =>
                        __formatter.write_fmt(format_args!("the player\'s team {0} is not one of TF2\'s",
                                __display0)),
                },
            PlayerError::UnsupportedMethod {} =>
                __formatter.write_str("the game does not expose the expected native method"),
            PlayerError::UserMessage(_0) =>
                ::core::fmt::Display::fmt(_0, __formatter),
        }
    }
}
PlayerError
#[allow(clippy :: redundant_field_names)]
fn from(source: InterfaceError) -> Self {
    PlayerError::Interface { 0: source }
}
PlayerError
#[allow(clippy :: redundant_field_names)]
fn from(source: NetPropError) -> Self { PlayerError::NetProp { 0: source } }
PlayerError
#[allow(clippy :: redundant_field_names)]
fn from(source: UserMessageError) -> Self {
    PlayerError::UserMessage { 0: source }
}thiserror::Error)]
184pub enum PlayerError {
185	/// A required engine interface is unavailable.
186	#[error(transparent)]
187	Interface(#[from] InterfaceError),
188
189	/// The player is marked for deletion.
190	#[error("the player is marked for deletion")]
191	MarkedForDeletion,
192
193	/// A networked variable could not be read or written.
194	#[error(transparent)]
195	NetProp(#[from] NetPropError),
196
197	/// A vector, angle or time given has a component that is NaN or infinite.
198	#[error("a value given is NaN or infinite")]
199	NonFinite,
200
201	/// The player is not alive.
202	#[error("the player is not alive")]
203	NotAlive,
204
205	/// The player has no edict, so no client knows it.
206	#[error("the player is not networked")]
207	NotNetworked,
208
209	/// The player is on neither RED nor BLU, which have the class menus.
210	#[error("the player is not on a playing team")]
211	NotPlaying,
212
213	/// The entity is not a TF2 player, or the server does not run TF2.
214	#[error("player operations require a TF2 player")]
215	NotTfPlayer,
216
217	/// The native binding of the member reported failure.
218	#[error("the native method rejected its arguments")]
219	Rejected,
220
221	/// The player's `m_iClass` or `m_iDesiredPlayerClass` holds neither
222	/// `TF_CLASS_UNDEFINED` nor a playable class, as scripts can make it.
223	#[error("the player's class {0} is not one of TF2's playable classes")]
224	UnknownClass(c_int),
225
226	/// The player's `m_nPlayerState` is not one of TF2's player states.
227	#[error("the player's state {0} is not one of TF2's")]
228	UnknownState(c_int),
229
230	/// The player's `m_iTeamNum` is not one of TF2's teams.
231	#[error("the player's team {0} is not one of TF2's")]
232	UnknownTeam(c_int),
233
234	/// The player's script class descriptors lack the member, or its
235	/// signature differs from the SDK's.
236	#[error("the game does not expose the expected native method")]
237	UnsupportedMethod,
238
239	/// The game's menu could not be sent to the player.
240	#[error(transparent)]
241	UserMessage(#[from] UserMessageError),
242}
243
244impl From<BindingError> for PlayerError {
245	fn from(error: BindingError) -> Self {
246		match error {
247			BindingError::Unavailable | BindingError::SignatureMismatch => Self::UnsupportedMethod,
248			BindingError::Rejected => Self::Rejected,
249		}
250	}
251}
252
253/// Where a TF2 player is in the game's handling of them (`m_nPlayerState`).
254#[derive(#[automatically_derived]
impl ::core::fmt::Debug for PlayerState {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                PlayerState::Active => "Active",
                PlayerState::Welcome => "Welcome",
                PlayerState::Observer => "Observer",
                PlayerState::Dying => "Dying",
            })
    }
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for PlayerState { }
#[automatically_derived]
impl ::core::clone::Clone for PlayerState {
    #[inline]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for PlayerState { }Copy, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for PlayerState { }
#[automatically_derived]
impl ::core::cmp::PartialEq for PlayerState {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        ::core::intrinsics::discriminant_value(self) ==
            ::core::intrinsics::discriminant_value(other)
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for PlayerState { }Eq, #[automatically_derived]
impl ::core::hash::Hash for PlayerState {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&::core::intrinsics::discriminant_value(self),
            state)
    }
}Hash)]
255pub enum PlayerState {
256	/// Playing, alive or dead, until they start to observe
257	/// (`TF_STATE_ACTIVE`).
258	#[doc(alias("TF_STATE_ACTIVE"))]
259	Active,
260
261	/// Just joined the server, and has chosen no team yet
262	/// (`TF_STATE_WELCOME`).
263	#[doc(alias("TF_STATE_WELCOME"))]
264	Welcome,
265
266	/// Observing, as spectators, unassigned players, and dead players once
267	/// the death cam ends, do (`TF_STATE_OBSERVER`).
268	#[doc(alias("TF_STATE_OBSERVER"))]
269	Observer,
270
271	/// Dying: from death until the player starts to observe
272	/// (`TF_STATE_DYING`).
273	#[doc(alias("TF_STATE_DYING"))]
274	Dying,
275}
276
277impl PlayerState {
278	/// The state TF2 numbers `raw`, or `None` if it numbers none so.
279	pub const fn from_raw(raw: c_int) -> Option<Self> {
280		match raw {
281			raw::TF_STATE_ACTIVE => Some(Self::Active),
282			raw::TF_STATE_WELCOME => Some(Self::Welcome),
283			raw::TF_STATE_OBSERVER => Some(Self::Observer),
284			raw::TF_STATE_DYING => Some(Self::Dying),
285			_ => None,
286		}
287	}
288
289	/// TF2's number for the state.
290	pub const fn to_raw(self) -> c_int {
291		match self {
292			Self::Active => raw::TF_STATE_ACTIVE,
293			Self::Welcome => raw::TF_STATE_WELCOME,
294			Self::Observer => raw::TF_STATE_OBSERVER,
295			Self::Dying => raw::TF_STATE_DYING,
296		}
297	}
298}
299
300/// A TF2 player or bot, within one engine callback.
301///
302/// Keep the player's [`EntityHandle`] across callbacks, and wrap it again in
303/// each.
304#[derive(#[automatically_derived]
impl<'s> ::core::fmt::Debug for TfPlayer<'s> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "TfPlayer",
            "server", &self.server, "player", &&self.player)
    }
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl<'s> ::core::clone::TrivialClone for TfPlayer<'s> { }
#[automatically_derived]
impl<'s> ::core::clone::Clone for TfPlayer<'s> {
    #[inline]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<Server<'s>>;
        let _: ::core::clone::AssertParamIsClone<Entity<'s>>;
        *self
    }
}Clone, #[automatically_derived]
impl<'s> ::core::marker::Copy for TfPlayer<'s> { }Copy)]
305pub struct TfPlayer<'s> {
306	server: Server<'s>,
307	player: Entity<'s>,
308}
309
310impl<'s> TfPlayer<'s> {
311	/// Wraps a player, or returns [`PlayerError::NotTfPlayer`] unless the
312	/// server runs TF2 and `player`'s datamaps include `CTFPlayer`.
313	pub fn new(server: Server<'s>, player: Entity<'s>) -> Result<Self, PlayerError> {
314		if server.game() != Game::TeamFortress2 || !player.has_data_map_class(c"CTFPlayer") {
315			return Err(PlayerError::NotTfPlayer);
316		}
317
318		Ok(Self { server, player })
319	}
320
321	/// Hides more parts of the player's HUD, keeping those hidden already
322	/// (`AddHudHideFlags`).
323	#[doc(alias("AddHudHideFlags", "m_iHideHUD"))]
324	pub fn add_hud_hide_flags(self, flags: HideHud) -> Result<(), PlayerError> {
325		self.call_with_flags(c"AddHudHideFlags", flags)
326	}
327
328	/// Pushes the player, adding `impulse` to their velocity as an explosion's
329	/// knockback does (`ApplyAbsVelocityImpulse`), in units per second.
330	///
331	/// TF2 scales the push first: it doubles it for a player shrunk by
332	/// `TF_COND_HALLOWEEN_TINY`, scales it by a scoped Sniper's
333	/// `mult_aiming_knockback_resistance`, and its horizontal part by 1.5 for
334	/// a player with a parachute open (or by 0 for one of Mann vs. Machine's
335	/// robots). Fails with [`PlayerError::NonFinite`] for an impulse that is
336	/// not finite, before the game is called.
337	#[doc(alias("ApplyAbsVelocityImpulse"))]
338	pub fn apply_impulse(self, impulse: Vector) -> Result<(), PlayerError> {
339		if !impulse.is_finite() {
340			return Err(PlayerError::NonFinite);
341		}
342
343		let impulse = sys::Vector::from(impulse);
344
345		// SAFETY: The checked member adds the finite impulse, which it only
346		// reads during the call, to the player's velocity.
347		unsafe {
348			self.call(
349				c"ApplyAbsVelocityImpulse",
350				&mut [vector(&impulse)],
351				binding::VOID,
352			)
353		}?;
354
355		Ok(())
356	}
357
358	/// Calls one of the native members `CTFPlayer` exposes to VScript, for a
359	/// player not marked for deletion.
360	///
361	/// # Safety
362	///
363	/// As for [`binding::call`]: the member must accept this player and these
364	/// arguments, which must stay valid for the call.
365	unsafe fn call(
366		self,
367		name: &CStr,
368		arguments: &mut [sys::ScriptVariant_t],
369		result_type: sys::ScriptDataType_t,
370	) -> Result<sys::ScriptVariant_t, PlayerError> {
371		self.check_live()?;
372
373		// SAFETY: The caller vouches for the member and its arguments.
374		Ok(unsafe { binding::call(self.player, SCRIPT_CLASS, name, arguments, result_type) }?)
375	}
376
377	/// Calls a member that returns one float.
378	///
379	/// # Safety
380	///
381	/// As for [`Self::call`].
382	unsafe fn call_for_float(self, name: &CStr) -> Result<f32, PlayerError> {
383		// SAFETY: The caller vouches for the member.
384		let result = unsafe { self.call(name, &mut [], binding::FLOAT) }?;
385
386		// SAFETY: The checked return type selects the float member.
387		Ok(unsafe { result.__bindgen_anon_1.m_float })
388	}
389
390	/// Calls a member that takes one boolean and returns nothing.
391	///
392	/// # Safety
393	///
394	/// As for [`Self::call`].
395	unsafe fn call_with_bool(self, name: &CStr, value: bool) -> Result<(), PlayerError> {
396		// SAFETY: The caller vouches for the member.
397		unsafe { self.call(name, &mut [boolean(value)], binding::VOID) }?;
398
399		Ok(())
400	}
401
402	/// Calls one of the members that write `m_iHideHUD` with `flags`.
403	fn call_with_flags(self, name: &CStr, flags: HideHud) -> Result<(), PlayerError> {
404		// SAFETY: The HUD flag members only compute and store the player's
405		// `m_iHideHUD`, of which clients read the bits they know.
406		unsafe { self.call(name, &mut [int(flags.bits() as c_int)], binding::VOID) }?;
407
408		Ok(())
409	}
410
411	/// Calls a member that takes a model's path and returns nothing.
412	fn call_with_model(self, name: &CStr, model: &CStr) -> Result<(), PlayerError> {
413		// SAFETY: The custom model members precache the model, copying its
414		// path, which they read only during the call, into the string pool.
415		// Updating the player's model frees nothing.
416		unsafe { self.call(name, &mut [binding::string(model)], binding::VOID) }?;
417
418		Ok(())
419	}
420
421	/// Fails with [`PlayerError::MarkedForDeletion`] for a player marked for
422	/// deletion.
423	fn check_live(self) -> Result<(), PlayerError> {
424		if self.player.is_marked_for_deletion() {
425			Err(PlayerError::MarkedForDeletion)
426		} else {
427			Ok(())
428		}
429	}
430
431	/// The player's class (`m_iClass`), or `None` until they first spawn as
432	/// one (`TF_CLASS_UNDEFINED`).
433	///
434	/// Fails with [`PlayerError::UnknownClass`] for any other value, such as
435	/// the civilian a script can set.
436	#[doc(alias("m_iClass", "GetPlayerClass"))]
437	pub fn class(self) -> Result<Option<PlayerClass>, PlayerError> {
438		self.read_class(c"m_iClass")
439	}
440
441	/// Clears the player's custom model, its offset and its rotation, so they
442	/// show their class's model again (`SetCustomModel` with an empty path).
443	#[doc(alias("SetCustomModel"))]
444	pub fn clear_custom_model(self) -> Result<(), PlayerError> {
445		self.call_with_model(c"SetCustomModel", c"")
446	}
447
448	/// Clears the rotation of the player's custom model
449	/// (`ClearCustomModelRotation`).
450	#[doc(alias("ClearCustomModelRotation"))]
451	pub fn clear_custom_model_rotation(self) -> Result<(), PlayerError> {
452		// SAFETY: The member resets the stored rotation, and invalidates the
453		// player's cached angles.
454		unsafe { self.call(c"ClearCustomModelRotation", &mut [], binding::VOID) }?;
455
456		Ok(())
457	}
458
459	/// Kills the player as the `kill` and `explode` commands do, through the
460	/// game's `CTFPlayer::CommitSuicide`, and returns whether they died.
461	///
462	/// With `explode`, the player bursts into gibs. TF2 refuses the suicide of
463	/// a player who is not alive, who has no class or is not in
464	/// [`PlayerState::Active`], who is a ghost or in a kart, while the match
465	/// summary shows, and, without `force`, of a player on the losing team
466	/// after a round is won.
467	///
468	/// The death runs the game's, other plugins', and this plugin's own death
469	/// callbacks synchronously, before this returns, such as hooks of the
470	/// player's `Event_Killed` and listeners of `player_death`. They must keep
471	/// to the contract of [`Server::new`].
472	#[doc(alias("CommitSuicide"))]
473	pub fn commit_suicide(self, explode: bool, force: bool) -> Result<bool, PlayerError> {
474		self.check_live()?;
475
476		if !self.player.is_alive() {
477			return Ok(false);
478		}
479
480		let player = self.player.as_ptr().cast::<sys::CTFPlayer>();
481
482		// SAFETY: `new` found `CTFPlayer` in the player's datamaps, so it is
483		// one, whose entity base `sdk_raw::tf2` asserts is at offset zero, and
484		// whose generated TF2 vtable has this entry under the target's ABI, at
485		// the slot `sdk_raw::tf2::player` checks. The callback keeps the player
486		// allocated, and the callbacks the death runs are bound by
487		// `Server::new`'s contract, which lets them free entities only through
488		// deferred deletion.
489		unsafe {
490			{
    let this = player;
    let vtable =
        ::source_sdk_2013_raw::util::vtable::vtable_pointer::<sys::CTFPlayer__bindgen_vtable>(this);
    ((*vtable).CTFPlayer_CommitSuicide)(this.cast(), explode, force)
}vcall!(player as sys::CTFPlayer__bindgen_vtable => CTFPlayer_CommitSuicide(explode, force))
491		};
492
493		Ok(!self.player.is_alive())
494	}
495
496	/// The class the player chose to play next (`m_iDesiredPlayerClass`),
497	/// which they spawn as, or `None` if they have chosen none.
498	///
499	/// Fails with [`PlayerError::UnknownClass`] for a value that is neither
500	/// `TF_CLASS_UNDEFINED` nor a playable class.
501	#[doc(alias("m_iDesiredPlayerClass", "GetDesiredPlayerClassIndex"))]
502	pub fn desired_class(self) -> Result<Option<PlayerClass>, PlayerError> {
503		self.read_class(c"m_iDesiredPlayerClass")
504	}
505
506	/// The angles the player looks along (`EyeAngles`): their view angles, in
507	/// the world's frame even while they move with a parent entity, whose frame
508	/// the game keeps their view angles in then.
509	#[doc(alias("EyeAngles"))]
510	pub fn eye_angles(self) -> Result<QAngle, PlayerError> {
511		self.check_live()?;
512
513		let player = self.player.as_ptr().cast::<sys::CTFPlayer>();
514
515		// SAFETY: As for `commit_suicide`, at the slot `sdk_raw::tf2::player`
516		// checks. The method only reads the player and its parent, and returns
517		// a reference to angles the player holds, or to a static, copied before
518		// anything can change them.
519		let angles = unsafe {
520			{
    let this = player;
    let vtable =
        ::source_sdk_2013_raw::util::vtable::vtable_pointer::<sys::CTFPlayer__bindgen_vtable>(this);
    ((*vtable).CTFPlayer_EyeAngles)(this.cast())
}vcall!(player as sys::CTFPlayer__bindgen_vtable => CTFPlayer_EyeAngles()).read()
521		};
522
523		Ok(angles.into())
524	}
525
526	/// Where the player sees from (`EyePosition`): their origin raised by their
527	/// [view offset](Self::view_offset).
528	#[doc(alias("EyePosition"))]
529	pub fn eye_position(self) -> Result<Vector, PlayerError> {
530		self.check_live()?;
531
532		let player = self.player.as_ptr().cast::<sys::CTFPlayer>();
533
534		// SAFETY: As for `commit_suicide`, at the slot `sdk_raw::tf2::player`
535		// checks, whose generated entry returns a `Vector` by value in one of
536		// the shapes `vcall_by_value!` calls. The method only reads the player.
537		let position = unsafe {
538			{
    let result: sys::Vector =
        {
            let this = player;
            let vtable =
                ::source_sdk_2013_raw::util::vtable::vtable_pointer::<sys::CTFPlayer__bindgen_vtable>(this);
            ((*vtable).CTFPlayer_EyePosition)(this.cast())
        };
    result
}vcall_by_value!(player as sys::CTFPlayer__bindgen_vtable => CTFPlayer_EyePosition() -> sys::Vector)
539		};
540
541		Ok(position.into())
542	}
543
544	/// Moves the player to `team` as the game's own team changes do
545	/// (`ForceChangeTeam`), whatever the team limits and balance allow.
546	///
547	/// TF2 removes the player's buildings and projectiles, and leaves a
548	/// living player alive, on the new team, unless `full_team_switch` is
549	/// false in highlander mode, which kills them and clears their class. A
550	/// player moved to [`Team::Spectator`] loses their weapons, and one moved
551	/// to [`Team::Spectator`] or [`Team::Unassigned`] starts to observe.
552	/// Without `full_team_switch`, the player's dominations end too, as they
553	/// do when a player changes teams themselves; the game passes it when it
554	/// swaps whole teams.
555	///
556	/// TF2 changes nothing for a player already on the team, nor for one in a
557	/// duel or coaching another, and outside community game modes its game
558	/// rules can assign another team, as Mann vs. Machine does. The change
559	/// runs the game's, other plugins', and this plugin's own callbacks
560	/// synchronously, such as `metamod_source`'s `team_hooks` and listeners of
561	/// `player_team`, and they must keep to the contract of [`Server::new`].
562	#[doc(alias("ForceChangeTeam", "ChangeClientTeam"))]
563	pub fn force_change_team(self, team: Team, full_team_switch: bool) -> Result<(), PlayerError> {
564		// SAFETY: The checked member accepts every global team, and frees the
565		// entities it removes, and those its callbacks free, only through
566		// deferred deletion (`Server::new`'s contract).
567		unsafe {
568			self.call(
569				c"ForceChangeTeam",
570				&mut [int(team.to_raw()), boolean(full_team_switch)],
571				binding::VOID,
572			)
573		}?;
574
575		Ok(())
576	}
577
578	/// Hides both teams' class menus from the player, if shown.
579	pub fn hide_class_menu(self) -> Result<(), PlayerError> {
580		self.send_panel(raw::PANEL_CLASS_RED, false)?;
581		self.send_panel(raw::PANEL_CLASS_BLUE, false)
582	}
583
584	/// Hides the team menu from the player, if shown.
585	pub fn hide_team_menu(self) -> Result<(), PlayerError> {
586		self.send_panel(raw::PANEL_TEAM, false)
587	}
588
589	/// The parts of the HUD hidden from the player (`GetHudHideFlags`).
590	#[doc(alias("GetHudHideFlags", "m_iHideHUD"))]
591	pub fn hud_hide_flags(self) -> Result<HideHud, PlayerError> {
592		// SAFETY: The member returns the player's `m_iHideHUD`.
593		let result = unsafe { self.call(c"GetHudHideFlags", &mut [], INT) }?;
594
595		// SAFETY: The checked return type selects the integer member.
596		let flags = unsafe { result.__bindgen_anon_1.m_int };
597
598		Ok(HideHud::from_bits_retain(flags as u32))
599	}
600
601	/// Whether the player has called for a Medic in the last few seconds
602	/// (`IsCallingForMedic`).
603	#[doc(alias("IsCallingForMedic"))]
604	pub fn is_calling_for_medic(self) -> Result<bool, PlayerError> {
605		// SAFETY: The member compares the time of the player's last call with
606		// the current time.
607		let result = unsafe { self.call(c"IsCallingForMedic", &mut [], BOOL) }?;
608
609		// SAFETY: The checked return type selects the boolean member.
610		Ok(unsafe { result.__bindgen_anon_1.m_bool })
611	}
612
613	/// Resolves one of the player's networked variables.
614	fn net_prop(self, name: &CStr) -> Result<NetProp<'s>, PlayerError> {
615		Ok(self
616			.server
617			.server_game_dll()?
618			.entity_net_prop(self.player, name)?)
619	}
620
621	/// The game time from which the player may change their class again
622	/// (`GetNextChangeClassTime`), as the game's current time counts it.
623	#[doc(alias("GetNextChangeClassTime", "m_flNextChangeClassTime"))]
624	pub fn next_change_class_time(self) -> Result<f32, PlayerError> {
625		// SAFETY: The member returns a field of the player.
626		unsafe { self.call_for_float(c"GetNextChangeClassTime") }
627	}
628
629	/// The game time from which the player may change their team again
630	/// (`GetNextChangeTeamTime`), as the game's current time counts it.
631	#[doc(alias("GetNextChangeTeamTime", "m_flNextChangeTeamTime"))]
632	pub fn next_change_team_time(self) -> Result<f32, PlayerError> {
633		// SAFETY: The member returns a field of the player.
634		unsafe { self.call_for_float(c"GetNextChangeTeamTime") }
635	}
636
637	/// The player.
638	pub const fn player(self) -> Entity<'s> {
639		self.player
640	}
641
642	/// The player's latest `tf_ragdoll` (`m_hRagdoll`), from which clients
643	/// make the ragdoll or gibs of their last death, or `None` if they have
644	/// none, or it is marked for deletion.
645	#[doc(alias("m_hRagdoll"))]
646	pub fn ragdoll(self) -> Result<Option<TfRagdoll<'s>>, PlayerError> {
647		let handle = self.net_prop(c"m_hRagdoll")?.get_handle(self.player)?;
648
649		Ok(self
650			.server
651			.server_tools()?
652			.entity_by_handle(handle)
653			.filter(|ragdoll| !ragdoll.is_marked_for_deletion())
654			.and_then(|ragdoll| TfRagdoll::new(self.server, ragdoll).ok()))
655	}
656
657	/// Reads a class variable, which holds `TF_CLASS_UNDEFINED` or a playable
658	/// class.
659	fn read_class(self, name: &CStr) -> Result<Option<PlayerClass>, PlayerError> {
660		let raw = self.net_prop(name)?.get::<c_int>(self.player)?;
661
662		match raw {
663			0 => Ok(None),
664
665			raw => PlayerClass::from_raw(raw)
666				.map(Some)
667				.ok_or(PlayerError::UnknownClass(raw)),
668		}
669	}
670
671	/// Resupplies the living player as a resupply cabinet does
672	/// (`Regenerate`).
673	///
674	/// TF2 sets the player up as their class afresh, which hands out their
675	/// loadout's weapons and cosmetics again, keeps any overheal, and, with
676	/// `refill_health_and_ammo`, refills their health and ammo and ends the
677	/// conditions a resupply cabinet cures, such as burning and bleeding.
678	/// Without it, their health and ammo stay as they are.
679	///
680	/// Handing out items creates entities, which runs entity-creation and
681	/// spawn callbacks synchronously, before this returns: the game's, other
682	/// plugins', and this plugin's own. They must keep to the contract of
683	/// [`Server::new`]. Fails with [`PlayerError::NotAlive`] before the game is
684	/// called for a player who is not alive.
685	#[doc(alias("Regenerate"))]
686	pub fn regenerate(self, refill_health_and_ammo: bool) -> Result<(), PlayerError> {
687		self.check_live()?;
688
689		if !self.player.is_alive() {
690			return Err(PlayerError::NotAlive);
691		}
692
693		// SAFETY: The checked member resupplies this living player. It frees
694		// the items it replaces, and its callbacks free entities, only through
695		// deferred deletion (`Server::new`'s contract).
696		unsafe { self.call_with_bool(c"Regenerate", refill_health_and_ammo) }
697	}
698
699	/// Respawns the player afresh, dead or alive, as their desired class, with
700	/// their health, ammo and items as a resupply leaves them
701	/// (`ForceRegenerateAndRespawn`).
702	///
703	/// This goes through the player's `ForceRespawn`, as
704	/// [`force_respawn`](crate::tf2::respawn::force_respawn) does, and does
705	/// nothing in the same cases.
706	#[doc(alias("ForceRegenerateAndRespawn"))]
707	pub fn regenerate_and_respawn(self) -> Result<(), PlayerError> {
708		// SAFETY: The checked member respawns the player as `force_respawn`
709		// does, whose spawn callbacks are bound by `Server::new`'s contract.
710		unsafe { self.call(c"ForceRegenerateAndRespawn", &mut [], binding::VOID) }?;
711
712		Ok(())
713	}
714
715	/// Shows parts of the player's HUD again (`RemoveHudHideFlags`).
716	#[doc(alias("RemoveHudHideFlags", "m_iHideHUD"))]
717	pub fn remove_hud_hide_flags(self, flags: HideHud) -> Result<(), PlayerError> {
718		self.call_with_flags(c"RemoveHudHideFlags", flags)
719	}
720
721	/// Removes the player's [ragdoll](Self::ragdoll), so clients make none of
722	/// their last death, or none from now on if they made it already, and
723	/// returns whether there was one to remove.
724	///
725	/// The `tf_ragdoll` is removed as the game removes it, with deferred
726	/// deletion, and `m_hRagdoll` cleared, which the game checks before each
727	/// use. Remove it in the frame of the death to keep clients from making
728	/// its ragdoll at all.
729	#[doc(alias("m_hRagdoll"))]
730	pub fn remove_ragdoll(self) -> Result<bool, PlayerError> {
731		self.check_live()?;
732
733		let prop = self.net_prop(c"m_hRagdoll")?;
734		let engine = self.server.valve_engine()?;
735		let tools = self.server.server_tools()?;
736		let Some(ragdoll) = self.ragdoll()? else {
737			return Ok(false);
738		};
739
740		if tools.remove(ragdoll.entity()).is_err() {
741			return Ok(false);
742		}
743
744		// SAFETY: A player has no ragdoll until their first death, and the
745		// game checks it for one before each use.
746		unsafe { prop.set_handle(engine, self.player, EntityHandle::INVALID) }?;
747
748		Ok(true)
749	}
750
751	/// Sends the player the game's message showing or hiding a panel.
752	fn send_panel(self, name: &CStr, show: bool) -> Result<(), PlayerError> {
753		self.check_live()?;
754
755		let edict = self.player.edict().ok_or(PlayerError::NotNetworked)?;
756		let menu = VguiMenu {
757			name,
758			show,
759			keys: &[],
760		};
761
762		user_messages::send(self.server, &Recipients::player(edict).reliable(), &menu)?;
763
764		Ok(())
765	}
766
767	/// Changes the player's class at once, as scripts do (`SetPlayerClass`),
768	/// without respawning them.
769	///
770	/// TF2 sets the player up as the class: their speed, maximum health and
771	/// abilities follow it, and their weapons are told of the change. Their
772	/// model, weapons and health stay as they are until they next spawn or
773	/// resupply, as do their [desired class](Self::desired_class), which they
774	/// spawn as, and their custom model, which this clears.
775	#[doc(alias("SetPlayerClass", "m_iClass"))]
776	pub fn set_class(self, class: PlayerClass) -> Result<(), PlayerError> {
777		// SAFETY: The checked member sets the player up as a playable class,
778		// as the game does itself, and frees nothing.
779		unsafe { self.call(c"SetPlayerClass", &mut [int(class.to_raw())], binding::VOID) }?;
780
781		Ok(())
782	}
783
784	/// Marks the class menu as open on the player's client, or closed, as
785	/// the client reports it, by running the client's `menuopen` or
786	/// `menuclosed` command for them.
787	///
788	/// While the game counts a dead player's class menu as open, they miss
789	/// respawn waves, and once it closes, they spawn at once if the game
790	/// would have spawned them meanwhile. A client reports its own menu
791	/// whenever it shows or hides it, overriding this.
792	///
793	/// The command goes through the engine's client command handling, as a
794	/// client's own commands do, so command hooks and listeners, the game's
795	/// and other plugins' included, run before this returns, and it counts
796	/// toward `sv_quota_stringcmdspersecond`.
797	#[doc(alias("menuopen", "menuclosed", "m_bIsClassMenuOpen"))]
798	pub fn set_class_menu_open(self, open: bool) -> Result<(), PlayerError> {
799		self.check_live()?;
800
801		let edict = self.player.edict().ok_or(PlayerError::NotNetworked)?;
802		let command = if open { c"menuopen" } else { c"menuclosed" };
803
804		self.server.plugin_helpers()?.client_command(edict, command);
805
806		Ok(())
807	}
808
809	/// Shows the player as `model`, a model's path such as
810	/// `models/bots/scout/bot_scout.mdl`, with the model's own animations
811	/// (`SetCustomModel`).
812	///
813	/// TF2 precaches the model if needed, which takes an entry of the level's
814	/// model table until the level ends, and fails the level if the table is
815	/// full. So precache models when the level starts, and do not take paths
816	/// from untrusted input. The model stays until it is cleared or the player
817	/// changes class, through respawns.
818	#[doc(alias("SetCustomModel"))]
819	pub fn set_custom_model(self, model: &CStr) -> Result<(), PlayerError> {
820		self.call_with_model(c"SetCustomModel", model)
821	}
822
823	/// Offsets the player's custom model from where the player stands
824	/// (`SetCustomModelOffset`). Fails with [`PlayerError::NonFinite`] for an
825	/// offset that is not finite.
826	#[doc(alias("SetCustomModelOffset"))]
827	pub fn set_custom_model_offset(self, offset: Vector) -> Result<(), PlayerError> {
828		if !offset.is_finite() {
829			return Err(PlayerError::NonFinite);
830		}
831
832		let offset = sys::Vector::from(offset);
833
834		// SAFETY: The checked member stores the finite offset, which it only
835		// reads during the call, and invalidates the player's cached position.
836		unsafe {
837			self.call(
838				c"SetCustomModelOffset",
839				&mut [vector(&offset)],
840				binding::VOID,
841			)
842		}?;
843
844		Ok(())
845	}
846
847	/// Whether the player's custom model turns with the player, as it does by
848	/// default (`SetCustomModelRotates`).
849	#[doc(alias("SetCustomModelRotates"))]
850	pub fn set_custom_model_rotates(self, rotates: bool) -> Result<(), PlayerError> {
851		// SAFETY: The checked member stores the flag, and invalidates the
852		// player's cached angles.
853		unsafe { self.call_with_bool(c"SetCustomModelRotates", rotates) }
854	}
855
856	/// Rotates the player's custom model (`SetCustomModelRotation`). Fails
857	/// with [`PlayerError::NonFinite`] for angles that are not finite.
858	#[doc(alias("SetCustomModelRotation"))]
859	pub fn set_custom_model_rotation(self, rotation: QAngle) -> Result<(), PlayerError> {
860		if ![rotation.pitch, rotation.yaw, rotation.roll]
861			.iter()
862			.all(|angle| angle.is_finite())
863		{
864			return Err(PlayerError::NonFinite);
865		}
866
867		let rotation = sys::QAngle::from(rotation);
868
869		// SAFETY: The checked member stores the finite angles, which it only
870		// reads during the call, and invalidates the player's cached angles.
871		unsafe {
872			self.call(
873				c"SetCustomModelRotation",
874				&mut [qangle(&rotation)],
875				binding::VOID,
876			)
877		}?;
878
879		Ok(())
880	}
881
882	/// Turns the player to look along `angles` at once (`SnapEyeAngles`), as
883	/// teleporters do. The game holds the angles for the player's next
884	/// command: a human's client is turned to them, and a bot's command runs
885	/// with them in place of its own, so the bot's weapon fires along them.
886	/// A bot's own aiming turns it again from there on its next update.
887	///
888	/// Fails with [`PlayerError::NonFinite`] for angles that are not finite.
889	#[doc(alias("SnapEyeAngles"))]
890	pub fn snap_eye_angles(self, angles: QAngle) -> Result<(), PlayerError> {
891		if ![angles.pitch, angles.yaw, angles.roll]
892			.iter()
893			.all(|angle| angle.is_finite())
894		{
895			return Err(PlayerError::NonFinite);
896		}
897
898		self.check_live()?;
899
900		let angles = sys::QAngle::from(angles);
901
902		// SAFETY: The checked member copies the finite angles, which it only
903		// reads during the call, into the player's view angles, and marks them
904		// fixed for the player's next command.
905		unsafe {
906			binding::call(
907				self.player,
908				BASE_SCRIPT_CLASS,
909				c"SnapEyeAngles",
910				&mut [qangle(&angles)],
911				binding::VOID,
912			)
913		}?;
914
915		Ok(())
916	}
917
918	/// Whether the player sees their custom model in third person, as they do
919	/// by default (`SetCustomModelVisibleToSelf`).
920	#[doc(alias("SetCustomModelVisibleToSelf"))]
921	pub fn set_custom_model_visible_to_self(self, visible: bool) -> Result<(), PlayerError> {
922		// SAFETY: The checked member stores the flag.
923		unsafe { self.call_with_bool(c"SetCustomModelVisibleToSelf", visible) }
924	}
925
926	/// As [`Self::set_custom_model`], but animates the model with the
927	/// player's class's animations, as Mann vs. Machine's robots are
928	/// (`SetCustomModelWithClassAnimations`).
929	#[doc(alias("SetCustomModelWithClassAnimations"))]
930	pub fn set_custom_model_with_class_animations(self, model: &CStr) -> Result<(), PlayerError> {
931		self.call_with_model(c"SetCustomModelWithClassAnimations", model)
932	}
933
934	/// Sets the class the player spawns as next (`m_iDesiredPlayerClass`),
935	/// as choosing it from the class menu would, without its checks or
936	/// respawn, or clears it with `None`, which keeps the player from
937	/// spawning until they choose one.
938	#[doc(alias("m_iDesiredPlayerClass", "SetDesiredPlayerClassIndex"))]
939	pub fn set_desired_class(self, class: Option<PlayerClass>) -> Result<(), PlayerError> {
940		self.check_live()?;
941
942		let engine = self.server.valve_engine()?;
943		let raw = class.map_or(0, PlayerClass::to_raw);
944
945		// SAFETY: The game assigns `TF_CLASS_UNDEFINED` and the playable
946		// classes itself.
947		unsafe {
948			self.net_prop(c"m_iDesiredPlayerClass")?
949				.set(engine, self.player, raw)
950		}?;
951
952		Ok(())
953	}
954
955	/// Forces the player's view into third person, as taunts do, or lets
956	/// them choose it again (`SetForcedTauntCam`). The game clears it as the
957	/// player spawns.
958	#[doc(alias("SetForcedTauntCam", "m_nForceTauntCam"))]
959	pub fn set_forced_taunt_cam(self, cam: ForcedTauntCam) -> Result<(), PlayerError> {
960		// SAFETY: The checked member stores one of the values the game uses.
961		unsafe {
962			self.call(
963				c"SetForcedTauntCam",
964				&mut [int(cam.to_raw())],
965				binding::VOID,
966			)
967		}?;
968
969		Ok(())
970	}
971
972	/// Hides exactly `flags`'s parts of the player's HUD, showing the others
973	/// (`SetHudHideFlags`).
974	#[doc(alias("SetHudHideFlags", "m_iHideHUD"))]
975	pub fn set_hud_hide_flags(self, flags: HideHud) -> Result<(), PlayerError> {
976		self.call_with_flags(c"SetHudHideFlags", flags)
977	}
978
979	/// Sets the game time from which the player may change their class again
980	/// (`SetNextChangeClassTime`). Fails with [`PlayerError::NonFinite`] for a
981	/// time that is not finite.
982	#[doc(alias("SetNextChangeClassTime", "m_flNextChangeClassTime"))]
983	pub fn set_next_change_class_time(self, time: f32) -> Result<(), PlayerError> {
984		self.set_time(c"SetNextChangeClassTime", time)
985	}
986
987	/// Sets the game time from which the player may change their team again
988	/// (`SetNextChangeTeamTime`). Fails with [`PlayerError::NonFinite`] for a
989	/// time that is not finite.
990	#[doc(alias("SetNextChangeTeamTime", "m_flNextChangeTeamTime"))]
991	pub fn set_next_change_team_time(self, time: f32) -> Result<(), PlayerError> {
992		self.set_time(c"SetNextChangeTeamTime", time)
993	}
994
995	/// Calls a member that stores a finite game time.
996	fn set_time(self, name: &CStr, time: f32) -> Result<(), PlayerError> {
997		if !time.is_finite() {
998			return Err(PlayerError::NonFinite);
999		}
1000
1001		// SAFETY: The time members store a field of the player.
1002		unsafe { self.call(name, &mut [binding::float(time)], binding::VOID) }?;
1003
1004		Ok(())
1005	}
1006
1007	/// Shows the player their team's class menu, as the game does as they join
1008	/// a team. Fails with [`PlayerError::NotPlaying`] for a player on neither
1009	/// RED nor BLU.
1010	pub fn show_class_menu(self) -> Result<(), PlayerError> {
1011		let panel = match self.team()? {
1012			Team::Red => raw::PANEL_CLASS_RED,
1013			Team::Blue => raw::PANEL_CLASS_BLUE,
1014			Team::Unassigned | Team::Spectator => return Err(PlayerError::NotPlaying),
1015		};
1016
1017		self.send_panel(panel, true)
1018	}
1019
1020	/// Shows the player the team menu, as the game does as they join the
1021	/// server.
1022	pub fn show_team_menu(self) -> Result<(), PlayerError> {
1023		self.send_panel(raw::PANEL_TEAM, true)
1024	}
1025
1026	/// A bit the game flips each time the player spawns (`m_iSpawnCounter`),
1027	/// from which clients tell that they respawned. A change between two
1028	/// reads means they spawned an odd number of times in between.
1029	///
1030	/// Despite its name, the variable is a `bool`, which TF2 sends as an 8-bit
1031	/// integer.
1032	#[doc(alias("m_iSpawnCounter"))]
1033	pub fn spawn_parity(self) -> Result<bool, PlayerError> {
1034		Ok(self
1035			.net_prop(c"m_iSpawnCounter")?
1036			.get::<bool>(self.player)?)
1037	}
1038
1039	/// Where the player is in the game's handling of them
1040	/// (`m_nPlayerState`).
1041	#[doc(alias("m_nPlayerState"))]
1042	pub fn state(self) -> Result<PlayerState, PlayerError> {
1043		let raw = self
1044			.net_prop(c"m_nPlayerState")?
1045			.get::<c_int>(self.player)?;
1046
1047		PlayerState::from_raw(raw).ok_or(PlayerError::UnknownState(raw))
1048	}
1049
1050	/// The player's team (`m_iTeamNum`).
1051	#[doc(alias("m_iTeamNum", "GetTeamNumber"))]
1052	pub fn team(self) -> Result<Team, PlayerError> {
1053		let raw = self.net_prop(c"m_iTeamNum")?.get::<c_int>(self.player)?;
1054
1055		Team::from_raw(raw).ok_or(PlayerError::UnknownTeam(raw))
1056	}
1057
1058	/// The player's view offset (`m_vecViewOffset`): how far above their
1059	/// origin they see from, which depends on their class and whether they
1060	/// duck.
1061	#[doc(alias("m_vecViewOffset", "GetViewOffset"))]
1062	pub fn view_offset(self) -> Result<Vector, PlayerError> {
1063		let [x, y, z] = VIEW_OFFSET.map(|name| {
1064			self.net_prop(name)
1065				.and_then(|prop| Ok(prop.get::<f32>(self.player)?))
1066		});
1067
1068		Ok(Vector::new(x?, y?, z?))
1069	}
1070}