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