Skip to content

Commit

Permalink
mw_dataformat + mw_datatool: general encoding/decoding roundtrip for …
Browse files Browse the repository at this point in the history
…IS and files!!
  • Loading branch information
inodentry committed Mar 6, 2024
1 parent e4a7978 commit 30528dc
Show file tree
Hide file tree
Showing 26 changed files with 2,028 additions and 30 deletions.
2 changes: 2 additions & 0 deletions bin/mw_certgen/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ enum CliCommand {
/// Generate a root CA certificate.
GenRootCa(GenRootCaArgs),
/// Generate a limited CA certificate.
///
/// For example, if we want to have a CA for a swarm of Host servers, instead of having
/// them under the root CA directly.
GenSubCa(GenSubCaArgs),
/// Generate a CA certificate to use for session authentication.
///
/// This will be used by the Auth server (or RPC) to generate single-use certificates
/// for players upon handoff to a Host server that has per-session player authentication enabled.
GenSessionCa(GenSessionCaArgs),
Expand Down
14 changes: 14 additions & 0 deletions bin/mw_datatool/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,18 @@ edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

# [features]
# proprietary = ["dep:mw_game_minewars"]

[dependencies]
anyhow = "1.0.79"

[dependencies.mw_common]
path = "../../lib/mw_common"

[dependencies.mw_dataformat]
path = "../../lib/mw_dataformat"

[dependencies.clap]
version = "4.5.1"
features = ["derive"]
63 changes: 63 additions & 0 deletions bin/mw_datatool/src/cmd/checksum_fix.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use std::io::{Read, Seek, SeekFrom, Write};

use mw_dataformat::read::MwFileReader;

use crate::prelude::*;
use crate::{CommonArgs, ChecksumFixArgs};

pub fn main(common: &CommonArgs, _args: &ChecksumFixArgs) -> AnyResult<()> {
match (&common.input, &common.output) {
(Some(in_path), None) => {
let file = std::fs::OpenOptions::new()
.read(true)
.write(true)
.truncate(false)
.create(false)
.open(in_path)
.context("Cannot open input file!")?;
let (file, headerdata) = gen_new_headerdata(file)?;
write_new_headerdata(file, &headerdata)?;
}
(Some(in_path), Some(out_path)) => {
std::fs::copy(in_path, out_path)
.context("Failed to copy data from input to output file!")?;
let in_file = std::fs::OpenOptions::new()
.read(true)
.open(in_path)
.context("Cannot open input file!")?;
let out_file = std::fs::OpenOptions::new()
.write(true)
.truncate(false)
.create(false)
.open(out_path)
.context("Cannot open output file!")?;
let (_, headerdata) = gen_new_headerdata(in_file)?;
write_new_headerdata(out_file, &headerdata)?;
}
(None, _) => {
bail!("Input filename must be specified!");
}
}

Ok(())
}

fn gen_new_headerdata<R: Read + Seek>(reader: R) -> AnyResult<(R, Vec<u8>)> {
let mut buf = Vec::new();

let mut mfr = MwFileReader::new(reader, &mut buf)
.context("Failed to load input file as a MineWars format file!")?;

mfr.compute_and_force_update_checksums()?;

let mut buf = vec![];
mfr.file_header().serialize(&mut buf);

Ok((mfr.into_inner(), buf))
}

fn write_new_headerdata<W: Write + Seek>(mut writer: W, headerdata: &[u8]) -> AnyResult<W> {
writer.seek(SeekFrom::Start(0))?;
writer.write_all(&headerdata)?;
Ok(writer)
}
73 changes: 73 additions & 0 deletions bin/mw_datatool/src/cmd/checksum_verify.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use mw_dataformat::read::MwFileReader;

use crate::prelude::*;
use crate::{CommonArgs, ChecksumVerifyArgs};

pub fn main(common: &CommonArgs, _args: &ChecksumVerifyArgs) -> AnyResult<()> {
let file = if let Some(in_path) = &common.input {
std::fs::OpenOptions::new()
.read(true)
.open(in_path)
.context("Cannot open input file!")?
} else {
bail!("Input filename must be specified!");
};
let mut buf = Vec::new();

let mut mfr = MwFileReader::new(file, &mut buf)
.context("Failed to load input file as a MineWars format file!")?;

let mut all_good = true;

let checksum_expected = mfr.file_header().checksum_header;
match mfr.compute_new_checksum_header() {
Ok(checksum) => {
if checksum == checksum_expected {
eprintln!("Header checksum: {:016x} (ok!)", checksum);
} else {
eprintln!("Header checksum: {:016x} (BAD! Expected: {:016x})", checksum, checksum_expected);
all_good = false;
}
}
Err(e) => {
eprintln!("Header checksum: Expected: {:016x} Cannot verify! Error: {:#}", checksum_expected, e);
all_good = false;
}
}
let checksum_expected = mfr.file_header().checksum_is;
match mfr.compute_new_checksum_isdata() {
Ok(checksum) => {
if checksum == checksum_expected {
eprintln!("ISData checksum: {:016x} (ok!)", checksum);
} else {
eprintln!("ISData checksum: {:016x} (BAD! Expected: {:016x})", checksum, checksum_expected);
all_good = false;
}
}
Err(e) => {
eprintln!("ISData checksum: Expected: {:016x} Cannot verify! Error: {:#}", checksum_expected, e);
all_good = false;
}
}
let checksum_expected = mfr.file_header().checksum_framedata;
match mfr.compute_new_checksum_framedata() {
Ok(checksum) => {
if checksum == checksum_expected {
eprintln!("Frames checksum: {:016x} (ok!)", checksum);
} else {
eprintln!("Frames checksum: {:016x} (BAD! Expected: {:016x})", checksum, checksum_expected);
all_good = false;
}
}
Err(e) => {
eprintln!("Frames checksum: Expected: {:016x} Cannot verify! Error: {:#}", checksum_expected, e);
all_good = false;
}
}

if all_good {
Ok(())
} else {
bail!("Checksum verification failed!");
}
}
38 changes: 38 additions & 0 deletions bin/mw_datatool/src/cmd/gen_map.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use std::io::BufWriter;

use mw_common::{game::{MapGenTileData, TileKind}, grid::*};

use crate::prelude::*;
use crate::{CommonArgs, GenMapArgs};

pub fn main(common: &CommonArgs, args: &GenMapArgs) -> AnyResult<()> {
let file = if let Some(out_path) = &common.output {
std::fs::OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(out_path)
.context("Cannot create output file!")?
} else {
bail!("Output filename must be specified!");
};
let mut buf = Vec::new();
let mut scratch = Vec::new();
let mut tile = MapGenTileData::default();
tile.set_kind(TileKind::Regular);
tile.set_region(0xFF);
let map: MapData<Hex, _> = MapData::new(args.size, tile);

let bufwriter = BufWriter::new(file);
let (b_file, b_is) = mw_dataformat::write::MwFileBuilder::new(bufwriter, &mut buf)?
.start_is()?;
let is = b_is
.with_map_lz4compressed(&map, true, &mut scratch)?
.with_cits([Pos(12, 17), Pos(7, 3)])?
.with_named_players(["iyes", "georgie", "gr.NET"])?
.finish()?;
let b_file = b_file.with_is(is)?;
b_file.finish()?;

Ok(())
}
59 changes: 59 additions & 0 deletions bin/mw_datatool/src/cmd/info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use mw_dataformat::read::MwFileReader;

use crate::prelude::*;
use crate::{CommonArgs, InfoArgs};

pub fn main(common: &CommonArgs, args: &InfoArgs) -> AnyResult<()> {
let file = if let Some(in_path) = &common.input {
std::fs::OpenOptions::new()
.read(true)
.open(in_path)
.context("Cannot read input file!")?
} else {
bail!("Input filename must be specified!");
};
let mut buf = Vec::new();

let mut mfr = MwFileReader::new(file, &mut buf)
.context("Failed to load input file as a MineWars format file!")?;

if !args.ignore_checksums {
mfr.verify_checksums()
.context("Checksum verification failed!")?;
}

eprintln!("File Header:");
let checksum_header = mfr.file_header().checksum_header;
eprintln!("Header checksum: {:016x}", checksum_header);
let checksum_is = mfr.file_header().checksum_is;
eprintln!("ISData checksum: {:016x}", checksum_is);
let checksum_framedata = mfr.file_header().checksum_framedata;
eprintln!("Frames checksum: {:016x}", checksum_framedata);
eprintln!("FrameData is compressed?: {}", mfr.is_framedata_compressed());
eprintln!("FrameData length (compressed): {}", mfr.file_header().len_framedata_compressed());
eprintln!("FrameData length (raw): {}", mfr.file_header().len_framedata_raw());

let (_, mut isr) = mfr.read_is()
.context("Cannot read IS")?;

eprintln!();
eprintln!("IS Header:");
eprintln!("Map Topology: {:?}", isr.map_topology());
eprintln!("Map Size: {}", isr.map_size());
eprintln!("Number of map regions: {}", isr.n_regions());
eprintln!("MapData is compressed?: {}", isr.is_mapdata_compressed());
eprintln!("MapData length (compressed): {}", isr.header().len_mapdata_compressed());
eprintln!("MapData length (raw): {}", isr.header().len_mapdata_raw());
eprintln!("Number of players: {}", isr.n_players());
eprintln!("Player names anonymized?: {}", isr.header().len_playerdata() == 0);
eprintln!("PlayerData length: {}", isr.header().len_playerdata());
eprintln!("RulesData length: {}", isr.header().len_rules());

eprintln!();
eprintln!("Player Names:");
for (i, name) in isr.read_players()?.enumerate() {
eprintln!("{}: {:?}", i, name);
}

Ok(())
}
54 changes: 54 additions & 0 deletions bin/mw_datatool/src/cmd/map_ascii.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use mw_common::game::{MapGenTileData, TileKind};
use mw_common::grid::{Coord, MapDataTopo, Pos};
use mw_dataformat::read::MwFileReader;

use crate::prelude::*;
use crate::{CommonArgs, MapAsciiArgs};

pub fn main(common: &CommonArgs, _args: &MapAsciiArgs) -> AnyResult<()> {
let file = if let Some(in_path) = &common.input {
std::fs::OpenOptions::new()
.read(true)
.open(in_path)
.context("Cannot open input file!")?
} else {
bail!("Input filename must be specified!");
};
let mut buf = Vec::new();
let mut scratch = Vec::new();

let mfr = MwFileReader::new(file, &mut buf)
.context("Failed to load input file as a MineWars format file!")?;

let (_, mut isr) = mfr.read_is()?;
let map: MapDataTopo<MapGenTileData> = isr.read_map_dyntopo(Some(&mut scratch), false)?;
let cits = isr.read_cits()?;

fn f_tile_ascii(cits: &[Pos], pos: Pos, kind: TileKind) -> u8 {
if cits.iter().position(|p| *p == pos).is_some() {
b'C'
} else {
match kind {
TileKind::Water => b'~',
TileKind::Regular => b'.',
TileKind::Fertile => b',',
TileKind::Forest => b'i',
TileKind::Mountain => b'm',
TileKind::Destroyed => b'+',
TileKind::FoundationRoad => b'x',
TileKind::FoundationStruct => b'_',
}
}
}

match map {
MapDataTopo::Hex(map) => {
map.ascii_art(&mut std::io::stdout().lock(), |c, d| f_tile_ascii(cits, c.into(), d.kind()))?;
}
MapDataTopo::Sq(map) => {
map.ascii_art(&mut std::io::stdout().lock(), |c, d| f_tile_ascii(cits, c.into(), d.kind()))?;
}
}

Ok(())
}
Loading

0 comments on commit 30528dc

Please sign in to comment.