mirror of
https://github.com/bevyengine/bevy
synced 2024-11-21 20:23:28 +00:00
Make Resource
trait opt-in, requiring #[derive(Resource)]
V2 (#5577)
*This PR description is an edited copy of #5007, written by @alice-i-cecile.* # Objective Follow-up to https://github.com/bevyengine/bevy/pull/2254. The `Resource` trait currently has a blanket implementation for all types that meet its bounds. While ergonomic, this results in several drawbacks: * it is possible to make confusing, silent mistakes such as inserting a function pointer (Foo) rather than a value (Foo::Bar) as a resource * it is challenging to discover if a type is intended to be used as a resource * we cannot later add customization options (see the [RFC](https://github.com/bevyengine/rfcs/blob/main/rfcs/27-derive-component.md) for the equivalent choice for Component). * dependencies can use the same Rust type as a resource in invisibly conflicting ways * raw Rust types used as resources cannot preserve privacy appropriately, as anyone able to access that type can read and write to internal values * we cannot capture a definitive list of possible resources to display to users in an editor ## Notes to reviewers * Review this commit-by-commit; there's effectively no back-tracking and there's a lot of churn in some of these commits. *ira: My commits are not as well organized :')* * I've relaxed the bound on Local to Send + Sync + 'static: I don't think these concerns apply there, so this can keep things simple. Storing e.g. a u32 in a Local is fine, because there's a variable name attached explaining what it does. * I think this is a bad place for the Resource trait to live, but I've left it in place to make reviewing easier. IMO that's best tackled with https://github.com/bevyengine/bevy/issues/4981. ## Changelog `Resource` is no longer automatically implemented for all matching types. Instead, use the new `#[derive(Resource)]` macro. ## Migration Guide Add `#[derive(Resource)]` to all types you are using as a resource. If you are using a third party type as a resource, wrap it in a tuple struct to bypass orphan rules. Consider deriving `Deref` and `DerefMut` to improve ergonomics. `ClearColor` no longer implements `Component`. Using `ClearColor` as a component in 0.8 did nothing. Use the `ClearColorConfig` in the `Camera3d` and `Camera2d` components instead. Co-authored-by: Alice <alice.i.cecile@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: devil-ira <justthecooldude@gmail.com> Co-authored-by: Carter Anderson <mcanders1@gmail.com>
This commit is contained in:
parent
2ac744331b
commit
992681b59b
133 changed files with 805 additions and 525 deletions
|
@ -1,6 +1,6 @@
|
|||
use bevy_ecs::{
|
||||
component::Component,
|
||||
prelude::{ParallelSystemDescriptorCoercion, Res, RunCriteriaDescriptorCoercion},
|
||||
prelude::{ParallelSystemDescriptorCoercion, Res, Resource, RunCriteriaDescriptorCoercion},
|
||||
schedule::{ShouldRun, Stage, SystemStage},
|
||||
system::Query,
|
||||
world::World,
|
||||
|
@ -136,7 +136,7 @@ pub fn run_criteria_no_with_labels(criterion: &mut Criterion) {
|
|||
group.finish();
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
#[derive(Component, Resource)]
|
||||
struct TestBool(pub bool);
|
||||
|
||||
pub fn run_criteria_yes_with_query(criterion: &mut Criterion) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::{CoreStage, Plugin, PluginGroup, PluginGroupBuilder, StartupSchedule, StartupStage};
|
||||
pub use bevy_derive::AppLabel;
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::{
|
||||
event::{Event, Events},
|
||||
prelude::{FromWorld, IntoExclusiveSystem},
|
||||
|
@ -22,6 +23,11 @@ bevy_utils::define_label!(
|
|||
AppLabelId,
|
||||
);
|
||||
|
||||
/// The [`Resource`] that stores the [`App`]'s [`TypeRegistry`](bevy_reflect::TypeRegistry).
|
||||
#[cfg(feature = "bevy_reflect")]
|
||||
#[derive(Resource, Clone, Deref, DerefMut, Default)]
|
||||
pub struct AppTypeRegistry(pub bevy_reflect::TypeRegistryArc);
|
||||
|
||||
#[allow(clippy::needless_doctest_main)]
|
||||
/// A container of app logic and data.
|
||||
///
|
||||
|
@ -74,7 +80,7 @@ impl Default for App {
|
|||
fn default() -> Self {
|
||||
let mut app = App::empty();
|
||||
#[cfg(feature = "bevy_reflect")]
|
||||
app.init_resource::<bevy_reflect::TypeRegistryArc>();
|
||||
app.init_resource::<AppTypeRegistry>();
|
||||
|
||||
app.add_default_stages()
|
||||
.add_event::<AppExit>()
|
||||
|
@ -647,7 +653,9 @@ impl App {
|
|||
///
|
||||
/// ```
|
||||
/// # use bevy_app::prelude::*;
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// #
|
||||
/// #[derive(Resource)]
|
||||
/// struct MyCounter {
|
||||
/// counter: usize,
|
||||
/// }
|
||||
|
@ -660,15 +668,16 @@ impl App {
|
|||
self
|
||||
}
|
||||
|
||||
/// Inserts a non-send [`Resource`] to the app.
|
||||
/// Inserts a non-send resource to the app.
|
||||
///
|
||||
/// You usually want to use [`insert_resource`](Self::insert_resource),
|
||||
/// but there are some special cases when a [`Resource`] cannot be sent across threads.
|
||||
/// but there are some special cases when a resource cannot be sent across threads.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_app::prelude::*;
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// #
|
||||
/// struct MyCounter {
|
||||
/// counter: usize,
|
||||
|
@ -694,7 +703,9 @@ impl App {
|
|||
///
|
||||
/// ```
|
||||
/// # use bevy_app::prelude::*;
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// #
|
||||
/// #[derive(Resource)]
|
||||
/// struct MyCounter {
|
||||
/// counter: usize,
|
||||
/// }
|
||||
|
@ -873,7 +884,7 @@ impl App {
|
|||
#[cfg(feature = "bevy_reflect")]
|
||||
pub fn register_type<T: bevy_reflect::GetTypeRegistration>(&mut self) -> &mut Self {
|
||||
{
|
||||
let registry = self.world.resource_mut::<bevy_reflect::TypeRegistryArc>();
|
||||
let registry = self.world.resource_mut::<AppTypeRegistry>();
|
||||
registry.write().register::<T>();
|
||||
}
|
||||
self
|
||||
|
@ -906,7 +917,7 @@ impl App {
|
|||
&mut self,
|
||||
) -> &mut Self {
|
||||
{
|
||||
let registry = self.world.resource_mut::<bevy_reflect::TypeRegistryArc>();
|
||||
let registry = self.world.resource_mut::<AppTypeRegistry>();
|
||||
registry.write().register_type_data::<T, D>();
|
||||
}
|
||||
self
|
||||
|
|
|
@ -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<u32>,
|
||||
|
|
|
@ -18,6 +18,9 @@ pub use schedule_runner::*;
|
|||
|
||||
#[allow(missing_docs)]
|
||||
pub mod prelude {
|
||||
#[cfg(feature = "bevy_reflect")]
|
||||
#[doc(hidden)]
|
||||
pub use crate::AppTypeRegistry;
|
||||
#[doc(hidden)]
|
||||
pub use crate::{
|
||||
app::App, CoreStage, DynamicPlugin, Plugin, PluginGroup, StartupSchedule, StartupStage,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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};
|
||||
|
@ -102,7 +102,7 @@ pub struct AssetServerInternal {
|
|||
/// See the [`asset_loading`] example for more information.
|
||||
///
|
||||
/// [`asset_loading`]: https://github.com/bevyengine/bevy/tree/latest/examples/asset/asset_loading.rs
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Resource)]
|
||||
pub struct AssetServer {
|
||||
pub(crate) server: Arc<AssetServerInternal>,
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
@ -66,7 +66,7 @@ impl<T: Asset> Debug for AssetEvent<T> {
|
|||
/// 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<T: Asset> {
|
||||
assets: HashMap<HandleId, T>,
|
||||
events: Events<AssetEvent<T>>,
|
||||
|
|
|
@ -6,7 +6,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;
|
||||
|
@ -52,6 +52,7 @@ pub struct DebugAssetServerPlugin;
|
|||
|
||||
/// A collection that maps internal assets in a [`DebugAssetApp`]'s asset server to their mirrors in
|
||||
/// the main [`App`].
|
||||
#[derive(Resource)]
|
||||
pub struct HandleMap<T: Asset> {
|
||||
/// The collection of asset handles.
|
||||
pub handles: HashMap<Handle<T>, Handle<T>>,
|
||||
|
|
|
@ -43,7 +43,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)]
|
||||
|
@ -62,6 +65,7 @@ pub enum AssetStage {
|
|||
pub struct AssetPlugin;
|
||||
|
||||
/// [`AssetServer`] settings.
|
||||
#[derive(Resource)]
|
||||
pub struct AssetServerSettings {
|
||||
/// The base folder where assets are loaded from, relative to the executable.
|
||||
pub asset_folder: String,
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
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};
|
||||
|
||||
/// Use this resource to play audio
|
||||
/// Use this [`Resource`] to play audio.
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_ecs::system::Res;
|
||||
|
@ -13,6 +14,7 @@ use std::{collections::VecDeque, fmt};
|
|||
/// audio.play(asset_server.load("my_sound.ogg"));
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Resource)]
|
||||
pub struct Audio<Source = AudioSource>
|
||||
where
|
||||
Source: Asset + Decodable,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -13,11 +13,11 @@ pub enum ClearColorConfig {
|
|||
None,
|
||||
}
|
||||
|
||||
/// When used as a resource, sets the color that is used to clear the screen between frames.
|
||||
/// A [`Resource`] that stores the color that is used to clear the screen between frames.
|
||||
///
|
||||
/// This color appears as the "background" color for simple apps, when
|
||||
/// there are portions of the screen with nothing rendered.
|
||||
#[derive(Component, Clone, Debug, Deref, DerefMut, ExtractResource, Reflect)]
|
||||
/// This color appears as the "background" color for simple apps,
|
||||
/// when there are portions of the screen with nothing rendered.
|
||||
#[derive(Resource, Clone, Debug, Deref, DerefMut, ExtractResource, Reflect)]
|
||||
#[reflect(Resource)]
|
||||
pub struct ClearColor(pub Color);
|
||||
|
||||
|
|
|
@ -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};
|
||||
|
@ -154,7 +155,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.
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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<Vec<DiagnosticId>>,
|
||||
|
|
|
@ -91,7 +91,7 @@ Apps often require unique resources, such as asset collections, renderers, audio
|
|||
```rust
|
||||
use bevy_ecs::prelude::*;
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Resource, Default)]
|
||||
struct Time {
|
||||
seconds: f32,
|
||||
}
|
||||
|
@ -213,6 +213,7 @@ Resources also expose change state:
|
|||
```rust
|
||||
use bevy_ecs::prelude::*;
|
||||
|
||||
#[derive(Resource)]
|
||||
struct Time(f32);
|
||||
|
||||
// Prints "time changed!" if the Time resource has changed since the last run of the System
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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::system::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();
|
||||
|
|
|
@ -496,6 +496,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)
|
||||
|
|
|
@ -31,6 +31,7 @@ pub const MAX_CHANGE_AGE: u32 = u32::MAX - (2 * CHECK_TICK_THRESHOLD - 1);
|
|||
/// ```
|
||||
/// use bevy_ecs::prelude::*;
|
||||
///
|
||||
/// #[derive(Resource)]
|
||||
/// struct MyResource(u32);
|
||||
///
|
||||
/// fn my_system(mut resource: ResMut<MyResource>) {
|
||||
|
@ -165,9 +166,9 @@ 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.
|
||||
/// See the [`Resource`] documentation for usage.
|
||||
///
|
||||
/// If you need a shared borrow, use [`Res`](crate::system::Res) instead.
|
||||
///
|
||||
|
@ -306,6 +307,8 @@ impl std::fmt::Debug for MutUntyped<'_> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use bevy_ecs_macros::Resource;
|
||||
|
||||
use crate::{
|
||||
self as bevy_ecs,
|
||||
change_detection::{
|
||||
|
@ -320,7 +323,8 @@ mod tests {
|
|||
#[derive(Component)]
|
||||
struct C;
|
||||
|
||||
struct R; // Resource
|
||||
#[derive(Resource)]
|
||||
struct R;
|
||||
|
||||
#[test]
|
||||
fn change_expiration() {
|
||||
|
|
|
@ -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, Resource, SystemParam};
|
||||
use bevy_utils::tracing::trace;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::{
|
||||
|
@ -128,7 +128,7 @@ struct EventInstance<E: Event> {
|
|||
/// [Example usage.](https://github.com/bevyengine/bevy/blob/latest/examples/ecs/event.rs)
|
||||
/// [Example usage standalone.](https://github.com/bevyengine/bevy/blob/latest/crates/bevy_ecs/examples/events.rs)
|
||||
///
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Resource)]
|
||||
pub struct Events<E: Event> {
|
||||
/// Holds the oldest still active events.
|
||||
/// Note that a.start_event_count + a.len() should always === events_b.start_event_count.
|
||||
|
|
|
@ -40,8 +40,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},
|
||||
};
|
||||
|
@ -58,6 +58,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};
|
||||
|
@ -69,7 +70,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);
|
||||
|
@ -1003,16 +1004,24 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn resource() {
|
||||
let mut world = World::default();
|
||||
assert!(world.get_resource::<i32>().is_none());
|
||||
assert!(!world.contains_resource::<i32>());
|
||||
assert!(!world.is_resource_added::<i32>());
|
||||
assert!(!world.is_resource_changed::<i32>());
|
||||
use crate::system::Resource;
|
||||
|
||||
world.insert_resource(123);
|
||||
#[derive(Resource, PartialEq, Debug)]
|
||||
struct Num(i32);
|
||||
|
||||
#[derive(Resource, PartialEq, Debug)]
|
||||
struct BigNum(u64);
|
||||
|
||||
let mut world = World::default();
|
||||
assert!(world.get_resource::<Num>().is_none());
|
||||
assert!(!world.contains_resource::<Num>());
|
||||
assert!(!world.is_resource_added::<Num>());
|
||||
assert!(!world.is_resource_changed::<Num>());
|
||||
|
||||
world.insert_resource(Num(123));
|
||||
let resource_id = world
|
||||
.components()
|
||||
.get_resource_id(TypeId::of::<i32>())
|
||||
.get_resource_id(TypeId::of::<Num>())
|
||||
.unwrap();
|
||||
let archetype_component_id = world
|
||||
.archetypes()
|
||||
|
@ -1020,61 +1029,61 @@ mod tests {
|
|||
.get_archetype_component_id(resource_id)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(*world.resource::<i32>(), 123);
|
||||
assert!(world.contains_resource::<i32>());
|
||||
assert!(world.is_resource_added::<i32>());
|
||||
assert!(world.is_resource_changed::<i32>());
|
||||
assert_eq!(world.resource::<Num>().0, 123);
|
||||
assert!(world.contains_resource::<Num>());
|
||||
assert!(world.is_resource_added::<Num>());
|
||||
assert!(world.is_resource_changed::<Num>());
|
||||
|
||||
world.insert_resource(456u64);
|
||||
assert_eq!(*world.resource::<u64>(), 456u64);
|
||||
world.insert_resource(BigNum(456));
|
||||
assert_eq!(world.resource::<BigNum>().0, 456u64);
|
||||
|
||||
world.insert_resource(789u64);
|
||||
assert_eq!(*world.resource::<u64>(), 789);
|
||||
world.insert_resource(BigNum(789));
|
||||
assert_eq!(world.resource::<BigNum>().0, 789);
|
||||
|
||||
{
|
||||
let mut value = world.resource_mut::<u64>();
|
||||
assert_eq!(*value, 789);
|
||||
*value = 10;
|
||||
let mut value = world.resource_mut::<BigNum>();
|
||||
assert_eq!(value.0, 789);
|
||||
value.0 = 10;
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
world.resource::<u64>(),
|
||||
&10,
|
||||
world.resource::<BigNum>().0,
|
||||
10,
|
||||
"resource changes are preserved"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
world.remove_resource::<u64>(),
|
||||
Some(10),
|
||||
world.remove_resource::<BigNum>(),
|
||||
Some(BigNum(10)),
|
||||
"removed resource has the correct value"
|
||||
);
|
||||
assert_eq!(
|
||||
world.get_resource::<u64>(),
|
||||
world.get_resource::<BigNum>(),
|
||||
None,
|
||||
"removed resource no longer exists"
|
||||
);
|
||||
assert_eq!(
|
||||
world.remove_resource::<u64>(),
|
||||
world.remove_resource::<BigNum>(),
|
||||
None,
|
||||
"double remove returns nothing"
|
||||
);
|
||||
|
||||
world.insert_resource(1u64);
|
||||
world.insert_resource(BigNum(1));
|
||||
assert_eq!(
|
||||
world.get_resource::<u64>(),
|
||||
Some(&1u64),
|
||||
world.get_resource::<BigNum>(),
|
||||
Some(&BigNum(1)),
|
||||
"re-inserting resources works"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
world.get_resource::<i32>(),
|
||||
Some(&123),
|
||||
world.get_resource::<Num>(),
|
||||
Some(&Num(123)),
|
||||
"other resources are unaffected"
|
||||
);
|
||||
|
||||
let current_resource_id = world
|
||||
.components()
|
||||
.get_resource_id(TypeId::of::<i32>())
|
||||
.get_resource_id(TypeId::of::<Num>())
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
resource_id, current_resource_id,
|
||||
|
@ -1120,7 +1129,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
e.get::<A>(),
|
||||
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::<B>(),
|
||||
|
@ -1325,12 +1334,12 @@ mod tests {
|
|||
#[test]
|
||||
fn resource_scope() {
|
||||
let mut world = World::default();
|
||||
world.insert_resource::<i32>(0);
|
||||
world.resource_scope(|world: &mut World, mut value: Mut<i32>| {
|
||||
*value += 1;
|
||||
assert!(!world.contains_resource::<i32>());
|
||||
world.insert_resource(A(0));
|
||||
world.resource_scope(|world: &mut World, mut value: Mut<A>| {
|
||||
value.0 += 1;
|
||||
assert!(!world.contains_resource::<A>());
|
||||
});
|
||||
assert_eq!(*world.resource::<i32>(), 1);
|
||||
assert_eq!(world.resource::<A>().0, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1367,7 +1376,7 @@ mod tests {
|
|||
fn clear_entities() {
|
||||
let mut world = World::default();
|
||||
|
||||
world.insert_resource::<i32>(0);
|
||||
world.insert_resource(A(0));
|
||||
world.spawn().insert(A(1));
|
||||
world.spawn().insert(SparseStored(1));
|
||||
|
||||
|
@ -1396,7 +1405,7 @@ mod tests {
|
|||
"world should not have any entities"
|
||||
);
|
||||
assert_eq!(
|
||||
*world.resource::<i32>(),
|
||||
world.resource::<A>().0,
|
||||
0,
|
||||
"world should still contain resources"
|
||||
);
|
||||
|
|
|
@ -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::<SchedulingEvent>();
|
||||
world.insert_resource(receiver);
|
||||
world.insert_resource(SchedulingEvents(receiver));
|
||||
self.events_sender = Some(sender);
|
||||
}
|
||||
|
||||
|
@ -260,7 +260,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);
|
||||
|
@ -308,29 +308,43 @@ 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<SchedulingEvent>);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::SchedulingEvent::{self, *};
|
||||
use crate::{
|
||||
schedule::{SingleThreadedExecutor, Stage, SystemStage},
|
||||
system::{NonSend, Query, Res, ResMut},
|
||||
self as bevy_ecs,
|
||||
component::Component,
|
||||
schedule::{
|
||||
executor_parallel::scheduling_event::*, SingleThreadedExecutor, Stage, SystemStage,
|
||||
},
|
||||
system::{NonSend, Query, Res, ResMut, Resource},
|
||||
world::World,
|
||||
};
|
||||
use async_channel::Receiver;
|
||||
|
||||
use crate as bevy_ecs;
|
||||
use crate::component::Component;
|
||||
use SchedulingEvent::StartedSystems;
|
||||
|
||||
#[derive(Component)]
|
||||
struct W<T>(T);
|
||||
#[derive(Resource, Default)]
|
||||
struct Counter(usize);
|
||||
|
||||
fn receive_events(world: &World) -> Vec<SchedulingEvent> {
|
||||
let mut events = Vec::new();
|
||||
while let Ok(event) = world.resource::<Receiver<SchedulingEvent>>().try_recv() {
|
||||
while let Ok(event) = world.resource::<SchedulingEvents>().0.try_recv() {
|
||||
events.push(event);
|
||||
}
|
||||
events
|
||||
|
@ -355,9 +369,9 @@ mod tests {
|
|||
#[test]
|
||||
fn resources() {
|
||||
let mut world = World::new();
|
||||
world.insert_resource(0usize);
|
||||
fn wants_mut(_: ResMut<usize>) {}
|
||||
fn wants_ref(_: Res<usize>) {}
|
||||
world.init_resource::<Counter>();
|
||||
fn wants_mut(_: ResMut<Counter>) {}
|
||||
fn wants_ref(_: Res<Counter>) {}
|
||||
let mut stage = SystemStage::parallel()
|
||||
.with_system(wants_mut)
|
||||
.with_system(wants_mut);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::{
|
||||
self as bevy_ecs,
|
||||
change_detection::CHECK_TICK_THRESHOLD,
|
||||
component::ComponentId,
|
||||
prelude::IntoSystem,
|
||||
|
@ -12,6 +13,7 @@ use crate::{
|
|||
},
|
||||
world::{World, WorldId},
|
||||
};
|
||||
use bevy_ecs_macros::Resource;
|
||||
use bevy_utils::{
|
||||
tracing::{info, warn},
|
||||
HashMap, HashSet,
|
||||
|
@ -50,7 +52,7 @@ impl_downcast!(Stage);
|
|||
///
|
||||
/// The checker may report a system more times than the amount of constraints it would actually need
|
||||
/// to have unambiguous order with regards to a group of already-constrained systems.
|
||||
#[derive(Default)]
|
||||
#[derive(Resource, Default)]
|
||||
pub struct ReportExecutionOrderAmbiguities;
|
||||
|
||||
/// Stores and executes systems. Execution order is not defined unless explicitly specified;
|
||||
|
@ -982,15 +984,22 @@ mod tests {
|
|||
|
||||
use crate as bevy_ecs;
|
||||
use crate::component::Component;
|
||||
use crate::system::Resource;
|
||||
|
||||
#[derive(Component)]
|
||||
struct W<T>(T);
|
||||
#[derive(Resource)]
|
||||
struct R(usize);
|
||||
|
||||
#[derive(Resource, Default)]
|
||||
struct EntityCount(Vec<usize>);
|
||||
|
||||
fn make_exclusive(tag: usize) -> impl FnMut(&mut World) {
|
||||
move |world| world.resource_mut::<Vec<usize>>().push(tag)
|
||||
move |world| world.resource_mut::<EntityCount>().0.push(tag)
|
||||
}
|
||||
|
||||
fn make_parallel(tag: usize) -> impl FnMut(ResMut<Vec<usize>>) {
|
||||
move |mut resource: ResMut<Vec<usize>>| resource.push(tag)
|
||||
fn make_parallel(tag: usize) -> impl FnMut(ResMut<EntityCount>) {
|
||||
move |mut resource: ResMut<EntityCount>| resource.0.push(tag)
|
||||
}
|
||||
|
||||
fn every_other_time(mut has_ran: Local<bool>) -> ShouldRun {
|
||||
|
@ -1005,48 +1014,48 @@ mod tests {
|
|||
#[test]
|
||||
fn insertion_points() {
|
||||
let mut world = World::new();
|
||||
world.insert_resource(Vec::<usize>::new());
|
||||
world.init_resource::<EntityCount>();
|
||||
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<usize>>(), vec![0, 1, 2, 3]);
|
||||
assert_eq!(world.resource_mut::<EntityCount>().0, vec![0, 1, 2, 3]);
|
||||
stage.set_executor(Box::new(SingleThreadedExecutor::default()));
|
||||
stage.run(&mut world);
|
||||
assert_eq!(
|
||||
*world.resource::<Vec<usize>>(),
|
||||
world.resource::<EntityCount>().0,
|
||||
vec![0, 1, 2, 3, 0, 1, 2, 3]
|
||||
);
|
||||
|
||||
world.resource_mut::<Vec<usize>>().clear();
|
||||
world.resource_mut::<EntityCount>().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<usize>>(), vec![0, 1, 2, 3]);
|
||||
assert_eq!(world.resource::<EntityCount>().0, vec![0, 1, 2, 3]);
|
||||
stage.set_executor(Box::new(SingleThreadedExecutor::default()));
|
||||
stage.run(&mut world);
|
||||
assert_eq!(
|
||||
*world.resource::<Vec<usize>>(),
|
||||
world.resource::<EntityCount>().0,
|
||||
vec![0, 1, 2, 3, 0, 1, 2, 3]
|
||||
);
|
||||
|
||||
world.resource_mut::<Vec<usize>>().clear();
|
||||
world.resource_mut::<EntityCount>().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<usize>>(), vec![0, 1, 2, 3]);
|
||||
assert_eq!(world.resource::<EntityCount>().0, vec![0, 1, 2, 3]);
|
||||
stage.set_executor(Box::new(SingleThreadedExecutor::default()));
|
||||
stage.run(&mut world);
|
||||
assert_eq!(
|
||||
*world.resource::<Vec<usize>>(),
|
||||
world.resource::<EntityCount>().0,
|
||||
vec![0, 1, 2, 3, 0, 1, 2, 3]
|
||||
);
|
||||
}
|
||||
|
@ -1054,7 +1063,7 @@ mod tests {
|
|||
#[test]
|
||||
fn exclusive_after() {
|
||||
let mut world = World::new();
|
||||
world.insert_resource(Vec::<usize>::new());
|
||||
world.init_resource::<EntityCount>();
|
||||
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"))
|
||||
|
@ -1062,13 +1071,13 @@ mod tests {
|
|||
stage.run(&mut world);
|
||||
stage.set_executor(Box::new(SingleThreadedExecutor::default()));
|
||||
stage.run(&mut world);
|
||||
assert_eq!(*world.resource::<Vec<usize>>(), vec![0, 1, 2, 0, 1, 2]);
|
||||
assert_eq!(world.resource::<EntityCount>().0, vec![0, 1, 2, 0, 1, 2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exclusive_before() {
|
||||
let mut world = World::new();
|
||||
world.insert_resource(Vec::<usize>::new());
|
||||
world.init_resource::<EntityCount>();
|
||||
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"))
|
||||
|
@ -1076,13 +1085,13 @@ mod tests {
|
|||
stage.run(&mut world);
|
||||
stage.set_executor(Box::new(SingleThreadedExecutor::default()));
|
||||
stage.run(&mut world);
|
||||
assert_eq!(*world.resource::<Vec<usize>>(), vec![0, 1, 2, 0, 1, 2]);
|
||||
assert_eq!(world.resource::<EntityCount>().0, vec![0, 1, 2, 0, 1, 2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exclusive_mixed() {
|
||||
let mut world = World::new();
|
||||
world.insert_resource(Vec::<usize>::new());
|
||||
world.init_resource::<EntityCount>();
|
||||
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"))
|
||||
|
@ -1093,7 +1102,7 @@ mod tests {
|
|||
stage.set_executor(Box::new(SingleThreadedExecutor::default()));
|
||||
stage.run(&mut world);
|
||||
assert_eq!(
|
||||
*world.resource::<Vec<usize>>(),
|
||||
world.resource::<EntityCount>().0,
|
||||
vec![0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
|
||||
);
|
||||
}
|
||||
|
@ -1101,7 +1110,7 @@ mod tests {
|
|||
#[test]
|
||||
fn exclusive_multiple_labels() {
|
||||
let mut world = World::new();
|
||||
world.insert_resource(Vec::<usize>::new());
|
||||
world.init_resource::<EntityCount>();
|
||||
let mut stage = SystemStage::parallel()
|
||||
.with_system(
|
||||
make_exclusive(1)
|
||||
|
@ -1119,9 +1128,9 @@ mod tests {
|
|||
stage.run(&mut world);
|
||||
stage.set_executor(Box::new(SingleThreadedExecutor::default()));
|
||||
stage.run(&mut world);
|
||||
assert_eq!(*world.resource::<Vec<usize>>(), vec![0, 1, 2, 0, 1, 2]);
|
||||
assert_eq!(world.resource::<EntityCount>().0, vec![0, 1, 2, 0, 1, 2]);
|
||||
|
||||
world.resource_mut::<Vec<usize>>().clear();
|
||||
world.resource_mut::<EntityCount>().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"))
|
||||
|
@ -1132,11 +1141,11 @@ mod tests {
|
|||
stage.set_executor(Box::new(SingleThreadedExecutor::default()));
|
||||
stage.run(&mut world);
|
||||
assert_eq!(
|
||||
*world.resource::<Vec<usize>>(),
|
||||
world.resource::<EntityCount>().0,
|
||||
vec![0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
|
||||
);
|
||||
|
||||
world.resource_mut::<Vec<usize>>().clear();
|
||||
world.resource_mut::<EntityCount>().0.clear();
|
||||
let mut stage = SystemStage::parallel()
|
||||
.with_system(make_exclusive(2).exclusive_system().label("234").label("2"))
|
||||
.with_system(
|
||||
|
@ -1158,7 +1167,7 @@ mod tests {
|
|||
stage.set_executor(Box::new(SingleThreadedExecutor::default()));
|
||||
stage.run(&mut world);
|
||||
assert_eq!(
|
||||
*world.resource::<Vec<usize>>(),
|
||||
world.resource::<EntityCount>().0,
|
||||
vec![0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
|
||||
);
|
||||
}
|
||||
|
@ -1166,7 +1175,7 @@ mod tests {
|
|||
#[test]
|
||||
fn exclusive_redundant_constraints() {
|
||||
let mut world = World::new();
|
||||
world.insert_resource(Vec::<usize>::new());
|
||||
world.init_resource::<EntityCount>();
|
||||
let mut stage = SystemStage::parallel()
|
||||
.with_system(
|
||||
make_exclusive(2)
|
||||
|
@ -1197,7 +1206,7 @@ mod tests {
|
|||
stage.set_executor(Box::new(SingleThreadedExecutor::default()));
|
||||
stage.run(&mut world);
|
||||
assert_eq!(
|
||||
*world.resource::<Vec<usize>>(),
|
||||
world.resource::<EntityCount>().0,
|
||||
vec![0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
|
||||
);
|
||||
}
|
||||
|
@ -1205,7 +1214,7 @@ mod tests {
|
|||
#[test]
|
||||
fn exclusive_mixed_across_sets() {
|
||||
let mut world = World::new();
|
||||
world.insert_resource(Vec::<usize>::new());
|
||||
world.init_resource::<EntityCount>();
|
||||
let mut stage = SystemStage::parallel()
|
||||
.with_system(make_exclusive(2).exclusive_system().label("2"))
|
||||
.with_system_set(
|
||||
|
@ -1219,7 +1228,7 @@ mod tests {
|
|||
stage.set_executor(Box::new(SingleThreadedExecutor::default()));
|
||||
stage.run(&mut world);
|
||||
assert_eq!(
|
||||
*world.resource::<Vec<usize>>(),
|
||||
world.resource::<EntityCount>().0,
|
||||
vec![0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
|
||||
);
|
||||
}
|
||||
|
@ -1227,7 +1236,7 @@ mod tests {
|
|||
#[test]
|
||||
fn exclusive_run_criteria() {
|
||||
let mut world = World::new();
|
||||
world.insert_resource(Vec::<usize>::new());
|
||||
world.init_resource::<EntityCount>();
|
||||
let mut stage = SystemStage::parallel()
|
||||
.with_system(make_exclusive(0).exclusive_system().before("1"))
|
||||
.with_system_set(
|
||||
|
@ -1242,7 +1251,7 @@ mod tests {
|
|||
stage.run(&mut world);
|
||||
stage.run(&mut world);
|
||||
assert_eq!(
|
||||
*world.resource::<Vec<usize>>(),
|
||||
world.resource::<EntityCount>().0,
|
||||
vec![0, 1, 2, 0, 2, 0, 1, 2, 0, 2]
|
||||
);
|
||||
}
|
||||
|
@ -1251,7 +1260,7 @@ mod tests {
|
|||
#[should_panic]
|
||||
fn exclusive_cycle_1() {
|
||||
let mut world = World::new();
|
||||
world.insert_resource(Vec::<usize>::new());
|
||||
world.init_resource::<EntityCount>();
|
||||
let mut stage = SystemStage::parallel()
|
||||
.with_system(make_exclusive(0).exclusive_system().label("0").after("0"));
|
||||
stage.run(&mut world);
|
||||
|
@ -1261,7 +1270,7 @@ mod tests {
|
|||
#[should_panic]
|
||||
fn exclusive_cycle_2() {
|
||||
let mut world = World::new();
|
||||
world.insert_resource(Vec::<usize>::new());
|
||||
world.init_resource::<EntityCount>();
|
||||
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"));
|
||||
|
@ -1272,7 +1281,7 @@ mod tests {
|
|||
#[should_panic]
|
||||
fn exclusive_cycle_3() {
|
||||
let mut world = World::new();
|
||||
world.insert_resource(Vec::<usize>::new());
|
||||
world.init_resource::<EntityCount>();
|
||||
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"))
|
||||
|
@ -1283,7 +1292,7 @@ mod tests {
|
|||
#[test]
|
||||
fn parallel_after() {
|
||||
let mut world = World::new();
|
||||
world.insert_resource(Vec::<usize>::new());
|
||||
world.init_resource::<EntityCount>();
|
||||
let mut stage = SystemStage::parallel()
|
||||
.with_system(make_parallel(1).after("0").label("1"))
|
||||
.with_system(make_parallel(2).after("1"))
|
||||
|
@ -1291,13 +1300,13 @@ mod tests {
|
|||
stage.run(&mut world);
|
||||
stage.set_executor(Box::new(SingleThreadedExecutor::default()));
|
||||
stage.run(&mut world);
|
||||
assert_eq!(*world.resource::<Vec<usize>>(), vec![0, 1, 2, 0, 1, 2]);
|
||||
assert_eq!(world.resource::<EntityCount>().0, vec![0, 1, 2, 0, 1, 2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parallel_before() {
|
||||
let mut world = World::new();
|
||||
world.insert_resource(Vec::<usize>::new());
|
||||
world.init_resource::<EntityCount>();
|
||||
let mut stage = SystemStage::parallel()
|
||||
.with_system(make_parallel(1).label("1").before("2"))
|
||||
.with_system(make_parallel(2).label("2"))
|
||||
|
@ -1305,13 +1314,13 @@ mod tests {
|
|||
stage.run(&mut world);
|
||||
stage.set_executor(Box::new(SingleThreadedExecutor::default()));
|
||||
stage.run(&mut world);
|
||||
assert_eq!(*world.resource::<Vec<usize>>(), vec![0, 1, 2, 0, 1, 2]);
|
||||
assert_eq!(world.resource::<EntityCount>().0, vec![0, 1, 2, 0, 1, 2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parallel_mixed() {
|
||||
let mut world = World::new();
|
||||
world.insert_resource(Vec::<usize>::new());
|
||||
world.init_resource::<EntityCount>();
|
||||
let mut stage = SystemStage::parallel()
|
||||
.with_system(make_parallel(2).label("2"))
|
||||
.with_system(make_parallel(1).after("0").before("2"))
|
||||
|
@ -1322,7 +1331,7 @@ mod tests {
|
|||
stage.set_executor(Box::new(SingleThreadedExecutor::default()));
|
||||
stage.run(&mut world);
|
||||
assert_eq!(
|
||||
*world.resource::<Vec<usize>>(),
|
||||
world.resource::<EntityCount>().0,
|
||||
vec![0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
|
||||
);
|
||||
}
|
||||
|
@ -1330,7 +1339,7 @@ mod tests {
|
|||
#[test]
|
||||
fn parallel_multiple_labels() {
|
||||
let mut world = World::new();
|
||||
world.insert_resource(Vec::<usize>::new());
|
||||
world.init_resource::<EntityCount>();
|
||||
let mut stage = SystemStage::parallel()
|
||||
.with_system(make_parallel(1).label("first").after("0"))
|
||||
.with_system(make_parallel(2).after("first"))
|
||||
|
@ -1338,9 +1347,9 @@ mod tests {
|
|||
stage.run(&mut world);
|
||||
stage.set_executor(Box::new(SingleThreadedExecutor::default()));
|
||||
stage.run(&mut world);
|
||||
assert_eq!(*world.resource::<Vec<usize>>(), vec![0, 1, 2, 0, 1, 2]);
|
||||
assert_eq!(world.resource::<EntityCount>().0, vec![0, 1, 2, 0, 1, 2]);
|
||||
|
||||
world.resource_mut::<Vec<usize>>().clear();
|
||||
world.resource_mut::<EntityCount>().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"))
|
||||
|
@ -1351,11 +1360,11 @@ mod tests {
|
|||
stage.set_executor(Box::new(SingleThreadedExecutor::default()));
|
||||
stage.run(&mut world);
|
||||
assert_eq!(
|
||||
*world.resource::<Vec<usize>>(),
|
||||
world.resource::<EntityCount>().0,
|
||||
vec![0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
|
||||
);
|
||||
|
||||
world.resource_mut::<Vec<usize>>().clear();
|
||||
world.resource_mut::<EntityCount>().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"))
|
||||
|
@ -1366,7 +1375,7 @@ mod tests {
|
|||
stage.set_executor(Box::new(SingleThreadedExecutor::default()));
|
||||
stage.run(&mut world);
|
||||
assert_eq!(
|
||||
*world.resource::<Vec<usize>>(),
|
||||
world.resource::<EntityCount>().0,
|
||||
vec![0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
|
||||
);
|
||||
}
|
||||
|
@ -1374,7 +1383,7 @@ mod tests {
|
|||
#[test]
|
||||
fn parallel_redundant_constraints() {
|
||||
let mut world = World::new();
|
||||
world.insert_resource(Vec::<usize>::new());
|
||||
world.init_resource::<EntityCount>();
|
||||
let mut stage = SystemStage::parallel()
|
||||
.with_system(
|
||||
make_parallel(2)
|
||||
|
@ -1400,7 +1409,7 @@ mod tests {
|
|||
stage.set_executor(Box::new(SingleThreadedExecutor::default()));
|
||||
stage.run(&mut world);
|
||||
assert_eq!(
|
||||
*world.resource::<Vec<usize>>(),
|
||||
world.resource::<EntityCount>().0,
|
||||
vec![0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
|
||||
);
|
||||
}
|
||||
|
@ -1408,7 +1417,7 @@ mod tests {
|
|||
#[test]
|
||||
fn parallel_mixed_across_sets() {
|
||||
let mut world = World::new();
|
||||
world.insert_resource(Vec::<usize>::new());
|
||||
world.init_resource::<EntityCount>();
|
||||
let mut stage = SystemStage::parallel()
|
||||
.with_system(make_parallel(2).label("2"))
|
||||
.with_system_set(
|
||||
|
@ -1422,7 +1431,7 @@ mod tests {
|
|||
stage.set_executor(Box::new(SingleThreadedExecutor::default()));
|
||||
stage.run(&mut world);
|
||||
assert_eq!(
|
||||
*world.resource::<Vec<usize>>(),
|
||||
world.resource::<EntityCount>().0,
|
||||
vec![0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
|
||||
);
|
||||
}
|
||||
|
@ -1431,7 +1440,7 @@ mod tests {
|
|||
fn parallel_run_criteria() {
|
||||
let mut world = World::new();
|
||||
|
||||
world.insert_resource(Vec::<usize>::new());
|
||||
world.init_resource::<EntityCount>();
|
||||
let mut stage = SystemStage::parallel()
|
||||
.with_system(
|
||||
make_parallel(0)
|
||||
|
@ -1444,9 +1453,9 @@ mod tests {
|
|||
stage.set_executor(Box::new(SingleThreadedExecutor::default()));
|
||||
stage.run(&mut world);
|
||||
stage.run(&mut world);
|
||||
assert_eq!(*world.resource::<Vec<usize>>(), vec![0, 1, 1, 0, 1, 1]);
|
||||
assert_eq!(world.resource::<EntityCount>().0, vec![0, 1, 1, 0, 1, 1]);
|
||||
|
||||
world.resource_mut::<Vec<usize>>().clear();
|
||||
world.resource_mut::<EntityCount>().0.clear();
|
||||
let mut stage = SystemStage::parallel()
|
||||
.with_system(make_parallel(0).before("1"))
|
||||
.with_system_set(
|
||||
|
@ -1461,12 +1470,12 @@ mod tests {
|
|||
stage.run(&mut world);
|
||||
stage.run(&mut world);
|
||||
assert_eq!(
|
||||
*world.resource::<Vec<usize>>(),
|
||||
world.resource::<EntityCount>().0,
|
||||
vec![0, 1, 2, 0, 2, 0, 1, 2, 0, 2]
|
||||
);
|
||||
|
||||
// Reusing criteria.
|
||||
world.resource_mut::<Vec<usize>>().clear();
|
||||
world.resource_mut::<EntityCount>().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"))
|
||||
|
@ -1488,13 +1497,13 @@ mod tests {
|
|||
stage.run(&mut world);
|
||||
stage.run(&mut world);
|
||||
assert_eq!(
|
||||
*world.resource::<Vec<usize>>(),
|
||||
world.resource::<EntityCount>().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::<Vec<usize>>().clear();
|
||||
world.resource_mut::<EntityCount>().0.clear();
|
||||
fn eot_piped(input: In<ShouldRun>, has_ran: Local<bool>) -> ShouldRun {
|
||||
if let ShouldRun::Yes | ShouldRun::YesAndCheckAgain = input.0 {
|
||||
every_other_time(has_ran)
|
||||
|
@ -1529,13 +1538,13 @@ mod tests {
|
|||
stage.run(&mut world);
|
||||
}
|
||||
assert_eq!(
|
||||
*world.resource::<Vec<usize>>(),
|
||||
world.resource::<EntityCount>().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::<Vec<usize>>().clear();
|
||||
world.resource_mut::<EntityCount>().0.clear();
|
||||
let mut stage =
|
||||
SystemStage::parallel()
|
||||
.with_system(make_parallel(0).before("1"))
|
||||
|
@ -1552,7 +1561,7 @@ mod tests {
|
|||
stage.run(&mut world);
|
||||
stage.run(&mut world);
|
||||
assert_eq!(
|
||||
*world.resource::<Vec<usize>>(),
|
||||
world.resource::<EntityCount>().0,
|
||||
vec![0, 1, 2, 3, 0, 3, 0, 1, 2, 3, 0, 3]
|
||||
);
|
||||
assert_eq!(stage.run_criteria.len(), 1);
|
||||
|
@ -1572,7 +1581,7 @@ mod tests {
|
|||
#[should_panic]
|
||||
fn parallel_cycle_1() {
|
||||
let mut world = World::new();
|
||||
world.insert_resource(Vec::<usize>::new());
|
||||
world.init_resource::<EntityCount>();
|
||||
let mut stage = SystemStage::parallel().with_system(make_parallel(0).label("0").after("0"));
|
||||
stage.run(&mut world);
|
||||
}
|
||||
|
@ -1581,7 +1590,7 @@ mod tests {
|
|||
#[should_panic]
|
||||
fn parallel_cycle_2() {
|
||||
let mut world = World::new();
|
||||
world.insert_resource(Vec::<usize>::new());
|
||||
world.init_resource::<EntityCount>();
|
||||
let mut stage = SystemStage::parallel()
|
||||
.with_system(make_parallel(0).label("0").after("1"))
|
||||
.with_system(make_parallel(1).label("1").after("0"));
|
||||
|
@ -1593,7 +1602,7 @@ mod tests {
|
|||
fn parallel_cycle_3() {
|
||||
let mut world = World::new();
|
||||
|
||||
world.insert_resource(Vec::<usize>::new());
|
||||
world.init_resource::<EntityCount>();
|
||||
let mut stage = SystemStage::parallel()
|
||||
.with_system(make_parallel(0).label("0"))
|
||||
.with_system(make_parallel(1).after("0").before("2"))
|
||||
|
@ -1628,7 +1637,7 @@ mod tests {
|
|||
}
|
||||
|
||||
fn empty() {}
|
||||
fn resource(_: ResMut<usize>) {}
|
||||
fn resource(_: ResMut<R>) {}
|
||||
fn component(_: Query<&mut W<f32>>) {}
|
||||
|
||||
let mut world = World::new();
|
||||
|
@ -1998,47 +2007,41 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn archetype_update_single_executor() {
|
||||
fn query_count_system(
|
||||
mut entity_count: ResMut<usize>,
|
||||
query: Query<crate::entity::Entity>,
|
||||
) {
|
||||
*entity_count = query.iter().count();
|
||||
fn query_count_system(mut entity_count: ResMut<R>, query: Query<crate::entity::Entity>) {
|
||||
*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::<usize>(), 1);
|
||||
assert_eq!(world.resource::<R>().0, 1);
|
||||
|
||||
world.get_entity_mut(entity).unwrap().insert(W(1));
|
||||
stage.run(&mut world);
|
||||
assert_eq!(*world.resource::<usize>(), 1);
|
||||
assert_eq!(world.resource::<R>().0, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn archetype_update_parallel_executor() {
|
||||
fn query_count_system(
|
||||
mut entity_count: ResMut<usize>,
|
||||
query: Query<crate::entity::Entity>,
|
||||
) {
|
||||
*entity_count = query.iter().count();
|
||||
fn query_count_system(mut entity_count: ResMut<R>, query: Query<crate::entity::Entity>) {
|
||||
*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::<usize>(), 1);
|
||||
assert_eq!(world.resource::<R>().0, 1);
|
||||
|
||||
world.get_entity_mut(entity).unwrap().insert(W(1));
|
||||
stage.run(&mut world);
|
||||
assert_eq!(*world.resource::<usize>(), 1);
|
||||
assert_eq!(world.resource::<R>().0, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -2060,12 +2063,12 @@ mod tests {
|
|||
commands.spawn().insert(Foo);
|
||||
}
|
||||
|
||||
fn count_entities(query: Query<&Foo>, mut res: ResMut<Vec<usize>>) {
|
||||
res.push(query.iter().len());
|
||||
fn count_entities(query: Query<&Foo>, mut res: ResMut<EntityCount>) {
|
||||
res.0.push(query.iter().len());
|
||||
}
|
||||
|
||||
let mut world = World::new();
|
||||
world.insert_resource(Vec::<usize>::new());
|
||||
world.init_resource::<EntityCount>();
|
||||
let mut stage = SystemStage::parallel()
|
||||
.with_system(spawn_entity.label("spawn"))
|
||||
.with_system_set(
|
||||
|
@ -2077,7 +2080,7 @@ mod tests {
|
|||
stage.run(&mut world);
|
||||
stage.run(&mut world);
|
||||
stage.run(&mut world);
|
||||
assert_eq!(*world.resource::<Vec<usize>>(), vec![0, 2]);
|
||||
assert_eq!(world.resource::<EntityCount>().0, vec![0, 2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -2099,12 +2102,12 @@ mod tests {
|
|||
commands.spawn().insert(Foo);
|
||||
}
|
||||
|
||||
fn count_entities(query: Query<&Foo>, mut res: ResMut<Vec<usize>>) {
|
||||
res.push(query.iter().len());
|
||||
fn count_entities(query: Query<&Foo>, mut res: ResMut<EntityCount>) {
|
||||
res.0.push(query.iter().len());
|
||||
}
|
||||
|
||||
let mut world = World::new();
|
||||
world.insert_resource(Vec::<usize>::new());
|
||||
world.init_resource::<EntityCount>();
|
||||
let mut stage_spawn = SystemStage::parallel().with_system(spawn_entity);
|
||||
let mut stage_count = SystemStage::parallel()
|
||||
.with_run_criteria(even_number_of_entities_critiera)
|
||||
|
@ -2117,6 +2120,6 @@ mod tests {
|
|||
stage_spawn.run(&mut world);
|
||||
stage_count.run(&mut world);
|
||||
stage_spawn.run(&mut world);
|
||||
assert_eq!(*world.resource::<Vec<usize>>(), vec![0, 2]);
|
||||
assert_eq!(world.resource::<EntityCount>().0, vec![0, 2]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<T> StateData for T where T: Send + Sync + Clone + Eq + Debug + Hash + 'static {}
|
||||
|
@ -21,7 +23,7 @@ impl<T> 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<T: StateData> {
|
||||
transition: Option<StateTransition<T>>,
|
||||
/// The current states in the stack.
|
||||
|
@ -489,9 +491,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::<NameList>();
|
||||
world.insert_resource(State::new(MyState::S1));
|
||||
|
||||
let mut stage = SystemStage::parallel();
|
||||
|
@ -500,55 +505,55 @@ mod test {
|
|||
stage
|
||||
.add_system_set(
|
||||
State::on_enter_set(MyState::S1)
|
||||
.with_system(|mut r: ResMut<Vec<&'static str>>| r.push("startup")),
|
||||
.with_system(|mut r: ResMut<NameList>| r.0.push("startup")),
|
||||
)
|
||||
.add_system_set(State::on_update_set(MyState::S1).with_system(
|
||||
|mut r: ResMut<Vec<&'static str>>, mut s: ResMut<State<MyState>>| {
|
||||
r.push("update S1");
|
||||
|mut r: ResMut<NameList>, mut s: ResMut<State<MyState>>| {
|
||||
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<Vec<&'static str>>| r.push("enter S2")),
|
||||
.with_system(|mut r: ResMut<NameList>| r.0.push("enter S2")),
|
||||
)
|
||||
.add_system_set(State::on_update_set(MyState::S2).with_system(
|
||||
|mut r: ResMut<Vec<&'static str>>, mut s: ResMut<State<MyState>>| {
|
||||
r.push("update S2");
|
||||
|mut r: ResMut<NameList>, mut s: ResMut<State<MyState>>| {
|
||||
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<Vec<&'static str>>| r.push("exit S2")),
|
||||
.with_system(|mut r: ResMut<NameList>| r.0.push("exit S2")),
|
||||
)
|
||||
.add_system_set(
|
||||
State::on_enter_set(MyState::S3)
|
||||
.with_system(|mut r: ResMut<Vec<&'static str>>| r.push("enter S3")),
|
||||
.with_system(|mut r: ResMut<NameList>| r.0.push("enter S3")),
|
||||
)
|
||||
.add_system_set(State::on_update_set(MyState::S3).with_system(
|
||||
|mut r: ResMut<Vec<&'static str>>, mut s: ResMut<State<MyState>>| {
|
||||
r.push("update S3");
|
||||
|mut r: ResMut<NameList>, mut s: ResMut<State<MyState>>| {
|
||||
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<Vec<&'static str>>| r.push("pause S3")),
|
||||
.with_system(|mut r: ResMut<NameList>| r.0.push("pause S3")),
|
||||
)
|
||||
.add_system_set(State::on_update_set(MyState::S4).with_system(
|
||||
|mut r: ResMut<Vec<&'static str>>, mut s: ResMut<State<MyState>>| {
|
||||
r.push("update S4");
|
||||
|mut r: ResMut<NameList>, mut s: ResMut<State<MyState>>| {
|
||||
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<Vec<&'static str>>| r.push("inactive S4")).label("inactive s4"),
|
||||
(|mut r: ResMut<NameList>| r.0.push("inactive S4")).label("inactive s4"),
|
||||
))
|
||||
.add_system_set(
|
||||
State::on_update_set(MyState::S5).with_system(
|
||||
(|mut r: ResMut<Vec<&'static str>>, mut s: ResMut<State<MyState>>| {
|
||||
r.push("update S5");
|
||||
(|mut r: ResMut<NameList>, mut s: ResMut<State<MyState>>| {
|
||||
r.0.push("update S5");
|
||||
s.overwrite_push(MyState::S6).unwrap();
|
||||
})
|
||||
.after("inactive s4"),
|
||||
|
@ -556,15 +561,15 @@ mod test {
|
|||
)
|
||||
.add_system_set(
|
||||
State::on_inactive_update_set(MyState::S5).with_system(
|
||||
(|mut r: ResMut<Vec<&'static str>>| r.push("inactive S5"))
|
||||
(|mut r: ResMut<NameList>| 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<Vec<&'static str>>, mut s: ResMut<State<MyState>>| {
|
||||
r.push("update S6");
|
||||
(|mut r: ResMut<NameList>, mut s: ResMut<State<MyState>>| {
|
||||
r.0.push("update S6");
|
||||
s.overwrite_push(MyState::Final).unwrap();
|
||||
})
|
||||
.after("inactive s5"),
|
||||
|
@ -572,11 +577,11 @@ mod test {
|
|||
)
|
||||
.add_system_set(
|
||||
State::on_resume_set(MyState::S4)
|
||||
.with_system(|mut r: ResMut<Vec<&'static str>>| r.push("resume S4")),
|
||||
.with_system(|mut r: ResMut<NameList>| r.0.push("resume S4")),
|
||||
)
|
||||
.add_system_set(
|
||||
State::on_exit_set(MyState::S5)
|
||||
.with_system(|mut r: ResMut<Vec<&'static str>>| r.push("exit S4")),
|
||||
.with_system(|mut r: ResMut<NameList>| r.0.push("exit S4")),
|
||||
);
|
||||
|
||||
const EXPECTED: &[&str] = &[
|
||||
|
@ -606,9 +611,9 @@ mod test {
|
|||
];
|
||||
|
||||
stage.run(&mut world);
|
||||
let mut collected = world.resource_mut::<Vec<&'static str>>();
|
||||
let mut collected = world.resource_mut::<NameList>();
|
||||
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;
|
||||
}
|
||||
|
@ -627,26 +632,32 @@ mod test {
|
|||
Main,
|
||||
}
|
||||
|
||||
fn should_run_once(mut flag: ResMut<bool>, 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<Flag>, test_name: Res<Name>) {
|
||||
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::<bool>(), "after control");
|
||||
assert!(world.resource::<Flag>().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::<AppState>::get_driver())
|
||||
.with_system(should_run_once);
|
||||
stage.run(&mut world);
|
||||
assert!(*world.resource::<bool>(), "after test");
|
||||
assert!(world.resource::<Flag>().0, "after test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -664,8 +675,11 @@ mod test {
|
|||
EnterFinish,
|
||||
}
|
||||
|
||||
#[derive(Resource, Default)]
|
||||
struct LoadStatusStack(Vec<LoadStatus>);
|
||||
|
||||
let mut world = World::new();
|
||||
world.insert_resource(Vec::<LoadStatus>::new());
|
||||
world.init_resource::<LoadStatusStack>();
|
||||
world.insert_resource(State::new(LoadState::Load));
|
||||
|
||||
let mut stage = SystemStage::parallel();
|
||||
|
@ -675,15 +689,16 @@ mod test {
|
|||
stage
|
||||
.add_system_set(
|
||||
State::on_enter_set(LoadState::Load)
|
||||
.with_system(|mut r: ResMut<Vec<LoadStatus>>| r.push(LoadStatus::EnterLoad)),
|
||||
.with_system(|mut r: ResMut<LoadStatusStack>| r.0.push(LoadStatus::EnterLoad)),
|
||||
)
|
||||
.add_system_set(
|
||||
State::on_exit_set(LoadState::Load)
|
||||
.with_system(|mut r: ResMut<Vec<LoadStatus>>| r.push(LoadStatus::ExitLoad)),
|
||||
.with_system(|mut r: ResMut<LoadStatusStack>| r.0.push(LoadStatus::ExitLoad)),
|
||||
)
|
||||
.add_system_set(
|
||||
State::on_enter_set(LoadState::Finish)
|
||||
.with_system(|mut r: ResMut<Vec<LoadStatus>>| r.push(LoadStatus::EnterFinish)),
|
||||
State::on_enter_set(LoadState::Finish).with_system(
|
||||
|mut r: ResMut<LoadStatusStack>| r.0.push(LoadStatus::EnterFinish),
|
||||
),
|
||||
);
|
||||
|
||||
stage.run(&mut world);
|
||||
|
@ -720,9 +735,9 @@ mod test {
|
|||
LoadStatus::EnterFinish,
|
||||
];
|
||||
|
||||
let mut collected = world.resource_mut::<Vec<LoadStatus>>();
|
||||
let mut collected = world.resource_mut::<LoadStatusStack>();
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ use super::Resource;
|
|||
/// # use bevy_ecs::prelude::*;
|
||||
/// # use bevy_ecs::system::Command;
|
||||
/// // Our world resource
|
||||
/// #[derive(Default)]
|
||||
/// #[derive(Resource, Default)]
|
||||
/// struct Counter(u64);
|
||||
///
|
||||
/// // Our custom command
|
||||
|
@ -331,7 +331,7 @@ impl<'w, 's> Commands<'w, 's> {
|
|||
/// ```
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// #
|
||||
/// # #[derive(Default)]
|
||||
/// # #[derive(Resource, Default)]
|
||||
/// # struct Scoreboard {
|
||||
/// # current_score: u32,
|
||||
/// # high_score: u32,
|
||||
|
@ -359,6 +359,7 @@ impl<'w, 's> Commands<'w, 's> {
|
|||
/// ```
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// #
|
||||
/// # #[derive(Resource)]
|
||||
/// # struct Scoreboard {
|
||||
/// # current_score: u32,
|
||||
/// # high_score: u32,
|
||||
|
@ -385,6 +386,7 @@ impl<'w, 's> Commands<'w, 's> {
|
|||
/// ```
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// #
|
||||
/// # #[derive(Resource)]
|
||||
/// # struct Scoreboard {
|
||||
/// # current_score: u32,
|
||||
/// # high_score: u32,
|
||||
|
@ -410,7 +412,7 @@ impl<'w, 's> Commands<'w, 's> {
|
|||
///
|
||||
/// ```
|
||||
/// # use bevy_ecs::{system::Command, prelude::*};
|
||||
/// #[derive(Default)]
|
||||
/// #[derive(Resource, Default)]
|
||||
/// struct Counter(u64);
|
||||
///
|
||||
/// struct AddToCounter(u64);
|
||||
|
@ -472,6 +474,7 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> {
|
|||
/// ```
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// #
|
||||
/// # #[derive(Resource)]
|
||||
/// # struct PlayerEntity { entity: Entity }
|
||||
/// # #[derive(Component)]
|
||||
/// # struct Health(u32);
|
||||
|
@ -548,6 +551,7 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> {
|
|||
/// ```
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// #
|
||||
/// # #[derive(Resource)]
|
||||
/// # struct PlayerEntity { entity: Entity }
|
||||
/// #
|
||||
/// # #[derive(Component)]
|
||||
|
@ -580,6 +584,7 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> {
|
|||
/// ```
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// #
|
||||
/// # #[derive(Resource)]
|
||||
/// # struct TargetEnemy { entity: Entity }
|
||||
/// # #[derive(Component)]
|
||||
/// # struct Enemy;
|
||||
|
@ -609,6 +614,7 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> {
|
|||
/// ```
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// #
|
||||
/// # #[derive(Resource)]
|
||||
/// # struct CharacterToRemove { entity: Entity }
|
||||
/// #
|
||||
/// fn remove_character_system(
|
||||
|
@ -854,7 +860,7 @@ mod tests {
|
|||
use crate::{
|
||||
self as bevy_ecs,
|
||||
component::Component,
|
||||
system::{CommandQueue, Commands},
|
||||
system::{CommandQueue, Commands, Resource},
|
||||
world::World,
|
||||
};
|
||||
use std::sync::{
|
||||
|
@ -881,7 +887,7 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
#[derive(Component, Resource)]
|
||||
struct W<T>(T);
|
||||
|
||||
fn simple_command(world: &mut World) {
|
||||
|
@ -992,21 +998,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::<i32>());
|
||||
assert!(world.contains_resource::<f64>());
|
||||
assert!(world.contains_resource::<W<i32>>());
|
||||
assert!(world.contains_resource::<W<f64>>());
|
||||
|
||||
{
|
||||
let mut commands = Commands::new(&mut queue, &world);
|
||||
// test resource removal
|
||||
commands.remove_resource::<i32>();
|
||||
commands.remove_resource::<W<i32>>();
|
||||
}
|
||||
queue.apply(&mut world);
|
||||
assert!(!world.contains_resource::<i32>());
|
||||
assert!(world.contains_resource::<f64>());
|
||||
assert!(!world.contains_resource::<W<i32>>());
|
||||
assert!(world.contains_resource::<W<f64>>());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Entity, With<Foo>>,
|
||||
mut counter: ResMut<usize>,
|
||||
mut counter: ResMut<Counter>,
|
||||
) {
|
||||
for entity in &query {
|
||||
*counter += 1;
|
||||
counter.0 += 1;
|
||||
commands.entity(entity).remove::<Foo>();
|
||||
}
|
||||
}
|
||||
|
||||
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::<usize>(), 1);
|
||||
assert_eq!(world.resource::<Counter>().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::<usize>(), 1);
|
||||
assert_eq!(world.resource::<Counter>().0, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_archetype_for_exclusive_system_coerced() {
|
||||
#[derive(Resource, Default)]
|
||||
struct CountEntities(Vec<usize>);
|
||||
|
||||
fn spawn_entity(mut commands: crate::prelude::Commands) {
|
||||
commands.spawn().insert(Foo(0.0));
|
||||
}
|
||||
|
||||
fn count_entities(query: Query<&Foo>, mut res: ResMut<Vec<usize>>) {
|
||||
res.push(query.iter().len());
|
||||
fn count_entities(query: Query<&Foo>, mut res: ResMut<CountEntities>) {
|
||||
res.0.push(query.iter().len());
|
||||
}
|
||||
|
||||
let mut world = World::new();
|
||||
world.insert_resource(Vec::<usize>::new());
|
||||
world.init_resource::<CountEntities>();
|
||||
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<usize>>(), vec![0, 1]);
|
||||
assert_eq!(world.resource::<CountEntities>().0, vec![0, 1]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,6 +82,7 @@ impl SystemMeta {
|
|||
/// use bevy_ecs::event::Events;
|
||||
///
|
||||
/// struct MyEvent;
|
||||
/// #[derive(Resource)]
|
||||
/// struct MyResource(u32);
|
||||
///
|
||||
/// #[derive(Component)]
|
||||
|
@ -110,6 +111,7 @@ impl SystemMeta {
|
|||
/// use bevy_ecs::event::Events;
|
||||
///
|
||||
/// struct MyEvent;
|
||||
/// #[derive(Resource)]
|
||||
/// struct CachedSystemState<'w, 's>{
|
||||
/// event_state: SystemState<EventReader<'w, 's, MyEvent>>
|
||||
/// }
|
||||
|
@ -246,10 +248,9 @@ impl<Param: SystemParam> FromWorld for SystemState<Param> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bevy_ecs::system::IntoSystem;
|
||||
/// use bevy_ecs::system::Res;
|
||||
/// use bevy_ecs::prelude::*;
|
||||
///
|
||||
/// fn my_system_function(an_usize_resource: Res<usize>) {}
|
||||
/// fn my_system_function(a_usize_local: Local<usize>) {}
|
||||
///
|
||||
/// let system = IntoSystem::into_system(my_system_function);
|
||||
/// ```
|
||||
|
@ -526,6 +527,7 @@ impl<T> Copy for SystemTypeIdLabel<T> {}
|
|||
/// assert_eq!(chained_system.run((), &mut world), Some(42));
|
||||
/// }
|
||||
///
|
||||
/// #[derive(Resource)]
|
||||
/// struct Message(String);
|
||||
///
|
||||
/// fn parse_message(message: Res<Message>) -> Result<usize, ParseIntError> {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
//! # struct Player { alive: bool }
|
||||
//! # #[derive(Component)]
|
||||
//! # struct Score(u32);
|
||||
//! # #[derive(Resource)]
|
||||
//! # struct Round(u32);
|
||||
//! #
|
||||
//! fn update_score_system(
|
||||
|
@ -139,22 +140,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)]
|
||||
|
@ -187,7 +194,7 @@ mod tests {
|
|||
#[test]
|
||||
fn query_system_gets() {
|
||||
fn query_system(
|
||||
mut ran: ResMut<bool>,
|
||||
mut ran: ResMut<SystemRan>,
|
||||
entity_query: Query<Entity, With<A>>,
|
||||
b_query: Query<&B>,
|
||||
a_c_query: Query<(&A, &C)>,
|
||||
|
@ -227,11 +234,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));
|
||||
|
@ -239,14 +246,14 @@ mod tests {
|
|||
|
||||
run_system(&mut world, query_system);
|
||||
|
||||
assert!(*world.resource::<bool>(), "system ran");
|
||||
assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn or_param_set_system() {
|
||||
// Regression test for issue #762
|
||||
fn query_system(
|
||||
mut ran: ResMut<bool>,
|
||||
mut ran: ResMut<SystemRan>,
|
||||
mut set: ParamSet<(
|
||||
Query<(), Or<(Changed<A>, Changed<B>)>>,
|
||||
Query<(), Or<(Added<A>, Added<B>)>>,
|
||||
|
@ -258,24 +265,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::<bool>(), "system ran");
|
||||
assert_eq!(*world.resource::<SystemRan>(), 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<bool>,
|
||||
value: Res<Flipper>,
|
||||
mut changed: ResMut<Changed>,
|
||||
mut added: ResMut<Added>,
|
||||
) {
|
||||
|
@ -289,7 +305,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));
|
||||
|
||||
|
@ -310,7 +326,7 @@ mod tests {
|
|||
assert_eq!(world.resource::<Added>().0, 1);
|
||||
assert_eq!(world.resource::<Changed>().0, 1);
|
||||
|
||||
*world.resource_mut::<bool>() = true;
|
||||
world.resource_mut::<Flipper>().0 = true;
|
||||
schedule.run(&mut world);
|
||||
assert_eq!(world.resource::<Added>().0, 1);
|
||||
assert_eq!(world.resource::<Changed>().0, 2);
|
||||
|
@ -434,7 +450,7 @@ mod tests {
|
|||
run_system(&mut world, sys);
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Resource)]
|
||||
struct BufferRes {
|
||||
_buffer: Vec<u8>,
|
||||
}
|
||||
|
@ -477,36 +493,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::<u32>() + 1,
|
||||
value: world.resource::<ProtoFoo>().value + 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sys(local: Local<Foo>, mut modified: ResMut<bool>) {
|
||||
fn sys(local: Local<Foo>, mut system_ran: ResMut<SystemRan>) {
|
||||
assert_eq!(local.value, 2);
|
||||
*modified = true;
|
||||
*system_ran = SystemRan::Yes;
|
||||
}
|
||||
|
||||
run_system(&mut world, sys);
|
||||
|
||||
// ensure the system actually ran
|
||||
assert!(*world.resource::<bool>());
|
||||
assert_eq!(*world.resource::<SystemRan>(), 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<i32>);
|
||||
struct NotSend2(std::rc::Rc<i32>);
|
||||
world.insert_non_send_resource(NotSend1(std::rc::Rc::new(0)));
|
||||
|
@ -514,34 +536,38 @@ mod tests {
|
|||
fn sys(
|
||||
op: Option<NonSend<NotSend1>>,
|
||||
mut _op2: Option<NonSendMut<NotSend2>>,
|
||||
mut run: ResMut<bool>,
|
||||
mut system_ran: ResMut<SystemRan>,
|
||||
) {
|
||||
op.expect("NonSend should exist");
|
||||
*run = true;
|
||||
*system_ran = SystemRan::Yes;
|
||||
}
|
||||
|
||||
run_system(&mut world, sys);
|
||||
// ensure the system actually ran
|
||||
assert!(*world.resource::<bool>());
|
||||
assert_eq!(*world.resource::<SystemRan>(), 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<i32>);
|
||||
struct NotSend2(std::rc::Rc<i32>);
|
||||
|
||||
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<NotSend1>, mut _op2: NonSendMut<NotSend2>, mut run: ResMut<bool>) {
|
||||
*run = true;
|
||||
fn sys(
|
||||
_op: NonSend<NotSend1>,
|
||||
mut _op2: NonSendMut<NotSend2>,
|
||||
mut system_ran: ResMut<SystemRan>,
|
||||
) {
|
||||
*system_ran = SystemRan::Yes;
|
||||
}
|
||||
|
||||
run_system(&mut world, sys);
|
||||
assert!(*world.resource::<bool>());
|
||||
assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -553,13 +579,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());
|
||||
|
||||
|
@ -615,7 +644,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,
|
||||
|
@ -623,7 +652,7 @@ mod tests {
|
|||
entities: &Entities,
|
||||
bundles: &Bundles,
|
||||
query: Query<Entity, With<W<i32>>>,
|
||||
mut modified: ResMut<bool>,
|
||||
mut system_ran: ResMut<SystemRan>,
|
||||
) {
|
||||
assert_eq!(query.iter().count(), 1, "entity exists");
|
||||
for entity in &query {
|
||||
|
@ -647,13 +676,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::<bool>());
|
||||
assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -751,7 +780,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)]
|
||||
|
@ -774,7 +803,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)]
|
||||
|
|
|
@ -735,6 +735,7 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
|
|||
/// ```
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// #
|
||||
/// # #[derive(Resource)]
|
||||
/// # struct SelectedCharacter { entity: Entity }
|
||||
/// # #[derive(Component)]
|
||||
/// # struct Character { name: String }
|
||||
|
@ -841,6 +842,7 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
|
|||
/// ```
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// #
|
||||
/// # #[derive(Resource)]
|
||||
/// # struct PoisonedCharacter { character_id: Entity }
|
||||
/// # #[derive(Component)]
|
||||
/// # struct Health(u32);
|
||||
|
@ -967,6 +969,7 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
|
|||
/// ```
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// #
|
||||
/// # #[derive(Resource)]
|
||||
/// # struct SelectedCharacter { entity: Entity }
|
||||
/// # #[derive(Component)]
|
||||
/// # struct Character { name: String }
|
||||
|
@ -1022,6 +1025,7 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
|
|||
/// ```
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// #
|
||||
/// # #[derive(Resource)]
|
||||
/// # struct PoisonedCharacter { character_id: Entity }
|
||||
/// # #[derive(Component)]
|
||||
/// # struct Health(u32);
|
||||
|
@ -1233,7 +1237,7 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
|
|||
/// #
|
||||
/// # #[derive(Component)]
|
||||
/// # struct Player;
|
||||
/// # #[derive(Component)]
|
||||
/// # #[derive(Resource)]
|
||||
/// # struct Score(u32);
|
||||
/// fn update_score_system(query: Query<(), With<Player>>, mut score: ResMut<Score>) {
|
||||
/// if !query.is_empty() {
|
||||
|
@ -1258,6 +1262,7 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
|
|||
/// # #[derive(Component)]
|
||||
/// # struct InRange;
|
||||
/// #
|
||||
/// # #[derive(Resource)]
|
||||
/// # struct Target {
|
||||
/// # entity: Entity,
|
||||
/// # }
|
||||
|
@ -1352,6 +1357,7 @@ impl<'w, 's, Q: ReadOnlyWorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
|
|||
/// ```
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// #
|
||||
/// # #[derive(Resource)]
|
||||
/// # struct SelectedCharacter { entity: Entity }
|
||||
/// # #[derive(Component)]
|
||||
/// # struct Character { name: String }
|
||||
|
|
|
@ -34,6 +34,7 @@ use std::borrow::Cow;
|
|||
/// assert_eq!(chained_system.run((), &mut world), Some(42));
|
||||
/// }
|
||||
///
|
||||
/// #[derive(Resource)]
|
||||
/// struct Message(String);
|
||||
///
|
||||
/// fn parse_message_system(message: Res<Message>) -> Result<usize, ParseIntError> {
|
||||
|
|
|
@ -11,6 +11,7 @@ use crate::{
|
|||
system::{CommandQueue, Commands, Query, SystemMeta},
|
||||
world::{FromWorld, World},
|
||||
};
|
||||
pub use bevy_ecs_macros::Resource;
|
||||
pub use bevy_ecs_macros::SystemParam;
|
||||
use bevy_ecs_macros::{all_tuples, impl_param_set};
|
||||
use bevy_ptr::UnsafeCellDeref;
|
||||
|
@ -48,14 +49,16 @@ use std::{
|
|||
///
|
||||
/// ```
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// # #[derive(Resource)]
|
||||
/// # struct SomeResource;
|
||||
/// use std::marker::PhantomData;
|
||||
/// use bevy_ecs::system::SystemParam;
|
||||
///
|
||||
/// #[derive(SystemParam)]
|
||||
/// struct MyParam<'w, 's> {
|
||||
/// foo: Res<'w, usize>,
|
||||
/// foo: Res<'w, SomeResource>,
|
||||
/// #[system_param(ignore)]
|
||||
/// marker: PhantomData<&'s usize>,
|
||||
/// marker: PhantomData<&'s ()>,
|
||||
/// }
|
||||
///
|
||||
/// fn my_system(param: MyParam) {
|
||||
|
@ -217,13 +220,42 @@ pub struct ParamSetState<T: for<'w, 's> SystemParamFetch<'w, 's>>(T);
|
|||
|
||||
impl_param_set!();
|
||||
|
||||
/// A type that can be inserted into a [`World`] as a singleton.
|
||||
///
|
||||
/// You can access resource data in systems using the [`Res`] and [`ResMut`] system parameters
|
||||
///
|
||||
/// Only one resource of each type can be stored in a [`World`] at any given time.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # let mut world = World::default();
|
||||
/// # let mut schedule = Schedule::default();
|
||||
/// # schedule.add_stage("update", SystemStage::parallel());
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// #[derive(Resource)]
|
||||
/// struct MyResource { value: u32 }
|
||||
///
|
||||
/// world.insert_resource(MyResource { value: 42 });
|
||||
///
|
||||
/// fn read_resource_system(resource: Res<MyResource>) {
|
||||
/// assert_eq!(resource.value, 42);
|
||||
/// }
|
||||
///
|
||||
/// fn write_resource_system(mut resource: ResMut<MyResource>) {
|
||||
/// assert_eq!(resource.value, 42);
|
||||
/// resource.value = 0;
|
||||
/// assert_eq!(resource.value, 0);
|
||||
/// }
|
||||
/// # schedule.add_system_to_stage("update", read_resource_system.label("first"));
|
||||
/// # schedule.add_system_to_stage("update", write_resource_system.after("first"));
|
||||
/// # schedule.run_once(&mut world);
|
||||
/// ```
|
||||
pub trait Resource: Send + Sync + 'static {}
|
||||
|
||||
impl<T> 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.
|
||||
/// See the [`Resource`] documentation for usage.
|
||||
///
|
||||
/// If you need a unique mutable borrow, use [`ResMut`] instead.
|
||||
///
|
||||
|
@ -632,6 +664,7 @@ impl<'w, 's> SystemParamFetch<'w, 's> for WorldState {
|
|||
/// # use bevy_ecs::prelude::*;
|
||||
/// # use bevy_ecs::system::assert_is_system;
|
||||
/// struct Config(u32);
|
||||
/// #[derive(Resource)]
|
||||
/// struct Myu32Wrapper(u32);
|
||||
/// fn reset_to_system(value: Config) -> impl FnMut(ResMut<Myu32Wrapper>) {
|
||||
/// move |mut val| val.0 = value.0
|
||||
|
@ -640,12 +673,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 + FromWorld>(&'a mut T);
|
||||
pub struct Local<'a, T: FromWorld + Send + Sync + 'static>(&'a mut T);
|
||||
|
||||
// SAFETY: Local only accesses internal state
|
||||
unsafe impl<T: Resource> ReadOnlySystemParamFetch for LocalState<T> {}
|
||||
// SAFE: Local only accesses internal state
|
||||
unsafe impl<T: Send + Sync + 'static> ReadOnlySystemParamFetch for LocalState<T> {}
|
||||
|
||||
impl<'a, T: Resource + FromWorld> Debug for Local<'a, T>
|
||||
impl<'a, T: FromWorld + Send + Sync + 'static> Debug for Local<'a, T>
|
||||
where
|
||||
T: Debug,
|
||||
{
|
||||
|
@ -654,7 +687,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Resource + FromWorld> Deref for Local<'a, T> {
|
||||
impl<'a, T: FromWorld + Send + Sync + 'static> Deref for Local<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
#[inline]
|
||||
|
@ -663,7 +696,7 @@ impl<'a, T: Resource + FromWorld> Deref for Local<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Resource + FromWorld> DerefMut for Local<'a, T> {
|
||||
impl<'a, T: FromWorld + Send + Sync + 'static> DerefMut for Local<'a, T> {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.0
|
||||
|
@ -672,20 +705,20 @@ impl<'a, T: Resource + FromWorld> DerefMut for Local<'a, T> {
|
|||
|
||||
/// The [`SystemParamState`] of [`Local<T>`].
|
||||
#[doc(hidden)]
|
||||
pub struct LocalState<T: Resource>(T);
|
||||
pub struct LocalState<T: Send + Sync + 'static>(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<T>;
|
||||
}
|
||||
|
||||
// SAFETY: only local state is accessed
|
||||
unsafe impl<T: Resource + FromWorld> SystemParamState for LocalState<T> {
|
||||
// SAFE: only local state is accessed
|
||||
unsafe impl<T: FromWorld + Send + Sync + 'static> SystemParamState for LocalState<T> {
|
||||
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<T> {
|
||||
impl<'w, 's, T: Send + Sync + 'static + FromWorld> SystemParamFetch<'w, 's> for LocalState<T> {
|
||||
type Item = Local<'s, T>;
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -30,6 +30,7 @@ use std::{
|
|||
mod identifier;
|
||||
|
||||
pub use identifier::WorldId;
|
||||
|
||||
/// Stores and exposes operations on [entities](Entity), [components](Component), resources,
|
||||
/// and their associated metadata.
|
||||
///
|
||||
|
@ -43,41 +44,12 @@ pub use identifier::WorldId;
|
|||
/// To mutate different parts of the world simultaneously,
|
||||
/// use [`World::resource_scope`] or [`SystemState`](crate::system::SystemState).
|
||||
///
|
||||
/// # Resources
|
||||
/// ## Resources
|
||||
///
|
||||
/// Worlds can also store *resources*, which are unique instances of a given type that don't
|
||||
/// belong to a specific Entity. There are also *non send resources*, which can only be
|
||||
/// accessed on the main thread.
|
||||
///
|
||||
/// ## Usage of global resources
|
||||
///
|
||||
/// 1. Insert the resource into the `World`, using [`World::insert_resource`].
|
||||
/// 2. Fetch the resource from a system, using [`Res`](crate::system::Res) or [`ResMut`](crate::system::ResMut).
|
||||
///
|
||||
/// ```
|
||||
/// # let mut world = World::default();
|
||||
/// # let mut schedule = Schedule::default();
|
||||
/// # schedule.add_stage("update", SystemStage::parallel());
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// #
|
||||
/// struct MyResource { value: u32 }
|
||||
///
|
||||
/// world.insert_resource(MyResource { value: 42 });
|
||||
///
|
||||
/// fn read_resource_system(resource: Res<MyResource>) {
|
||||
/// assert_eq!(resource.value, 42);
|
||||
/// }
|
||||
///
|
||||
/// fn write_resource_system(mut resource: ResMut<MyResource>) {
|
||||
/// assert_eq!(resource.value, 42);
|
||||
/// resource.value = 0;
|
||||
/// assert_eq!(resource.value, 0);
|
||||
/// }
|
||||
/// #
|
||||
/// # schedule.add_system_to_stage("update", read_resource_system.label("first"));
|
||||
/// # schedule.add_system_to_stage("update", write_resource_system.after("first"));
|
||||
/// # schedule.run_once(&mut world);
|
||||
/// ```
|
||||
/// Worlds can also store [`Resource`]s,
|
||||
/// which are unique instances of a given type that don't belong to a specific Entity.
|
||||
/// There are also *non send resources*, which can only be accessed on the main thread.
|
||||
/// See [`Resource`] for usage.
|
||||
pub struct World {
|
||||
id: WorldId,
|
||||
pub(crate) entities: Entities,
|
||||
|
@ -1089,8 +1061,8 @@ impl World {
|
|||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use bevy_ecs::{component::Component, world::{World, Mut}};
|
||||
/// #[derive(Component)]
|
||||
/// use bevy_ecs::prelude::*;
|
||||
/// #[derive(Resource)]
|
||||
/// struct A(u32);
|
||||
/// #[derive(Component)]
|
||||
/// struct B(u32);
|
||||
|
@ -1597,6 +1569,7 @@ mod tests {
|
|||
change_detection::DetectChanges,
|
||||
component::{ComponentDescriptor, ComponentId, ComponentInfo, StorageType},
|
||||
ptr::OwningPtr,
|
||||
system::Resource,
|
||||
};
|
||||
use bevy_ecs_macros::Component;
|
||||
use bevy_utils::HashSet;
|
||||
|
@ -1726,7 +1699,7 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
#[derive(Resource)]
|
||||
struct TestResource(u32);
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -318,40 +318,47 @@ 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::<u32>();
|
||||
assert_eq!(1, *a);
|
||||
*a = 2;
|
||||
let mut a = cell.resource_mut::<A>();
|
||||
assert_eq!(1, a.0);
|
||||
a.0 = 2;
|
||||
}
|
||||
{
|
||||
let a = cell.resource::<u32>();
|
||||
assert_eq!(2, *a, "ensure access is dropped");
|
||||
let a = cell.resource::<A>();
|
||||
assert_eq!(2, a.0, "ensure access is dropped");
|
||||
|
||||
let b = cell.resource::<u32>();
|
||||
let a2 = cell.resource::<A>();
|
||||
assert_eq!(
|
||||
2, *b,
|
||||
2, a2.0,
|
||||
"ensure multiple immutable accesses can occur at the same time"
|
||||
);
|
||||
}
|
||||
{
|
||||
let a = cell.resource_mut::<u32>();
|
||||
let a = cell.resource_mut::<A>();
|
||||
assert_eq!(
|
||||
2, *a,
|
||||
2, a.0,
|
||||
"ensure both immutable accesses are dropped, enabling a new mutable access"
|
||||
);
|
||||
|
||||
let b = cell.resource::<u64>();
|
||||
let b = cell.resource::<B>();
|
||||
assert_eq!(
|
||||
1, *b,
|
||||
1, b.0,
|
||||
"ensure multiple non-conflicting mutable accesses can occur at the same time"
|
||||
);
|
||||
}
|
||||
|
@ -360,23 +367,20 @@ 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::<u32>();
|
||||
assert_eq!(1, *a);
|
||||
*a = 2;
|
||||
let mut a = cell.resource_mut::<A>();
|
||||
assert_eq!(1, a.0);
|
||||
a.0 = 2;
|
||||
}
|
||||
}
|
||||
|
||||
let u32_component_id = world
|
||||
.components
|
||||
.get_resource_id(TypeId::of::<u32>())
|
||||
.unwrap();
|
||||
let resource_id = world.components.get_resource_id(TypeId::of::<A>()).unwrap();
|
||||
let resource_archetype = world.archetypes.get(ArchetypeId::RESOURCE).unwrap();
|
||||
let u32_archetype_component_id = resource_archetype
|
||||
.get_archetype_component_id(u32_component_id)
|
||||
.get_archetype_component_id(resource_id)
|
||||
.unwrap();
|
||||
assert_eq!(world.archetype_component_access.access.len(), 1);
|
||||
assert_eq!(
|
||||
|
@ -393,38 +397,38 @@ 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::<u32>();
|
||||
let _value_b = cell.resource_mut::<u32>();
|
||||
let _value_a = cell.resource_mut::<A>();
|
||||
let _value_b = cell.resource_mut::<A>();
|
||||
}
|
||||
|
||||
#[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::<u32>();
|
||||
let _value_b = cell.resource_mut::<u32>();
|
||||
let _value_a = cell.resource::<A>();
|
||||
let _value_b = cell.resource_mut::<A>();
|
||||
}
|
||||
|
||||
#[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::<u32>();
|
||||
let _value_b = cell.resource::<u32>();
|
||||
let _value_a = cell.resource_mut::<A>();
|
||||
let _value_b = cell.resource::<A>();
|
||||
}
|
||||
|
||||
#[test]
|
||||
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::<u32>();
|
||||
let _value_b = cell.resource::<u32>();
|
||||
let _value_a = cell.resource::<A>();
|
||||
let _value_b = cell.resource::<A>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@ use bevy_ecs::prelude::*;
|
|||
#[derive(Component)]
|
||||
struct A(usize);
|
||||
|
||||
fn system(mut query: Query<&mut A>, e: Res<Entity>) {
|
||||
let iter = query.iter_many_mut([*e]);
|
||||
fn system(mut query: Query<&mut A>, e: Entity) {
|
||||
let iter = query.iter_many_mut([e]);
|
||||
|
||||
// This should fail to compile.
|
||||
is_iterator(iter)
|
||||
|
|
|
@ -3,9 +3,9 @@ use bevy_ecs::prelude::*;
|
|||
#[derive(Component)]
|
||||
struct A(usize);
|
||||
|
||||
fn system(mut query: Query<&mut A>, e: Res<Entity>) {
|
||||
let a1 = query.get_mut(*e).unwrap();
|
||||
let a2 = query.get_mut(*e).unwrap();
|
||||
fn system(mut query: Query<&mut A>, e: Entity) {
|
||||
let a1 = query.get_mut(e).unwrap();
|
||||
let a2 = query.get_mut(e).unwrap();
|
||||
// this should fail to compile
|
||||
println!("{} {}", a1.0, a2.0);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
error[E0499]: cannot borrow `query` as mutable more than once at a time
|
||||
--> tests/ui/system_query_get_lifetime_safety.rs:8:14
|
||||
|
|
||||
7 | let a1 = query.get_mut(*e).unwrap();
|
||||
| ----------------- first mutable borrow occurs here
|
||||
8 | let a2 = query.get_mut(*e).unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
|
||||
7 | let a1 = query.get_mut(e).unwrap();
|
||||
| ---------------- first mutable borrow occurs here
|
||||
8 | let a2 = query.get_mut(e).unwrap();
|
||||
| ^^^^^^^^^^^^^^^^ second mutable borrow occurs here
|
||||
9 | // this should fail to compile
|
||||
10 | println!("{} {}", a1.0, a2.0);
|
||||
| -- first borrow later used here
|
||||
|
|
|
@ -3,9 +3,9 @@ use bevy_ecs::prelude::*;
|
|||
#[derive(Component)]
|
||||
struct A(usize);
|
||||
|
||||
fn system(mut query: Query<&mut A>, e: Res<Entity>) {
|
||||
let a1 = query.get_many([*e, *e]).unwrap();
|
||||
let a2 = query.get_mut(*e).unwrap();
|
||||
fn system(mut query: Query<&mut A>, e: Entity) {
|
||||
let a1 = query.get_many([e, e]).unwrap();
|
||||
let a2 = query.get_mut(e).unwrap();
|
||||
// this should fail to compile
|
||||
println!("{} {}", a1[0].0, a2.0);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
error[E0502]: cannot borrow `query` as mutable because it is also borrowed as immutable
|
||||
--> tests/ui/system_query_get_many_lifetime_safety.rs:8:14
|
||||
|
|
||||
7 | let a1 = query.get_many([*e, *e]).unwrap();
|
||||
| ------------------------ immutable borrow occurs here
|
||||
8 | let a2 = query.get_mut(*e).unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
|
||||
7 | let a1 = query.get_many([e, e]).unwrap();
|
||||
| ---------------------- immutable borrow occurs here
|
||||
8 | let a2 = query.get_mut(e).unwrap();
|
||||
| ^^^^^^^^^^^^^^^^ mutable borrow occurs here
|
||||
9 | // this should fail to compile
|
||||
10 | println!("{} {}", a1[0].0, a2.0);
|
||||
| ----- immutable borrow later used here
|
||||
|
|
|
@ -3,9 +3,9 @@ use bevy_ecs::prelude::*;
|
|||
#[derive(Component)]
|
||||
struct A(usize);
|
||||
|
||||
fn system(mut query: Query<&mut A>, e: Res<Entity>) {
|
||||
let a1 = query.get_many_mut([*e, *e]).unwrap();
|
||||
let a2 = query.get_mut(*e).unwrap();
|
||||
fn system(mut query: Query<&mut A>, e: Entity) {
|
||||
let a1 = query.get_many_mut([e, e]).unwrap();
|
||||
let a2 = query.get_mut(e).unwrap();
|
||||
// this should fail to compile
|
||||
println!("{} {}", a1[0].0, a2.0);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
error[E0499]: cannot borrow `query` as mutable more than once at a time
|
||||
--> tests/ui/system_query_get_many_mut_lifetime_safety.rs:8:14
|
||||
|
|
||||
7 | let a1 = query.get_many_mut([*e, *e]).unwrap();
|
||||
| ---------------------------- first mutable borrow occurs here
|
||||
8 | let a2 = query.get_mut(*e).unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
|
||||
7 | let a1 = query.get_many_mut([e, e]).unwrap();
|
||||
| -------------------------- first mutable borrow occurs here
|
||||
8 | let a2 = query.get_mut(e).unwrap();
|
||||
| ^^^^^^^^^^^^^^^^ second mutable borrow occurs here
|
||||
9 | // this should fail to compile
|
||||
10 | println!("{} {}", a1[0].0, a2.0);
|
||||
| ----- first borrow later used here
|
||||
|
|
|
@ -3,9 +3,9 @@ use bevy_ecs::prelude::*;
|
|||
#[derive(Component)]
|
||||
struct A(usize);
|
||||
|
||||
fn system(mut query: Query<&mut A>, e: Res<Entity>) {
|
||||
fn system(mut query: Query<&mut A>, e: Entity) {
|
||||
let mut results = Vec::new();
|
||||
let mut iter = query.iter_many_mut([*e, *e]);
|
||||
let mut iter = query.iter_many_mut([e, e]);
|
||||
while let Some(a) = iter.fetch_next() {
|
||||
// this should fail to compile
|
||||
results.push(a);
|
||||
|
|
|
@ -3,23 +3,23 @@ use bevy_ecs::prelude::*;
|
|||
#[derive(Component)]
|
||||
struct A(usize);
|
||||
|
||||
fn query_set(mut queries: ParamSet<(Query<&mut A>, Query<&A>)>, e: Res<Entity>) {
|
||||
fn query_set(mut queries: ParamSet<(Query<&mut A>, Query<&A>)>, e: Entity) {
|
||||
let mut q2 = queries.p0();
|
||||
let mut b = q2.get_mut(*e).unwrap();
|
||||
let mut b = q2.get_mut(e).unwrap();
|
||||
|
||||
let q1 = queries.p1();
|
||||
let a = q1.get(*e).unwrap();
|
||||
let a = q1.get(e).unwrap();
|
||||
|
||||
// this should fail to compile
|
||||
b.0 = a.0
|
||||
}
|
||||
|
||||
fn query_set_flip(mut queries: ParamSet<(Query<&mut A>, Query<&A>)>, e: Res<Entity>) {
|
||||
fn query_set_flip(mut queries: ParamSet<(Query<&mut A>, Query<&A>)>, e: Entity) {
|
||||
let q1 = queries.p1();
|
||||
let a = q1.get(*e).unwrap();
|
||||
let a = q1.get(e).unwrap();
|
||||
|
||||
let mut q2 = queries.p0();
|
||||
let mut b = q2.get_mut(*e).unwrap();
|
||||
let mut b = q2.get_mut(e).unwrap();
|
||||
|
||||
// this should fail to compile
|
||||
b.0 = a.0
|
||||
|
|
|
@ -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<T> {
|
||||
/// The position data of the input devices.
|
||||
axis_data: HashMap<T, f32>,
|
||||
|
|
|
@ -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};
|
||||
|
||||
/// A gamepad with an associated `ID`.
|
||||
|
@ -39,7 +39,7 @@ impl Gamepad {
|
|||
/// The [`Gamepad`]s are registered and deregistered in the [`gamepad_connection_system`]
|
||||
/// whenever a [`GamepadEventType::Connected`] or [`GamepadEventType::Disconnected`]
|
||||
/// event is received.
|
||||
#[derive(Default, Debug)]
|
||||
#[derive(Resource, Default, Debug)]
|
||||
pub struct Gamepads {
|
||||
/// The collection of the connected [`Gamepad`]s.
|
||||
gamepads: HashSet<Gamepad>,
|
||||
|
@ -144,18 +144,19 @@ impl GamepadEvent {
|
|||
/// # use bevy_input::gamepad::GamepadEventRaw;
|
||||
/// # use bevy_app::prelude::*;
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// #
|
||||
/// // This system sets the `bool` resource to `true` if the `South` button
|
||||
/// // of the first gamepad is pressed.
|
||||
/// #[derive(Resource)]
|
||||
/// struct MyResource(bool);
|
||||
///
|
||||
/// // This system sets the bool inside `MyResource` to `true` if the `South` button of the first gamepad is pressed.
|
||||
/// fn change_resource_on_gamepad_button_press(
|
||||
/// mut my_resource: ResMut<bool>,
|
||||
/// mut my_resource: ResMut<MyResource>,
|
||||
/// gamepads: Res<Gamepads>,
|
||||
/// button_inputs: ResMut<Input<GamepadButton>>,
|
||||
/// ) {
|
||||
/// let gamepad = gamepads.iter().next().unwrap();
|
||||
/// let gamepad_button= GamepadButton::new(*gamepad, GamepadButtonType::South);
|
||||
///
|
||||
/// *my_resource = button_inputs.pressed(gamepad_button);
|
||||
/// my_resource.0 = button_inputs.pressed(gamepad_button);
|
||||
/// }
|
||||
///
|
||||
/// // Create our app.
|
||||
|
@ -163,7 +164,7 @@ impl GamepadEvent {
|
|||
///
|
||||
/// // Add the input plugin and the system/resource we want to test.
|
||||
/// app.add_plugin(InputPlugin)
|
||||
/// .insert_resource(false)
|
||||
/// .insert_resource(MyResource(false))
|
||||
/// .add_system(change_resource_on_gamepad_button_press);
|
||||
///
|
||||
/// // Define our dummy gamepad input data.
|
||||
|
@ -185,8 +186,8 @@ impl GamepadEvent {
|
|||
/// app.update();
|
||||
///
|
||||
/// // At this point you can check if your game logic corresponded correctly to the gamepad input.
|
||||
/// // In this example we are checking if the `bool` resource was updated from `false` to `true`.
|
||||
/// assert!(app.world.resource::<bool>());
|
||||
/// // In this example we are checking if the bool in `MyResource` was updated from `false` to `true`.
|
||||
/// assert!(app.world.resource::<MyResource>().0);
|
||||
///
|
||||
/// // Send the gamepad input event to mark the `South` gamepad button as released.
|
||||
/// // This updates the `Input<GamepadButton>` resource accordingly.
|
||||
|
@ -198,8 +199,8 @@ impl GamepadEvent {
|
|||
/// // Advance the execution of the schedule by another cycle.
|
||||
/// app.update();
|
||||
///
|
||||
/// // Check if the `bool` resource was updated from `true` to `false`.
|
||||
/// assert!(!app.world.resource::<bool>());
|
||||
/// // Check if the bool in `MyResource` was updated from `true` to `false`.
|
||||
/// assert!(!app.world.resource::<MyResource>().0);
|
||||
/// #
|
||||
/// # bevy_ecs::system::assert_is_system(change_resource_on_gamepad_button_press);
|
||||
/// ```
|
||||
|
@ -391,7 +392,7 @@ impl GamepadAxis {
|
|||
///
|
||||
/// The [`GamepadSettings`] are used inside of the [`gamepad_event_system`], but are never written to
|
||||
/// inside of `bevy`. To modify these settings, mutate the corresponding resource.
|
||||
#[derive(Default, Debug)]
|
||||
#[derive(Resource, Default, Debug)]
|
||||
pub struct GamepadSettings {
|
||||
/// The default button settings.
|
||||
pub default_button_settings: ButtonSettings,
|
||||
|
|
|
@ -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<T: Eq + Hash> {
|
||||
/// A collection of every button that is currently being pressed.
|
||||
pressed: HashSet<T>,
|
||||
|
|
|
@ -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<u64, Touch>,
|
||||
|
|
|
@ -14,6 +14,7 @@ trace = [ "tracing-error" ]
|
|||
[dependencies]
|
||||
bevy_app = { path = "../bevy_app", version = "0.9.0-dev" }
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.9.0-dev" }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.9.0-dev" }
|
||||
|
||||
tracing-subscriber = {version = "0.3.1", features = ["registry", "env-filter"]}
|
||||
tracing-chrome = { version = "0.4.0", optional = true }
|
||||
|
|
|
@ -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")]
|
||||
|
@ -89,6 +91,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,
|
||||
|
|
|
@ -23,6 +23,7 @@ bevy_render = { path = "../bevy_render", version = "0.9.0-dev" }
|
|||
bevy_transform = { path = "../bevy_transform", version = "0.9.0-dev" }
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.9.0-dev" }
|
||||
bevy_window = { path = "../bevy_window", version = "0.9.0-dev" }
|
||||
bevy_derive = { path = "../bevy_derive", version = "0.9.0-dev" }
|
||||
|
||||
# other
|
||||
bitflags = "1.2"
|
||||
|
|
|
@ -73,7 +73,7 @@ impl PointLight {
|
|||
pub const DEFAULT_SHADOW_NORMAL_BIAS: f32 = 0.6;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Reflect)]
|
||||
#[derive(Resource, Clone, Debug, Reflect)]
|
||||
#[reflect(Resource)]
|
||||
pub struct PointLightShadowMap {
|
||||
pub size: usize,
|
||||
|
@ -208,7 +208,7 @@ impl DirectionalLight {
|
|||
pub const DEFAULT_SHADOW_NORMAL_BIAS: f32 = 0.6;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Reflect)]
|
||||
#[derive(Resource, Clone, Debug, Reflect)]
|
||||
#[reflect(Resource)]
|
||||
pub struct DirectionalLightShadowMap {
|
||||
pub size: usize,
|
||||
|
@ -224,7 +224,7 @@ impl Default for DirectionalLightShadowMap {
|
|||
}
|
||||
|
||||
/// An ambient light, which lights the entire scene equally.
|
||||
#[derive(Clone, Debug, ExtractResource, Reflect)]
|
||||
#[derive(Resource, Clone, Debug, ExtractResource, Reflect)]
|
||||
#[reflect(Resource)]
|
||||
pub struct AmbientLight {
|
||||
pub color: Color,
|
||||
|
@ -773,7 +773,7 @@ impl PointLightAssignmentData {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Resource, Default)]
|
||||
pub struct GlobalVisiblePointLights {
|
||||
entities: HashSet<Entity>,
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ use crate::{
|
|||
use bevy_app::{App, Plugin};
|
||||
use bevy_asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle};
|
||||
use bevy_core_pipeline::core_3d::{AlphaMask3d, Opaque3d, Transparent3d};
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::{
|
||||
entity::Entity,
|
||||
event::EventReader,
|
||||
|
@ -12,7 +13,7 @@ use bevy_ecs::{
|
|||
schedule::ParallelSystemDescriptorCoercion,
|
||||
system::{
|
||||
lifetimeless::{Read, SQuery, SRes},
|
||||
Commands, Local, Query, Res, ResMut, SystemParamItem,
|
||||
Commands, Local, Query, Res, ResMut, Resource, SystemParamItem,
|
||||
},
|
||||
world::FromWorld,
|
||||
};
|
||||
|
@ -224,6 +225,7 @@ where
|
|||
}
|
||||
|
||||
/// Render pipeline data for a given [`Material`].
|
||||
#[derive(Resource)]
|
||||
pub struct MaterialPipeline<M: Material> {
|
||||
pub mesh_pipeline: MeshPipeline,
|
||||
pub material_layout: BindGroupLayout,
|
||||
|
@ -434,6 +436,7 @@ pub struct PreparedMaterial<T: Material> {
|
|||
pub properties: MaterialProperties,
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
struct ExtractedMaterials<M: Material> {
|
||||
extracted: Vec<(Handle<M>, M)>,
|
||||
removed: Vec<Handle<M>>,
|
||||
|
@ -449,7 +452,14 @@ impl<M: Material> Default for ExtractedMaterials<M> {
|
|||
}
|
||||
|
||||
/// Stores all prepared representations of [`Material`] assets for as long as they exist.
|
||||
pub type RenderMaterials<T> = HashMap<Handle<T>, PreparedMaterial<T>>;
|
||||
#[derive(Resource, Deref, DerefMut)]
|
||||
pub struct RenderMaterials<T: Material>(pub HashMap<Handle<T>, PreparedMaterial<T>>);
|
||||
|
||||
impl<T: Material> Default for RenderMaterials<T> {
|
||||
fn default() -> Self {
|
||||
Self(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
/// This system extracts all created or modified assets of the corresponding [`Material`] type
|
||||
/// into the "render world".
|
||||
|
|
|
@ -214,6 +214,7 @@ pub const MAX_UNIFORM_BUFFER_POINT_LIGHTS: usize = 256;
|
|||
pub const MAX_DIRECTIONAL_LIGHTS: usize = 1;
|
||||
pub const SHADOW_FORMAT: TextureFormat = TextureFormat::Depth32Float;
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct ShadowPipeline {
|
||||
pub view_layout: BindGroupLayout,
|
||||
pub mesh_layout: BindGroupLayout,
|
||||
|
@ -662,6 +663,7 @@ pub struct ViewLightsUniformOffset {
|
|||
// at least that many are supported using this constant and SupportedBindingType::from_device()
|
||||
pub const CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT: u32 = 3;
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct GlobalLightMeta {
|
||||
pub gpu_point_lights: GpuPointLights,
|
||||
pub entity_to_index: HashMap<Entity, usize>,
|
||||
|
@ -686,7 +688,7 @@ impl GlobalLightMeta {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Resource, Default)]
|
||||
pub struct LightMeta {
|
||||
pub view_gpu_lights: DynamicUniformBuffer<GpuLights>,
|
||||
pub shadow_view_bind_group: Option<BindGroup>,
|
||||
|
|
|
@ -165,7 +165,7 @@ pub fn extract_meshes(
|
|||
commands.insert_or_spawn_batch(not_caster_commands);
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[derive(Resource, Debug, Default)]
|
||||
pub struct ExtractedJoints {
|
||||
pub buffer: Vec<Mat4>,
|
||||
}
|
||||
|
@ -247,7 +247,7 @@ pub fn extract_skinned_meshes(
|
|||
commands.insert_or_spawn_batch(values);
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Resource, Clone)]
|
||||
pub struct MeshPipeline {
|
||||
pub view_layout: BindGroupLayout,
|
||||
pub mesh_layout: BindGroupLayout,
|
||||
|
@ -651,6 +651,7 @@ impl SpecializedMeshPipeline for MeshPipeline {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct MeshBindGroup {
|
||||
pub normal: BindGroup,
|
||||
pub skinned: Option<BindGroup>,
|
||||
|
@ -706,6 +707,7 @@ pub fn queue_mesh_bind_group(
|
|||
// ignoring the rest, whether they're valid for other dynamic offsets or not. This trick may
|
||||
// be supported later in encase, and then we should make use of it.
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct SkinnedMeshUniform {
|
||||
pub buffer: BufferVec<Mat4>,
|
||||
}
|
||||
|
|
|
@ -62,13 +62,14 @@ fn extract_wireframes(mut commands: Commands, query: Extract<Query<Entity, With<
|
|||
#[reflect(Component, Default)]
|
||||
pub struct Wireframe;
|
||||
|
||||
#[derive(Debug, Clone, Default, ExtractResource, Reflect)]
|
||||
#[derive(Resource, Debug, Clone, Default, ExtractResource, Reflect)]
|
||||
#[reflect(Resource)]
|
||||
pub struct WireframeConfig {
|
||||
/// Whether to show wireframes for all meshes. If `false`, only meshes with a [Wireframe] component will be rendered.
|
||||
pub global: bool,
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct WireframePipeline {
|
||||
mesh_pipeline: MeshPipeline,
|
||||
shader: Handle<Shader>,
|
||||
|
|
|
@ -69,6 +69,7 @@ impl<C: Component + ShaderType + WriteInto + Clone> Plugin for UniformComponentP
|
|||
}
|
||||
|
||||
/// Stores all uniforms of the component type.
|
||||
#[derive(Resource)]
|
||||
pub struct ComponentUniforms<C: Component + ShaderType> {
|
||||
uniforms: DynamicUniformBuffer<C>,
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ use crate::{
|
|||
primitives::{CubemapFrusta, Frustum},
|
||||
render_graph::RenderGraph,
|
||||
render_resource::{PipelineCache, Shader, ShaderLoader},
|
||||
renderer::render_system,
|
||||
renderer::{render_system, RenderInstance},
|
||||
texture::ImagePlugin,
|
||||
view::{ViewPlugin, WindowRenderPlugin},
|
||||
};
|
||||
|
@ -91,9 +91,13 @@ pub enum RenderStage {
|
|||
/// This resource is only available during [`RenderStage::Extract`] and not
|
||||
/// during command application of that stage.
|
||||
/// See [`Extract`] for more details.
|
||||
#[derive(Default)]
|
||||
#[derive(Resource, Default)]
|
||||
pub struct MainWorld(World);
|
||||
|
||||
/// The Render App World. This is only available as a resource during the Extract step.
|
||||
#[derive(Resource, Default)]
|
||||
pub struct RenderWorld(World);
|
||||
|
||||
impl Deref for MainWorld {
|
||||
type Target = World;
|
||||
|
||||
|
@ -194,7 +198,7 @@ impl Plugin for RenderPlugin {
|
|||
)
|
||||
.add_stage(RenderStage::Cleanup, SystemStage::parallel())
|
||||
.init_resource::<RenderGraph>()
|
||||
.insert_resource(instance)
|
||||
.insert_resource(RenderInstance(instance))
|
||||
.insert_resource(device)
|
||||
.insert_resource(queue)
|
||||
.insert_resource(adapter_info)
|
||||
|
@ -323,7 +327,7 @@ impl Plugin for RenderPlugin {
|
|||
|
||||
/// A "scratch" world used to avoid allocating new worlds every frame when
|
||||
/// swapping out the [`MainWorld`] for [`RenderStage::Extract`].
|
||||
#[derive(Default)]
|
||||
#[derive(Resource, Default)]
|
||||
struct ScratchMainWorld(World);
|
||||
|
||||
/// Executes the [`Extract`](RenderStage::Extract) stage of the renderer.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::{Extract, RenderApp, RenderStage};
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_asset::{Asset, AssetEvent, Assets, Handle};
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::{
|
||||
prelude::*,
|
||||
system::{StaticSystemParam, SystemParam, SystemParamItem},
|
||||
|
@ -101,6 +102,7 @@ impl<A: RenderAsset> Plugin for RenderAssetPlugin<A> {
|
|||
}
|
||||
|
||||
/// Temporarily stores the extracted and removed assets of the current frame.
|
||||
#[derive(Resource)]
|
||||
pub struct ExtractedAssets<A: RenderAsset> {
|
||||
extracted: Vec<(Handle<A>, A::ExtractedAsset)>,
|
||||
removed: Vec<Handle<A>>,
|
||||
|
@ -117,7 +119,14 @@ impl<A: RenderAsset> Default for ExtractedAssets<A> {
|
|||
|
||||
/// Stores all GPU representations ([`RenderAsset::PreparedAssets`](RenderAsset::PreparedAsset))
|
||||
/// of [`RenderAssets`](RenderAsset) as long as they exist.
|
||||
pub type RenderAssets<A> = HashMap<Handle<A>, <A as RenderAsset>::PreparedAsset>;
|
||||
#[derive(Resource, Deref, DerefMut)]
|
||||
pub struct RenderAssets<A: RenderAsset>(HashMap<Handle<A>, A::PreparedAsset>);
|
||||
|
||||
impl<A: RenderAsset> Default for RenderAssets<A> {
|
||||
fn default() -> Self {
|
||||
Self(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
/// This system extracts all crated or modified assets of the corresponding [`RenderAsset`] type
|
||||
/// into the "render world".
|
||||
|
@ -155,6 +164,7 @@ fn extract_render_asset<A: RenderAsset>(
|
|||
|
||||
// TODO: consider storing inside system?
|
||||
/// All assets that should be prepared next frame.
|
||||
#[derive(Resource)]
|
||||
pub struct PrepareNextFrameAssets<A: RenderAsset> {
|
||||
assets: Vec<(Handle<A>, A::ExtractedAsset)>,
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
|||
},
|
||||
renderer::RenderContext,
|
||||
};
|
||||
use bevy_ecs::prelude::World;
|
||||
use bevy_ecs::{prelude::World, system::Resource};
|
||||
use bevy_utils::HashMap;
|
||||
use std::{borrow::Cow, fmt::Debug};
|
||||
|
||||
|
@ -48,7 +48,7 @@ use super::EdgeExistence;
|
|||
/// graph.add_node("output_node", MyNode);
|
||||
/// graph.add_node_edge("output_node", "input_node").unwrap();
|
||||
/// ```
|
||||
#[derive(Default)]
|
||||
#[derive(Resource, Default)]
|
||||
pub struct RenderGraph {
|
||||
nodes: HashMap<NodeId, NodeState>,
|
||||
node_names: HashMap<Cow<'static, str>, NodeId>,
|
||||
|
|
|
@ -7,7 +7,8 @@ use bevy_ecs::{
|
|||
all_tuples,
|
||||
entity::Entity,
|
||||
system::{
|
||||
lifetimeless::SRes, ReadOnlySystemParamFetch, SystemParam, SystemParamItem, SystemState,
|
||||
lifetimeless::SRes, ReadOnlySystemParamFetch, Resource, SystemParam, SystemParamItem,
|
||||
SystemState,
|
||||
},
|
||||
world::World,
|
||||
};
|
||||
|
@ -100,6 +101,7 @@ impl<P: PhaseItem> DrawFunctionsInternal<P> {
|
|||
|
||||
/// Stores all draw functions for the [`PhaseItem`] type hidden behind a reader-writer lock.
|
||||
/// To access them the [`DrawFunctions::read`] and [`DrawFunctions::write`] methods are used.
|
||||
#[derive(Resource)]
|
||||
pub struct DrawFunctions<P: PhaseItem> {
|
||||
internal: RwLock<DrawFunctionsInternal<P>>,
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@ use crate::{
|
|||
Extract,
|
||||
};
|
||||
use bevy_asset::{AssetEvent, Assets, Handle};
|
||||
use bevy_ecs::event::EventReader;
|
||||
use bevy_ecs::system::{Res, ResMut};
|
||||
use bevy_ecs::{event::EventReader, system::Resource};
|
||||
use bevy_utils::{default, tracing::error, Entry, HashMap, HashSet};
|
||||
use std::{hash::Hash, iter::FusedIterator, mem, ops::Deref, sync::Arc};
|
||||
use thiserror::Error;
|
||||
|
@ -263,6 +263,7 @@ impl LayoutCache {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct PipelineCache {
|
||||
layout_cache: LayoutCache,
|
||||
shader_cache: ShaderCache,
|
||||
|
|
|
@ -6,6 +6,7 @@ use crate::{
|
|||
VertexBufferLayout,
|
||||
},
|
||||
};
|
||||
use bevy_ecs::system::Resource;
|
||||
use bevy_utils::{
|
||||
default, hashbrown::hash_map::RawEntryMut, tracing::error, Entry, HashMap, PreHashMap,
|
||||
PreHashMapExt,
|
||||
|
@ -18,6 +19,7 @@ pub trait SpecializedRenderPipeline {
|
|||
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor;
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct SpecializedRenderPipelines<S: SpecializedRenderPipeline> {
|
||||
cache: HashMap<S::Key, CachedRenderPipelineId>,
|
||||
}
|
||||
|
@ -80,6 +82,7 @@ pub trait SpecializedMeshPipeline {
|
|||
) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError>;
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct SpecializedMeshPipelines<S: SpecializedMeshPipeline> {
|
||||
mesh_layout_cache:
|
||||
PreHashMap<InnerMeshVertexBufferLayout, HashMap<S::Key, CachedRenderPipelineId>>,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
mod graph_runner;
|
||||
mod render_device;
|
||||
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_utils::tracing::{error, info, info_span};
|
||||
pub use graph_runner::*;
|
||||
pub use render_device::*;
|
||||
|
@ -28,7 +29,7 @@ pub fn render_system(world: &mut World) {
|
|||
if let Err(e) = RenderGraphRunner::run(
|
||||
graph,
|
||||
render_device.clone(), // TODO: is this clone really necessary?
|
||||
render_queue,
|
||||
&render_queue.0,
|
||||
world,
|
||||
) {
|
||||
error!("Error running render graph:");
|
||||
|
@ -84,11 +85,17 @@ pub fn render_system(world: &mut World) {
|
|||
}
|
||||
|
||||
/// This queue is used to enqueue tasks for the GPU to execute asynchronously.
|
||||
pub type RenderQueue = Arc<Queue>;
|
||||
#[derive(Resource, Clone, Deref, DerefMut)]
|
||||
pub struct RenderQueue(pub Arc<Queue>);
|
||||
|
||||
/// The GPU instance is used to initialize the [`RenderQueue`] and [`RenderDevice`],
|
||||
/// as well as to create [`WindowSurfaces`](crate::view::window::WindowSurfaces).
|
||||
pub type RenderInstance = Instance;
|
||||
#[derive(Resource, Deref, DerefMut)]
|
||||
pub struct RenderInstance(pub Instance);
|
||||
|
||||
/// The `AdapterInfo` of the adapter in use by the renderer.
|
||||
#[derive(Resource, Clone, Deref, DerefMut)]
|
||||
pub struct RenderAdapterInfo(pub AdapterInfo);
|
||||
|
||||
/// Initializes the renderer by retrieving and preparing the GPU instance, device and queue
|
||||
/// for the specified backend.
|
||||
|
@ -96,7 +103,7 @@ pub async fn initialize_renderer(
|
|||
instance: &Instance,
|
||||
options: &WgpuSettings,
|
||||
request_adapter_options: &RequestAdapterOptions<'_>,
|
||||
) -> (RenderDevice, RenderQueue, AdapterInfo) {
|
||||
) -> (RenderDevice, RenderQueue, RenderAdapterInfo) {
|
||||
let adapter = instance
|
||||
.request_adapter(request_adapter_options)
|
||||
.await
|
||||
|
@ -245,7 +252,11 @@ pub async fn initialize_renderer(
|
|||
.unwrap();
|
||||
let device = Arc::new(device);
|
||||
let queue = Arc::new(queue);
|
||||
(RenderDevice::from(device), queue, adapter_info)
|
||||
(
|
||||
RenderDevice::from(device),
|
||||
RenderQueue(queue),
|
||||
RenderAdapterInfo(adapter_info),
|
||||
)
|
||||
}
|
||||
|
||||
/// The context with all information required to interact with the GPU.
|
||||
|
|
|
@ -2,13 +2,14 @@ use crate::render_resource::{
|
|||
BindGroup, BindGroupLayout, Buffer, ComputePipeline, RawRenderPipelineDescriptor,
|
||||
RenderPipeline, Sampler, Texture,
|
||||
};
|
||||
use bevy_ecs::system::Resource;
|
||||
use std::sync::Arc;
|
||||
use wgpu::{util::DeviceExt, BufferAsyncError, BufferBindingType};
|
||||
|
||||
use super::RenderQueue;
|
||||
|
||||
/// This GPU device is responsible for the creation of most rendering and compute resources.
|
||||
#[derive(Clone)]
|
||||
#[derive(Resource, Clone)]
|
||||
pub struct RenderDevice {
|
||||
device: Arc<wgpu::Device>,
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use bevy_ecs::system::Resource;
|
||||
pub use wgpu::{Backends, Features as WgpuFeatures, Limits as WgpuLimits, PowerPreference};
|
||||
|
||||
/// Configures the priority used when automatically configuring the features/limits of `wgpu`.
|
||||
|
@ -22,7 +23,7 @@ pub enum WgpuSettingsPriority {
|
|||
/// NOTE: If you want to use [`Backends::GL`](Backends::GL) in a native app on Windows, you must
|
||||
/// use [`ANGLE`](https://github.com/gfx-rs/wgpu#angle). This is because wgpu requires EGL to
|
||||
/// create a GL context without a window and only ANGLE supports that.
|
||||
#[derive(Clone)]
|
||||
#[derive(Resource, Clone)]
|
||||
pub struct WgpuSettings {
|
||||
pub device_label: Option<Cow<'static, str>>,
|
||||
pub backends: Option<Backends>,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{render_resource::*, texture::DefaultImageSampler};
|
||||
use bevy_derive::Deref;
|
||||
use bevy_ecs::prelude::FromWorld;
|
||||
use bevy_ecs::{prelude::FromWorld, system::Resource};
|
||||
use bevy_math::Vec2;
|
||||
use wgpu::{Extent3d, TextureDimension, TextureFormat};
|
||||
|
||||
|
@ -14,7 +14,7 @@ use crate::{
|
|||
/// which can be used in situations where an image was not explicitly defined. The most common
|
||||
/// use case is [`AsBindGroup`] implementations (such as materials) that support optional textures.
|
||||
/// [`FallbackImage`] defaults to a 1x1 fully white texture, making blending colors with it a no-op.
|
||||
#[derive(Deref)]
|
||||
#[derive(Resource, Deref)]
|
||||
pub struct FallbackImage(GpuImage);
|
||||
|
||||
impl FromWorld for FallbackImage {
|
||||
|
|
|
@ -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;
|
||||
|
@ -162,6 +162,7 @@ impl ImageSampler {
|
|||
/// Global resource for [`Image`] settings.
|
||||
///
|
||||
/// Can be set via `insert_resource` during app initialization to change the default settings.
|
||||
#[derive(Resource)]
|
||||
pub struct ImageSettings {
|
||||
/// The default image sampler to use when [`ImageSampler`] is set to `Default`.
|
||||
pub default_sampler: wgpu::SamplerDescriptor<'static>,
|
||||
|
@ -194,7 +195,7 @@ impl ImageSettings {
|
|||
///
|
||||
/// The [`ImageSettings`] resource can be set during app initialization to change the default
|
||||
/// image sampler.
|
||||
#[derive(Debug, Clone, Deref, DerefMut)]
|
||||
#[derive(Resource, Debug, Clone, Deref, DerefMut)]
|
||||
pub struct DefaultImageSampler(pub(crate) Sampler);
|
||||
|
||||
impl Default for Image {
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::{
|
|||
render_resource::{Texture, TextureView},
|
||||
renderer::RenderDevice,
|
||||
};
|
||||
use bevy_ecs::prelude::ResMut;
|
||||
use bevy_ecs::{prelude::ResMut, system::Resource};
|
||||
use bevy_utils::{Entry, HashMap};
|
||||
use wgpu::{TextureDescriptor, TextureViewDescriptor};
|
||||
|
||||
|
@ -26,7 +26,7 @@ pub struct CachedTexture {
|
|||
|
||||
/// This resource caches textures that are created repeatedly in the rendering process and
|
||||
/// are only required for one frame.
|
||||
#[derive(Default)]
|
||||
#[derive(Resource, Default)]
|
||||
pub struct TextureCache {
|
||||
textures: HashMap<wgpu::TextureDescriptor<'static>, Vec<CachedTextureMeta>>,
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ impl Plugin for ViewPlugin {
|
|||
/// .insert_resource(Msaa { samples: 4 })
|
||||
/// .run();
|
||||
/// ```
|
||||
#[derive(Clone, ExtractResource, Reflect)]
|
||||
#[derive(Resource, Clone, ExtractResource, Reflect)]
|
||||
#[reflect(Resource)]
|
||||
pub struct Msaa {
|
||||
/// The number of samples to run for Multi-Sample Anti-Aliasing. Higher numbers result in
|
||||
|
@ -105,7 +105,7 @@ pub struct ViewUniform {
|
|||
height: f32,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Resource, Default)]
|
||||
pub struct ViewUniforms {
|
||||
pub uniforms: DynamicUniformBuffer<ViewUniform>,
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ use std::ops::{Deref, DerefMut};
|
|||
use wgpu::TextureFormat;
|
||||
|
||||
/// Token to ensure a system runs on the main thread.
|
||||
#[derive(Default)]
|
||||
#[derive(Resource, Default)]
|
||||
pub struct NonSendMarker;
|
||||
|
||||
pub struct WindowRenderPlugin;
|
||||
|
@ -48,7 +48,7 @@ pub struct ExtractedWindow {
|
|||
pub size_changed: bool,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Resource)]
|
||||
pub struct ExtractedWindows {
|
||||
pub windows: HashMap<WindowId, ExtractedWindow>,
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ fn extract_windows(
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Resource, Default)]
|
||||
pub struct WindowSurfaces {
|
||||
surfaces: HashMap<WindowId, wgpu::Surface>,
|
||||
/// List of windows that we have already called the initial `configure_surface` for
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::{serde::SceneSerializer, Scene, SceneSpawnError};
|
||||
use anyhow::Result;
|
||||
use bevy_app::AppTypeRegistry;
|
||||
use bevy_ecs::{
|
||||
entity::EntityMap,
|
||||
reflect::{ReflectComponent, ReflectMapEntities},
|
||||
|
@ -84,7 +85,7 @@ impl DynamicScene {
|
|||
world: &mut World,
|
||||
entity_map: &mut EntityMap,
|
||||
) -> Result<(), SceneSpawnError> {
|
||||
let registry = world.resource::<TypeRegistryArc>().clone();
|
||||
let registry = world.resource::<AppTypeRegistry>().clone();
|
||||
let type_registry = registry.read();
|
||||
|
||||
for scene_entity in &self.entities {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::serde::SceneDeserializer;
|
||||
use anyhow::Result;
|
||||
use bevy_app::AppTypeRegistry;
|
||||
use bevy_asset::{AssetLoader, LoadContext, LoadedAsset};
|
||||
use bevy_ecs::world::{FromWorld, World};
|
||||
use bevy_reflect::TypeRegistryArc;
|
||||
|
@ -13,9 +14,9 @@ pub struct SceneLoader {
|
|||
|
||||
impl FromWorld for SceneLoader {
|
||||
fn from_world(world: &mut World) -> Self {
|
||||
let type_registry = world.resource::<TypeRegistryArc>();
|
||||
let type_registry = world.resource::<AppTypeRegistry>();
|
||||
SceneLoader {
|
||||
type_registry: (*type_registry).clone(),
|
||||
type_registry: type_registry.0.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
use crate::{DynamicScene, Scene};
|
||||
use bevy_app::AppTypeRegistry;
|
||||
use bevy_asset::{AssetEvent, Assets, Handle};
|
||||
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};
|
||||
use bevy_reflect::TypeRegistryArc;
|
||||
use bevy_utils::{tracing::error, HashMap};
|
||||
use thiserror::Error;
|
||||
use uuid::Uuid;
|
||||
|
@ -27,7 +27,7 @@ impl InstanceId {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Resource)]
|
||||
pub struct SceneSpawner {
|
||||
spawned_scenes: HashMap<Handle<Scene>, Vec<InstanceId>>,
|
||||
spawned_dynamic_scenes: HashMap<Handle<DynamicScene>, Vec<InstanceId>>,
|
||||
|
@ -164,7 +164,7 @@ impl SceneSpawner {
|
|||
let mut instance_info = InstanceInfo {
|
||||
entity_map: EntityMap::default(),
|
||||
};
|
||||
let type_registry = world.resource::<TypeRegistryArc>().clone();
|
||||
let type_registry = world.resource::<AppTypeRegistry>().clone();
|
||||
let type_registry = type_registry.read();
|
||||
world.resource_scope(|world, scenes: Mut<Assets<Scene>>| {
|
||||
let scene =
|
||||
|
|
|
@ -22,6 +22,7 @@ bevy_reflect = { path = "../bevy_reflect", version = "0.9.0-dev", features = [
|
|||
bevy_render = { path = "../bevy_render", version = "0.9.0-dev" }
|
||||
bevy_transform = { path = "../bevy_transform", version = "0.9.0-dev" }
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.9.0-dev" }
|
||||
bevy_derive = { path = "../bevy_derive", version = "0.9.0-dev" }
|
||||
|
||||
# other
|
||||
bytemuck = { version = "1.5", features = ["derive"] }
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use bevy_app::{App, Plugin};
|
||||
use bevy_asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle};
|
||||
use bevy_core_pipeline::core_2d::Transparent2d;
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::{
|
||||
entity::Entity,
|
||||
event::EventReader,
|
||||
|
@ -8,7 +9,7 @@ use bevy_ecs::{
|
|||
schedule::ParallelSystemDescriptorCoercion,
|
||||
system::{
|
||||
lifetimeless::{Read, SQuery, SRes},
|
||||
Commands, Local, Query, Res, ResMut, SystemParamItem,
|
||||
Commands, Local, Query, Res, ResMut, Resource, SystemParamItem,
|
||||
},
|
||||
world::FromWorld,
|
||||
};
|
||||
|
@ -170,6 +171,7 @@ where
|
|||
}
|
||||
|
||||
/// Render pipeline data for a given [`Material2d`]
|
||||
#[derive(Resource)]
|
||||
pub struct Material2dPipeline<M: Material2d> {
|
||||
pub mesh2d_pipeline: Mesh2dPipeline,
|
||||
pub material2d_layout: BindGroupLayout,
|
||||
|
@ -373,6 +375,7 @@ pub struct PreparedMaterial2d<T: Material2d> {
|
|||
pub key: T::Data,
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
struct ExtractedMaterials2d<M: Material2d> {
|
||||
extracted: Vec<(Handle<M>, M)>,
|
||||
removed: Vec<Handle<M>>,
|
||||
|
@ -388,7 +391,14 @@ impl<M: Material2d> Default for ExtractedMaterials2d<M> {
|
|||
}
|
||||
|
||||
/// Stores all prepared representations of [`Material2d`] assets for as long as they exist.
|
||||
pub type RenderMaterials2d<T> = HashMap<Handle<T>, PreparedMaterial2d<T>>;
|
||||
#[derive(Resource, Deref, DerefMut)]
|
||||
pub struct RenderMaterials2d<T: Material2d>(HashMap<Handle<T>, PreparedMaterial2d<T>>);
|
||||
|
||||
impl<T: Material2d> Default for RenderMaterials2d<T> {
|
||||
fn default() -> Self {
|
||||
Self(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
/// This system extracts all created or modified assets of the corresponding [`Material2d`] type
|
||||
/// into the "render world".
|
||||
|
|
|
@ -148,7 +148,7 @@ pub fn extract_mesh2d(
|
|||
commands.insert_or_spawn_batch(values);
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Resource, Clone)]
|
||||
pub struct Mesh2dPipeline {
|
||||
pub view_layout: BindGroupLayout,
|
||||
pub mesh_layout: BindGroupLayout,
|
||||
|
@ -379,6 +379,7 @@ impl SpecializedMeshPipeline for Mesh2dPipeline {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct Mesh2dBindGroup {
|
||||
pub value: BindGroup,
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ use bytemuck::{Pod, Zeroable};
|
|||
use copyless::VecHelper;
|
||||
use fixedbitset::FixedBitSet;
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct SpritePipeline {
|
||||
view_layout: BindGroupLayout,
|
||||
material_layout: BindGroupLayout,
|
||||
|
@ -190,12 +191,12 @@ pub struct ExtractedSprite {
|
|||
pub anchor: Vec2,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Resource, Default)]
|
||||
pub struct ExtractedSprites {
|
||||
pub sprites: Vec<ExtractedSprite>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Resource, Default)]
|
||||
pub struct SpriteAssetEvents {
|
||||
pub images: Vec<AssetEvent<Image>>,
|
||||
}
|
||||
|
@ -303,6 +304,7 @@ struct ColoredSpriteVertex {
|
|||
pub color: [f32; 4],
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct SpriteMeta {
|
||||
vertices: BufferVec<SpriteVertex>,
|
||||
colored_vertices: BufferVec<ColoredSpriteVertex>,
|
||||
|
@ -341,7 +343,7 @@ pub struct SpriteBatch {
|
|||
colored: bool,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Resource, Default)]
|
||||
pub struct ImageBindGroups {
|
||||
values: HashMap<Handle<Image>, BindGroup>,
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ use std::hash::Hash;
|
|||
|
||||
use ab_glyph::{PxScale, ScaleFont};
|
||||
use bevy_asset::{Assets, Handle, HandleId};
|
||||
use bevy_ecs::system::Resource;
|
||||
use bevy_math::Vec2;
|
||||
use bevy_render::texture::Image;
|
||||
use bevy_sprite::TextureAtlas;
|
||||
|
@ -14,6 +15,7 @@ use crate::{
|
|||
TextAlignment, TextSection,
|
||||
};
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct TextPipeline<ID> {
|
||||
brush: GlyphBrush,
|
||||
glyph_map: HashMap<ID, TextLayoutInfo>,
|
||||
|
|
|
@ -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<String, FixedTimestepState>,
|
||||
}
|
||||
|
@ -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::<Count>(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::<Count>());
|
||||
assert_eq!(0, world.resource::<Count>().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::<Count>());
|
||||
assert_eq!(0, world.resource::<Count>().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::<Count>());
|
||||
assert_eq!(1, world.resource::<Count>().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::<Count>());
|
||||
assert_eq!(3, world.resource::<Count>().0);
|
||||
assert_eq!(2., get_accumulator_deciseconds(&world));
|
||||
}
|
||||
|
||||
fn fixed_update(mut count: ResMut<Count>) {
|
||||
*count += 1;
|
||||
count.0 += 1;
|
||||
}
|
||||
|
||||
fn advance_time(world: &mut World, instance: Instant, seconds: f32) {
|
||||
|
|
|
@ -46,8 +46,11 @@ impl Plugin for TimePlugin {
|
|||
}
|
||||
|
||||
/// Channel resource used to receive time from render world
|
||||
#[derive(Resource)]
|
||||
pub struct TimeReceiver(pub Receiver<Instant>);
|
||||
|
||||
/// Channel resource used to send time from render world
|
||||
#[derive(Resource)]
|
||||
pub struct TimeSender(pub Sender<Instant>);
|
||||
|
||||
/// Creates channels used for sending time between render world and app world
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use bevy_ecs::reflect::ReflectResource;
|
||||
use bevy_ecs::{reflect::ReflectResource, system::Resource};
|
||||
use bevy_reflect::Reflect;
|
||||
use bevy_utils::{Duration, Instant};
|
||||
|
||||
/// Tracks elapsed time since the last update and since the App has started
|
||||
#[derive(Reflect, Debug, Clone)]
|
||||
#[derive(Resource, Reflect, Debug, Clone)]
|
||||
#[reflect(Resource)]
|
||||
pub struct Time {
|
||||
delta: Duration,
|
||||
|
@ -54,6 +54,7 @@ impl Time {
|
|||
/// # fn main () {
|
||||
/// # test_health_system();
|
||||
/// # }
|
||||
/// #[derive(Resource)]
|
||||
/// struct Health {
|
||||
/// // Health value between 0.0 and 1.0
|
||||
/// health_value: f32,
|
||||
|
|
|
@ -5,7 +5,7 @@ use bevy_ecs::{
|
|||
entity::Entity,
|
||||
event::EventReader,
|
||||
query::{Changed, With, Without, WorldQuery},
|
||||
system::{Query, Res, ResMut},
|
||||
system::{Query, Res, ResMut, Resource},
|
||||
};
|
||||
use bevy_hierarchy::{Children, Parent};
|
||||
use bevy_log::warn;
|
||||
|
@ -16,6 +16,7 @@ use bevy_window::{Window, WindowId, WindowScaleFactorChanged, Windows};
|
|||
use std::fmt;
|
||||
use taffy::{number::Number, Taffy};
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct FlexSurface {
|
||||
entity_to_taffy: HashMap<Entity, taffy::node::Node>,
|
||||
window_nodes: HashMap<WindowId, taffy::node::Node>,
|
||||
|
|
|
@ -168,7 +168,7 @@ pub struct ExtractedUiNode {
|
|||
pub clip: Option<Rect>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Resource, Default)]
|
||||
pub struct ExtractedUiNodes {
|
||||
pub uinodes: Vec<ExtractedUiNode>,
|
||||
}
|
||||
|
@ -341,6 +341,7 @@ struct UiVertex {
|
|||
pub color: [f32; 4],
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct UiMeta {
|
||||
vertices: BufferVec<UiVertex>,
|
||||
view_bind_group: Option<BindGroup>,
|
||||
|
@ -504,7 +505,7 @@ pub fn prepare_uinodes(
|
|||
ui_meta.vertices.write_buffer(&render_device, &render_queue);
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Resource, Default)]
|
||||
pub struct UiImageBindGroups {
|
||||
pub values: HashMap<Handle<Image>, BindGroup>,
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ use bevy_render::{
|
|||
render_resource::*, renderer::RenderDevice, texture::BevyDefault, view::ViewUniform,
|
||||
};
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct UiPipeline {
|
||||
pub view_layout: BindGroupLayout,
|
||||
pub image_layout: BindGroupLayout,
|
||||
|
|
|
@ -25,13 +25,14 @@ use bevy_app::prelude::*;
|
|||
use bevy_ecs::{
|
||||
event::Events,
|
||||
schedule::{ParallelSystemDescriptorCoercion, SystemLabel},
|
||||
system::Resource,
|
||||
};
|
||||
|
||||
/// The configuration information for the [`WindowPlugin`].
|
||||
///
|
||||
/// It can be added as a [`Resource`](bevy_ecs::system::Resource) before the [`WindowPlugin`]
|
||||
/// runs, to configure how it behaves.
|
||||
#[derive(Clone)]
|
||||
#[derive(Resource, Clone)]
|
||||
pub struct WindowSettings {
|
||||
/// Whether to create a window when added.
|
||||
///
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use bevy_ecs::system::Resource;
|
||||
use bevy_math::{DVec2, IVec2, UVec2, Vec2};
|
||||
use bevy_reflect::{FromReflect, Reflect};
|
||||
use bevy_utils::{tracing::warn, Uuid};
|
||||
|
@ -777,7 +778,7 @@ pub enum MonitorSelection {
|
|||
/// 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(Resource, Debug, Clone)]
|
||||
pub struct WindowDescriptor {
|
||||
/// The requested logical width of the window's client area.
|
||||
///
|
||||
|
|
|
@ -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<WindowId, Window>,
|
||||
}
|
||||
|
|
|
@ -316,7 +316,7 @@ impl Default for WinitPersistentState {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Resource)]
|
||||
struct WinitCreateWindowReader(ManualEventReader<CreateWindow>);
|
||||
|
||||
pub fn winit_runner_with(mut app: App) {
|
||||
|
|
|
@ -20,13 +20,14 @@ struct ResizeEvent {
|
|||
window_id: WindowId,
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
pub(crate) struct CanvasParentResizeEventChannel {
|
||||
sender: Sender<ResizeEvent>,
|
||||
receiver: Receiver<ResizeEvent>,
|
||||
}
|
||||
|
||||
fn canvas_parent_resize_event_handler(
|
||||
winit_windows: Res<WinitWindows>,
|
||||
winit_windows: NonSend<WinitWindows>,
|
||||
resize_events: Res<CanvasParentResizeEventChannel>,
|
||||
) {
|
||||
for event in resize_events.receiver.try_iter() {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -16,6 +16,7 @@ fn main() {
|
|||
.run();
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
struct MyEntity(Entity);
|
||||
|
||||
#[derive(Component)]
|
||||
|
|
|
@ -116,6 +116,7 @@ fn star(
|
|||
pub struct ColoredMesh2d;
|
||||
|
||||
/// Custom pipeline for 2d meshes with vertex colors
|
||||
#[derive(Resource)]
|
||||
pub struct ColoredMesh2dPipeline {
|
||||
/// this pipeline wraps the standard [`Mesh2dPipeline`]
|
||||
mesh2d_pipeline: Mesh2dPipeline,
|
||||
|
|
|
@ -21,7 +21,7 @@ enum AppState {
|
|||
Finished,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Resource, Default)]
|
||||
struct RpgSpriteHandles {
|
||||
handles: Vec<HandleUntyped>,
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ fn main() {
|
|||
.run();
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
struct Cubemap {
|
||||
is_loaded: bool,
|
||||
index: usize,
|
||||
|
|
|
@ -15,6 +15,7 @@ fn main() {
|
|||
.run();
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
struct Animations(Vec<Handle<AnimationClip>>);
|
||||
|
||||
fn setup(
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
use bevy::prelude::*;
|
||||
use std::io;
|
||||
|
||||
#[derive(Resource)]
|
||||
struct Input(String);
|
||||
|
||||
fn my_runner(mut app: App) {
|
||||
|
|
|
@ -35,6 +35,7 @@ impl Plugin for PrintMessagePlugin {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
struct PrintMessageState {
|
||||
message: String,
|
||||
timer: Timer,
|
||||
|
|
|
@ -46,7 +46,7 @@ fn main() {
|
|||
.run();
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Resource, Default)]
|
||||
struct State {
|
||||
handle: Handle<CustomAsset>,
|
||||
printed: bool,
|
||||
|
|
|
@ -22,9 +22,10 @@ fn main() {
|
|||
// Number of cubes to spawn across the x, y, and z axis
|
||||
const NUM_CUBES: u32 = 6;
|
||||
|
||||
#[derive(Deref)]
|
||||
#[derive(Resource, Deref)]
|
||||
struct BoxMeshHandle(Handle<Mesh>);
|
||||
#[derive(Deref)]
|
||||
|
||||
#[derive(Resource, Deref)]
|
||||
struct BoxMaterialHandle(Handle<StandardMaterial>);
|
||||
|
||||
/// Startup system which runs only once and generates our Box Mesh
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue