Improve Code Documentation

This commit is contained in:
Quentin Rouland 2024-05-25 16:25:03 -04:00
parent bb4e163f45
commit 1d5fa1b860
3 changed files with 52 additions and 8 deletions

View File

@ -1,4 +1,13 @@
#[macro_use] extern crate log; #![warn(missing_docs)]
//! sgtool is a library for analyze of the replay of the Stormgate game.
//!
//!
//! # Example
//! ```
//! let replay_path = "replay.SGReplay";
//! let mut buffer : Vec<u8> = vec![];
//! let replay : Replay = Replay::load_file(replay_path, &mut buffer)?;
//! ```
//!
pub mod parser; pub mod parser;
mod protos; mod protos;

View File

@ -1,3 +1,11 @@
//! sgtool is a tool for analyze of the replay of the Stormgate game.
//!
//!
//! # Example
//! ```
//! sgtool -i replays/replay.SGReplay
//! ```
extern crate pretty_env_logger; extern crate pretty_env_logger;
#[macro_use] extern crate log; #[macro_use] extern crate log;

View File

@ -1,3 +1,13 @@
//! A parser for Stormgate Replay.
//!
//!
//! # Example
//! ```
//! let replay_path = "replay.SGReplay";
//! let mut buffer : Vec<u8> = vec![];
//! let replay : Replay = Replay::load_file(replay_path, &mut buffer)?;
//! ```
use std::{fs::OpenOptions, io::{BufRead, BufReader, Read}, path::Path}; use std::{fs::OpenOptions, io::{BufRead, BufReader, Read}, path::Path};
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
use flate2::bufread::GzDecoder; use flate2::bufread::GzDecoder;
@ -6,7 +16,8 @@ use quick_protobuf::BytesReader;
use crate::protos::stormgate::ReplayChunk; use crate::protos::stormgate::ReplayChunk;
/// Stormgate Replay Header. /// Stormgate Replay Header.
/// It consists of 16 bytes at the top of the replay //
// It consists of 16 bytes at the top of the replay
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Header { pub struct Header {
h1: u32, // 12 first bytes repsentation are unknown at the moment h1: u32, // 12 first bytes repsentation are unknown at the moment
@ -14,20 +25,22 @@ pub struct Header {
} }
/// Stormgate Replay Payload. /// Stormgate Replay Payload.
/// After the the 16 bytes header, the actual payload of the replay of Protobuf messages that are gzipped ///
/// Each Protobuf messages represents events that appended in the game from the differetns clients // After the the 16 bytes header, the actual payload of the replay of Protobuf messages that are gzipped
// Each Protobuf messages represents events that appended in the game from the differetns clients
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Payload<'a> { pub struct Payload<'a> {
chunks: Vec<ReplayChunk<'a>>, chunks: Vec<ReplayChunk<'a>>,
} }
/// Stormgate replay /// Stormgate Replay.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Replay<'a> { pub struct Replay<'a> {
header: Header, // header of the replay header: Header, // header of the replay
payload: Payload<'a>, // the content of a replay is set of messages payload: Payload<'a>, // the content of a replay is set of messages
} }
/// Load n bytes into a buffer.
fn load_part<'a, R: Read>(reader: &'a mut R) -> impl FnMut(usize) -> Result<Vec<u8>, std::io::Error> + 'a { fn load_part<'a, R: Read>(reader: &'a mut R) -> impl FnMut(usize) -> Result<Vec<u8>, std::io::Error> + 'a {
move |size| { move |size| {
let mut buf = vec![0u8; size]; let mut buf = vec![0u8; size];
@ -37,7 +50,7 @@ fn load_part<'a, R: Read>(reader: &'a mut R) -> impl FnMut(usize) -> Result<Vec<
} }
impl Header { impl Header {
/// /// Load the 16 bytes as a `Header`.
fn load<T: BufRead>(reader: &mut T) -> Result<Header, std::io::Error> { fn load<T: BufRead>(reader: &mut T) -> Result<Header, std::io::Error> {
let mut load = load_part(reader); let mut load = load_part(reader);
let h1 = LittleEndian::read_u32(&load(12)?); let h1 = LittleEndian::read_u32(&load(12)?);
@ -47,6 +60,7 @@ impl Header {
} }
impl<'a> Payload<'a> { impl<'a> Payload<'a> {
/// Load the replay content as a `Payload`.
fn load<T: BufRead>(buf_reader: &mut T, buf: &'a mut Vec<u8>) -> Result<Payload<'a>, Box<dyn std::error::Error>> { fn load<T: BufRead>(buf_reader: &mut T, buf: &'a mut Vec<u8>) -> Result<Payload<'a>, Box<dyn std::error::Error>> {
let mut d = GzDecoder::new(buf_reader); let mut d = GzDecoder::new(buf_reader);
d.read_to_end(buf)?; d.read_to_end(buf)?;
@ -65,6 +79,7 @@ impl<'a> Payload<'a> {
impl<'a> Replay<'a> { impl<'a> Replay<'a> {
fn load<T: BufRead>(buf_reader: &mut T, buf: &'a mut Vec<u8>) -> Result<Replay<'a>, Box<dyn std::error::Error>> { fn load<T: BufRead>(buf_reader: &mut T, buf: &'a mut Vec<u8>) -> Result<Replay<'a>, Box<dyn std::error::Error>> {
// Get Header // Get Header
let header = Header::load(buf_reader)?; let header = Header::load(buf_reader)?;
@ -75,6 +90,18 @@ impl<'a> Replay<'a> {
Ok(Replay { header, payload: data }) Ok(Replay { header, payload: data })
} }
/// Load a replay file as `Replay`.
///
/// # Arguments
/// * `path` : Path of the storgmate replay file.
/// * `buf` : Byte Buffer use by the parser.
///
/// # Example
/// ```
/// let replay_path = "replay.SGReplay";
/// let mut buffer : Vec<u8> = vec![];
/// let replay : Replay = Replay::load_file(replay_path, &mut buffer)?;
/// ```
pub fn load_file(path: &Path, buf: &'a mut Vec<u8>) -> Result<Replay<'a>, Box<dyn std::error::Error>> { pub fn load_file(path: &Path, buf: &'a mut Vec<u8>) -> Result<Replay<'a>, Box<dyn std::error::Error>> {
let file = OpenOptions::new().read(true).open(path).unwrap(); let file = OpenOptions::new().read(true).open(path).unwrap();
let mut buf_reader = BufReader::new(file); let mut buf_reader = BufReader::new(file);
@ -90,7 +117,7 @@ mod tests {
#[test] #[test]
fn load_file() { fn load_file() {
// Replay used is form Alpha phase of stormgate, threfore is not provided in the repo to avoid any problem with NDA at this time // Replay used is form Alpha phase of stormgate, threfore is not provided in the repo to avoid any problem with NDA at this time
// TODO : when the game officially can out fix provide sample replay for testing directly in the repo // TODO : when the game officially came out fix provide sample replay for testing directly in the repo
let replay_path = Path::new("replays/CL55366-2024.05.12-01.53.SGReplay"); let replay_path = Path::new("replays/CL55366-2024.05.12-01.53.SGReplay");
let mut buffer : Vec<u8> = vec![]; let mut buffer : Vec<u8> = vec![];
let r = Replay::load_file(replay_path, &mut buffer).unwrap(); let r = Replay::load_file(replay_path, &mut buffer).unwrap();