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::ClCommand(cl_command) => {
145 let ClCommand { name, arguments } = cl_command;
146 let name = String::from_utf8_lossy(name);
147 let arguments = String::from_utf8_lossy(arguments);
148 write!(f, "NetMsg cid={cid} type=command name={name:?} arguments={arguments:?};")
149 }
150 },
151 Err(_err) => {
152 let msg = hex::encode(msg);
154 write!(f, "NetMsg cid={cid}, raw_msg={msg}")
155 }
156 }
157 }
158 Chunk::Join { cid } => {
159 write!(f, "Join cid={cid};")
160 }
161 Chunk::Drop(drop) => {
162 let Drop { cid, reason } = drop;
163 let reason = String::from_utf8_lossy(reason);
164 write!(f, "Drop cid={cid} reason={reason:?};")
165 }
166 Chunk::ConsoleCommand(console_command) => {
167 let ConsoleCommand {
168 cid,
169 flags,
170 cmd,
171 ref args,
172 } = console_command;
173 let cmd = String::from_utf8_lossy(cmd);
174 let mut had_previous = false;
175 write!(
176 f,
177 "ConsoleCommand cid={cid} flags={flags} cmd={cmd:?} args=["
178 )?;
179 for arg in args {
180 if had_previous {
181 write!(f, " ")?;
182 } else {
183 had_previous = true;
184 }
185 let arg = String::from_utf8_lossy(arg);
186 write!(f, "{arg:?}")?;
187 }
188 write!(f, "];")
189 }
190 Chunk::UnknownEx(unknown_ex) => {
191 let UnknownEx { uuid, data } = unknown_ex;
192 let data = hex::encode(data);
193 write!(f, "UnknownEx uuid={uuid} data={data};")
194 }
195 Chunk::Test => write!(f, "Test;"),
196 Chunk::DdnetVersionOld(ddnet_version_old) => {
197 let DdnetVersionOld { cid, version } = ddnet_version_old;
198 write!(f, "DdnetVersionOld cid={cid} version={version};")
199 }
200 Chunk::DdnetVersion(ddnet_version) => {
201 let DdnetVersion {
202 cid,
203 connection_id,
204 version,
205 version_str,
206 } = ddnet_version;
207 let version_str = String::from_utf8_lossy(version_str);
208 write!(f, "DdnetVersion cid={cid} connection_id={connection_id} version={version} version_str={version_str:?};")
209 }
210 Chunk::AuthInit(auth) => {
211 let Auth {
212 cid,
213 level,
214 auth_name,
215 } = auth;
216 let auth_name = String::from_utf8_lossy(auth_name);
217 write!(
218 f,
219 "AuthInit cid={cid} level={level} auth_name={auth_name:?};"
220 )
221 }
222 Chunk::AuthLogin(auth) => {
223 let Auth {
224 cid,
225 level,
226 auth_name,
227 } = auth;
228 let auth_name = String::from_utf8_lossy(auth_name);
229 write!(
230 f,
231 "AuthLogin cid={cid} level={level} auth_name={auth_name:?};"
232 )
233 }
234 Chunk::AuthLogout { cid } => {
235 write!(f, "AuthLogout cid={cid};")
236 }
237 Chunk::JoinVer6 { cid } => {
238 write!(f, "JoinVer6 cid={cid};")
239 }
240 Chunk::JoinVer7 { cid } => {
241 write!(f, "JoinVer7 cid={cid};")
242 }
243 Chunk::RejoinVer6 { cid } => {
244 write!(f, "RejoinVer6 cid={cid};")
245 }
246 Chunk::TeamSaveSuccess(team_save) => {
247 let TeamSave {
248 team,
249 save_id,
250 save,
251 } = team_save;
252 let save = String::from_utf8_lossy(save);
253 write!(
254 f,
255 "TeamSaveSuccess team={team} save_id={save_id} save={save:?};"
256 )
257 }
258 Chunk::TeamSaveFailure { team } => {
259 write!(f, "TeamSaveFailure team={team};")
260 }
261 Chunk::TeamLoadSuccess(team_save) => {
262 let TeamSave {
263 team,
264 save_id,
265 save,
266 } = team_save;
267 let save = String::from_utf8_lossy(save);
268 write!(
269 f,
270 "TeamLoadSuccess team={team} save_id={save_id} save={save:?};"
271 )
272 }
273 Chunk::TeamLoadFailure { team } => {
274 write!(f, "TeamLoadFailure team={team};")
275 }
276 Chunk::PlayerTeam { cid, team } => {
277 write!(f, "PlayerTeam cid={cid} team={team};")
278 }
279 Chunk::TeamPractice { team, practice } => {
280 write!(f, "TeamPractice team={team} enabled={practice};")
281 }
282 Chunk::PlayerReady { cid } => {
283 write!(f, "PlayerReady cid={cid};")
284 }
285 Chunk::PlayerSwap { cid1, cid2 } => {
286 write!(f, "PlayerSwap cid1={cid1} cid2={cid2};")
287 }
288 Chunk::Antibot(antibot) => {
289 let Antibot { data } = antibot;
290 let data = hex::encode(data);
291 write!(f, "Antibot data={data};")
292 }
293 Chunk::PlayerName(player_name) => {
294 let PlayerName { cid, name } = player_name;
295 let name = String::from_utf8_lossy(name);
296 write!(f, "PlayerName cid={cid} name={name:?};")
297 }
298 Chunk::PlayerFinish { cid, time } => {
299 let time = Instant::zero() + Duration::from_ticks(*time);
300 write!(f, r#"PlayerFinish cid={cid} time="{time}";"#)
301 }
302 Chunk::TeamFinish { team, time } => {
303 let time = Instant::zero() + Duration::from_ticks(*time);
304 write!(f, "TeamFinish team={team} time={time};")
305 }
306 }
307 }
308}