tf_demo_parser/demo/message/
serverinfo.rs1use crate::demo::parser::{Encode, ParseBitSkip};
2use crate::{Parse, ParserState, Result, Stream};
3use bitbuffer::{BitRead, BitWrite, BitWriteStream, LittleEndian};
4use serde::{Deserialize, Serialize};
5
6#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
7#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
8pub struct ServerInfoMessage {
9 pub version: u16,
10 pub server_count: u32,
11 pub stv: bool,
12 pub dedicated: bool,
13 pub max_crc: u32,
14 pub max_classes: u16,
15 pub map_hash: [u8; 16],
16 pub player_slot: u8,
17 pub max_player_count: u8,
18 pub interval_per_tick: f32,
19 pub platform: String,
20 pub game: String,
21 pub map: String,
22 pub skybox: String,
23 pub server_name: String,
24 pub replay: bool,
25}
26
27impl<'a> Parse<'a> for ServerInfoMessage {
28 fn parse(stream: &mut Stream<'a>, state: &ParserState) -> Result<Self> {
29 let part1 = ServerInfoMessagePart1::read(stream)?;
30 let map_hash = if state.protocol_version > 17 {
31 <[u8; 16]>::read(stream)?
32 } else {
33 let mut hash = [0; 16];
34 let crc = u32::read(stream)?;
35 hash[0..4].copy_from_slice(&crc.to_le_bytes());
36 hash
37 };
38 let part2 = ServerInfoMessagePart2::read(stream)?;
39 let replay = if state.protocol_version > 15 {
40 bool::read(stream)?
41 } else {
42 false
43 };
44 Ok(ServerInfoMessage {
45 version: part1.version,
46 server_count: part1.server_count,
47 stv: part1.stv,
48 dedicated: part1.dedicated,
49 max_crc: part1.max_crc,
50 max_classes: part1.max_classes,
51 map_hash,
52 player_slot: part2.player_slot,
53 max_player_count: part2.max_player_count,
54 interval_per_tick: part2.interval_per_tick,
55 platform: part2.platform,
56 game: part2.game,
57 map: part2.map,
58 skybox: part2.skybox,
59 server_name: part2.server_name,
60 replay,
61 })
62 }
63}
64
65impl<'a> ParseBitSkip<'a> for ServerInfoMessage {
66 fn parse_skip(stream: &mut Stream<'a>, state: &ParserState) -> Result<()> {
67 let version_dependent_size = match state.protocol_version {
68 0..=15 => 4 * 8, 16..=17 => 4 * 8 + 1, 18.. => 16 * 8 + 1, };
72 let size = <ServerInfoMessagePart1 as BitRead<LittleEndian>>::bit_size()
73 .unwrap_or_default()
74 + <ServerInfoMessagePart2 as BitRead<LittleEndian>>::bit_size().unwrap_or_default()
75 + version_dependent_size;
76 stream.skip_bits(size)?;
77 Ok(())
78 }
79}
80
81impl Encode for ServerInfoMessage {
82 fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> {
83 let part1 = ServerInfoMessagePart1 {
84 version: self.version,
85 server_count: self.server_count,
86 stv: self.stv,
87 dedicated: self.dedicated,
88 max_crc: self.max_crc,
89 max_classes: self.max_classes,
90 };
91 part1.write(stream)?;
92 if state.protocol_version > 17 {
93 self.map_hash.write(stream)?;
94 } else {
95 let crc = u32::from_le_bytes([
96 self.map_hash[0],
97 self.map_hash[1],
98 self.map_hash[2],
99 self.map_hash[3],
100 ]);
101 crc.write(stream)?;
102 };
103 let part2 = ServerInfoMessagePart2 {
104 player_slot: self.player_slot,
105 max_player_count: self.max_player_count,
106 interval_per_tick: self.interval_per_tick,
107 platform: self.platform.clone(),
108 game: self.game.clone(),
109 map: self.map.clone(),
110 skybox: self.skybox.clone(),
111 server_name: self.server_name.clone(),
112 };
113 part2.write(stream)?;
114 if state.protocol_version > 15 {
115 self.replay.write(stream)?;
116 }
117 Ok(())
118 }
119}
120
121#[derive(BitRead, BitWrite)]
122pub struct ServerInfoMessagePart1 {
123 pub version: u16,
124 pub server_count: u32,
125 pub stv: bool,
126 pub dedicated: bool,
127 pub max_crc: u32,
128 pub max_classes: u16,
129}
130
131#[derive(BitRead, BitWrite)]
132pub struct ServerInfoMessagePart2 {
133 pub player_slot: u8,
134 pub max_player_count: u8,
135 pub interval_per_tick: f32,
136 #[size = 1]
137 pub platform: String,
138 pub game: String,
139 pub map: String,
140 pub skybox: String,
141 pub server_name: String,
142}