diff --git a/gmflib/src/types.rs b/gmflib/src/types.rs index 8f54152..b572875 100644 --- a/gmflib/src/types.rs +++ b/gmflib/src/types.rs @@ -673,8 +673,7 @@ pub struct LightObject { #[gma_name("NODE_NAME")] pub name: String, pub tm: TransformMatrix, - #[gma_skip] - pub target: String, + pub tm2: Option, #[gma_name("LIGHT_TYPE")] pub light_type: LightType, pub shadows: LightShadows, @@ -684,17 +683,24 @@ pub struct LightObject { #[gma_name("LIGHT_INTENS")] pub intensity: f32, pub aspect: f32, - #[gma_skip] - pub unk1: [u8; 8], + #[gma_skip(self.light_type == LightType::Omni)] + pub hotspot: f32, + #[gma_skip(self.light_type == LightType::Omni)] + pub falloff: f32, + #[gma_skip(self.light_type == LightType::Directional)] pub attn_start: f32, + #[gma_skip(self.light_type == LightType::Directional)] pub attn_end: f32, pub tdist: f32, pub use_far_attenuation: FarAttenuation, } -#[derive(Debug,GMISerializable,GMASerializable,Serialize)] +#[derive(Debug,PartialEq,Eq,GMISerializable,GMASerializable,Serialize)] pub enum LightType { Omni = 0, + Target = 1, + Directional = 2, + Free = 4, } #[derive(Debug,GMISerializable,GMASerializable,Serialize)] @@ -931,7 +937,8 @@ pub struct RBCollectionObject { #[gma_name("SOLVER_TYPE")] pub solver_type: u32, pub rigidbody_list: RigidBodyList, - #[gmi_read_parameters(disabled_pairs)] + // Some DSL-IRL 2.6 GMFs have this set to ffffff / ffffffff for some reason.. + #[gmi_read_parameters(if disabled_pairs < 4096 { disabled_pairs } else { 0 })] pub disabled_collision_pairs: Option, } diff --git a/gmfmacros/src/lib.rs b/gmfmacros/src/lib.rs index 21759e2..b380d9f 100644 --- a/gmfmacros/src/lib.rs +++ b/gmfmacros/src/lib.rs @@ -229,6 +229,35 @@ impl GMAValue { } } +struct GMASkip { + #[allow(dead_code)] + paren_token: syn::token::Paren, + fields: syn::punctuated::Punctuated, +} + +impl syn::parse::Parse for GMASkip { + fn parse(input: syn::parse::ParseStream) -> syn::parse::Result { + let content; + Ok(Self { + paren_token: parenthesized!(content in input), + fields: content.parse_terminated(syn::Expr::parse)?, + }) + } +} + +impl GMASkip { + fn from_attrs(attrs: &Vec) -> Option { + if let Some(attr) = attrs.iter().find(|a| a.path.is_ident("gma_skip")) { + let parameters = syn::parse2::(attr.tokens.clone()).expect("invalid gma_skip attribute"); + if parameters.fields.len() != 1 { + panic!("gma_skip must have exactly one attribute"); + } + return Some(parameters.fields.iter().next().unwrap().clone()); + } + None + } +} + #[proc_macro_derive(GMASerializable, attributes(gma_name, gma_name_bare, gma_value, gma_skip, gma_space_delim))] pub fn gma_serializable_macro(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); @@ -266,7 +295,7 @@ pub fn gma_serializable_macro(input: TokenStream) -> TokenStream { }).unwrap(); let writes: Vec = fields.named.iter().map(|field| { let field_ident = &field.ident; - let field_skip = field.attrs.iter().any(|a| a.path.is_ident("gma_skip")); + let field_skip = GMASkip::from_attrs(&field.attrs); let field_space = field.attrs.iter().any(|a| a.path.is_ident("gma_space_delim")); let field_name = GMAName::from_attrs(&field.attrs) .map(|s| @@ -278,15 +307,16 @@ pub fn gma_serializable_macro(input: TokenStream) -> TokenStream { .or_else(|| { Some(struct_name.clone() + "_" + &gma_name_from_ident(field_ident.as_ref().unwrap())) }).unwrap(); - if field_skip { - quote! { } - } else { - if field_space { - quote! { + let mut cond = field_skip.map(|el| quote! { #el } ).unwrap_or(quote! { false } ); + if field_space { + quote! { + if ! ( #cond ) { _w.emit(&format!("{} {}", #field_name, self.#field_ident.atom()))?; } - } else { - quote! { + } + } else { + quote! { + if ! ( #cond ) { self.#field_ident.write(#field_name, _w)?; } }