Skip to content

Commit

Permalink
QoL features for replaying to aid decoding. Update readme.
Browse files Browse the repository at this point in the history
  • Loading branch information
lkolbly committed Aug 23, 2020
1 parent 4248e16 commit e037ed0
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 9 deletions.
31 changes: 28 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ which indicates that the recipient `604965` received 1254 units of damage from `

The `wowsreplay` format has a majority of packets under the `7` and `8` packet types, which I refer to as "Entity" packets. These packets have not yet been decoded (their packet ID is unknown), although it is known that they contain an entity ID (that's all that's known about them).

Some packets will appear as "Invalid" packets, these are packets for which the packet ID is known, but for some reason the parser decided it didn't know what to do with the packet.
Some packets will appear as "Invalid" packets, these are packets for which the packet ID is known, but for some reason the parser decided it didn't know what to do with the packet. If you find one of these, please feel free to copy the packet into a new issue!

Trace Utility
=============
Expand All @@ -56,9 +56,34 @@ The following game versions are currently supported:
- 0.9.6 (and .1)
- 0.9.7

The version policy for this component is forward-looking: After game version X is released, I won't work very hard to decode new packets from version X-1 and below. To the extent practical, though, support for older versions will be maintained.
The version policy for this component is forward-looking: After game version X is released, I won't work very hard to decode new packets from version X-1 and below. To the extent practical, though, support for older versions will be maintained - but it is not guaranteed that any version other than the "current" will work.

Packet Support
==============

The following packets are parsed at least partially:
- The initial "Setup" packet which enumerates the players, their ships, camo configuration, etc. is partially decoded.
- The general structure is partially decoded. Most fields are not decoded.
- Position and PlayerOrientation: The position of other ships and of the player and of the camera.
- Some fields are not fully decoded.
- Chat: Emitted whenever a player sends a chat message.
- DamageReceived: Emitted whenever damage is dealt to a ship.
- ArtilleryHit: Emitted whenever either the player's guns hit a ship or whenever the player's ship is hit by shells. This packet has many unknown fields.
- Banner: Emitted when the player receives a banner.

Packet wishlist
===============

The following information is not yet extracted from replays, but is information that is known to exist in the replay file:
- Torpedoes.
- Planes.
- Ship visibility/hidden status (and the player's "detected" status)
- Ship destruction.
- Incapacitation type.
- Consumable usage.
- Smoke.

Contributing
============

Feel free to open issues or PRs if you find any bugs or want to be able to parse any particular packets from your replay files. This project is in Rust, but the `dump` command can generate JSON data for consumption in any language, so if you end up writing a packet parser for a new packet in another language please open an issue and I can add it to the Rust code.
Feel free to open issues or PRs if you find any bugs or want to be able to parse any particular packets from your replay files. This project is in Rust, but the `dump` command can generate JSON data for consumption in any language, so if you end up writing a packet parser for a new packet in another language please open an issue and I can port it to the Rust code.
6 changes: 3 additions & 3 deletions parser/src/packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ pub struct PlayerOrientationPacket {

/// Radians, 0 is North and positive numbers are clockwise
/// e.g. pi/2 is due East, -pi/2 is due West, and +/-pi is due South.
pub bearing: f32,
pub heading: f32,

pub f4: f32,
pub f5: f32,
Expand Down Expand Up @@ -176,7 +176,7 @@ fn parse_player_orientation_packet(i: &[u8]) -> IResult<&[u8], PacketType> {
let (i, x) = le_f32(i)?;
let (i, y) = le_f32(i)?;
let (i, z) = le_f32(i)?;
let (i, bearing) = le_f32(i)?;
let (i, heading) = le_f32(i)?;
let (i, f4) = le_f32(i)?;
let (i, f5) = le_f32(i)?;
Ok((
Expand All @@ -187,7 +187,7 @@ fn parse_player_orientation_packet(i: &[u8]) -> IResult<&[u8], PacketType> {
x,
y,
z,
bearing,
heading,
f4,
f5,
}),
Expand Down
3 changes: 0 additions & 3 deletions replayshark/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,11 @@ wows-replays = { version = "0.1.0", path = "../parser" }
nom = "6.0.0-alpha1"
hexdump = "0.1.0"
flate2 = "1.0.14"
rust-lzma = "0.5"
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
thiserror = "1.0.19"
lzw = "0.10.0"
rust-crypto = "0.2.36"
libz-sys = "1.0.25"
plotters = "0.2.15"
image = "0.23.4"
clap = "2.33.1"
Expand Down
100 changes: 100 additions & 0 deletions replayshark/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,11 +341,35 @@ fn main() {
.help("Filter packets to be the given entity subtype")
.takes_value(true),
)
.arg(
Arg::with_name("exclude-subtypes")
.long("exclude-subtypes")
.help("A comma-delimited list of Entity subtypes to exclude")
.takes_value(true)
)
.arg(
Arg::with_name("timestamps")
.long("timestamps")
.help("A comma-delimited list of timestamps to highlight in the output")
.takes_value(true)
)
.arg(
Arg::with_name("timestamp-offset")
.long("timestamp-offset")
.help("Number of seconds to subtract from the timestamps")
.takes_value(true)
)
.arg(
Arg::with_name("no-meta")
.long("no-meta")
.help("Don't output the metadata"),
)
.arg(
Arg::with_name("speed")
.long("speed")
.help("Play back the file at the given speed multiplier")
.takes_value(true),
)
.arg(replay_arg.clone()),
)
.get_matches();
Expand All @@ -360,12 +384,58 @@ fn main() {
},
&std::path::PathBuf::from(input),
|_, meta, packets| {

let timestamp_offset: u32 = matches.value_of("timestamp-offset").unwrap_or("0").parse().expect("Couldn't parse timestamp-offset as float");

let mut timestamps: Vec<u32> = matches.value_of("timestamps").unwrap_or("").split(',').map(|x| {
if x.len() == 0 { // TODO: This is a workaround for empty
return 0;
}
let parts: Vec<&str> = x.split(':').collect();
assert!(parts.len() == 2);
let m: u32 = parts[0].parse().unwrap();
let s: u32 = parts[1].parse().unwrap();
(m * 60 + s) - timestamp_offset
}).collect();
timestamps.sort();
if timestamps.len() == 1 && timestamps[0] == 0 { // TODO: Workaround for empty timestamps specifier
timestamps = vec!();
}
//println!("{:?}", timestamps);

#[derive(PartialEq)]
enum PacketIdent {
PacketType(u32),
WithSubtype((u32, u32)),
};

let mut exclude_packets: Vec<PacketIdent> = matches.value_of("exclude-subtypes").unwrap_or("").split(',').map(|x| {
if x.len() == 0 { // TODO: This is a workaround for empty lists
return PacketIdent::PacketType(0);
}
if x.contains(":") {
let parts: Vec<&str> = x.split(':').collect();
assert!(parts.len() == 2);
let supertype = parts[0].parse().expect("Couldn't parse supertype");
let subtype = parts[1].parse().expect("Couldn't parse subtype");
PacketIdent::WithSubtype((supertype, subtype))
} else {
PacketIdent::PacketType(x.parse().expect("Couldn't parse u32"))
}
//x.parse().expect("Couldn't parse exclude packet")
}).collect();
if exclude_packets.len() == 0 && exclude_packets[0] == PacketIdent::PacketType(0) { // TODO: This is a workaround for empty lists
exclude_packets = vec!();
}

if !matches.is_present("no-meta") {
println!(
"{}",
serde_json::to_string(&meta).expect("Couldn't JSON-format metadata")
);
}
let speed: u32 = matches.value_of("speed").map(|x| x.parse().expect("Couldn't parse speed! Must specify an integer")).unwrap_or(0);
let start_tm = std::time::Instant::now();
for packet in packets {
let superfilter: Option<u32> =
matches.value_of("filter-super").map(|x| x.parse().unwrap());
Expand All @@ -391,8 +461,38 @@ fn main() {
}
},
};
/*if exclude_packets.len() > 0 {
let packet_type = if packet.packet_type == 7 || packet.packet_type == 8 {
match &packet.payload {
PacketType::Entity(p) => {
PacketIdent::WithSubtype((p.supertype, p.subtype))
}
_ => {
// Skip known packets
continue;
}
}
} else {
PacketIdent::PacketType(packet.packet_type)
};
if exclude_packets.contains(&packet_type) {
continue;
}
}*/
let s = serde_json::to_string(&packet)
.expect("Couldn't JSON-format serialize packet");
if speed > 0 {
let current_tm = start_tm.elapsed().as_secs_f32() * speed as f32;
if packet.clock > current_tm {
let millis = (packet.clock - current_tm) * 1000.0;
//println!("Sleeping for {}", millis);
std::thread::sleep(std::time::Duration::from_millis(millis as u64));
}
}
if timestamps.len() > 0 && timestamps[0] < packet.clock as u32 {
println!("{{\"clock\":{},\"timestamp\":1}}", packet.clock);
timestamps.remove(0);
}
println!("{}", s);
}
},
Expand Down

0 comments on commit e037ed0

Please sign in to comment.