diff --git a/Cargo.toml b/Cargo.toml index b68602e..3b1dc8a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,22 @@ edition = "2018" name = "lvd" path = "src/lib.rs" +[[bin]] +name = "yamlvd" +path = "src/main.rs" +required-features = ["cli"] + [dependencies] binrw = { git = "https://github.com/jam1garner/binrw" } binwrite = "0.2.1" + +# serde support +serde = { version = "1", features = ["derive"], optional = true } + +# cli +clap = { version = "3.0.0-beta", optional = true } +serde_yaml = { version = "0.8", optional = true } + +[features] +serde_support = ["serde"] +cli = ["serde_support", "clap", "serde_yaml"] diff --git a/src/lib.rs b/src/lib.rs index 8a04dc7..e971381 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,14 @@ -use binrw::{prelude::*, punctuated::Punctuated, NullString, derive_binread}; +use binrw::{prelude::*, helpers::Punctuated, NullString, derive_binread}; use binwrite::BinWrite; use std::path::Path; use core::fmt; +#[cfg(feature = "serde_support")] +use serde::{Serialize, Deserialize}; + mod writer; +#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] #[derive(BinRead, Debug)] #[br(big, magic = b"\x00\x00\x00\x01\x0D\x01\x4C\x56\x44\x31")] pub struct LvdFile { @@ -33,6 +37,7 @@ pub struct LvdFile { pub shrunk_blastzones: Section, } +#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] #[derive(BinRead, Debug)] #[br(magic = b"\x01\x04\x01\x01\x77\x35\xBB\x75\x00\x00\x00\x02")] pub struct Point { @@ -45,6 +50,7 @@ pub struct Point { pub pos: Vector3, } +#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] #[derive(BinRead, Debug)] #[br(magic = b"\x01\x04\x01\x01\x77\x35\xBB\x75\x00\x00\x00\x02")] pub struct PokemonTrainerPlatform { @@ -55,6 +61,7 @@ pub struct PokemonTrainerPlatform { #[derive_binread] #[derive(Debug)] +#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] #[br(magic = b"\x04\x04\x01\x01\x77\x35\xBB\x75\x00\x00\x00\x02")] pub struct PokemonTrainer { pub entry: LvdEntry, @@ -64,16 +71,17 @@ pub struct PokemonTrainer { pub boundary_max: Vector3, #[br(temp, pad_before = 1)] pub trainer_count: u32, - #[br(pad_before = 1, parse_with = Punctuated::separated, count = trainer_count)] - pub trainers: Punctuated, - #[br(pad_before = 1, pad_size_to = 0x40)] - pub platform_name: NullString, - #[br(pad_before = 1, pad_size_to = 0x40)] - pub sub_name: NullString, + #[br(pad_before = 1, parse_with = Punctuated::::separated, map = Punctuated::into_values, count = trainer_count)] + pub trainers: Vec, + #[br(pad_before = 1, pad_size_to = 0x40, map = NullString::into_string)] + pub platform_name: String, + #[br(pad_before = 1, pad_size_to = 0x40, map = NullString::into_string)] + pub sub_name: String, } #[derive_binread] #[derive(Debug)] +#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] #[br(magic = b"\x01\x04\x01\x01\x77\x35\xBB\x75\x00\x00\x00\x02")] pub struct ItemSpawner { pub entry: LvdEntry, @@ -82,12 +90,13 @@ pub struct ItemSpawner { pub unk: u8, #[br(temp, pad_before = 1)] pub section_count: u32, - #[br(pad_before = 1, parse_with = Punctuated::separated, count = section_count)] - pub sections: Punctuated, + #[br(pad_before = 1, parse_with = Punctuated::::separated, map = Punctuated::into_values, count = section_count)] + pub sections: Vec, } #[derive_binread] #[derive(Debug)] +#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] pub enum LvdShape { #[br(magic = b"\x03\0\0\0\x01")] Point { @@ -123,8 +132,8 @@ pub enum LvdShape { Path { #[br(temp, pad_before = 0x12)] point_count: u32, - #[br(pad_before = 1, parse_with = Punctuated::separated, count = point_count)] - points: Punctuated, + #[br(pad_before = 1, parse_with = Punctuated::::separated, map = Punctuated::into_values, count = point_count)] + points: Vec, }, Invalid { magic: u32, @@ -133,6 +142,7 @@ pub enum LvdShape { #[derive(BinRead, Debug)] #[br(assert(count == 0))] +#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] pub struct UnsupportedSection { #[br(pad_before = 1)] pub count: u32, @@ -140,6 +150,8 @@ pub struct UnsupportedSection { #[derive_binread] #[derive(Debug)] +#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde_support", serde(transparent))] pub struct Section> { #[br(temp, pad_before = 1)] pub count: u32, @@ -164,6 +176,7 @@ impl> core::ops::DerefMut for Section { #[derive(BinRead, Debug)] #[br(magic = b"\x02\x04\x01\x01\x77\x35\xBB\x75\x00\x00\x00\x02")] +#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] pub struct Spawn { pub entry: LvdEntry, #[br(pad_before = 1)] @@ -172,6 +185,7 @@ pub struct Spawn { #[derive(BinRead, Debug)] #[br(magic = b"\x02\x04\x01\x01\x77\x35\xBB\x75\x00\x00\x00\x02")] +#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] pub struct Bounds { pub entry: LvdEntry, #[br(pad_before = 1)] @@ -182,6 +196,7 @@ pub struct Bounds { } #[derive(BinRead, BinWrite)] +#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] pub struct Vector3 { pub x: f32, pub y: f32, @@ -199,6 +214,7 @@ impl fmt::Debug for Vector3 { } #[derive(BinRead, BinWrite)] +#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] pub struct Vector2 { pub x: f32, pub y: f32, @@ -215,11 +231,12 @@ fn cbool(x: u8) -> bool { } #[derive(BinRead, Debug)] +#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] pub struct LvdEntry { - #[br(pad_before = 1, pad_size_to = 0x38)] - pub name: NullString, - #[br(pad_before = 1, pad_size_to = 0x40)] - pub subname: NullString, + #[br(pad_before = 1, pad_size_to = 0x38, map = NullString::into_string)] + pub name: String, + #[br(pad_before = 1, pad_size_to = 0x40, map = NullString::into_string)] + pub subname: String, #[br(pad_before = 1)] pub start_pos: Vector3, #[br(map = cbool)] @@ -229,13 +246,14 @@ pub struct LvdEntry { #[br(pad_before = 1)] pub unk2: Vector3, pub unk3: u32, - #[br(pad_before = 1, pad_size_to = 0x40)] - pub bone_name: NullString, + #[br(pad_before = 1, pad_size_to = 0x40, map = NullString::into_string)] + pub bone_name: String, } use writer::c_bool as to_c_bool; #[derive(BinRead, BinWrite, Debug)] +#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] pub struct ColFlags { #[br(map = cbool)] #[binwrite(preprocessor(to_c_bool))] @@ -258,11 +276,12 @@ type Material = [u8; 0xC]; #[derive(BinRead, Debug)] #[br(magic = b"\x02\x04\x01\x01\x77\x35\xBB\x75\x00\x00\x00\x02")] +#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] pub struct UnknownEntry { pub entry: LvdEntry, pub unk: u32, - #[br(pad_before = 1, pad_size_to = 0x40)] - pub string: NullString, + #[br(pad_before = 1, pad_size_to = 0x40, map = NullString::into_string)] + pub string: String, pub unk2: Vector2, pub unk3: Vector2, pub unk4: [u8; 8], @@ -271,25 +290,26 @@ pub struct UnknownEntry { #[derive_binread] #[derive(Debug)] #[br(magic = b"\x04\x04\x01\x01\x77\x35\xBB\x75\x00\x00\x00\x02")] +#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] pub struct Collision { pub entry: LvdEntry, pub col_flags: ColFlags, #[br(temp, pad_before = 1)] pub vert_count: u32, - #[br(pad_before = 1, parse_with = Punctuated::separated, count = vert_count)] - pub verts: Punctuated, + #[br(pad_before = 1, parse_with = Punctuated::::separated, map = Punctuated::into_values, count = vert_count)] + pub verts: Vec, #[br(temp, pad_before = 1)] pub normal_count: u32, - #[br(pad_before = 1, parse_with = Punctuated::separated, count = normal_count)] - pub normals: Punctuated, + #[br(pad_before = 1, parse_with = Punctuated::::separated, map = Punctuated::into_values, count = normal_count)] + pub normals: Vec, #[br(temp, pad_before = 1)] pub cliff_count: u32, #[br(count = cliff_count)] pub cliffs: Vec, #[br(temp, pad_before = 1)] pub mat_count: u32, - #[br(pad_before = 1, parse_with = Punctuated::separated, count = mat_count)] - pub materials: Punctuated, + #[br(pad_before = 1, parse_with = Punctuated::::separated, map = Punctuated::into_values, count = mat_count)] + pub materials: Vec, #[br(temp, pad_before = 1)] pub unk_count: u32, #[br(count = unk_count)] @@ -298,6 +318,7 @@ pub struct Collision { #[derive(BinRead, Debug)] #[br(magic = b"\x03\x04\x01\x01\x77\x35\xBB\x75\x00\x00\x00\x02")] +#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] pub struct CollisionCliff { pub entry: LvdEntry, #[br(pad_before = 1)] diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..621205d --- /dev/null +++ b/src/main.rs @@ -0,0 +1,31 @@ +use std::path::PathBuf; +use std::fs; + +use lvd::LvdFile; +use clap::Clap; + +#[derive(Clap)] +struct Args { + in_file: PathBuf, + out_file: PathBuf, +} + +fn main() { + let args = Args::parse(); + + match LvdFile::open(&args.in_file) { + Ok(lvd_file) => { + fs::write(&args.out_file, serde_yaml::to_string(&lvd_file).unwrap()).unwrap(); + } + Err(binrw::Error::BadMagic { .. }) => { + // Magic doesn't match, is a yaml file + let contents = fs::read_to_string(&args.in_file).unwrap(); + let lvd_file: LvdFile = serde_yaml::from_str(&contents).unwrap(); + + lvd_file.save(&args.out_file).unwrap(); + } + Err(err) => { + eprintln!("Error: {:?}", err); + } + } +} diff --git a/src/writer.rs b/src/writer.rs index c9dba19..5cf3882 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -132,7 +132,7 @@ impl BinWrite for UnknownEntry { &self.entry, self.unk, 1u8, - string38(self.string.clone().to_string()), + string38(&self.string), &self.unk2, &self.unk3, &self.unk3, @@ -141,22 +141,22 @@ impl BinWrite for UnknownEntry { } #[derive(BinWrite)] -struct String38 { +struct String38<'a> { #[binwrite(cstr, align_after(0x38))] - s: String + s: &'a str } -fn string38(s: String) -> String38 { +fn string38(s: &str) -> String38 { String38 { s } } #[derive(BinWrite)] -struct String40 { +struct String40<'a> { #[binwrite(cstr, align_after(0x40))] - s: String + s: &'a str } -fn string40(s: String) -> String40 { +fn string40(s: &str) -> String40 { String40 { s } } @@ -168,9 +168,9 @@ impl BinWrite for LvdEntry { fn write_options(&self, writer: &mut W, options: &WriterOption) -> io::Result<()> { ( 1u8, - string38(self.name.clone().into_string()), + string38(&self.name), 1u8, - string40(self.subname.clone().into_string()), + string40(&self.subname), 1u8, &self.start_pos, c_bool(&self.use_start), @@ -180,7 +180,7 @@ impl BinWrite for LvdEntry { &self.unk2, self.unk3, 1u8, - string40(self.bone_name.clone().into_string()), + string40(&self.bone_name), ).write_options(writer, options) } } @@ -283,9 +283,9 @@ impl BinWrite for PokemonTrainer { 1u8, LvdList(&self.trainers), 1u8, - string40(self.platform_name.to_string()), + string40(&self.platform_name), 1u8, - string40(self.sub_name.to_string()), + string40(&self.sub_name), ).write_options(writer, options) } }