mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-06-06 12:58:45 +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.
|
||||
/// * `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 {
|
||||
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<usize> = None;
|
||||
let mut fixed_vec: Option<usize> = 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<usize> = None;
|
||||
let mut fixed_vec: Option<usize> = 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 = <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.
|
||||
#[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 {
|
||||
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<usize> = None;
|
||||
let mut fstring_no_trim = false;
|
||||
let mut fixed_vec: Option<usize> = 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)?;
|
||||
|
||||
@@ -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)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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::<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(())
|
||||
@@ -238,10 +341,151 @@ enum EnumScr {
|
||||
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)]
|
||||
#[serde(tag = "type", content = "data")]
|
||||
enum ListData {
|
||||
Scr(EnumScr),
|
||||
Gfx(EnumGfx),
|
||||
Snd(EnumSnd),
|
||||
Unknown(Vec<u8>),
|
||||
}
|
||||
|
||||
|
||||
@@ -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<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