diff --git a/crates/bevy_app/src/ci_testing.rs b/crates/bevy_app/src/ci_testing.rs index 66206d91095c3..17d8d929d6a4c 100644 --- a/crates/bevy_app/src/ci_testing.rs +++ b/crates/bevy_app/src/ci_testing.rs @@ -1,6 +1,7 @@ use crate::{app::AppExit, App}; use serde::Deserialize; +use bevy_ecs::prelude::Resource; use bevy_utils::tracing::info; /// A configuration struct for automated CI testing. @@ -8,7 +9,7 @@ use bevy_utils::tracing::info; /// It gets used when the `bevy_ci_testing` feature is enabled to automatically /// exit a Bevy app when run through the CI. This is needed because otherwise /// Bevy apps would be stuck in the game loop and wouldn't allow the CI to progress. -#[derive(Deserialize)] +#[derive(Deserialize, Resource)] pub struct CiTestingConfig { /// The number of frames after which Bevy should exit. pub exit_after: Option, diff --git a/crates/bevy_app/src/schedule_runner.rs b/crates/bevy_app/src/schedule_runner.rs index aa63ce1a8b3d0..04535c045dd9d 100644 --- a/crates/bevy_app/src/schedule_runner.rs +++ b/crates/bevy_app/src/schedule_runner.rs @@ -3,6 +3,7 @@ use crate::{ plugin::Plugin, }; use bevy_ecs::event::{Events, ManualEventReader}; +use bevy_ecs::prelude::Resource; use bevy_utils::{Duration, Instant}; #[cfg(target_arch = "wasm32")] @@ -34,7 +35,7 @@ impl Default for RunMode { /// The configuration information for the [`ScheduleRunnerPlugin`]. /// /// It gets added as a [`Resource`](bevy_ecs::system::Resource) inside of the [`ScheduleRunnerPlugin`]. -#[derive(Copy, Clone, Default)] +#[derive(Copy, Clone, Default, Resource)] pub struct ScheduleRunnerSettings { /// Determines whether the [`Schedule`](bevy_ecs::schedule::Schedule) is run once or repeatedly. pub run_mode: RunMode, diff --git a/crates/bevy_asset/src/asset_server.rs b/crates/bevy_asset/src/asset_server.rs index bc7defc361c52..85f0318d30d00 100644 --- a/crates/bevy_asset/src/asset_server.rs +++ b/crates/bevy_asset/src/asset_server.rs @@ -5,7 +5,7 @@ use crate::{ RefChange, RefChangeChannel, SourceInfo, SourceMeta, }; use anyhow::Result; -use bevy_ecs::system::{Res, ResMut}; +use bevy_ecs::system::{Res, ResMut, Resource}; use bevy_log::warn; use bevy_tasks::IoTaskPool; use bevy_utils::{Entry, HashMap, Uuid}; @@ -59,7 +59,7 @@ pub struct AssetServerInternal { } /// Loads assets from the filesystem on background threads -#[derive(Clone)] +#[derive(Clone, Resource)] pub struct AssetServer { pub(crate) server: Arc, } diff --git a/crates/bevy_asset/src/assets.rs b/crates/bevy_asset/src/assets.rs index 23ec2cf3dee66..897dfa3a695d8 100644 --- a/crates/bevy_asset/src/assets.rs +++ b/crates/bevy_asset/src/assets.rs @@ -5,7 +5,7 @@ use crate::{ use bevy_app::App; use bevy_ecs::{ event::{EventWriter, Events}, - system::ResMut, + system::{ResMut, Resource}, world::FromWorld, }; use bevy_utils::HashMap; @@ -62,7 +62,7 @@ impl Debug for AssetEvent { /// Remember, if there are no Strong handles for an asset (i.e. they have all been dropped), the /// asset will unload. Make sure you always have a Strong handle when you want to keep an asset /// loaded! -#[derive(Debug)] +#[derive(Debug, Resource)] pub struct Assets { assets: HashMap, events: Events>, diff --git a/crates/bevy_asset/src/debug_asset_server.rs b/crates/bevy_asset/src/debug_asset_server.rs index b7e3c71c85c89..2e101fbf491a3 100644 --- a/crates/bevy_asset/src/debug_asset_server.rs +++ b/crates/bevy_asset/src/debug_asset_server.rs @@ -2,7 +2,7 @@ use bevy_app::{App, Plugin}; use bevy_ecs::{ event::Events, schedule::SystemLabel, - system::{NonSendMut, Res, ResMut, SystemState}, + system::{NonSendMut, Res, ResMut, Resource, SystemState}, }; use bevy_tasks::{IoTaskPool, TaskPoolBuilder}; use bevy_utils::HashMap; @@ -44,6 +44,8 @@ pub struct DebugAssetAppRun; /// Currently only hot reloads assets stored in the `crates` folder. #[derive(Default)] pub struct DebugAssetServerPlugin; + +#[derive(Resource)] pub struct HandleMap { pub handles: HashMap, Handle>, } diff --git a/crates/bevy_asset/src/lib.rs b/crates/bevy_asset/src/lib.rs index b5ba1a1854d02..ada3102c1a080 100644 --- a/crates/bevy_asset/src/lib.rs +++ b/crates/bevy_asset/src/lib.rs @@ -29,7 +29,10 @@ pub use loader::*; pub use path::*; use bevy_app::{prelude::Plugin, App}; -use bevy_ecs::schedule::{StageLabel, SystemStage}; +use bevy_ecs::{ + schedule::{StageLabel, SystemStage}, + system::Resource, +}; /// The names of asset stages in an App Schedule #[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)] @@ -43,6 +46,7 @@ pub enum AssetStage { #[derive(Default)] pub struct AssetPlugin; +#[derive(Resource)] pub struct AssetServerSettings { pub asset_folder: String, /// Whether to watch for changes in asset files. Requires the `filesystem_watcher` feature, diff --git a/crates/bevy_audio/src/audio.rs b/crates/bevy_audio/src/audio.rs index a7c3a614ba66b..fe5ded50f2787 100644 --- a/crates/bevy_audio/src/audio.rs +++ b/crates/bevy_audio/src/audio.rs @@ -1,5 +1,6 @@ use crate::{AudioSink, AudioSource, Decodable}; use bevy_asset::{Asset, Handle, HandleId}; +use bevy_ecs::system::Resource; use parking_lot::RwLock; use std::{collections::VecDeque, fmt}; @@ -13,6 +14,7 @@ use std::{collections::VecDeque, fmt}; /// audio.play(asset_server.load("my_sound.ogg")); /// } /// ``` +#[derive(Resource)] pub struct Audio where Source: Asset + Decodable, diff --git a/crates/bevy_core/src/task_pool_options.rs b/crates/bevy_core/src/task_pool_options.rs index 152489b7cf7ae..d4ab934407278 100644 --- a/crates/bevy_core/src/task_pool_options.rs +++ b/crates/bevy_core/src/task_pool_options.rs @@ -1,3 +1,4 @@ +use bevy_ecs::prelude::Resource; use bevy_tasks::{AsyncComputeTaskPool, ComputeTaskPool, IoTaskPool, TaskPoolBuilder}; use bevy_utils::tracing::trace; @@ -33,7 +34,7 @@ impl TaskPoolThreadAssignmentPolicy { /// Helper for configuring and creating the default task pools. For end-users who want full control, /// insert the default task pools into the resource map manually. If the pools are already inserted, /// this helper will do nothing. -#[derive(Clone)] +#[derive(Clone, Resource)] pub struct DefaultTaskPoolOptions { /// If the number of physical cores is less than min_total_threads, force using /// min_total_threads diff --git a/crates/bevy_diagnostic/src/diagnostic.rs b/crates/bevy_diagnostic/src/diagnostic.rs index ba8d1a0c041bf..a7672229ddeca 100644 --- a/crates/bevy_diagnostic/src/diagnostic.rs +++ b/crates/bevy_diagnostic/src/diagnostic.rs @@ -1,3 +1,4 @@ +use bevy_ecs::system::Resource; use bevy_log::warn; use bevy_utils::{Duration, Instant, StableHashMap, Uuid}; use std::{borrow::Cow, collections::VecDeque}; @@ -136,7 +137,7 @@ impl Diagnostic { } /// A collection of [Diagnostic]s -#[derive(Debug, Default)] +#[derive(Debug, Default, Resource)] pub struct Diagnostics { // This uses a [`StableHashMap`] to ensure that the iteration order is deterministic between // runs when all diagnostics are inserted in the same order. diff --git a/crates/bevy_diagnostic/src/frame_time_diagnostics_plugin.rs b/crates/bevy_diagnostic/src/frame_time_diagnostics_plugin.rs index 2dd016e30d518..323d763149a46 100644 --- a/crates/bevy_diagnostic/src/frame_time_diagnostics_plugin.rs +++ b/crates/bevy_diagnostic/src/frame_time_diagnostics_plugin.rs @@ -1,12 +1,13 @@ use crate::{Diagnostic, DiagnosticId, Diagnostics}; use bevy_app::prelude::*; -use bevy_ecs::system::{Res, ResMut}; +use bevy_ecs::system::{Res, ResMut, Resource}; use bevy_time::Time; /// Adds "frame time" diagnostic to an App, specifically "frame time", "fps" and "frame count" #[derive(Default)] pub struct FrameTimeDiagnosticsPlugin; +#[derive(Resource)] pub struct FrameTimeDiagnosticsState { frame_count: u64, } diff --git a/crates/bevy_diagnostic/src/log_diagnostics_plugin.rs b/crates/bevy_diagnostic/src/log_diagnostics_plugin.rs index 728f1cd123a5a..b37ecbe40d979 100644 --- a/crates/bevy_diagnostic/src/log_diagnostics_plugin.rs +++ b/crates/bevy_diagnostic/src/log_diagnostics_plugin.rs @@ -1,6 +1,6 @@ use super::{Diagnostic, DiagnosticId, Diagnostics}; use bevy_app::prelude::*; -use bevy_ecs::system::{Res, ResMut}; +use bevy_ecs::system::{Res, ResMut, Resource}; use bevy_log::{debug, info}; use bevy_time::{Time, Timer}; use bevy_utils::Duration; @@ -13,6 +13,7 @@ pub struct LogDiagnosticsPlugin { } /// State used by the [`LogDiagnosticsPlugin`] +#[derive(Resource)] struct LogDiagnosticsState { timer: Timer, filter: Option>, diff --git a/crates/bevy_ecs/examples/change_detection.rs b/crates/bevy_ecs/examples/change_detection.rs index 1a3e135b654e2..1f2af2e35c812 100644 --- a/crates/bevy_ecs/examples/change_detection.rs +++ b/crates/bevy_ecs/examples/change_detection.rs @@ -40,7 +40,7 @@ fn main() { } // This struct will be used as a Resource keeping track of the total amount of spawned entities -#[derive(Debug)] +#[derive(Debug, Resource)] struct EntityCounter { pub value: i32, } diff --git a/crates/bevy_ecs/examples/resources.rs b/crates/bevy_ecs/examples/resources.rs index c6700a6b9ed9d..3127f52d90732 100644 --- a/crates/bevy_ecs/examples/resources.rs +++ b/crates/bevy_ecs/examples/resources.rs @@ -27,7 +27,7 @@ fn main() { } // Counter resource to be increased and read by systems -#[derive(Debug)] +#[derive(Debug, Resource)] struct Counter { pub value: i32, } diff --git a/crates/bevy_ecs/macros/src/component.rs b/crates/bevy_ecs/macros/src/component.rs index 440fe31468df7..ab1a07a31dd53 100644 --- a/crates/bevy_ecs/macros/src/component.rs +++ b/crates/bevy_ecs/macros/src/component.rs @@ -4,6 +4,24 @@ use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::{quote, ToTokens}; use syn::{parse_macro_input, parse_quote, DeriveInput, Error, Ident, Path, Result}; +pub fn derive_resource(input: TokenStream) -> TokenStream { + let mut ast = parse_macro_input!(input as DeriveInput); + let bevy_ecs_path: Path = crate::bevy_ecs_path(); + + ast.generics + .make_where_clause() + .predicates + .push(parse_quote! { Self: Send + Sync + 'static }); + + let struct_name = &ast.ident; + let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl(); + + TokenStream::from(quote! { + impl #impl_generics #bevy_ecs_path::component::Resource for #struct_name #type_generics #where_clause { + } + }) +} + pub fn derive_component(input: TokenStream) -> TokenStream { let mut ast = parse_macro_input!(input as DeriveInput); let bevy_ecs_path: Path = crate::bevy_ecs_path(); diff --git a/crates/bevy_ecs/macros/src/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index 3273faf9ab1a2..a55a97ec05a1a 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -480,6 +480,11 @@ pub(crate) fn bevy_ecs_path() -> syn::Path { BevyManifest::default().get_path("bevy_ecs") } +#[proc_macro_derive(Resource)] +pub fn derive_resource(input: TokenStream) -> TokenStream { + component::derive_resource(input) +} + #[proc_macro_derive(Component, attributes(component))] pub fn derive_component(input: TokenStream) -> TokenStream { component::derive_component(input) diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index 2b5ae2bd2f5cb..909b70a65905f 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -165,7 +165,7 @@ pub(crate) struct Ticks<'a> { pub(crate) change_tick: u32, } -/// Unique mutable borrow of a resource. +/// Unique mutable borrow of a [`Resource`]. /// /// See the [`World`](crate::world::World) documentation to see the usage of a resource. /// diff --git a/crates/bevy_ecs/src/component.rs b/crates/bevy_ecs/src/component.rs index fdcb2a0d0d974..c5f6b1793d996 100644 --- a/crates/bevy_ecs/src/component.rs +++ b/crates/bevy_ecs/src/component.rs @@ -1,6 +1,6 @@ //! Types for declaring and storing [`Component`]s. -use crate::{ +pub use crate::{ change_detection::MAX_CHANGE_AGE, storage::{SparseSetIndex, Storages}, system::Resource, diff --git a/crates/bevy_ecs/src/event.rs b/crates/bevy_ecs/src/event.rs index 22af1b3ed2dff..33b94c3926804 100644 --- a/crates/bevy_ecs/src/event.rs +++ b/crates/bevy_ecs/src/event.rs @@ -1,7 +1,7 @@ //! Event handling types. use crate as bevy_ecs; -use crate::system::{Local, Res, ResMut, SystemParam}; +use crate::system::{Local, Res, ResMut, SystemParam, Resource}; use bevy_utils::tracing::trace; use std::ops::{Deref, DerefMut}; use std::{ @@ -128,7 +128,7 @@ struct EventInstance { /// [Example usage.](https://github.com/bevyengine/bevy/blob/latest/examples/ecs/event.rs) /// [Example usage standalone.](https://github.com/bevyengine/bevy/blob/latest/bevy_ecs/examples/events.rs) /// -#[derive(Debug)] +#[derive(Debug, Resource)] pub struct Events { /// Holds the oldest still active events. /// Note that a.start_event_count + a.len() should always === events_b.start_event_count. diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index 30a373a9d5ae0..faf6995d732f8 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -39,8 +39,8 @@ pub mod prelude { }, system::{ Commands, In, IntoChainSystem, IntoExclusiveSystem, IntoSystem, Local, NonSend, - NonSendMut, ParallelCommands, ParamSet, Query, RemovedComponents, Res, ResMut, System, - SystemParamFunction, + NonSendMut, ParallelCommands, ParamSet, Query, RemovedComponents, Res, ResMut, + Resource, System, SystemParamFunction, }, world::{FromWorld, Mut, World}, }; @@ -57,6 +57,7 @@ mod tests { component::{Component, ComponentId}, entity::Entity, query::{Added, ChangeTrackers, Changed, FilteredAccess, With, Without, WorldQuery}, + system::Resource, world::{Mut, World}, }; use bevy_tasks::{ComputeTaskPool, TaskPool}; @@ -68,7 +69,7 @@ mod tests { }, }; - #[derive(Component, Debug, PartialEq, Eq, Clone, Copy)] + #[derive(Component, Resource, Debug, PartialEq, Eq, Clone, Copy)] struct A(usize); #[derive(Component, Debug, PartialEq, Eq, Clone, Copy)] struct B(usize); @@ -1002,16 +1003,24 @@ mod tests { #[test] fn resource() { + use crate::system::Resource; + + #[derive(Resource, PartialEq, Debug)] + struct Num(i32); + + #[derive(Resource, PartialEq, Debug)] + struct BigNum(u64); + let mut world = World::default(); - assert!(world.get_resource::().is_none()); - assert!(!world.contains_resource::()); - assert!(!world.is_resource_added::()); - assert!(!world.is_resource_changed::()); + assert!(world.get_resource::().is_none()); + assert!(!world.contains_resource::()); + assert!(!world.is_resource_added::()); + assert!(!world.is_resource_changed::()); - world.insert_resource(123); + world.insert_resource(Num(123)); let resource_id = world .components() - .get_resource_id(TypeId::of::()) + .get_resource_id(TypeId::of::()) .unwrap(); let archetype_component_id = world .archetypes() @@ -1019,61 +1028,61 @@ mod tests { .get_archetype_component_id(resource_id) .unwrap(); - assert_eq!(*world.resource::(), 123); - assert!(world.contains_resource::()); - assert!(world.is_resource_added::()); - assert!(world.is_resource_changed::()); + assert_eq!(world.resource::().0, 123); + assert!(world.contains_resource::()); + assert!(world.is_resource_added::()); + assert!(world.is_resource_changed::()); - world.insert_resource(456u64); - assert_eq!(*world.resource::(), 456u64); + world.insert_resource(BigNum(456)); + assert_eq!(world.resource::().0, 456u64); - world.insert_resource(789u64); - assert_eq!(*world.resource::(), 789); + world.insert_resource(BigNum(789)); + assert_eq!(world.resource::().0, 789); { - let mut value = world.resource_mut::(); - assert_eq!(*value, 789); - *value = 10; + let mut value = world.resource_mut::(); + assert_eq!(value.0, 789); + value.0 = 10; } assert_eq!( - world.resource::(), - &10, + world.resource::().0, + 10, "resource changes are preserved" ); assert_eq!( - world.remove_resource::(), - Some(10), + world.remove_resource::(), + Some(BigNum(10)), "removed resource has the correct value" ); assert_eq!( - world.get_resource::(), + world.get_resource::(), None, "removed resource no longer exists" ); assert_eq!( - world.remove_resource::(), + world.remove_resource::(), None, "double remove returns nothing" ); - world.insert_resource(1u64); + world.insert_resource(BigNum(1)); assert_eq!( - world.get_resource::(), - Some(&1u64), + world.get_resource::(), + Some(&BigNum(1)), "re-inserting resources works" ); assert_eq!( - world.get_resource::(), - Some(&123), + world.get_resource::(), + Some(&Num(123)), "other resources are unaffected" ); let current_resource_id = world .components() - .get_resource_id(TypeId::of::()) + .get_resource_id(TypeId::of::()) .unwrap(); assert_eq!( resource_id, current_resource_id, @@ -1119,7 +1128,7 @@ mod tests { assert_eq!( e.get::(), None, - "i32 is in the removed bundle, so it should not exist" + "Num is in the removed bundle, so it should not exist" ); assert_eq!( e.get::(), @@ -1324,12 +1333,12 @@ mod tests { #[test] fn resource_scope() { let mut world = World::default(); - world.insert_resource::(0); - world.resource_scope(|world: &mut World, mut value: Mut| { - *value += 1; - assert!(!world.contains_resource::()); + world.insert_resource(A(0)); + world.resource_scope(|world: &mut World, mut value: Mut| { + value.0 += 1; + assert!(!world.contains_resource::()); }); - assert_eq!(*world.resource::(), 1); + assert_eq!(world.resource::().0, 1); } #[test] @@ -1366,7 +1375,7 @@ mod tests { fn clear_entities() { let mut world = World::default(); - world.insert_resource::(0); + world.insert_resource(A(0)); world.spawn().insert(A(1)); world.spawn().insert(SparseStored(1)); @@ -1395,7 +1404,7 @@ mod tests { "world should not have any entities" ); assert_eq!( - *world.resource::(), + world.resource::().0, 0, "world should still contain resources" ); diff --git a/crates/bevy_ecs/src/reflect.rs b/crates/bevy_ecs/src/reflect.rs index 4881dd83f0edd..cfcd5c04571d3 100644 --- a/crates/bevy_ecs/src/reflect.rs +++ b/crates/bevy_ecs/src/reflect.rs @@ -4,10 +4,12 @@ pub use crate::change_detection::ReflectMut; use crate::{ component::Component, entity::{Entity, EntityMap, MapEntities, MapEntitiesError}, + system::Resource, world::{FromWorld, World}, }; use bevy_reflect::{ impl_from_reflect_value, impl_reflect_value, FromType, Reflect, ReflectDeserialize, + TypeRegistryArc, }; #[derive(Clone)] @@ -154,3 +156,6 @@ impl FromType for ReflectMapEntities { } } } + +// We cannot implement this in bevy_reflect, or we would create a cyclic dependendency +impl Resource for TypeRegistryArc {} diff --git a/crates/bevy_ecs/src/schedule/executor_parallel.rs b/crates/bevy_ecs/src/schedule/executor_parallel.rs index c82924b0e276c..ec0f3c10081f0 100644 --- a/crates/bevy_ecs/src/schedule/executor_parallel.rs +++ b/crates/bevy_ecs/src/schedule/executor_parallel.rs @@ -11,7 +11,7 @@ use bevy_utils::tracing::Instrument; use fixedbitset::FixedBitSet; #[cfg(test)] -use SchedulingEvent::*; +use scheduling_event::*; struct SystemSchedulingMetadata { /// Used to signal the system's task to start the system. @@ -107,7 +107,7 @@ impl ParallelSystemExecutor for ParallelExecutor { #[cfg(test)] if self.events_sender.is_none() { let (sender, receiver) = async_channel::unbounded::(); - world.insert_resource(receiver); + world.insert_resource(SchedulingEvents(receiver)); self.events_sender = Some(sender); } @@ -259,7 +259,7 @@ impl ParallelExecutor { } #[cfg(test)] if started_systems != 0 { - self.emit_event(StartedSystems(started_systems)); + self.emit_event(SchedulingEvent::StartedSystems(started_systems)); } // Remove now running systems from the queue. self.queued.difference_with(&self.running); @@ -307,29 +307,42 @@ impl ParallelExecutor { } #[cfg(test)] -#[derive(Debug, PartialEq, Eq)] -enum SchedulingEvent { - StartedSystems(usize), +mod scheduling_event { + use crate as bevy_ecs; + use crate::system::Resource; + use async_channel::Receiver; + + #[derive(Debug, PartialEq, Eq)] + pub(super) enum SchedulingEvent { + StartedSystems(usize), + } + + #[derive(Resource)] + pub(super) struct SchedulingEvents(pub(crate) Receiver); } +#[cfg(test)] #[cfg(test)] mod tests { - use super::SchedulingEvent::{self, *}; + use super::scheduling_event::*; use crate::{ schedule::{SingleThreadedExecutor, Stage, SystemStage}, system::{NonSend, Query, Res, ResMut}, world::World, }; - use async_channel::Receiver; use crate as bevy_ecs; use crate::component::Component; + use crate::system::Resource; + #[derive(Component)] struct W(T); + #[derive(Resource, Default)] + struct Counter(usize); fn receive_events(world: &World) -> Vec { let mut events = Vec::new(); - while let Ok(event) = world.resource::>().try_recv() { + while let Ok(event) = world.resource::().0.try_recv() { events.push(event); } events @@ -347,23 +360,29 @@ mod tests { stage.run(&mut world); assert_eq!( receive_events(&world), - vec![StartedSystems(3), StartedSystems(3),] + vec![ + SchedulingEvent::StartedSystems(3), + SchedulingEvent::StartedSystems(3), + ] ); } #[test] fn resources() { let mut world = World::new(); - world.insert_resource(0usize); - fn wants_mut(_: ResMut) {} - fn wants_ref(_: Res) {} + world.init_resource::(); + fn wants_mut(_: ResMut) {} + fn wants_ref(_: Res) {} let mut stage = SystemStage::parallel() .with_system(wants_mut) .with_system(wants_mut); stage.run(&mut world); assert_eq!( receive_events(&world), - vec![StartedSystems(1), StartedSystems(1),] + vec![ + SchedulingEvent::StartedSystems(1), + SchedulingEvent::StartedSystems(1), + ] ); let mut stage = SystemStage::parallel() .with_system(wants_mut) @@ -371,13 +390,19 @@ mod tests { stage.run(&mut world); assert_eq!( receive_events(&world), - vec![StartedSystems(1), StartedSystems(1),] + vec![ + SchedulingEvent::StartedSystems(1), + SchedulingEvent::StartedSystems(1), + ] ); let mut stage = SystemStage::parallel() .with_system(wants_ref) .with_system(wants_ref); stage.run(&mut world); - assert_eq!(receive_events(&world), vec![StartedSystems(2),]); + assert_eq!( + receive_events(&world), + vec![SchedulingEvent::StartedSystems(2),] + ); } #[test] @@ -392,7 +417,10 @@ mod tests { stage.run(&mut world); assert_eq!( receive_events(&world), - vec![StartedSystems(1), StartedSystems(1),] + vec![ + SchedulingEvent::StartedSystems(1), + SchedulingEvent::StartedSystems(1), + ] ); let mut stage = SystemStage::parallel() .with_system(wants_mut) @@ -400,13 +428,19 @@ mod tests { stage.run(&mut world); assert_eq!( receive_events(&world), - vec![StartedSystems(1), StartedSystems(1),] + vec![ + SchedulingEvent::StartedSystems(1), + SchedulingEvent::StartedSystems(1), + ] ); let mut stage = SystemStage::parallel() .with_system(wants_ref) .with_system(wants_ref); stage.run(&mut world); - assert_eq!(receive_events(&world), vec![StartedSystems(2),]); + assert_eq!( + receive_events(&world), + vec![SchedulingEvent::StartedSystems(2),] + ); let mut world = World::new(); world.spawn().insert_bundle((W(0usize), W(0u32), W(0f32))); fn wants_mut_usize(_: Query<(&mut W, &W)>) {} @@ -415,7 +449,10 @@ mod tests { .with_system(wants_mut_usize) .with_system(wants_mut_u32); stage.run(&mut world); - assert_eq!(receive_events(&world), vec![StartedSystems(2),]); + assert_eq!( + receive_events(&world), + vec![SchedulingEvent::StartedSystems(2),] + ); } #[test] @@ -430,7 +467,10 @@ mod tests { stage.run(&mut world); assert_eq!( receive_events(&world), - vec![StartedSystems(1), StartedSystems(1),] + vec![ + SchedulingEvent::StartedSystems(1), + SchedulingEvent::StartedSystems(1), + ] ); let mut stage = SystemStage::parallel() .with_system(wants_mut) @@ -438,13 +478,19 @@ mod tests { stage.run(&mut world); assert_eq!( receive_events(&world), - vec![StartedSystems(1), StartedSystems(1),] + vec![ + SchedulingEvent::StartedSystems(1), + SchedulingEvent::StartedSystems(1), + ] ); let mut stage = SystemStage::parallel() .with_system(wants_world) .with_system(wants_world); stage.run(&mut world); - assert_eq!(receive_events(&world), vec![StartedSystems(2),]); + assert_eq!( + receive_events(&world), + vec![SchedulingEvent::StartedSystems(2),] + ); } #[test] @@ -467,10 +513,10 @@ mod tests { assert_eq!( receive_events(&world), vec![ - StartedSystems(3), - StartedSystems(1), - StartedSystems(1), - StartedSystems(1), + SchedulingEvent::StartedSystems(3), + SchedulingEvent::StartedSystems(1), + SchedulingEvent::StartedSystems(1), + SchedulingEvent::StartedSystems(1), ] ); stage.set_executor(Box::new(SingleThreadedExecutor::default())); diff --git a/crates/bevy_ecs/src/schedule/stage.rs b/crates/bevy_ecs/src/schedule/stage.rs index ff26ced892a6f..d1ca79358bca8 100644 --- a/crates/bevy_ecs/src/schedule/stage.rs +++ b/crates/bevy_ecs/src/schedule/stage.rs @@ -958,15 +958,22 @@ mod tests { use crate as bevy_ecs; use crate::component::Component; + use crate::system::Resource; + #[derive(Component)] struct W(T); + #[derive(Resource)] + struct R(usize); + + #[derive(Resource, Default)] + struct EntityCount(Vec); fn make_exclusive(tag: usize) -> impl FnMut(&mut World) { - move |world| world.resource_mut::>().push(tag) + move |world| world.resource_mut::().0.push(tag) } - fn make_parallel(tag: usize) -> impl FnMut(ResMut>) { - move |mut resource: ResMut>| resource.push(tag) + fn make_parallel(tag: usize) -> impl FnMut(ResMut) { + move |mut resource: ResMut| resource.0.push(tag) } fn every_other_time(mut has_ran: Local) -> ShouldRun { @@ -981,48 +988,48 @@ mod tests { #[test] fn insertion_points() { let mut world = World::new(); - world.insert_resource(Vec::::new()); + world.init_resource::(); let mut stage = SystemStage::parallel() .with_system(make_exclusive(0).exclusive_system().at_start()) .with_system(make_parallel(1)) .with_system(make_exclusive(2).exclusive_system().before_commands()) .with_system(make_exclusive(3).exclusive_system().at_end()); stage.run(&mut world); - assert_eq!(*world.resource_mut::>(), vec![0, 1, 2, 3]); + assert_eq!(world.resource_mut::().0, vec![0, 1, 2, 3]); stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); assert_eq!( - *world.resource::>(), + world.resource::().0, vec![0, 1, 2, 3, 0, 1, 2, 3] ); - world.resource_mut::>().clear(); + world.resource_mut::().0.clear(); let mut stage = SystemStage::parallel() .with_system(make_exclusive(2).exclusive_system().before_commands()) .with_system(make_exclusive(3).exclusive_system().at_end()) .with_system(make_parallel(1)) .with_system(make_exclusive(0).exclusive_system().at_start()); stage.run(&mut world); - assert_eq!(*world.resource::>(), vec![0, 1, 2, 3]); + assert_eq!(world.resource::().0, vec![0, 1, 2, 3]); stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); assert_eq!( - *world.resource::>(), + world.resource::().0, vec![0, 1, 2, 3, 0, 1, 2, 3] ); - world.resource_mut::>().clear(); + world.resource_mut::().0.clear(); let mut stage = SystemStage::parallel() .with_system(make_parallel(2).exclusive_system().before_commands()) .with_system(make_parallel(3).exclusive_system().at_end()) .with_system(make_parallel(1)) .with_system(make_parallel(0).exclusive_system().at_start()); stage.run(&mut world); - assert_eq!(*world.resource::>(), vec![0, 1, 2, 3]); + assert_eq!(world.resource::().0, vec![0, 1, 2, 3]); stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); assert_eq!( - *world.resource::>(), + world.resource::().0, vec![0, 1, 2, 3, 0, 1, 2, 3] ); } @@ -1030,7 +1037,7 @@ mod tests { #[test] fn exclusive_after() { let mut world = World::new(); - world.insert_resource(Vec::::new()); + world.init_resource::(); let mut stage = SystemStage::parallel() .with_system(make_exclusive(1).exclusive_system().label("1").after("0")) .with_system(make_exclusive(2).exclusive_system().after("1")) @@ -1038,13 +1045,13 @@ mod tests { stage.run(&mut world); stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); - assert_eq!(*world.resource::>(), vec![0, 1, 2, 0, 1, 2]); + assert_eq!(world.resource::().0, vec![0, 1, 2, 0, 1, 2]); } #[test] fn exclusive_before() { let mut world = World::new(); - world.insert_resource(Vec::::new()); + world.init_resource::(); let mut stage = SystemStage::parallel() .with_system(make_exclusive(1).exclusive_system().label("1").before("2")) .with_system(make_exclusive(2).exclusive_system().label("2")) @@ -1052,13 +1059,13 @@ mod tests { stage.run(&mut world); stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); - assert_eq!(*world.resource::>(), vec![0, 1, 2, 0, 1, 2]); + assert_eq!(world.resource::().0, vec![0, 1, 2, 0, 1, 2]); } #[test] fn exclusive_mixed() { let mut world = World::new(); - world.insert_resource(Vec::::new()); + world.init_resource::(); let mut stage = SystemStage::parallel() .with_system(make_exclusive(2).exclusive_system().label("2")) .with_system(make_exclusive(1).exclusive_system().after("0").before("2")) @@ -1069,7 +1076,7 @@ mod tests { stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); assert_eq!( - *world.resource::>(), + world.resource::().0, vec![0, 1, 2, 3, 4, 0, 1, 2, 3, 4] ); } @@ -1077,7 +1084,7 @@ mod tests { #[test] fn exclusive_multiple_labels() { let mut world = World::new(); - world.insert_resource(Vec::::new()); + world.init_resource::(); let mut stage = SystemStage::parallel() .with_system( make_exclusive(1) @@ -1095,9 +1102,9 @@ mod tests { stage.run(&mut world); stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); - assert_eq!(*world.resource::>(), vec![0, 1, 2, 0, 1, 2]); + assert_eq!(world.resource::().0, vec![0, 1, 2, 0, 1, 2]); - world.resource_mut::>().clear(); + world.resource_mut::().0.clear(); let mut stage = SystemStage::parallel() .with_system(make_exclusive(2).exclusive_system().after("01").label("2")) .with_system(make_exclusive(1).exclusive_system().label("01").after("0")) @@ -1108,11 +1115,11 @@ mod tests { stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); assert_eq!( - *world.resource::>(), + world.resource::().0, vec![0, 1, 2, 3, 4, 0, 1, 2, 3, 4] ); - world.resource_mut::>().clear(); + world.resource_mut::().0.clear(); let mut stage = SystemStage::parallel() .with_system(make_exclusive(2).exclusive_system().label("234").label("2")) .with_system( @@ -1134,7 +1141,7 @@ mod tests { stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); assert_eq!( - *world.resource::>(), + world.resource::().0, vec![0, 1, 2, 3, 4, 0, 1, 2, 3, 4] ); } @@ -1142,7 +1149,7 @@ mod tests { #[test] fn exclusive_redundant_constraints() { let mut world = World::new(); - world.insert_resource(Vec::::new()); + world.init_resource::(); let mut stage = SystemStage::parallel() .with_system( make_exclusive(2) @@ -1173,7 +1180,7 @@ mod tests { stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); assert_eq!( - *world.resource::>(), + world.resource::().0, vec![0, 1, 2, 3, 4, 0, 1, 2, 3, 4] ); } @@ -1181,7 +1188,7 @@ mod tests { #[test] fn exclusive_mixed_across_sets() { let mut world = World::new(); - world.insert_resource(Vec::::new()); + world.init_resource::(); let mut stage = SystemStage::parallel() .with_system(make_exclusive(2).exclusive_system().label("2")) .with_system_set( @@ -1195,7 +1202,7 @@ mod tests { stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); assert_eq!( - *world.resource::>(), + world.resource::().0, vec![0, 1, 2, 3, 4, 0, 1, 2, 3, 4] ); } @@ -1203,7 +1210,7 @@ mod tests { #[test] fn exclusive_run_criteria() { let mut world = World::new(); - world.insert_resource(Vec::::new()); + world.init_resource::(); let mut stage = SystemStage::parallel() .with_system(make_exclusive(0).exclusive_system().before("1")) .with_system_set( @@ -1218,7 +1225,7 @@ mod tests { stage.run(&mut world); stage.run(&mut world); assert_eq!( - *world.resource::>(), + world.resource::().0, vec![0, 1, 2, 0, 2, 0, 1, 2, 0, 2] ); } @@ -1227,7 +1234,7 @@ mod tests { #[should_panic] fn exclusive_cycle_1() { let mut world = World::new(); - world.insert_resource(Vec::::new()); + world.init_resource::(); let mut stage = SystemStage::parallel() .with_system(make_exclusive(0).exclusive_system().label("0").after("0")); stage.run(&mut world); @@ -1237,7 +1244,7 @@ mod tests { #[should_panic] fn exclusive_cycle_2() { let mut world = World::new(); - world.insert_resource(Vec::::new()); + world.init_resource::(); let mut stage = SystemStage::parallel() .with_system(make_exclusive(0).exclusive_system().label("0").after("1")) .with_system(make_exclusive(1).exclusive_system().label("1").after("0")); @@ -1248,7 +1255,7 @@ mod tests { #[should_panic] fn exclusive_cycle_3() { let mut world = World::new(); - world.insert_resource(Vec::::new()); + world.init_resource::(); let mut stage = SystemStage::parallel() .with_system(make_exclusive(0).exclusive_system().label("0")) .with_system(make_exclusive(1).exclusive_system().after("0").before("2")) @@ -1259,7 +1266,7 @@ mod tests { #[test] fn parallel_after() { let mut world = World::new(); - world.insert_resource(Vec::::new()); + world.init_resource::(); let mut stage = SystemStage::parallel() .with_system(make_parallel(1).after("0").label("1")) .with_system(make_parallel(2).after("1")) @@ -1267,13 +1274,13 @@ mod tests { stage.run(&mut world); stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); - assert_eq!(*world.resource::>(), vec![0, 1, 2, 0, 1, 2]); + assert_eq!(world.resource::().0, vec![0, 1, 2, 0, 1, 2]); } #[test] fn parallel_before() { let mut world = World::new(); - world.insert_resource(Vec::::new()); + world.init_resource::(); let mut stage = SystemStage::parallel() .with_system(make_parallel(1).label("1").before("2")) .with_system(make_parallel(2).label("2")) @@ -1281,13 +1288,13 @@ mod tests { stage.run(&mut world); stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); - assert_eq!(*world.resource::>(), vec![0, 1, 2, 0, 1, 2]); + assert_eq!(world.resource::().0, vec![0, 1, 2, 0, 1, 2]); } #[test] fn parallel_mixed() { let mut world = World::new(); - world.insert_resource(Vec::::new()); + world.init_resource::(); let mut stage = SystemStage::parallel() .with_system(make_parallel(2).label("2")) .with_system(make_parallel(1).after("0").before("2")) @@ -1298,7 +1305,7 @@ mod tests { stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); assert_eq!( - *world.resource::>(), + world.resource::().0, vec![0, 1, 2, 3, 4, 0, 1, 2, 3, 4] ); } @@ -1306,7 +1313,7 @@ mod tests { #[test] fn parallel_multiple_labels() { let mut world = World::new(); - world.insert_resource(Vec::::new()); + world.init_resource::(); let mut stage = SystemStage::parallel() .with_system(make_parallel(1).label("first").after("0")) .with_system(make_parallel(2).after("first")) @@ -1314,9 +1321,9 @@ mod tests { stage.run(&mut world); stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); - assert_eq!(*world.resource::>(), vec![0, 1, 2, 0, 1, 2]); + assert_eq!(world.resource::().0, vec![0, 1, 2, 0, 1, 2]); - world.resource_mut::>().clear(); + world.resource_mut::().0.clear(); let mut stage = SystemStage::parallel() .with_system(make_parallel(2).after("01").label("2")) .with_system(make_parallel(1).label("01").after("0")) @@ -1327,11 +1334,11 @@ mod tests { stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); assert_eq!( - *world.resource::>(), + world.resource::().0, vec![0, 1, 2, 3, 4, 0, 1, 2, 3, 4] ); - world.resource_mut::>().clear(); + world.resource_mut::().0.clear(); let mut stage = SystemStage::parallel() .with_system(make_parallel(2).label("234").label("2")) .with_system(make_parallel(1).before("234").after("0")) @@ -1342,7 +1349,7 @@ mod tests { stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); assert_eq!( - *world.resource::>(), + world.resource::().0, vec![0, 1, 2, 3, 4, 0, 1, 2, 3, 4] ); } @@ -1350,7 +1357,7 @@ mod tests { #[test] fn parallel_redundant_constraints() { let mut world = World::new(); - world.insert_resource(Vec::::new()); + world.init_resource::(); let mut stage = SystemStage::parallel() .with_system( make_parallel(2) @@ -1376,7 +1383,7 @@ mod tests { stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); assert_eq!( - *world.resource::>(), + world.resource::().0, vec![0, 1, 2, 3, 4, 0, 1, 2, 3, 4] ); } @@ -1384,7 +1391,7 @@ mod tests { #[test] fn parallel_mixed_across_sets() { let mut world = World::new(); - world.insert_resource(Vec::::new()); + world.init_resource::(); let mut stage = SystemStage::parallel() .with_system(make_parallel(2).label("2")) .with_system_set( @@ -1398,7 +1405,7 @@ mod tests { stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); assert_eq!( - *world.resource::>(), + world.resource::().0, vec![0, 1, 2, 3, 4, 0, 1, 2, 3, 4] ); } @@ -1407,7 +1414,7 @@ mod tests { fn parallel_run_criteria() { let mut world = World::new(); - world.insert_resource(Vec::::new()); + world.init_resource::(); let mut stage = SystemStage::parallel() .with_system( make_parallel(0) @@ -1420,9 +1427,9 @@ mod tests { stage.set_executor(Box::new(SingleThreadedExecutor::default())); stage.run(&mut world); stage.run(&mut world); - assert_eq!(*world.resource::>(), vec![0, 1, 1, 0, 1, 1]); + assert_eq!(world.resource::().0, vec![0, 1, 1, 0, 1, 1]); - world.resource_mut::>().clear(); + world.resource_mut::().0.clear(); let mut stage = SystemStage::parallel() .with_system(make_parallel(0).before("1")) .with_system_set( @@ -1437,12 +1444,12 @@ mod tests { stage.run(&mut world); stage.run(&mut world); assert_eq!( - *world.resource::>(), + world.resource::().0, vec![0, 1, 2, 0, 2, 0, 1, 2, 0, 2] ); // Reusing criteria. - world.resource_mut::>().clear(); + world.resource_mut::().0.clear(); let mut stage = SystemStage::parallel() .with_system_run_criteria(every_other_time.label("every other time")) .with_system(make_parallel(0).before("1")) @@ -1464,13 +1471,13 @@ mod tests { stage.run(&mut world); stage.run(&mut world); assert_eq!( - *world.resource::>(), + world.resource::().0, vec![0, 1, 2, 3, 0, 3, 0, 1, 2, 3, 0, 3] ); assert_eq!(stage.run_criteria.len(), 1); // Piping criteria. - world.resource_mut::>().clear(); + world.resource_mut::().0.clear(); fn eot_piped(input: In, has_ran: Local) -> ShouldRun { if let ShouldRun::Yes | ShouldRun::YesAndCheckAgain = input.0 { every_other_time(has_ran) @@ -1505,13 +1512,13 @@ mod tests { stage.run(&mut world); } assert_eq!( - *world.resource::>(), + world.resource::().0, vec![0, 1, 2, 3, 4, 0, 0, 1, 0, 0, 1, 2, 3, 4, 0, 0, 1, 0, 0, 1, 2, 3, 4] ); assert_eq!(stage.run_criteria.len(), 3); // Discarding extra criteria with matching labels. - world.resource_mut::>().clear(); + world.resource_mut::().0.clear(); let mut stage = SystemStage::parallel() .with_system(make_parallel(0).before("1")) @@ -1528,7 +1535,7 @@ mod tests { stage.run(&mut world); stage.run(&mut world); assert_eq!( - *world.resource::>(), + world.resource::().0, vec![0, 1, 2, 3, 0, 3, 0, 1, 2, 3, 0, 3] ); assert_eq!(stage.run_criteria.len(), 1); @@ -1548,7 +1555,7 @@ mod tests { #[should_panic] fn parallel_cycle_1() { let mut world = World::new(); - world.insert_resource(Vec::::new()); + world.init_resource::(); let mut stage = SystemStage::parallel().with_system(make_parallel(0).label("0").after("0")); stage.run(&mut world); } @@ -1557,7 +1564,7 @@ mod tests { #[should_panic] fn parallel_cycle_2() { let mut world = World::new(); - world.insert_resource(Vec::::new()); + world.init_resource::(); let mut stage = SystemStage::parallel() .with_system(make_parallel(0).label("0").after("1")) .with_system(make_parallel(1).label("1").after("0")); @@ -1569,7 +1576,7 @@ mod tests { fn parallel_cycle_3() { let mut world = World::new(); - world.insert_resource(Vec::::new()); + world.init_resource::(); let mut stage = SystemStage::parallel() .with_system(make_parallel(0).label("0")) .with_system(make_parallel(1).after("0").before("2")) @@ -1606,7 +1613,7 @@ mod tests { } fn empty() {} - fn resource(_: ResMut) {} + fn resource(_: ResMut) {} fn component(_: Query<&mut W>) {} let mut world = World::new(); @@ -1976,47 +1983,41 @@ mod tests { #[test] fn archetype_update_single_executor() { - fn query_count_system( - mut entity_count: ResMut, - query: Query, - ) { - *entity_count = query.iter().count(); + fn query_count_system(mut entity_count: ResMut, query: Query) { + *entity_count = R(query.iter().count()); } let mut world = World::new(); - world.insert_resource(0_usize); + world.insert_resource(R(0)); let mut stage = SystemStage::single(query_count_system); let entity = world.spawn().insert_bundle(()).id(); stage.run(&mut world); - assert_eq!(*world.resource::(), 1); + assert_eq!(world.resource::().0, 1); world.get_entity_mut(entity).unwrap().insert(W(1)); stage.run(&mut world); - assert_eq!(*world.resource::(), 1); + assert_eq!(world.resource::().0, 1); } #[test] fn archetype_update_parallel_executor() { - fn query_count_system( - mut entity_count: ResMut, - query: Query, - ) { - *entity_count = query.iter().count(); + fn query_count_system(mut entity_count: ResMut, query: Query) { + *entity_count = R(query.iter().count()); } let mut world = World::new(); - world.insert_resource(0_usize); + world.insert_resource(R(0)); let mut stage = SystemStage::parallel(); stage.add_system(query_count_system); let entity = world.spawn().insert_bundle(()).id(); stage.run(&mut world); - assert_eq!(*world.resource::(), 1); + assert_eq!(world.resource::().0, 1); world.get_entity_mut(entity).unwrap().insert(W(1)); stage.run(&mut world); - assert_eq!(*world.resource::(), 1); + assert_eq!(world.resource::().0, 1); } #[test] @@ -2038,12 +2039,12 @@ mod tests { commands.spawn().insert(Foo); } - fn count_entities(query: Query<&Foo>, mut res: ResMut>) { - res.push(query.iter().len()); + fn count_entities(query: Query<&Foo>, mut res: ResMut) { + res.0.push(query.iter().len()); } let mut world = World::new(); - world.insert_resource(Vec::::new()); + world.init_resource::(); let mut stage = SystemStage::parallel() .with_system(spawn_entity.label("spawn")) .with_system_set( @@ -2055,7 +2056,7 @@ mod tests { stage.run(&mut world); stage.run(&mut world); stage.run(&mut world); - assert_eq!(*world.resource::>(), vec![0, 2]); + assert_eq!(world.resource::().0, vec![0, 2]); } #[test] @@ -2077,12 +2078,12 @@ mod tests { commands.spawn().insert(Foo); } - fn count_entities(query: Query<&Foo>, mut res: ResMut>) { - res.push(query.iter().len()); + fn count_entities(query: Query<&Foo>, mut res: ResMut) { + res.0.push(query.iter().len()); } let mut world = World::new(); - world.insert_resource(Vec::::new()); + world.init_resource::(); let mut stage_spawn = SystemStage::parallel().with_system(spawn_entity); let mut stage_count = SystemStage::parallel() .with_run_criteria(even_number_of_entities_critiera) @@ -2095,6 +2096,6 @@ mod tests { stage_spawn.run(&mut world); stage_count.run(&mut world); stage_spawn.run(&mut world); - assert_eq!(*world.resource::>(), vec![0, 2]); + assert_eq!(world.resource::().0, vec![0, 2]); } } diff --git a/crates/bevy_ecs/src/schedule/state.rs b/crates/bevy_ecs/src/schedule/state.rs index 1693f0adce7e3..6b6a84a1008c7 100644 --- a/crates/bevy_ecs/src/schedule/state.rs +++ b/crates/bevy_ecs/src/schedule/state.rs @@ -3,13 +3,15 @@ use crate::{ RunCriteriaDescriptor, RunCriteriaDescriptorCoercion, RunCriteriaLabel, ShouldRun, SystemSet, }, - system::{In, IntoChainSystem, Local, Res, ResMut}, + system::{In, IntoChainSystem, Local, Res, ResMut, Resource}, }; use std::{ any::TypeId, fmt::{self, Debug}, hash::Hash, }; +// Required for derive macros +use crate as bevy_ecs; pub trait StateData: Send + Sync + Clone + Eq + Debug + Hash + 'static {} impl StateData for T where T: Send + Sync + Clone + Eq + Debug + Hash + 'static {} @@ -21,7 +23,7 @@ impl StateData for T where T: Send + Sync + Clone + Eq + Debug + Hash + 'stat /// * Pop removes the current state, and unpauses the last paused state /// * Set replaces the active state with a new one /// * Replace unwinds the state stack, and replaces the entire stack with a single new state -#[derive(Debug)] +#[derive(Debug, Resource)] pub struct State { transition: Option>, /// The current states in the stack. @@ -531,9 +533,12 @@ mod test { #[test] fn state_test() { + #[derive(Resource, Default)] + struct NameList(Vec<&'static str>); + let mut world = World::default(); - world.insert_resource(Vec::<&'static str>::new()); + world.init_resource::(); world.insert_resource(State::new(MyState::S1)); let mut stage = SystemStage::parallel(); @@ -542,55 +547,55 @@ mod test { stage .add_system_set( State::on_enter_set(MyState::S1) - .with_system(|mut r: ResMut>| r.push("startup")), + .with_system(|mut r: ResMut| r.0.push("startup")), ) .add_system_set(State::on_update_set(MyState::S1).with_system( - |mut r: ResMut>, mut s: ResMut>| { - r.push("update S1"); + |mut r: ResMut, mut s: ResMut>| { + r.0.push("update S1"); s.overwrite_replace(MyState::S2).unwrap(); }, )) .add_system_set( State::on_enter_set(MyState::S2) - .with_system(|mut r: ResMut>| r.push("enter S2")), + .with_system(|mut r: ResMut| r.0.push("enter S2")), ) .add_system_set(State::on_update_set(MyState::S2).with_system( - |mut r: ResMut>, mut s: ResMut>| { - r.push("update S2"); + |mut r: ResMut, mut s: ResMut>| { + r.0.push("update S2"); s.overwrite_replace(MyState::S3).unwrap(); }, )) .add_system_set( State::on_exit_set(MyState::S2) - .with_system(|mut r: ResMut>| r.push("exit S2")), + .with_system(|mut r: ResMut| r.0.push("exit S2")), ) .add_system_set( State::on_enter_set(MyState::S3) - .with_system(|mut r: ResMut>| r.push("enter S3")), + .with_system(|mut r: ResMut| r.0.push("enter S3")), ) .add_system_set(State::on_update_set(MyState::S3).with_system( - |mut r: ResMut>, mut s: ResMut>| { - r.push("update S3"); + |mut r: ResMut, mut s: ResMut>| { + r.0.push("update S3"); s.overwrite_push(MyState::S4).unwrap(); }, )) .add_system_set( State::on_pause_set(MyState::S3) - .with_system(|mut r: ResMut>| r.push("pause S3")), + .with_system(|mut r: ResMut| r.0.push("pause S3")), ) .add_system_set(State::on_update_set(MyState::S4).with_system( - |mut r: ResMut>, mut s: ResMut>| { - r.push("update S4"); + |mut r: ResMut, mut s: ResMut>| { + r.0.push("update S4"); s.overwrite_push(MyState::S5).unwrap(); }, )) .add_system_set(State::on_inactive_update_set(MyState::S4).with_system( - (|mut r: ResMut>| r.push("inactive S4")).label("inactive s4"), + (|mut r: ResMut| r.0.push("inactive S4")).label("inactive s4"), )) .add_system_set( State::on_update_set(MyState::S5).with_system( - (|mut r: ResMut>, mut s: ResMut>| { - r.push("update S5"); + (|mut r: ResMut, mut s: ResMut>| { + r.0.push("update S5"); s.overwrite_push(MyState::S6).unwrap(); }) .after("inactive s4"), @@ -598,15 +603,15 @@ mod test { ) .add_system_set( State::on_inactive_update_set(MyState::S5).with_system( - (|mut r: ResMut>| r.push("inactive S5")) + (|mut r: ResMut| r.0.push("inactive S5")) .label("inactive s5") .after("inactive s4"), ), ) .add_system_set( State::on_update_set(MyState::S6).with_system( - (|mut r: ResMut>, mut s: ResMut>| { - r.push("update S6"); + (|mut r: ResMut, mut s: ResMut>| { + r.0.push("update S6"); s.overwrite_push(MyState::Final).unwrap(); }) .after("inactive s5"), @@ -614,11 +619,11 @@ mod test { ) .add_system_set( State::on_resume_set(MyState::S4) - .with_system(|mut r: ResMut>| r.push("resume S4")), + .with_system(|mut r: ResMut| r.0.push("resume S4")), ) .add_system_set( State::on_exit_set(MyState::S5) - .with_system(|mut r: ResMut>| r.push("exit S4")), + .with_system(|mut r: ResMut| r.0.push("exit S4")), ); const EXPECTED: &[&str] = &[ @@ -648,9 +653,9 @@ mod test { ]; stage.run(&mut world); - let mut collected = world.resource_mut::>(); + let mut collected = world.resource_mut::(); let mut count = 0; - for (found, expected) in collected.drain(..).zip(EXPECTED) { + for (found, expected) in collected.0.drain(..).zip(EXPECTED) { assert_eq!(found, *expected); count += 1; } @@ -669,26 +674,32 @@ mod test { Main, } - fn should_run_once(mut flag: ResMut, test_name: Res<&'static str>) { - assert!(!*flag, "{:?}", *test_name); - *flag = true; + #[derive(Resource)] + struct Flag(bool); + + #[derive(Resource)] + struct Name(&'static str); + + fn should_run_once(mut flag: ResMut, test_name: Res) { + assert!(!flag.0, "{:?}", test_name.0); + flag.0 = true; } let mut world = World::new(); world.insert_resource(State::new(AppState::Main)); - world.insert_resource(false); - world.insert_resource("control"); + world.insert_resource(Flag(false)); + world.insert_resource(Name("control")); let mut stage = SystemStage::parallel().with_system(should_run_once); stage.run(&mut world); - assert!(*world.resource::(), "after control"); + assert!(world.resource::().0, "after control"); - world.insert_resource(false); - world.insert_resource("test"); + world.insert_resource(Flag(false)); + world.insert_resource(Name("test")); let mut stage = SystemStage::parallel() .with_system_set(State::::get_driver()) .with_system(should_run_once); stage.run(&mut world); - assert!(*world.resource::(), "after test"); + assert!(world.resource::().0, "after test"); } #[test] @@ -706,8 +717,11 @@ mod test { EnterFinish, } + #[derive(Resource, Default)] + struct LoadStatusStack(Vec); + let mut world = World::new(); - world.insert_resource(Vec::::new()); + world.init_resource::(); world.insert_resource(State::new(LoadState::Load)); let mut stage = SystemStage::parallel(); @@ -717,15 +731,16 @@ mod test { stage .add_system_set( State::on_enter_set(LoadState::Load) - .with_system(|mut r: ResMut>| r.push(LoadStatus::EnterLoad)), + .with_system(|mut r: ResMut| r.0.push(LoadStatus::EnterLoad)), ) .add_system_set( State::on_exit_set(LoadState::Load) - .with_system(|mut r: ResMut>| r.push(LoadStatus::ExitLoad)), + .with_system(|mut r: ResMut| r.0.push(LoadStatus::ExitLoad)), ) .add_system_set( - State::on_enter_set(LoadState::Finish) - .with_system(|mut r: ResMut>| r.push(LoadStatus::EnterFinish)), + State::on_enter_set(LoadState::Finish).with_system( + |mut r: ResMut| r.0.push(LoadStatus::EnterFinish), + ), ); stage.run(&mut world); @@ -762,9 +777,9 @@ mod test { LoadStatus::EnterFinish, ]; - let mut collected = world.resource_mut::>(); + let mut collected = world.resource_mut::(); let mut count = 0; - for (found, expected) in collected.drain(..).zip(EXPECTED) { + for (found, expected) in collected.0.drain(..).zip(EXPECTED) { assert_eq!(found, *expected); count += 1; } diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index bf40e13fb98b1..d9af56557094f 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -799,7 +799,7 @@ mod tests { use crate::{ self as bevy_ecs, component::Component, - system::{CommandQueue, Commands}, + system::{CommandQueue, Commands, Resource}, world::World, }; use std::sync::{ @@ -826,7 +826,7 @@ mod tests { } } - #[derive(Component)] + #[derive(Component, Resource)] struct W(T); fn simple_command(world: &mut World) { @@ -937,21 +937,21 @@ mod tests { let mut queue = CommandQueue::default(); { let mut commands = Commands::new(&mut queue, &world); - commands.insert_resource(123); - commands.insert_resource(456.0); + commands.insert_resource(W(123i32)); + commands.insert_resource(W(456.0f64)); } queue.apply(&mut world); - assert!(world.contains_resource::()); - assert!(world.contains_resource::()); + assert!(world.contains_resource::>()); + assert!(world.contains_resource::>()); { let mut commands = Commands::new(&mut queue, &world); // test resource removal - commands.remove_resource::(); + commands.remove_resource::>(); } queue.apply(&mut world); - assert!(!world.contains_resource::()); - assert!(world.contains_resource::()); + assert!(!world.contains_resource::>()); + assert!(world.contains_resource::>()); } } diff --git a/crates/bevy_ecs/src/system/exclusive_system.rs b/crates/bevy_ecs/src/system/exclusive_system.rs index 46d2e9eb8c091..9cc166d257ea0 100644 --- a/crates/bevy_ecs/src/system/exclusive_system.rs +++ b/crates/bevy_ecs/src/system/exclusive_system.rs @@ -112,7 +112,7 @@ mod tests { entity::Entity, query::With, schedule::{Stage, SystemStage}, - system::{Commands, IntoExclusiveSystem, Query, ResMut}, + system::{Commands, IntoExclusiveSystem, Query, ResMut, Resource}, world::World, }; @@ -123,49 +123,55 @@ mod tests { fn parallel_with_commands_as_exclusive() { let mut world = World::new(); + #[derive(Resource)] + struct Counter(usize); + fn removal( mut commands: Commands, query: Query>, - mut counter: ResMut, + mut counter: ResMut, ) { for entity in query.iter() { - *counter += 1; + counter.0 += 1; commands.entity(entity).remove::(); } } let mut stage = SystemStage::parallel().with_system(removal); world.spawn().insert(Foo(0.0f32)); - world.insert_resource(0usize); + world.insert_resource(Counter(0)); stage.run(&mut world); stage.run(&mut world); - assert_eq!(*world.resource::(), 1); + assert_eq!(world.resource::().0, 1); let mut stage = SystemStage::parallel().with_system(removal.exclusive_system()); world.spawn().insert(Foo(0.0f32)); - world.insert_resource(0usize); + world.insert_resource(Counter(0)); stage.run(&mut world); stage.run(&mut world); - assert_eq!(*world.resource::(), 1); + assert_eq!(world.resource::().0, 1); } #[test] fn update_archetype_for_exclusive_system_coerced() { + #[derive(Resource, Default)] + struct CountEntities(Vec); + fn spawn_entity(mut commands: crate::prelude::Commands) { commands.spawn().insert(Foo(0.0)); } - fn count_entities(query: Query<&Foo>, mut res: ResMut>) { - res.push(query.iter().len()); + fn count_entities(query: Query<&Foo>, mut res: ResMut) { + res.0.push(query.iter().len()); } let mut world = World::new(); - world.insert_resource(Vec::::new()); + world.init_resource::(); let mut stage = SystemStage::parallel() .with_system(spawn_entity) .with_system(count_entities.exclusive_system()); stage.run(&mut world); stage.run(&mut world); - assert_eq!(*world.resource::>(), vec![0, 1]); + assert_eq!(world.resource::().0, vec![0, 1]); } } diff --git a/crates/bevy_ecs/src/system/mod.rs b/crates/bevy_ecs/src/system/mod.rs index 04d14f9afe652..2e97165ea4714 100644 --- a/crates/bevy_ecs/src/system/mod.rs +++ b/crates/bevy_ecs/src/system/mod.rs @@ -111,22 +111,28 @@ mod tests { schedule::{Schedule, Stage, SystemStage}, system::{ Commands, IntoExclusiveSystem, IntoSystem, Local, NonSend, NonSendMut, ParamSet, Query, - RemovedComponents, Res, ResMut, System, SystemState, + RemovedComponents, Res, ResMut, Resource, System, SystemState, }, world::{FromWorld, World}, }; - #[derive(Component, Debug, Eq, PartialEq, Default)] + #[derive(Resource, PartialEq, Debug)] + enum SystemRan { + Yes, + No, + } + + #[derive(Component, Resource, Debug, Eq, PartialEq, Default)] struct A; - #[derive(Component)] + #[derive(Component, Resource)] struct B; - #[derive(Component)] + #[derive(Component, Resource)] struct C; - #[derive(Component)] + #[derive(Component, Resource)] struct D; - #[derive(Component)] + #[derive(Component, Resource)] struct E; - #[derive(Component)] + #[derive(Component, Resource)] struct F; #[derive(Component)] @@ -159,7 +165,7 @@ mod tests { #[test] fn query_system_gets() { fn query_system( - mut ran: ResMut, + mut ran: ResMut, entity_query: Query>, b_query: Query<&B>, a_c_query: Query<(&A, &C)>, @@ -199,11 +205,11 @@ mod tests { "entity 3 should have D" ); - *ran = true; + *ran = SystemRan::Yes; } let mut world = World::default(); - world.insert_resource(false); + world.insert_resource(SystemRan::No); world.spawn().insert_bundle((A,)); world.spawn().insert_bundle((A, B)); world.spawn().insert_bundle((A, C)); @@ -211,14 +217,14 @@ mod tests { run_system(&mut world, query_system); - assert!(*world.resource::(), "system ran"); + assert_eq!(*world.resource::(), SystemRan::Yes); } #[test] fn or_param_set_system() { // Regression test for issue #762 fn query_system( - mut ran: ResMut, + mut ran: ResMut, mut set: ParamSet<( Query<(), Or<(Changed, Changed)>>, Query<(), Or<(Added, Added)>>, @@ -230,24 +236,33 @@ mod tests { assert_eq!(changed, 1); assert_eq!(added, 1); - *ran = true; + *ran = SystemRan::Yes; } let mut world = World::default(); - world.insert_resource(false); + world.insert_resource(SystemRan::No); world.spawn().insert_bundle((A, B)); run_system(&mut world, query_system); - assert!(*world.resource::(), "system ran"); + assert_eq!(*world.resource::(), SystemRan::Yes); } #[test] fn changed_resource_system() { + use crate::system::Resource; + + #[derive(Resource)] + struct Flipper(bool); + + #[derive(Resource)] struct Added(usize); + + #[derive(Resource)] struct Changed(usize); + fn incr_e_on_flip( - value: Res, + value: Res, mut changed: ResMut, mut added: ResMut, ) { @@ -261,7 +276,7 @@ mod tests { } let mut world = World::default(); - world.insert_resource(false); + world.insert_resource(Flipper(false)); world.insert_resource(Added(0)); world.insert_resource(Changed(0)); @@ -282,7 +297,7 @@ mod tests { assert_eq!(world.resource::().0, 1); assert_eq!(world.resource::().0, 1); - *world.resource_mut::() = true; + world.resource_mut::().0 = true; schedule.run(&mut world); assert_eq!(world.resource::().0, 1); assert_eq!(world.resource::().0, 2); @@ -406,7 +421,7 @@ mod tests { run_system(&mut world, sys); } - #[derive(Default)] + #[derive(Default, Resource)] struct BufferRes { _buffer: Vec, } @@ -449,36 +464,42 @@ mod tests { #[test] fn local_system() { let mut world = World::default(); - world.insert_resource(1u32); - world.insert_resource(false); + world.insert_resource(ProtoFoo { value: 1 }); + world.insert_resource(SystemRan::No); + struct Foo { value: u32, } + #[derive(Resource)] + struct ProtoFoo { + value: u32, + } + impl FromWorld for Foo { fn from_world(world: &mut World) -> Self { Foo { - value: *world.resource::() + 1, + value: world.resource::().value + 1, } } } - fn sys(local: Local, mut modified: ResMut) { + fn sys(local: Local, mut system_ran: ResMut) { assert_eq!(local.value, 2); - *modified = true; + *system_ran = SystemRan::Yes; } run_system(&mut world, sys); // ensure the system actually ran - assert!(*world.resource::()); + assert_eq!(*world.resource::(), SystemRan::Yes); } #[test] fn non_send_option_system() { let mut world = World::default(); - world.insert_resource(false); + world.insert_resource(SystemRan::No); struct NotSend1(std::rc::Rc); struct NotSend2(std::rc::Rc); world.insert_non_send_resource(NotSend1(std::rc::Rc::new(0))); @@ -486,34 +507,38 @@ mod tests { fn sys( op: Option>, mut _op2: Option>, - mut run: ResMut, + mut system_ran: ResMut, ) { op.expect("NonSend should exist"); - *run = true; + *system_ran = SystemRan::Yes; } run_system(&mut world, sys); // ensure the system actually ran - assert!(*world.resource::()); + assert_eq!(*world.resource::(), SystemRan::Yes); } #[test] fn non_send_system() { let mut world = World::default(); - world.insert_resource(false); + world.insert_resource(SystemRan::No); struct NotSend1(std::rc::Rc); struct NotSend2(std::rc::Rc); world.insert_non_send_resource(NotSend1(std::rc::Rc::new(1))); world.insert_non_send_resource(NotSend2(std::rc::Rc::new(2))); - fn sys(_op: NonSend, mut _op2: NonSendMut, mut run: ResMut) { - *run = true; + fn sys( + _op: NonSend, + mut _op2: NonSendMut, + mut system_ran: ResMut, + ) { + *system_ran = SystemRan::Yes; } run_system(&mut world, sys); - assert!(*world.resource::()); + assert_eq!(*world.resource::(), SystemRan::Yes); } #[test] @@ -525,13 +550,16 @@ mod tests { let spurious_entity = world.spawn().id(); // Track which entities we want to operate on + #[derive(Resource)] struct Despawned(Entity); world.insert_resource(Despawned(entity_to_despawn)); + + #[derive(Resource)] struct Removed(Entity); world.insert_resource(Removed(entity_to_remove_w_from)); // Verify that all the systems actually ran - #[derive(Default)] + #[derive(Default, Resource)] struct NSystems(usize); world.insert_resource(NSystems::default()); @@ -587,7 +615,7 @@ mod tests { #[test] fn world_collections_system() { let mut world = World::default(); - world.insert_resource(false); + world.insert_resource(SystemRan::No); world.spawn().insert_bundle((W(42), W(true))); fn sys( archetypes: &Archetypes, @@ -595,7 +623,7 @@ mod tests { entities: &Entities, bundles: &Bundles, query: Query>>, - mut modified: ResMut, + mut system_ran: ResMut, ) { assert_eq!(query.iter().count(), 1, "entity exists"); for entity in query.iter() { @@ -619,13 +647,13 @@ mod tests { "entity's bundle components exactly match entity's archetype components" ); } - *modified = true; + *system_ran = SystemRan::Yes; } run_system(&mut world, sys); // ensure the system actually ran - assert!(*world.resource::()); + assert_eq!(*world.resource::(), SystemRan::Yes); } #[test] @@ -723,7 +751,7 @@ mod tests { #[test] fn read_system_state() { - #[derive(Eq, PartialEq, Debug)] + #[derive(Eq, PartialEq, Debug, Resource)] struct A(usize); #[derive(Component, Eq, PartialEq, Debug)] @@ -746,7 +774,7 @@ mod tests { #[test] fn write_system_state() { - #[derive(Eq, PartialEq, Debug)] + #[derive(Resource, Eq, PartialEq, Debug)] struct A(usize); #[derive(Component, Eq, PartialEq, Debug)] diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index 60c9c56ac7717..240caad94aae2 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -1,4 +1,5 @@ pub use crate::change_detection::{NonSendMut, ResMut}; +pub use bevy_ecs_macros::Resource; use crate::{ archetype::{Archetype, Archetypes}, bundle::Bundles, @@ -221,11 +222,18 @@ pub struct ParamSetState SystemParamFetch<'w, 's>>(T); impl_param_set!(); +/// A type that can be inserted into a [`World`](crate::world::World) as a singleton. +/// +/// Resources are commonly used to store global collections (like assets or events), +/// or unique global information (such as the current level or state of the app). +/// +/// You can access resource data in systems using the [`Res`] and [`ResMut`] system parameters. +/// +/// Only one resource of each type can exist at any given time. +/// Inserting a duplicate resource will overwrite the existing resource. pub trait Resource: Send + Sync + 'static {} -impl Resource for T where T: Send + Sync + 'static {} - -/// Shared borrow of a resource. +/// Shared borrow of a [`Resource`]. /// /// See the [`World`] documentation to see the usage of a resource. /// @@ -639,12 +647,12 @@ impl<'w, 's> SystemParamFetch<'w, 's> for WorldState { /// // .add_system(reset_to_system(my_config)) /// # assert_is_system(reset_to_system(Config(10))); /// ``` -pub struct Local<'a, T: Resource>(&'a mut T); +pub struct Local<'a, T: Send + Sync + 'static>(&'a mut T); // SAFE: Local only accesses internal state -unsafe impl ReadOnlySystemParamFetch for LocalState {} +unsafe impl ReadOnlySystemParamFetch for LocalState {} -impl<'a, T: Resource> Debug for Local<'a, T> +impl<'a, T: Send + Sync + 'static> Debug for Local<'a, T> where T: Debug, { @@ -653,7 +661,7 @@ where } } -impl<'a, T: Resource> Deref for Local<'a, T> { +impl<'a, T: Send + Sync + 'static> Deref for Local<'a, T> { type Target = T; #[inline] @@ -662,7 +670,7 @@ impl<'a, T: Resource> Deref for Local<'a, T> { } } -impl<'a, T: Resource> DerefMut for Local<'a, T> { +impl<'a, T: Send + Sync + 'static> DerefMut for Local<'a, T> { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { self.0 @@ -671,20 +679,20 @@ impl<'a, T: Resource> DerefMut for Local<'a, T> { /// The [`SystemParamState`] of [`Local`]. #[doc(hidden)] -pub struct LocalState(T); +pub struct LocalState(T); -impl<'a, T: Resource + FromWorld> SystemParam for Local<'a, T> { +impl<'a, T: Send + Sync + 'static + FromWorld> SystemParam for Local<'a, T> { type Fetch = LocalState; } // SAFE: only local state is accessed -unsafe impl SystemParamState for LocalState { +unsafe impl SystemParamState for LocalState { fn init(world: &mut World, _system_meta: &mut SystemMeta) -> Self { Self(T::from_world(world)) } } -impl<'w, 's, T: Resource + FromWorld> SystemParamFetch<'w, 's> for LocalState { +impl<'w, 's, T: Send + Sync + 'static + FromWorld> SystemParamFetch<'w, 's> for LocalState { type Item = Local<'s, T>; #[inline] diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index 71ee4c7a3716b..f7160cb2fd034 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -1509,6 +1509,7 @@ mod tests { change_detection::DetectChanges, component::{ComponentDescriptor, ComponentId, StorageType}, ptr::OwningPtr, + system::Resource, }; use bevy_ecs_macros::Component; use std::{ @@ -1635,7 +1636,7 @@ mod tests { ); } - #[derive(Component)] + #[derive(Resource)] struct TestResource(u32); #[test] diff --git a/crates/bevy_ecs/src/world/world_cell.rs b/crates/bevy_ecs/src/world/world_cell.rs index 5a1fff6cdf9a2..96f8a9348fb6a 100644 --- a/crates/bevy_ecs/src/world/world_cell.rs +++ b/crates/bevy_ecs/src/world/world_cell.rs @@ -318,40 +318,46 @@ impl<'w> WorldCell<'w> { #[cfg(test)] mod tests { use super::BASE_ACCESS; - use crate::{archetype::ArchetypeId, world::World}; + use crate as bevy_ecs; + use crate::{archetype::ArchetypeId, system::Resource, world::World}; use std::any::TypeId; + #[derive(Resource)] + struct A(u32); + #[derive(Resource)] + struct B(u64); + #[test] fn world_cell() { let mut world = World::default(); - world.insert_resource(1u32); - world.insert_resource(1u64); + world.insert_resource(A(1)); + world.insert_resource(B(1)); let cell = world.cell(); { - let mut a = cell.resource_mut::(); - assert_eq!(1, *a); - *a = 2; + let mut a = cell.resource_mut::(); + assert_eq!(1, a.0); + a.0 = 2; } { - let a = cell.resource::(); - assert_eq!(2, *a, "ensure access is dropped"); + let a = cell.resource::(); + assert_eq!(2, a.0, "ensure access is dropped"); - let b = cell.resource::(); + let a2 = cell.resource::(); assert_eq!( - 2, *b, + 2, a2.0, "ensure multiple immutable accesses can occur at the same time" ); } { - let a = cell.resource_mut::(); + let a = cell.resource_mut::(); assert_eq!( - 2, *a, + 2, a.0, "ensure both immutable accesses are dropped, enabling a new mutable access" ); - let b = cell.resource::(); + let b = cell.resource::(); assert_eq!( - 1, *b, + 1, b.0, "ensure multiple non-conflicting mutable accesses can occur at the same time" ); } @@ -360,13 +366,13 @@ mod tests { #[test] fn world_access_reused() { let mut world = World::default(); - world.insert_resource(1u32); + world.insert_resource(A(1)); { let cell = world.cell(); { - let mut a = cell.resource_mut::(); - assert_eq!(1, *a); - *a = 2; + let mut a = cell.resource_mut::(); + assert_eq!(1, a.0); + a.0 = 2; } } @@ -393,39 +399,39 @@ mod tests { #[should_panic] fn world_cell_double_mut() { let mut world = World::default(); - world.insert_resource(1u32); + world.insert_resource(A(1)); let cell = world.cell(); - let _value_a = cell.resource_mut::(); - let _value_b = cell.resource_mut::(); + let _value_a = cell.resource_mut::(); + let _value_b = cell.resource_mut::(); } #[test] #[should_panic] fn world_cell_ref_and_mut() { let mut world = World::default(); - world.insert_resource(1u32); + world.insert_resource(A(1)); let cell = world.cell(); - let _value_a = cell.resource::(); - let _value_b = cell.resource_mut::(); + let _value_a = cell.resource::(); + let _value_b = cell.resource_mut::(); } #[test] #[should_panic] fn world_cell_mut_and_ref() { let mut world = World::default(); - world.insert_resource(1u32); + world.insert_resource(A(1)); let cell = world.cell(); - let _value_a = cell.resource_mut::(); - let _value_b = cell.resource::(); + let _value_a = cell.resource_mut::(); + let _value_b = cell.resource::(); } #[test] #[should_panic] fn world_cell_ref_and_ref() { let mut world = World::default(); - world.insert_resource(1u32); + world.insert_resource(A(1)); let cell = world.cell(); - let _value_a = cell.resource_mut::(); - let _value_b = cell.resource::(); + let _value_a = cell.resource_mut::(); + let _value_b = cell.resource::(); } } diff --git a/crates/bevy_input/src/axis.rs b/crates/bevy_input/src/axis.rs index 5ba80f3ee9c92..228365f16bdff 100644 --- a/crates/bevy_input/src/axis.rs +++ b/crates/bevy_input/src/axis.rs @@ -1,10 +1,11 @@ +use bevy_ecs::system::Resource; use bevy_utils::HashMap; use std::hash::Hash; /// Stores the position data of the input devices of type `T`. /// /// The values are stored as `f32`s, which range from [`Axis::MIN`] to [`Axis::MAX`], inclusive. -#[derive(Debug)] +#[derive(Debug, Resource)] pub struct Axis { /// The position data of the input devices. axis_data: HashMap, diff --git a/crates/bevy_input/src/gamepad.rs b/crates/bevy_input/src/gamepad.rs index 5fd06285a0b70..a29cc3a1546da 100644 --- a/crates/bevy_input/src/gamepad.rs +++ b/crates/bevy_input/src/gamepad.rs @@ -1,6 +1,6 @@ use crate::{Axis, Input}; use bevy_ecs::event::{EventReader, EventWriter}; -use bevy_ecs::system::{Res, ResMut}; +use bevy_ecs::system::{Res, ResMut, Resource}; use bevy_utils::{tracing::info, HashMap, HashSet}; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -15,7 +15,7 @@ impl Gamepad { } } -#[derive(Default)] +#[derive(Default, Resource)] /// Container of unique connected [`Gamepad`]s /// /// [`Gamepad`]s are registered and deregistered in [`gamepad_connection_system`] @@ -152,7 +152,7 @@ impl GamepadAxis { } } -#[derive(Default, Debug)] +#[derive(Default, Debug, Resource)] pub struct GamepadSettings { pub default_button_settings: ButtonSettings, pub default_axis_settings: AxisSettings, diff --git a/crates/bevy_input/src/input.rs b/crates/bevy_input/src/input.rs index 0c654af0ce92e..1a1078fee9f75 100644 --- a/crates/bevy_input/src/input.rs +++ b/crates/bevy_input/src/input.rs @@ -1,3 +1,4 @@ +use bevy_ecs::system::Resource; use bevy_utils::HashSet; use std::hash::Hash; @@ -32,7 +33,7 @@ use bevy_ecs::schedule::State; /// * Call the [`Input::press`] method for each press event. /// * Call the [`Input::release`] method for each release event. /// * Call the [`Input::clear`] method at each frame start, before processing events. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Resource)] pub struct Input { /// A collection of every button that is currently being pressed. pressed: HashSet, diff --git a/crates/bevy_input/src/touch.rs b/crates/bevy_input/src/touch.rs index 4ba55c0118967..0018d6e90662d 100644 --- a/crates/bevy_input/src/touch.rs +++ b/crates/bevy_input/src/touch.rs @@ -1,5 +1,5 @@ use bevy_ecs::event::EventReader; -use bevy_ecs::system::ResMut; +use bevy_ecs::system::{ResMut, Resource}; use bevy_math::Vec2; use bevy_utils::HashMap; @@ -201,7 +201,7 @@ impl From<&TouchInput> for Touch { /// ## Updating /// /// The resource is updated inside of the [`touch_screen_input_system`](crate::touch::touch_screen_input_system). -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Default, Resource)] pub struct Touches { /// A collection of every [`Touch`] that is currently being pressed. pressed: HashMap, diff --git a/crates/bevy_log/Cargo.toml b/crates/bevy_log/Cargo.toml index affd19cc7d19e..381b4e6a198ea 100644 --- a/crates/bevy_log/Cargo.toml +++ b/crates/bevy_log/Cargo.toml @@ -13,6 +13,7 @@ trace = [ "tracing-error" ] [dependencies] bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } tracing-subscriber = {version = "0.3.1", features = ["registry", "env-filter"]} diff --git a/crates/bevy_log/src/lib.rs b/crates/bevy_log/src/lib.rs index 0259aafd71457..5a8773c9d18aa 100644 --- a/crates/bevy_log/src/lib.rs +++ b/crates/bevy_log/src/lib.rs @@ -30,6 +30,8 @@ pub use bevy_utils::tracing::{ Level, }; +use bevy_ecs::prelude::Resource; + use bevy_app::{App, Plugin}; use tracing_log::LogTracer; #[cfg(feature = "tracing-chrome")] @@ -91,6 +93,7 @@ use tracing_subscriber::{prelude::*, registry::Registry, EnvFilter}; pub struct LogPlugin; /// `LogPlugin` settings +#[derive(Resource)] pub struct LogSettings { /// Filters logs using the [`EnvFilter`] format pub filter: String, diff --git a/crates/bevy_render/src/extract_component.rs b/crates/bevy_render/src/extract_component.rs index 673b23c30770e..3f5479ec5a684 100644 --- a/crates/bevy_render/src/extract_component.rs +++ b/crates/bevy_render/src/extract_component.rs @@ -69,6 +69,7 @@ impl Plugin for UniformComponentP } /// Stores all uniforms of the component type. +#[derive(Resource)] pub struct ComponentUniforms { uniforms: DynamicUniformBuffer, } diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 0caa1a75bc29c..09791908acf5a 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -79,7 +79,7 @@ pub enum RenderStage { } /// The Render App World. This is only available as a resource during the Extract step. -#[derive(Default)] +#[derive(Default, Resource)] pub struct RenderWorld(World); impl Deref for RenderWorld { diff --git a/crates/bevy_render/src/render_asset.rs b/crates/bevy_render/src/render_asset.rs index 22936f3e677be..7abe582722ff7 100644 --- a/crates/bevy_render/src/render_asset.rs +++ b/crates/bevy_render/src/render_asset.rs @@ -106,6 +106,7 @@ impl Plugin for RenderAssetPlugin { } /// Temporarily stores the extracted and removed assets of the current frame. +#[derive(Resource)] pub struct ExtractedAssets { extracted: Vec<(Handle, A::ExtractedAsset)>, removed: Vec>, @@ -160,6 +161,7 @@ fn extract_render_asset( // TODO: consider storing inside system? /// All assets that should be prepared next frame. +#[derive(Resource)] pub struct PrepareNextFrameAssets { assets: Vec<(Handle, A::ExtractedAsset)>, } diff --git a/crates/bevy_render/src/renderer/render_device.rs b/crates/bevy_render/src/renderer/render_device.rs index 4430e7001273f..2a42d1157bfa3 100644 --- a/crates/bevy_render/src/renderer/render_device.rs +++ b/crates/bevy_render/src/renderer/render_device.rs @@ -2,6 +2,7 @@ use crate::render_resource::{ BindGroup, BindGroupLayout, Buffer, ComputePipeline, RawRenderPipelineDescriptor, RenderPipeline, Sampler, Texture, }; +use bevy_ecs::system::Resource; use futures_lite::future; use std::sync::Arc; use wgpu::{util::DeviceExt, BufferBindingType}; @@ -9,7 +10,7 @@ use wgpu::{util::DeviceExt, BufferBindingType}; use super::RenderQueue; /// This GPU device is responsible for the creation of most rendering and compute resources. -#[derive(Clone)] +#[derive(Clone, Resource)] pub struct RenderDevice { device: Arc, } diff --git a/crates/bevy_render/src/texture/image.rs b/crates/bevy_render/src/texture/image.rs index f898140acbd73..701bc83d580e7 100644 --- a/crates/bevy_render/src/texture/image.rs +++ b/crates/bevy_render/src/texture/image.rs @@ -14,7 +14,7 @@ use crate::{ }; use bevy_asset::HandleUntyped; use bevy_derive::{Deref, DerefMut}; -use bevy_ecs::system::{lifetimeless::SRes, SystemParamItem}; +use bevy_ecs::system::{lifetimeless::SRes, Resource, SystemParamItem}; use bevy_math::Vec2; use bevy_reflect::TypeUuid; use std::hash::Hash; @@ -148,7 +148,7 @@ impl ImageSampler { /// Resource used as the global default image sampler for [`Image`]s with their `sampler_descriptor` /// set to [`ImageSampler::Default`]. -#[derive(Debug, Clone, Deref, DerefMut)] +#[derive(Debug, Clone, Deref, DerefMut, Resource)] pub struct DefaultImageSampler(pub(crate) Sampler); impl Default for Image { diff --git a/crates/bevy_render/src/view/mod.rs b/crates/bevy_render/src/view/mod.rs index 2638e94d4581a..f45789bc81132 100644 --- a/crates/bevy_render/src/view/mod.rs +++ b/crates/bevy_render/src/view/mod.rs @@ -45,7 +45,7 @@ impl Plugin for ViewPlugin { } } -#[derive(Clone, ExtractResource)] +#[derive(Clone, Resource, ExtractResource)] /// Configuration resource for [Multi-Sample Anti-Aliasing](https://en.wikipedia.org/wiki/Multisample_anti-aliasing). /// /// # Example diff --git a/crates/bevy_render/src/view/window.rs b/crates/bevy_render/src/view/window.rs index 305a56ddd115b..d8d4d379f0af4 100644 --- a/crates/bevy_render/src/view/window.rs +++ b/crates/bevy_render/src/view/window.rs @@ -48,7 +48,7 @@ pub struct ExtractedWindow { pub size_changed: bool, } -#[derive(Default)] +#[derive(Default, Resource)] pub struct ExtractedWindows { pub windows: HashMap, } diff --git a/crates/bevy_scene/src/scene_spawner.rs b/crates/bevy_scene/src/scene_spawner.rs index dd6cf489f195d..4b6fc9c17f2df 100644 --- a/crates/bevy_scene/src/scene_spawner.rs +++ b/crates/bevy_scene/src/scene_spawner.rs @@ -4,7 +4,7 @@ use bevy_ecs::{ entity::{Entity, EntityMap}, event::{Events, ManualEventReader}, reflect::{ReflectComponent, ReflectMapEntities}, - system::Command, + system::{Command, Resource}, world::{Mut, World}, }; use bevy_hierarchy::{AddChild, Parent}; @@ -27,7 +27,7 @@ impl InstanceId { } } -#[derive(Default)] +#[derive(Default, Resource)] pub struct SceneSpawner { spawned_scenes: HashMap, Vec>, spawned_dynamic_scenes: HashMap, Vec>, diff --git a/crates/bevy_time/src/fixed_timestep.rs b/crates/bevy_time/src/fixed_timestep.rs index d79f4e6ccf0f3..62a2e3020eb31 100644 --- a/crates/bevy_time/src/fixed_timestep.rs +++ b/crates/bevy_time/src/fixed_timestep.rs @@ -4,7 +4,7 @@ use bevy_ecs::{ component::ComponentId, query::Access, schedule::ShouldRun, - system::{IntoSystem, Res, ResMut, System}, + system::{IntoSystem, Res, ResMut, Resource, System}, world::World, }; use bevy_utils::HashMap; @@ -41,7 +41,7 @@ impl FixedTimestepState { /// A global resource that tracks the individual [`FixedTimestepState`]s /// for every labeled [`FixedTimestep`]. -#[derive(Default)] +#[derive(Default, Resource)] pub struct FixedTimesteps { fixed_timesteps: HashMap, } @@ -234,7 +234,8 @@ mod test { use std::ops::{Add, Mul}; use std::time::Duration; - type Count = usize; + #[derive(Resource)] + struct Count(usize); const LABEL: &str = "test_step"; #[test] @@ -245,7 +246,7 @@ mod test { time.update_with_instant(instance); world.insert_resource(time); world.insert_resource(FixedTimesteps::default()); - world.insert_resource::(0); + world.insert_resource(Count(0)); let mut schedule = Schedule::default(); schedule.add_stage( @@ -258,30 +259,30 @@ mod test { // if time does not progress, the step does not run schedule.run(&mut world); schedule.run(&mut world); - assert_eq!(0, *world.resource::()); + assert_eq!(0, world.resource::().0); assert_eq!(0., get_accumulator_deciseconds(&world)); // let's progress less than one step advance_time(&mut world, instance, 0.4); schedule.run(&mut world); - assert_eq!(0, *world.resource::()); + assert_eq!(0, world.resource::().0); assert_eq!(4., get_accumulator_deciseconds(&world)); // finish the first step with 0.1s above the step length advance_time(&mut world, instance, 0.6); schedule.run(&mut world); - assert_eq!(1, *world.resource::()); + assert_eq!(1, world.resource::().0); assert_eq!(1., get_accumulator_deciseconds(&world)); // runs multiple times if the delta is multiple step lengths advance_time(&mut world, instance, 1.7); schedule.run(&mut world); - assert_eq!(3, *world.resource::()); + assert_eq!(3, world.resource::().0); assert_eq!(2., get_accumulator_deciseconds(&world)); } fn fixed_update(mut count: ResMut) { - *count += 1; + count.0 += 1; } fn advance_time(world: &mut World, instance: Instant, seconds: f32) { diff --git a/crates/bevy_time/src/time.rs b/crates/bevy_time/src/time.rs index 179eb74073b70..dbb6649864bce 100644 --- a/crates/bevy_time/src/time.rs +++ b/crates/bevy_time/src/time.rs @@ -1,7 +1,8 @@ +use bevy_ecs::system::Resource; use bevy_utils::{Duration, Instant}; /// Tracks elapsed time since the last update and since the App has started -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Resource)] pub struct Time { delta: Duration, last_update: Option, diff --git a/crates/bevy_window/src/window.rs b/crates/bevy_window/src/window.rs index 19aa6cbbb8267..1b50b186b2f1b 100644 --- a/crates/bevy_window/src/window.rs +++ b/crates/bevy_window/src/window.rs @@ -1,3 +1,4 @@ +use bevy_ecs::system::Resource; use bevy_math::{DVec2, IVec2, Vec2}; use bevy_utils::{tracing::warn, Uuid}; use raw_window_handle::RawWindowHandle; @@ -632,7 +633,7 @@ impl Window { /// See [`examples/window/window_settings.rs`] for usage. /// /// [`examples/window/window_settings.rs`]: https://github.com/bevyengine/bevy/blob/latest/examples/window/window_settings.rs -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Resource)] pub struct WindowDescriptor { /// The requested logical width of the window's client area. /// May vary from the physical width due to different pixel density on different monitors. diff --git a/crates/bevy_window/src/windows.rs b/crates/bevy_window/src/windows.rs index df20688018133..2916c2f815761 100644 --- a/crates/bevy_window/src/windows.rs +++ b/crates/bevy_window/src/windows.rs @@ -1,8 +1,9 @@ use super::{Window, WindowId}; +use bevy_ecs::prelude::Resource; use bevy_utils::HashMap; /// A collection of [`Window`]s with unique [`WindowId`]s. -#[derive(Debug, Default)] +#[derive(Debug, Default, Resource)] pub struct Windows { windows: HashMap, } diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index 88e3f81126bea..fa050cfcee0b3 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -279,7 +279,7 @@ impl Default for WinitPersistentState { } } -#[derive(Default)] +#[derive(Default, Resource)] struct WinitCreateWindowReader(ManualEventReader); pub fn winit_runner_with(mut app: App) { diff --git a/crates/bevy_winit/src/winit_config.rs b/crates/bevy_winit/src/winit_config.rs index 9f40db04f2fc4..c1db2b2fd27e6 100644 --- a/crates/bevy_winit/src/winit_config.rs +++ b/crates/bevy_winit/src/winit_config.rs @@ -1,7 +1,8 @@ +use bevy_ecs::system::Resource; use bevy_utils::Duration; /// A resource for configuring usage of the `rust_winit` library. -#[derive(Debug)] +#[derive(Debug, Resource)] pub struct WinitSettings { /// Configures the winit library to return control to the main thread after the /// [run](bevy_app::App::run) loop is exited. Winit strongly recommends avoiding this when