tf_demo_parser/demo/packet/
mod.rs1use bitbuffer::{BitRead, BitWrite, BitWriteStream, LittleEndian};
2
3use crate::{Parse, ParserState, Result, Stream};
4
5use self::consolecmd::ConsoleCmdPacket;
6use self::datatable::DataTablePacket;
7use self::message::MessagePacket;
8use self::stop::StopPacket;
9use self::stringtable::StringTablePacket;
10use self::synctick::SyncTickPacket;
11use self::usercmd::UserCmdPacket;
12use crate::demo::data::DemoTick;
13use crate::demo::parser::Encode;
14use serde::{Deserialize, Serialize};
15#[cfg(feature = "trace")]
16use tracing::{event, span, Level};
17
18pub mod consolecmd;
19pub mod datatable;
20pub mod message;
21pub mod stop;
22pub mod stringtable;
23pub mod synctick;
24pub mod usercmd;
25
26#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
27#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
28#[serde(bound(deserialize = "'a: 'static"))]
29#[serde(tag = "type")]
30pub enum Packet<'a> {
31 Signon(MessagePacket<'a>),
32 Message(MessagePacket<'a>),
33 SyncTick(SyncTickPacket),
34 ConsoleCmd(ConsoleCmdPacket),
35 UserCmd(UserCmdPacket),
36 DataTables(DataTablePacket),
37 Stop(StopPacket),
38 StringTables(StringTablePacket<'a>),
39}
40
41impl Packet<'_> {
42 pub fn tick(&self) -> DemoTick {
43 match self {
44 Packet::Signon(msg) => msg.tick,
45 Packet::Message(msg) => msg.tick,
46 Packet::SyncTick(msg) => msg.tick,
47 Packet::ConsoleCmd(msg) => msg.tick,
48 Packet::UserCmd(msg) => msg.tick,
49 Packet::DataTables(msg) => msg.tick,
50 Packet::Stop(msg) => msg.tick,
51 Packet::StringTables(msg) => msg.tick,
52 }
53 }
54
55 pub fn set_tick(&mut self, tick: DemoTick) {
56 match self {
57 Packet::Signon(msg) => msg.tick = tick,
58 Packet::Message(msg) => msg.tick = tick,
59 Packet::SyncTick(msg) => msg.tick = tick,
60 Packet::ConsoleCmd(msg) => msg.tick = tick,
61 Packet::UserCmd(msg) => msg.tick = tick,
62 Packet::DataTables(msg) => msg.tick = tick,
63 Packet::Stop(msg) => msg.tick = tick,
64 Packet::StringTables(msg) => msg.tick = tick,
65 }
66 }
67}
68
69#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
70#[derive(BitRead, BitWrite, Debug, Clone, Copy, Eq, PartialEq)]
71#[discriminant_bits = 8]
72#[repr(u8)]
73pub enum PacketType {
74 Signon = 1,
75 Message = 2,
76 SyncTick = 3,
77 ConsoleCmd = 4,
78 UserCmd = 5,
79 DataTables = 6,
80 Stop = 7,
81 StringTables = 8,
82}
83
84impl Packet<'_> {
85 pub fn packet_type(&self) -> PacketType {
86 match self {
87 Packet::Signon(_) => PacketType::Signon,
88 Packet::Message(_) => PacketType::Message,
89 Packet::SyncTick(_) => PacketType::SyncTick,
90 Packet::ConsoleCmd(_) => PacketType::ConsoleCmd,
91 Packet::UserCmd(_) => PacketType::UserCmd,
92 Packet::DataTables(_) => PacketType::DataTables,
93 Packet::Stop(_) => PacketType::Stop,
94 Packet::StringTables(_) => PacketType::StringTables,
95 }
96 }
97}
98
99impl<'a> Parse<'a> for Packet<'a> {
100 fn parse(stream: &mut Stream<'a>, state: &ParserState) -> Result<Self> {
101 let packet_type = PacketType::read(stream)?;
102 #[cfg(feature = "trace")]
103 {
104 let tick: u32 = stream.read()?;
105 stream.set_pos(stream.pos() - 32)?;
106 let _span =
107 span!(Level::INFO, "reading packet", packet_type = ?packet_type, tick = tick)
108 .entered();
109 event!(Level::DEBUG, "parsing packet");
110 }
111 Ok(match packet_type {
112 PacketType::Signon => Packet::Signon(MessagePacket::parse(stream, state)?),
113 PacketType::Message => Packet::Message(MessagePacket::parse(stream, state)?),
114 PacketType::SyncTick => Packet::SyncTick(SyncTickPacket::parse(stream, state)?),
115 PacketType::ConsoleCmd => Packet::ConsoleCmd(ConsoleCmdPacket::parse(stream, state)?),
116 PacketType::UserCmd => Packet::UserCmd(UserCmdPacket::parse(stream, state)?),
117 PacketType::DataTables => Packet::DataTables(DataTablePacket::parse(stream, state)?),
118 PacketType::Stop => Packet::Stop(StopPacket::parse(stream, state)?),
119 PacketType::StringTables => {
120 Packet::StringTables(StringTablePacket::parse(stream, state)?)
121 }
122 })
123 }
124}
125
126impl Encode for Packet<'_> {
127 fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> {
128 #[cfg(feature = "trace")]
129 let _span = span!(Level::INFO, "encoding packet", packet_type = ?self.packet_type(), tick = ?self.tick()).entered();
130 self.packet_type().write(stream)?;
131 match self {
132 Packet::Signon(inner) => inner.encode(stream, state),
133 Packet::Message(inner) => inner.encode(stream, state),
134 Packet::SyncTick(inner) => inner.encode(stream, state),
135 Packet::ConsoleCmd(inner) => inner.encode(stream, state),
136 Packet::UserCmd(inner) => inner.encode(stream, state),
137 Packet::DataTables(inner) => inner.encode(stream, state),
138 Packet::Stop(inner) => inner.encode(stream, state),
139 Packet::StringTables(inner) => inner.encode(stream, state),
140 }
141 }
142}
143
144impl PacketType {
145 pub fn as_str(&self) -> &'static str {
146 match self {
147 PacketType::Signon => "Signon",
148 PacketType::Message => "Message",
149 PacketType::SyncTick => "SyncTick",
150 PacketType::ConsoleCmd => "ConsoleCmd",
151 PacketType::UserCmd => "UserCmd",
152 PacketType::DataTables => "DataTables",
153 PacketType::Stop => "Stop",
154 PacketType::StringTables => "StringTables",
155 }
156 }
157
158 pub fn as_lowercase_str(&self) -> &'static str {
159 match self {
160 PacketType::Signon => "signon",
161 PacketType::Message => "message",
162 PacketType::SyncTick => "synctick",
163 PacketType::ConsoleCmd => "consolecmd",
164 PacketType::UserCmd => "usercmd",
165 PacketType::DataTables => "datatables",
166 PacketType::Stop => "stop",
167 PacketType::StringTables => "stringtables",
168 }
169 }
170}