mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-07-08 01:31:53 +08:00
Add more fmt
This commit is contained in:
@@ -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.
|
/// * `skip_pack` attribute can be used to skip fields from packing.
|
||||||
/// * `fstring = <len>` attribute can be used to specify a fixed string length for String fields.
|
/// * `fstring = <len>` attribute can be used to specify a fixed string length for String fields.
|
||||||
#[proc_macro_derive(StructPack, attributes(skip_pack, fstring))]
|
/// * `fvec = <len>` 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 {
|
pub fn struct_pack_derive(input: TokenStream) -> TokenStream {
|
||||||
let a = syn::parse_macro_input!(input as PackStruct);
|
let a = syn::parse_macro_input!(input as PackStruct);
|
||||||
match a {
|
match a {
|
||||||
@@ -73,6 +74,7 @@ pub fn struct_pack_derive(input: TokenStream) -> TokenStream {
|
|||||||
let fields = sut.fields.iter().map(|field| {
|
let fields = sut.fields.iter().map(|field| {
|
||||||
let mut skipped = false;
|
let mut skipped = false;
|
||||||
let mut fixed_string: Option<usize> = None;
|
let mut fixed_string: Option<usize> = None;
|
||||||
|
let mut fixed_vec: Option<usize> = None;
|
||||||
for attr in &field.attrs {
|
for attr in &field.attrs {
|
||||||
let path = attr.path();
|
let path = attr.path();
|
||||||
if path.is_ident("skip_pack") {
|
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 {
|
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! {
|
quote::quote! {
|
||||||
self.#field_name.pack(writer, big, encoding)?;
|
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 fields: Vec<_> = variant.fields.iter().enumerate().map(|(idx, field)| {
|
||||||
let mut skipped = false;
|
let mut skipped = false;
|
||||||
let mut fixed_string: Option<usize> = None;
|
let mut fixed_string: Option<usize> = None;
|
||||||
|
let mut fixed_vec: Option<usize> = None;
|
||||||
for attr in &field.attrs {
|
for attr in &field.attrs {
|
||||||
let path = attr.path();
|
let path = attr.path();
|
||||||
if path.is_ident("skip_pack") {
|
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 {
|
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! {
|
quote::quote! {
|
||||||
#field_name.pack(writer, big, encoding)?;
|
#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.
|
/// * `skip_unpack` attribute can be used to skip fields from unpacking.
|
||||||
/// * `fstring = <len>` attribute can be used to specify a fixed string length for String fields.
|
/// * `fstring = <len>` 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.
|
/// * `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 = <len>` 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 {
|
pub fn struct_unpack_derive(input: TokenStream) -> TokenStream {
|
||||||
let sut = syn::parse_macro_input!(input as syn::ItemStruct);
|
let sut = syn::parse_macro_input!(input as syn::ItemStruct);
|
||||||
let name = sut.ident;
|
let name = sut.ident;
|
||||||
@@ -242,6 +290,7 @@ pub fn struct_unpack_derive(input: TokenStream) -> TokenStream {
|
|||||||
let mut skipped = false;
|
let mut skipped = false;
|
||||||
let mut fixed_string: Option<usize> = None;
|
let mut fixed_string: Option<usize> = None;
|
||||||
let mut fstring_no_trim = false;
|
let mut fstring_no_trim = false;
|
||||||
|
let mut fixed_vec: Option<usize> = None;
|
||||||
for attr in &field.attrs {
|
for attr in &field.attrs {
|
||||||
let path = attr.path();
|
let path = attr.path();
|
||||||
if path.is_ident("skip_unpack") {
|
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") {
|
} else if path.is_ident("fstring_no_trim") {
|
||||||
fstring_no_trim = true;
|
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 {
|
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! {
|
quote::quote! {
|
||||||
let #field_name = #field_type::unpack(&mut reader, big, encoding)?;
|
let #field_name = #field_type::unpack(&mut reader, big, encoding)?;
|
||||||
|
|||||||
@@ -531,7 +531,6 @@ pub fn export_script(
|
|||||||
}
|
}
|
||||||
types::OutputScriptType::Custom => {
|
types::OutputScriptType::Custom => {
|
||||||
let enc = get_output_encoding(arg);
|
let enc = get_output_encoding(arg);
|
||||||
println!("f: {}", f);
|
|
||||||
script.custom_export(f.as_ref(), enc)?;
|
script.custom_export(f.as_ref(), enc)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -148,6 +148,109 @@ impl EscudeBinList {
|
|||||||
ent.data = data_entry;
|
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::<BgT>(count, false, encoding)?,
|
||||||
|
)),
|
||||||
|
1 => ListData::Gfx(EnumGfx::Evs(
|
||||||
|
reader.read_struct_vec::<EvT>(count, false, encoding)?,
|
||||||
|
)),
|
||||||
|
2 => ListData::Gfx(EnumGfx::Sts(
|
||||||
|
reader.read_struct_vec::<StT>(count, false, encoding)?,
|
||||||
|
)),
|
||||||
|
3 => ListData::Gfx(EnumGfx::Efxs(
|
||||||
|
reader.read_struct_vec::<EfxT>(count, false, encoding)?,
|
||||||
|
)),
|
||||||
|
4 => ListData::Gfx(EnumGfx::Locs(
|
||||||
|
reader.read_struct_vec::<LocT>(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::<BgmT>(count, false, encoding)?,
|
||||||
|
)),
|
||||||
|
1 => ListData::Snd(EnumSnd::Amb(
|
||||||
|
reader.read_struct_vec::<AmbT>(count, false, encoding)?,
|
||||||
|
)),
|
||||||
|
2 => ListData::Snd(EnumSnd::Se(
|
||||||
|
reader.read_struct_vec::<SeT>(count, false, encoding)?,
|
||||||
|
)),
|
||||||
|
3 => ListData::Snd(EnumSnd::Sfx(
|
||||||
|
reader.read_struct_vec::<SfxT>(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(())
|
Ok(())
|
||||||
@@ -238,10 +341,151 @@ enum EnumScr {
|
|||||||
Scenes(Vec<SceneT>),
|
Scenes(Vec<SceneT>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exft_padding() -> Vec<u8> {
|
||||||
|
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<Point>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, StructPack)]
|
||||||
|
#[serde(tag = "type", content = "data")]
|
||||||
|
enum EnumGfx {
|
||||||
|
Bgs(Vec<BgT>),
|
||||||
|
Evs(Vec<EvT>),
|
||||||
|
Sts(Vec<StT>),
|
||||||
|
Efxs(Vec<EfxT>),
|
||||||
|
Locs(Vec<LocT>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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<BgmT>),
|
||||||
|
Amb(Vec<AmbT>),
|
||||||
|
Se(Vec<SeT>),
|
||||||
|
Sfx(Vec<SfxT>),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, StructPack)]
|
#[derive(Debug, Serialize, Deserialize, StructPack)]
|
||||||
#[serde(tag = "type", content = "data")]
|
#[serde(tag = "type", content = "data")]
|
||||||
enum ListData {
|
enum ListData {
|
||||||
Scr(EnumScr),
|
Scr(EnumScr),
|
||||||
|
Gfx(EnumGfx),
|
||||||
|
Snd(EnumSnd),
|
||||||
Unknown(Vec<u8>),
|
Unknown(Vec<u8>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,3 +32,18 @@ struct_unpack_impl_for_num!(i64);
|
|||||||
struct_unpack_impl_for_num!(i128);
|
struct_unpack_impl_for_num!(i128);
|
||||||
struct_unpack_impl_for_num!(f32);
|
struct_unpack_impl_for_num!(f32);
|
||||||
struct_unpack_impl_for_num!(f64);
|
struct_unpack_impl_for_num!(f64);
|
||||||
|
|
||||||
|
impl StructUnpack for bool {
|
||||||
|
fn unpack<R: Read + Seek>(mut reader: R, _big: bool, _encoding: Encoding) -> Result<Self> {
|
||||||
|
let mut buf = [0u8; 1];
|
||||||
|
reader.read_exact(&mut buf)?;
|
||||||
|
Ok(buf[0] != 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StructPack for bool {
|
||||||
|
fn pack<W: Write>(&self, writer: &mut W, _big: bool, _encoding: Encoding) -> Result<()> {
|
||||||
|
writer.write_all(&[if *self { 1 } else { 0 }])?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user