···35353636fn main() {
3737 App::new()
3838- .add_systems(PreUpdate, (
3939- reset_component_modifiers::<Speed>,
4040- reset_resource_modifiers::<Speed>,
3838+ .add_plugins((
3939+ ResetComponentPlugin::<Speed>::new(),
4040+ ResetResourcePlugin::<Speed>::new(),
4141 ))
4242 .run();
4343}
···4646### Bevy Butler
47474848If you use [Bevy Butler](https://github.com/TGRCdev/bevy-butler/), you can also use the `bevy_butler` feature flag.
4949-This automatically registers the required system(s) using the `add_component` attribute.
4949+This automatically registers the required system(s) using the `add_component` attribute
5050+or the existing `insert_resource` macro.
50515152```rust
5253#[butler_plugin]
5354struct MyPlugin;
54555556// `StatContainer` derive adds the `add_component` attribute
5656-// and hooks into the existing `add_resource` macro.
5757+// and hooks into the existing `insert_resource` macro.
5758#[derive(StatContainer, Component, Resource)]
5859#[add_component(plugin = MyPlugin)] // Adds `reset_component_modifiers` system.
5959-#[add_resource(plugin = MyPlugin)] // Adds `reset_resource_modifiers` system.
6060+#[insert_resource(plugin = MyPlugin)] // Adds `reset_resource_modifiers` system.
6061struct Speed(Stat);
6162```
6263
+1-1
immediate_stats/Cargo.toml
···1717bevy_app = { version = "0.16.0", default-features = false, optional = true, features = [
1818 "bevy_reflect",
1919] }
2020-bevy-butler = { version = "0.6.1-alpha", optional = true }
2020+bevy-butler = { version = "0.6.1", optional = true }
2121bevy_ecs = { version = "0.16.0", default-features = false, optional = true, features = [
2222 "bevy_reflect",
2323] }
-63
immediate_stats/README.md
···11-# Immediate Stats
22-33-Game stats that reset every frame. Inspired by immediate mode rendering.
44-Includes a derive macro which propagates stat resets to any stat fields.
55-66-```rust
77-#[derive(StatContainer)]
88-struct Speed(Stat);
99-1010-fn main() {
1111- loop {
1212- let mut speed = Speed(Stat::new(10)); // Set base speed to 10.
1313-1414- speed.0 *= 2.0; // Applies a multiplier to the final result.
1515- speed.0 += 5; // Adds a bonus to the final result.
1616- // The order does not matter. Bonuses are always applied before multipliers.
1717- assert_eq!(speed.0.total(), 30); // (10 + 5) * 2 = 30
1818-1919- speed.reset_modifiers(); // Reset bonus and multiplier, so speed is back to 10.
2020- }
2121-}
2222-```
2323-2424-## Bevy
2525-2626-There is build-in integration with the [Bevy Engine](https://bevyengine.org) via the `bevy` feature flag.
2727-This adds systems for resetting `StatContainer` components and resources.
2828-2929-```rust
3030-#[derive(StatContainer, Component, Resource)]
3131-struct Speed(Stat);
3232-3333-fn main() {
3434- App::new()
3535- .add_systems(PreUpdate, (
3636- reset_component_modifiers::<Speed>,
3737- reset_resource_modifiers::<Speed>,
3838- ))
3939- .run();
4040-}
4141-```
4242-4343-### Bevy Butler
4444-4545-If you use [Bevy Butler](https://github.com/TGRCdev/bevy-butler/), you can also use the `bevy_butler` feature flag.
4646-This automatically registers the required system(s) using the `add_component` attribute
4747-or the existing `add_resource` macro.
4848-4949-```rust
5050-#[butler_plugin]
5151-struct MyPlugin;
5252-5353-// `StatContainer` derive adds the `add_component` attribute and hooks into the existing `add_resource` macro.
5454-#[derive(StatContainer, Component, Resource, Default)]
5555-#[add_component(plugin = MyPlugin)] // Adds `reset_component_modifiers` system.
5656-#[add_resource(plugin = MyPlugin)] // Adds `reset_resource_modifiers` system.
5757-struct Speed(Stat);
5858-```
5959-6060-### Version Compatibility
6161-| bevy | immediate_stats |
6262-|--------|-----------------|
6363-| `0.16` | `0.1` |
+10-4
immediate_stats/examples/simple_bevy.rs
···12121313impl Plugin for SpeedPlugin {
1414 fn build(&self, app: &mut App) {
1515- app.add_systems(Startup, init_speed)
1616- .add_systems(PreUpdate, reset_component_modifiers::<Speed>)
1717- // Modifiers must be applied before the speed can be read.
1818- .add_systems(Update, (apply_modifiers, read_speed).chain());
1515+ app.add_plugins((ImmediateStatsPlugin, ResetComponentPlugin::<Speed>::new()))
1616+ .add_systems(Startup, init_speed)
1717+ .add_systems(
1818+ Update,
1919+ (
2020+ // Modifiers must be applied before the speed can be read.
2121+ apply_modifiers.in_set(StatSystems::Modify),
2222+ read_speed.in_set(StatSystems::Read),
2323+ ),
2424+ );
1925 }
2026}
2127
+5-4
immediate_stats/examples/simple_bevy_butler.rs
···66use immediate_stats::*;
7788fn main() {
99- App::new().add_plugins((MinimalPlugins, SpeedPlugin)).run();
99+ App::new()
1010+ .add_plugins((MinimalPlugins, ImmediateStatsPlugin, SpeedPlugin))
1111+ .run();
1012}
11131214#[butler_plugin]
···2123 commands.spawn(Speed(Stat::new(10))); // Set base speed to 10.
2224}
23252424-#[add_system(plugin = SpeedPlugin, schedule = Update)]
2626+#[add_system(plugin = SpeedPlugin, schedule = Update, in_set = StatSystems::Modify)]
2527fn apply_modifiers(mut speeds: Query<&mut Speed>) {
2628 for mut speed in &mut speeds {
2729 speed.0 *= 2.0; // Applies a multiplier to the final result.
···3032 }
3133}
32343333-// Modifiers must be applied before the speed can be read.
3434-#[add_system(plugin = SpeedPlugin, schedule = Update, after = apply_modifiers)]
3535+#[add_system(plugin = SpeedPlugin, schedule = Update, in_set = StatSystems::Read)]
3536fn read_speed(speeds: Query<&Speed>) {
3637 for speed in &speeds {
3738 println!("The current speed is {}.", speed.0.total());
+90-6
immediate_stats/src/bevy.rs
···44use crate::StatContainer;
55use crate::modifier::Modifier;
66use crate::stat::Stat;
77-use bevy_app::{App, Plugin};
77+use bevy_app::{App, Plugin, PreUpdate, Update};
88use bevy_ecs::component::Mutable;
99-use bevy_ecs::prelude::ReflectComponent;
109use bevy_ecs::prelude::{Component, Query, ResMut, Resource, Without};
1010+use bevy_ecs::prelude::{IntoScheduleConfigs, ReflectComponent, SystemSet};
1111use bevy_reflect::Reflect;
1212use bevy_reflect::prelude::ReflectDefault;
1313+use std::marker::PhantomData;
13141414-/// Registers all types used by Immediate Stats with the Bevy type registry.
1515+/// Configures [system ordering](StatSystems) and registers types with the Bevy type registry.
1616+///
1717+/// - [`StatSystems::Reset`] runs in `PreUpdate`.
1818+/// - [`StatSystems::Modify`] runs before [`StatSystems::Read`] in `Update`.
1519pub struct ImmediateStatsPlugin;
16201721impl Plugin for ImmediateStatsPlugin {
1822 fn build(&self, app: &mut App) {
1923 app.register_type::<PauseStatReset>()
2024 .register_type::<Stat>()
2121- .register_type::<Modifier>();
2525+ .register_type::<Modifier>()
2626+ .configure_sets(Update, StatSystems::Modify.before(StatSystems::Read))
2727+ .configure_sets(PreUpdate, StatSystems::Reset);
2228 }
2329}
24303131+/// A [`SystemSet`] for ordering Immediate Stats operations.
3232+/// Recommend configuration can be added via the [`ImmediateStatsPlugin`].
3333+#[derive(SystemSet, Debug, Clone, Eq, PartialEq, Hash)]
3434+pub enum StatSystems {
3535+ /// Systems that reset [`StatContainers`](StatContainer).
3636+ Reset,
3737+ /// Systems that apply modifiers to stats.
3838+ Modify,
3939+ /// Systems that read the final value of stats.
4040+ Read,
4141+}
4242+2543/// Prevents any [`StatContainers`](StatContainer) on an entity from resetting.
2644#[derive(Component, Reflect, Eq, PartialEq, Debug, Default, Clone)]
2745#[component(storage = "SparseSet")]
2846#[reflect(Component, PartialEq, Debug, Default, Clone)]
2947pub struct PauseStatReset;
30483131-/// Calls [`StatContainer::reset_modifiers`] on all `T` components.
4949+/// Calls [`reset_modifiers`](StatContainer::reset_modifiers) on all `T` components.
5050+///
5151+/// Reset occurs in the [`Reset`](StatSystems::Reset) system set during [`PreUpdate`].
5252+pub struct ResetComponentPlugin<T: Component<Mutability = Mutable> + StatContainer> {
5353+ _phantom: PhantomData<T>,
5454+}
5555+5656+impl<T: Component<Mutability = Mutable> + StatContainer> Plugin for ResetComponentPlugin<T> {
5757+ fn build(&self, app: &mut App) {
5858+ app.add_systems(
5959+ PreUpdate,
6060+ reset_component_modifiers::<T>.in_set(StatSystems::Reset),
6161+ );
6262+ }
6363+}
6464+6565+/// Calls [`reset_modifiers`](StatContainer::reset_modifiers) on all `T` components.
6666+///
6767+/// Use the [`ResetResourcePlugin`] for recommended configuration.
3268pub fn reset_component_modifiers<T: Component<Mutability = Mutable> + StatContainer>(
3369 mut query: Query<&mut T, Without<PauseStatReset>>,
3470) {
···3773 }
3874}
39754040-/// Calls [`StatContainer::reset_modifiers`] on all the `T` resource, if it exists.
7676+impl<T: Component<Mutability = Mutable> + StatContainer> ResetComponentPlugin<T> {
7777+ #[allow(missing_docs)]
7878+ pub fn new() -> Self {
7979+ Self::default()
8080+ }
8181+}
8282+8383+impl<T: Component<Mutability = Mutable> + StatContainer> Default for ResetComponentPlugin<T> {
8484+ fn default() -> Self {
8585+ Self {
8686+ _phantom: PhantomData::default(),
8787+ }
8888+ }
8989+}
9090+9191+/// Calls [`reset_modifiers`](StatContainer::reset_modifiers) on the `T` resource, if it exists.
9292+///
9393+/// Reset occurs in the [`Reset`](StatSystems::Reset) system set during [`PreUpdate`].
9494+pub struct ResetResourcePlugin<T: Resource + StatContainer> {
9595+ _phantom: PhantomData<T>,
9696+}
9797+9898+impl<T: Resource + StatContainer> Plugin for ResetResourcePlugin<T> {
9999+ fn build(&self, app: &mut App) {
100100+ app.add_systems(
101101+ PreUpdate,
102102+ reset_resource_modifiers::<T>.in_set(StatSystems::Reset),
103103+ );
104104+ }
105105+}
106106+107107+/// Calls [`reset_modifiers`](StatContainer::reset_modifiers) on the `T` resource, if it exists.
108108+///
109109+/// Use the [`ResetResourcePlugin`] for recommended configuration.
41110pub fn reset_resource_modifiers<T: Resource + StatContainer>(res: Option<ResMut<T>>) {
42111 if let Some(mut res) = res {
43112 res.reset_modifiers();
44113 }
45114}
115115+116116+impl<T: Resource + StatContainer> ResetResourcePlugin<T> {
117117+ #[allow(missing_docs)]
118118+ pub fn new() -> Self {
119119+ Self::default()
120120+ }
121121+}
122122+123123+impl<T: Resource + StatContainer> Default for ResetResourcePlugin<T> {
124124+ fn default() -> Self {
125125+ Self {
126126+ _phantom: PhantomData::default(),
127127+ }
128128+ }
129129+}
+10-10
immediate_stats/src/lib.rs
···3939//!
4040//! fn main() {
4141//! App::new()
4242-//! .add_systems(PreUpdate, (
4343-//! reset_component_modifiers::<Speed>,
4444-//! reset_resource_modifiers::<Speed>,
4242+//! .add_plugins((
4343+//! ResetComponentPlugin::<Speed>::new(),
4444+//! ResetResourcePlugin::<Speed>::new(),
4545//! ))
4646//! .run();
4747//! }
···5252//! If you use [Bevy Butler](https://github.com/TGRCdev/bevy-butler/),
5353//! you can also use the `bevy_butler` feature flag.
5454//! This automatically registers the required system(s) using the `add_component` attribute
5555-//! or the existing `add_resource` macro.
5555+//! or the existing `insert_resource` macro.
5656//!
5757#![cfg_attr(not(feature = "bevy_butler"), doc = "```rust ignore")]
5858#![cfg_attr(feature = "bevy_butler", doc = "```rust")]
···6464//! struct MyPlugin;
6565//!
6666//! // `StatContainer` derive adds the `add_component` attribute
6767-//! // and hooks into the existing `add_resource` macro.
6767+//! // and hooks into the existing `insert_resource` macro.
6868//! #[derive(StatContainer, Component, Resource, Default)]
6969//! #[add_component(plugin = MyPlugin)] // Adds `reset_component_modifiers` system.
7070-//! #[add_resource(plugin = MyPlugin)] // Adds `reset_resource_modifiers` system.
7070+//! #[insert_resource(plugin = MyPlugin)] // Adds `reset_resource_modifiers` system.
7171//! struct Speed(Stat);
7272//! ```
7373//!
···138138/// ```
139139/// # Bevy Butler
140140/// If the `bevy_butler` feature flag is enabled, you may also use the `add_component` attribute
141141-/// or the existing `add_resource` macro to register [`reset_component_modifiers`]
141141+/// or the existing `insert_resource` macro to register [`reset_component_modifiers`]
142142/// and/or [`reset_resource_modifiers`] automatically.
143143#[cfg_attr(not(feature = "bevy_butler"), doc = "```rust ignore")]
144144#[cfg_attr(feature = "bevy_butler", doc = "```rust")]
···149149/// struct MyPlugin;
150150///
151151/// // `StatContainer` derive adds the `add_component` attribute
152152-/// // and hooks into the existing `add_resource` macro.
152152+/// // and hooks into the existing `insert_resource` macro.
153153/// #[derive(StatContainer, Component, Resource, Default)]
154154/// #[add_component(plugin = MyPlugin)] // Adds `reset_component_modifiers` system.
155155-/// #[add_resource(plugin = MyPlugin)] // Adds `reset_resource_modifiers` system.
155155+/// #[insert_resource(plugin = MyPlugin)] // Adds `reset_resource_modifiers` system.
156156/// struct Speed(Stat);
157157/// ```
158158pub use immediate_stats_macros::StatContainer;
···165165// Used by derive macro.
166166#[cfg(feature = "bevy")]
167167#[doc(hidden)]
168168-pub use bevy_app::prelude::PreUpdate;
168168+pub use bevy_app::prelude::PreUpdate as __PreUpdate;
169169170170/// Types that contain stats that need to be reset.
171171///