From 90f8c87ddc55d3967aa3864d8d60f7de5a809940 Mon Sep 17 00:00:00 2001 From: Tad Hardesty Date: Fri, 20 Oct 2017 17:57:09 -0700 Subject: [PATCH] Add TGM output Vars are now a LinkedHashMap to preserve order in the case that they aren't alphabetized in the input. --- Cargo.lock | 7 ++++ Cargo.toml | 1 + src/dmm.rs | 106 ++++++++++++++++++++++++++++++++++++++++++++++--- src/main.rs | 1 + src/objtree.rs | 4 +- 5 files changed, 111 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 19527a4a..625ddbc9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -110,6 +110,11 @@ name = "libc" version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "linked-hash-map" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "matrixmultiply" version = "0.1.13" @@ -124,6 +129,7 @@ version = "0.1.0" dependencies = [ "flame 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "inflate 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "linked-hash-map 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "ndarray 0.10.11 (registry+https://github.com/rust-lang/crates.io-index)", "petgraph 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "png 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -339,6 +345,7 @@ dependencies = [ "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c9e5e58fa1a4c3b915a561a78a22ee0cac6ab97dca2504428bc1cb074375f8d5" "checksum libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "56cce3130fd040c28df6f495c8492e5ec5808fb4c9093c310df02b0c8f030148" +"checksum linked-hash-map 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2aab0478615bb586559b0114d94dd8eca4fdbb73b443adcb0d00b61692b4bf" "checksum matrixmultiply 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "7ce012d2c43046267a74283eaa7e9a51941479901e2b86702be10f27e2779158" "checksum ndarray 0.10.11 (registry+https://github.com/rust-lang/crates.io-index)" = "61f6cb6e2d51afc73d17e19ca3e711b6bd0221773867dbd6453698612d7af95f" "checksum num-complex 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "503e668405c5492d67cf662a81e05be40efe2e6bcf10f7794a07bd9865e704e6" diff --git a/Cargo.toml b/Cargo.toml index 8e030037..42a2fe66 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ png = "0.11.0" inflate = "0.3.3" ndarray = "0.10.11" rand = "0.3.17" +linked-hash-map = "0.5.0" flame = { version = "0.2.0", optional = true } [dev-dependencies] diff --git a/src/dmm.rs b/src/dmm.rs index 0b1ef8a2..fb2bd38b 100644 --- a/src/dmm.rs +++ b/src/dmm.rs @@ -1,13 +1,16 @@ use std::collections::BTreeMap; use std::path::Path; use std::fs::File; -use std::io::{self, BufReader}; +use std::io::{self, BufReader, BufWriter}; +use std::fmt; use ndarray::{self, Array3, Axis}; +use linked_hash_map::LinkedHashMap; #[derive(Debug)] pub struct Map { pub key_length: u8, + // sorted order pub dictionary: BTreeMap>, pub grid: Array3, // Z/Y/X order } @@ -17,8 +20,8 @@ pub type Grid<'a> = ndarray::ArrayBase, ndarray::Dim< #[derive(Debug, Default)] pub struct Prefab { pub path: String, - // important that this is a BTreeMap, so it's ordered alphabetically - pub vars: BTreeMap, + // insertion order, sort of most of the time alphabetical but not quite + pub vars: LinkedHashMap, } impl Map { @@ -26,13 +29,18 @@ impl Map { flame!("Map::from_file"); let mut map = Map { key_length: 0, - dictionary: BTreeMap::new(), + dictionary: Default::default(), grid: Array3::default((1, 255, 255)), }; parse_map(&mut map, File::open(path)?)?; Ok(map) } + pub fn to_file(&self, path: &Path) -> io::Result<()> { + // DMM saver later + save_tgm(self, File::create(path)?) + } + #[inline] pub fn dim_z(&self) -> usize { self.grid.dim().0 @@ -42,6 +50,90 @@ impl Map { pub fn z_level(&self, z: usize) -> Grid { self.grid.subview(Axis(0), z) } + + #[inline] + pub fn format_key(&self, key: u32) -> FormatKey { + FormatKey(self.key_length, key) + } +} + +// ---------------------------------------------------------------------------- +// Map Writer + +#[derive(Copy, Clone)] +pub struct FormatKey(u8, u32); + +impl FormatKey { + #[inline] + pub fn new(key_length: u8, key: u32) -> FormatKey { + FormatKey(key_length, key) + } +} + +impl fmt::Display for FormatKey { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use std::fmt::Write; + let FormatKey(key_length, key) = *self; + + if key >= 52u32.pow(key_length as u32) { + panic!(); // TODO be more reasonable + } + + let mut current = 52usize.pow(key_length as u32 - 1); + for i in 0..key_length { + f.write_char(BASE_52[(key as usize / current) % 52] as char)?; + current /= 52; + } + + Ok(()) + } +} + +const BASE_52: &[u8] = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + +const TGM_HEADER: &str = "//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE"; + +fn save_tgm(map: &Map, f: File) -> io::Result<()> { + use std::io::Write; + + let mut f = BufWriter::new(f); + write!(f, "{}\n", TGM_HEADER)?; + + // dictionary + for (&key, prefabs) in map.dictionary.iter() { + write!(f, "\"{}\" = (\n", map.format_key(key))?; + for (i, fab) in prefabs.iter().enumerate() { + write!(f, "{}", fab.path)?; + if !fab.vars.is_empty() { + write!(f, "{{")?; + for (i, (var, value)) in fab.vars.iter().enumerate() { + write!(f, "\n\t{} = {}", var, value)?; + if i + 1 != fab.vars.len() { + write!(f, ";")?; + } + } + write!(f, "\n\t}}")?; + } + if i + 1 != prefabs.len() { + write!(f, ",\n")?; + } + } + write!(f, ")\n")?; + } + + // grid in Y-major + for (z, z_grid) in map.grid.axis_iter(Axis(0)).enumerate() { + write!(f, "\n")?; + for (x, x_col) in z_grid.axis_iter(Axis(1)).enumerate() { + write!(f, "({},1,{}) = {{\"\n", x + 1, z + 1)?; + for &elem in x_col.iter() { + write!(f, "{}\n", map.format_key(elem))?; + } + write!(f, "\"}}\n")?; + } + } + + Ok(()) } // ---------------------------------------------------------------------------- @@ -125,7 +217,7 @@ fn parse_map(map: &mut Map, f: File) -> io::Result<()> { if ch == '"' { curr_datum.push(ch); in_quote_block = true; - } else if ch == '=' { + } else if ch == '=' && curr_var.is_empty() { curr_var = take(&mut curr_datum); let length = curr_var.trim_right().len(); curr_var.truncate(length); @@ -134,7 +226,9 @@ fn parse_map(map: &mut Map, f: File) -> io::Result<()> { curr_prefab.vars.insert(take(&mut curr_var), take(&mut curr_datum)); skip_whitespace = true; } else if ch == '}' { - curr_prefab.vars.insert(take(&mut curr_var), take(&mut curr_datum)); + if !curr_var.is_empty() { + curr_prefab.vars.insert(take(&mut curr_var), take(&mut curr_datum)); + } in_varedit_block = false; } else { curr_datum.push(ch); diff --git a/src/main.rs b/src/main.rs index 546ab08e..3060f8cd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ extern crate petgraph; extern crate png; extern crate inflate; +extern crate linked_hash_map; #[macro_use] extern crate ndarray; extern crate rand; diff --git a/src/objtree.rs b/src/objtree.rs index 835b8fd1..345f9e11 100644 --- a/src/objtree.rs +++ b/src/objtree.rs @@ -7,7 +7,7 @@ use petgraph::graph::{Graph, NodeIndex}; use xml::EventReader; use xml::reader::XmlEvent; -pub type Vars = BTreeMap; +pub type Vars = ::linked_hash_map::LinkedHashMap; #[derive(Debug)] pub struct ObjectTree { @@ -54,7 +54,7 @@ impl ObjectTree { let mut tree = ObjectTree { graph: Graph::new(), types: BTreeMap::new(), - blank_vars: BTreeMap::new(), + blank_vars: Default::default(), }; let root = tree.graph.add_node(Type { name: String::new(),