use super::{EncodeError, MessageId, NetMessage, Reliability};
use crate::bitbuf::BitWriter;
use crate::math::{QAngle, Vector};
use sdk_raw::edicts::MAX_EDICT_BITS;
use std::ffi::CStr;
pub(super) const ANGLE_BITS: u32 = 16;
pub(super) const DECAL_INDEX_BITS: u32 = 9;
pub const MAX_COMMAND_LEN: usize = 1023;
pub const MAX_CONVAR_LEN: usize = sdk_raw::net::incoming::MAX_OSPATH - 1;
#[doc(alias("MAX_USER_MSG_DATA"))]
pub const MAX_MESSAGE_DATA_BYTES: usize = 255;
pub const MAX_PRINT_LEN: usize = 2047;
pub const MAX_QUERY_NAME_LEN: usize = 255;
pub const MAX_VOICE_DATA_BYTES: usize = ((1 << VOICE_LENGTH_BITS) - 1) / 8;
pub(super) const MODEL_INDEX_BITS: u32 = 13;
pub(super) const PAYLOAD_LENGTH_BITS: u32 = 11;
pub(super) const SERVER_CLASS_BITS: u32 = 9;
pub(super) const SOUND_INDEX_BITS: u32 = 14;
pub(super) const VOICE_LENGTH_BITS: u32 = 16;
#[doc(alias("SVC_BSPDecal"))]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct BspDecal {
pub position: Vector,
pub texture: u16,
pub target: Option<DecalTarget>,
pub low_priority: bool,
}
impl NetMessage for BspDecal {
fn id(&self) -> MessageId {
MessageId::BSP_DECAL
}
fn write_body(&self, out: &mut BitWriter) -> Result<(), EncodeError> {
EncodeError::check_bits("texture", self.texture.into(), DECAL_INDEX_BITS)?;
if let Some(target) = self.target {
EncodeError::check_bits("entity", target.entity.into(), MAX_EDICT_BITS)?;
EncodeError::check_bits("model", target.model.into(), MODEL_INDEX_BITS)?;
}
out.write_bit_vec3_coord(self.position);
out.write_ubits(self.texture.into(), DECAL_INDEX_BITS);
match self.target {
Some(target) => {
out.write_bit(true);
out.write_ubits(target.entity.into(), MAX_EDICT_BITS);
out.write_ubits(target.model.into(), MODEL_INDEX_BITS);
}
None => out.write_bit(false),
}
out.write_bit(self.low_priority);
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DecalTarget {
pub entity: u16,
pub model: u16,
}
#[doc(alias("SVC_EntityMessage"))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EntityMessage<'a> {
pub entity: u16,
pub class_id: u16,
pub data: &'a BitWriter,
}
impl NetMessage for EntityMessage<'_> {
fn id(&self) -> MessageId {
MessageId::ENTITY_MESSAGE
}
fn write_body(&self, out: &mut BitWriter) -> Result<(), EncodeError> {
EncodeError::check_bits("entity", self.entity.into(), MAX_EDICT_BITS)?;
EncodeError::check_bits("class ID", self.class_id.into(), SERVER_CLASS_BITS)?;
let mut body = BitWriter::new();
body.write_ubits(self.entity.into(), MAX_EDICT_BITS);
body.write_ubits(self.class_id.into(), SERVER_CLASS_BITS);
write_payload(
&mut body,
"entity message data",
self.data,
MAX_MESSAGE_DATA_BYTES,
)?;
out.write_bits(&body);
Ok(())
}
}
#[doc(alias("SVC_FixAngle"))]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct FixAngle {
pub relative: bool,
pub angles: QAngle,
}
impl NetMessage for FixAngle {
fn id(&self) -> MessageId {
MessageId::FIX_ANGLE
}
fn write_body(&self, out: &mut BitWriter) -> Result<(), EncodeError> {
out.write_bit(self.relative);
out.write_bit_angle(self.angles.pitch, ANGLE_BITS);
out.write_bit_angle(self.angles.yaw, ANGLE_BITS);
out.write_bit_angle(self.angles.roll, ANGLE_BITS);
Ok(())
}
}
#[doc(alias("SVC_GameEvent"))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct GameEvent<'a> {
pub data: &'a BitWriter,
}
impl NetMessage for GameEvent<'_> {
fn id(&self) -> MessageId {
MessageId::GAME_EVENT
}
fn write_body(&self, out: &mut BitWriter) -> Result<(), EncodeError> {
write_payload(out, "game event data", self.data, usize::MAX)
}
}
#[doc(alias("SVC_GetCvarValue"))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct GetCvarValue<'a> {
pub cookie: i32,
pub name: &'a CStr,
}
impl NetMessage for GetCvarValue<'_> {
fn id(&self) -> MessageId {
MessageId::GET_CVAR_VALUE
}
fn write_body(&self, out: &mut BitWriter) -> Result<(), EncodeError> {
EncodeError::check_len("name", self.name.count_bytes(), MAX_QUERY_NAME_LEN)?;
out.write_i32(self.cookie);
out.write_cstr(self.name);
Ok(())
}
}
#[doc(alias("SVC_Prefetch"))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Prefetch {
pub sound: u16,
}
impl NetMessage for Prefetch {
fn id(&self) -> MessageId {
MessageId::PREFETCH
}
fn write_body(&self, out: &mut BitWriter) -> Result<(), EncodeError> {
EncodeError::check_bits("sound", self.sound.into(), SOUND_INDEX_BITS)?;
out.write_ubits(self.sound.into(), SOUND_INDEX_BITS);
Ok(())
}
}
#[doc(alias("SVC_Print"))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Print<'a> {
pub text: &'a CStr,
}
impl NetMessage for Print<'_> {
fn id(&self) -> MessageId {
MessageId::PRINT
}
fn write_body(&self, out: &mut BitWriter) -> Result<(), EncodeError> {
EncodeError::check_len("text", self.text.count_bytes(), MAX_PRINT_LEN)?;
out.write_cstr(self.text);
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Raw<'a> {
pub id: MessageId,
pub body: &'a BitWriter,
}
impl NetMessage for Raw<'_> {
fn id(&self) -> MessageId {
self.id
}
fn write_body(&self, out: &mut BitWriter) -> Result<(), EncodeError> {
out.write_bits(self.body);
Ok(())
}
}
#[doc(alias("NET_SetConVar"))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SetConVar<'a> {
pub convars: &'a [(&'a CStr, &'a CStr)],
}
impl NetMessage for SetConVar<'_> {
fn id(&self) -> MessageId {
MessageId::SET_CONVAR
}
fn write_body(&self, out: &mut BitWriter) -> Result<(), EncodeError> {
let count = u8::try_from(self.convars.len()).map_err(|_| EncodeError::OutOfRange {
field: "convar count",
value: self.convars.len() as u64,
max: u8::MAX.into(),
})?;
out.write_u8(count);
for &(name, value) in self.convars {
EncodeError::check_len("convar name", name.count_bytes(), MAX_CONVAR_LEN)?;
EncodeError::check_len("convar value", value.count_bytes(), MAX_CONVAR_LEN)?;
out.write_cstr(name);
out.write_cstr(value);
}
Ok(())
}
}
#[doc(alias("SVC_SetPause"))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SetPause {
pub paused: bool,
}
impl NetMessage for SetPause {
fn id(&self) -> MessageId {
MessageId::SET_PAUSE
}
fn write_body(&self, out: &mut BitWriter) -> Result<(), EncodeError> {
out.write_bit(self.paused);
Ok(())
}
}
#[doc(alias("SVC_SetView"))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SetView {
pub entity: u16,
}
impl NetMessage for SetView {
fn id(&self) -> MessageId {
MessageId::SET_VIEW
}
fn write_body(&self, out: &mut BitWriter) -> Result<(), EncodeError> {
EncodeError::check_bits("entity", self.entity.into(), MAX_EDICT_BITS)?;
out.write_ubits(self.entity.into(), MAX_EDICT_BITS);
Ok(())
}
}
#[doc(alias("NET_StringCmd"))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct StringCmd<'a> {
pub command: &'a CStr,
}
impl NetMessage for StringCmd<'_> {
fn id(&self) -> MessageId {
MessageId::STRING_CMD
}
fn write_body(&self, out: &mut BitWriter) -> Result<(), EncodeError> {
EncodeError::check_len("command", self.command.count_bytes(), MAX_COMMAND_LEN)?;
out.write_cstr(self.command);
Ok(())
}
}
#[doc(alias("SVC_UserMessage"))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct UserMessage<'a> {
pub message_type: u8,
pub data: &'a BitWriter,
}
impl NetMessage for UserMessage<'_> {
fn id(&self) -> MessageId {
MessageId::USER_MESSAGE
}
fn write_body(&self, out: &mut BitWriter) -> Result<(), EncodeError> {
let mut body = BitWriter::new();
body.write_u8(self.message_type);
write_payload(
&mut body,
"user message data",
self.data,
MAX_MESSAGE_DATA_BYTES,
)?;
out.write_bits(&body);
Ok(())
}
}
#[doc(alias("SVC_VoiceData"))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct VoiceData<'a> {
pub speaker: u8,
pub proximity: bool,
pub data: &'a [u8],
}
impl NetMessage for VoiceData<'_> {
fn id(&self) -> MessageId {
MessageId::VOICE_DATA
}
fn reliability(&self) -> Reliability {
Reliability::Unreliable
}
fn write_body(&self, out: &mut BitWriter) -> Result<(), EncodeError> {
EncodeError::check_len("voice data", self.data.len(), MAX_VOICE_DATA_BYTES)?;
out.write_u8(self.speaker);
out.write_u8(self.proximity.into());
out.write_u16((self.data.len() * 8) as u16);
out.write_bytes(self.data);
Ok(())
}
}
fn write_payload(
out: &mut BitWriter,
field: &'static str,
data: &BitWriter,
max_bytes: usize,
) -> Result<(), EncodeError> {
EncodeError::check_len(field, data.byte_len(), max_bytes)?;
EncodeError::check_bits(field, data.len() as u64, PAYLOAD_LENGTH_BITS)?;
out.write_ubits(data.len() as u32, PAYLOAD_LENGTH_BITS);
out.write_bits(data);
Ok(())
}