Game stats that reset every frame, inspired by immediate mode GUI.
gamedev bevy stats
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Rewrite butler derive code.

+121 -42
+56 -2
Cargo.lock
··· 363 363 364 364 [[package]] 365 365 name = "cc" 366 - version = "1.2.19" 366 + version = "1.2.20" 367 367 source = "registry+https://github.com/rust-lang/crates.io-index" 368 - checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" 368 + checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a" 369 369 dependencies = [ 370 370 "shlex", 371 371 ] ··· 473 473 ] 474 474 475 475 [[package]] 476 + name = "darling" 477 + version = "0.20.11" 478 + source = "registry+https://github.com/rust-lang/crates.io-index" 479 + checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" 480 + dependencies = [ 481 + "darling_core", 482 + "darling_macro", 483 + ] 484 + 485 + [[package]] 486 + name = "darling_core" 487 + version = "0.20.11" 488 + source = "registry+https://github.com/rust-lang/crates.io-index" 489 + checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" 490 + dependencies = [ 491 + "fnv", 492 + "ident_case", 493 + "proc-macro2", 494 + "quote", 495 + "strsim", 496 + "syn 2.0.100", 497 + ] 498 + 499 + [[package]] 500 + name = "darling_macro" 501 + version = "0.20.11" 502 + source = "registry+https://github.com/rust-lang/crates.io-index" 503 + checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" 504 + dependencies = [ 505 + "darling_core", 506 + "quote", 507 + "syn 2.0.100", 508 + ] 509 + 510 + [[package]] 476 511 name = "derive_more" 477 512 version = "1.0.0" 478 513 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 548 583 version = "0.5.7" 549 584 source = "registry+https://github.com/rust-lang/crates.io-index" 550 585 checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" 586 + 587 + [[package]] 588 + name = "fnv" 589 + version = "1.0.7" 590 + source = "registry+https://github.com/rust-lang/crates.io-index" 591 + checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 551 592 552 593 [[package]] 553 594 name = "foldhash" ··· 676 717 checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 677 718 678 719 [[package]] 720 + name = "ident_case" 721 + version = "1.0.1" 722 + source = "registry+https://github.com/rust-lang/crates.io-index" 723 + checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 724 + 725 + [[package]] 679 726 name = "immediate_stats" 680 727 version = "0.1.0" 681 728 dependencies = [ ··· 690 737 name = "immediate_stats_macros" 691 738 version = "0.1.0" 692 739 dependencies = [ 740 + "darling", 693 741 "proc-macro-error", 694 742 "proc-macro2", 695 743 "quote", ··· 1158 1206 version = "1.2.0" 1159 1207 source = "registry+https://github.com/rust-lang/crates.io-index" 1160 1208 checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1209 + 1210 + [[package]] 1211 + name = "strsim" 1212 + version = "0.11.1" 1213 + source = "registry+https://github.com/rust-lang/crates.io-index" 1214 + checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1161 1215 1162 1216 [[package]] 1163 1217 name = "syn"
+1
immediate_stats_macros/Cargo.toml
··· 17 17 bevy_butler = ["bevy"] 18 18 19 19 [dependencies] 20 + darling = "0.20.11" 20 21 proc-macro2 = "1.0" 21 22 proc-macro-error = "1.0" 22 23 quote = "1.0"
+57 -37
immediate_stats_macros/src/bevy/butler.rs
··· 1 - use proc_macro2::{Ident, Span, TokenStream}; 2 - use quote::quote; 3 - use syn::{DeriveInput, Token}; 1 + use darling::FromMeta; 2 + use proc_macro::{self, TokenStream}; 3 + use proc_macro2::Ident; 4 + use quote::{ToTokens, format_ident, quote}; 5 + use syn::{DeriveInput, Path, parse_macro_input}; 4 6 5 - pub(crate) fn register_butler_systems(tree: &DeriveInput) -> TokenStream { 6 - let mut systems = Vec::new(); 7 + pub fn register_systems(input: TokenStream) -> TokenStream { 8 + let input = parse_macro_input!(input as DeriveInput); 9 + let struct_name = &input.ident; 7 10 8 - for attr in &tree.attrs { 9 - let struct_name = &tree.ident; 11 + let mut butler_attributes = ButlerAttributes::new(struct_name); 10 12 11 - let path = attr.meta.path(); 13 + for attr in input.attrs { 14 + if attr.path().is_ident("add_component") { 15 + let plugin = PluginPath::from_meta(&attr.meta).unwrap(); 16 + butler_attributes.component_plugin = Some(plugin); 17 + } else if attr.path().is_ident("add_resource") { 18 + let plugin = PluginPath::from_meta(&attr.meta).unwrap(); 19 + butler_attributes.resource_plugin = Some(plugin); 20 + } 21 + } 12 22 13 - let Some(ident) = path.get_ident() else { 14 - continue; 15 - }; 23 + butler_attributes.into_token_stream().into() 24 + } 16 25 17 - let use_system = match ident.to_string().as_str() { 18 - "add_resource" => quote! { use immediate_stats::bevy::reset_resource_modifiers }, 19 - "add_component" => { 20 - quote! { use immediate_stats::bevy::reset_component_modifiers } 21 - } 22 - _ => continue, 23 - }; 26 + #[derive(FromMeta)] 27 + pub struct PluginPath { 28 + pub plugin: Path, 29 + } 24 30 25 - attr.parse_nested_meta(|meta| { 26 - let Some(var_name) = meta.path.segments.first() else { 27 - return Ok(()) 28 - }; 31 + pub struct ButlerAttributes<'a> { 32 + ident: &'a Ident, 33 + component_plugin: Option<PluginPath>, 34 + resource_plugin: Option<PluginPath>, 35 + } 29 36 30 - if var_name.ident.to_string() != "plugin" { 31 - return Ok(()) 32 - }; 37 + impl<'a> ButlerAttributes<'a> { 38 + pub fn new(ident: &'a Ident) -> Self { 39 + Self { 40 + ident, 41 + component_plugin: None, 42 + resource_plugin: None, 43 + } 44 + } 45 + } 33 46 34 - let input = &meta.input; 47 + impl<'a> ToTokens for ButlerAttributes<'a> { 48 + fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { 49 + if let Some(plugin_path) = &self.component_plugin { 50 + let ident = &self.ident; 51 + let plugin = &plugin_path.plugin; 52 + let use_as = format_ident!("__{ident}_component"); 35 53 36 - input.parse::<Token![=]>().expect("An equals sign."); 37 - let input = input.parse::<proc_macro2::Ident>().expect("An identifier."); 54 + tokens.extend(quote! { 55 + #[bevy_butler::add_system(generics = <#ident>, plugin = #plugin, schedule = immediate_stats::PreUpdate)] 56 + use immediate_stats::bevy::reset_component_modifiers as #use_as; 57 + }); 58 + } 38 59 39 - let use_as = Ident::new(&format!("__{struct_name}_{ident}"), Span::call_site()); 60 + if let Some(plugin_path) = &self.resource_plugin { 61 + let ident = &self.ident; 62 + let plugin = &plugin_path.plugin; 63 + let use_as = format_ident!("__{ident}_resource"); 40 64 41 - systems.push(quote! { 42 - #[bevy_butler::add_system(generics = <#struct_name>, plugin = #input, schedule = immediate_stats::PreUpdate)] 43 - #use_system as #use_as; 65 + tokens.extend(quote! { 66 + #[bevy_butler::add_system(generics = <#ident>, plugin = #plugin, schedule = immediate_stats::PreUpdate)] 67 + use immediate_stats::bevy::reset_resource_modifiers as #use_as; 44 68 }); 45 - 46 - Ok(()) 47 - }).unwrap(); 69 + } 48 70 } 49 - 50 - quote! { #(#systems)* } 51 71 }
+7 -3
immediate_stats_macros/src/lib.rs
··· 1 1 #[cfg(feature = "bevy")] 2 2 mod bevy; 3 3 4 + use crate::bevy::butler::register_systems; 4 5 use proc_macro_error::{ 5 6 emit_call_site_error, emit_call_site_warning, emit_warning, proc_macro_error, 6 7 }; ··· 8 9 use quote::{ToTokens, quote}; 9 10 use syn::{Data, DataEnum, DataStruct, DeriveInput, Field, Ident, Index}; 10 11 11 - #[proc_macro_derive(StatContainer, attributes(stat, stat_ignore, add_component))] 12 + #[proc_macro_derive( 13 + StatContainer, 14 + attributes(stat, stat_ignore, add_component, add_resource) 15 + )] 12 16 #[proc_macro_error] 13 17 pub fn stat_container_derive(item: proc_macro::TokenStream) -> proc_macro::TokenStream { 14 - let tree: DeriveInput = syn::parse(item).expect("TokenStream must be valid."); 18 + let tree: DeriveInput = syn::parse(item.clone()).expect("TokenStream must be valid."); 15 19 16 20 let struct_name = &tree.ident; 17 21 ··· 32 36 33 37 #[cfg(feature = "bevy_butler")] 34 38 { 35 - let systems = bevy::butler::register_butler_systems(&tree); 39 + let systems: TokenStream = register_systems(item).into(); 36 40 quote! { #result #systems }.into() 37 41 } 38 42