[Core] Make proc macros into declarative macros

This commit is contained in:
widberg 2025-04-19 00:32:37 -04:00
parent acc235163b
commit c25918d9b6
84 changed files with 525 additions and 811 deletions

View file

@ -32,3 +32,4 @@ panic = "abort"
[profile.dev]
opt-level = 3
debug = 0

View file

@ -1,308 +0,0 @@
use proc_macro2::TokenStream;
use quote::quote;
use syn::parse::{Parse, ParseStream};
use syn::spanned::Spanned;
use syn::{Arm, Attribute, Ident, Result, braced};
pub struct BffClassMacroInput {
class: Ident,
forms: Vec<Arm>,
has_generic: bool,
}
impl Parse for BffClassMacroInput {
fn parse(input: ParseStream) -> Result<Self> {
let attrs: Vec<Attribute> = input.call(Attribute::parse_inner)?;
let has_generic = !attrs
.iter()
.filter(|attr| attr.path().is_ident("generic"))
.collect::<Vec<_>>()
.is_empty();
let class = input.parse()?;
let content;
braced!(content in input);
let mut forms = Vec::new();
while !content.is_empty() {
forms.push(content.parse()?);
}
Ok(Self {
class,
forms,
has_generic,
})
}
}
pub fn derive_bff_class(input: BffClassMacroInput) -> TokenStream {
let enum_class = impl_enum_class(&input);
let from_object_to_shadow_class = impl_from_object_to_shadow_class(&input);
let from_shadow_class_to_object = impl_from_shadow_class_to_object(&input);
let from_shadow_class_to_generic = impl_from_shadow_class_to_generic(&input);
let try_your_best = impl_try_your_best(&input);
if input.has_generic {
quote! {
#enum_class
#from_object_to_shadow_class
#from_shadow_class_to_object
#from_shadow_class_to_generic
#try_your_best
}
} else {
quote! {
#enum_class
#from_object_to_shadow_class
#from_shadow_class_to_object
#try_your_best
}
}
}
fn impl_enum_class(input: &BffClassMacroInput) -> proc_macro2::TokenStream {
let class = &input.class;
let variants = input
.forms
.iter()
.map(|form| {
let body = &form.body;
quote! { #body(std::boxed::Box<#body>) }
})
.collect::<Vec<_>>();
let import_export = if input.forms.is_empty() {
quote! {
impl crate::traits::Export for #class {}
impl crate::traits::Import for #class {}
}
} else {
let arms_export = input
.forms
.iter()
.map(|form| {
let body = &form.body;
quote! { #class::#body(class) => <#body as crate::traits::Export>::export(class) }
})
.collect::<Vec<_>>();
let arms_import = input
.forms
.iter()
.map(|form| {
let body = &form.body;
quote! { #class::#body(class) => <#body as crate::traits::Import>::import(class, artifacts) }
})
.collect::<Vec<_>>();
quote! {
impl crate::traits::Export for #class {
fn export(&self) -> crate::BffResult<std::collections::HashMap<std::ffi::OsString, crate::traits::Artifact>> {
match self {
#(#arms_export,)*
}
}
}
impl crate::traits::Import for #class {
fn import(&mut self, artifacts: &std::collections::HashMap<std::ffi::OsString, crate::traits::Artifact>) -> crate::BffResult<()> {
match self {
#(#arms_import,)*
}
}
}
}
};
quote! {
#[derive(serde::Serialize, serde::Deserialize, Debug, bff_derive::NamedClass, derive_more::From, derive_more::IsVariant, bff_derive::ReferencedNames)]
pub enum #class {
#(#variants),*
}
#import_export
}
}
fn impl_try_your_best(input: &BffClassMacroInput) -> proc_macro2::TokenStream {
let class = &input.class;
let variants = input
.forms
.iter()
.map(|form| &form.body)
.collect::<Vec<_>>();
let report_struct = quote::format_ident!("{}TryYourBestReport", class);
quote! {
#[allow(non_snake_case)]
#[derive(Default, Clone, Copy, Debug)]
pub struct #report_struct {
pub total: usize,
#(#variants: usize),*
}
impl crate::traits::TryYourBest<&crate::bigfile::resource::Resource> for #class {
type Report = #report_struct;
fn update_report(resource: &crate::bigfile::resource::Resource, platform: crate::bigfile::platforms::Platform, report: &mut Self::Report) {
report.total += 1;
// TODO: Probably need a way to do this without specifying a version.
#(
report.#variants += <bool as Into<usize>>::into(<&crate::bigfile::resource::Resource as crate::traits::TryIntoVersionPlatform<#variants>>::try_into_version_platform(resource, crate::bigfile::versions::Version::Asobo(0, 0, 0, 0), platform).is_ok());
)*
}
}
impl std::fmt::Display for #report_struct {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "{}", stringify!(#class))?;
writeln!(f, "Total: {}", self.total)?;
#(
writeln!(f, "{}: {}", stringify!(#variants), self.#variants)?;
)*
Ok(())
}
}
}
}
fn impl_from_object_to_shadow_class(input: &BffClassMacroInput) -> proc_macro2::TokenStream {
let class = &input.class;
let arms = input.forms.iter().map(|form| {
let attrs = &form.attrs;
let pat = &form.pat;
let guard = match &form.guard {
Some((_, guard)) => quote! { #guard },
None => quote! {},
};
let body = &form.body;
quote! {
#(#attrs)*
#pat #guard => {
let shadow_class: #body = <&crate::bigfile::resource::Resource as crate::traits::TryIntoVersionPlatform<#body>>::try_into_version_platform(object, version, platform)?;
Ok(std::boxed::Box::new(shadow_class).into())
}
}
}).collect::<Vec<_>>();
let body = if arms.is_empty() {
quote! {
todo!()
}
} else {
quote! {
use crate::bigfile::versions::Version::*;
use crate::bigfile::platforms::Platform::*;
match (version.clone(), platform) {
#(#arms)*
_ => Err(
// TODO: Pick the right name based on the algorithm and suffix for the current BigFile
crate::error::UnimplementedClassError::new(object.name, <Self as crate::traits::NamedClass<crate::names::NameAsobo32>>::NAME.into(), version, platform).into(),
),
}
}
};
quote! {
impl crate::traits::TryFromVersionPlatform<&crate::bigfile::resource::Resource> for #class {
type Error = crate::error::Error;
fn try_from_version_platform(
object: &crate::bigfile::resource::Resource,
version: crate::bigfile::versions::Version,
platform: crate::bigfile::platforms::Platform,
) -> crate::BffResult<#class> {
#body
}
}
}
}
fn impl_from_shadow_class_to_object(input: &BffClassMacroInput) -> proc_macro2::TokenStream {
let class = &input.class;
let arms = input.forms.iter().map(|form| {
let attrs = &form.attrs;
let body = &form.body;
quote! {
#(#attrs)*
#class::#body(class) => {
let object: crate::bigfile::resource::Resource = <&#body as crate::traits::TryIntoVersionPlatform<crate::bigfile::resource::Resource>>::try_into_version_platform(class, version, platform)?;
Ok(object)
}
}
}).collect::<Vec<_>>();
let body = if arms.is_empty() {
quote! {
todo!()
}
} else {
quote! {
use crate::bigfile::versions::Version::*;
use crate::bigfile::platforms::Platform::*;
match class {
#(#arms)*
}
}
};
quote! {
impl crate::traits::TryFromVersionPlatform<&#class> for crate::bigfile::resource::Resource {
type Error = crate::error::Error;
fn try_from_version_platform(
class: &#class,
version: crate::bigfile::versions::Version,
platform: crate::bigfile::platforms::Platform,
) -> crate::BffResult<crate::bigfile::resource::Resource> {
#body
}
}
}
}
fn impl_from_shadow_class_to_generic(input: &BffClassMacroInput) -> proc_macro2::TokenStream {
let class = &input.class;
let generic_class_str = format!("{}Generic", class);
let generic_class = Ident::new(&generic_class_str, generic_class_str.span());
let arms = input
.forms
.iter()
.map(|form| {
let attrs = &form.attrs;
let body = &form.body;
quote! {
#(#attrs)*
#class::#body(class) => {
(*class).into()
}
}
})
.collect::<Vec<_>>();
let body = if arms.is_empty() {
quote! {
todo!()
}
} else {
quote! {
match class {
#(#arms)*
}
}
};
quote! {
impl From<#class> for generic::#generic_class {
fn from(
class: #class,
) -> generic::#generic_class {
#body
}
}
}
}

