Something went wrong. Try again.
Data management tools for playing BattleTech
Something went wrong. Try again.
3.4 kB · 100 lines
Rust
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101//! Readers for MegaMek's two unit file formats.//!//! MegaMek stores a unit design in one of two hand-editable text formats://! `.mtf` for Meks and `.blk` for everything else. Both are declarative — they//! record what the designer chose, not what the choices add up to. Battle//! value, C-bill cost and the Alpha Strike conversion are computed when//! MegaMek loads the design and appear in neither format; those live in//! [`helm_core::ComputedStats`].//!//! What these readers give you is everything the designer declared: chassis//! and model, tech base, era, tonnage, engine, movement, armour, the equipment//! list and the quirks.//!//! Nothing is discarded. Fields the typed struct does not name stay in//! [`Unit::fields`] under their original key, so a MegaMek release that adds//! one is readable before this crate knows about it.//!//! Parsing one design is pure and available everywhere. Reading a whole//! library touches the filesystem and a zip, so it is behind the `library`//! feature, which is on by default and off for wasm.
pub use helm_core::{Format, Mount, Unit};
mod blk;pub mod mekset;mod mtf;mod mul;
pub use blk::parse_blk;pub use mtf::{armor_location_order, parse_mtf, split_pipe_list, split_system_field};pub use mul::{ ForceNode, ForceRef, Kept, MUL_VERSION, Mul, MulUnit, locations_for, locations_for_config, parse_force_chain, parse_mul, write_mul,};
#[cfg(feature = "library")]mod library;#[cfg(feature = "library")]pub use library::{Library, megamek_version, read_dir, read_mekset, read_zip, read_zip_text};
/// What went wrong reading a unit file.#[derive(Debug)]pub enum Error { #[cfg(feature = "library")] Io(std::io::Error), #[cfg(feature = "library")] Zip(zip::result::ZipError), /// The file parsed but does not identify a unit. Malformed { path: String, reason: String },}
impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { #[cfg(feature = "library")] Error::Io(e) => write!(f, "{e}"), #[cfg(feature = "library")] Error::Zip(e) => write!(f, "{e}"), Error::Malformed { path, reason } => write!(f, "{path}: {reason}"), } }}
impl std::error::Error for Error {}
#[cfg(feature = "library")]impl From<std::io::Error> for Error { fn from(e: std::io::Error) -> Self { Error::Io(e) }}
#[cfg(feature = "library")]impl From<zip::result::ZipError> for Error { fn from(e: zip::result::ZipError) -> Self { Error::Zip(e) }}
/// Parse a unit from bytes, choosing the reader by file extension.pub fn parse(path: &str, bytes: &[u8]) -> Result<Unit, Error> { // MegaMek's library is thirty years of files from many editors. Most are // UTF-8; the rest are Latin-1 and would otherwise fail to read at all. let text = match std::str::from_utf8(bytes) { Ok(s) => s.to_string(), Err(_) => bytes.iter().map(|&b| b as char).collect(), };
let lower = path.to_ascii_lowercase(); if lower.ends_with(".mtf") { parse_mtf(path, &text) } else if lower.ends_with(".blk") { parse_blk(path, &text) } else { Err(Error::Malformed { path: path.to_string(), reason: "not a .mtf or .blk file".into(), }) }}