mindustry logic execution, map- and schematic- parsing and rendering
-rw-r--r--Cargo.toml2
-rw-r--r--src/data/schematic.rs3
-rw-r--r--src/main.rs163
3 files changed, 165 insertions, 3 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 254c0f5..32bdc78 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "plandustry"
-version = "0.0.1"
+version = "0.1.0"
edition = "2021"
publish = false
diff --git a/src/data/schematic.rs b/src/data/schematic.rs
index 10252aa..d1e1c9a 100644
--- a/src/data/schematic.rs
+++ b/src/data/schematic.rs
@@ -602,11 +602,10 @@ impl fmt::Display for Schematic
writeln!(f)?;
}
// print the letters assigned to blocks
- writeln!(f)?;
for (k, _) in name_cnt
{
let v = *types.get(k).unwrap();
- writeln!(f, "({v}) {k}")?;
+ write!(f, "\n({v}) {k}")?;
}
}
else {write!(f, "<empty {} * {}>", self.width, self.height)?;}
diff --git a/src/main.rs b/src/main.rs
index 90d8d48..e9f7522 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,12 @@
+use std::borrow::Cow;
+use std::env::Args;
+use std::io::{self, Write};
+use std::fs;
+
+use crate::args::{ArgOption, OptionError, OptionHandler, OptionValue};
+use crate::data::{DataRead, Serializer};
+use crate::data::schematic::{Schematic, SchematicSerializer};
+
pub mod access;
pub mod args;
pub mod block;
@@ -6,4 +15,158 @@ pub mod logic;
fn main()
{
+ let mut args = std::env::args();
+ args.next().unwrap(); // path to executable
+ match args.next()
+ {
+ None => panic!("not enough arguments"),
+ Some(s) if s == "print" => main_print(args),
+ Some(s) => panic!("unknown argument {s}"),
+ }
+}
+
+fn main_print(mut args: Args)
+{
+ const FILE: ArgOption = ArgOption::new(Some('f'), Some(Cow::Borrowed("file")));
+ const INTERACTIVE: ArgOption = ArgOption::new(Some('i'), Some(Cow::Borrowed("interactive")));
+ let mut handler = OptionHandler::new();
+ handler.add(FILE).unwrap();
+ handler.add(INTERACTIVE).unwrap();
+ match args::parse(&mut args, &mut handler)
+ {
+ Err(args::Error::Handler{pos, val: OptionError::NoSuchShort(short)}) =>
+ {
+ println!("Invalid argument \"-{short}\" (at #{pos})).");
+ return;
+ },
+ Err(args::Error::Handler{pos, val: OptionError::NoSuchLong(long)}) =>
+ {
+ println!("Invalid argument \"--{long}\" (at #{pos})).");
+ return;
+ },
+ Err(args::Error::Handler{pos, val: OptionError::Duplicate(opt)}) =>
+ {
+ match (opt.get_short(), opt.get_long())
+ {
+ (None, None) => unreachable!("unnamed ArgOption (at #{pos}))"),
+ (None, Some(long)) => println!("Duplicate argument \"--{long}\" (at #{pos}))."),
+ (Some(short), None) => println!("Duplicate argument \"-{short}\" (at #{pos}))."),
+ (Some(short), Some(long)) => println!("Duplicate argument \"--{long}\" (\"-{short}\", at #{pos}))."),
+ }
+ return;
+ },
+ Err(args::Error::EmptyName{pos}) =>
+ {
+ println!("Invalid empty argument (at #{pos}).");
+ return;
+ },
+ _ => (),
+ }
+
+ let reg = block::build_registry();
+ let mut ss = SchematicSerializer(&reg);
+ let mut first = true;
+ // process the file if any
+ let file = match handler.get_long("file").unwrap().1
+ {
+ OptionValue::Absent => false,
+ OptionValue::Present =>
+ {
+ return;
+ },
+ OptionValue::Value(ref path) =>
+ {
+ match fs::read(path)
+ {
+ Ok(data) =>
+ {
+ match ss.deserialize(&mut DataRead::new(&data))
+ {
+ Ok(s) =>
+ {
+ if first {first = false;}
+ else {println!();}
+ println!("Schematic: @{path}");
+ print_schematic(&s);
+ },
+ // continue processing literals & maybe interactive mode
+ Err(e) => println!("Could not read schematic: {e:?}"),
+ }
+ },
+ // continue processing literals & maybe interactive mode
+ Err(e) => println!("Could not read file {path:?}: {e}"),
+ }
+ true
+ },
+ };
+ // process schematics from command line
+ for curr in handler.get_literals()
+ {
+ match ss.deserialize_base64(curr)
+ {
+ Ok(s) =>
+ {
+ if first {first = false;}
+ else {println!();}
+ println!("Schematic: {curr}");
+ print_schematic(&s);
+ },
+ // continue processing literals & maybe interactive mode
+ Err(e) => println!("Could not read schematic: {e:?}"),
+ }
+ }
+ // if --interactive or no schematics: continue parsing from console
+ let interactive = if let OptionValue::Absent = handler.get_long("interactive").unwrap().1 {false} else {true};
+ if interactive || (!file && handler.get_literals().is_empty())
+ {
+ println!("\nEntering interactive mode, paste schematic to print details.\n");
+ let mut buff = String::new();
+ let stdin = io::stdin();
+ loop
+ {
+ buff.clear();
+ print!("> ");
+ if let Err(e) = io::stdout().flush()
+ {
+ // what the print & println macros would do
+ panic!("failed printing to stdout: {e}");
+ }
+ match stdin.read_line(&mut buff)
+ {
+ Ok(..) =>
+ {
+ let data = buff.trim();
+ if data.is_empty() {break;}
+ match ss.deserialize_base64(data)
+ {
+ Ok(s) => print_schematic(&s),
+ // continue interactive mode, typos are especially likely here
+ Err(e) => println!("Could not read schematic: {e:?}"),
+ }
+ },
+ Err(e) =>
+ {
+ println!("Failed to read next line: {e}");
+ break;
+ },
+ }
+ }
+ }
+}
+
+fn print_schematic(s: &Schematic)
+{
+ if let Some(name) = s.get_tags().get("name")
+ {
+ if !name.is_empty() {println!("Name: {name}");}
+ }
+ if let Some(desc) = s.get_tags().get("description")
+ {
+ if !desc.is_empty() {println!("Desc: {desc}");}
+ }
+ if let Some(labels) = s.get_tags().get("labels")
+ {
+ if !labels.is_empty() && labels != "[]" {println!("Tags: {:?}", labels);}
+ }
+ println!("\n{s}");
}