faf_replay_parser/lib.rs
1//! A parser for Supreme Commander: Forged Alliance replay data.
2//!
3//! # The Replay Format
4//! Replays are a sequence of game commands that are executed in the sim (game simulation). This
5//! includes actions taken by the players as well as automated "driver" commands that tell the sim
6//! to run and verify the sim state.
7//!
8//! The most common command present in the replay is the `Advance` command. This tells the sim to
9//! run a certain number of in game ticks. In practice the number of ticks appears to always be 1.
10//! Counting the total number of ticks present in `Advance` commands can tell you how much in game
11//! time has passed in a replay, as ticks always happen at a consistent rate of `10` ticks per
12//! in game second. As counting the number of ticks is a fairly common use case, this library
13//! offers some specially optimized functions for doing this, and we will use this for many
14//! examples of how to use the library.
15//!
16//! # Parser Interfaces
17//! There are two main ways to interface with the parser, depending on how your data is available.
18//! If most general interfaces uses [`std::io::Read`] to inspect the command data and can be used
19//! directly on any objects that implement it such as files, network sockets, and non-contiguous
20//! structures. However, it can be significantly more efficient to work with byte slices directly,
21//! so there are a number of functions for that specific case.
22//!
23//! ## Examples
24//! Lets look at some examples of using the parser to count the ticks in a replay.
25//!
26//! ### Using the optimized functions
27//!
28//! ```rust
29//! use faf_replay_parser::{body_offset, body_ticks};
30//! use std::fs::File;
31//! use std::io::Read;
32//!
33//! let mut data = Vec::new();
34//! File::open("tests/data/6176549.scfareplay")
35//! .expect("Failed to open file")
36//! .read_to_end(&mut data)
37//! .expect("Failed to read file");
38//!
39//! // Find the index where the header stops and the replay data begins
40//! let offset = body_offset(&data).expect("Malformed replay header");
41//! // Count the number of ticks present in the replay data
42//! let ticks = body_ticks(&data[offset..]).expect("Corrupt replay data");
43//!
44//! assert_eq!(ticks, 28917);
45//! ```
46//!
47//! For more details on the available functions see [`scfa::bytes`].
48//!
49//! ### Using the byte iterator
50//!
51//! ```rust
52//! use faf_replay_parser::iter::prelude::*;
53//! use faf_replay_parser::scfa::{replay_command, ReplayCommand};
54//! use faf_replay_parser::{body_offset, SCFA};
55//! use std::fs::File;
56//! use std::io::Read;
57//!
58//! let mut data = Vec::new();
59//! File::open("tests/data/6176549.scfareplay")
60//! .expect("Failed to open file")
61//! .read_to_end(&mut data)
62//! .expect("Failed to read file");
63//!
64//! // Find the index where the header stops and the replay data begins
65//! let offset = body_offset(&data).expect("Malformed replay header");
66//! let body = &data[offset..];
67//!
68//! // Count the number of ticks present in the replay data, stopping on the first error.
69//! let ticks = body
70//! .iter_command_frames_raw()
71//! .filter(|frame| frame.cmd == replay_command::ADVANCE)
72//! .parse_command::<SCFA>()
73//! .while_ok()
74//! .map(|command| match command {
75//! ReplayCommand::Advance { ticks } => ticks,
76//! _ => unreachable!(),
77//! })
78//! .sum::<u32>();
79//!
80//! assert_eq!(ticks, 28917);
81//! ```
82//!
83//! For more details on the available functions see [`iter`].
84//!
85//! ### Using the generic `Parser`
86//!
87//! ```rust
88//! use faf_replay_parser::{Parser, SCFA};
89//! use std::fs::File;
90//! use std::io::{BufReader, Read};
91//!
92//! let file = File::open("tests/data/6176549.scfareplay")
93//! .expect("Failed to open file");
94//! let mut reader = BufReader::new(file);
95//!
96//! let parser = Parser::<SCFA>::new();
97//! let replay = parser.parse(&mut reader).expect("Corrupt replay data");
98//!
99//! let ticks = replay.body.sim.tick;
100//!
101//! assert_eq!(ticks, 28917);
102//! ```
103//!
104//! Note that functions which parse the header also require [`std::io::BufRead`] to be implemented.
105//!
106//! For more details on the available functions see [`parser`].
107
108pub mod aggregator;
109pub mod iter;
110pub mod parser;
111pub mod replay;
112pub mod sc2;
113pub mod scfa;
114pub mod version;
115
116#[cfg(feature = "faf")]
117pub mod faf;
118
119// Internal modules
120mod display;
121pub mod lua;
122mod parser_builder;
123mod reader;
124
125pub use iter::{CommandFrameAdapters, CommandIter};
126pub use parser::{Parser, StreamParser};
127pub use parser_builder::ParserBuilder;
128pub use reader::{ReplayReadError, ReplayResult};
129pub use scfa::{body_offset, body_ticks, has_frame};
130
131// Reexport versions
132pub use sc2::SC2;
133pub use scfa::SCFA;
134pub use version::Version;
135
136const MIB: usize = 1_048_576;