vault
is a Company of Heroes 2 replay parsing library written in Rust. It has evolved from work done by a number of individuals in the Company of Heroes community, most notably Seb and pingtoft, and has been helped along by the assistance of Relic Entertainment. This particular project is a rewrite and extension of a parser written by Seb, which itself was an extension of my original PHP port of pingtoft's C# Company of Heroes parsing code. Its goal is to provide a robust, complete, and flexible interface into Company of Heroes 2 replay files through a general library that can be used in a variety of environments and languages. It is also written to be fast and to take advantage of Rust's thread and memory safety features.
Currently vault
supports Company of Heroes 2 replays recorded on version 19545 or newer. This was the first version after the release of the British forces expansion.
vault
can handle parsing individual files, archived files in the zip format (.zip
only, not .7z
currently), and directories of replay files. When parsing an archive, all .rec
files inside the archive and its subfolders will be parsed. When parsing a directory, all .rec
and .zip
files at that directory level will be parsed. vault
currently will not recursively traverse subdirectories when parsing directories.
flank
is a very basic CLI parsing application for CoH2 replays written using this library as a proof of concept and reference point. It is currently powering COH2.ORG's replay section. If you would like to try it out or look through the code, it is available on GitHub.
If you are writing a Rust application, you can use vault
from crates.io:
Cargo.toml
:
toml
[dependencies]
vault = "1"
src/main.rs
:
```rust extern crate vault;
use std::path::Path;
fn main() { let path = Path::new("/path/to/replay.rec"); let replay = vault::parse_replay(&path, None).unwrap(); println!("{}", replay.version); } ```
vault
's Replay
type can also be serialized to JSON using rustc_serialize
.
Each of vault
's parse
functions can be passed an Option<Config>
, which controls the behaviour of the replay parser during parsing. If None
is passed, the default configuration shown below is used. See documentation for a more detailed look at what each configuration setting does.
text
strict = false // If true, only .rec files will be parsed
commands = true // If true, commands will be parsed; if false, commands will be skipped
command_bytes = false // If true, the byte sequence of all commands will be stored for debugging
clean_file = true // If true, the replay byte stream will be emptied after parsing for cleaner JSON
vault
's core library is only able to parse single replay files. However, it includes reference implementations for multithreaded parsing of .zip
archives as well as directories. These can be used in lieu of a custom implementation by enabling the appropriate feature flags.
In order to build with features enabled, run
bash
$ cargo build --release --features="feature1 feature2"
Available features include:
parse-archive
Enables .zip
archive parsing. This feature adds the parse_archive
function which takes a .zip
archive and parses every .rec
file it finds inside.
parse-all
Enables the parse-archive
feature and extends it by adding parse_directory
and parse_any
functions. parse_directory
takes a directory path and parses all .rec
and .zip
files at the first level of that path. parse_any
takes a path to any file or directory and parses it based on the file extension.
dev
Enables clippy
linting on build. Useful only for development, and requires a nightly Rust compiler.
ffi
Enables FFI functionality. See below for details.
vault
can be called into from foreign code as easily as a C library. This can be used to parse replays with vault
from a higher-level language such as Python or Javascript.
First, build vault
from source with the ffi
feature enabled. You're going to need the latest version of stable Rust.
bash
$ git clone https://github.com/ryantaylor/vault.git && cd vault
$ cargo build --release --features=ffi
The library you want to be using is libvault.so
, which you can find at vault/target/release
. This library exposes two external functions for use over FFI:
rust
pub extern fn parse_to_cstring(path: *const c_char) -> *mut c_char {
// ...
}
This function takes a string path to a replay, archive, or directory and parses the replay file(s) it finds. It then serializes the result and passes it back to the caller as a JSON string.
rust
pub extern fn free_cstring(ptr: *mut c_char) {
// ...
}
This function takes the pointer passed back from parse_to_cstring
and deallocates its memory. Every call to parse_to_cstring
must have a matching call to free_cstring
in order to prevent memory leaks. free_cstring
is the only way to safely deallocate the pointer returned by parse_to_cstring
.
node.js
```javascript var ffi = require('ffi'); var ref = require('ref');
var charPtr = ref.refType(ref.types.CString);
var lib = ffi.Library('/path/to/vault/target/release/libvault', { 'parsetocstring': [charPtr, ['string']], 'free_cstring': ['void', [charPtr]] });
var path = '/path/to/replay.rec'; var ptr = lib.parsetocstring(path); var str = ref.readCString(ptr, 0); lib.free_cstring(ptr);
console.log(str); ```
IMPORTANT: Failing to call free_cstring
on the pointer returned by parse_to_cstring
will cause a memory leak, and calling free_cstring
on another pointer will likely cause a segfault.
Documentation for vault
can be viewed online.
Alternatively, you can easily build an offline copy of the documentation for yourself with cargo
:
$ cargo doc --features=parse-all
For documentation that includes the FFI functions available with the ffi
feature, run:
$ cargo doc --features="parse-all ffi"
The resulting documentation can then be found at vault/target/doc
.
MIT