7 releases
0.5.2 | Apr 10, 2022 |
---|---|
0.5.1 | Mar 23, 2021 |
0.4.0 | Mar 22, 2020 |
0.3.2 | Mar 21, 2020 |
0.3.1 | Aug 25, 2019 |
#1155 in Parser implementations
1.5MB
2.5K
SLoC
FAF Replay Parser
A Supreme Commander: Forged Alliance replay parser based on https://github.com/FAForever/faf-scfa-replay-parser.
This project aims to provide a fast parser for the Supreme Commander Forged Alliance (SCFA) replay data format. These replay files are relatively small by today's standards, however, performance still matters when you need to parse a large number of replays.
This repository includes the parser implementation as a Rust crate, as well as a command line utility.
Usage
Parse replays through the Parser
class:
extern crate faf_replay_parser;
use faf_replay_parser::{Parser, ParserBuilder};
use std::fs::File;
use std::io::{BufReader, Read};
use std::time::Duration;
let parser = ParserBuilder::new()
// Skip all commands except the ones defined here
.commands(&[
replay_command::ADVANCE,
replay_command::VERIFY_CHECKSUM,
])
// Throw away commands right after we parse them. Setting this to `True` will
// increase the parse time.
.save_commands(false)
// Parse the whole replay even if it desynced
.stop_on_desync(false)
.build();
// Or create a parser with default arguments (turn off save_commands though)
// let parser = Parser::new();
// Read replay file
let mut f = BufReader::new(File::open("12345.scfareplay").expect("Couldn't open file"));
let mut data = Vec::new();
f.read_to_end(&mut data).expect("Couldn't read from file");
// Parse the replay
let replay = parser
.parse(&mut data.as_slice())
.expect("Failed to parse replay");
println!("Game time: {:?}", Duration::from_millis(replay.body.sim.tick as u64 * 100));
if !replay.body.sim.desync_ticks.is_empty() {
println!("Replay desynced!");
}
Or use the high performance functions for special cases:
use faf_replay_parser::{body_offset, body_ticks};
use std::time::Duration;
// Split replay data into header and body
let offset = body_offset(&data);
let (header_data, body_data) = data.split_at(offset);
// Get replay length in ticks
let ticks = body_ticks(&body_data);
println!("Game time: {:?}", Duration::from_millis(ticks as u64 * 100));
The Command Line Utility
Disclaimer: The cli is a work in progress, and some parts of it may currently print out excess amounts of debug information.
Installing
You can get the cli by cloning this repository and building it with:
$ cargo build --release --features cli
This will produce an executable in target/release/
. Copy this to some location
in your $PATH
, for instance ~/.local/bin/
.
Alternatively, a Linux binary is available in the GitLab CI build artifacts of every tagged release.
Functionality
The cli currently performs 3 main functions. Printing a summary of the replay
(mostly header information), inspecting the contents of the command stream, and
converting fafreplay
files into scfareplay
files.
Info
Shows an overview of the replay contents. Additional information about the map, players, game options and more can be enabled as well.
$ fafreplay info 6176549.fafreplay
processing replay: 6176549.fafreplay
Supreme Commander v1.50.3698 Replay v1.9
Seton's Clutch (00:48:11)
Dozens of battles have been fought over the years across Seton's Clutch. A patient searcher could find the remains of thousands of units resting beneath the earth and under the waves.
Team 1
civilian (AI) 5
Team 2
[PLD] EricaPwnz (1200) Aeon
Vmcsnekke (1600) UEF
[AoS] Strogo (2100) UEF
[JEW] Licious (1600) Seraphim
Team 3
[SNF] PlodoNoob (1800) Cybran
Mizer (1400) Seraphim
[SC] HerzogGorky (1400) Cybran
[JEW] Robogear (2100) UEF
Commands
Displays commands as they appear in the replay file. By default this only shows the most common commands.
$ fafreplay commands 9000556.scfareplay --limit 10
processing replay: 9000556.fafreplay
Supreme Commander v1.50.3701 Replay v1.9
0 ├── SetCommandSource { id: 0 }
1 ├── VerifyChecksum { digest: [168, 55, 122, 87, 70, 60, 17, 145, 224, 174, 52, 71, 2, 143, 109, 2], tick: 0 }
2 ├── Advance { ticks: 1 }
3 ├── Advance { ticks: 1 }
4 ├── Advance { ticks: 1 }
5 ├── Advance { ticks: 1 }
6 ├── Advance { ticks: 1 }
7 ├── Advance { ticks: 1 }
8 ├── Advance { ticks: 1 }
9 ├── Advance { ticks: 1 }
Total commands parsed: 10
Unpack
Converts a .fafreplay file into a .scfareplay file.
$ fafreplay unpack 9000556.fafreplay
Extracting...
Done
Writing 9000556.scfareplay
Wrote 12314246 bytes
Building
To build the command line utility:
$ cargo build --release --features cli
Related Projects
Looking for a parser in a different language? Check out these other replay parser implementations:
- faf-scfa-replay-parser a library implementation in pure Python
- ReplayParser a library implementation in C#
- fafafaf.bitbucket.org a JavaScript application for viewing replay stats
- Replay Sync Tool a PyQT application for synchronized replay playback with a rudimentary Python 2 parser implementation.
- (Bonus) https://pastebin.com/H4hazWFp the beginnings of a Python implementation by ZePilot