View file

@ -1,364 +0,0 @@
use proc_macro2::TokenStream;
use quote::quote;
use syn::parse::{Parse, ParseStream};
use syn::{Arm, Result};
pub struct BffBigFileMacroInput {
forms: Vec<Arm>,
}
impl Parse for BffBigFileMacroInput {
fn parse(input: ParseStream) -> Result<Self> {
let mut forms = Vec::new();
while !input.is_empty() {
forms.push(input.parse()?);
}
Ok(Self { forms })
}
}
pub fn derive_bigfiles(input: BffBigFileMacroInput) -> TokenStream {
let try_your_best_bigfile = impl_try_your_best_bigfile(&input);
let read_bigfile = impl_read_bigfile(&input);
let write_bigfile = impl_write_bigfile(&input);
let (dump_resource, dump_resource_resource) = impl_dump_resource(&input);
let (read_resource, read_resource_resource) = impl_read_resource(&input);
let version_into_name_type = impl_version_into_name_type(&input);
quote! {
impl BigFile {
#read_bigfile
#write_bigfile
#dump_resource
#read_resource
}
#try_your_best_bigfile
impl crate::bigfile::resource::Resource {
#dump_resource_resource
#read_resource_resource
}
#version_into_name_type
}
}
fn impl_try_your_best_bigfile(input: &BffBigFileMacroInput) -> proc_macro2::TokenStream {
let variants = input
.forms
.iter()
.map(|form| &form.body)
.collect::<Vec<_>>();
quote! {
#[allow(non_snake_case)]
#[derive(Default, Clone, Copy, Debug)]
pub struct BigFileTryYourBestReport {
pub total: usize,
#(#variants: usize),*
}
impl<R: std::io::Read + std::io::Seek> crate::traits::TryYourBest<&mut R> for BigFile {
type Report = BigFileTryYourBestReport;
fn update_report(reader: &mut R, platform: crate::bigfile::platforms::Platform, report: &mut Self::Report) {
use crate::traits::BigFileIo;
report.total += 1;
// TODO: Probably need a way to do this without specifying a version.
#(
reader.seek(std::io::SeekFrom::Start(256)).unwrap();
report.#variants += {crate::names::names().lock().unwrap().name_type = <#variants as BigFileIo>::NAME_TYPE;
<bool as Into<usize>>::into(<#variants as BigFileIo>::read(reader, crate::bigfile::versions::Version::Asobo(0, 0, 0, 0), platform).is_ok())};
)*
reader.rewind().unwrap();
}
}
impl std::fmt::Display for BigFileTryYourBestReport {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "BigFile")?;
writeln!(f, "Total: {}", self.total)?;
#(
writeln!(f, "{}: {}", stringify!(#variants), self.#variants)?;
)*
Ok(())
}
}
}
}
fn impl_read_bigfile(input: &BffBigFileMacroInput) -> proc_macro2::TokenStream {
let arms = input
.forms
.iter()
.map(|form| {
let attrs = &form.attrs;
let pat = &form.pat;
let guard = match &form.guard {
Some((_, guard)) => quote! { #guard },
None => quote! {},
};
let body = &form.body;
quote! {
#(#attrs)*
#pat #guard => {
crate::names::names().lock().unwrap().name_type = <#body as BigFileIo>::NAME_TYPE;
<#body as BigFileIo>::read(reader, version, platform)
}
}
})
.collect::<Vec<_>>();
quote! {
pub fn read_platform<R: std::io::Read + std::io::Seek>(reader: &mut R, platform: crate::bigfile::platforms::Platform, version_override: &Option<crate::bigfile::versions::Version>) -> crate::BffResult<Self> {
use crate::bigfile::versions::Version::*;
use crate::bigfile::platforms::Platform::*;
use binrw::BinRead;
use crate::traits::BigFileIo;
let endian: crate::Endian = platform.into();
let version: crate::bigfile::versions::Version = crate::helpers::FixedStringNull::<256>::read_be(reader)?.as_str().into();
let version = version_override.clone().unwrap_or(version);
match (&version, platform) {
#(#arms)*
_ => Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into()),
}
}
}
}
fn impl_write_bigfile(input: &BffBigFileMacroInput) -> proc_macro2::TokenStream {
let arms = input
.forms
.iter()
.map(|form| {
let attrs = &form.attrs;
let pat = &form.pat;
let guard = match &form.guard {
Some((_, guard)) => quote! { #guard },
None => quote! {},
};
let body = &form.body;
quote! {
#(#attrs)*
#pat #guard => {
crate::names::names().lock().unwrap().name_type = <#body as BigFileIo>::NAME_TYPE;
<#body as BigFileIo>::write(self, writer, tag)
}
}
})
.collect::<Vec<_>>();
quote! {
pub fn write<W: std::io::Write + std::io::Seek>(&self, writer: &mut W, platform_override: Option<crate::bigfile::platforms::Platform>, version_override: &Option<crate::bigfile::versions::Version>, tag: Option<&str>) -> crate::BffResult<()> {
use crate::bigfile::versions::Version::*;
use crate::bigfile::platforms::Platform::*;
use binrw::BinWrite;
use crate::traits::BigFileIo;
let platform = platform_override.unwrap_or(self.manifest.platform);
let endian: crate::Endian = platform.into();
let version = &self.manifest.version;
let version = version_override.as_ref().unwrap_or(version);
let version_string = version.to_string();
crate::helpers::FixedStringNull::<256>::write_be(&version_string.into(), writer)?;
match (version.clone(), platform) {
#(#arms)*
(version, platform) => Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into()),
}
}
}
}
fn impl_dump_resource(
input: &BffBigFileMacroInput,
) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
let arms = input
.forms
.iter()
.map(|form| {
let attrs = &form.attrs;
let pat = &form.pat;
let guard = match &form.guard {
Some((_, guard)) => quote! { #guard },
None => quote! {},
};
let body = &form.body;
quote! {
#(#attrs)*
#pat #guard => {
crate::names::names().lock().unwrap().name_type = <#body as BigFileIo>::NAME_TYPE;
Ok(<#body as BigFileIo>::ResourceType::dump_resource(resource, writer, endian)?)
}
}
})
.collect::<Vec<_>>();
(
quote! {
pub fn dump_resource<W: std::io::Write + std::io::Seek>(&self, resource: &crate::bigfile::resource::Resource, writer: &mut W) -> crate::BffResult<()> {
use crate::bigfile::versions::Version::*;
use crate::bigfile::platforms::Platform::*;
use crate::traits::BigFileIo;
let platform = self.manifest.platform;
let endian: crate::Endian = platform.into();
let version = &self.manifest.version;
match (version.clone(), platform) {
#(#arms)*
(version, platform) => Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into()),
}
}
pub fn dump_bff_resource<W: std::io::Write + std::io::Seek>(&self, resource: &crate::bigfile::resource::Resource, writer: &mut W) -> crate::BffResult<()> {
let platform = self.manifest.platform;
let version = &self.manifest.version;
crate::bigfile::resource::Resource::dump_bff_resource(resource, writer, platform, version)
}
},
quote! {
pub fn dump_resource<W: std::io::Write + std::io::Seek>(&self, writer: &mut W, platform: crate::bigfile::platforms::Platform, version: &crate::bigfile::versions::Version) -> crate::BffResult<()> {
use crate::bigfile::versions::Version::*;
use crate::bigfile::platforms::Platform::*;
use crate::traits::BigFileIo;
let endian: crate::Endian = platform.into();
let resource = self;
match (version.clone(), platform) {
#(#arms)*
(version, platform) => Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into()),
}
}
pub fn dump_bff_resource<W: std::io::Write + std::io::Seek>(&self, writer: &mut W, platform: crate::bigfile::platforms::Platform, version: &crate::bigfile::versions::Version) -> crate::BffResult<()> {
use crate::bigfile::versions::Version::*;
use crate::bigfile::platforms::Platform::*;
use crate::traits::BigFileIo;
let endian: crate::Endian = platform.into();
<crate::bigfile::resource::BffResourceHeader as binrw::BinWrite>::write(&crate::bigfile::resource::BffResourceHeader {
platform,
version: version.clone(),
}, writer)?;
let resource = self;
match (version.clone(), platform) {
#(#arms)*
(version, platform) => Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into()),
}
}
},
)
}
fn impl_read_resource(
input: &BffBigFileMacroInput,
) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
let arms = input
.forms
.iter()
.map(|form| {
let attrs = &form.attrs;
let pat = &form.pat;
let guard = match &form.guard {
Some((_, guard)) => quote! { #guard },
None => quote! {},
};
let body = &form.body;
quote! {
#(#attrs)*
#pat #guard => {
crate::names::names().lock().unwrap().name_type = <#body as BigFileIo>::NAME_TYPE;
Ok(<#body as BigFileIo>::ResourceType::read_resource(reader, endian)?)
}
}
})
.collect::<Vec<_>>();
(
quote! {
pub fn read_resource<R: std::io::Read + std::io::Seek>(&self, reader: &mut R) -> crate::BffResult<crate::bigfile::resource::Resource> {
use crate::bigfile::versions::Version::*;
use crate::bigfile::platforms::Platform::*;
use crate::traits::BigFileIo;
let platform = self.manifest.platform;
let endian: crate::Endian = platform.into();
let version = &self.manifest.version;
match (version.clone(), platform) {
#(#arms)*
(version, platform) => Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into()),
}
}
pub fn read_bff_resource<R: std::io::Read + std::io::Seek>(&self, reader: &mut R) -> crate::BffResult<crate::bigfile::resource::Resource> {
use crate::bigfile::versions::Version::*;
use crate::bigfile::platforms::Platform::*;
use crate::traits::BigFileIo;
let crate::bigfile::resource::BffResourceHeader {
platform,
version,
} = <crate::bigfile::resource::BffResourceHeader as binrw::BinRead>::read(reader)?;
let endian: crate::Endian = platform.into();
match (version.clone(), platform) {
#(#arms)*
(version, platform) => Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into()),
}
}
},
quote! {
pub fn read_resource<R: std::io::Read + std::io::Seek>(reader: &mut R, platform: crate::bigfile::platforms::Platform, version: &crate::bigfile::versions::Version) -> crate::BffResult<crate::bigfile::resource::Resource> {
use crate::bigfile::versions::Version::*;
use crate::bigfile::platforms::Platform::*;
use crate::traits::BigFileIo;
let endian: crate::Endian = platform.into();
match (version.clone(), platform) {
#(#arms)*
(version, platform) => Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into()),
}
}
pub fn read_bff_resource<R: std::io::Read + std::io::Seek>(reader: &mut R) -> crate::BffResult<crate::bigfile::resource::Resource> {
use crate::bigfile::versions::Version::*;
use crate::bigfile::platforms::Platform::*;
use crate::traits::BigFileIo;
let crate::bigfile::resource::BffResourceHeader {
platform,
version,
} = <crate::bigfile::resource::BffResourceHeader as binrw::BinRead>::read(reader)?;
let endian: crate::Endian = platform.into();
match (version.clone(), platform) {
#(#arms)*
(version, platform) => Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into()),
}
}
},
)
}
fn impl_version_into_name_type(input: &BffBigFileMacroInput) -> proc_macro2::TokenStream {
let arms = input
.forms
.iter()
.map(|form| {
let attrs = &form.attrs;
let pat = &form.pat;
let guard = match &form.guard {
Some((_, guard)) => quote! { #guard },
None => quote! {},
};
let body = &form.body;
quote! {
#(#attrs)*
#pat #guard => Ok(<#body as BigFileIo>::NAME_TYPE),
}
})
.collect::<Vec<_>>();
quote! {
impl TryFrom<&crate::bigfile::versions::Version> for crate::names::NameType {
type Error = crate::BffError;
fn try_from(version: &crate::bigfile::versions::Version) -> Result<crate::names::NameType, Self::Error> {
use crate::bigfile::versions::Version::*;
use crate::bigfile::platforms::Platform::*;
use crate::traits::BigFileIo;
match (version.clone(), PC) {
#(#arms)*
(version, platform) => Err(crate::error::UnimplementedVersionError::new(version).into()),
}
}
}
}
}

View file

@ -1,40 +1,19 @@
use proc_macro::TokenStream;
use syn::{DeriveInput, parse_macro_input};
use crate::bff_class::{BffClassMacroInput, derive_bff_class};
use crate::bigfiles::{BffBigFileMacroInput, derive_bigfiles};
use crate::generic_class::derive_generic_class;
use crate::named_class::derive_named_class;
use crate::referenced_names::derive_referenced_names;
use crate::trivial_class::{TrivialClassMacroInput, derive_trivial_class};
mod bff_class;
mod bigfiles;
mod generic_class;
mod named_class;
mod referenced_names;
mod trivial_class;
#[proc_macro_derive(NamedClass)]
pub fn named_class(input: TokenStream) -> TokenStream {
derive_named_class(parse_macro_input!(input as DeriveInput)).into()
}
#[proc_macro_derive(GenericClass, attributes(generic))]
pub fn generic_class(input: TokenStream) -> TokenStream {
derive_generic_class(parse_macro_input!(input as DeriveInput)).into()
}
#[proc_macro]
pub fn bff_class(input: TokenStream) -> TokenStream {
derive_bff_class(parse_macro_input!(input as BffClassMacroInput)).into()
}
#[proc_macro]
pub fn bigfiles(input: TokenStream) -> TokenStream {
derive_bigfiles(parse_macro_input!(input as BffBigFileMacroInput)).into()
}
#[proc_macro]
pub fn trivial_class(input: TokenStream) -> TokenStream {
derive_trivial_class(parse_macro_input!(input as TrivialClassMacroInput)).into()

View file

@ -1,42 +0,0 @@
use proc_macro2::TokenStream;
use quote::quote;
use syn::{DeriveInput, LitStr};
pub fn derive_named_class(input: DeriveInput) -> TokenStream {
let name = &input.ident;
let class_name = LitStr::new(format!("{}_Z", name).as_str(), name.span());
let class_name_legacy = LitStr::new(&name.to_string().to_uppercase(), name.span());
// This mess can go away once https://github.com/rust-lang/rust/issues/76001 is stabilized
quote! {
impl crate::traits::NamedClass<crate::names::NameAsobo32> for #name {
const NAME: crate::names::NameAsobo32 = crate::names::NameAsobo32::new(crate::crc::asobo32(#class_name.as_bytes()));
const NAME_LEGACY: crate::names::NameAsobo32 = crate::names::NameAsobo32::new(crate::crc::asobo32(#class_name_legacy.as_bytes()));
}
impl crate::traits::NamedClass<crate::names::NameAsoboAlternate32> for #name {
const NAME: crate::names::NameAsoboAlternate32 = crate::names::NameAsoboAlternate32::new(crate::crc::asobo_alternate32(#class_name.as_bytes()));
const NAME_LEGACY: crate::names::NameAsoboAlternate32 = crate::names::NameAsoboAlternate32::new(crate::crc::asobo_alternate32(#class_name_legacy.as_bytes()));
}
impl crate::traits::NamedClass<crate::names::NameKalisto32> for #name {
const NAME: crate::names::NameKalisto32 = crate::names::NameKalisto32::new(crate::crc::kalisto32(#class_name.as_bytes()));
const NAME_LEGACY: crate::names::NameKalisto32 = crate::names::NameKalisto32::new(crate::crc::kalisto32(#class_name_legacy.as_bytes()));
}
impl crate::traits::NamedClass<crate::names::NameBlackSheep32> for #name {
const NAME: crate::names::NameBlackSheep32 = crate::names::NameBlackSheep32::new(crate::crc::blacksheep32(#class_name.as_bytes()));
const NAME_LEGACY: crate::names::NameBlackSheep32 = crate::names::NameBlackSheep32::new(crate::crc::blacksheep32(#class_name_legacy.as_bytes()));
}
impl crate::traits::NamedClass<crate::names::NameAsobo64> for #name {
const NAME: crate::names::NameAsobo64 = crate::names::NameAsobo64::new(crate::crc::asobo64(#class_name.as_bytes()));
const NAME_LEGACY: crate::names::NameAsobo64 = crate::names::NameAsobo64::new(crate::crc::asobo64(#class_name_legacy.as_bytes()));
}
impl crate::traits::NamedClass<&'static str> for #name {
const NAME: &'static str = #class_name;
const NAME_LEGACY: &'static str = #class_name_legacy;
}
}
}

View file

@ -15,7 +15,6 @@ pub mod versions;
use std::collections::HashMap;
use bff_derive::bigfiles;
use petgraph::Graph;
use serde::Serialize;
@ -36,6 +35,7 @@ use crate::bigfile::v2_128_52_19_pc::BigFileV2_128_52_19PC;
use crate::bigfile::v2_128_92_19_pc::BigFileV2_128_92_19PC;
use crate::bigfile::v2_256_38_19_pc::BigFileV2_256_38_19PC;
use crate::class::Class;
use crate::macros::bigfiles::bigfiles;
use crate::names::Name;
use crate::traits::{ReferencedNames, TryIntoVersionPlatform};

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(AnimFrame {});

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
pub mod generic;
mod v1_291_03_06_pc;

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(AnimationGraph {});

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(AnimationGraphOverride {});

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(AreaLight {});

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_381_67_09_pc;

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
pub mod generic;
mod v1_06_63_02_pc;

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_381_67_09_pc;
use v1_381_67_09_pc::CameraV1_381_67_09PC;

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_06_63_02_pc;
use v1_06_63_02_pc::CameraZoneV1_06_63_02PC;

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_291_03_06_pc;
mod v1_381_67_09_pc;

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(CollisionVolData {});

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(Conductor {});

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(Decal {});

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(DialogEvent {});

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(Entity {});

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(Flare {});

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(FlareData {});

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(FogVolume {});

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_381_67_09_pc;

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(FxParticles {});

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(FxParticlesData {});

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_291_03_06_pc;
mod v1_381_67_09_pc;

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_381_67_09_pc;
use v1_381_67_09_pc::GenWorldV1_381_67_09PC;

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(Graph {});

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_381_67_09_pc;
use v1_381_67_09_pc::GwRoadV1_381_67_09PC;

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(HFog {});

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(HFogData {});

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(HullSplineZone {});

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
pub mod generic;
mod v1_291_03_06_pc;

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_06_63_02_pc;
mod v1_291_03_06_pc;

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(LightProbeVolume {});

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_06_63_02_pc;
mod v1_291_03_06_pc;

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_06_63_02_pc;
mod v1_291_03_06_pc;

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(MassInstancingVolume {});

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_06_63_02_pc;
mod v1_291_03_06_pc;

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_381_67_09_pc;

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(MaterialCollect {});

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_381_67_09_pc;

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
pub mod generic;
pub mod v1_06_63_02_pc;

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_06_63_02_pc;
mod v1_291_03_06_pc;

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(NetBingObj {});

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
// mod v1_06_63_02_pc;
mod v1_291_03_06_pc;

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(Occluder {});

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_381_67_09_pc;

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(OmniData {});

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(Override {});

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_381_67_09_pc;

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_381_67_09_pc;

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(Prefab {});

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(PrefabRef {});

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(ReflectionProbe {});

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
// mod v1_06_63_02_pc;
mod v1_291_03_06_pc;

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_381_67_09_pc;

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_381_67_09_pc;

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(Shader {});

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_06_63_02_pc;
mod v1_291_03_06_pc;

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
pub mod v1_291_03_06_pc;
pub mod v1_381_67_09_pc;

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(SkinData {});

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
pub mod generic;
mod v1_291_03_06_pc;

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(SoundEvent {});

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(SpecialEffectNode {});

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_06_63_02_pc;
mod v1_381_67_09_pc;

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_381_67_09_pc;

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(SplineZone {});

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
// mod v1_06_63_02_pc;
mod v1_291_03_06_pc;

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_381_67_09_pc;

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(Terrain {});

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(Texture {});

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(Txt {});

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod generic;
mod v1_291_03_06_pc;

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(UserDefineScript {});

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_06_63_02_pc;
use v1_06_63_02_pc::WarpV1_06_63_02PC;

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_06_63_02_pc;
mod v1_291_03_06_pc;

View file

@ -1,4 +1,4 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
mod v1_381_67_09_pc;

View file

@ -1,3 +1,3 @@
use bff_derive::bff_class;
use crate::macros::bff_class::bff_class;
bff_class!(XRefNode {});

228
bff/src/macros/bff_class.rs Normal file
View file

@ -0,0 +1,228 @@
macro_rules! named_class {
($class:ident) => {
// This mess can go away once https://github.com/rust-lang/rust/issues/76001 is stabilized
pastey::paste! {
impl crate::traits::NamedClass<crate::names::NameAsobo32> for $class {
const NAME: crate::names::NameAsobo32 = crate::names::NameAsobo32::new(crate::crc::asobo32(stringify!([<$class _Z>]).as_bytes()));
const NAME_LEGACY: crate::names::NameAsobo32 = crate::names::NameAsobo32::new(crate::crc::asobo32(stringify!([<$class:upper>]).as_bytes()));
}
impl crate::traits::NamedClass<crate::names::NameAsoboAlternate32> for $class {
const NAME: crate::names::NameAsoboAlternate32 = crate::names::NameAsoboAlternate32::new(crate::crc::asobo_alternate32(stringify!([<$class _Z>]).as_bytes()));
const NAME_LEGACY: crate::names::NameAsoboAlternate32 = crate::names::NameAsoboAlternate32::new(crate::crc::asobo_alternate32(stringify!([<$class:upper>]).as_bytes()));
}
impl crate::traits::NamedClass<crate::names::NameKalisto32> for $class {
const NAME: crate::names::NameKalisto32 = crate::names::NameKalisto32::new(crate::crc::kalisto32(stringify!([<$class _Z>]).as_bytes()));
const NAME_LEGACY: crate::names::NameKalisto32 = crate::names::NameKalisto32::new(crate::crc::kalisto32(stringify!([<$class:upper>]).as_bytes()));
}
impl crate::traits::NamedClass<crate::names::NameBlackSheep32> for $class {
const NAME: crate::names::NameBlackSheep32 = crate::names::NameBlackSheep32::new(crate::crc::blacksheep32(stringify!([<$class _Z>]).as_bytes()));
const NAME_LEGACY: crate::names::NameBlackSheep32 = crate::names::NameBlackSheep32::new(crate::crc::blacksheep32(stringify!([<$class:upper>]).as_bytes()));
}
impl crate::traits::NamedClass<crate::names::NameAsobo64> for $class {
const NAME: crate::names::NameAsobo64 = crate::names::NameAsobo64::new(crate::crc::asobo64(stringify!([<$class _Z>]).as_bytes()));
const NAME_LEGACY: crate::names::NameAsobo64 = crate::names::NameAsobo64::new(crate::crc::asobo64(stringify!([<$class:upper>]).as_bytes()));
}
impl crate::traits::NamedClass<&'static str> for $class {
const NAME: &'static str = stringify!([<$class _Z>]);
const NAME_LEGACY: &'static str = stringify!([<$class:upper>]);
}
}
};
}
pub(crate) use named_class;
macro_rules! bff_class {
($class:ident {}) => {
#[derive(serde::Serialize, serde::Deserialize, Debug, derive_more::From, derive_more::IsVariant, bff_derive::ReferencedNames)]
pub enum $class {}
crate::macros::bff_class::named_class! { $class }
impl crate::traits::Export for $class {}
impl crate::traits::Import for $class {}
impl crate::traits::TryFromVersionPlatform<&crate::bigfile::resource::Resource> for $class {
type Error = crate::error::Error;
fn try_from_version_platform(
_object: &crate::bigfile::resource::Resource,
_version: crate::bigfile::versions::Version,
_platform: crate::bigfile::platforms::Platform,
) -> crate::BffResult<$class> {
todo!()
}
}
impl crate::traits::TryFromVersionPlatform<&$class> for crate::bigfile::resource::Resource {
type Error = crate::error::Error;
fn try_from_version_platform(
_class: &$class,
_version: crate::bigfile::versions::Version,
_platform: crate::bigfile::platforms::Platform,
) -> crate::BffResult<crate::bigfile::resource::Resource> {
todo!()
}
}
pastey::paste! {
#[allow(non_snake_case)]
#[derive(Default, Clone, Copy, Debug)]
pub struct [<$class TryYourBestReport>] {
pub total: usize,
}
impl crate::traits::TryYourBest<&crate::bigfile::resource::Resource> for $class {
type Report = [<$class TryYourBestReport>];
fn update_report(_resource: &crate::bigfile::resource::Resource, _platform: crate::bigfile::platforms::Platform, report: &mut Self::Report) {
report.total += 1;
}
}
impl std::fmt::Display for [<$class TryYourBestReport>] {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "{}", stringify!($class))?;
writeln!(f, "Total: {}", self.total)?;
Ok(())
}
}
}
};
($class:ident { $($pattern:pat => $variant:ident),* $(,)? }) => {
#[derive(serde::Serialize, serde::Deserialize, Debug, derive_more::From, derive_more::IsVariant, bff_derive::ReferencedNames)]
pub enum $class {
$($variant(std::boxed::Box<$variant>)),*
}
crate::macros::bff_class::named_class! { $class }
impl crate::traits::Export for $class {
fn export(&self) -> crate::BffResult<std::collections::HashMap<std::ffi::OsString, crate::traits::Artifact>> {
match self {
$($class::$variant(class) => <$variant as crate::traits::Export>::export(class),)*
}
}
}
impl crate::traits::Import for $class {
fn import(&mut self, artifacts: &std::collections::HashMap<std::ffi::OsString, crate::traits::Artifact>) -> crate::BffResult<()> {
match self {
$($class::$variant(class) => <$variant as crate::traits::Import>::import(class, artifacts),)*
}
}
}
impl crate::traits::TryFromVersionPlatform<&crate::bigfile::resource::Resource> for $class {
type Error = crate::error::Error;
#[allow(unused_imports)]
fn try_from_version_platform(
object: &crate::bigfile::resource::Resource,
version: crate::bigfile::versions::Version,
platform: crate::bigfile::platforms::Platform,
) -> crate::BffResult<$class> {
use crate::bigfile::versions::Version::*;
use crate::bigfile::platforms::Platform::*;
match (version.clone(), platform) {
$($pattern => {
let shadow_class: $variant = <&crate::bigfile::resource::Resource as crate::traits::TryIntoVersionPlatform<$variant>>::try_into_version_platform(object, version, platform)?;
Ok(std::boxed::Box::new(shadow_class).into())
})*
_ => Err(
// TODO: Pick the right name based on the algorithm and suffix for the current BigFile
crate::error::UnimplementedClassError::new(object.name, <Self as crate::traits::NamedClass<crate::names::NameAsobo32>>::NAME.into(), version, platform).into(),
),
}
}
}
impl crate::traits::TryFromVersionPlatform<&$class> for crate::bigfile::resource::Resource {
type Error = crate::error::Error;
#[allow(unused_imports)]
fn try_from_version_platform(
class: &$class,
version: crate::bigfile::versions::Version,
platform: crate::bigfile::platforms::Platform,
) -> crate::BffResult<crate::bigfile::resource::Resource> {
use crate::bigfile::versions::Version::*;
use crate::bigfile::platforms::Platform::*;
match class {
$($class::$variant(class) => {
let object: crate::bigfile::resource::Resource = <&$variant as crate::traits::TryIntoVersionPlatform<crate::bigfile::resource::Resource>>::try_into_version_platform(class, version, platform)?;
Ok(object)
})*
}
}
}
pastey::paste! {
#[allow(non_snake_case)]
#[derive(Default, Clone, Copy, Debug)]
pub struct [<$class TryYourBestReport>] {
pub total: usize,
$($variant: usize),*
}
impl crate::traits::TryYourBest<&crate::bigfile::resource::Resource> for $class {
type Report = [<$class TryYourBestReport>];
fn update_report(resource: &crate::bigfile::resource::Resource, platform: crate::bigfile::platforms::Platform, report: &mut Self::Report) {
report.total += 1;
// TODO: Probably need a way to do this without specifying a version.
$(
report.$variant += <bool as Into<usize>>::into(<&crate::bigfile::resource::Resource as crate::traits::TryIntoVersionPlatform<$variant>>::try_into_version_platform(resource, crate::bigfile::versions::Version::Asobo(0, 0, 0, 0), platform).is_ok());
)*
}
}
impl std::fmt::Display for [<$class TryYourBestReport>] {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "{}", stringify!($class))?;
writeln!(f, "Total: {}", self.total)?;
$(
writeln!(f, "{}: {}", stringify!($variant), self.$variant)?;
)*
Ok(())
}
}
}
};
(#![generic] $class:ident {}) => {
bff_class! {$class {}}
pastey::paste! {
impl From<#class> for generic::[<$class Generic>] {
fn from(
class: $class,
) -> generic::[<$class Generic>] {
todo!()
}
}
}
};
(#![generic] $class:ident { $($pattern:pat => $variant:ident),* $(,)? }) => {
bff_class! {$class { $($pattern => $variant),* }}
pastey::paste! {
impl From<$class> for generic::[<$class Generic>] {
fn from(
class: $class,
) -> generic::[<$class Generic>] {
match class {
$($class::$variant(class) => {
(*class).into()
})*
}
}
}
}
};
}
pub(crate) use bff_class;

218
bff/src/macros/bigfiles.rs Normal file
View file

@ -0,0 +1,218 @@
macro_rules! bigfiles {
($($pattern:pat => $bigfile:ident),* $(,)?) => {
impl BigFile {
#[allow(unused_imports)]
pub fn read_platform<R: std::io::Read + std::io::Seek>(reader: &mut R, platform: crate::bigfile::platforms::Platform, version_override: &Option<crate::bigfile::versions::Version>) -> crate::BffResult<Self> {
use crate::bigfile::versions::Version::*;
use crate::bigfile::platforms::Platform::*;
use binrw::BinRead;
use crate::traits::BigFileIo;
let _endian: crate::Endian = platform.into();
let version: crate::bigfile::versions::Version = crate::helpers::FixedStringNull::<256>::read_be(reader)?.as_str().into();
let version = version_override.clone().unwrap_or(version);
match (&version, platform) {
$($pattern => {
crate::names::names().lock().unwrap().name_type = <$bigfile as BigFileIo>::NAME_TYPE;
<$bigfile as BigFileIo>::read(reader, version, platform)
})*
_ => Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into()),
}
}
#[allow(unused_imports)]
pub fn write<W: std::io::Write + std::io::Seek>(&self, writer: &mut W, platform_override: Option<crate::bigfile::platforms::Platform>, version_override: &Option<crate::bigfile::versions::Version>, tag: Option<&str>) -> crate::BffResult<()> {
use crate::bigfile::versions::Version::*;
use crate::bigfile::platforms::Platform::*;
use binrw::BinWrite;
use crate::traits::BigFileIo;
let platform = platform_override.unwrap_or(self.manifest.platform);
let _endian: crate::Endian = platform.into();
let version = &self.manifest.version;
let version = version_override.as_ref().unwrap_or(version);
let version_string = version.to_string();
crate::helpers::FixedStringNull::<256>::write_be(&version_string.into(), writer)?;
match (version.clone(), platform) {
$($pattern => {
crate::names::names().lock().unwrap().name_type = <$bigfile as BigFileIo>::NAME_TYPE;
<$bigfile as BigFileIo>::write(self, writer, tag)
})*
(version, platform) => Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into()),
}
}
#[allow(unused_imports)]
pub fn dump_resource<W: std::io::Write + std::io::Seek>(&self, resource: &crate::bigfile::resource::Resource, writer: &mut W) -> crate::BffResult<()> {
use crate::bigfile::versions::Version::*;
use crate::bigfile::platforms::Platform::*;
use crate::traits::BigFileIo;
let platform = self.manifest.platform;
let endian: crate::Endian = platform.into();
let version = &self.manifest.version;
match (version.clone(), platform) {
$($pattern => {crate::names::names().lock().unwrap().name_type = <$bigfile as BigFileIo>::NAME_TYPE;
Ok(<$bigfile as BigFileIo>::ResourceType::dump_resource(resource, writer, endian)?)})*
(version, platform) => Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into()),
}
}
pub fn dump_bff_resource<W: std::io::Write + std::io::Seek>(&self, resource: &crate::bigfile::resource::Resource, writer: &mut W) -> crate::BffResult<()> {
let platform = self.manifest.platform;
let version = &self.manifest.version;
crate::bigfile::resource::Resource::dump_bff_resource(resource, writer, platform, version)
}
#[allow(unused_imports)]
pub fn read_resource<R: std::io::Read + std::io::Seek>(&self, reader: &mut R) -> crate::BffResult<crate::bigfile::resource::Resource> {
use crate::bigfile::versions::Version::*;
use crate::bigfile::platforms::Platform::*;
use crate::traits::BigFileIo;
let platform = self.manifest.platform;
let endian: crate::Endian = platform.into();
let version = &self.manifest.version;
match (version.clone(), platform) {
$($pattern => {
crate::names::names().lock().unwrap().name_type = <$bigfile as BigFileIo>::NAME_TYPE;
Ok(<$bigfile as BigFileIo>::ResourceType::read_resource(reader, endian)?)
})*
(version, platform) => Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into()),
}
}
#[allow(unused_imports)]
pub fn read_bff_resource<R: std::io::Read + std::io::Seek>(&self, reader: &mut R) -> crate::BffResult<crate::bigfile::resource::Resource> {
use crate::bigfile::versions::Version::*;
use crate::bigfile::platforms::Platform::*;
use crate::traits::BigFileIo;
let crate::bigfile::resource::BffResourceHeader {
platform,
version,
} = <crate::bigfile::resource::BffResourceHeader as binrw::BinRead>::read(reader)?;
let endian: crate::Endian = platform.into();
match (version.clone(), platform) {
$($pattern => {
crate::names::names().lock().unwrap().name_type = <$bigfile as BigFileIo>::NAME_TYPE;
Ok(<$bigfile as BigFileIo>::ResourceType::read_resource(reader, endian)?)
})*
(version, platform) => Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into()),
}
}
}
#[allow(unused_imports)]
impl crate::bigfile::resource::Resource {
pub fn dump_resource<W: std::io::Write + std::io::Seek>(&self, writer: &mut W, platform: crate::bigfile::platforms::Platform, version: &crate::bigfile::versions::Version) -> crate::BffResult<()> {
use crate::bigfile::versions::Version::*;
use crate::bigfile::platforms::Platform::*;
use crate::traits::BigFileIo;
let endian: crate::Endian = platform.into();
let resource = self;
match (version.clone(), platform) {
$($pattern => {crate::names::names().lock().unwrap().name_type = <$bigfile as BigFileIo>::NAME_TYPE;
Ok(<$bigfile as BigFileIo>::ResourceType::dump_resource(resource, writer, endian)?)})*
(version, platform) => Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into()),
}
}
#[allow(unused_imports)]
pub fn dump_bff_resource<W: std::io::Write + std::io::Seek>(&self, writer: &mut W, platform: crate::bigfile::platforms::Platform, version: &crate::bigfile::versions::Version) -> crate::BffResult<()> {
use crate::bigfile::versions::Version::*;
use crate::bigfile::platforms::Platform::*;
use crate::traits::BigFileIo;
let endian: crate::Endian = platform.into();
<crate::bigfile::resource::BffResourceHeader as binrw::BinWrite>::write(&crate::bigfile::resource::BffResourceHeader {
platform,
version: version.clone(),
}, writer)?;
let resource = self;
match (version.clone(), platform) {
$($pattern => {crate::names::names().lock().unwrap().name_type = <$bigfile as BigFileIo>::NAME_TYPE;
Ok(<$bigfile as BigFileIo>::ResourceType::dump_resource(resource, writer, endian)?)})*
(version, platform) => Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into()),
}
}
#[allow(unused_imports)]
pub fn read_resource<R: std::io::Read + std::io::Seek>(reader: &mut R, platform: crate::bigfile::platforms::Platform, version: &crate::bigfile::versions::Version) -> crate::BffResult<crate::bigfile::resource::Resource> {
use crate::bigfile::versions::Version::*;
use crate::bigfile::platforms::Platform::*;
use crate::traits::BigFileIo;
let endian: crate::Endian = platform.into();
match (version.clone(), platform) {
$($pattern => {
crate::names::names().lock().unwrap().name_type = <$bigfile as BigFileIo>::NAME_TYPE;
Ok(<$bigfile as BigFileIo>::ResourceType::read_resource(reader, endian)?)
})*
(version, platform) => Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into()),
}
}
#[allow(unused_imports)]
pub fn read_bff_resource<R: std::io::Read + std::io::Seek>(reader: &mut R) -> crate::BffResult<crate::bigfile::resource::Resource> {
use crate::bigfile::versions::Version::*;
use crate::bigfile::platforms::Platform::*;
use crate::traits::BigFileIo;
let crate::bigfile::resource::BffResourceHeader {
platform,
version,
} = <crate::bigfile::resource::BffResourceHeader as binrw::BinRead>::read(reader)?;
let endian: crate::Endian = platform.into();
match (version.clone(), platform) {
$($pattern => {
crate::names::names().lock().unwrap().name_type = <$bigfile as BigFileIo>::NAME_TYPE;
Ok(<$bigfile as BigFileIo>::ResourceType::read_resource(reader, endian)?)
})*
(version, platform) => Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into()),
}
}
}
#[allow(non_snake_case)]
#[derive(Default, Clone, Copy, Debug)]
pub struct BigFileTryYourBestReport {
pub total: usize,
$($bigfile: usize),*
}
impl<R: std::io::Read + std::io::Seek> crate::traits::TryYourBest<&mut R> for BigFile {
type Report = BigFileTryYourBestReport;
fn update_report(reader: &mut R, platform: crate::bigfile::platforms::Platform, report: &mut Self::Report) {
use crate::traits::BigFileIo;
report.total += 1;
// TODO: Probably need a way to do this without specifying a version.
$(
reader.seek(std::io::SeekFrom::Start(256)).unwrap();
report.$bigfile += {crate::names::names().lock().unwrap().name_type = <$bigfile as BigFileIo>::NAME_TYPE;
<bool as Into<usize>>::into(<$bigfile as BigFileIo>::read(reader, crate::bigfile::versions::Version::Asobo(0, 0, 0, 0), platform).is_ok())};
)*
reader.rewind().unwrap();
}
}
impl std::fmt::Display for BigFileTryYourBestReport {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "BigFile")?;
writeln!(f, "Total: {}", self.total)?;
$(
writeln!(f, "{}: {}", stringify!($bigfile), self.$bigfile)?;
)*
Ok(())
}
}
impl TryFrom<&crate::bigfile::versions::Version> for crate::names::NameType {
type Error = crate::BffError;
fn try_from(version: &crate::bigfile::versions::Version) -> Result<crate::names::NameType, Self::Error> {
use crate::bigfile::versions::Version::*;
use crate::bigfile::platforms::Platform::*;
use crate::traits::BigFileIo;
match (version.clone(), PC) {
$($pattern => Ok(<$bigfile as BigFileIo>::NAME_TYPE),)*
(version, _platform) => Err(crate::error::UnimplementedVersionError::new(version).into()),
}
}
}
}
}
pub(crate) use bigfiles;

View file

@ -1,2 +1,4 @@
pub mod bff_class;
pub mod bigfiles;
pub mod classes;
pub mod platforms;