mindustry logic execution, map- and schematic- parsing and rendering
embed assets into the binary
| -rw-r--r-- | Cargo.toml | 6 | ||||
| -rw-r--r-- | build.rs | 63 | ||||
| -rw-r--r-- | src/data/renderer.rs | 20 |
3 files changed, 83 insertions, 6 deletions
@@ -15,6 +15,12 @@ strconv = { path = "strconv" } image = { version = "0.24.6", features = ["png"], default-features = false } const-str = "0.5.5" color-hex = "0.2.0" +zip = { version = "0.6.6", features = ["zstd"], default-features = false } + +[build-dependencies] +zip = { version = "0.6.6", features = ["zstd"], default-features = false } +walkdir = "2" + [[bin]] name = "plandustry" diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..b740e86 --- /dev/null +++ b/build.rs @@ -0,0 +1,63 @@ +use std::fs::File; +use std::io::prelude::*; +use std::io::{Seek, Write}; +use std::iter::Iterator; +use std::path::Path; +use walkdir::{DirEntry, WalkDir}; +use zip::result::ZipError; +use zip::write::FileOptions; + +fn zip_dir<T>( + it: &mut dyn Iterator<Item = DirEntry>, + prefix: &str, + writer: T, + method: zip::CompressionMethod, +) -> zip::result::ZipResult<()> +where + T: Write + Seek, +{ + let mut zip = zip::ZipWriter::new(writer); + let options = FileOptions::default() + .compression_method(method) + .unix_permissions(0o755); + + let mut buffer = Vec::new(); + for entry in it { + let path = entry.path(); + let name = path.strip_prefix(Path::new(prefix)).unwrap(); + + // Write file or directory explicitly + // Some unzip tools unzip files with directory paths correctly, some do not! + if path.is_file() { + println!("adding file {path:?} as {name:?} ..."); + #[allow(deprecated)] + zip.start_file_from_path(name, options)?; + let mut f = File::open(path)?; + + f.read_to_end(&mut buffer)?; + zip.write_all(&buffer)?; + buffer.clear(); + } else if !name.as_os_str().is_empty() { + // Only if not root! Avoids path spec / warning + // and mapname conversion failed error on unzip + println!("adding dir {path:?} as {name:?} ..."); + #[allow(deprecated)] + zip.add_directory_from_path(name, options)?; + } + } + zip.finish()?; + Result::Ok(()) +} + +fn main() -> Result<(), ZipError> { + let walkdir = WalkDir::new("assets"); + let it = walkdir.into_iter(); + println!("cargo:rerun-if-changed=assets/"); + println!("cargo:rerun-if-changed=build.rs"); + zip_dir( + &mut it.filter_map(|e| e.ok()), + "assets", + File::create(std::env::var("OUT_DIR").unwrap() + "/asset").unwrap(), + zip::CompressionMethod::Zstd, + ) +} diff --git a/src/data/renderer.rs b/src/data/renderer.rs index 3a7713b..4f81b17 100644 --- a/src/data/renderer.rs +++ b/src/data/renderer.rs @@ -1,20 +1,31 @@ -use std::io::BufReader; +use std::io::{BufReader, Cursor}; use std::path::Path; use image::codecs::png::PngDecoder; use image::imageops::overlay; use image::{DynamicImage, RgbaImage}; +use zip::ZipArchive; use super::schematic::Schematic; pub fn load(category: &str, name: &str) -> Option<RgbaImage> { - let mut p = Path::new("assets/blocks").join(category).join(name); + let mut p = Path::new("target/out/blocks").join(category).join(name); p.set_extension("png"); let f = std::fs::File::open(p).ok()?; let r = PngDecoder::new(BufReader::new(f)).unwrap(); Some(DynamicImage::from_decoder(r).unwrap().into_rgba8()) } +fn load_zip() { + if !Path::new("target/out").exists() { + let mut zip = ZipArchive::new(Cursor::new( + include_bytes!(concat!(env!("OUT_DIR"), "/asset")).to_vec(), + )) + .unwrap(); + zip.extract("target/out").unwrap(); + } +} + const SUFFIXES: &[&str; 8] = &[ "bottom", "mid", "", "-base", "-left", "-right", "-top", "-over", ]; @@ -24,10 +35,6 @@ where { let mut c = RgbaImage::new(size.into() * 32, size.into() * 32); for suffix in SUFFIXES { - let mut p = Path::new("assets/blocks") - .join(category) - .join(format!("{name}{suffix}")); - p.set_extension("png"); if let Some(p) = load(category, &format!("{name}{suffix}")) { image::imageops::overlay(&mut c, &p, 0, 0); } @@ -38,6 +45,7 @@ where pub struct Renderer {} impl<'l> Renderer { pub fn render(s: &'l Schematic<'_>) -> RgbaImage { + load_zip(); let mut canvas = RgbaImage::new((s.width * 32).into(), (s.height * 32).into()); for tile in s.block_iter() { let mut x = tile.pos.0 as i64; |