diff --git a/msg_tool_macro/src/lib.rs b/msg_tool_macro/src/lib.rs index 3cc9ddf..f359c52 100644 --- a/msg_tool_macro/src/lib.rs +++ b/msg_tool_macro/src/lib.rs @@ -63,7 +63,8 @@ pub fn struct_unpack_impl_for_num(item: TokenStream) -> TokenStream { /// /// * `skip_pack` attribute can be used to skip fields from packing. /// * `fstring = ` attribute can be used to specify a fixed string length for String fields. -#[proc_macro_derive(StructPack, attributes(skip_pack, fstring))] +/// * `fvec = ` attribute can be used to specify a fixed vector length for Vec<_> fields. +#[proc_macro_derive(StructPack, attributes(skip_pack, fstring, fvec))] pub fn struct_pack_derive(input: TokenStream) -> TokenStream { let a = syn::parse_macro_input!(input as PackStruct); match a { @@ -73,6 +74,7 @@ pub fn struct_pack_derive(input: TokenStream) -> TokenStream { let fields = sut.fields.iter().map(|field| { let mut skipped = false; let mut fixed_string: Option = None; + let mut fixed_vec: Option = None; for attr in &field.attrs { let path = attr.path(); if path.is_ident("skip_pack") { @@ -85,6 +87,14 @@ pub fn struct_pack_derive(input: TokenStream) -> TokenStream { } } } + } else if path.is_ident("fvec") { + if let syn::Meta::NameValue(nv) = &attr.meta { + if let syn::Expr::Lit(lit) = &nv.value { + if let syn::Lit::Int(s) = &lit.lit { + fixed_vec = Some(s.base10_parse().unwrap()); + } + } + } } } if skipped { @@ -117,6 +127,20 @@ pub fn struct_pack_derive(input: TokenStream) -> TokenStream { } } } + if let Some(segment) = type_path.path.segments.first() { + if segment.ident == "Vec" { + if let Some(fixed_vec) = fixed_vec { + return quote::quote! { + if self.#field_name.len() != #fixed_vec { + return Err(anyhow::anyhow!("Vector length was not equal to {}", #fixed_vec)); + } + for item in &self.#field_name { + item.pack(writer, big, encoding)?; + } + }; + } + } + } } quote::quote! { self.#field_name.pack(writer, big, encoding)?; @@ -151,6 +175,7 @@ pub fn struct_pack_derive(input: TokenStream) -> TokenStream { let fields: Vec<_> = variant.fields.iter().enumerate().map(|(idx, field)| { let mut skipped = false; let mut fixed_string: Option = None; + let mut fixed_vec: Option = None; for attr in &field.attrs { let path = attr.path(); if path.is_ident("skip_pack") { @@ -163,6 +188,14 @@ pub fn struct_pack_derive(input: TokenStream) -> TokenStream { } } } + } else if path.is_ident("fvec") { + if let syn::Meta::NameValue(nv) = &attr.meta { + if let syn::Expr::Lit(lit) = &nv.value { + if let syn::Lit::Int(s) = &lit.lit { + fixed_vec = Some(s.base10_parse().unwrap()); + } + } + } } } if skipped { @@ -196,6 +229,20 @@ pub fn struct_pack_derive(input: TokenStream) -> TokenStream { } } } + if let Some(segment) = type_path.path.segments.first() { + if segment.ident == "Vec" { + if let Some(fixed_vec) = fixed_vec { + return quote::quote! { + if #field_name.len() != #fixed_vec { + return Err(anyhow::anyhow!("Vector length was not equal to {}", #fixed_vec)); + } + for item in &#field_name { + item.pack(writer, big, encoding)?; + } + }; + } + } + } } quote::quote! { #field_name.pack(writer, big, encoding)?; @@ -231,7 +278,8 @@ pub fn struct_pack_derive(input: TokenStream) -> TokenStream { /// * `skip_unpack` attribute can be used to skip fields from unpacking. /// * `fstring = ` attribute can be used to specify a fixed string length for String fields. /// * `fstring_no_trim` attribute can be used to disable trimming of fixed strings. -#[proc_macro_derive(StructUnpack, attributes(skip_unpack, fstring, fstring_no_trim))] +/// * `fvec = ` attribute can be used to specify a fixed vector length for Vec<_> fields. +#[proc_macro_derive(StructUnpack, attributes(skip_unpack, fstring, fstring_no_trim, fvec))] pub fn struct_unpack_derive(input: TokenStream) -> TokenStream { let sut = syn::parse_macro_input!(input as syn::ItemStruct); let name = sut.ident; @@ -242,6 +290,7 @@ pub fn struct_unpack_derive(input: TokenStream) -> TokenStream { let mut skipped = false; let mut fixed_string: Option = None; let mut fstring_no_trim = false; + let mut fixed_vec: Option = None; for attr in &field.attrs { let path = attr.path(); if path.is_ident("skip_unpack") { @@ -256,6 +305,14 @@ pub fn struct_unpack_derive(input: TokenStream) -> TokenStream { } } else if path.is_ident("fstring_no_trim") { fstring_no_trim = true; + } else if path.is_ident("fvec") { + if let syn::Meta::NameValue(nv) = &attr.meta { + if let syn::Expr::Lit(lit) = &nv.value { + if let syn::Lit::Int(s) = &lit.lit { + fixed_vec = Some(s.base10_parse().unwrap()); + } + } + } } } let field_name = match &field.ident { @@ -285,6 +342,15 @@ pub fn struct_unpack_derive(input: TokenStream) -> TokenStream { } } } + if let Some(segment) = type_path.path.segments.first() { + if segment.ident == "Vec" { + if let Some(fixed_vec) = fixed_vec { + return quote::quote! { + let #field_name = reader.read_struct_vec(#fixed_vec, big, encoding)?; + }; + } + } + } } quote::quote! { let #field_name = #field_type::unpack(&mut reader, big, encoding)?; diff --git a/src/main.rs b/src/main.rs index 9ce5a54..b851029 100644 --- a/src/main.rs +++ b/src/main.rs @@ -531,7 +531,6 @@ pub fn export_script( } types::OutputScriptType::Custom => { let enc = get_output_encoding(arg); - println!("f: {}", f); script.custom_export(f.as_ref(), enc)?; } } diff --git a/src/scripts/escude/list.rs b/src/scripts/escude/list.rs index 02b5f8b..4ea71e8 100644 --- a/src/scripts/escude/list.rs +++ b/src/scripts/escude/list.rs @@ -148,6 +148,109 @@ impl EscudeBinList { ent.data = data_entry; } } + } else if filename == "enum_gfx.bin" { + for ent in self.entries.iter_mut() { + let id = ent.id; + if let ListData::Unknown(unk) = &ent.data { + let mut reader = MemReader::new(unk.clone()); + let element_size = if id == 0 { + 248 + } else if id == 1 { + 248 + } else if id == 2 { + 248 + } else if id == 3 { + 112 + } else if id == 4 { + 32 + } else if id == 9999 { + 1 + } else { + return Err(anyhow::anyhow!("Unknown enum gfx ID: {}", id)); + }; + let len = unk.len(); + if len % element_size != 0 { + return Err(anyhow::anyhow!( + "Invalid enum gfx length: {} for ID: {}", + len, + id + )); + } + let count = len / element_size; + let data_entry = match id { + 0 => ListData::Gfx(EnumGfx::Bgs( + reader.read_struct_vec::(count, false, encoding)?, + )), + 1 => ListData::Gfx(EnumGfx::Evs( + reader.read_struct_vec::(count, false, encoding)?, + )), + 2 => ListData::Gfx(EnumGfx::Sts( + reader.read_struct_vec::(count, false, encoding)?, + )), + 3 => ListData::Gfx(EnumGfx::Efxs( + reader.read_struct_vec::(count, false, encoding)?, + )), + 4 => ListData::Gfx(EnumGfx::Locs( + reader.read_struct_vec::(count, false, encoding)?, + )), + 9999 => { + // Special case for unknown enum gfx ID + ListData::Unknown(unk.clone()) + } + _ => return Err(anyhow::anyhow!("Unknown enum gfx ID: {}", id)), + }; + ent.data = data_entry; + } + } + } else if filename == "enum_snd.bin" { + for ent in self.entries.iter_mut() { + let id = ent.id; + if let ListData::Unknown(unk) = &ent.data { + let mut reader = MemReader::new(unk.clone()); + let element_size = if id == 0 { + 196 + } else if id == 1 { + 128 + } else if id == 2 { + 128 + } else if id == 3 { + 128 + } else if id == 9999 { + 1 + } else { + return Err(anyhow::anyhow!("Unknown enum sound ID: {}", id)); + }; + let len = unk.len(); + if len % element_size != 0 { + return Err(anyhow::anyhow!( + "Invalid enum sound length: {} for ID: {}", + len, + id + )); + } + let count = len / element_size; + let data_entry = match id { + 0 => ListData::Snd(EnumSnd::Bgm( + reader.read_struct_vec::(count, false, encoding)?, + )), + 1 => ListData::Snd(EnumSnd::Amb( + reader.read_struct_vec::(count, false, encoding)?, + )), + 2 => ListData::Snd(EnumSnd::Se( + reader.read_struct_vec::(count, false, encoding)?, + )), + 3 => ListData::Snd(EnumSnd::Sfx( + reader.read_struct_vec::(count, false, encoding)?, + )), + 9999 => { + // Special case for unknown enum sound ID + ListData::Unknown(unk.clone()) + } + _ => return Err(anyhow::anyhow!("Unknown enum sound ID: {}", id)), + }; + ent.data = data_entry; + } + } } } Ok(()) @@ -238,10 +341,151 @@ enum EnumScr { Scenes(Vec), } +#[derive(Debug, Serialize, Deserialize, StructPack, StructUnpack)] +struct BgT { + /// Background image name + #[fstring = 32] + name: String, + /// Background image file name + #[fstring = 64] + file: String, + #[fstring = 128] + option: String, + coverd: u32, + color: u32, + id: u32, + loc: u32, + order: i32, + link: u32, +} + +#[derive(Debug, Serialize, Deserialize, StructPack, StructUnpack)] +struct EvT { + /// Event image name + #[fstring = 32] + name: String, + /// Event image file name + #[fstring = 64] + file: String, + #[fstring = 128] + option: String, + coverd: u32, + color: u32, + id: u32, + loc: u32, + order: i32, + link: u32, +} + +#[derive(Debug, Serialize, Deserialize, StructPack, StructUnpack)] +struct StT { + #[fstring = 32] + name: String, + #[fstring = 64] + file: String, + #[fstring = 128] + option: String, + coverd: u32, + color: u32, + id: u32, + loc: u32, + order: i32, + link: u32, +} + +#[derive(Debug, Serialize, Deserialize, StructPack, StructUnpack)] +struct EfxT { + /// Effect image name + #[fstring = 32] + name: String, + /// Effect image file name + #[fstring = 64] + file: String, + spot: i32, + dx: i32, + dy: i32, + r#loop: bool, + #[fvec = 3] + #[serde(skip, default = "exft_padding")] + padding: Vec, +} + +fn exft_padding() -> Vec { + vec![0; 3] +} + +#[derive(Debug, Serialize, Deserialize, StructPack, StructUnpack)] +struct Point { + x: i16, + y: i16, +} + +#[derive(Debug, Serialize, Deserialize, StructPack, StructUnpack)] +struct LocT { + #[fvec = 8] + pt: Vec, +} + +#[derive(Debug, Serialize, Deserialize, StructPack)] +#[serde(tag = "type", content = "data")] +enum EnumGfx { + Bgs(Vec), + Evs(Vec), + Sts(Vec), + Efxs(Vec), + Locs(Vec), +} + +#[derive(Debug, Serialize, Deserialize, StructPack, StructUnpack)] +struct BgmT { + #[fstring = 64] + pub name: String, + #[fstring = 64] + pub file: String, + #[fstring = 64] + pub title: String, + pub order: i32, +} + +#[derive(Debug, Serialize, Deserialize, StructPack, StructUnpack)] +struct AmbT { + #[fstring = 64] + pub name: String, + #[fstring = 64] + pub file: String, +} + +#[derive(Debug, Serialize, Deserialize, StructPack, StructUnpack)] +struct SeT { + #[fstring = 64] + pub name: String, + #[fstring = 64] + pub file: String, +} + +#[derive(Debug, Serialize, Deserialize, StructPack, StructUnpack)] +struct SfxT { + #[fstring = 64] + pub name: String, + #[fstring = 64] + pub file: String, +} + +#[derive(Debug, Serialize, Deserialize, StructPack)] +#[serde(tag = "type", content = "data")] +enum EnumSnd { + Bgm(Vec), + Amb(Vec), + Se(Vec), + Sfx(Vec), +} + #[derive(Debug, Serialize, Deserialize, StructPack)] #[serde(tag = "type", content = "data")] enum ListData { Scr(EnumScr), + Gfx(EnumGfx), + Snd(EnumSnd), Unknown(Vec), } diff --git a/src/utils/struct_pack.rs b/src/utils/struct_pack.rs index 2718ed6..2e1d0c4 100644 --- a/src/utils/struct_pack.rs +++ b/src/utils/struct_pack.rs @@ -32,3 +32,18 @@ struct_unpack_impl_for_num!(i64); struct_unpack_impl_for_num!(i128); struct_unpack_impl_for_num!(f32); struct_unpack_impl_for_num!(f64); + +impl StructUnpack for bool { + fn unpack(mut reader: R, _big: bool, _encoding: Encoding) -> Result { + let mut buf = [0u8; 1]; + reader.read_exact(&mut buf)?; + Ok(buf[0] != 0) + } +} + +impl StructPack for bool { + fn pack(&self, writer: &mut W, _big: bool, _encoding: Encoding) -> Result<()> { + writer.write_all(&[if *self { 1 } else { 0 }])?; + Ok(()) + } +}