use crate::net_msg::{
ClCallVote, ClCommand, ClNetMessage, ClPlayerInfo, ClSay, ClSetSpectatorMode, ClShowDistance,
NetVersion,
};
use crate::Input;
use std::fmt;
use teehistorian::chunks::{
Antibot, Auth, ConsoleCommand, DdnetVersion, DdnetVersionOld, Drop, InputDiff, InputNew,
NetMessage, PlayerDiff, PlayerName, PlayerNew, TeamSave, UnknownEx,
};
use teehistorian::Chunk;
use twsnap::time::{Duration, Instant};
pub struct DisplayChunk<'a>(pub &'a Chunk<'a>);
impl fmt::Display for DisplayChunk<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.0 {
Chunk::PlayerDiff(player_diff) => {
let PlayerDiff { cid, dx, dy } = player_diff;
write!(f, "PlayerDiff cid={cid} diff=({dx}, {dy});")
}
Chunk::Eos => write!(f, "Eos;"),
Chunk::TickSkip { dt } => {
write!(f, "TickSkip dt={dt};")
}
Chunk::PlayerNew(player_new) => {
let PlayerNew { cid, x, y } = player_new;
write!(f, "PlayerNew cid={cid} pos=({x}, {y});")
}
Chunk::PlayerOld { cid } => {
write!(f, "PlayerOld cid={cid};")
}
Chunk::InputDiff(input_diff) => {
let InputDiff { cid, dinput } = input_diff;
let Input {
direction,
target_x,
target_y,
jump,
fire,
hook,
player_flags,
wanted_weapon,
next_weapon,
prev_weapon,
} = Input::from(*dinput);
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};")
}
Chunk::InputNew(input_new) => {
let InputNew { cid, input } = input_new;
let Input {
direction,
target_x,
target_y,
jump,
fire,
hook,
player_flags,
wanted_weapon,
next_weapon,
prev_weapon,
} = Input::from(*input);
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};")
}
Chunk::NetMessage(net_msg) => {
let NetMessage { cid, msg } = net_msg;
match crate::net_msg::parse_net_msg(msg, &mut NetVersion::Unknown) {
Ok(msg) => match msg {
ClNetMessage::ClSay(cl_say) => {
let ClSay {
mode,
target,
message,
} = cl_say;
let message = String::from_utf8_lossy(message);
write!(f, "NetMsg cid={cid} type=say mode={mode:?} target={target}, message={message:?};")
}
ClNetMessage::ClSetTeam(team) => {
write!(f, "NetMsg cid={cid} type=set_team team={team:?};")
}
ClNetMessage::ClSetSpectatorMode(set_spectator_mode) => {
let ClSetSpectatorMode {
spec_mode,
spectator_id,
} = set_spectator_mode;
write!(f, "NetMsg cid={cid} type=set_spectator_mode spec_mode={spec_mode:?} spectator_id={spectator_id};")
}
ClNetMessage::ClStartInfo(start_info) => {
let ClPlayerInfo {
name,
clan,
country,
skin,
} = start_info;
let name = String::from_utf8_lossy(name);
let clan = String::from_utf8_lossy(clan);
write!(f, "NetMsg cid={cid} type=start_info name={name:?} clan={clan:?} country={country} skin={skin};")
}
ClNetMessage::ClChangeInfo(change_info) => {
let ClPlayerInfo {
name,
clan,
country,
skin,
} = change_info;
let name = String::from_utf8_lossy(name);
let clan = String::from_utf8_lossy(clan);
write!(f, "NetMsg cid={cid} type=change_info name={name:?} clan={clan:?} country={country} skin={skin};")
}
ClNetMessage::ClKill => {
write!(f, "NetMsg cid={cid} type=kill;")
}
ClNetMessage::ClEmoticon(emoticon) => {
write!(f, "NetMsg cid={cid} type=emoticon emoticon={emoticon:?};")
}
ClNetMessage::ClVote(vote) => {
write!(f, "NetMsg cid={cid} type=vote vote={vote};")
}
ClNetMessage::ClCallVote(call_vote) => {
let ClCallVote {
type_,
value,
reason,
force,
} = call_vote;
let type_ = String::from_utf8_lossy(type_);
let value = String::from_utf8_lossy(value);
let reason = String::from_utf8_lossy(reason);
write!(f, "NetMsg cid={cid} type=call_vote_type={type_} vote value={value:?} reason={reason:?} force={force};")
}
ClNetMessage::ClIsDdnet(version) => {
write!(f, "NetMsg cid={cid} type=id_ddnet version={version};")
}
ClNetMessage::ClShowOthers(enabled) => {
write!(f, "NetMsg cid={cid} type=show_others enabled={enabled};")
}
ClNetMessage::ClShowDistance(show_distance) => {
let ClShowDistance { x, y } = show_distance;
write!(f, "NetMsg cid={cid} type=show_distance x={x} y={y};")
}
ClNetMessage::ClCameraInfo(camera_info) => {
let crate::net_msg::ClCameraInfo {
zoom,
deadzone,
follow_factor,
} = camera_info;
write!(
f,
"NetMsg cid={cid} type=camera_info zoom={zoom} deadzone={deadzone} follow_factor={follow_factor};"
)
}
ClNetMessage::ClEnableSpectatorCount(enable) => {
write!(
f,
"NetMsg cid={cid} type=enable_spectator_count enable={enable};"
)
}
ClNetMessage::ClCommand(cl_command) => {
let ClCommand { name, arguments } = cl_command;
let name = String::from_utf8_lossy(name);
let arguments = String::from_utf8_lossy(arguments);
write!(f, "NetMsg cid={cid} type=command name={name:?} arguments={arguments:?};")
}
},
Err(_err) => {
let msg = hex::encode(msg);
write!(f, "NetMsg cid={cid}, raw_msg={msg}")
}
}
}
Chunk::Join { cid } => {
write!(f, "Join cid={cid};")
}
Chunk::Drop(drop) => {
let Drop { cid, reason } = drop;
let reason = String::from_utf8_lossy(reason);
write!(f, "Drop cid={cid} reason={reason:?};")
}
Chunk::ConsoleCommand(console_command) => {
let ConsoleCommand {
cid,
flags,
cmd,
ref args,
} = console_command;
let cmd = String::from_utf8_lossy(cmd);
let mut had_previous = false;
write!(
f,
"ConsoleCommand cid={cid} flags={flags} cmd={cmd:?} args=["
)?;
for arg in args {
if had_previous {
write!(f, " ")?;
} else {
had_previous = true;
}
let arg = String::from_utf8_lossy(arg);
write!(f, "{arg:?}")?;
}
write!(f, "];")
}
Chunk::UnknownEx(unknown_ex) => {
let UnknownEx { uuid, data } = unknown_ex;
let data = hex::encode(data);
write!(f, "UnknownEx uuid={uuid} data={data};")
}
Chunk::Test => write!(f, "Test;"),
Chunk::DdnetVersionOld(ddnet_version_old) => {
let DdnetVersionOld { cid, version } = ddnet_version_old;
write!(f, "DdnetVersionOld cid={cid} version={version};")
}
Chunk::DdnetVersion(ddnet_version) => {
let DdnetVersion {
cid,
connection_id,
version,
version_str,
} = ddnet_version;
let version_str = String::from_utf8_lossy(version_str);
write!(f, "DdnetVersion cid={cid} connection_id={connection_id} version={version} version_str={version_str:?};")
}
Chunk::AuthInit(auth) => {
let Auth {
cid,
level,
auth_name,
} = auth;
let auth_name = String::from_utf8_lossy(auth_name);
write!(
f,
"AuthInit cid={cid} level={level} auth_name={auth_name:?};"
)
}
Chunk::AuthLogin(auth) => {
let Auth {
cid,
level,
auth_name,
} = auth;
let auth_name = String::from_utf8_lossy(auth_name);
write!(
f,
"AuthLogin cid={cid} level={level} auth_name={auth_name:?};"
)
}
Chunk::AuthLogout { cid } => {
write!(f, "AuthLogout cid={cid};")
}
Chunk::JoinVer6 { cid } => {
write!(f, "JoinVer6 cid={cid};")
}
Chunk::JoinVer7 { cid } => {
write!(f, "JoinVer7 cid={cid};")
}
Chunk::RejoinVer6 { cid } => {
write!(f, "RejoinVer6 cid={cid};")
}
Chunk::TeamSaveSuccess(team_save) => {
let TeamSave {
team,
save_id,
save,
} = team_save;
let save = String::from_utf8_lossy(save);
write!(
f,
"TeamSaveSuccess team={team} save_id={save_id} save={save:?};"
)
}
Chunk::TeamSaveFailure { team } => {
write!(f, "TeamSaveFailure team={team};")
}
Chunk::TeamLoadSuccess(team_save) => {
let TeamSave {
team,
save_id,
save,
} = team_save;
let save = String::from_utf8_lossy(save);
write!(
f,
"TeamLoadSuccess team={team} save_id={save_id} save={save:?};"
)
}
Chunk::TeamLoadFailure { team } => {
write!(f, "TeamLoadFailure team={team};")
}
Chunk::PlayerTeam { cid, team } => {
write!(f, "PlayerTeam cid={cid} team={team};")
}
Chunk::TeamPractice { team, practice } => {
write!(f, "TeamPractice team={team} enabled={practice};")
}
Chunk::PlayerReady { cid } => {
write!(f, "PlayerReady cid={cid};")
}
Chunk::PlayerSwap { cid1, cid2 } => {
write!(f, "PlayerSwap cid1={cid1} cid2={cid2};")
}
Chunk::Antibot(antibot) => {
let Antibot { data } = antibot;
let data = hex::encode(data);
write!(f, "Antibot data={data};")
}
Chunk::PlayerName(player_name) => {
let PlayerName { cid, name } = player_name;
let name = String::from_utf8_lossy(name);
write!(f, "PlayerName cid={cid} name={name:?};")
}
Chunk::PlayerFinish { cid, time } => {
let time = Instant::zero() + Duration::from_ticks(*time);
write!(f, r#"PlayerFinish cid={cid} time="{time}";"#)
}
Chunk::TeamFinish { team, time } => {
let time = Instant::zero() + Duration::from_ticks(*time);
write!(f, "TeamFinish team={team} time={time};")
}
}
}
}