Plugins own their settings. Rework PluginGroup trait. (#6336)
# Objective
Fixes #5884 #2879
Alternative to #2988 #5885 #2886
"Immutable" Plugin settings are currently represented as normal ECS resources, which are read as part of plugin init. This presents a number of problems:
1. If a user inserts the plugin settings resource after the plugin is initialized, it will be silently ignored (and use the defaults instead)
2. Users can modify the plugin settings resource after the plugin has been initialized. This creates a false sense of control over settings that can no longer be changed.
(1) and (2) are especially problematic and confusing for the `WindowDescriptor` resource, but this is a general problem.
## Solution
Immutable Plugin settings now live on each Plugin struct (ex: `WindowPlugin`). PluginGroups have been reworked to support overriding plugin values. This also removes the need for the `add_plugins_with` api, as the `add_plugins` api can use the builder pattern directly. Settings that can be used at runtime continue to be represented as ECS resources.
Plugins are now configured like this:
```rust
app.add_plugin(AssetPlugin {
watch_for_changes: true,
..default()
})
```
PluginGroups are now configured like this:
```rust
app.add_plugins(DefaultPlugins
.set(AssetPlugin {
watch_for_changes: true,
..default()
})
)
```
This is an alternative to #2988, which is similar. But I personally prefer this solution for a couple of reasons:
* ~~#2988 doesn't solve (1)~~ #2988 does solve (1) and will panic in that case. I was wrong!
* This PR directly ties plugin settings to Plugin types in a 1:1 relationship, rather than a loose "setup resource" <-> plugin coupling (where the setup resource is consumed by the first plugin that uses it).
* I'm not a huge fan of overloading the ECS resource concept and implementation for something that has very different use cases and constraints.
## Changelog
- PluginGroups can now be configured directly using the builder pattern. Individual plugin values can be overridden by using `plugin_group.set(SomePlugin {})`, which enables overriding default plugin values.
- `WindowDescriptor` plugin settings have been moved to `WindowPlugin` and `AssetServerSettings` have been moved to `AssetPlugin`
- `app.add_plugins_with` has been replaced by using `add_plugins` with the builder pattern.
## Migration Guide
The `WindowDescriptor` settings have been moved from a resource to `WindowPlugin::window`:
```rust
// Old (Bevy 0.8)
app
.insert_resource(WindowDescriptor {
width: 400.0,
..default()
})
.add_plugins(DefaultPlugins)
// New (Bevy 0.9)
app.add_plugins(DefaultPlugins.set(WindowPlugin {
window: WindowDescriptor {
width: 400.0,
..default()
},
..default()
}))
```
The `AssetServerSettings` resource has been removed in favor of direct `AssetPlugin` configuration:
```rust
// Old (Bevy 0.8)
app
.insert_resource(AssetServerSettings {
watch_for_changes: true,
..default()
})
.add_plugins(DefaultPlugins)
// New (Bevy 0.9)
app.add_plugins(DefaultPlugins.set(AssetPlugin {
watch_for_changes: true,
..default()
}))
```
`add_plugins_with` has been replaced by `add_plugins` in combination with the builder pattern:
```rust
// Old (Bevy 0.8)
app.add_plugins_with(DefaultPlugins, |group| group.disable::<AssetPlugin>());
// New (Bevy 0.9)
app.add_plugins(DefaultPlugins.build().disable::<AssetPlugin>());
```
2022-10-24 21:20:33 +00:00
|
|
|
|
use crate::{CoreStage, Plugin, PluginGroup, StartupSchedule, StartupStage};
|
2021-11-22 23:16:36 +00:00
|
|
|
|
pub use bevy_derive::AppLabel;
|
Bevy ECS V2 (#1525)
# Bevy ECS V2
This is a rewrite of Bevy ECS (basically everything but the new executor/schedule, which are already awesome). The overall goal was to improve the performance and versatility of Bevy ECS. Here is a quick bulleted list of changes before we dive into the details:
* Complete World rewrite
* Multiple component storage types:
* Tables: fast cache friendly iteration, slower add/removes (previously called Archetypes)
* Sparse Sets: fast add/remove, slower iteration
* Stateful Queries (caches query results for faster iteration. fragmented iteration is _fast_ now)
* Stateful System Params (caches expensive operations. inspired by @DJMcNab's work in #1364)
* Configurable System Params (users can set configuration when they construct their systems. once again inspired by @DJMcNab's work)
* Archetypes are now "just metadata", component storage is separate
* Archetype Graph (for faster archetype changes)
* Component Metadata
* Configure component storage type
* Retrieve information about component size/type/name/layout/send-ness/etc
* Components are uniquely identified by a densely packed ComponentId
* TypeIds are now totally optional (which should make implementing scripting easier)
* Super fast "for_each" query iterators
* Merged Resources into World. Resources are now just a special type of component
* EntityRef/EntityMut builder apis (more efficient and more ergonomic)
* Fast bitset-backed `Access<T>` replaces old hashmap-based approach everywhere
* Query conflicts are determined by component access instead of archetype component access (to avoid random failures at runtime)
* With/Without are still taken into account for conflicts, so this should still be comfy to use
* Much simpler `IntoSystem` impl
* Significantly reduced the amount of hashing throughout the ecs in favor of Sparse Sets (indexed by densely packed ArchetypeId, ComponentId, BundleId, and TableId)
* Safety Improvements
* Entity reservation uses a normal world reference instead of unsafe transmute
* QuerySets no longer transmute lifetimes
* Made traits "unsafe" where relevant
* More thorough safety docs
* WorldCell
* Exposes safe mutable access to multiple resources at a time in a World
* Replaced "catch all" `System::update_archetypes(world: &World)` with `System::new_archetype(archetype: &Archetype)`
* Simpler Bundle implementation
* Replaced slow "remove_bundle_one_by_one" used as fallback for Commands::remove_bundle with fast "remove_bundle_intersection"
* Removed `Mut<T>` query impl. it is better to only support one way: `&mut T`
* Removed with() from `Flags<T>` in favor of `Option<Flags<T>>`, which allows querying for flags to be "filtered" by default
* Components now have is_send property (currently only resources support non-send)
* More granular module organization
* New `RemovedComponents<T>` SystemParam that replaces `query.removed::<T>()`
* `world.resource_scope()` for mutable access to resources and world at the same time
* WorldQuery and QueryFilter traits unified. FilterFetch trait added to enable "short circuit" filtering. Auto impled for cases that don't need it
* Significantly slimmed down SystemState in favor of individual SystemParam state
* System Commands changed from `commands: &mut Commands` back to `mut commands: Commands` (to allow Commands to have a World reference)
Fixes #1320
## `World` Rewrite
This is a from-scratch rewrite of `World` that fills the niche that `hecs` used to. Yes, this means Bevy ECS is no longer a "fork" of hecs. We're going out our own!
(the only shared code between the projects is the entity id allocator, which is already basically ideal)
A huge shout out to @SanderMertens (author of [flecs](https://github.com/SanderMertens/flecs)) for sharing some great ideas with me (specifically hybrid ecs storage and archetype graphs). He also helped advise on a number of implementation details.
## Component Storage (The Problem)
Two ECS storage paradigms have gained a lot of traction over the years:
* **Archetypal ECS**:
* Stores components in "tables" with static schemas. Each "column" stores components of a given type. Each "row" is an entity.
* Each "archetype" has its own table. Adding/removing an entity's component changes the archetype.
* Enables super-fast Query iteration due to its cache-friendly data layout
* Comes at the cost of more expensive add/remove operations for an Entity's components, because all components need to be copied to the new archetype's "table"
* **Sparse Set ECS**:
* Stores components of the same type in densely packed arrays, which are sparsely indexed by densely packed unsigned integers (Entity ids)
* Query iteration is slower than Archetypal ECS because each entity's component could be at any position in the sparse set. This "random access" pattern isn't cache friendly. Additionally, there is an extra layer of indirection because you must first map the entity id to an index in the component array.
* Adding/removing components is a cheap, constant time operation
Bevy ECS V1, hecs, legion, flec, and Unity DOTS are all "archetypal ecs-es". I personally think "archetypal" storage is a good default for game engines. An entity's archetype doesn't need to change frequently in general, and it creates "fast by default" query iteration (which is a much more common operation). It is also "self optimizing". Users don't need to think about optimizing component layouts for iteration performance. It "just works" without any extra boilerplate.
Shipyard and EnTT are "sparse set ecs-es". They employ "packing" as a way to work around the "suboptimal by default" iteration performance for specific sets of components. This helps, but I didn't think this was a good choice for a general purpose engine like Bevy because:
1. "packs" conflict with each other. If bevy decides to internally pack the Transform and GlobalTransform components, users are then blocked if they want to pack some custom component with Transform.
2. users need to take manual action to optimize
Developers selecting an ECS framework are stuck with a hard choice. Select an "archetypal" framework with "fast iteration everywhere" but without the ability to cheaply add/remove components, or select a "sparse set" framework to cheaply add/remove components but with slower iteration performance.
## Hybrid Component Storage (The Solution)
In Bevy ECS V2, we get to have our cake and eat it too. It now has _both_ of the component storage types above (and more can be added later if needed):
* **Tables** (aka "archetypal" storage)
* The default storage. If you don't configure anything, this is what you get
* Fast iteration by default
* Slower add/remove operations
* **Sparse Sets**
* Opt-in
* Slower iteration
* Faster add/remove operations
These storage types complement each other perfectly. By default Query iteration is fast. If developers know that they want to add/remove a component at high frequencies, they can set the storage to "sparse set":
```rust
world.register_component(
ComponentDescriptor::new::<MyComponent>(StorageType::SparseSet)
).unwrap();
```
## Archetypes
Archetypes are now "just metadata" ... they no longer store components directly. They do store:
* The `ComponentId`s of each of the Archetype's components (and that component's storage type)
* Archetypes are uniquely defined by their component layouts
* For example: entities with "table" components `[A, B, C]` _and_ "sparse set" components `[D, E]` will always be in the same archetype.
* The `TableId` associated with the archetype
* For now each archetype has exactly one table (which can have no components),
* There is a 1->Many relationship from Tables->Archetypes. A given table could have any number of archetype components stored in it:
* Ex: an entity with "table storage" components `[A, B, C]` and "sparse set" components `[D, E]` will share the same `[A, B, C]` table as an entity with `[A, B, C]` table component and `[F]` sparse set components.
* This 1->Many relationship is how we preserve fast "cache friendly" iteration performance when possible (more on this later)
* A list of entities that are in the archetype and the row id of the table they are in
* ArchetypeComponentIds
* unique densely packed identifiers for (ArchetypeId, ComponentId) pairs
* used by the schedule executor for cheap system access control
* "Archetype Graph Edges" (see the next section)
## The "Archetype Graph"
Archetype changes in Bevy (and a number of other archetypal ecs-es) have historically been expensive to compute. First, you need to allocate a new vector of the entity's current component ids, add or remove components based on the operation performed, sort it (to ensure it is order-independent), then hash it to find the archetype (if it exists). And thats all before we get to the _already_ expensive full copy of all components to the new table storage.
The solution is to build a "graph" of archetypes to cache these results. @SanderMertens first exposed me to the idea (and he got it from @gjroelofs, who came up with it). They propose adding directed edges between archetypes for add/remove component operations. If `ComponentId`s are densely packed, you can use sparse sets to cheaply jump between archetypes.
Bevy takes this one step further by using add/remove `Bundle` edges instead of `Component` edges. Bevy encourages the use of `Bundles` to group add/remove operations. This is largely for "clearer game logic" reasons, but it also helps cut down on the number of archetype changes required. `Bundles` now also have densely-packed `BundleId`s. This allows us to use a _single_ edge for each bundle operation (rather than needing to traverse N edges ... one for each component). Single component operations are also bundles, so this is strictly an improvement over a "component only" graph.
As a result, an operation that used to be _heavy_ (both for allocations and compute) is now two dirt-cheap array lookups and zero allocations.
## Stateful Queries
World queries are now stateful. This allows us to:
1. Cache archetype (and table) matches
* This resolves another issue with (naive) archetypal ECS: query performance getting worse as the number of archetypes goes up (and fragmentation occurs).
2. Cache Fetch and Filter state
* The expensive parts of fetch/filter operations (such as hashing the TypeId to find the ComponentId) now only happen once when the Query is first constructed
3. Incrementally build up state
* When new archetypes are added, we only process the new archetypes (no need to rebuild state for old archetypes)
As a result, the direct `World` query api now looks like this:
```rust
let mut query = world.query::<(&A, &mut B)>();
for (a, mut b) in query.iter_mut(&mut world) {
}
```
Requiring `World` to generate stateful queries (rather than letting the `QueryState` type be constructed separately) allows us to ensure that _all_ queries are properly initialized (and the relevant world state, such as ComponentIds). This enables QueryState to remove branches from its operations that check for initialization status (and also enables query.iter() to take an immutable world reference because it doesn't need to initialize anything in world).
However in systems, this is a non-breaking change. State management is done internally by the relevant SystemParam.
## Stateful SystemParams
Like Queries, `SystemParams` now also cache state. For example, `Query` system params store the "stateful query" state mentioned above. Commands store their internal `CommandQueue`. This means you can now safely use as many separate `Commands` parameters in your system as you want. `Local<T>` system params store their `T` value in their state (instead of in Resources).
SystemParam state also enabled a significant slim-down of SystemState. It is much nicer to look at now.
Per-SystemParam state naturally insulates us from an "aliased mut" class of errors we have hit in the past (ex: using multiple `Commands` system params).
(credit goes to @DJMcNab for the initial idea and draft pr here #1364)
## Configurable SystemParams
@DJMcNab also had the great idea to make SystemParams configurable. This allows users to provide some initial configuration / values for system parameters (when possible). Most SystemParams have no config (the config type is `()`), but the `Local<T>` param now supports user-provided parameters:
```rust
fn foo(value: Local<usize>) {
}
app.add_system(foo.system().config(|c| c.0 = Some(10)));
```
## Uber Fast "for_each" Query Iterators
Developers now have the choice to use a fast "for_each" iterator, which yields ~1.5-3x iteration speed improvements for "fragmented iteration", and minor ~1.2x iteration speed improvements for unfragmented iteration.
```rust
fn system(query: Query<(&A, &mut B)>) {
// you now have the option to do this for a speed boost
query.for_each_mut(|(a, mut b)| {
});
// however normal iterators are still available
for (a, mut b) in query.iter_mut() {
}
}
```
I think in most cases we should continue to encourage "normal" iterators as they are more flexible and more "rust idiomatic". But when that extra "oomf" is needed, it makes sense to use `for_each`.
We should also consider using `for_each` for internal bevy systems to give our users a nice speed boost (but that should be a separate pr).
## Component Metadata
`World` now has a `Components` collection, which is accessible via `world.components()`. This stores mappings from `ComponentId` to `ComponentInfo`, as well as `TypeId` to `ComponentId` mappings (where relevant). `ComponentInfo` stores information about the component, such as ComponentId, TypeId, memory layout, send-ness (currently limited to resources), and storage type.
## Significantly Cheaper `Access<T>`
We used to use `TypeAccess<TypeId>` to manage read/write component/archetype-component access. This was expensive because TypeIds must be hashed and compared individually. The parallel executor got around this by "condensing" type ids into bitset-backed access types. This worked, but it had to be re-generated from the `TypeAccess<TypeId>`sources every time archetypes changed.
This pr removes TypeAccess in favor of faster bitset access everywhere. We can do this thanks to the move to densely packed `ComponentId`s and `ArchetypeComponentId`s.
## Merged Resources into World
Resources had a lot of redundant functionality with Components. They stored typed data, they had access control, they had unique ids, they were queryable via SystemParams, etc. In fact the _only_ major difference between them was that they were unique (and didn't correlate to an entity).
Separate resources also had the downside of requiring a separate set of access controls, which meant the parallel executor needed to compare more bitsets per system and manage more state.
I initially got the "separate resources" idea from `legion`. I think that design was motivated by the fact that it made the direct world query/resource lifetime interactions more manageable. It certainly made our lives easier when using Resources alongside hecs/bevy_ecs. However we already have a construct for safely and ergonomically managing in-world lifetimes: systems (which use `Access<T>` internally).
This pr merges Resources into World:
```rust
world.insert_resource(1);
world.insert_resource(2.0);
let a = world.get_resource::<i32>().unwrap();
let mut b = world.get_resource_mut::<f64>().unwrap();
*b = 3.0;
```
Resources are now just a special kind of component. They have their own ComponentIds (and their own resource TypeId->ComponentId scope, so they don't conflict wit components of the same type). They are stored in a special "resource archetype", which stores components inside the archetype using a new `unique_components` sparse set (note that this sparse set could later be used to implement Tags). This allows us to keep the code size small by reusing existing datastructures (namely Column, Archetype, ComponentFlags, and ComponentInfo). This allows us the executor to use a single `Access<ArchetypeComponentId>` per system. It should also make scripting language integration easier.
_But_ this merge did create problems for people directly interacting with `World`. What if you need mutable access to multiple resources at the same time? `world.get_resource_mut()` borrows World mutably!
## WorldCell
WorldCell applies the `Access<ArchetypeComponentId>` concept to direct world access:
```rust
let world_cell = world.cell();
let a = world_cell.get_resource_mut::<i32>().unwrap();
let b = world_cell.get_resource_mut::<f64>().unwrap();
```
This adds cheap runtime checks (a sparse set lookup of `ArchetypeComponentId` and a counter) to ensure that world accesses do not conflict with each other. Each operation returns a `WorldBorrow<'w, T>` or `WorldBorrowMut<'w, T>` wrapper type, which will release the relevant ArchetypeComponentId resources when dropped.
World caches the access sparse set (and only one cell can exist at a time), so `world.cell()` is a cheap operation.
WorldCell does _not_ use atomic operations. It is non-send, does a mutable borrow of world to prevent other accesses, and uses a simple `Rc<RefCell<ArchetypeComponentAccess>>` wrapper in each WorldBorrow pointer.
The api is currently limited to resource access, but it can and should be extended to queries / entity component access.
## Resource Scopes
WorldCell does not yet support component queries, and even when it does there are sometimes legitimate reasons to want a mutable world ref _and_ a mutable resource ref (ex: bevy_render and bevy_scene both need this). In these cases we could always drop down to the unsafe `world.get_resource_unchecked_mut()`, but that is not ideal!
Instead developers can use a "resource scope"
```rust
world.resource_scope(|world: &mut World, a: &mut A| {
})
```
This temporarily removes the `A` resource from `World`, provides mutable pointers to both, and re-adds A to World when finished. Thanks to the move to ComponentIds/sparse sets, this is a cheap operation.
If multiple resources are required, scopes can be nested. We could also consider adding a "resource tuple" to the api if this pattern becomes common and the boilerplate gets nasty.
## Query Conflicts Use ComponentId Instead of ArchetypeComponentId
For safety reasons, systems cannot contain queries that conflict with each other without wrapping them in a QuerySet. On bevy `main`, we use ArchetypeComponentIds to determine conflicts. This is nice because it can take into account filters:
```rust
// these queries will never conflict due to their filters
fn filter_system(a: Query<&mut A, With<B>>, b: Query<&mut B, Without<B>>) {
}
```
But it also has a significant downside:
```rust
// these queries will not conflict _until_ an entity with A, B, and C is spawned
fn maybe_conflicts_system(a: Query<(&mut A, &C)>, b: Query<(&mut A, &B)>) {
}
```
The system above will panic at runtime if an entity with A, B, and C is spawned. This makes it hard to trust that your game logic will run without crashing.
In this pr, I switched to using `ComponentId` instead. This _is_ more constraining. `maybe_conflicts_system` will now always fail, but it will do it consistently at startup. Naively, it would also _disallow_ `filter_system`, which would be a significant downgrade in usability. Bevy has a number of internal systems that rely on disjoint queries and I expect it to be a common pattern in userspace.
To resolve this, I added a new `FilteredAccess<T>` type, which wraps `Access<T>` and adds with/without filters. If two `FilteredAccess` have with/without values that prove they are disjoint, they will no longer conflict.
## EntityRef / EntityMut
World entity operations on `main` require that the user passes in an `entity` id to each operation:
```rust
let entity = world.spawn((A, )); // create a new entity with A
world.get::<A>(entity);
world.insert(entity, (B, C));
world.insert_one(entity, D);
```
This means that each operation needs to look up the entity location / verify its validity. The initial spawn operation also requires a Bundle as input. This can be awkward when no components are required (or one component is required).
These operations have been replaced by `EntityRef` and `EntityMut`, which are "builder-style" wrappers around world that provide read and read/write operations on a single, pre-validated entity:
```rust
// spawn now takes no inputs and returns an EntityMut
let entity = world.spawn()
.insert(A) // insert a single component into the entity
.insert_bundle((B, C)) // insert a bundle of components into the entity
.id() // id returns the Entity id
// Returns EntityMut (or panics if the entity does not exist)
world.entity_mut(entity)
.insert(D)
.insert_bundle(SomeBundle::default());
{
// returns EntityRef (or panics if the entity does not exist)
let d = world.entity(entity)
.get::<D>() // gets the D component
.unwrap();
// world.get still exists for ergonomics
let d = world.get::<D>(entity).unwrap();
}
// These variants return Options if you want to check existence instead of panicing
world.get_entity_mut(entity)
.unwrap()
.insert(E);
if let Some(entity_ref) = world.get_entity(entity) {
let d = entity_ref.get::<D>().unwrap();
}
```
This _does not_ affect the current Commands api or terminology. I think that should be a separate conversation as that is a much larger breaking change.
## Safety Improvements
* Entity reservation in Commands uses a normal world borrow instead of an unsafe transmute
* QuerySets no longer transmutes lifetimes
* Made traits "unsafe" when implementing a trait incorrectly could cause unsafety
* More thorough safety docs
## RemovedComponents SystemParam
The old approach to querying removed components: `query.removed:<T>()` was confusing because it had no connection to the query itself. I replaced it with the following, which is both clearer and allows us to cache the ComponentId mapping in the SystemParamState:
```rust
fn system(removed: RemovedComponents<T>) {
for entity in removed.iter() {
}
}
```
## Simpler Bundle implementation
Bundles are no longer responsible for sorting (or deduping) TypeInfo. They are just a simple ordered list of component types / data. This makes the implementation smaller and opens the door to an easy "nested bundle" implementation in the future (which i might even add in this pr). Duplicate detection is now done once per bundle type by World the first time a bundle is used.
## Unified WorldQuery and QueryFilter types
(don't worry they are still separate type _parameters_ in Queries .. this is a non-breaking change)
WorldQuery and QueryFilter were already basically identical apis. With the addition of `FetchState` and more storage-specific fetch methods, the overlap was even clearer (and the redundancy more painful).
QueryFilters are now just `F: WorldQuery where F::Fetch: FilterFetch`. FilterFetch requires `Fetch<Item = bool>` and adds new "short circuit" variants of fetch methods. This enables a filter tuple like `(With<A>, Without<B>, Changed<C>)` to stop evaluating the filter after the first mismatch is encountered. FilterFetch is automatically implemented for `Fetch` implementations that return bool.
This forces fetch implementations that return things like `(bool, bool, bool)` (such as the filter above) to manually implement FilterFetch and decide whether or not to short-circuit.
## More Granular Modules
World no longer globs all of the internal modules together. It now exports `core`, `system`, and `schedule` separately. I'm also considering exporting `core` submodules directly as that is still pretty "glob-ey" and unorganized (feedback welcome here).
## Remaining Draft Work (to be done in this pr)
* ~~panic on conflicting WorldQuery fetches (&A, &mut A)~~
* ~~bevy `main` and hecs both currently allow this, but we should protect against it if possible~~
* ~~batch_iter / par_iter (currently stubbed out)~~
* ~~ChangedRes~~
* ~~I skipped this while we sort out #1313. This pr should be adapted to account for whatever we land on there~~.
* ~~The `Archetypes` and `Tables` collections use hashes of sorted lists of component ids to uniquely identify each archetype/table. This hash is then used as the key in a HashMap to look up the relevant ArchetypeId or TableId. (which doesn't handle hash collisions properly)~~
* ~~It is currently unsafe to generate a Query from "World A", then use it on "World B" (despite the api claiming it is safe). We should probably close this gap. This could be done by adding a randomly generated WorldId to each world, then storing that id in each Query. They could then be compared to each other on each `query.do_thing(&world)` operation. This _does_ add an extra branch to each query operation, so I'm open to other suggestions if people have them.~~
* ~~Nested Bundles (if i find time)~~
## Potential Future Work
* Expand WorldCell to support queries.
* Consider not allocating in the empty archetype on `world.spawn()`
* ex: return something like EntityMutUninit, which turns into EntityMut after an `insert` or `insert_bundle` op
* this actually regressed performance last time i tried it, but in theory it should be faster
* Optimize SparseSet::insert (see `PERF` comment on insert)
* Replace SparseArray `Option<T>` with T::MAX to cut down on branching
* would enable cheaper get_unchecked() operations
* upstream fixedbitset optimizations
* fixedbitset could be allocation free for small block counts (store blocks in a SmallVec)
* fixedbitset could have a const constructor
* Consider implementing Tags (archetype-specific by-value data that affects archetype identity)
* ex: ArchetypeA could have `[A, B, C]` table components and `[D(1)]` "tag" component. ArchetypeB could have `[A, B, C]` table components and a `[D(2)]` tag component. The archetypes are different, despite both having D tags because the value inside D is different.
* this could potentially build on top of the `archetype.unique_components` added in this pr for resource storage.
* Consider reverting `all_tuples` proc macro in favor of the old `macro_rules` implementation
* all_tuples is more flexible and produces cleaner documentation (the macro_rules version produces weird type parameter orders due to parser constraints)
* but unfortunately all_tuples also appears to make Rust Analyzer sad/slow when working inside of `bevy_ecs` (does not affect user code)
* Consider "resource queries" and/or "mixed resource and entity component queries" as an alternative to WorldCell
* this is basically just "systems" so maybe it's not worth it
* Add more world ops
* `world.clear()`
* `world.reserve<T: Bundle>(count: usize)`
* Try using the old archetype allocation strategy (allocate new memory on resize and copy everything over). I expect this to improve batch insertion performance at the cost of unbatched performance. But thats just a guess. I'm not an allocation perf pro :)
* Adapt Commands apis for consistency with new World apis
## Benchmarks
key:
* `bevy_old`: bevy `main` branch
* `bevy`: this branch
* `_foreach`: uses an optimized for_each iterator
* ` _sparse`: uses sparse set storage (if unspecified assume table storage)
* `_system`: runs inside a system (if unspecified assume test happens via direct world ops)
### Simple Insert (from ecs_bench_suite)
![image](https://user-images.githubusercontent.com/2694663/109245573-9c3ce100-7795-11eb-9003-bfd41cd5c51f.png)
### Simpler Iter (from ecs_bench_suite)
![image](https://user-images.githubusercontent.com/2694663/109245795-ffc70e80-7795-11eb-92fb-3ffad09aabf7.png)
### Fragment Iter (from ecs_bench_suite)
![image](https://user-images.githubusercontent.com/2694663/109245849-0fdeee00-7796-11eb-8d25-eb6b7a682c48.png)
### Sparse Fragmented Iter
Iterate a query that matches 5 entities from a single matching archetype, but there are 100 unmatching archetypes
![image](https://user-images.githubusercontent.com/2694663/109245916-2b49f900-7796-11eb-9a8f-ed89c203f940.png)
### Schedule (from ecs_bench_suite)
![image](https://user-images.githubusercontent.com/2694663/109246428-1fab0200-7797-11eb-8841-1b2161e90fa4.png)
### Add Remove Component (from ecs_bench_suite)
![image](https://user-images.githubusercontent.com/2694663/109246492-39e4e000-7797-11eb-8985-2706bd0495ab.png)
### Add Remove Component Big
Same as the test above, but each entity has 5 "large" matrix components and 1 "large" matrix component is added and removed
![image](https://user-images.githubusercontent.com/2694663/109246517-449f7500-7797-11eb-835e-28b6790daeaa.png)
### Get Component
Looks up a single component value a large number of times
![image](https://user-images.githubusercontent.com/2694663/109246129-87ad1880-7796-11eb-9fcb-c38012aa7c70.png)
2021-03-05 07:54:35 +00:00
|
|
|
|
use bevy_ecs::{
|
2022-05-09 13:19:32 +00:00
|
|
|
|
event::{Event, Events},
|
Exclusive Systems Now Implement `System`. Flexible Exclusive System Params (#6083)
# Objective
The [Stageless RFC](https://github.com/bevyengine/rfcs/pull/45) involves allowing exclusive systems to be referenced and ordered relative to parallel systems. We've agreed that unifying systems under `System` is the right move.
This is an alternative to #4166 (see rationale in the comments I left there). Note that this builds on the learnings established there (and borrows some patterns).
## Solution
This unifies parallel and exclusive systems under the shared `System` trait, removing the old `ExclusiveSystem` trait / impls. This is accomplished by adding a new `ExclusiveFunctionSystem` impl similar to `FunctionSystem`. It is backed by `ExclusiveSystemParam`, which is similar to `SystemParam`. There is a new flattened out SystemContainer api (which cuts out a lot of trait and type complexity).
This means you can remove all cases of `exclusive_system()`:
```rust
// before
commands.add_system(some_system.exclusive_system());
// after
commands.add_system(some_system);
```
I've also implemented `ExclusiveSystemParam` for `&mut QueryState` and `&mut SystemState`, which makes this possible in exclusive systems:
```rust
fn some_exclusive_system(
world: &mut World,
transforms: &mut QueryState<&Transform>,
state: &mut SystemState<(Res<Time>, Query<&Player>)>,
) {
for transform in transforms.iter(world) {
println!("{transform:?}");
}
let (time, players) = state.get(world);
for player in players.iter() {
println!("{player:?}");
}
}
```
Note that "exclusive function systems" assume `&mut World` is present (and the first param). I think this is a fair assumption, given that the presence of `&mut World` is what defines the need for an exclusive system.
I added some targeted SystemParam `static` constraints, which removed the need for this:
``` rust
fn some_exclusive_system(state: &mut SystemState<(Res<'static, Time>, Query<&'static Player>)>) {}
```
## Related
- #2923
- #3001
- #3946
## Changelog
- `ExclusiveSystem` trait (and implementations) has been removed in favor of sharing the `System` trait.
- `ExclusiveFunctionSystem` and `ExclusiveSystemParam` were added, enabling flexible exclusive function systems
- `&mut SystemState` and `&mut QueryState` now implement `ExclusiveSystemParam`
- Exclusive and parallel System configuration is now done via a unified `SystemDescriptor`, `IntoSystemDescriptor`, and `SystemContainer` api.
## Migration Guide
Calling `.exclusive_system()` is no longer required (or supported) for converting exclusive system functions to exclusive systems:
```rust
// Old (0.8)
app.add_system(some_exclusive_system.exclusive_system());
// New (0.9)
app.add_system(some_exclusive_system);
```
Converting "normal" parallel systems to exclusive systems is done by calling the exclusive ordering apis:
```rust
// Old (0.8)
app.add_system(some_system.exclusive_system().at_end());
// New (0.9)
app.add_system(some_system.at_end());
```
Query state in exclusive systems can now be cached via ExclusiveSystemParams, which should be preferred for clarity and performance reasons:
```rust
// Old (0.8)
fn some_system(world: &mut World) {
let mut transforms = world.query::<&Transform>();
for transform in transforms.iter(world) {
}
}
// New (0.9)
fn some_system(world: &mut World, transforms: &mut QueryState<&Transform>) {
for transform in transforms.iter(world) {
}
}
```
2022-09-26 23:57:07 +00:00
|
|
|
|
prelude::FromWorld,
|
2021-07-27 20:21:06 +00:00
|
|
|
|
schedule::{
|
2022-05-04 18:41:37 +00:00
|
|
|
|
IntoSystemDescriptor, Schedule, ShouldRun, Stage, StageLabel, State, StateData, SystemSet,
|
2021-10-03 19:23:44 +00:00
|
|
|
|
SystemStage,
|
2021-07-27 20:21:06 +00:00
|
|
|
|
},
|
2021-10-03 19:23:44 +00:00
|
|
|
|
system::Resource,
|
Bevy ECS V2 (#1525)
# Bevy ECS V2
This is a rewrite of Bevy ECS (basically everything but the new executor/schedule, which are already awesome). The overall goal was to improve the performance and versatility of Bevy ECS. Here is a quick bulleted list of changes before we dive into the details:
* Complete World rewrite
* Multiple component storage types:
* Tables: fast cache friendly iteration, slower add/removes (previously called Archetypes)
* Sparse Sets: fast add/remove, slower iteration
* Stateful Queries (caches query results for faster iteration. fragmented iteration is _fast_ now)
* Stateful System Params (caches expensive operations. inspired by @DJMcNab's work in #1364)
* Configurable System Params (users can set configuration when they construct their systems. once again inspired by @DJMcNab's work)
* Archetypes are now "just metadata", component storage is separate
* Archetype Graph (for faster archetype changes)
* Component Metadata
* Configure component storage type
* Retrieve information about component size/type/name/layout/send-ness/etc
* Components are uniquely identified by a densely packed ComponentId
* TypeIds are now totally optional (which should make implementing scripting easier)
* Super fast "for_each" query iterators
* Merged Resources into World. Resources are now just a special type of component
* EntityRef/EntityMut builder apis (more efficient and more ergonomic)
* Fast bitset-backed `Access<T>` replaces old hashmap-based approach everywhere
* Query conflicts are determined by component access instead of archetype component access (to avoid random failures at runtime)
* With/Without are still taken into account for conflicts, so this should still be comfy to use
* Much simpler `IntoSystem` impl
* Significantly reduced the amount of hashing throughout the ecs in favor of Sparse Sets (indexed by densely packed ArchetypeId, ComponentId, BundleId, and TableId)
* Safety Improvements
* Entity reservation uses a normal world reference instead of unsafe transmute
* QuerySets no longer transmute lifetimes
* Made traits "unsafe" where relevant
* More thorough safety docs
* WorldCell
* Exposes safe mutable access to multiple resources at a time in a World
* Replaced "catch all" `System::update_archetypes(world: &World)` with `System::new_archetype(archetype: &Archetype)`
* Simpler Bundle implementation
* Replaced slow "remove_bundle_one_by_one" used as fallback for Commands::remove_bundle with fast "remove_bundle_intersection"
* Removed `Mut<T>` query impl. it is better to only support one way: `&mut T`
* Removed with() from `Flags<T>` in favor of `Option<Flags<T>>`, which allows querying for flags to be "filtered" by default
* Components now have is_send property (currently only resources support non-send)
* More granular module organization
* New `RemovedComponents<T>` SystemParam that replaces `query.removed::<T>()`
* `world.resource_scope()` for mutable access to resources and world at the same time
* WorldQuery and QueryFilter traits unified. FilterFetch trait added to enable "short circuit" filtering. Auto impled for cases that don't need it
* Significantly slimmed down SystemState in favor of individual SystemParam state
* System Commands changed from `commands: &mut Commands` back to `mut commands: Commands` (to allow Commands to have a World reference)
Fixes #1320
## `World` Rewrite
This is a from-scratch rewrite of `World` that fills the niche that `hecs` used to. Yes, this means Bevy ECS is no longer a "fork" of hecs. We're going out our own!
(the only shared code between the projects is the entity id allocator, which is already basically ideal)
A huge shout out to @SanderMertens (author of [flecs](https://github.com/SanderMertens/flecs)) for sharing some great ideas with me (specifically hybrid ecs storage and archetype graphs). He also helped advise on a number of implementation details.
## Component Storage (The Problem)
Two ECS storage paradigms have gained a lot of traction over the years:
* **Archetypal ECS**:
* Stores components in "tables" with static schemas. Each "column" stores components of a given type. Each "row" is an entity.
* Each "archetype" has its own table. Adding/removing an entity's component changes the archetype.
* Enables super-fast Query iteration due to its cache-friendly data layout
* Comes at the cost of more expensive add/remove operations for an Entity's components, because all components need to be copied to the new archetype's "table"
* **Sparse Set ECS**:
* Stores components of the same type in densely packed arrays, which are sparsely indexed by densely packed unsigned integers (Entity ids)
* Query iteration is slower than Archetypal ECS because each entity's component could be at any position in the sparse set. This "random access" pattern isn't cache friendly. Additionally, there is an extra layer of indirection because you must first map the entity id to an index in the component array.
* Adding/removing components is a cheap, constant time operation
Bevy ECS V1, hecs, legion, flec, and Unity DOTS are all "archetypal ecs-es". I personally think "archetypal" storage is a good default for game engines. An entity's archetype doesn't need to change frequently in general, and it creates "fast by default" query iteration (which is a much more common operation). It is also "self optimizing". Users don't need to think about optimizing component layouts for iteration performance. It "just works" without any extra boilerplate.
Shipyard and EnTT are "sparse set ecs-es". They employ "packing" as a way to work around the "suboptimal by default" iteration performance for specific sets of components. This helps, but I didn't think this was a good choice for a general purpose engine like Bevy because:
1. "packs" conflict with each other. If bevy decides to internally pack the Transform and GlobalTransform components, users are then blocked if they want to pack some custom component with Transform.
2. users need to take manual action to optimize
Developers selecting an ECS framework are stuck with a hard choice. Select an "archetypal" framework with "fast iteration everywhere" but without the ability to cheaply add/remove components, or select a "sparse set" framework to cheaply add/remove components but with slower iteration performance.
## Hybrid Component Storage (The Solution)
In Bevy ECS V2, we get to have our cake and eat it too. It now has _both_ of the component storage types above (and more can be added later if needed):
* **Tables** (aka "archetypal" storage)
* The default storage. If you don't configure anything, this is what you get
* Fast iteration by default
* Slower add/remove operations
* **Sparse Sets**
* Opt-in
* Slower iteration
* Faster add/remove operations
These storage types complement each other perfectly. By default Query iteration is fast. If developers know that they want to add/remove a component at high frequencies, they can set the storage to "sparse set":
```rust
world.register_component(
ComponentDescriptor::new::<MyComponent>(StorageType::SparseSet)
).unwrap();
```
## Archetypes
Archetypes are now "just metadata" ... they no longer store components directly. They do store:
* The `ComponentId`s of each of the Archetype's components (and that component's storage type)
* Archetypes are uniquely defined by their component layouts
* For example: entities with "table" components `[A, B, C]` _and_ "sparse set" components `[D, E]` will always be in the same archetype.
* The `TableId` associated with the archetype
* For now each archetype has exactly one table (which can have no components),
* There is a 1->Many relationship from Tables->Archetypes. A given table could have any number of archetype components stored in it:
* Ex: an entity with "table storage" components `[A, B, C]` and "sparse set" components `[D, E]` will share the same `[A, B, C]` table as an entity with `[A, B, C]` table component and `[F]` sparse set components.
* This 1->Many relationship is how we preserve fast "cache friendly" iteration performance when possible (more on this later)
* A list of entities that are in the archetype and the row id of the table they are in
* ArchetypeComponentIds
* unique densely packed identifiers for (ArchetypeId, ComponentId) pairs
* used by the schedule executor for cheap system access control
* "Archetype Graph Edges" (see the next section)
## The "Archetype Graph"
Archetype changes in Bevy (and a number of other archetypal ecs-es) have historically been expensive to compute. First, you need to allocate a new vector of the entity's current component ids, add or remove components based on the operation performed, sort it (to ensure it is order-independent), then hash it to find the archetype (if it exists). And thats all before we get to the _already_ expensive full copy of all components to the new table storage.
The solution is to build a "graph" of archetypes to cache these results. @SanderMertens first exposed me to the idea (and he got it from @gjroelofs, who came up with it). They propose adding directed edges between archetypes for add/remove component operations. If `ComponentId`s are densely packed, you can use sparse sets to cheaply jump between archetypes.
Bevy takes this one step further by using add/remove `Bundle` edges instead of `Component` edges. Bevy encourages the use of `Bundles` to group add/remove operations. This is largely for "clearer game logic" reasons, but it also helps cut down on the number of archetype changes required. `Bundles` now also have densely-packed `BundleId`s. This allows us to use a _single_ edge for each bundle operation (rather than needing to traverse N edges ... one for each component). Single component operations are also bundles, so this is strictly an improvement over a "component only" graph.
As a result, an operation that used to be _heavy_ (both for allocations and compute) is now two dirt-cheap array lookups and zero allocations.
## Stateful Queries
World queries are now stateful. This allows us to:
1. Cache archetype (and table) matches
* This resolves another issue with (naive) archetypal ECS: query performance getting worse as the number of archetypes goes up (and fragmentation occurs).
2. Cache Fetch and Filter state
* The expensive parts of fetch/filter operations (such as hashing the TypeId to find the ComponentId) now only happen once when the Query is first constructed
3. Incrementally build up state
* When new archetypes are added, we only process the new archetypes (no need to rebuild state for old archetypes)
As a result, the direct `World` query api now looks like this:
```rust
let mut query = world.query::<(&A, &mut B)>();
for (a, mut b) in query.iter_mut(&mut world) {
}
```
Requiring `World` to generate stateful queries (rather than letting the `QueryState` type be constructed separately) allows us to ensure that _all_ queries are properly initialized (and the relevant world state, such as ComponentIds). This enables QueryState to remove branches from its operations that check for initialization status (and also enables query.iter() to take an immutable world reference because it doesn't need to initialize anything in world).
However in systems, this is a non-breaking change. State management is done internally by the relevant SystemParam.
## Stateful SystemParams
Like Queries, `SystemParams` now also cache state. For example, `Query` system params store the "stateful query" state mentioned above. Commands store their internal `CommandQueue`. This means you can now safely use as many separate `Commands` parameters in your system as you want. `Local<T>` system params store their `T` value in their state (instead of in Resources).
SystemParam state also enabled a significant slim-down of SystemState. It is much nicer to look at now.
Per-SystemParam state naturally insulates us from an "aliased mut" class of errors we have hit in the past (ex: using multiple `Commands` system params).
(credit goes to @DJMcNab for the initial idea and draft pr here #1364)
## Configurable SystemParams
@DJMcNab also had the great idea to make SystemParams configurable. This allows users to provide some initial configuration / values for system parameters (when possible). Most SystemParams have no config (the config type is `()`), but the `Local<T>` param now supports user-provided parameters:
```rust
fn foo(value: Local<usize>) {
}
app.add_system(foo.system().config(|c| c.0 = Some(10)));
```
## Uber Fast "for_each" Query Iterators
Developers now have the choice to use a fast "for_each" iterator, which yields ~1.5-3x iteration speed improvements for "fragmented iteration", and minor ~1.2x iteration speed improvements for unfragmented iteration.
```rust
fn system(query: Query<(&A, &mut B)>) {
// you now have the option to do this for a speed boost
query.for_each_mut(|(a, mut b)| {
});
// however normal iterators are still available
for (a, mut b) in query.iter_mut() {
}
}
```
I think in most cases we should continue to encourage "normal" iterators as they are more flexible and more "rust idiomatic". But when that extra "oomf" is needed, it makes sense to use `for_each`.
We should also consider using `for_each` for internal bevy systems to give our users a nice speed boost (but that should be a separate pr).
## Component Metadata
`World` now has a `Components` collection, which is accessible via `world.components()`. This stores mappings from `ComponentId` to `ComponentInfo`, as well as `TypeId` to `ComponentId` mappings (where relevant). `ComponentInfo` stores information about the component, such as ComponentId, TypeId, memory layout, send-ness (currently limited to resources), and storage type.
## Significantly Cheaper `Access<T>`
We used to use `TypeAccess<TypeId>` to manage read/write component/archetype-component access. This was expensive because TypeIds must be hashed and compared individually. The parallel executor got around this by "condensing" type ids into bitset-backed access types. This worked, but it had to be re-generated from the `TypeAccess<TypeId>`sources every time archetypes changed.
This pr removes TypeAccess in favor of faster bitset access everywhere. We can do this thanks to the move to densely packed `ComponentId`s and `ArchetypeComponentId`s.
## Merged Resources into World
Resources had a lot of redundant functionality with Components. They stored typed data, they had access control, they had unique ids, they were queryable via SystemParams, etc. In fact the _only_ major difference between them was that they were unique (and didn't correlate to an entity).
Separate resources also had the downside of requiring a separate set of access controls, which meant the parallel executor needed to compare more bitsets per system and manage more state.
I initially got the "separate resources" idea from `legion`. I think that design was motivated by the fact that it made the direct world query/resource lifetime interactions more manageable. It certainly made our lives easier when using Resources alongside hecs/bevy_ecs. However we already have a construct for safely and ergonomically managing in-world lifetimes: systems (which use `Access<T>` internally).
This pr merges Resources into World:
```rust
world.insert_resource(1);
world.insert_resource(2.0);
let a = world.get_resource::<i32>().unwrap();
let mut b = world.get_resource_mut::<f64>().unwrap();
*b = 3.0;
```
Resources are now just a special kind of component. They have their own ComponentIds (and their own resource TypeId->ComponentId scope, so they don't conflict wit components of the same type). They are stored in a special "resource archetype", which stores components inside the archetype using a new `unique_components` sparse set (note that this sparse set could later be used to implement Tags). This allows us to keep the code size small by reusing existing datastructures (namely Column, Archetype, ComponentFlags, and ComponentInfo). This allows us the executor to use a single `Access<ArchetypeComponentId>` per system. It should also make scripting language integration easier.
_But_ this merge did create problems for people directly interacting with `World`. What if you need mutable access to multiple resources at the same time? `world.get_resource_mut()` borrows World mutably!
## WorldCell
WorldCell applies the `Access<ArchetypeComponentId>` concept to direct world access:
```rust
let world_cell = world.cell();
let a = world_cell.get_resource_mut::<i32>().unwrap();
let b = world_cell.get_resource_mut::<f64>().unwrap();
```
This adds cheap runtime checks (a sparse set lookup of `ArchetypeComponentId` and a counter) to ensure that world accesses do not conflict with each other. Each operation returns a `WorldBorrow<'w, T>` or `WorldBorrowMut<'w, T>` wrapper type, which will release the relevant ArchetypeComponentId resources when dropped.
World caches the access sparse set (and only one cell can exist at a time), so `world.cell()` is a cheap operation.
WorldCell does _not_ use atomic operations. It is non-send, does a mutable borrow of world to prevent other accesses, and uses a simple `Rc<RefCell<ArchetypeComponentAccess>>` wrapper in each WorldBorrow pointer.
The api is currently limited to resource access, but it can and should be extended to queries / entity component access.
## Resource Scopes
WorldCell does not yet support component queries, and even when it does there are sometimes legitimate reasons to want a mutable world ref _and_ a mutable resource ref (ex: bevy_render and bevy_scene both need this). In these cases we could always drop down to the unsafe `world.get_resource_unchecked_mut()`, but that is not ideal!
Instead developers can use a "resource scope"
```rust
world.resource_scope(|world: &mut World, a: &mut A| {
})
```
This temporarily removes the `A` resource from `World`, provides mutable pointers to both, and re-adds A to World when finished. Thanks to the move to ComponentIds/sparse sets, this is a cheap operation.
If multiple resources are required, scopes can be nested. We could also consider adding a "resource tuple" to the api if this pattern becomes common and the boilerplate gets nasty.
## Query Conflicts Use ComponentId Instead of ArchetypeComponentId
For safety reasons, systems cannot contain queries that conflict with each other without wrapping them in a QuerySet. On bevy `main`, we use ArchetypeComponentIds to determine conflicts. This is nice because it can take into account filters:
```rust
// these queries will never conflict due to their filters
fn filter_system(a: Query<&mut A, With<B>>, b: Query<&mut B, Without<B>>) {
}
```
But it also has a significant downside:
```rust
// these queries will not conflict _until_ an entity with A, B, and C is spawned
fn maybe_conflicts_system(a: Query<(&mut A, &C)>, b: Query<(&mut A, &B)>) {
}
```
The system above will panic at runtime if an entity with A, B, and C is spawned. This makes it hard to trust that your game logic will run without crashing.
In this pr, I switched to using `ComponentId` instead. This _is_ more constraining. `maybe_conflicts_system` will now always fail, but it will do it consistently at startup. Naively, it would also _disallow_ `filter_system`, which would be a significant downgrade in usability. Bevy has a number of internal systems that rely on disjoint queries and I expect it to be a common pattern in userspace.
To resolve this, I added a new `FilteredAccess<T>` type, which wraps `Access<T>` and adds with/without filters. If two `FilteredAccess` have with/without values that prove they are disjoint, they will no longer conflict.
## EntityRef / EntityMut
World entity operations on `main` require that the user passes in an `entity` id to each operation:
```rust
let entity = world.spawn((A, )); // create a new entity with A
world.get::<A>(entity);
world.insert(entity, (B, C));
world.insert_one(entity, D);
```
This means that each operation needs to look up the entity location / verify its validity. The initial spawn operation also requires a Bundle as input. This can be awkward when no components are required (or one component is required).
These operations have been replaced by `EntityRef` and `EntityMut`, which are "builder-style" wrappers around world that provide read and read/write operations on a single, pre-validated entity:
```rust
// spawn now takes no inputs and returns an EntityMut
let entity = world.spawn()
.insert(A) // insert a single component into the entity
.insert_bundle((B, C)) // insert a bundle of components into the entity
.id() // id returns the Entity id
// Returns EntityMut (or panics if the entity does not exist)
world.entity_mut(entity)
.insert(D)
.insert_bundle(SomeBundle::default());
{
// returns EntityRef (or panics if the entity does not exist)
let d = world.entity(entity)
.get::<D>() // gets the D component
.unwrap();
// world.get still exists for ergonomics
let d = world.get::<D>(entity).unwrap();
}
// These variants return Options if you want to check existence instead of panicing
world.get_entity_mut(entity)
.unwrap()
.insert(E);
if let Some(entity_ref) = world.get_entity(entity) {
let d = entity_ref.get::<D>().unwrap();
}
```
This _does not_ affect the current Commands api or terminology. I think that should be a separate conversation as that is a much larger breaking change.
## Safety Improvements
* Entity reservation in Commands uses a normal world borrow instead of an unsafe transmute
* QuerySets no longer transmutes lifetimes
* Made traits "unsafe" when implementing a trait incorrectly could cause unsafety
* More thorough safety docs
## RemovedComponents SystemParam
The old approach to querying removed components: `query.removed:<T>()` was confusing because it had no connection to the query itself. I replaced it with the following, which is both clearer and allows us to cache the ComponentId mapping in the SystemParamState:
```rust
fn system(removed: RemovedComponents<T>) {
for entity in removed.iter() {
}
}
```
## Simpler Bundle implementation
Bundles are no longer responsible for sorting (or deduping) TypeInfo. They are just a simple ordered list of component types / data. This makes the implementation smaller and opens the door to an easy "nested bundle" implementation in the future (which i might even add in this pr). Duplicate detection is now done once per bundle type by World the first time a bundle is used.
## Unified WorldQuery and QueryFilter types
(don't worry they are still separate type _parameters_ in Queries .. this is a non-breaking change)
WorldQuery and QueryFilter were already basically identical apis. With the addition of `FetchState` and more storage-specific fetch methods, the overlap was even clearer (and the redundancy more painful).
QueryFilters are now just `F: WorldQuery where F::Fetch: FilterFetch`. FilterFetch requires `Fetch<Item = bool>` and adds new "short circuit" variants of fetch methods. This enables a filter tuple like `(With<A>, Without<B>, Changed<C>)` to stop evaluating the filter after the first mismatch is encountered. FilterFetch is automatically implemented for `Fetch` implementations that return bool.
This forces fetch implementations that return things like `(bool, bool, bool)` (such as the filter above) to manually implement FilterFetch and decide whether or not to short-circuit.
## More Granular Modules
World no longer globs all of the internal modules together. It now exports `core`, `system`, and `schedule` separately. I'm also considering exporting `core` submodules directly as that is still pretty "glob-ey" and unorganized (feedback welcome here).
## Remaining Draft Work (to be done in this pr)
* ~~panic on conflicting WorldQuery fetches (&A, &mut A)~~
* ~~bevy `main` and hecs both currently allow this, but we should protect against it if possible~~
* ~~batch_iter / par_iter (currently stubbed out)~~
* ~~ChangedRes~~
* ~~I skipped this while we sort out #1313. This pr should be adapted to account for whatever we land on there~~.
* ~~The `Archetypes` and `Tables` collections use hashes of sorted lists of component ids to uniquely identify each archetype/table. This hash is then used as the key in a HashMap to look up the relevant ArchetypeId or TableId. (which doesn't handle hash collisions properly)~~
* ~~It is currently unsafe to generate a Query from "World A", then use it on "World B" (despite the api claiming it is safe). We should probably close this gap. This could be done by adding a randomly generated WorldId to each world, then storing that id in each Query. They could then be compared to each other on each `query.do_thing(&world)` operation. This _does_ add an extra branch to each query operation, so I'm open to other suggestions if people have them.~~
* ~~Nested Bundles (if i find time)~~
## Potential Future Work
* Expand WorldCell to support queries.
* Consider not allocating in the empty archetype on `world.spawn()`
* ex: return something like EntityMutUninit, which turns into EntityMut after an `insert` or `insert_bundle` op
* this actually regressed performance last time i tried it, but in theory it should be faster
* Optimize SparseSet::insert (see `PERF` comment on insert)
* Replace SparseArray `Option<T>` with T::MAX to cut down on branching
* would enable cheaper get_unchecked() operations
* upstream fixedbitset optimizations
* fixedbitset could be allocation free for small block counts (store blocks in a SmallVec)
* fixedbitset could have a const constructor
* Consider implementing Tags (archetype-specific by-value data that affects archetype identity)
* ex: ArchetypeA could have `[A, B, C]` table components and `[D(1)]` "tag" component. ArchetypeB could have `[A, B, C]` table components and a `[D(2)]` tag component. The archetypes are different, despite both having D tags because the value inside D is different.
* this could potentially build on top of the `archetype.unique_components` added in this pr for resource storage.
* Consider reverting `all_tuples` proc macro in favor of the old `macro_rules` implementation
* all_tuples is more flexible and produces cleaner documentation (the macro_rules version produces weird type parameter orders due to parser constraints)
* but unfortunately all_tuples also appears to make Rust Analyzer sad/slow when working inside of `bevy_ecs` (does not affect user code)
* Consider "resource queries" and/or "mixed resource and entity component queries" as an alternative to WorldCell
* this is basically just "systems" so maybe it's not worth it
* Add more world ops
* `world.clear()`
* `world.reserve<T: Bundle>(count: usize)`
* Try using the old archetype allocation strategy (allocate new memory on resize and copy everything over). I expect this to improve batch insertion performance at the cost of unbatched performance. But thats just a guess. I'm not an allocation perf pro :)
* Adapt Commands apis for consistency with new World apis
## Benchmarks
key:
* `bevy_old`: bevy `main` branch
* `bevy`: this branch
* `_foreach`: uses an optimized for_each iterator
* ` _sparse`: uses sparse set storage (if unspecified assume table storage)
* `_system`: runs inside a system (if unspecified assume test happens via direct world ops)
### Simple Insert (from ecs_bench_suite)
![image](https://user-images.githubusercontent.com/2694663/109245573-9c3ce100-7795-11eb-9003-bfd41cd5c51f.png)
### Simpler Iter (from ecs_bench_suite)
![image](https://user-images.githubusercontent.com/2694663/109245795-ffc70e80-7795-11eb-92fb-3ffad09aabf7.png)
### Fragment Iter (from ecs_bench_suite)
![image](https://user-images.githubusercontent.com/2694663/109245849-0fdeee00-7796-11eb-8d25-eb6b7a682c48.png)
### Sparse Fragmented Iter
Iterate a query that matches 5 entities from a single matching archetype, but there are 100 unmatching archetypes
![image](https://user-images.githubusercontent.com/2694663/109245916-2b49f900-7796-11eb-9a8f-ed89c203f940.png)
### Schedule (from ecs_bench_suite)
![image](https://user-images.githubusercontent.com/2694663/109246428-1fab0200-7797-11eb-8841-1b2161e90fa4.png)
### Add Remove Component (from ecs_bench_suite)
![image](https://user-images.githubusercontent.com/2694663/109246492-39e4e000-7797-11eb-8985-2706bd0495ab.png)
### Add Remove Component Big
Same as the test above, but each entity has 5 "large" matrix components and 1 "large" matrix component is added and removed
![image](https://user-images.githubusercontent.com/2694663/109246517-449f7500-7797-11eb-835e-28b6790daeaa.png)
### Get Component
Looks up a single component value a large number of times
![image](https://user-images.githubusercontent.com/2694663/109246129-87ad1880-7796-11eb-9fcb-c38012aa7c70.png)
2021-03-05 07:54:35 +00:00
|
|
|
|
world::World,
|
|
|
|
|
};
|
2022-10-31 16:12:19 +00:00
|
|
|
|
use bevy_utils::{tracing::debug, HashMap, HashSet};
|
2021-10-03 19:23:44 +00:00
|
|
|
|
use std::fmt::Debug;
|
2021-07-27 20:21:06 +00:00
|
|
|
|
|
2020-11-11 02:49:49 +00:00
|
|
|
|
#[cfg(feature = "trace")]
|
2020-11-13 01:23:57 +00:00
|
|
|
|
use bevy_utils::tracing::info_span;
|
2022-07-20 19:39:42 +00:00
|
|
|
|
bevy_utils::define_label!(
|
|
|
|
|
/// A strongly-typed class of labels used to identify an [`App`].
|
|
|
|
|
AppLabel,
|
|
|
|
|
/// A strongly-typed identifier for an [`AppLabel`].
|
|
|
|
|
AppLabelId,
|
|
|
|
|
);
|
2021-08-24 00:31:21 +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>
2022-08-08 21:36:35 +00:00
|
|
|
|
/// The [`Resource`] that stores the [`App`]'s [`TypeRegistry`](bevy_reflect::TypeRegistry).
|
|
|
|
|
#[cfg(feature = "bevy_reflect")]
|
add `ReflectAsset` and `ReflectHandle` (#5923)
# Objective
![image](https://user-images.githubusercontent.com/22177966/189350194-639a0211-e984-4f73-ae62-0ede44891eb9.png)
^ enable this
Concretely, I need to
- list all handle ids for an asset type
- fetch the asset as `dyn Reflect`, given a `HandleUntyped`
- when encountering a `Handle<T>`, find out what asset type that handle refers to (`T`'s type id) and turn the handle into a `HandleUntyped`
## Solution
- add `ReflectAsset` type containing function pointers for working with assets
```rust
pub struct ReflectAsset {
type_uuid: Uuid,
assets_resource_type_id: TypeId, // TypeId of the `Assets<T>` resource
get: fn(&World, HandleUntyped) -> Option<&dyn Reflect>,
get_mut: fn(&mut World, HandleUntyped) -> Option<&mut dyn Reflect>,
get_unchecked_mut: unsafe fn(&World, HandleUntyped) -> Option<&mut dyn Reflect>,
add: fn(&mut World, &dyn Reflect) -> HandleUntyped,
set: fn(&mut World, HandleUntyped, &dyn Reflect) -> HandleUntyped,
len: fn(&World) -> usize,
ids: for<'w> fn(&'w World) -> Box<dyn Iterator<Item = HandleId> + 'w>,
remove: fn(&mut World, HandleUntyped) -> Option<Box<dyn Reflect>>,
}
```
- add `ReflectHandle` type relating the handle back to the asset type and providing a way to create a `HandleUntyped`
```rust
pub struct ReflectHandle {
type_uuid: Uuid,
asset_type_id: TypeId,
downcast_handle_untyped: fn(&dyn Any) -> Option<HandleUntyped>,
}
```
- add the corresponding `FromType` impls
- add a function `app.register_asset_reflect` which is supposed to be called after `.add_asset` and registers `ReflectAsset` and `ReflectHandle` in the type registry
---
## Changelog
- add `ReflectAsset` and `ReflectHandle` types, which allow code to use reflection to manipulate arbitrary assets without knowing their types at compile time
2022-10-28 20:42:33 +00:00
|
|
|
|
#[derive(Resource, Clone, bevy_derive::Deref, bevy_derive::DerefMut, Default)]
|
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>
2022-08-08 21:36:35 +00:00
|
|
|
|
pub struct AppTypeRegistry(pub bevy_reflect::TypeRegistryArc);
|
|
|
|
|
|
2022-10-31 16:12:19 +00:00
|
|
|
|
pub(crate) enum AppError {
|
|
|
|
|
DuplicatePlugin { plugin_name: String },
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-16 07:30:04 +00:00
|
|
|
|
#[allow(clippy::needless_doctest_main)]
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// A container of app logic and data.
|
2020-08-09 23:13:04 +00:00
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// Bundles together the necessary elements like [`World`] and [`Schedule`] to create
|
|
|
|
|
/// an ECS-based application. It also stores a pointer to a [runner function](Self::set_runner).
|
|
|
|
|
/// The runner is responsible for managing the application's event loop and applying the
|
|
|
|
|
/// [`Schedule`] to the [`World`] to drive application logic.
|
|
|
|
|
///
|
|
|
|
|
/// # Examples
|
2020-08-09 23:13:04 +00:00
|
|
|
|
///
|
|
|
|
|
/// Here is a simple "Hello World" Bevy app:
|
2022-04-05 22:36:02 +00:00
|
|
|
|
///
|
2020-08-09 23:13:04 +00:00
|
|
|
|
/// ```
|
2021-03-11 00:27:30 +00:00
|
|
|
|
/// # use bevy_app::prelude::*;
|
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// #
|
2021-03-11 00:27:30 +00:00
|
|
|
|
/// fn main() {
|
2021-07-27 20:21:06 +00:00
|
|
|
|
/// App::new()
|
2021-07-27 23:42:36 +00:00
|
|
|
|
/// .add_system(hello_world_system)
|
2020-08-09 23:13:04 +00:00
|
|
|
|
/// .run();
|
2021-03-11 00:27:30 +00:00
|
|
|
|
/// }
|
2020-08-09 23:13:04 +00:00
|
|
|
|
///
|
2021-03-11 00:27:30 +00:00
|
|
|
|
/// fn hello_world_system() {
|
2020-08-09 23:13:04 +00:00
|
|
|
|
/// println!("hello world");
|
2021-03-11 00:27:30 +00:00
|
|
|
|
/// }
|
2020-08-09 23:13:04 +00:00
|
|
|
|
/// ```
|
2020-04-06 03:19:02 +00:00
|
|
|
|
pub struct App {
|
2022-01-06 23:16:47 +00:00
|
|
|
|
/// The main ECS [`World`] of the [`App`].
|
|
|
|
|
/// This stores and provides access to all the main data of the application.
|
|
|
|
|
/// The systems of the [`App`] will run using this [`World`].
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// If additional separate [`World`]-[`Schedule`] pairs are needed, you can use [`sub_app`](App::add_sub_app)s.
|
2020-04-06 03:19:02 +00:00
|
|
|
|
pub world: World,
|
2022-01-06 23:16:47 +00:00
|
|
|
|
/// The [runner function](Self::set_runner) is primarily responsible for managing
|
|
|
|
|
/// the application's event loop and advancing the [`Schedule`].
|
|
|
|
|
/// Typically, it is not configured manually, but set by one of Bevy's built-in plugins.
|
|
|
|
|
/// See `bevy::winit::WinitPlugin` and [`ScheduleRunnerPlugin`](crate::schedule_runner::ScheduleRunnerPlugin).
|
2020-07-22 20:32:17 +00:00
|
|
|
|
pub runner: Box<dyn Fn(App)>,
|
2022-01-06 23:16:47 +00:00
|
|
|
|
/// A container of [`Stage`]s set to be run in a linear order.
|
2020-07-10 04:18:35 +00:00
|
|
|
|
pub schedule: Schedule,
|
Simplify design for `*Label`s (#4957)
# Objective
- Closes #4954
- Reduce the complexity of the `{System, App, *}Label` APIs.
## Solution
For the sake of brevity I will only refer to `SystemLabel`, but everything applies to all of the other label types as well.
- Add `SystemLabelId`, a lightweight, `copy` struct.
- Convert custom types into `SystemLabelId` using the trait `SystemLabel`.
## Changelog
- String literals implement `SystemLabel` for now, but this should be changed with #4409 .
## Migration Guide
- Any previous use of `Box<dyn SystemLabel>` should be replaced with `SystemLabelId`.
- `AsSystemLabel` trait has been modified.
- No more output generics.
- Method `as_system_label` now returns `SystemLabelId`, removing an unnecessary level of indirection.
- If you *need* a label that is determined at runtime, you can use `Box::leak`. Not recommended.
## Questions for later
* Should we generate a `Debug` impl along with `#[derive(*Label)]`?
* Should we rename `as_str()`?
* Should we remove the extra derives (such as `Hash`) from builtin `*Label` types?
* Should we automatically derive types like `Clone, Copy, PartialEq, Eq`?
* More-ergonomic comparisons between `Label` and `LabelId`.
* Move `Dyn{Eq, Hash,Clone}` somewhere else.
* Some API to make interning dynamic labels easier.
* Optimize string representation
* Empty string for unit structs -- no debug info but faster comparisons
* Don't show enum types -- same tradeoffs as asbove.
2022-07-14 18:23:01 +00:00
|
|
|
|
sub_apps: HashMap<AppLabelId, SubApp>,
|
2022-10-26 17:52:16 +00:00
|
|
|
|
plugin_registry: Vec<Box<dyn Plugin>>,
|
2022-10-31 16:12:19 +00:00
|
|
|
|
plugin_name_added: HashSet<String>,
|
2022-12-24 23:43:41 +00:00
|
|
|
|
/// A private marker to prevent incorrect calls to `App::run()` from `Plugin::build()`
|
|
|
|
|
is_building_plugin: bool,
|
2021-04-11 20:13:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
Adding Debug implementations for App, Stage, Schedule, Query, QueryState, etc. (#6214)
# Objective
- Adding Debug implementations for App, Stage, Schedule, Query, QueryState.
- Fixes #1130.
## Solution
- Implemented std::fmt::Debug for a number of structures.
---
## Changelog
Also added Debug implementations for ParallelSystemExecutor, SingleThreadedExecutor, various RunCriteria structures, SystemContainer, and SystemDescriptor.
Opinions are sure to differ as to what information to provide in a Debug implementation. Best guess was taken for this initial version for these structures.
Co-authored-by: targrub <62773321+targrub@users.noreply.github.com>
2022-10-10 20:59:38 +00:00
|
|
|
|
impl Debug for App {
|
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
|
write!(f, "App {{ sub_apps: ")?;
|
|
|
|
|
f.debug_map()
|
|
|
|
|
.entries(self.sub_apps.iter().map(|(k, v)| (k, v)))
|
|
|
|
|
.finish()?;
|
|
|
|
|
write!(f, "}}")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// Each `SubApp` has its own [`Schedule`] and [`World`], enabling a separation of concerns.
|
2021-04-11 20:13:07 +00:00
|
|
|
|
struct SubApp {
|
|
|
|
|
app: App,
|
Separate Extract from Sub App Schedule (#7046)
# Objective
- This pulls out some of the changes to Plugin setup and sub apps from #6503 to make that PR easier to review.
- Separate the extract stage from running the sub app's schedule to allow for them to be run on separate threads in the future
- Fixes #6990
## Solution
- add a run method to `SubApp` that runs the schedule
- change the name of `sub_app_runner` to extract to make it clear that this function is only for extracting data between the main app and the sub app
- remove the extract stage from the sub app schedule so it can be run separately. This is done by adding a `setup` method to the `Plugin` trait that runs after all plugin build methods run. This is required to allow the extract stage to be removed from the schedule after all the plugins have added their systems to the stage. We will also need the setup method for pipelined rendering to setup the render thread. See https://github.com/bevyengine/bevy/blob/e3267965e15f14be18eec942dcaf16807144eb05/crates/bevy_render/src/pipelined_rendering.rs#L57-L98
## Changelog
- Separate SubApp Extract stage from running the sub app schedule.
## Migration Guide
### SubApp `runner` has conceptually been changed to an `extract` function.
The `runner` no longer is in charge of running the sub app schedule. It's only concern is now moving data between the main world and the sub app. The `sub_app.app.schedule` is now run for you after the provided function is called.
```rust
// before
fn main() {
let sub_app = App::empty();
sub_app.add_stage(MyStage, SystemStage::parallel());
App::new().add_sub_app(MySubApp, sub_app, move |main_world, sub_app| {
extract(app_world, render_app);
render_app.app.schedule.run();
});
}
// after
fn main() {
let sub_app = App::empty();
sub_app.add_stage(MyStage, SystemStage::parallel());
App::new().add_sub_app(MySubApp, sub_app, move |main_world, sub_app| {
extract(app_world, render_app);
// schedule is automatically called for you after extract is run
});
}
```
2023-01-09 19:24:54 +00:00
|
|
|
|
extract: Box<dyn Fn(&mut World, &mut App)>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl SubApp {
|
|
|
|
|
/// Runs the `SubApp`'s schedule.
|
|
|
|
|
pub fn run(&mut self) {
|
|
|
|
|
self.app.schedule.run(&mut self.app.world);
|
|
|
|
|
self.app.world.clear_trackers();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Extracts data from main world to this sub-app.
|
|
|
|
|
pub fn extract(&mut self, main_world: &mut World) {
|
|
|
|
|
(self.extract)(main_world, &mut self.app);
|
|
|
|
|
}
|
2020-04-06 03:19:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
Adding Debug implementations for App, Stage, Schedule, Query, QueryState, etc. (#6214)
# Objective
- Adding Debug implementations for App, Stage, Schedule, Query, QueryState.
- Fixes #1130.
## Solution
- Implemented std::fmt::Debug for a number of structures.
---
## Changelog
Also added Debug implementations for ParallelSystemExecutor, SingleThreadedExecutor, various RunCriteria structures, SystemContainer, and SystemDescriptor.
Opinions are sure to differ as to what information to provide in a Debug implementation. Best guess was taken for this initial version for these structures.
Co-authored-by: targrub <62773321+targrub@users.noreply.github.com>
2022-10-10 20:59:38 +00:00
|
|
|
|
impl Debug for SubApp {
|
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
|
write!(f, "SubApp {{ app: ")?;
|
|
|
|
|
f.debug_map()
|
|
|
|
|
.entries(self.app.sub_apps.iter().map(|(k, v)| (k, v)))
|
|
|
|
|
.finish()?;
|
|
|
|
|
write!(f, "}}")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-22 20:32:17 +00:00
|
|
|
|
impl Default for App {
|
|
|
|
|
fn default() -> Self {
|
2021-07-27 20:21:06 +00:00
|
|
|
|
let mut app = App::empty();
|
|
|
|
|
#[cfg(feature = "bevy_reflect")]
|
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>
2022-08-08 21:36:35 +00:00
|
|
|
|
app.init_resource::<AppTypeRegistry>();
|
2021-07-27 20:21:06 +00:00
|
|
|
|
|
2022-12-11 18:34:15 +00:00
|
|
|
|
app.add_default_stages().add_event::<AppExit>();
|
2021-07-27 20:21:06 +00:00
|
|
|
|
|
|
|
|
|
#[cfg(feature = "bevy_ci_testing")]
|
|
|
|
|
{
|
|
|
|
|
crate::ci_testing::setup_app(&mut app);
|
2020-07-22 20:32:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-27 20:21:06 +00:00
|
|
|
|
app
|
|
|
|
|
}
|
2020-07-22 20:32:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-06 03:19:02 +00:00
|
|
|
|
impl App {
|
2022-01-06 23:16:47 +00:00
|
|
|
|
/// Creates a new [`App`] with some default structure to enable core engine features.
|
|
|
|
|
/// This is the preferred constructor for most use cases.
|
2021-07-27 20:21:06 +00:00
|
|
|
|
pub fn new() -> App {
|
|
|
|
|
App::default()
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-06 23:16:47 +00:00
|
|
|
|
/// Creates a new empty [`App`] with minimal default configuration.
|
|
|
|
|
///
|
|
|
|
|
/// This constructor should be used if you wish to provide a custom schedule, exit handling, cleanup, etc.
|
2021-07-27 20:21:06 +00:00
|
|
|
|
pub fn empty() -> App {
|
|
|
|
|
Self {
|
|
|
|
|
world: Default::default(),
|
|
|
|
|
schedule: Default::default(),
|
|
|
|
|
runner: Box::new(run_once),
|
2021-08-24 00:31:21 +00:00
|
|
|
|
sub_apps: HashMap::default(),
|
2022-10-26 17:52:16 +00:00
|
|
|
|
plugin_registry: Vec::default(),
|
2022-10-31 16:12:19 +00:00
|
|
|
|
plugin_name_added: Default::default(),
|
2022-12-24 23:43:41 +00:00
|
|
|
|
is_building_plugin: false,
|
2021-07-27 20:21:06 +00:00
|
|
|
|
}
|
2020-04-06 03:19:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// Advances the execution of the [`Schedule`] by one cycle.
|
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// This method also updates sub apps.
|
2022-01-14 23:14:42 +00:00
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// See [`add_sub_app`](Self::add_sub_app) and [`run_once`](Schedule::run_once) for more details.
|
2020-04-06 03:19:02 +00:00
|
|
|
|
pub fn update(&mut self) {
|
2021-04-30 02:08:49 +00:00
|
|
|
|
#[cfg(feature = "trace")]
|
2022-03-18 04:19:21 +00:00
|
|
|
|
let _bevy_frame_update_span = info_span!("frame").entered();
|
Bevy ECS V2 (#1525)
# Bevy ECS V2
This is a rewrite of Bevy ECS (basically everything but the new executor/schedule, which are already awesome). The overall goal was to improve the performance and versatility of Bevy ECS. Here is a quick bulleted list of changes before we dive into the details:
* Complete World rewrite
* Multiple component storage types:
* Tables: fast cache friendly iteration, slower add/removes (previously called Archetypes)
* Sparse Sets: fast add/remove, slower iteration
* Stateful Queries (caches query results for faster iteration. fragmented iteration is _fast_ now)
* Stateful System Params (caches expensive operations. inspired by @DJMcNab's work in #1364)
* Configurable System Params (users can set configuration when they construct their systems. once again inspired by @DJMcNab's work)
* Archetypes are now "just metadata", component storage is separate
* Archetype Graph (for faster archetype changes)
* Component Metadata
* Configure component storage type
* Retrieve information about component size/type/name/layout/send-ness/etc
* Components are uniquely identified by a densely packed ComponentId
* TypeIds are now totally optional (which should make implementing scripting easier)
* Super fast "for_each" query iterators
* Merged Resources into World. Resources are now just a special type of component
* EntityRef/EntityMut builder apis (more efficient and more ergonomic)
* Fast bitset-backed `Access<T>` replaces old hashmap-based approach everywhere
* Query conflicts are determined by component access instead of archetype component access (to avoid random failures at runtime)
* With/Without are still taken into account for conflicts, so this should still be comfy to use
* Much simpler `IntoSystem` impl
* Significantly reduced the amount of hashing throughout the ecs in favor of Sparse Sets (indexed by densely packed ArchetypeId, ComponentId, BundleId, and TableId)
* Safety Improvements
* Entity reservation uses a normal world reference instead of unsafe transmute
* QuerySets no longer transmute lifetimes
* Made traits "unsafe" where relevant
* More thorough safety docs
* WorldCell
* Exposes safe mutable access to multiple resources at a time in a World
* Replaced "catch all" `System::update_archetypes(world: &World)` with `System::new_archetype(archetype: &Archetype)`
* Simpler Bundle implementation
* Replaced slow "remove_bundle_one_by_one" used as fallback for Commands::remove_bundle with fast "remove_bundle_intersection"
* Removed `Mut<T>` query impl. it is better to only support one way: `&mut T`
* Removed with() from `Flags<T>` in favor of `Option<Flags<T>>`, which allows querying for flags to be "filtered" by default
* Components now have is_send property (currently only resources support non-send)
* More granular module organization
* New `RemovedComponents<T>` SystemParam that replaces `query.removed::<T>()`
* `world.resource_scope()` for mutable access to resources and world at the same time
* WorldQuery and QueryFilter traits unified. FilterFetch trait added to enable "short circuit" filtering. Auto impled for cases that don't need it
* Significantly slimmed down SystemState in favor of individual SystemParam state
* System Commands changed from `commands: &mut Commands` back to `mut commands: Commands` (to allow Commands to have a World reference)
Fixes #1320
## `World` Rewrite
This is a from-scratch rewrite of `World` that fills the niche that `hecs` used to. Yes, this means Bevy ECS is no longer a "fork" of hecs. We're going out our own!
(the only shared code between the projects is the entity id allocator, which is already basically ideal)
A huge shout out to @SanderMertens (author of [flecs](https://github.com/SanderMertens/flecs)) for sharing some great ideas with me (specifically hybrid ecs storage and archetype graphs). He also helped advise on a number of implementation details.
## Component Storage (The Problem)
Two ECS storage paradigms have gained a lot of traction over the years:
* **Archetypal ECS**:
* Stores components in "tables" with static schemas. Each "column" stores components of a given type. Each "row" is an entity.
* Each "archetype" has its own table. Adding/removing an entity's component changes the archetype.
* Enables super-fast Query iteration due to its cache-friendly data layout
* Comes at the cost of more expensive add/remove operations for an Entity's components, because all components need to be copied to the new archetype's "table"
* **Sparse Set ECS**:
* Stores components of the same type in densely packed arrays, which are sparsely indexed by densely packed unsigned integers (Entity ids)
* Query iteration is slower than Archetypal ECS because each entity's component could be at any position in the sparse set. This "random access" pattern isn't cache friendly. Additionally, there is an extra layer of indirection because you must first map the entity id to an index in the component array.
* Adding/removing components is a cheap, constant time operation
Bevy ECS V1, hecs, legion, flec, and Unity DOTS are all "archetypal ecs-es". I personally think "archetypal" storage is a good default for game engines. An entity's archetype doesn't need to change frequently in general, and it creates "fast by default" query iteration (which is a much more common operation). It is also "self optimizing". Users don't need to think about optimizing component layouts for iteration performance. It "just works" without any extra boilerplate.
Shipyard and EnTT are "sparse set ecs-es". They employ "packing" as a way to work around the "suboptimal by default" iteration performance for specific sets of components. This helps, but I didn't think this was a good choice for a general purpose engine like Bevy because:
1. "packs" conflict with each other. If bevy decides to internally pack the Transform and GlobalTransform components, users are then blocked if they want to pack some custom component with Transform.
2. users need to take manual action to optimize
Developers selecting an ECS framework are stuck with a hard choice. Select an "archetypal" framework with "fast iteration everywhere" but without the ability to cheaply add/remove components, or select a "sparse set" framework to cheaply add/remove components but with slower iteration performance.
## Hybrid Component Storage (The Solution)
In Bevy ECS V2, we get to have our cake and eat it too. It now has _both_ of the component storage types above (and more can be added later if needed):
* **Tables** (aka "archetypal" storage)
* The default storage. If you don't configure anything, this is what you get
* Fast iteration by default
* Slower add/remove operations
* **Sparse Sets**
* Opt-in
* Slower iteration
* Faster add/remove operations
These storage types complement each other perfectly. By default Query iteration is fast. If developers know that they want to add/remove a component at high frequencies, they can set the storage to "sparse set":
```rust
world.register_component(
ComponentDescriptor::new::<MyComponent>(StorageType::SparseSet)
).unwrap();
```
## Archetypes
Archetypes are now "just metadata" ... they no longer store components directly. They do store:
* The `ComponentId`s of each of the Archetype's components (and that component's storage type)
* Archetypes are uniquely defined by their component layouts
* For example: entities with "table" components `[A, B, C]` _and_ "sparse set" components `[D, E]` will always be in the same archetype.
* The `TableId` associated with the archetype
* For now each archetype has exactly one table (which can have no components),
* There is a 1->Many relationship from Tables->Archetypes. A given table could have any number of archetype components stored in it:
* Ex: an entity with "table storage" components `[A, B, C]` and "sparse set" components `[D, E]` will share the same `[A, B, C]` table as an entity with `[A, B, C]` table component and `[F]` sparse set components.
* This 1->Many relationship is how we preserve fast "cache friendly" iteration performance when possible (more on this later)
* A list of entities that are in the archetype and the row id of the table they are in
* ArchetypeComponentIds
* unique densely packed identifiers for (ArchetypeId, ComponentId) pairs
* used by the schedule executor for cheap system access control
* "Archetype Graph Edges" (see the next section)
## The "Archetype Graph"
Archetype changes in Bevy (and a number of other archetypal ecs-es) have historically been expensive to compute. First, you need to allocate a new vector of the entity's current component ids, add or remove components based on the operation performed, sort it (to ensure it is order-independent), then hash it to find the archetype (if it exists). And thats all before we get to the _already_ expensive full copy of all components to the new table storage.
The solution is to build a "graph" of archetypes to cache these results. @SanderMertens first exposed me to the idea (and he got it from @gjroelofs, who came up with it). They propose adding directed edges between archetypes for add/remove component operations. If `ComponentId`s are densely packed, you can use sparse sets to cheaply jump between archetypes.
Bevy takes this one step further by using add/remove `Bundle` edges instead of `Component` edges. Bevy encourages the use of `Bundles` to group add/remove operations. This is largely for "clearer game logic" reasons, but it also helps cut down on the number of archetype changes required. `Bundles` now also have densely-packed `BundleId`s. This allows us to use a _single_ edge for each bundle operation (rather than needing to traverse N edges ... one for each component). Single component operations are also bundles, so this is strictly an improvement over a "component only" graph.
As a result, an operation that used to be _heavy_ (both for allocations and compute) is now two dirt-cheap array lookups and zero allocations.
## Stateful Queries
World queries are now stateful. This allows us to:
1. Cache archetype (and table) matches
* This resolves another issue with (naive) archetypal ECS: query performance getting worse as the number of archetypes goes up (and fragmentation occurs).
2. Cache Fetch and Filter state
* The expensive parts of fetch/filter operations (such as hashing the TypeId to find the ComponentId) now only happen once when the Query is first constructed
3. Incrementally build up state
* When new archetypes are added, we only process the new archetypes (no need to rebuild state for old archetypes)
As a result, the direct `World` query api now looks like this:
```rust
let mut query = world.query::<(&A, &mut B)>();
for (a, mut b) in query.iter_mut(&mut world) {
}
```
Requiring `World` to generate stateful queries (rather than letting the `QueryState` type be constructed separately) allows us to ensure that _all_ queries are properly initialized (and the relevant world state, such as ComponentIds). This enables QueryState to remove branches from its operations that check for initialization status (and also enables query.iter() to take an immutable world reference because it doesn't need to initialize anything in world).
However in systems, this is a non-breaking change. State management is done internally by the relevant SystemParam.
## Stateful SystemParams
Like Queries, `SystemParams` now also cache state. For example, `Query` system params store the "stateful query" state mentioned above. Commands store their internal `CommandQueue`. This means you can now safely use as many separate `Commands` parameters in your system as you want. `Local<T>` system params store their `T` value in their state (instead of in Resources).
SystemParam state also enabled a significant slim-down of SystemState. It is much nicer to look at now.
Per-SystemParam state naturally insulates us from an "aliased mut" class of errors we have hit in the past (ex: using multiple `Commands` system params).
(credit goes to @DJMcNab for the initial idea and draft pr here #1364)
## Configurable SystemParams
@DJMcNab also had the great idea to make SystemParams configurable. This allows users to provide some initial configuration / values for system parameters (when possible). Most SystemParams have no config (the config type is `()`), but the `Local<T>` param now supports user-provided parameters:
```rust
fn foo(value: Local<usize>) {
}
app.add_system(foo.system().config(|c| c.0 = Some(10)));
```
## Uber Fast "for_each" Query Iterators
Developers now have the choice to use a fast "for_each" iterator, which yields ~1.5-3x iteration speed improvements for "fragmented iteration", and minor ~1.2x iteration speed improvements for unfragmented iteration.
```rust
fn system(query: Query<(&A, &mut B)>) {
// you now have the option to do this for a speed boost
query.for_each_mut(|(a, mut b)| {
});
// however normal iterators are still available
for (a, mut b) in query.iter_mut() {
}
}
```
I think in most cases we should continue to encourage "normal" iterators as they are more flexible and more "rust idiomatic". But when that extra "oomf" is needed, it makes sense to use `for_each`.
We should also consider using `for_each` for internal bevy systems to give our users a nice speed boost (but that should be a separate pr).
## Component Metadata
`World` now has a `Components` collection, which is accessible via `world.components()`. This stores mappings from `ComponentId` to `ComponentInfo`, as well as `TypeId` to `ComponentId` mappings (where relevant). `ComponentInfo` stores information about the component, such as ComponentId, TypeId, memory layout, send-ness (currently limited to resources), and storage type.
## Significantly Cheaper `Access<T>`
We used to use `TypeAccess<TypeId>` to manage read/write component/archetype-component access. This was expensive because TypeIds must be hashed and compared individually. The parallel executor got around this by "condensing" type ids into bitset-backed access types. This worked, but it had to be re-generated from the `TypeAccess<TypeId>`sources every time archetypes changed.
This pr removes TypeAccess in favor of faster bitset access everywhere. We can do this thanks to the move to densely packed `ComponentId`s and `ArchetypeComponentId`s.
## Merged Resources into World
Resources had a lot of redundant functionality with Components. They stored typed data, they had access control, they had unique ids, they were queryable via SystemParams, etc. In fact the _only_ major difference between them was that they were unique (and didn't correlate to an entity).
Separate resources also had the downside of requiring a separate set of access controls, which meant the parallel executor needed to compare more bitsets per system and manage more state.
I initially got the "separate resources" idea from `legion`. I think that design was motivated by the fact that it made the direct world query/resource lifetime interactions more manageable. It certainly made our lives easier when using Resources alongside hecs/bevy_ecs. However we already have a construct for safely and ergonomically managing in-world lifetimes: systems (which use `Access<T>` internally).
This pr merges Resources into World:
```rust
world.insert_resource(1);
world.insert_resource(2.0);
let a = world.get_resource::<i32>().unwrap();
let mut b = world.get_resource_mut::<f64>().unwrap();
*b = 3.0;
```
Resources are now just a special kind of component. They have their own ComponentIds (and their own resource TypeId->ComponentId scope, so they don't conflict wit components of the same type). They are stored in a special "resource archetype", which stores components inside the archetype using a new `unique_components` sparse set (note that this sparse set could later be used to implement Tags). This allows us to keep the code size small by reusing existing datastructures (namely Column, Archetype, ComponentFlags, and ComponentInfo). This allows us the executor to use a single `Access<ArchetypeComponentId>` per system. It should also make scripting language integration easier.
_But_ this merge did create problems for people directly interacting with `World`. What if you need mutable access to multiple resources at the same time? `world.get_resource_mut()` borrows World mutably!
## WorldCell
WorldCell applies the `Access<ArchetypeComponentId>` concept to direct world access:
```rust
let world_cell = world.cell();
let a = world_cell.get_resource_mut::<i32>().unwrap();
let b = world_cell.get_resource_mut::<f64>().unwrap();
```
This adds cheap runtime checks (a sparse set lookup of `ArchetypeComponentId` and a counter) to ensure that world accesses do not conflict with each other. Each operation returns a `WorldBorrow<'w, T>` or `WorldBorrowMut<'w, T>` wrapper type, which will release the relevant ArchetypeComponentId resources when dropped.
World caches the access sparse set (and only one cell can exist at a time), so `world.cell()` is a cheap operation.
WorldCell does _not_ use atomic operations. It is non-send, does a mutable borrow of world to prevent other accesses, and uses a simple `Rc<RefCell<ArchetypeComponentAccess>>` wrapper in each WorldBorrow pointer.
The api is currently limited to resource access, but it can and should be extended to queries / entity component access.
## Resource Scopes
WorldCell does not yet support component queries, and even when it does there are sometimes legitimate reasons to want a mutable world ref _and_ a mutable resource ref (ex: bevy_render and bevy_scene both need this). In these cases we could always drop down to the unsafe `world.get_resource_unchecked_mut()`, but that is not ideal!
Instead developers can use a "resource scope"
```rust
world.resource_scope(|world: &mut World, a: &mut A| {
})
```
This temporarily removes the `A` resource from `World`, provides mutable pointers to both, and re-adds A to World when finished. Thanks to the move to ComponentIds/sparse sets, this is a cheap operation.
If multiple resources are required, scopes can be nested. We could also consider adding a "resource tuple" to the api if this pattern becomes common and the boilerplate gets nasty.
## Query Conflicts Use ComponentId Instead of ArchetypeComponentId
For safety reasons, systems cannot contain queries that conflict with each other without wrapping them in a QuerySet. On bevy `main`, we use ArchetypeComponentIds to determine conflicts. This is nice because it can take into account filters:
```rust
// these queries will never conflict due to their filters
fn filter_system(a: Query<&mut A, With<B>>, b: Query<&mut B, Without<B>>) {
}
```
But it also has a significant downside:
```rust
// these queries will not conflict _until_ an entity with A, B, and C is spawned
fn maybe_conflicts_system(a: Query<(&mut A, &C)>, b: Query<(&mut A, &B)>) {
}
```
The system above will panic at runtime if an entity with A, B, and C is spawned. This makes it hard to trust that your game logic will run without crashing.
In this pr, I switched to using `ComponentId` instead. This _is_ more constraining. `maybe_conflicts_system` will now always fail, but it will do it consistently at startup. Naively, it would also _disallow_ `filter_system`, which would be a significant downgrade in usability. Bevy has a number of internal systems that rely on disjoint queries and I expect it to be a common pattern in userspace.
To resolve this, I added a new `FilteredAccess<T>` type, which wraps `Access<T>` and adds with/without filters. If two `FilteredAccess` have with/without values that prove they are disjoint, they will no longer conflict.
## EntityRef / EntityMut
World entity operations on `main` require that the user passes in an `entity` id to each operation:
```rust
let entity = world.spawn((A, )); // create a new entity with A
world.get::<A>(entity);
world.insert(entity, (B, C));
world.insert_one(entity, D);
```
This means that each operation needs to look up the entity location / verify its validity. The initial spawn operation also requires a Bundle as input. This can be awkward when no components are required (or one component is required).
These operations have been replaced by `EntityRef` and `EntityMut`, which are "builder-style" wrappers around world that provide read and read/write operations on a single, pre-validated entity:
```rust
// spawn now takes no inputs and returns an EntityMut
let entity = world.spawn()
.insert(A) // insert a single component into the entity
.insert_bundle((B, C)) // insert a bundle of components into the entity
.id() // id returns the Entity id
// Returns EntityMut (or panics if the entity does not exist)
world.entity_mut(entity)
.insert(D)
.insert_bundle(SomeBundle::default());
{
// returns EntityRef (or panics if the entity does not exist)
let d = world.entity(entity)
.get::<D>() // gets the D component
.unwrap();
// world.get still exists for ergonomics
let d = world.get::<D>(entity).unwrap();
}
// These variants return Options if you want to check existence instead of panicing
world.get_entity_mut(entity)
.unwrap()
.insert(E);
if let Some(entity_ref) = world.get_entity(entity) {
let d = entity_ref.get::<D>().unwrap();
}
```
This _does not_ affect the current Commands api or terminology. I think that should be a separate conversation as that is a much larger breaking change.
## Safety Improvements
* Entity reservation in Commands uses a normal world borrow instead of an unsafe transmute
* QuerySets no longer transmutes lifetimes
* Made traits "unsafe" when implementing a trait incorrectly could cause unsafety
* More thorough safety docs
## RemovedComponents SystemParam
The old approach to querying removed components: `query.removed:<T>()` was confusing because it had no connection to the query itself. I replaced it with the following, which is both clearer and allows us to cache the ComponentId mapping in the SystemParamState:
```rust
fn system(removed: RemovedComponents<T>) {
for entity in removed.iter() {
}
}
```
## Simpler Bundle implementation
Bundles are no longer responsible for sorting (or deduping) TypeInfo. They are just a simple ordered list of component types / data. This makes the implementation smaller and opens the door to an easy "nested bundle" implementation in the future (which i might even add in this pr). Duplicate detection is now done once per bundle type by World the first time a bundle is used.
## Unified WorldQuery and QueryFilter types
(don't worry they are still separate type _parameters_ in Queries .. this is a non-breaking change)
WorldQuery and QueryFilter were already basically identical apis. With the addition of `FetchState` and more storage-specific fetch methods, the overlap was even clearer (and the redundancy more painful).
QueryFilters are now just `F: WorldQuery where F::Fetch: FilterFetch`. FilterFetch requires `Fetch<Item = bool>` and adds new "short circuit" variants of fetch methods. This enables a filter tuple like `(With<A>, Without<B>, Changed<C>)` to stop evaluating the filter after the first mismatch is encountered. FilterFetch is automatically implemented for `Fetch` implementations that return bool.
This forces fetch implementations that return things like `(bool, bool, bool)` (such as the filter above) to manually implement FilterFetch and decide whether or not to short-circuit.
## More Granular Modules
World no longer globs all of the internal modules together. It now exports `core`, `system`, and `schedule` separately. I'm also considering exporting `core` submodules directly as that is still pretty "glob-ey" and unorganized (feedback welcome here).
## Remaining Draft Work (to be done in this pr)
* ~~panic on conflicting WorldQuery fetches (&A, &mut A)~~
* ~~bevy `main` and hecs both currently allow this, but we should protect against it if possible~~
* ~~batch_iter / par_iter (currently stubbed out)~~
* ~~ChangedRes~~
* ~~I skipped this while we sort out #1313. This pr should be adapted to account for whatever we land on there~~.
* ~~The `Archetypes` and `Tables` collections use hashes of sorted lists of component ids to uniquely identify each archetype/table. This hash is then used as the key in a HashMap to look up the relevant ArchetypeId or TableId. (which doesn't handle hash collisions properly)~~
* ~~It is currently unsafe to generate a Query from "World A", then use it on "World B" (despite the api claiming it is safe). We should probably close this gap. This could be done by adding a randomly generated WorldId to each world, then storing that id in each Query. They could then be compared to each other on each `query.do_thing(&world)` operation. This _does_ add an extra branch to each query operation, so I'm open to other suggestions if people have them.~~
* ~~Nested Bundles (if i find time)~~
## Potential Future Work
* Expand WorldCell to support queries.
* Consider not allocating in the empty archetype on `world.spawn()`
* ex: return something like EntityMutUninit, which turns into EntityMut after an `insert` or `insert_bundle` op
* this actually regressed performance last time i tried it, but in theory it should be faster
* Optimize SparseSet::insert (see `PERF` comment on insert)
* Replace SparseArray `Option<T>` with T::MAX to cut down on branching
* would enable cheaper get_unchecked() operations
* upstream fixedbitset optimizations
* fixedbitset could be allocation free for small block counts (store blocks in a SmallVec)
* fixedbitset could have a const constructor
* Consider implementing Tags (archetype-specific by-value data that affects archetype identity)
* ex: ArchetypeA could have `[A, B, C]` table components and `[D(1)]` "tag" component. ArchetypeB could have `[A, B, C]` table components and a `[D(2)]` tag component. The archetypes are different, despite both having D tags because the value inside D is different.
* this could potentially build on top of the `archetype.unique_components` added in this pr for resource storage.
* Consider reverting `all_tuples` proc macro in favor of the old `macro_rules` implementation
* all_tuples is more flexible and produces cleaner documentation (the macro_rules version produces weird type parameter orders due to parser constraints)
* but unfortunately all_tuples also appears to make Rust Analyzer sad/slow when working inside of `bevy_ecs` (does not affect user code)
* Consider "resource queries" and/or "mixed resource and entity component queries" as an alternative to WorldCell
* this is basically just "systems" so maybe it's not worth it
* Add more world ops
* `world.clear()`
* `world.reserve<T: Bundle>(count: usize)`
* Try using the old archetype allocation strategy (allocate new memory on resize and copy everything over). I expect this to improve batch insertion performance at the cost of unbatched performance. But thats just a guess. I'm not an allocation perf pro :)
* Adapt Commands apis for consistency with new World apis
## Benchmarks
key:
* `bevy_old`: bevy `main` branch
* `bevy`: this branch
* `_foreach`: uses an optimized for_each iterator
* ` _sparse`: uses sparse set storage (if unspecified assume table storage)
* `_system`: runs inside a system (if unspecified assume test happens via direct world ops)
### Simple Insert (from ecs_bench_suite)
![image](https://user-images.githubusercontent.com/2694663/109245573-9c3ce100-7795-11eb-9003-bfd41cd5c51f.png)
### Simpler Iter (from ecs_bench_suite)
![image](https://user-images.githubusercontent.com/2694663/109245795-ffc70e80-7795-11eb-92fb-3ffad09aabf7.png)
### Fragment Iter (from ecs_bench_suite)
![image](https://user-images.githubusercontent.com/2694663/109245849-0fdeee00-7796-11eb-8d25-eb6b7a682c48.png)
### Sparse Fragmented Iter
Iterate a query that matches 5 entities from a single matching archetype, but there are 100 unmatching archetypes
![image](https://user-images.githubusercontent.com/2694663/109245916-2b49f900-7796-11eb-9a8f-ed89c203f940.png)
### Schedule (from ecs_bench_suite)
![image](https://user-images.githubusercontent.com/2694663/109246428-1fab0200-7797-11eb-8841-1b2161e90fa4.png)
### Add Remove Component (from ecs_bench_suite)
![image](https://user-images.githubusercontent.com/2694663/109246492-39e4e000-7797-11eb-8985-2706bd0495ab.png)
### Add Remove Component Big
Same as the test above, but each entity has 5 "large" matrix components and 1 "large" matrix component is added and removed
![image](https://user-images.githubusercontent.com/2694663/109246517-449f7500-7797-11eb-835e-28b6790daeaa.png)
### Get Component
Looks up a single component value a large number of times
![image](https://user-images.githubusercontent.com/2694663/109246129-87ad1880-7796-11eb-9fcb-c38012aa7c70.png)
2021-03-05 07:54:35 +00:00
|
|
|
|
self.schedule.run(&mut self.world);
|
2022-12-11 18:34:15 +00:00
|
|
|
|
|
2021-08-24 00:31:21 +00:00
|
|
|
|
for sub_app in self.sub_apps.values_mut() {
|
Separate Extract from Sub App Schedule (#7046)
# Objective
- This pulls out some of the changes to Plugin setup and sub apps from #6503 to make that PR easier to review.
- Separate the extract stage from running the sub app's schedule to allow for them to be run on separate threads in the future
- Fixes #6990
## Solution
- add a run method to `SubApp` that runs the schedule
- change the name of `sub_app_runner` to extract to make it clear that this function is only for extracting data between the main app and the sub app
- remove the extract stage from the sub app schedule so it can be run separately. This is done by adding a `setup` method to the `Plugin` trait that runs after all plugin build methods run. This is required to allow the extract stage to be removed from the schedule after all the plugins have added their systems to the stage. We will also need the setup method for pipelined rendering to setup the render thread. See https://github.com/bevyengine/bevy/blob/e3267965e15f14be18eec942dcaf16807144eb05/crates/bevy_render/src/pipelined_rendering.rs#L57-L98
## Changelog
- Separate SubApp Extract stage from running the sub app schedule.
## Migration Guide
### SubApp `runner` has conceptually been changed to an `extract` function.
The `runner` no longer is in charge of running the sub app schedule. It's only concern is now moving data between the main world and the sub app. The `sub_app.app.schedule` is now run for you after the provided function is called.
```rust
// before
fn main() {
let sub_app = App::empty();
sub_app.add_stage(MyStage, SystemStage::parallel());
App::new().add_sub_app(MySubApp, sub_app, move |main_world, sub_app| {
extract(app_world, render_app);
render_app.app.schedule.run();
});
}
// after
fn main() {
let sub_app = App::empty();
sub_app.add_stage(MyStage, SystemStage::parallel());
App::new().add_sub_app(MySubApp, sub_app, move |main_world, sub_app| {
extract(app_world, render_app);
// schedule is automatically called for you after extract is run
});
}
```
2023-01-09 19:24:54 +00:00
|
|
|
|
sub_app.extract(&mut self.world);
|
|
|
|
|
sub_app.run();
|
2021-04-11 20:13:07 +00:00
|
|
|
|
}
|
2022-12-11 18:34:15 +00:00
|
|
|
|
|
|
|
|
|
self.world.clear_trackers();
|
2020-10-18 19:25:33 +00:00
|
|
|
|
}
|
2020-07-22 20:32:17 +00:00
|
|
|
|
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// Starts the application by calling the app's [runner function](Self::set_runner).
|
2021-07-27 20:21:06 +00:00
|
|
|
|
///
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// Finalizes the [`App`] configuration. For general usage, see the example on the item
|
|
|
|
|
/// level documentation.
|
2022-12-24 23:43:41 +00:00
|
|
|
|
///
|
2023-01-18 23:02:38 +00:00
|
|
|
|
/// # `run()` might not return
|
|
|
|
|
///
|
|
|
|
|
/// Calls to [`App::run()`] might never return.
|
|
|
|
|
///
|
|
|
|
|
/// In simple and *headless* applications, one can expect that execution will
|
|
|
|
|
/// proceed, normally, after calling [`run()`](App::run()) but this is not the case for
|
|
|
|
|
/// windowed applications.
|
|
|
|
|
///
|
|
|
|
|
/// Windowed apps are typically driven by an *event loop* or *message loop* and
|
|
|
|
|
/// some window-manager APIs expect programs to terminate when their primary
|
|
|
|
|
/// window is closed and that event loop terminates – behaviour of processes that
|
|
|
|
|
/// do not is often platform dependent or undocumented.
|
|
|
|
|
///
|
|
|
|
|
/// By default, *Bevy* uses the `winit` crate for window creation. See
|
|
|
|
|
/// [`WinitSettings::return_from_run`](https://docs.rs/bevy/latest/bevy/winit/struct.WinitSettings.html#structfield.return_from_run)
|
|
|
|
|
/// for further discussion of this topic and for a mechanism to require that [`App::run()`]
|
|
|
|
|
/// *does* return – albeit one that carries its own caveats and disclaimers.
|
|
|
|
|
///
|
2022-12-24 23:43:41 +00:00
|
|
|
|
/// # Panics
|
|
|
|
|
///
|
|
|
|
|
/// Panics if called from `Plugin::build()`, because it would prevent other plugins to properly build.
|
2021-07-27 20:21:06 +00:00
|
|
|
|
pub fn run(&mut self) {
|
2020-11-11 02:49:49 +00:00
|
|
|
|
#[cfg(feature = "trace")]
|
2022-03-18 04:19:21 +00:00
|
|
|
|
let _bevy_app_run_span = info_span!("bevy_app").entered();
|
2020-11-11 02:49:49 +00:00
|
|
|
|
|
2021-07-27 20:21:06 +00:00
|
|
|
|
let mut app = std::mem::replace(self, App::empty());
|
2022-12-24 23:43:41 +00:00
|
|
|
|
if app.is_building_plugin {
|
|
|
|
|
panic!("App::run() was called from within Plugin::Build(), which is not allowed.");
|
|
|
|
|
}
|
Separate Extract from Sub App Schedule (#7046)
# Objective
- This pulls out some of the changes to Plugin setup and sub apps from #6503 to make that PR easier to review.
- Separate the extract stage from running the sub app's schedule to allow for them to be run on separate threads in the future
- Fixes #6990
## Solution
- add a run method to `SubApp` that runs the schedule
- change the name of `sub_app_runner` to extract to make it clear that this function is only for extracting data between the main app and the sub app
- remove the extract stage from the sub app schedule so it can be run separately. This is done by adding a `setup` method to the `Plugin` trait that runs after all plugin build methods run. This is required to allow the extract stage to be removed from the schedule after all the plugins have added their systems to the stage. We will also need the setup method for pipelined rendering to setup the render thread. See https://github.com/bevyengine/bevy/blob/e3267965e15f14be18eec942dcaf16807144eb05/crates/bevy_render/src/pipelined_rendering.rs#L57-L98
## Changelog
- Separate SubApp Extract stage from running the sub app schedule.
## Migration Guide
### SubApp `runner` has conceptually been changed to an `extract` function.
The `runner` no longer is in charge of running the sub app schedule. It's only concern is now moving data between the main world and the sub app. The `sub_app.app.schedule` is now run for you after the provided function is called.
```rust
// before
fn main() {
let sub_app = App::empty();
sub_app.add_stage(MyStage, SystemStage::parallel());
App::new().add_sub_app(MySubApp, sub_app, move |main_world, sub_app| {
extract(app_world, render_app);
render_app.app.schedule.run();
});
}
// after
fn main() {
let sub_app = App::empty();
sub_app.add_stage(MyStage, SystemStage::parallel());
App::new().add_sub_app(MySubApp, sub_app, move |main_world, sub_app| {
extract(app_world, render_app);
// schedule is automatically called for you after extract is run
});
}
```
2023-01-09 19:24:54 +00:00
|
|
|
|
|
|
|
|
|
// temporarily remove the plugin registry to run each plugin's setup function on app.
|
|
|
|
|
let mut plugin_registry = std::mem::take(&mut app.plugin_registry);
|
|
|
|
|
for plugin in &plugin_registry {
|
|
|
|
|
plugin.setup(&mut app);
|
|
|
|
|
}
|
|
|
|
|
std::mem::swap(&mut app.plugin_registry, &mut plugin_registry);
|
|
|
|
|
|
2021-07-27 20:21:06 +00:00
|
|
|
|
let runner = std::mem::replace(&mut app.runner, Box::new(run_once));
|
|
|
|
|
(runner)(app);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// Adds a [`Stage`] with the given `label` to the last position of the app's
|
|
|
|
|
/// [`Schedule`].
|
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// # Examples
|
2021-09-17 18:00:29 +00:00
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use bevy_app::prelude::*;
|
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
|
/// # let mut app = App::new();
|
|
|
|
|
/// #
|
2022-09-03 18:06:41 +00:00
|
|
|
|
/// #[derive(StageLabel)]
|
|
|
|
|
/// struct MyStage;
|
|
|
|
|
/// app.add_stage(MyStage, SystemStage::parallel());
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// ```
|
2021-07-27 20:21:06 +00:00
|
|
|
|
pub fn add_stage<S: Stage>(&mut self, label: impl StageLabel, stage: S) -> &mut Self {
|
|
|
|
|
self.schedule.add_stage(label, stage);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// Adds a [`Stage`] with the given `label` to the app's [`Schedule`], located
|
|
|
|
|
/// immediately after the stage labeled by `target`.
|
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// # Examples
|
2021-09-17 18:00:29 +00:00
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use bevy_app::prelude::*;
|
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
|
/// # let mut app = App::new();
|
|
|
|
|
/// #
|
2022-09-03 18:06:41 +00:00
|
|
|
|
/// #[derive(StageLabel)]
|
|
|
|
|
/// struct MyStage;
|
|
|
|
|
/// app.add_stage_after(CoreStage::Update, MyStage, SystemStage::parallel());
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// ```
|
2021-07-27 20:21:06 +00:00
|
|
|
|
pub fn add_stage_after<S: Stage>(
|
|
|
|
|
&mut self,
|
|
|
|
|
target: impl StageLabel,
|
|
|
|
|
label: impl StageLabel,
|
|
|
|
|
stage: S,
|
|
|
|
|
) -> &mut Self {
|
|
|
|
|
self.schedule.add_stage_after(target, label, stage);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// Adds a [`Stage`] with the given `label` to the app's [`Schedule`], located
|
|
|
|
|
/// immediately before the stage labeled by `target`.
|
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// # Examples
|
2021-09-17 18:00:29 +00:00
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use bevy_app::prelude::*;
|
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
|
/// # let mut app = App::new();
|
|
|
|
|
/// #
|
2022-09-03 18:06:41 +00:00
|
|
|
|
/// #[derive(StageLabel)]
|
|
|
|
|
/// struct MyStage;
|
|
|
|
|
/// app.add_stage_before(CoreStage::Update, MyStage, SystemStage::parallel());
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// ```
|
2021-07-27 20:21:06 +00:00
|
|
|
|
pub fn add_stage_before<S: Stage>(
|
|
|
|
|
&mut self,
|
|
|
|
|
target: impl StageLabel,
|
|
|
|
|
label: impl StageLabel,
|
|
|
|
|
stage: S,
|
|
|
|
|
) -> &mut Self {
|
|
|
|
|
self.schedule.add_stage_before(target, label, stage);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// Adds a [`Stage`] with the given `label` to the last position of the
|
|
|
|
|
/// [startup schedule](Self::add_default_stages).
|
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// # Examples
|
2021-09-17 18:00:29 +00:00
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use bevy_app::prelude::*;
|
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
|
/// # let mut app = App::new();
|
|
|
|
|
/// #
|
2022-09-03 18:06:41 +00:00
|
|
|
|
/// #[derive(StageLabel)]
|
|
|
|
|
/// struct MyStartupStage;
|
|
|
|
|
/// app.add_startup_stage(MyStartupStage, SystemStage::parallel());
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// ```
|
2021-07-27 20:21:06 +00:00
|
|
|
|
pub fn add_startup_stage<S: Stage>(&mut self, label: impl StageLabel, stage: S) -> &mut Self {
|
|
|
|
|
self.schedule
|
Move the CoreStage::Startup to a seperate StartupSchedule label (#2434)
# Objective
- `CoreStage::Startup` is unique in the `CoreStage` enum, in that it represents a `Schedule` and not a `SystemStage`.
- This can lead to confusion about how `CoreStage::Startup` and the `StartupStage` enum are related.
- Beginners sometimes try `.add_system_to_stage(CoreStage::Startup, setup.system())` instead of `.add_startup_system(setup.system())`, which causes a Panic:
```
thread 'main' panicked at 'Stage 'Startup' does not exist or is not a SystemStage', crates\bevy_ecs\src\schedule\mod.rs:153:13
stack backtrace:
0: std::panicking::begin_panic_handler
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b\/library\std\src\panicking.rs:493
1: std::panicking::begin_panic_fmt
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b\/library\std\src\panicking.rs:435
2: bevy_ecs::schedule::{{impl}}::add_system_to_stage::stage_not_found
at .\crates\bevy_ecs\src\schedule\mod.rs:153
3: bevy_ecs::schedule::{{impl}}::add_system_to_stage::{{closure}}<tuple<bevy_ecs::system::function_system::IsFunctionSystem, tuple<bevy_ecs::system::commands::Commands, bevy_ecs::change_detection::ResMut<bevy_asset::assets::Assets<bevy_render::mesh::mesh::Me
at .\crates\bevy_ecs\src\schedule\mod.rs:161
4: core::option::Option<mut bevy_ecs::schedule::stage::SystemStage*>::unwrap_or_else<mut bevy_ecs::schedule::stage::SystemStage*,closure-0>
at C:\Users\scher\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\option.rs:427
5: bevy_ecs::schedule::Schedule::add_system_to_stage<tuple<bevy_ecs::system::function_system::IsFunctionSystem, tuple<bevy_ecs::system::commands::Commands, bevy_ecs::change_detection::ResMut<bevy_asset::assets::Assets<bevy_render::mesh::mesh::Mesh>>, bevy_ec
at .\crates\bevy_ecs\src\schedule\mod.rs:159
6: bevy_app::app_builder::AppBuilder::add_system_to_stage<tuple<bevy_ecs::system::function_system::IsFunctionSystem, tuple<bevy_ecs::system::commands::Commands, bevy_ecs::change_detection::ResMut<bevy_asset::assets::Assets<bevy_render::mesh::mesh::Mesh>>, be
at .\crates\bevy_app\src\app_builder.rs:196
7: 3d_scene::main
at .\examples\3d\3d_scene.rs:4
8: core::ops::function::FnOnce::call_once<fn(),tuple<>>
at C:\Users\scher\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\ops\function.rs:227
```
## Solution
- Replace the `CoreStage::Startup` Label with the new `StartupSchedule` unit type.
Resolves #2229
2022-02-08 00:03:50 +00:00
|
|
|
|
.stage(StartupSchedule, |schedule: &mut Schedule| {
|
2021-07-27 20:21:06 +00:00
|
|
|
|
schedule.add_stage(label, stage)
|
|
|
|
|
});
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// Adds a [startup stage](Self::add_default_stages) with the given `label`, immediately
|
|
|
|
|
/// after the stage labeled by `target`.
|
|
|
|
|
///
|
|
|
|
|
/// The `target` label must refer to a stage inside the startup schedule.
|
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// # Examples
|
2021-09-17 18:00:29 +00:00
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use bevy_app::prelude::*;
|
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
|
/// # let mut app = App::new();
|
|
|
|
|
/// #
|
2022-09-03 18:06:41 +00:00
|
|
|
|
/// #[derive(StageLabel)]
|
|
|
|
|
/// struct MyStartupStage;
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// app.add_startup_stage_after(
|
|
|
|
|
/// StartupStage::Startup,
|
2022-09-03 18:06:41 +00:00
|
|
|
|
/// MyStartupStage,
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// SystemStage::parallel()
|
|
|
|
|
/// );
|
|
|
|
|
/// ```
|
2021-07-27 20:21:06 +00:00
|
|
|
|
pub fn add_startup_stage_after<S: Stage>(
|
|
|
|
|
&mut self,
|
|
|
|
|
target: impl StageLabel,
|
|
|
|
|
label: impl StageLabel,
|
|
|
|
|
stage: S,
|
|
|
|
|
) -> &mut Self {
|
|
|
|
|
self.schedule
|
Move the CoreStage::Startup to a seperate StartupSchedule label (#2434)
# Objective
- `CoreStage::Startup` is unique in the `CoreStage` enum, in that it represents a `Schedule` and not a `SystemStage`.
- This can lead to confusion about how `CoreStage::Startup` and the `StartupStage` enum are related.
- Beginners sometimes try `.add_system_to_stage(CoreStage::Startup, setup.system())` instead of `.add_startup_system(setup.system())`, which causes a Panic:
```
thread 'main' panicked at 'Stage 'Startup' does not exist or is not a SystemStage', crates\bevy_ecs\src\schedule\mod.rs:153:13
stack backtrace:
0: std::panicking::begin_panic_handler
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b\/library\std\src\panicking.rs:493
1: std::panicking::begin_panic_fmt
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b\/library\std\src\panicking.rs:435
2: bevy_ecs::schedule::{{impl}}::add_system_to_stage::stage_not_found
at .\crates\bevy_ecs\src\schedule\mod.rs:153
3: bevy_ecs::schedule::{{impl}}::add_system_to_stage::{{closure}}<tuple<bevy_ecs::system::function_system::IsFunctionSystem, tuple<bevy_ecs::system::commands::Commands, bevy_ecs::change_detection::ResMut<bevy_asset::assets::Assets<bevy_render::mesh::mesh::Me
at .\crates\bevy_ecs\src\schedule\mod.rs:161
4: core::option::Option<mut bevy_ecs::schedule::stage::SystemStage*>::unwrap_or_else<mut bevy_ecs::schedule::stage::SystemStage*,closure-0>
at C:\Users\scher\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\option.rs:427
5: bevy_ecs::schedule::Schedule::add_system_to_stage<tuple<bevy_ecs::system::function_system::IsFunctionSystem, tuple<bevy_ecs::system::commands::Commands, bevy_ecs::change_detection::ResMut<bevy_asset::assets::Assets<bevy_render::mesh::mesh::Mesh>>, bevy_ec
at .\crates\bevy_ecs\src\schedule\mod.rs:159
6: bevy_app::app_builder::AppBuilder::add_system_to_stage<tuple<bevy_ecs::system::function_system::IsFunctionSystem, tuple<bevy_ecs::system::commands::Commands, bevy_ecs::change_detection::ResMut<bevy_asset::assets::Assets<bevy_render::mesh::mesh::Mesh>>, be
at .\crates\bevy_app\src\app_builder.rs:196
7: 3d_scene::main
at .\examples\3d\3d_scene.rs:4
8: core::ops::function::FnOnce::call_once<fn(),tuple<>>
at C:\Users\scher\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\ops\function.rs:227
```
## Solution
- Replace the `CoreStage::Startup` Label with the new `StartupSchedule` unit type.
Resolves #2229
2022-02-08 00:03:50 +00:00
|
|
|
|
.stage(StartupSchedule, |schedule: &mut Schedule| {
|
2021-07-27 20:21:06 +00:00
|
|
|
|
schedule.add_stage_after(target, label, stage)
|
|
|
|
|
});
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// Adds a [startup stage](Self::add_default_stages) with the given `label`, immediately
|
|
|
|
|
/// before the stage labeled by `target`.
|
|
|
|
|
///
|
|
|
|
|
/// The `target` label must refer to a stage inside the startup schedule.
|
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// # Examples
|
2021-09-17 18:00:29 +00:00
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use bevy_app::prelude::*;
|
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
|
/// # let mut app = App::new();
|
|
|
|
|
/// #
|
2022-09-03 18:06:41 +00:00
|
|
|
|
/// #[derive(StageLabel)]
|
|
|
|
|
/// struct MyStartupStage;
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// app.add_startup_stage_before(
|
|
|
|
|
/// StartupStage::Startup,
|
2022-09-03 18:06:41 +00:00
|
|
|
|
/// MyStartupStage,
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// SystemStage::parallel()
|
|
|
|
|
/// );
|
|
|
|
|
/// ```
|
2021-07-27 20:21:06 +00:00
|
|
|
|
pub fn add_startup_stage_before<S: Stage>(
|
|
|
|
|
&mut self,
|
|
|
|
|
target: impl StageLabel,
|
|
|
|
|
label: impl StageLabel,
|
|
|
|
|
stage: S,
|
|
|
|
|
) -> &mut Self {
|
|
|
|
|
self.schedule
|
Move the CoreStage::Startup to a seperate StartupSchedule label (#2434)
# Objective
- `CoreStage::Startup` is unique in the `CoreStage` enum, in that it represents a `Schedule` and not a `SystemStage`.
- This can lead to confusion about how `CoreStage::Startup` and the `StartupStage` enum are related.
- Beginners sometimes try `.add_system_to_stage(CoreStage::Startup, setup.system())` instead of `.add_startup_system(setup.system())`, which causes a Panic:
```
thread 'main' panicked at 'Stage 'Startup' does not exist or is not a SystemStage', crates\bevy_ecs\src\schedule\mod.rs:153:13
stack backtrace:
0: std::panicking::begin_panic_handler
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b\/library\std\src\panicking.rs:493
1: std::panicking::begin_panic_fmt
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b\/library\std\src\panicking.rs:435
2: bevy_ecs::schedule::{{impl}}::add_system_to_stage::stage_not_found
at .\crates\bevy_ecs\src\schedule\mod.rs:153
3: bevy_ecs::schedule::{{impl}}::add_system_to_stage::{{closure}}<tuple<bevy_ecs::system::function_system::IsFunctionSystem, tuple<bevy_ecs::system::commands::Commands, bevy_ecs::change_detection::ResMut<bevy_asset::assets::Assets<bevy_render::mesh::mesh::Me
at .\crates\bevy_ecs\src\schedule\mod.rs:161
4: core::option::Option<mut bevy_ecs::schedule::stage::SystemStage*>::unwrap_or_else<mut bevy_ecs::schedule::stage::SystemStage*,closure-0>
at C:\Users\scher\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\option.rs:427
5: bevy_ecs::schedule::Schedule::add_system_to_stage<tuple<bevy_ecs::system::function_system::IsFunctionSystem, tuple<bevy_ecs::system::commands::Commands, bevy_ecs::change_detection::ResMut<bevy_asset::assets::Assets<bevy_render::mesh::mesh::Mesh>>, bevy_ec
at .\crates\bevy_ecs\src\schedule\mod.rs:159
6: bevy_app::app_builder::AppBuilder::add_system_to_stage<tuple<bevy_ecs::system::function_system::IsFunctionSystem, tuple<bevy_ecs::system::commands::Commands, bevy_ecs::change_detection::ResMut<bevy_asset::assets::Assets<bevy_render::mesh::mesh::Mesh>>, be
at .\crates\bevy_app\src\app_builder.rs:196
7: 3d_scene::main
at .\examples\3d\3d_scene.rs:4
8: core::ops::function::FnOnce::call_once<fn(),tuple<>>
at C:\Users\scher\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\ops\function.rs:227
```
## Solution
- Replace the `CoreStage::Startup` Label with the new `StartupSchedule` unit type.
Resolves #2229
2022-02-08 00:03:50 +00:00
|
|
|
|
.stage(StartupSchedule, |schedule: &mut Schedule| {
|
2021-07-27 20:21:06 +00:00
|
|
|
|
schedule.add_stage_before(target, label, stage)
|
|
|
|
|
});
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// Fetches the [`Stage`] of type `T` marked with `label` from the [`Schedule`], then
|
|
|
|
|
/// executes the provided `func` passing the fetched stage to it as an argument.
|
|
|
|
|
///
|
|
|
|
|
/// The `func` argument should be a function or a closure that accepts a mutable reference
|
|
|
|
|
/// to a struct implementing `Stage` and returns the same type. That means that it should
|
|
|
|
|
/// also assume that the stage has already been fetched successfully.
|
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// See [`stage`](Schedule::stage) for more details.
|
2021-09-17 18:00:29 +00:00
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// # Examples
|
2021-09-17 18:00:29 +00:00
|
|
|
|
///
|
|
|
|
|
/// Here the closure is used to add a system to the update stage:
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use bevy_app::prelude::*;
|
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
|
/// #
|
|
|
|
|
/// # let mut app = App::new();
|
|
|
|
|
/// # fn my_system() {}
|
|
|
|
|
/// #
|
|
|
|
|
/// app.stage(CoreStage::Update, |stage: &mut SystemStage| {
|
|
|
|
|
/// stage.add_system(my_system)
|
|
|
|
|
/// });
|
|
|
|
|
/// ```
|
2021-07-27 20:21:06 +00:00
|
|
|
|
pub fn stage<T: Stage, F: FnOnce(&mut T) -> &mut T>(
|
|
|
|
|
&mut self,
|
|
|
|
|
label: impl StageLabel,
|
|
|
|
|
func: F,
|
|
|
|
|
) -> &mut Self {
|
|
|
|
|
self.schedule.stage(label, func);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// Adds a system to the [update stage](Self::add_default_stages) of the app's [`Schedule`].
|
2021-07-27 20:21:06 +00:00
|
|
|
|
///
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// Refer to the [system module documentation](bevy_ecs::system) to see how a system
|
|
|
|
|
/// can be defined.
|
2021-07-27 20:21:06 +00:00
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// # Examples
|
2021-07-27 20:21:06 +00:00
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use bevy_app::prelude::*;
|
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
|
/// #
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// # fn my_system() {}
|
|
|
|
|
/// # let mut app = App::new();
|
|
|
|
|
/// #
|
|
|
|
|
/// app.add_system(my_system);
|
2021-07-27 20:21:06 +00:00
|
|
|
|
/// ```
|
|
|
|
|
pub fn add_system<Params>(&mut self, system: impl IntoSystemDescriptor<Params>) -> &mut Self {
|
|
|
|
|
self.add_system_to_stage(CoreStage::Update, system)
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// Adds a [`SystemSet`] to the [update stage](Self::add_default_stages).
|
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// # Examples
|
2021-09-17 18:00:29 +00:00
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use bevy_app::prelude::*;
|
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
|
/// #
|
|
|
|
|
/// # let mut app = App::new();
|
|
|
|
|
/// # fn system_a() {}
|
|
|
|
|
/// # fn system_b() {}
|
|
|
|
|
/// # fn system_c() {}
|
|
|
|
|
/// #
|
|
|
|
|
/// app.add_system_set(
|
|
|
|
|
/// SystemSet::new()
|
|
|
|
|
/// .with_system(system_a)
|
|
|
|
|
/// .with_system(system_b)
|
|
|
|
|
/// .with_system(system_c),
|
|
|
|
|
/// );
|
|
|
|
|
/// ```
|
2021-07-27 20:21:06 +00:00
|
|
|
|
pub fn add_system_set(&mut self, system_set: SystemSet) -> &mut Self {
|
|
|
|
|
self.add_system_set_to_stage(CoreStage::Update, system_set)
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// Adds a system to the [`Stage`] identified by `stage_label`.
|
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// # Examples
|
2021-09-17 18:00:29 +00:00
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use bevy_app::prelude::*;
|
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
|
/// #
|
|
|
|
|
/// # let mut app = App::new();
|
|
|
|
|
/// # fn my_system() {}
|
|
|
|
|
/// #
|
|
|
|
|
/// app.add_system_to_stage(CoreStage::PostUpdate, my_system);
|
|
|
|
|
/// ```
|
2021-07-27 20:21:06 +00:00
|
|
|
|
pub fn add_system_to_stage<Params>(
|
|
|
|
|
&mut self,
|
|
|
|
|
stage_label: impl StageLabel,
|
|
|
|
|
system: impl IntoSystemDescriptor<Params>,
|
|
|
|
|
) -> &mut Self {
|
2022-02-04 02:26:18 +00:00
|
|
|
|
use std::any::TypeId;
|
2022-02-13 22:33:55 +00:00
|
|
|
|
assert!(
|
|
|
|
|
stage_label.type_id() != TypeId::of::<StartupStage>(),
|
2022-09-02 12:18:44 +00:00
|
|
|
|
"use `add_startup_system_to_stage` instead of `add_system_to_stage` to add a system to a StartupStage"
|
2022-02-13 22:33:55 +00:00
|
|
|
|
);
|
2021-07-27 20:21:06 +00:00
|
|
|
|
self.schedule.add_system_to_stage(stage_label, system);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// Adds a [`SystemSet`] to the [`Stage`] identified by `stage_label`.
|
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// # Examples
|
2021-09-17 18:00:29 +00:00
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use bevy_app::prelude::*;
|
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
|
/// #
|
|
|
|
|
/// # let mut app = App::new();
|
|
|
|
|
/// # fn system_a() {}
|
|
|
|
|
/// # fn system_b() {}
|
|
|
|
|
/// # fn system_c() {}
|
|
|
|
|
/// #
|
|
|
|
|
/// app.add_system_set_to_stage(
|
|
|
|
|
/// CoreStage::PostUpdate,
|
|
|
|
|
/// SystemSet::new()
|
|
|
|
|
/// .with_system(system_a)
|
|
|
|
|
/// .with_system(system_b)
|
|
|
|
|
/// .with_system(system_c),
|
|
|
|
|
/// );
|
|
|
|
|
/// ```
|
2021-07-27 20:21:06 +00:00
|
|
|
|
pub fn add_system_set_to_stage(
|
|
|
|
|
&mut self,
|
|
|
|
|
stage_label: impl StageLabel,
|
|
|
|
|
system_set: SystemSet,
|
|
|
|
|
) -> &mut Self {
|
2022-02-04 02:26:18 +00:00
|
|
|
|
use std::any::TypeId;
|
2022-02-13 22:33:55 +00:00
|
|
|
|
assert!(
|
|
|
|
|
stage_label.type_id() != TypeId::of::<StartupStage>(),
|
2022-09-02 12:18:44 +00:00
|
|
|
|
"use `add_startup_system_set_to_stage` instead of `add_system_set_to_stage` to add system sets to a StartupStage"
|
2022-02-13 22:33:55 +00:00
|
|
|
|
);
|
2021-07-27 20:21:06 +00:00
|
|
|
|
self.schedule
|
|
|
|
|
.add_system_set_to_stage(stage_label, system_set);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// Adds a system to the [startup stage](Self::add_default_stages) of the app's [`Schedule`].
|
2021-07-27 20:21:06 +00:00
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// * For adding a system that runs every frame, see [`add_system`](Self::add_system).
|
|
|
|
|
/// * For adding a system to a specific stage, see [`add_system_to_stage`](Self::add_system_to_stage).
|
|
|
|
|
///
|
|
|
|
|
/// # Examples
|
2021-07-27 20:21:06 +00:00
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use bevy_app::prelude::*;
|
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
|
/// #
|
|
|
|
|
/// fn my_startup_system(_commands: Commands) {
|
|
|
|
|
/// println!("My startup system");
|
|
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// App::new()
|
2022-02-08 04:00:58 +00:00
|
|
|
|
/// .add_startup_system(my_startup_system);
|
2021-07-27 20:21:06 +00:00
|
|
|
|
/// ```
|
|
|
|
|
pub fn add_startup_system<Params>(
|
|
|
|
|
&mut self,
|
|
|
|
|
system: impl IntoSystemDescriptor<Params>,
|
|
|
|
|
) -> &mut Self {
|
|
|
|
|
self.add_startup_system_to_stage(StartupStage::Startup, system)
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// Adds a [`SystemSet`] to the [startup stage](Self::add_default_stages).
|
2021-09-17 18:00:29 +00:00
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// # Examples
|
2021-09-17 18:00:29 +00:00
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use bevy_app::prelude::*;
|
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
|
/// #
|
|
|
|
|
/// # let mut app = App::new();
|
|
|
|
|
/// # fn startup_system_a() {}
|
|
|
|
|
/// # fn startup_system_b() {}
|
|
|
|
|
/// # fn startup_system_c() {}
|
|
|
|
|
/// #
|
|
|
|
|
/// app.add_startup_system_set(
|
|
|
|
|
/// SystemSet::new()
|
|
|
|
|
/// .with_system(startup_system_a)
|
|
|
|
|
/// .with_system(startup_system_b)
|
|
|
|
|
/// .with_system(startup_system_c),
|
|
|
|
|
/// );
|
|
|
|
|
/// ```
|
2021-07-27 20:21:06 +00:00
|
|
|
|
pub fn add_startup_system_set(&mut self, system_set: SystemSet) -> &mut Self {
|
|
|
|
|
self.add_startup_system_set_to_stage(StartupStage::Startup, system_set)
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// Adds a system to the [startup schedule](Self::add_default_stages), in the stage
|
|
|
|
|
/// identified by `stage_label`.
|
|
|
|
|
///
|
|
|
|
|
/// `stage_label` must refer to a stage inside the startup schedule.
|
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// # Examples
|
2021-09-17 18:00:29 +00:00
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use bevy_app::prelude::*;
|
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
|
/// #
|
|
|
|
|
/// # let mut app = App::new();
|
|
|
|
|
/// # fn my_startup_system() {}
|
|
|
|
|
/// #
|
|
|
|
|
/// app.add_startup_system_to_stage(StartupStage::PreStartup, my_startup_system);
|
|
|
|
|
/// ```
|
2021-07-27 20:21:06 +00:00
|
|
|
|
pub fn add_startup_system_to_stage<Params>(
|
|
|
|
|
&mut self,
|
|
|
|
|
stage_label: impl StageLabel,
|
|
|
|
|
system: impl IntoSystemDescriptor<Params>,
|
|
|
|
|
) -> &mut Self {
|
|
|
|
|
self.schedule
|
Move the CoreStage::Startup to a seperate StartupSchedule label (#2434)
# Objective
- `CoreStage::Startup` is unique in the `CoreStage` enum, in that it represents a `Schedule` and not a `SystemStage`.
- This can lead to confusion about how `CoreStage::Startup` and the `StartupStage` enum are related.
- Beginners sometimes try `.add_system_to_stage(CoreStage::Startup, setup.system())` instead of `.add_startup_system(setup.system())`, which causes a Panic:
```
thread 'main' panicked at 'Stage 'Startup' does not exist or is not a SystemStage', crates\bevy_ecs\src\schedule\mod.rs:153:13
stack backtrace:
0: std::panicking::begin_panic_handler
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b\/library\std\src\panicking.rs:493
1: std::panicking::begin_panic_fmt
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b\/library\std\src\panicking.rs:435
2: bevy_ecs::schedule::{{impl}}::add_system_to_stage::stage_not_found
at .\crates\bevy_ecs\src\schedule\mod.rs:153
3: bevy_ecs::schedule::{{impl}}::add_system_to_stage::{{closure}}<tuple<bevy_ecs::system::function_system::IsFunctionSystem, tuple<bevy_ecs::system::commands::Commands, bevy_ecs::change_detection::ResMut<bevy_asset::assets::Assets<bevy_render::mesh::mesh::Me
at .\crates\bevy_ecs\src\schedule\mod.rs:161
4: core::option::Option<mut bevy_ecs::schedule::stage::SystemStage*>::unwrap_or_else<mut bevy_ecs::schedule::stage::SystemStage*,closure-0>
at C:\Users\scher\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\option.rs:427
5: bevy_ecs::schedule::Schedule::add_system_to_stage<tuple<bevy_ecs::system::function_system::IsFunctionSystem, tuple<bevy_ecs::system::commands::Commands, bevy_ecs::change_detection::ResMut<bevy_asset::assets::Assets<bevy_render::mesh::mesh::Mesh>>, bevy_ec
at .\crates\bevy_ecs\src\schedule\mod.rs:159
6: bevy_app::app_builder::AppBuilder::add_system_to_stage<tuple<bevy_ecs::system::function_system::IsFunctionSystem, tuple<bevy_ecs::system::commands::Commands, bevy_ecs::change_detection::ResMut<bevy_asset::assets::Assets<bevy_render::mesh::mesh::Mesh>>, be
at .\crates\bevy_app\src\app_builder.rs:196
7: 3d_scene::main
at .\examples\3d\3d_scene.rs:4
8: core::ops::function::FnOnce::call_once<fn(),tuple<>>
at C:\Users\scher\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\ops\function.rs:227
```
## Solution
- Replace the `CoreStage::Startup` Label with the new `StartupSchedule` unit type.
Resolves #2229
2022-02-08 00:03:50 +00:00
|
|
|
|
.stage(StartupSchedule, |schedule: &mut Schedule| {
|
2021-07-27 20:21:06 +00:00
|
|
|
|
schedule.add_system_to_stage(stage_label, system)
|
|
|
|
|
});
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// Adds a [`SystemSet`] to the [startup schedule](Self::add_default_stages), in the stage
|
|
|
|
|
/// identified by `stage_label`.
|
|
|
|
|
///
|
|
|
|
|
/// `stage_label` must refer to a stage inside the startup schedule.
|
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// # Examples
|
2021-09-17 18:00:29 +00:00
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use bevy_app::prelude::*;
|
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
|
/// #
|
|
|
|
|
/// # let mut app = App::new();
|
|
|
|
|
/// # fn startup_system_a() {}
|
|
|
|
|
/// # fn startup_system_b() {}
|
|
|
|
|
/// # fn startup_system_c() {}
|
|
|
|
|
/// #
|
|
|
|
|
/// app.add_startup_system_set_to_stage(
|
|
|
|
|
/// StartupStage::PreStartup,
|
|
|
|
|
/// SystemSet::new()
|
|
|
|
|
/// .with_system(startup_system_a)
|
|
|
|
|
/// .with_system(startup_system_b)
|
|
|
|
|
/// .with_system(startup_system_c),
|
|
|
|
|
/// );
|
|
|
|
|
/// ```
|
2021-07-27 20:21:06 +00:00
|
|
|
|
pub fn add_startup_system_set_to_stage(
|
|
|
|
|
&mut self,
|
|
|
|
|
stage_label: impl StageLabel,
|
|
|
|
|
system_set: SystemSet,
|
|
|
|
|
) -> &mut Self {
|
|
|
|
|
self.schedule
|
Move the CoreStage::Startup to a seperate StartupSchedule label (#2434)
# Objective
- `CoreStage::Startup` is unique in the `CoreStage` enum, in that it represents a `Schedule` and not a `SystemStage`.
- This can lead to confusion about how `CoreStage::Startup` and the `StartupStage` enum are related.
- Beginners sometimes try `.add_system_to_stage(CoreStage::Startup, setup.system())` instead of `.add_startup_system(setup.system())`, which causes a Panic:
```
thread 'main' panicked at 'Stage 'Startup' does not exist or is not a SystemStage', crates\bevy_ecs\src\schedule\mod.rs:153:13
stack backtrace:
0: std::panicking::begin_panic_handler
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b\/library\std\src\panicking.rs:493
1: std::panicking::begin_panic_fmt
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b\/library\std\src\panicking.rs:435
2: bevy_ecs::schedule::{{impl}}::add_system_to_stage::stage_not_found
at .\crates\bevy_ecs\src\schedule\mod.rs:153
3: bevy_ecs::schedule::{{impl}}::add_system_to_stage::{{closure}}<tuple<bevy_ecs::system::function_system::IsFunctionSystem, tuple<bevy_ecs::system::commands::Commands, bevy_ecs::change_detection::ResMut<bevy_asset::assets::Assets<bevy_render::mesh::mesh::Me
at .\crates\bevy_ecs\src\schedule\mod.rs:161
4: core::option::Option<mut bevy_ecs::schedule::stage::SystemStage*>::unwrap_or_else<mut bevy_ecs::schedule::stage::SystemStage*,closure-0>
at C:\Users\scher\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\option.rs:427
5: bevy_ecs::schedule::Schedule::add_system_to_stage<tuple<bevy_ecs::system::function_system::IsFunctionSystem, tuple<bevy_ecs::system::commands::Commands, bevy_ecs::change_detection::ResMut<bevy_asset::assets::Assets<bevy_render::mesh::mesh::Mesh>>, bevy_ec
at .\crates\bevy_ecs\src\schedule\mod.rs:159
6: bevy_app::app_builder::AppBuilder::add_system_to_stage<tuple<bevy_ecs::system::function_system::IsFunctionSystem, tuple<bevy_ecs::system::commands::Commands, bevy_ecs::change_detection::ResMut<bevy_asset::assets::Assets<bevy_render::mesh::mesh::Mesh>>, be
at .\crates\bevy_app\src\app_builder.rs:196
7: 3d_scene::main
at .\examples\3d\3d_scene.rs:4
8: core::ops::function::FnOnce::call_once<fn(),tuple<>>
at C:\Users\scher\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\ops\function.rs:227
```
## Solution
- Replace the `CoreStage::Startup` Label with the new `StartupSchedule` unit type.
Resolves #2229
2022-02-08 00:03:50 +00:00
|
|
|
|
.stage(StartupSchedule, |schedule: &mut Schedule| {
|
2021-07-27 20:21:06 +00:00
|
|
|
|
schedule.add_system_set_to_stage(stage_label, system_set)
|
|
|
|
|
});
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-30 09:08:19 +00:00
|
|
|
|
/// Adds a new [`State`] with the given `initial` value.
|
|
|
|
|
/// This inserts a new `State<T>` resource and adds a new "driver" to [`CoreStage::Update`].
|
2021-07-27 20:21:06 +00:00
|
|
|
|
/// Each stage that uses `State<T>` for system run criteria needs a driver. If you need to use
|
2021-12-30 09:08:19 +00:00
|
|
|
|
/// your state in a different stage, consider using [`Self::add_state_to_stage`] or manually
|
|
|
|
|
/// adding [`State::get_driver`] to additional stages you need it in.
|
2021-07-27 20:21:06 +00:00
|
|
|
|
pub fn add_state<T>(&mut self, initial: T) -> &mut Self
|
|
|
|
|
where
|
2021-10-03 19:23:44 +00:00
|
|
|
|
T: StateData,
|
2021-07-27 20:21:06 +00:00
|
|
|
|
{
|
|
|
|
|
self.add_state_to_stage(CoreStage::Update, initial)
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-30 09:08:19 +00:00
|
|
|
|
/// Adds a new [`State`] with the given `initial` value.
|
2021-07-27 20:21:06 +00:00
|
|
|
|
/// This inserts a new `State<T>` resource and adds a new "driver" to the given stage.
|
|
|
|
|
/// Each stage that uses `State<T>` for system run criteria needs a driver. If you need to use
|
2021-12-30 09:08:19 +00:00
|
|
|
|
/// your state in more than one stage, consider manually adding [`State::get_driver`] to the
|
2021-07-27 20:21:06 +00:00
|
|
|
|
/// stages you need it in.
|
|
|
|
|
pub fn add_state_to_stage<T>(&mut self, stage: impl StageLabel, initial: T) -> &mut Self
|
|
|
|
|
where
|
2021-10-03 19:23:44 +00:00
|
|
|
|
T: StateData,
|
2021-07-27 20:21:06 +00:00
|
|
|
|
{
|
|
|
|
|
self.insert_resource(State::new(initial))
|
|
|
|
|
.add_system_set_to_stage(stage, State::<T>::get_driver())
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// Adds utility stages to the [`Schedule`], giving it a standardized structure.
|
|
|
|
|
///
|
|
|
|
|
/// Adding those stages is necessary to make some core engine features work, like
|
|
|
|
|
/// adding systems without specifying a stage, or registering events. This is however
|
|
|
|
|
/// done by default by calling `App::default`, which is in turn called by
|
|
|
|
|
/// [`App::new`].
|
|
|
|
|
///
|
|
|
|
|
/// # The stages
|
|
|
|
|
///
|
|
|
|
|
/// All the added stages, with the exception of the startup stage, run every time the
|
|
|
|
|
/// schedule is invoked. The stages are the following, in order of execution:
|
2022-04-05 22:36:02 +00:00
|
|
|
|
///
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// - **First:** Runs at the very start of the schedule execution cycle, even before the
|
|
|
|
|
/// startup stage.
|
|
|
|
|
/// - **Startup:** This is actually a schedule containing sub-stages. Runs only once
|
|
|
|
|
/// when the app starts.
|
|
|
|
|
/// - **Pre-startup:** Intended for systems that need to run before other startup systems.
|
|
|
|
|
/// - **Startup:** The main startup stage. Startup systems are added here by default.
|
|
|
|
|
/// - **Post-startup:** Intended for systems that need to run after other startup systems.
|
|
|
|
|
/// - **Pre-update:** Often used by plugins to prepare their internal state before the
|
|
|
|
|
/// update stage begins.
|
|
|
|
|
/// - **Update:** Intended for user defined logic. Systems are added here by default.
|
|
|
|
|
/// - **Post-update:** Often used by plugins to finalize their internal state after the
|
|
|
|
|
/// world changes that happened during the update stage.
|
|
|
|
|
/// - **Last:** Runs right before the end of the schedule execution cycle.
|
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// The labels for those stages are defined in the [`CoreStage`] and [`StartupStage`] `enum`s.
|
2021-09-17 18:00:29 +00:00
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// # Examples
|
2021-09-17 18:00:29 +00:00
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use bevy_app::prelude::*;
|
|
|
|
|
/// #
|
|
|
|
|
/// let app = App::empty().add_default_stages();
|
|
|
|
|
/// ```
|
2021-07-27 20:21:06 +00:00
|
|
|
|
pub fn add_default_stages(&mut self) -> &mut Self {
|
|
|
|
|
self.add_stage(CoreStage::First, SystemStage::parallel())
|
|
|
|
|
.add_stage(
|
Move the CoreStage::Startup to a seperate StartupSchedule label (#2434)
# Objective
- `CoreStage::Startup` is unique in the `CoreStage` enum, in that it represents a `Schedule` and not a `SystemStage`.
- This can lead to confusion about how `CoreStage::Startup` and the `StartupStage` enum are related.
- Beginners sometimes try `.add_system_to_stage(CoreStage::Startup, setup.system())` instead of `.add_startup_system(setup.system())`, which causes a Panic:
```
thread 'main' panicked at 'Stage 'Startup' does not exist or is not a SystemStage', crates\bevy_ecs\src\schedule\mod.rs:153:13
stack backtrace:
0: std::panicking::begin_panic_handler
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b\/library\std\src\panicking.rs:493
1: std::panicking::begin_panic_fmt
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b\/library\std\src\panicking.rs:435
2: bevy_ecs::schedule::{{impl}}::add_system_to_stage::stage_not_found
at .\crates\bevy_ecs\src\schedule\mod.rs:153
3: bevy_ecs::schedule::{{impl}}::add_system_to_stage::{{closure}}<tuple<bevy_ecs::system::function_system::IsFunctionSystem, tuple<bevy_ecs::system::commands::Commands, bevy_ecs::change_detection::ResMut<bevy_asset::assets::Assets<bevy_render::mesh::mesh::Me
at .\crates\bevy_ecs\src\schedule\mod.rs:161
4: core::option::Option<mut bevy_ecs::schedule::stage::SystemStage*>::unwrap_or_else<mut bevy_ecs::schedule::stage::SystemStage*,closure-0>
at C:\Users\scher\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\option.rs:427
5: bevy_ecs::schedule::Schedule::add_system_to_stage<tuple<bevy_ecs::system::function_system::IsFunctionSystem, tuple<bevy_ecs::system::commands::Commands, bevy_ecs::change_detection::ResMut<bevy_asset::assets::Assets<bevy_render::mesh::mesh::Mesh>>, bevy_ec
at .\crates\bevy_ecs\src\schedule\mod.rs:159
6: bevy_app::app_builder::AppBuilder::add_system_to_stage<tuple<bevy_ecs::system::function_system::IsFunctionSystem, tuple<bevy_ecs::system::commands::Commands, bevy_ecs::change_detection::ResMut<bevy_asset::assets::Assets<bevy_render::mesh::mesh::Mesh>>, be
at .\crates\bevy_app\src\app_builder.rs:196
7: 3d_scene::main
at .\examples\3d\3d_scene.rs:4
8: core::ops::function::FnOnce::call_once<fn(),tuple<>>
at C:\Users\scher\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\ops\function.rs:227
```
## Solution
- Replace the `CoreStage::Startup` Label with the new `StartupSchedule` unit type.
Resolves #2229
2022-02-08 00:03:50 +00:00
|
|
|
|
StartupSchedule,
|
2021-07-27 20:21:06 +00:00
|
|
|
|
Schedule::default()
|
2022-05-04 18:41:37 +00:00
|
|
|
|
.with_run_criteria(ShouldRun::once)
|
2021-07-27 20:21:06 +00:00
|
|
|
|
.with_stage(StartupStage::PreStartup, SystemStage::parallel())
|
|
|
|
|
.with_stage(StartupStage::Startup, SystemStage::parallel())
|
|
|
|
|
.with_stage(StartupStage::PostStartup, SystemStage::parallel()),
|
|
|
|
|
)
|
|
|
|
|
.add_stage(CoreStage::PreUpdate, SystemStage::parallel())
|
|
|
|
|
.add_stage(CoreStage::Update, SystemStage::parallel())
|
|
|
|
|
.add_stage(CoreStage::PostUpdate, SystemStage::parallel())
|
|
|
|
|
.add_stage(CoreStage::Last, SystemStage::parallel())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Setup the application to manage events of type `T`.
|
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// This is done by adding a [`Resource`] of type [`Events::<T>`],
|
|
|
|
|
/// and inserting an [`update_system`](Events::update_system) into [`CoreStage::First`].
|
2021-09-17 18:00:29 +00:00
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// See [`Events`] for defining events.
|
2021-09-17 18:00:29 +00:00
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// # Examples
|
2021-09-17 18:00:29 +00:00
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use bevy_app::prelude::*;
|
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
|
/// #
|
|
|
|
|
/// # struct MyEvent;
|
|
|
|
|
/// # let mut app = App::new();
|
|
|
|
|
/// #
|
|
|
|
|
/// app.add_event::<MyEvent>();
|
|
|
|
|
/// ```
|
2021-07-27 20:21:06 +00:00
|
|
|
|
pub fn add_event<T>(&mut self) -> &mut Self
|
|
|
|
|
where
|
2022-05-09 13:19:32 +00:00
|
|
|
|
T: Event,
|
2021-07-27 20:21:06 +00:00
|
|
|
|
{
|
2022-03-20 21:54:10 +00:00
|
|
|
|
if !self.world.contains_resource::<Events<T>>() {
|
|
|
|
|
self.init_resource::<Events<T>>()
|
|
|
|
|
.add_system_to_stage(CoreStage::First, Events::<T>::update_system);
|
|
|
|
|
}
|
|
|
|
|
self
|
2021-07-27 20:21:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// Inserts a [`Resource`] to the current [`App`] and overwrites any [`Resource`] previously added of the same type.
|
2021-07-27 20:21:06 +00:00
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// A [`Resource`] in Bevy represents globally unique data. [`Resource`]s must be added to Bevy apps
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// before using them. This happens with [`insert_resource`](Self::insert_resource).
|
2021-07-27 20:21:06 +00:00
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// See [`init_resource`](Self::init_resource) for [`Resource`]s that implement [`Default`] or [`FromWorld`].
|
|
|
|
|
///
|
|
|
|
|
/// # Examples
|
2021-07-27 20:21:06 +00:00
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use bevy_app::prelude::*;
|
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>
2022-08-08 21:36:35 +00:00
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
2021-07-27 20:21:06 +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>
2022-08-08 21:36:35 +00:00
|
|
|
|
/// #[derive(Resource)]
|
2021-07-27 20:21:06 +00:00
|
|
|
|
/// struct MyCounter {
|
|
|
|
|
/// counter: usize,
|
|
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// App::new()
|
|
|
|
|
/// .insert_resource(MyCounter { counter: 0 });
|
|
|
|
|
/// ```
|
2022-02-08 23:04:19 +00:00
|
|
|
|
pub fn insert_resource<R: Resource>(&mut self, resource: R) -> &mut Self {
|
2021-07-27 20:21:06 +00:00
|
|
|
|
self.world.insert_resource(resource);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
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>
2022-08-08 21:36:35 +00:00
|
|
|
|
/// Inserts a non-send resource to the app.
|
2021-07-27 20:21:06 +00:00
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// You usually want to use [`insert_resource`](Self::insert_resource),
|
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>
2022-08-08 21:36:35 +00:00
|
|
|
|
/// but there are some special cases when a resource cannot be sent across threads.
|
2022-04-05 22:36:02 +00:00
|
|
|
|
///
|
|
|
|
|
/// # Examples
|
2021-07-27 20:21:06 +00:00
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use bevy_app::prelude::*;
|
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>
2022-08-08 21:36:35 +00:00
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
2021-07-27 20:21:06 +00:00
|
|
|
|
/// #
|
|
|
|
|
/// struct MyCounter {
|
|
|
|
|
/// counter: usize,
|
|
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// App::new()
|
|
|
|
|
/// .insert_non_send_resource(MyCounter { counter: 0 });
|
|
|
|
|
/// ```
|
2022-02-08 23:04:19 +00:00
|
|
|
|
pub fn insert_non_send_resource<R: 'static>(&mut self, resource: R) -> &mut Self {
|
|
|
|
|
self.world.insert_non_send_resource(resource);
|
2021-07-27 20:21:06 +00:00
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// Initialize a [`Resource`] with standard starting values by adding it to the [`World`].
|
|
|
|
|
///
|
|
|
|
|
/// If the [`Resource`] already exists, nothing happens.
|
2021-09-17 18:00:29 +00:00
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// The [`Resource`] must implement the [`FromWorld`] trait.
|
|
|
|
|
/// If the [`Default`] trait is implemented, the [`FromWorld`] trait will use
|
|
|
|
|
/// the [`Default::default`] method to initialize the [`Resource`].
|
2021-07-27 20:21:06 +00:00
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// # Examples
|
2021-07-27 20:21:06 +00:00
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use bevy_app::prelude::*;
|
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>
2022-08-08 21:36:35 +00:00
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
2021-07-27 20:21:06 +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>
2022-08-08 21:36:35 +00:00
|
|
|
|
/// #[derive(Resource)]
|
2021-07-27 20:21:06 +00:00
|
|
|
|
/// struct MyCounter {
|
|
|
|
|
/// counter: usize,
|
|
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// impl Default for MyCounter {
|
|
|
|
|
/// fn default() -> MyCounter {
|
|
|
|
|
/// MyCounter {
|
|
|
|
|
/// counter: 100
|
|
|
|
|
/// }
|
|
|
|
|
/// }
|
|
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// App::new()
|
|
|
|
|
/// .init_resource::<MyCounter>();
|
|
|
|
|
/// ```
|
2022-02-08 23:04:19 +00:00
|
|
|
|
pub fn init_resource<R: Resource + FromWorld>(&mut self) -> &mut Self {
|
|
|
|
|
self.world.init_resource::<R>();
|
2021-07-27 20:21:06 +00:00
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// Initialize a non-send [`Resource`] with standard starting values by adding it to the [`World`].
|
2021-09-17 18:00:29 +00:00
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// The [`Resource`] must implement the [`FromWorld`] trait.
|
|
|
|
|
/// If the [`Default`] trait is implemented, the [`FromWorld`] trait will use
|
|
|
|
|
/// the [`Default::default`] method to initialize the [`Resource`].
|
2022-02-08 23:04:19 +00:00
|
|
|
|
pub fn init_non_send_resource<R: 'static + FromWorld>(&mut self) -> &mut Self {
|
|
|
|
|
self.world.init_non_send_resource::<R>();
|
2021-07-27 20:21:06 +00:00
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// Sets the function that will be called when the app is run.
|
2021-07-27 20:21:06 +00:00
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// The runner function `run_fn` is called only once by [`App::run`]. If the
|
|
|
|
|
/// presence of a main loop in the app is desired, it is the responsibility of the runner
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// function to provide it.
|
2021-07-27 20:21:06 +00:00
|
|
|
|
///
|
2021-09-17 18:00:29 +00:00
|
|
|
|
/// The runner function is usually not set manually, but by Bevy integrated plugins
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// (e.g. `WinitPlugin`).
|
|
|
|
|
///
|
|
|
|
|
/// # Examples
|
2021-07-27 20:21:06 +00:00
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use bevy_app::prelude::*;
|
|
|
|
|
/// #
|
|
|
|
|
/// fn my_runner(mut app: App) {
|
|
|
|
|
/// loop {
|
|
|
|
|
/// println!("In main loop");
|
|
|
|
|
/// app.update();
|
|
|
|
|
/// }
|
|
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// App::new()
|
|
|
|
|
/// .set_runner(my_runner);
|
|
|
|
|
/// ```
|
|
|
|
|
pub fn set_runner(&mut self, run_fn: impl Fn(App) + 'static) -> &mut Self {
|
|
|
|
|
self.runner = Box::new(run_fn);
|
|
|
|
|
self
|
2020-04-06 03:19:02 +00:00
|
|
|
|
}
|
2021-07-27 20:21:06 +00:00
|
|
|
|
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// Adds a single [`Plugin`].
|
2021-07-27 20:21:06 +00:00
|
|
|
|
///
|
|
|
|
|
/// One of Bevy's core principles is modularity. All Bevy engine features are implemented
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// as [`Plugin`]s. This includes internal features like the renderer.
|
|
|
|
|
///
|
|
|
|
|
/// Bevy also provides a few sets of default [`Plugin`]s. See [`add_plugins`](Self::add_plugins).
|
2021-07-27 20:21:06 +00:00
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// # Examples
|
2021-07-27 20:21:06 +00:00
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use bevy_app::prelude::*;
|
|
|
|
|
/// #
|
2022-07-04 13:04:18 +00:00
|
|
|
|
/// # // Dummies created to avoid using `bevy_log`,
|
|
|
|
|
/// # // which pulls in too many dependencies and breaks rust-analyzer
|
|
|
|
|
/// # pub mod bevy_log {
|
|
|
|
|
/// # use bevy_app::prelude::*;
|
|
|
|
|
/// # #[derive(Default)]
|
|
|
|
|
/// # pub struct LogPlugin;
|
|
|
|
|
/// # impl Plugin for LogPlugin{
|
|
|
|
|
/// # fn build(&self, app: &mut App) {}
|
|
|
|
|
/// # }
|
|
|
|
|
/// # }
|
2021-07-27 20:21:06 +00:00
|
|
|
|
/// App::new().add_plugin(bevy_log::LogPlugin::default());
|
|
|
|
|
/// ```
|
2022-10-31 16:12:19 +00:00
|
|
|
|
///
|
|
|
|
|
/// # Panics
|
|
|
|
|
///
|
|
|
|
|
/// Panics if the plugin was already added to the application.
|
2021-07-27 20:21:06 +00:00
|
|
|
|
pub fn add_plugin<T>(&mut self, plugin: T) -> &mut Self
|
|
|
|
|
where
|
|
|
|
|
T: Plugin,
|
|
|
|
|
{
|
2022-10-31 16:12:19 +00:00
|
|
|
|
match self.add_boxed_plugin(Box::new(plugin)) {
|
|
|
|
|
Ok(app) => app,
|
|
|
|
|
Err(AppError::DuplicatePlugin { plugin_name }) => panic!(
|
2023-01-11 09:51:22 +00:00
|
|
|
|
"Error adding plugin {plugin_name}: : plugin was already added in application"
|
2022-10-31 16:12:19 +00:00
|
|
|
|
),
|
|
|
|
|
}
|
2022-10-26 17:52:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Boxed variant of `add_plugin`, can be used from a [`PluginGroup`]
|
2022-10-31 16:12:19 +00:00
|
|
|
|
pub(crate) fn add_boxed_plugin(
|
|
|
|
|
&mut self,
|
|
|
|
|
plugin: Box<dyn Plugin>,
|
|
|
|
|
) -> Result<&mut Self, AppError> {
|
2021-07-27 20:21:06 +00:00
|
|
|
|
debug!("added plugin: {}", plugin.name());
|
2022-10-31 16:12:19 +00:00
|
|
|
|
if plugin.is_unique() && !self.plugin_name_added.insert(plugin.name().to_string()) {
|
|
|
|
|
Err(AppError::DuplicatePlugin {
|
|
|
|
|
plugin_name: plugin.name().to_string(),
|
|
|
|
|
})?;
|
|
|
|
|
}
|
2022-12-24 23:43:41 +00:00
|
|
|
|
self.is_building_plugin = true;
|
2021-07-27 20:21:06 +00:00
|
|
|
|
plugin.build(self);
|
2022-12-24 23:43:41 +00:00
|
|
|
|
self.is_building_plugin = false;
|
2022-10-26 17:52:16 +00:00
|
|
|
|
self.plugin_registry.push(plugin);
|
2022-10-31 16:12:19 +00:00
|
|
|
|
Ok(self)
|
2021-07-27 20:21:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-26 17:52:16 +00:00
|
|
|
|
/// Checks if a [`Plugin`] has already been added.
|
|
|
|
|
///
|
|
|
|
|
/// This can be used by plugins to check if a plugin they depend upon has already been
|
|
|
|
|
/// added.
|
|
|
|
|
pub fn is_plugin_added<T>(&self) -> bool
|
|
|
|
|
where
|
|
|
|
|
T: Plugin,
|
|
|
|
|
{
|
|
|
|
|
self.plugin_registry
|
|
|
|
|
.iter()
|
|
|
|
|
.any(|p| p.downcast_ref::<T>().is_some())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns a vector of references to any plugins of type `T` that have been added.
|
|
|
|
|
///
|
|
|
|
|
/// This can be used to read the settings of any already added plugins.
|
|
|
|
|
/// This vector will be length zero if no plugins of that type have been added.
|
|
|
|
|
/// If multiple copies of the same plugin are added to the [`App`], they will be listed in insertion order in this vector.
|
|
|
|
|
///
|
|
|
|
|
/// ```rust
|
|
|
|
|
/// # use bevy_app::prelude::*;
|
|
|
|
|
/// # #[derive(Default)]
|
|
|
|
|
/// # struct ImagePlugin {
|
|
|
|
|
/// # default_sampler: bool,
|
|
|
|
|
/// # }
|
|
|
|
|
/// # impl Plugin for ImagePlugin {
|
|
|
|
|
/// # fn build(&self, app: &mut App) {}
|
|
|
|
|
/// # }
|
|
|
|
|
/// # let mut app = App::new();
|
|
|
|
|
/// # app.add_plugin(ImagePlugin::default());
|
|
|
|
|
/// let default_sampler = app.get_added_plugins::<ImagePlugin>()[0].default_sampler;
|
|
|
|
|
/// ```
|
|
|
|
|
pub fn get_added_plugins<T>(&self) -> Vec<&T>
|
|
|
|
|
where
|
|
|
|
|
T: Plugin,
|
|
|
|
|
{
|
|
|
|
|
self.plugin_registry
|
|
|
|
|
.iter()
|
|
|
|
|
.filter_map(|p| p.downcast_ref())
|
|
|
|
|
.collect()
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// Adds a group of [`Plugin`]s.
|
2021-07-27 20:21:06 +00:00
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// [`Plugin`]s can be grouped into a set by using a [`PluginGroup`].
|
2021-07-27 20:21:06 +00:00
|
|
|
|
///
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// There are built-in [`PluginGroup`]s that provide core engine functionality.
|
|
|
|
|
/// The [`PluginGroup`]s available by default are `DefaultPlugins` and `MinimalPlugins`.
|
|
|
|
|
///
|
2022-05-09 13:06:22 +00:00
|
|
|
|
/// To customize the plugins in the group (reorder, disable a plugin, add a new plugin
|
Plugins own their settings. Rework PluginGroup trait. (#6336)
# Objective
Fixes #5884 #2879
Alternative to #2988 #5885 #2886
"Immutable" Plugin settings are currently represented as normal ECS resources, which are read as part of plugin init. This presents a number of problems:
1. If a user inserts the plugin settings resource after the plugin is initialized, it will be silently ignored (and use the defaults instead)
2. Users can modify the plugin settings resource after the plugin has been initialized. This creates a false sense of control over settings that can no longer be changed.
(1) and (2) are especially problematic and confusing for the `WindowDescriptor` resource, but this is a general problem.
## Solution
Immutable Plugin settings now live on each Plugin struct (ex: `WindowPlugin`). PluginGroups have been reworked to support overriding plugin values. This also removes the need for the `add_plugins_with` api, as the `add_plugins` api can use the builder pattern directly. Settings that can be used at runtime continue to be represented as ECS resources.
Plugins are now configured like this:
```rust
app.add_plugin(AssetPlugin {
watch_for_changes: true,
..default()
})
```
PluginGroups are now configured like this:
```rust
app.add_plugins(DefaultPlugins
.set(AssetPlugin {
watch_for_changes: true,
..default()
})
)
```
This is an alternative to #2988, which is similar. But I personally prefer this solution for a couple of reasons:
* ~~#2988 doesn't solve (1)~~ #2988 does solve (1) and will panic in that case. I was wrong!
* This PR directly ties plugin settings to Plugin types in a 1:1 relationship, rather than a loose "setup resource" <-> plugin coupling (where the setup resource is consumed by the first plugin that uses it).
* I'm not a huge fan of overloading the ECS resource concept and implementation for something that has very different use cases and constraints.
## Changelog
- PluginGroups can now be configured directly using the builder pattern. Individual plugin values can be overridden by using `plugin_group.set(SomePlugin {})`, which enables overriding default plugin values.
- `WindowDescriptor` plugin settings have been moved to `WindowPlugin` and `AssetServerSettings` have been moved to `AssetPlugin`
- `app.add_plugins_with` has been replaced by using `add_plugins` with the builder pattern.
## Migration Guide
The `WindowDescriptor` settings have been moved from a resource to `WindowPlugin::window`:
```rust
// Old (Bevy 0.8)
app
.insert_resource(WindowDescriptor {
width: 400.0,
..default()
})
.add_plugins(DefaultPlugins)
// New (Bevy 0.9)
app.add_plugins(DefaultPlugins.set(WindowPlugin {
window: WindowDescriptor {
width: 400.0,
..default()
},
..default()
}))
```
The `AssetServerSettings` resource has been removed in favor of direct `AssetPlugin` configuration:
```rust
// Old (Bevy 0.8)
app
.insert_resource(AssetServerSettings {
watch_for_changes: true,
..default()
})
.add_plugins(DefaultPlugins)
// New (Bevy 0.9)
app.add_plugins(DefaultPlugins.set(AssetPlugin {
watch_for_changes: true,
..default()
}))
```
`add_plugins_with` has been replaced by `add_plugins` in combination with the builder pattern:
```rust
// Old (Bevy 0.8)
app.add_plugins_with(DefaultPlugins, |group| group.disable::<AssetPlugin>());
// New (Bevy 0.9)
app.add_plugins(DefaultPlugins.build().disable::<AssetPlugin>());
```
2022-10-24 21:20:33 +00:00
|
|
|
|
/// before / after another plugin), call [`build()`](PluginGroup::build) on the group,
|
|
|
|
|
/// which will convert it to a [`PluginGroupBuilder`](crate::PluginGroupBuilder).
|
2021-07-27 20:21:06 +00:00
|
|
|
|
///
|
2022-05-09 13:06:22 +00:00
|
|
|
|
/// ## Examples
|
2021-07-27 20:21:06 +00:00
|
|
|
|
/// ```
|
2022-07-04 13:04:18 +00:00
|
|
|
|
/// # use bevy_app::{prelude::*, PluginGroupBuilder, NoopPluginGroup as MinimalPlugins};
|
2021-07-27 20:21:06 +00:00
|
|
|
|
/// #
|
|
|
|
|
/// App::new()
|
|
|
|
|
/// .add_plugins(MinimalPlugins);
|
|
|
|
|
/// ```
|
2022-10-31 16:12:19 +00:00
|
|
|
|
///
|
|
|
|
|
/// # Panics
|
|
|
|
|
///
|
|
|
|
|
/// Panics if one of the plugin in the group was already added to the application.
|
Plugins own their settings. Rework PluginGroup trait. (#6336)
# Objective
Fixes #5884 #2879
Alternative to #2988 #5885 #2886
"Immutable" Plugin settings are currently represented as normal ECS resources, which are read as part of plugin init. This presents a number of problems:
1. If a user inserts the plugin settings resource after the plugin is initialized, it will be silently ignored (and use the defaults instead)
2. Users can modify the plugin settings resource after the plugin has been initialized. This creates a false sense of control over settings that can no longer be changed.
(1) and (2) are especially problematic and confusing for the `WindowDescriptor` resource, but this is a general problem.
## Solution
Immutable Plugin settings now live on each Plugin struct (ex: `WindowPlugin`). PluginGroups have been reworked to support overriding plugin values. This also removes the need for the `add_plugins_with` api, as the `add_plugins` api can use the builder pattern directly. Settings that can be used at runtime continue to be represented as ECS resources.
Plugins are now configured like this:
```rust
app.add_plugin(AssetPlugin {
watch_for_changes: true,
..default()
})
```
PluginGroups are now configured like this:
```rust
app.add_plugins(DefaultPlugins
.set(AssetPlugin {
watch_for_changes: true,
..default()
})
)
```
This is an alternative to #2988, which is similar. But I personally prefer this solution for a couple of reasons:
* ~~#2988 doesn't solve (1)~~ #2988 does solve (1) and will panic in that case. I was wrong!
* This PR directly ties plugin settings to Plugin types in a 1:1 relationship, rather than a loose "setup resource" <-> plugin coupling (where the setup resource is consumed by the first plugin that uses it).
* I'm not a huge fan of overloading the ECS resource concept and implementation for something that has very different use cases and constraints.
## Changelog
- PluginGroups can now be configured directly using the builder pattern. Individual plugin values can be overridden by using `plugin_group.set(SomePlugin {})`, which enables overriding default plugin values.
- `WindowDescriptor` plugin settings have been moved to `WindowPlugin` and `AssetServerSettings` have been moved to `AssetPlugin`
- `app.add_plugins_with` has been replaced by using `add_plugins` with the builder pattern.
## Migration Guide
The `WindowDescriptor` settings have been moved from a resource to `WindowPlugin::window`:
```rust
// Old (Bevy 0.8)
app
.insert_resource(WindowDescriptor {
width: 400.0,
..default()
})
.add_plugins(DefaultPlugins)
// New (Bevy 0.9)
app.add_plugins(DefaultPlugins.set(WindowPlugin {
window: WindowDescriptor {
width: 400.0,
..default()
},
..default()
}))
```
The `AssetServerSettings` resource has been removed in favor of direct `AssetPlugin` configuration:
```rust
// Old (Bevy 0.8)
app
.insert_resource(AssetServerSettings {
watch_for_changes: true,
..default()
})
.add_plugins(DefaultPlugins)
// New (Bevy 0.9)
app.add_plugins(DefaultPlugins.set(AssetPlugin {
watch_for_changes: true,
..default()
}))
```
`add_plugins_with` has been replaced by `add_plugins` in combination with the builder pattern:
```rust
// Old (Bevy 0.8)
app.add_plugins_with(DefaultPlugins, |group| group.disable::<AssetPlugin>());
// New (Bevy 0.9)
app.add_plugins(DefaultPlugins.build().disable::<AssetPlugin>());
```
2022-10-24 21:20:33 +00:00
|
|
|
|
pub fn add_plugins<T: PluginGroup>(&mut self, group: T) -> &mut Self {
|
|
|
|
|
let builder = group.build();
|
|
|
|
|
builder.finish(self);
|
2021-07-27 20:21:06 +00:00
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
remove blanket `Serialize + Deserialize` requirement for `Reflect` on generic types (#5197)
# Objective
Some generic types like `Option<T>`, `Vec<T>` and `HashMap<K, V>` implement `Reflect` when where their generic types `T`/`K`/`V` implement `Serialize + for<'de> Deserialize<'de>`.
This is so that in their `GetTypeRegistration` impl they can insert the `ReflectSerialize` and `ReflectDeserialize` type data structs.
This has the annoying side effect that if your struct contains a `Option<NonSerdeStruct>` you won't be able to derive reflect (https://github.com/bevyengine/bevy/issues/4054).
## Solution
- remove the `Serialize + Deserialize` bounds on wrapper types
- this means that `ReflectSerialize` and `ReflectDeserialize` will no longer be inserted even for `.register::<Option<DoesImplSerde>>()`
- add `register_type_data<T, D>` shorthand for `registry.get_mut(T).insert(D::from_type<T>())`
- require users to register their specific generic types **and the serde types** separately like
```rust
.register_type::<Option<String>>()
.register_type_data::<Option<String>, ReflectSerialize>()
.register_type_data::<Option<String>, ReflectDeserialize>()
```
I believe this is the best we can do for extensibility and convenience without specialization.
## Changelog
- `.register_type` for generic types like `Option<T>`, `Vec<T>`, `HashMap<K, V>` will no longer insert `ReflectSerialize` and `ReflectDeserialize` type data. Instead you need to register it separately for concrete generic types like so:
```rust
.register_type::<Option<String>>()
.register_type_data::<Option<String>, ReflectSerialize>()
.register_type_data::<Option<String>, ReflectDeserialize>()
```
TODO: more docs and tweaks to the scene example to demonstrate registering generic types.
2022-07-21 14:57:37 +00:00
|
|
|
|
/// Registers the type `T` in the [`TypeRegistry`](bevy_reflect::TypeRegistry) resource,
|
|
|
|
|
/// adding reflect data as specified in the [`Reflect`](bevy_reflect::Reflect) derive:
|
|
|
|
|
/// ```rust,ignore
|
|
|
|
|
/// #[derive(Reflect)]
|
|
|
|
|
/// #[reflect(Component, Serialize, Deserialize)] // will register ReflectComponent, ReflectSerialize, ReflectDeserialize
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// See [`bevy_reflect::TypeRegistry::register`].
|
2021-07-27 20:21:06 +00:00
|
|
|
|
#[cfg(feature = "bevy_reflect")]
|
|
|
|
|
pub fn register_type<T: bevy_reflect::GetTypeRegistration>(&mut self) -> &mut Self {
|
|
|
|
|
{
|
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>
2022-08-08 21:36:35 +00:00
|
|
|
|
let registry = self.world.resource_mut::<AppTypeRegistry>();
|
2021-07-27 20:21:06 +00:00
|
|
|
|
registry.write().register::<T>();
|
|
|
|
|
}
|
|
|
|
|
self
|
|
|
|
|
}
|
2021-04-11 20:13:07 +00:00
|
|
|
|
|
remove blanket `Serialize + Deserialize` requirement for `Reflect` on generic types (#5197)
# Objective
Some generic types like `Option<T>`, `Vec<T>` and `HashMap<K, V>` implement `Reflect` when where their generic types `T`/`K`/`V` implement `Serialize + for<'de> Deserialize<'de>`.
This is so that in their `GetTypeRegistration` impl they can insert the `ReflectSerialize` and `ReflectDeserialize` type data structs.
This has the annoying side effect that if your struct contains a `Option<NonSerdeStruct>` you won't be able to derive reflect (https://github.com/bevyengine/bevy/issues/4054).
## Solution
- remove the `Serialize + Deserialize` bounds on wrapper types
- this means that `ReflectSerialize` and `ReflectDeserialize` will no longer be inserted even for `.register::<Option<DoesImplSerde>>()`
- add `register_type_data<T, D>` shorthand for `registry.get_mut(T).insert(D::from_type<T>())`
- require users to register their specific generic types **and the serde types** separately like
```rust
.register_type::<Option<String>>()
.register_type_data::<Option<String>, ReflectSerialize>()
.register_type_data::<Option<String>, ReflectDeserialize>()
```
I believe this is the best we can do for extensibility and convenience without specialization.
## Changelog
- `.register_type` for generic types like `Option<T>`, `Vec<T>`, `HashMap<K, V>` will no longer insert `ReflectSerialize` and `ReflectDeserialize` type data. Instead you need to register it separately for concrete generic types like so:
```rust
.register_type::<Option<String>>()
.register_type_data::<Option<String>, ReflectSerialize>()
.register_type_data::<Option<String>, ReflectDeserialize>()
```
TODO: more docs and tweaks to the scene example to demonstrate registering generic types.
2022-07-21 14:57:37 +00:00
|
|
|
|
/// Adds the type data `D` to type `T` in the [`TypeRegistry`](bevy_reflect::TypeRegistry) resource.
|
|
|
|
|
///
|
|
|
|
|
/// Most of the time [`App::register_type`] can be used instead to register a type you derived [`Reflect`](bevy_reflect::Reflect) for.
|
|
|
|
|
/// However, in cases where you want to add a piece of type data that was not included in the list of `#[reflect(...)]` type data in the derive,
|
|
|
|
|
/// or where the type is generic and cannot register e.g. `ReflectSerialize` unconditionally without knowing the specific type parameters,
|
|
|
|
|
/// this method can be used to insert additional type data.
|
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
/// ```rust
|
|
|
|
|
/// use bevy_app::App;
|
|
|
|
|
/// use bevy_reflect::{ReflectSerialize, ReflectDeserialize};
|
|
|
|
|
///
|
|
|
|
|
/// App::new()
|
|
|
|
|
/// .register_type::<Option<String>>()
|
|
|
|
|
/// .register_type_data::<Option<String>, ReflectSerialize>()
|
|
|
|
|
/// .register_type_data::<Option<String>, ReflectDeserialize>();
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// See [`bevy_reflect::TypeRegistry::register_type_data`].
|
|
|
|
|
#[cfg(feature = "bevy_reflect")]
|
|
|
|
|
pub fn register_type_data<
|
|
|
|
|
T: bevy_reflect::Reflect + 'static,
|
|
|
|
|
D: bevy_reflect::TypeData + bevy_reflect::FromType<T>,
|
|
|
|
|
>(
|
|
|
|
|
&mut self,
|
|
|
|
|
) -> &mut Self {
|
|
|
|
|
{
|
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>
2022-08-08 21:36:35 +00:00
|
|
|
|
let registry = self.world.resource_mut::<AppTypeRegistry>();
|
remove blanket `Serialize + Deserialize` requirement for `Reflect` on generic types (#5197)
# Objective
Some generic types like `Option<T>`, `Vec<T>` and `HashMap<K, V>` implement `Reflect` when where their generic types `T`/`K`/`V` implement `Serialize + for<'de> Deserialize<'de>`.
This is so that in their `GetTypeRegistration` impl they can insert the `ReflectSerialize` and `ReflectDeserialize` type data structs.
This has the annoying side effect that if your struct contains a `Option<NonSerdeStruct>` you won't be able to derive reflect (https://github.com/bevyengine/bevy/issues/4054).
## Solution
- remove the `Serialize + Deserialize` bounds on wrapper types
- this means that `ReflectSerialize` and `ReflectDeserialize` will no longer be inserted even for `.register::<Option<DoesImplSerde>>()`
- add `register_type_data<T, D>` shorthand for `registry.get_mut(T).insert(D::from_type<T>())`
- require users to register their specific generic types **and the serde types** separately like
```rust
.register_type::<Option<String>>()
.register_type_data::<Option<String>, ReflectSerialize>()
.register_type_data::<Option<String>, ReflectDeserialize>()
```
I believe this is the best we can do for extensibility and convenience without specialization.
## Changelog
- `.register_type` for generic types like `Option<T>`, `Vec<T>`, `HashMap<K, V>` will no longer insert `ReflectSerialize` and `ReflectDeserialize` type data. Instead you need to register it separately for concrete generic types like so:
```rust
.register_type::<Option<String>>()
.register_type_data::<Option<String>, ReflectSerialize>()
.register_type_data::<Option<String>, ReflectDeserialize>()
```
TODO: more docs and tweaks to the scene example to demonstrate registering generic types.
2022-07-21 14:57:37 +00:00
|
|
|
|
registry.write().register_type_data::<T, D>();
|
|
|
|
|
}
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// Adds an [`App`] as a child of the current one.
|
2022-01-06 23:16:47 +00:00
|
|
|
|
///
|
2023-01-09 21:43:29 +00:00
|
|
|
|
/// The provided function `sub_app_runner` is called by the [`update`](Self::update) method. The [`World`]
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// parameter represents the main app world, while the [`App`] parameter is just a mutable
|
|
|
|
|
/// reference to the `SubApp` itself.
|
2021-04-11 20:13:07 +00:00
|
|
|
|
pub fn add_sub_app(
|
|
|
|
|
&mut self,
|
2021-08-24 06:37:28 +00:00
|
|
|
|
label: impl AppLabel,
|
Add global init and get accessors for all newtyped TaskPools (#2250)
Right now, a direct reference to the target TaskPool is required to launch tasks on the pools, despite the three newtyped pools (AsyncComputeTaskPool, ComputeTaskPool, and IoTaskPool) effectively acting as global instances. The need to pass a TaskPool reference adds notable friction to spawning subtasks within existing tasks. Possible use cases for this may include chaining tasks within the same pool like spawning separate send/receive I/O tasks after waiting on a network connection to be established, or allowing cross-pool dependent tasks like starting dependent multi-frame computations following a long I/O load.
Other task execution runtimes provide static access to spawning tasks (i.e. `tokio::spawn`), which is notably easier to use than the reference passing required by `bevy_tasks` right now.
This PR makes does the following:
* Adds `*TaskPool::init` which initializes a `OnceCell`'ed with a provided TaskPool. Failing if the pool has already been initialized.
* Adds `*TaskPool::get` which fetches the initialized global pool of the respective type or panics. This generally should not be an issue in normal Bevy use, as the pools are initialized before they are accessed.
* Updated default task pool initialization to either pull the global handles and save them as resources, or if they are already initialized, pull the a cloned global handle as the resource.
This should make it notably easier to build more complex task hierarchies for dependent tasks. It should also make writing bevy-adjacent, but not strictly bevy-only plugin crates easier, as the global pools ensure it's all running on the same threads.
One alternative considered is keeping a thread-local reference to the pool for all threads in each pool to enable the same `tokio::spawn` interface. This would spawn tasks on the same pool that a task is currently running in. However this potentially leads to potential footgun situations where long running blocking tasks run on `ComputeTaskPool`.
2022-06-09 02:43:24 +00:00
|
|
|
|
app: App,
|
Separate Extract from Sub App Schedule (#7046)
# Objective
- This pulls out some of the changes to Plugin setup and sub apps from #6503 to make that PR easier to review.
- Separate the extract stage from running the sub app's schedule to allow for them to be run on separate threads in the future
- Fixes #6990
## Solution
- add a run method to `SubApp` that runs the schedule
- change the name of `sub_app_runner` to extract to make it clear that this function is only for extracting data between the main app and the sub app
- remove the extract stage from the sub app schedule so it can be run separately. This is done by adding a `setup` method to the `Plugin` trait that runs after all plugin build methods run. This is required to allow the extract stage to be removed from the schedule after all the plugins have added their systems to the stage. We will also need the setup method for pipelined rendering to setup the render thread. See https://github.com/bevyengine/bevy/blob/e3267965e15f14be18eec942dcaf16807144eb05/crates/bevy_render/src/pipelined_rendering.rs#L57-L98
## Changelog
- Separate SubApp Extract stage from running the sub app schedule.
## Migration Guide
### SubApp `runner` has conceptually been changed to an `extract` function.
The `runner` no longer is in charge of running the sub app schedule. It's only concern is now moving data between the main world and the sub app. The `sub_app.app.schedule` is now run for you after the provided function is called.
```rust
// before
fn main() {
let sub_app = App::empty();
sub_app.add_stage(MyStage, SystemStage::parallel());
App::new().add_sub_app(MySubApp, sub_app, move |main_world, sub_app| {
extract(app_world, render_app);
render_app.app.schedule.run();
});
}
// after
fn main() {
let sub_app = App::empty();
sub_app.add_stage(MyStage, SystemStage::parallel());
App::new().add_sub_app(MySubApp, sub_app, move |main_world, sub_app| {
extract(app_world, render_app);
// schedule is automatically called for you after extract is run
});
}
```
2023-01-09 19:24:54 +00:00
|
|
|
|
extract: impl Fn(&mut World, &mut App) + 'static,
|
2021-04-11 20:13:07 +00:00
|
|
|
|
) -> &mut Self {
|
2021-08-24 00:31:21 +00:00
|
|
|
|
self.sub_apps.insert(
|
Simplify design for `*Label`s (#4957)
# Objective
- Closes #4954
- Reduce the complexity of the `{System, App, *}Label` APIs.
## Solution
For the sake of brevity I will only refer to `SystemLabel`, but everything applies to all of the other label types as well.
- Add `SystemLabelId`, a lightweight, `copy` struct.
- Convert custom types into `SystemLabelId` using the trait `SystemLabel`.
## Changelog
- String literals implement `SystemLabel` for now, but this should be changed with #4409 .
## Migration Guide
- Any previous use of `Box<dyn SystemLabel>` should be replaced with `SystemLabelId`.
- `AsSystemLabel` trait has been modified.
- No more output generics.
- Method `as_system_label` now returns `SystemLabelId`, removing an unnecessary level of indirection.
- If you *need* a label that is determined at runtime, you can use `Box::leak`. Not recommended.
## Questions for later
* Should we generate a `Debug` impl along with `#[derive(*Label)]`?
* Should we rename `as_str()`?
* Should we remove the extra derives (such as `Hash`) from builtin `*Label` types?
* Should we automatically derive types like `Clone, Copy, PartialEq, Eq`?
* More-ergonomic comparisons between `Label` and `LabelId`.
* Move `Dyn{Eq, Hash,Clone}` somewhere else.
* Some API to make interning dynamic labels easier.
* Optimize string representation
* Empty string for unit structs -- no debug info but faster comparisons
* Don't show enum types -- same tradeoffs as asbove.
2022-07-14 18:23:01 +00:00
|
|
|
|
label.as_label(),
|
2021-08-24 00:31:21 +00:00
|
|
|
|
SubApp {
|
|
|
|
|
app,
|
Separate Extract from Sub App Schedule (#7046)
# Objective
- This pulls out some of the changes to Plugin setup and sub apps from #6503 to make that PR easier to review.
- Separate the extract stage from running the sub app's schedule to allow for them to be run on separate threads in the future
- Fixes #6990
## Solution
- add a run method to `SubApp` that runs the schedule
- change the name of `sub_app_runner` to extract to make it clear that this function is only for extracting data between the main app and the sub app
- remove the extract stage from the sub app schedule so it can be run separately. This is done by adding a `setup` method to the `Plugin` trait that runs after all plugin build methods run. This is required to allow the extract stage to be removed from the schedule after all the plugins have added their systems to the stage. We will also need the setup method for pipelined rendering to setup the render thread. See https://github.com/bevyengine/bevy/blob/e3267965e15f14be18eec942dcaf16807144eb05/crates/bevy_render/src/pipelined_rendering.rs#L57-L98
## Changelog
- Separate SubApp Extract stage from running the sub app schedule.
## Migration Guide
### SubApp `runner` has conceptually been changed to an `extract` function.
The `runner` no longer is in charge of running the sub app schedule. It's only concern is now moving data between the main world and the sub app. The `sub_app.app.schedule` is now run for you after the provided function is called.
```rust
// before
fn main() {
let sub_app = App::empty();
sub_app.add_stage(MyStage, SystemStage::parallel());
App::new().add_sub_app(MySubApp, sub_app, move |main_world, sub_app| {
extract(app_world, render_app);
render_app.app.schedule.run();
});
}
// after
fn main() {
let sub_app = App::empty();
sub_app.add_stage(MyStage, SystemStage::parallel());
App::new().add_sub_app(MySubApp, sub_app, move |main_world, sub_app| {
extract(app_world, render_app);
// schedule is automatically called for you after extract is run
});
}
```
2023-01-09 19:24:54 +00:00
|
|
|
|
extract: Box::new(extract),
|
2021-08-24 00:31:21 +00:00
|
|
|
|
},
|
|
|
|
|
);
|
2021-04-11 20:13:07 +00:00
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// Retrieves a `SubApp` stored inside this [`App`].
|
|
|
|
|
///
|
|
|
|
|
/// # Panics
|
|
|
|
|
///
|
|
|
|
|
/// Panics if the `SubApp` doesn't exist.
|
2021-12-24 06:57:30 +00:00
|
|
|
|
pub fn sub_app_mut(&mut self, label: impl AppLabel) -> &mut App {
|
|
|
|
|
match self.get_sub_app_mut(label) {
|
2021-08-24 06:37:28 +00:00
|
|
|
|
Ok(app) => app,
|
Simplify design for `*Label`s (#4957)
# Objective
- Closes #4954
- Reduce the complexity of the `{System, App, *}Label` APIs.
## Solution
For the sake of brevity I will only refer to `SystemLabel`, but everything applies to all of the other label types as well.
- Add `SystemLabelId`, a lightweight, `copy` struct.
- Convert custom types into `SystemLabelId` using the trait `SystemLabel`.
## Changelog
- String literals implement `SystemLabel` for now, but this should be changed with #4409 .
## Migration Guide
- Any previous use of `Box<dyn SystemLabel>` should be replaced with `SystemLabelId`.
- `AsSystemLabel` trait has been modified.
- No more output generics.
- Method `as_system_label` now returns `SystemLabelId`, removing an unnecessary level of indirection.
- If you *need* a label that is determined at runtime, you can use `Box::leak`. Not recommended.
## Questions for later
* Should we generate a `Debug` impl along with `#[derive(*Label)]`?
* Should we rename `as_str()`?
* Should we remove the extra derives (such as `Hash`) from builtin `*Label` types?
* Should we automatically derive types like `Clone, Copy, PartialEq, Eq`?
* More-ergonomic comparisons between `Label` and `LabelId`.
* Move `Dyn{Eq, Hash,Clone}` somewhere else.
* Some API to make interning dynamic labels easier.
* Optimize string representation
* Empty string for unit structs -- no debug info but faster comparisons
* Don't show enum types -- same tradeoffs as asbove.
2022-07-14 18:23:01 +00:00
|
|
|
|
Err(label) => panic!("Sub-App with label '{:?}' does not exist", label.as_str()),
|
2021-08-24 06:37:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// Retrieves a `SubApp` inside this [`App`] with the given label, if it exists. Otherwise returns
|
|
|
|
|
/// an [`Err`] containing the given label.
|
Simplify design for `*Label`s (#4957)
# Objective
- Closes #4954
- Reduce the complexity of the `{System, App, *}Label` APIs.
## Solution
For the sake of brevity I will only refer to `SystemLabel`, but everything applies to all of the other label types as well.
- Add `SystemLabelId`, a lightweight, `copy` struct.
- Convert custom types into `SystemLabelId` using the trait `SystemLabel`.
## Changelog
- String literals implement `SystemLabel` for now, but this should be changed with #4409 .
## Migration Guide
- Any previous use of `Box<dyn SystemLabel>` should be replaced with `SystemLabelId`.
- `AsSystemLabel` trait has been modified.
- No more output generics.
- Method `as_system_label` now returns `SystemLabelId`, removing an unnecessary level of indirection.
- If you *need* a label that is determined at runtime, you can use `Box::leak`. Not recommended.
## Questions for later
* Should we generate a `Debug` impl along with `#[derive(*Label)]`?
* Should we rename `as_str()`?
* Should we remove the extra derives (such as `Hash`) from builtin `*Label` types?
* Should we automatically derive types like `Clone, Copy, PartialEq, Eq`?
* More-ergonomic comparisons between `Label` and `LabelId`.
* Move `Dyn{Eq, Hash,Clone}` somewhere else.
* Some API to make interning dynamic labels easier.
* Optimize string representation
* Empty string for unit structs -- no debug info but faster comparisons
* Don't show enum types -- same tradeoffs as asbove.
2022-07-14 18:23:01 +00:00
|
|
|
|
pub fn get_sub_app_mut(&mut self, label: impl AppLabel) -> Result<&mut App, AppLabelId> {
|
|
|
|
|
let label = label.as_label();
|
2021-08-24 00:31:21 +00:00
|
|
|
|
self.sub_apps
|
Simplify design for `*Label`s (#4957)
# Objective
- Closes #4954
- Reduce the complexity of the `{System, App, *}Label` APIs.
## Solution
For the sake of brevity I will only refer to `SystemLabel`, but everything applies to all of the other label types as well.
- Add `SystemLabelId`, a lightweight, `copy` struct.
- Convert custom types into `SystemLabelId` using the trait `SystemLabel`.
## Changelog
- String literals implement `SystemLabel` for now, but this should be changed with #4409 .
## Migration Guide
- Any previous use of `Box<dyn SystemLabel>` should be replaced with `SystemLabelId`.
- `AsSystemLabel` trait has been modified.
- No more output generics.
- Method `as_system_label` now returns `SystemLabelId`, removing an unnecessary level of indirection.
- If you *need* a label that is determined at runtime, you can use `Box::leak`. Not recommended.
## Questions for later
* Should we generate a `Debug` impl along with `#[derive(*Label)]`?
* Should we rename `as_str()`?
* Should we remove the extra derives (such as `Hash`) from builtin `*Label` types?
* Should we automatically derive types like `Clone, Copy, PartialEq, Eq`?
* More-ergonomic comparisons between `Label` and `LabelId`.
* Move `Dyn{Eq, Hash,Clone}` somewhere else.
* Some API to make interning dynamic labels easier.
* Optimize string representation
* Empty string for unit structs -- no debug info but faster comparisons
* Don't show enum types -- same tradeoffs as asbove.
2022-07-14 18:23:01 +00:00
|
|
|
|
.get_mut(&label)
|
2021-08-24 00:31:21 +00:00
|
|
|
|
.map(|sub_app| &mut sub_app.app)
|
2021-08-24 06:37:28 +00:00
|
|
|
|
.ok_or(label)
|
2021-04-11 20:13:07 +00:00
|
|
|
|
}
|
2021-12-24 06:57:30 +00:00
|
|
|
|
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// Retrieves a `SubApp` stored inside this [`App`].
|
|
|
|
|
///
|
|
|
|
|
/// # Panics
|
|
|
|
|
///
|
|
|
|
|
/// Panics if the `SubApp` doesn't exist.
|
2021-12-24 06:57:30 +00:00
|
|
|
|
pub fn sub_app(&self, label: impl AppLabel) -> &App {
|
|
|
|
|
match self.get_sub_app(label) {
|
|
|
|
|
Ok(app) => app,
|
Simplify design for `*Label`s (#4957)
# Objective
- Closes #4954
- Reduce the complexity of the `{System, App, *}Label` APIs.
## Solution
For the sake of brevity I will only refer to `SystemLabel`, but everything applies to all of the other label types as well.
- Add `SystemLabelId`, a lightweight, `copy` struct.
- Convert custom types into `SystemLabelId` using the trait `SystemLabel`.
## Changelog
- String literals implement `SystemLabel` for now, but this should be changed with #4409 .
## Migration Guide
- Any previous use of `Box<dyn SystemLabel>` should be replaced with `SystemLabelId`.
- `AsSystemLabel` trait has been modified.
- No more output generics.
- Method `as_system_label` now returns `SystemLabelId`, removing an unnecessary level of indirection.
- If you *need* a label that is determined at runtime, you can use `Box::leak`. Not recommended.
## Questions for later
* Should we generate a `Debug` impl along with `#[derive(*Label)]`?
* Should we rename `as_str()`?
* Should we remove the extra derives (such as `Hash`) from builtin `*Label` types?
* Should we automatically derive types like `Clone, Copy, PartialEq, Eq`?
* More-ergonomic comparisons between `Label` and `LabelId`.
* Move `Dyn{Eq, Hash,Clone}` somewhere else.
* Some API to make interning dynamic labels easier.
* Optimize string representation
* Empty string for unit structs -- no debug info but faster comparisons
* Don't show enum types -- same tradeoffs as asbove.
2022-07-14 18:23:01 +00:00
|
|
|
|
Err(label) => panic!("Sub-App with label '{:?}' does not exist", label.as_str()),
|
2021-12-24 06:57:30 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-05 22:36:02 +00:00
|
|
|
|
/// Retrieves a `SubApp` inside this [`App`] with the given label, if it exists. Otherwise returns
|
|
|
|
|
/// an [`Err`] containing the given label.
|
2021-12-24 06:57:30 +00:00
|
|
|
|
pub fn get_sub_app(&self, label: impl AppLabel) -> Result<&App, impl AppLabel> {
|
|
|
|
|
self.sub_apps
|
Simplify design for `*Label`s (#4957)
# Objective
- Closes #4954
- Reduce the complexity of the `{System, App, *}Label` APIs.
## Solution
For the sake of brevity I will only refer to `SystemLabel`, but everything applies to all of the other label types as well.
- Add `SystemLabelId`, a lightweight, `copy` struct.
- Convert custom types into `SystemLabelId` using the trait `SystemLabel`.
## Changelog
- String literals implement `SystemLabel` for now, but this should be changed with #4409 .
## Migration Guide
- Any previous use of `Box<dyn SystemLabel>` should be replaced with `SystemLabelId`.
- `AsSystemLabel` trait has been modified.
- No more output generics.
- Method `as_system_label` now returns `SystemLabelId`, removing an unnecessary level of indirection.
- If you *need* a label that is determined at runtime, you can use `Box::leak`. Not recommended.
## Questions for later
* Should we generate a `Debug` impl along with `#[derive(*Label)]`?
* Should we rename `as_str()`?
* Should we remove the extra derives (such as `Hash`) from builtin `*Label` types?
* Should we automatically derive types like `Clone, Copy, PartialEq, Eq`?
* More-ergonomic comparisons between `Label` and `LabelId`.
* Move `Dyn{Eq, Hash,Clone}` somewhere else.
* Some API to make interning dynamic labels easier.
* Optimize string representation
* Empty string for unit structs -- no debug info but faster comparisons
* Don't show enum types -- same tradeoffs as asbove.
2022-07-14 18:23:01 +00:00
|
|
|
|
.get(&label.as_label())
|
2021-12-24 06:57:30 +00:00
|
|
|
|
.map(|sub_app| &sub_app.app)
|
|
|
|
|
.ok_or(label)
|
|
|
|
|
}
|
2021-07-27 20:21:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn run_once(mut app: App) {
|
|
|
|
|
app.update();
|
2020-04-06 03:19:02 +00:00
|
|
|
|
}
|
2020-07-10 04:18:35 +00:00
|
|
|
|
|
2022-04-25 17:40:44 +00:00
|
|
|
|
/// An event that indicates the [`App`] should exit. This will fully exit the app process at the
|
|
|
|
|
/// start of the next tick of the schedule.
|
|
|
|
|
///
|
|
|
|
|
/// You can also use this event to detect that an exit was requested. In order to receive it, systems
|
|
|
|
|
/// subscribing to this event should run after it was emitted and before the schedule of the same
|
|
|
|
|
/// frame is over.
|
2022-02-04 01:24:47 +00:00
|
|
|
|
#[derive(Debug, Clone, Default)]
|
2020-07-10 04:18:35 +00:00
|
|
|
|
pub struct AppExit;
|
2022-10-31 16:12:19 +00:00
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use crate::{App, Plugin};
|
|
|
|
|
|
|
|
|
|
struct PluginA;
|
|
|
|
|
impl Plugin for PluginA {
|
|
|
|
|
fn build(&self, _app: &mut crate::App) {}
|
|
|
|
|
}
|
|
|
|
|
struct PluginB;
|
|
|
|
|
impl Plugin for PluginB {
|
|
|
|
|
fn build(&self, _app: &mut crate::App) {}
|
|
|
|
|
}
|
|
|
|
|
struct PluginC<T>(T);
|
|
|
|
|
impl<T: Send + Sync + 'static> Plugin for PluginC<T> {
|
|
|
|
|
fn build(&self, _app: &mut crate::App) {}
|
|
|
|
|
}
|
|
|
|
|
struct PluginD;
|
|
|
|
|
impl Plugin for PluginD {
|
|
|
|
|
fn build(&self, _app: &mut crate::App) {}
|
|
|
|
|
fn is_unique(&self) -> bool {
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn can_add_two_plugins() {
|
|
|
|
|
App::new().add_plugin(PluginA).add_plugin(PluginB);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[should_panic]
|
|
|
|
|
fn cant_add_twice_the_same_plugin() {
|
|
|
|
|
App::new().add_plugin(PluginA).add_plugin(PluginA);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn can_add_twice_the_same_plugin_with_different_type_param() {
|
|
|
|
|
App::new().add_plugin(PluginC(0)).add_plugin(PluginC(true));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn can_add_twice_the_same_plugin_not_unique() {
|
|
|
|
|
App::new().add_plugin(PluginD).add_plugin(PluginD);
|
|
|
|
|
}
|
2022-12-24 23:43:41 +00:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[should_panic]
|
|
|
|
|
fn cant_call_app_run_from_plugin_build() {
|
|
|
|
|
struct PluginRun;
|
|
|
|
|
impl Plugin for PluginRun {
|
|
|
|
|
fn build(&self, app: &mut crate::App) {
|
|
|
|
|
app.run();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
App::new().add_plugin(PluginRun);
|
|
|
|
|
}
|
2022-10-31 16:12:19 +00:00
|
|
|
|
}
|