1use crate::net_msg::{
2 ClCallVote, ClCommand, ClNetMessage, ClPlayerInfo, ClSay, ClSetSpectatorMode, ClShowDistance,
3 NetVersion,
4};
5use crate::Input;
6use std::fmt;
7use teehistorian::chunks::{
8 Antibot, Auth, ConsoleCommand, DdnetVersion, DdnetVersionOld, Drop, InputDiff, InputNew,
9 NetMessage, PlayerDiff, PlayerName, PlayerNew, TeamSave, UnknownEx,
10};
11use teehistorian::Chunk;
12use twsnap::time::{Duration, Instant};
13
14pub struct DisplayChunk<'a>(pub &'a Chunk<'a>);
17
18impl fmt::Display for DisplayChunk<'_> {
19 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20 match &self.0 {
21 Chunk::PlayerDiff(player_diff) => {
22 let PlayerDiff { cid, dx, dy } = player_diff;
23 write!(f, "PlayerDiff cid={cid} diff=({dx}, {dy});")
24 }
25 Chunk::Eos => write!(f, "Eos;"),
26 Chunk::TickSkip { dt } => {
27 write!(f, "TickSkip dt={dt};")
28 }
29 Chunk::PlayerNew(player_new) => {
30 let PlayerNew { cid, x, y } = player_new;
31 write!(f, "PlayerNew cid={cid} pos=({x}, {y});")
32 }
33 Chunk::PlayerOld { cid } => {
34 write!(f, "PlayerOld cid={cid};")
35 }
36 Chunk::InputDiff(input_diff) => {
37 let InputDiff { cid, dinput } = input_diff;
38 let Input {
39 direction,
40 target_x,
41 target_y,
42 jump,
43 fire,
44 hook,
45 player_flags,
46 wanted_weapon,
47 next_weapon,
48 prev_weapon,
49 } = Input::from(*dinput);
50 write!(f, "InputDiff cid={cid} direction={direction} target=({target_x}, {target_y}) jump={jump} fire={fire} hook={hook} player_flags={player_flags} wanted_weapon={wanted_weapon} next_weapon={next_weapon} prev_weapon={prev_weapon};")
51 }
52 Chunk::InputNew(input_new) => {
53 let InputNew { cid, input } = input_new;
54 let Input {
55 direction,
56 target_x,
57 target_y,
58 jump,
59 fire,
60 hook,
61 player_flags,
62 wanted_weapon,
63 next_weapon,
64 prev_weapon,
65 } = Input::from(*input);
66 write!(f, "InputNew cid={cid} direction={direction} target=({target_x}, {target_y}) jump={jump} fire={fire} hook={hook} player_flags={player_flags} wanted_weapon={wanted_weapon} next_weapon={next_weapon} prev_weapon={prev_weapon};")
67 }
68 Chunk::NetMessage(net_msg) => {
69 let NetMessage { cid, msg } = net_msg;
70 match crate::net_msg::parse_net_msg(msg, &mut NetVersion::Unknown) {
71 Ok(msg) => match msg {
72 ClNetMessage::ClSay(cl_say) => {
73 let ClSay {
74 mode,
75 target,
76 message,
77 } = cl_say;
78 let message = String::from_utf8_lossy(message);
79 write!(f, "NetMsg cid={cid} type=say mode={mode:?} target={target}, message={message:?};")
80 }
81 ClNetMessage::ClSetTeam(team) => {
82 write!(f, "NetMsg cid={cid} type=set_team team={team:?};")
83 }
84 ClNetMessage::ClSetSpectatorMode(set_spectator_mode) => {
85 let ClSetSpectatorMode {
86 spec_mode,
87 spectator_id,
88 } = set_spectator_mode;
89 write!(f, "NetMsg cid={cid} type=set_spectator_mode spec_mode={spec_mode:?} spectator_id={spectator_id};")
90 }
91 ClNetMessage::ClStartInfo(start_info) => {
92 let ClPlayerInfo {
93 name,
94 clan,
95 country,
96 skin,
97 } = start_info;
98 let name = String::from_utf8_lossy(name);
99 let clan = String::from_utf8_lossy(clan);
100 write!(f, "NetMsg cid={cid} type=start_info name={name:?} clan={clan:?} country={country} skin={skin};")
101 }
102 ClNetMessage::ClChangeInfo(change_info) => {
103 let ClPlayerInfo {
104 name,
105 clan,
106 country,
107 skin,
108 } = change_info;
109 let name = String::from_utf8_lossy(name);
110 let clan = String::from_utf8_lossy(clan);
111 write!(f, "NetMsg cid={cid} type=change_info name={name:?} clan={clan:?} country={country} skin={skin};")
112 }
113 ClNetMessage::ClKill => {
114 write!(f, "NetMsg cid={cid} type=kill;")
115 }
116 ClNetMessage::ClEmoticon(emoticon) => {
117 write!(f, "NetMsg cid={cid} type=emoticon emoticon={emoticon:?};")
118 }
119 ClNetMessage::ClVote(vote) => {
120 write!(f, "NetMsg cid={cid} type=vote vote={vote};")
121 }
122 ClNetMessage::ClCallVote(call_vote) => {
123 let ClCallVote {
124 type_,
125 value,
126 reason,
127 force,
128 } = call_vote;
129 let type_ = String::from_utf8_lossy(type_);
130 let value = String::from_utf8_lossy(value);
131 let reason = String::from_utf8_lossy(reason);
132 write!(f, "NetMsg cid={cid} type=call_vote_type={type_} vote value={value:?} reason={reason:?} force={force};")
133 }
134 ClNetMessage::ClIsDdnet(version) => {
135 write!(f, "NetMsg cid={cid} type=id_ddnet version={version};")
136 }
137 ClNetMessage::ClShowOthers(enabled) => {
138 write!(f, "NetMsg cid={cid} type=show_others enabled={enabled};")
139 }
140 ClNetMessage::ClShowDistance(show_distance) => {
141 let ClShowDistance { x, y } = show_distance;
142 write!(f, "NetMsg cid={cid} type=show_distance x={x} y={y};")
143 }
144 ClNetMessage::ClCameraInfo(camera_info) => {
145 let crate::net_msg::ClCameraInfo {
146 zoom,
147 deadzone,
148 follow_factor,
149 } = camera_info;
150 write!(
151 f,
152 "NetMsg cid={cid} type=camera_info zoom={zoom} deadzone={deadzone} follow_factor={follow_factor};"
153 )
154 }
155 ClNetMessage::ClEnableSpectatorCount(enable) => {
156 write!(
157 f,
158 "NetMsg cid={cid} type=enable_spectator_count enable={enable};"
159 )
160 }
161 ClNetMessage::ClCommand(cl_command) => {
162 let ClCommand { name, arguments } = cl_command;
163 let name = String::from_utf8_lossy(name);
164 let arguments = String::from_utf8_lossy(arguments);
165 write!(f, "NetMsg cid={cid} type=command name={name:?} arguments={arguments:?};")
166 }
167 },
168 Err(_err) => {
169 let msg = hex::encode(msg);
171 write!(f, "NetMsg cid={cid}, raw_msg={msg}")
172 }
173 }
174 }
175 Chunk::Join { cid } => {
176 write!(f, "Join cid={cid};")
177 }
178 Chunk::Drop(drop) => {
179 let Drop { cid, reason } = drop;
180 let reason = String::from_utf8_lossy(reason);
181 write!(f, "Drop cid={cid} reason={reason:?};")
182 }
183 Chunk::ConsoleCommand(console_command) => {
184 let ConsoleCommand {
185 cid,
186 flags,
187 cmd,
188 ref args,
189 } = console_command;
190 let cmd = String::from_utf8_lossy(cmd);
191 let mut had_previous = false;
192 write!(
193 f,
194 "ConsoleCommand cid={cid} flags={flags} cmd={cmd:?} args=["
195 )?;
196 for arg in args {
197 if had_previous {
198 write!(f, " ")?;
199 } else {
200 had_previous = true;
201 }
202 let arg = String::from_utf8_lossy(arg);
203 write!(f, "{arg:?}")?;
204 }
205 write!(f, "];")
206 }
207 Chunk::UnknownEx(unknown_ex) => {
208 let UnknownEx { uuid, data } = unknown_ex;
209 let data = hex::encode(data);
210 write!(f, "UnknownEx uuid={uuid} data={data};")
211 }
212 Chunk::Test => write!(f, "Test;"),
213 Chunk::DdnetVersionOld(ddnet_version_old) => {
214 let DdnetVersionOld { cid, version } = ddnet_version_old;
215 write!(f, "DdnetVersionOld cid={cid} version={version};")
216 }
217 Chunk::DdnetVersion(ddnet_version) => {
218 let DdnetVersion {
219 cid,
220 connection_id,
221 version,
222 version_str,
223 } = ddnet_version;
224 let version_str = String::from_utf8_lossy(version_str);
225 write!(f, "DdnetVersion cid={cid} connection_id={connection_id} version={version} version_str={version_str:?};")
226 }
227 Chunk::AuthInit(auth) => {
228 let Auth {
229 cid,
230 level,
231 auth_name,
232 } = auth;
233 let auth_name = String::from_utf8_lossy(auth_name);
234 write!(
235 f,
236 "AuthInit cid={cid} level={level} auth_name={auth_name:?};"
237 )
238 }
239 Chunk::AuthLogin(auth) => {
240 let Auth {
241 cid,
242 level,
243 auth_name,
244 } = auth;
245 let auth_name = String::from_utf8_lossy(auth_name);
246 write!(
247 f,
248 "AuthLogin cid={cid} level={level} auth_name={auth_name:?};"
249 )
250 }
251 Chunk::AuthLogout { cid } => {
252 write!(f, "AuthLogout cid={cid};")
253 }
254 Chunk::JoinVer6 { cid } => {
255 write!(f, "JoinVer6 cid={cid};")
256 }
257 Chunk::JoinVer7 { cid } => {
258 write!(f, "JoinVer7 cid={cid};")
259 }
260 Chunk::RejoinVer6 { cid } => {
261 write!(f, "RejoinVer6 cid={cid};")
262 }
263 Chunk::TeamSaveSuccess(team_save) => {
264 let TeamSave {
265 team,
266 save_id,
267 save,
268 } = team_save;
269 let save = String::from_utf8_lossy(save);
270 write!(
271 f,
272 "TeamSaveSuccess team={team} save_id={save_id} save={save:?};"
273 )
274 }
275 Chunk::TeamSaveFailure { team } => {
276 write!(f, "TeamSaveFailure team={team};")
277 }
278 Chunk::TeamLoadSuccess(team_save) => {
279 let TeamSave {
280 team,
281 save_id,
282 save,
283 } = team_save;
284 let save = String::from_utf8_lossy(save);
285 write!(
286 f,
287 "TeamLoadSuccess team={team} save_id={save_id} save={save:?};"
288 )
289 }
290 Chunk::TeamLoadFailure { team } => {
291 write!(f, "TeamLoadFailure team={team};")
292 }
293 Chunk::PlayerTeam { cid, team } => {
294 write!(f, "PlayerTeam cid={cid} team={team};")
295 }
296 Chunk::TeamPractice { team, practice } => {
297 write!(f, "TeamPractice team={team} enabled={practice};")
298 }
299 Chunk::PlayerReady { cid } => {
300 write!(f, "PlayerReady cid={cid};")
301 }
302 Chunk::PlayerSwap { cid1, cid2 } => {
303 write!(f, "PlayerSwap cid1={cid1} cid2={cid2};")
304 }
305 Chunk::Antibot(antibot) => {
306 let Antibot { data } = antibot;
307 let data = hex::encode(data);
308 write!(f, "Antibot data={data};")
309 }
310 Chunk::PlayerName(player_name) => {
311 let PlayerName { cid, name } = player_name;
312 let name = String::from_utf8_lossy(name);
313 write!(f, "PlayerName cid={cid} name={name:?};")
314 }
315 Chunk::PlayerFinish { cid, time } => {
316 let time = Instant::zero() + Duration::from_ticks(*time);
317 write!(f, r#"PlayerFinish cid={cid} time="{time}";"#)
318 }
319 Chunk::TeamFinish { team, time } => {
320 let time = Instant::zero() + Duration::from_ticks(*time);
321 write!(f, "TeamFinish team={team} time={time};")
322 }
323 }
324 }
325}