# Objective
- Prevent the case where a hook/observer is triggered but the source
entity/component no longer exists
## Solution
- Re-order command application such that all hooks/observers that are
notified will run before any have a chance to invalidate the result.
## Testing
Updated relevant tests in `bevy_ecs`, all other tests pass.
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
Co-authored-by: Mike Hsu <mike.hsu@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- Implement a general purpose mechanism for building `SystemParam`.
- Unblock the usage of dynamic queries in regular systems.
## Solution
- Implement a `SystemBuilder` type.
## Examples
Here are some simple test cases for the builder:
```rust
fn local_system(local: Local<u64>) -> u64 {
*local
}
fn query_system(query: Query<()>) -> usize {
query.iter().count()
}
fn multi_param_system(a: Local<u64>, b: Local<u64>) -> u64 {
*a + *b + 1
}
#[test]
fn local_builder() {
let mut world = World::new();
let system = SystemBuilder::<()>::new(&mut world)
.builder::<Local<u64>>(|x| *x = 10)
.build(local_system);
let result = world.run_system_once(system);
assert_eq!(result, 10);
}
#[test]
fn query_builder() {
let mut world = World::new();
world.spawn(A);
world.spawn_empty();
let system = SystemBuilder::<()>::new(&mut world)
.builder::<Query<()>>(|query| {
query.with::<A>();
})
.build(query_system);
let result = world.run_system_once(system);
assert_eq!(result, 1);
}
#[test]
fn multi_param_builder() {
let mut world = World::new();
world.spawn(A);
world.spawn_empty();
let system = SystemBuilder::<()>::new(&mut world)
.param::<Local<u64>>()
.param::<Local<u64>>()
.build(multi_param_system);
let result = world.run_system_once(system);
assert_eq!(result, 1);
}
```
This will be expanded as this PR is iterated.
# Objective
- Fixes#12377
## Solution
Added simple `#[diagnostic::on_unimplemented(...)]` attributes to some
critical public traits providing a more approachable initial error
message. Where appropriate, a `note` is added indicating that a `derive`
macro is available.
## Examples
<details>
<summary>Examples hidden for brevity</summary>
Below is a collection of examples showing the new error messages
produced by this change. In general, messages will start with a more
Bevy-centric error message (e.g., _`MyComponent` is not a `Component`_),
and a note directing the user to an available derive macro where
appropriate.
### Missing `#[derive(Resource)]`
<details>
<summary>Example Code</summary>
```rust
use bevy::prelude::*;
struct MyResource;
fn main() {
App::new()
.insert_resource(MyResource)
.run();
}
```
</details>
<details>
<summary>Error Generated</summary>
```error
error[E0277]: `MyResource` is not a `Resource`
--> examples/app/empty.rs:7:26
|
7 | .insert_resource(MyResource)
| --------------- ^^^^^^^^^^ invalid `Resource`
| |
| required by a bound introduced by this call
|
= help: the trait `Resource` is not implemented for `MyResource`
= note: consider annotating `MyResource` with `#[derive(Resource)]`
= help: the following other types implement trait `Resource`:
AccessibilityRequested
ManageAccessibilityUpdates
bevy::bevy_a11y::Focus
DiagnosticsStore
FrameCount
bevy::prelude::State<S>
SystemInfo
bevy::prelude::Axis<T>
and 141 others
note: required by a bound in `bevy::prelude::App::insert_resource`
--> C:\Users\Zac\Documents\GitHub\bevy\crates\bevy_app\src\app.rs:419:31
|
419 | pub fn insert_resource<R: Resource>(&mut self, resource: R) -> &mut Self {
| ^^^^^^^^ required by this bound in `App::insert_resource`
```
</details>
### Putting A `QueryData` in a `QueryFilter` Slot
<details>
<summary>Example Code</summary>
```rust
use bevy::prelude::*;
#[derive(Component)]
struct A;
#[derive(Component)]
struct B;
fn my_system(_query: Query<&A, &B>) {}
fn main() {
App::new()
.add_systems(Update, my_system)
.run();
}
```
</details>
<details>
<summary>Error Generated</summary>
```error
error[E0277]: `&B` is not a valid `Query` filter
--> examples/app/empty.rs:9:22
|
9 | fn my_system(_query: Query<&A, &B>) {}
| ^^^^^^^^^^^^^ invalid `Query` filter
|
= help: the trait `QueryFilter` is not implemented for `&B`
= help: the following other types implement trait `QueryFilter`:
With<T>
Without<T>
bevy::prelude::Or<()>
bevy::prelude::Or<(F0,)>
bevy::prelude::Or<(F0, F1)>
bevy::prelude::Or<(F0, F1, F2)>
bevy::prelude::Or<(F0, F1, F2, F3)>
bevy::prelude::Or<(F0, F1, F2, F3, F4)>
and 28 others
note: required by a bound in `bevy::prelude::Query`
--> C:\Users\Zac\Documents\GitHub\bevy\crates\bevy_ecs\src\system\query.rs:349:51
|
349 | pub struct Query<'world, 'state, D: QueryData, F: QueryFilter = ()> {
| ^^^^^^^^^^^ required by this bound in `Query`
```
</details>
### Missing `#[derive(Component)]`
<details>
<summary>Example Code</summary>
```rust
use bevy::prelude::*;
struct A;
fn my_system(mut commands: Commands) {
commands.spawn(A);
}
fn main() {
App::new()
.add_systems(Startup, my_system)
.run();
}
```
</details>
<details>
<summary>Error Generated</summary>
```error
error[E0277]: `A` is not a `Bundle`
--> examples/app/empty.rs:6:20
|
6 | commands.spawn(A);
| ----- ^ invalid `Bundle`
| |
| required by a bound introduced by this call
|
= help: the trait `bevy::prelude::Component` is not implemented for `A`, which is required by `A: Bundle`
= note: consider annotating `A` with `#[derive(Component)]` or `#[derive(Bundle)]`
= help: the following other types implement trait `Bundle`:
TransformBundle
SceneBundle
DynamicSceneBundle
AudioSourceBundle<Source>
SpriteBundle
SpriteSheetBundle
Text2dBundle
MaterialMesh2dBundle<M>
and 34 others
= note: required for `A` to implement `Bundle`
note: required by a bound in `bevy::prelude::Commands::<'w, 's>::spawn`
--> C:\Users\Zac\Documents\GitHub\bevy\crates\bevy_ecs\src\system\commands\mod.rs:243:21
|
243 | pub fn spawn<T: Bundle>(&mut self, bundle: T) -> EntityCommands {
| ^^^^^^ required by this bound in `Commands::<'w, 's>::spawn`
```
</details>
### Missing `#[derive(Asset)]`
<details>
<summary>Example Code</summary>
```rust
use bevy::prelude::*;
struct A;
fn main() {
App::new()
.init_asset::<A>()
.run();
}
```
</details>
<details>
<summary>Error Generated</summary>
```error
error[E0277]: `A` is not an `Asset`
--> examples/app/empty.rs:7:23
|
7 | .init_asset::<A>()
| ---------- ^ invalid `Asset`
| |
| required by a bound introduced by this call
|
= help: the trait `Asset` is not implemented for `A`
= note: consider annotating `A` with `#[derive(Asset)]`
= help: the following other types implement trait `Asset`:
Font
AnimationGraph
DynamicScene
Scene
AudioSource
Pitch
bevy::bevy_gltf::Gltf
GltfNode
and 17 others
note: required by a bound in `init_asset`
--> C:\Users\Zac\Documents\GitHub\bevy\crates\bevy_asset\src\lib.rs:307:22
|
307 | fn init_asset<A: Asset>(&mut self) -> &mut Self;
| ^^^^^ required by this bound in `AssetApp::init_asset`
```
</details>
### Mismatched Input and Output on System Piping
<details>
<summary>Example Code</summary>
```rust
use bevy::prelude::*;
fn producer() -> u32 {
123
}
fn consumer(_: In<u16>) {}
fn main() {
App::new()
.add_systems(Update, producer.pipe(consumer))
.run();
}
```
</details>
<details>
<summary>Error Generated</summary>
```error
error[E0277]: `fn(bevy::prelude::In<u16>) {consumer}` is not a valid system with input `u32` and output `_`
--> examples/app/empty.rs:11:44
|
11 | .add_systems(Update, producer.pipe(consumer))
| ---- ^^^^^^^^ invalid system
| |
| required by a bound introduced by this call
|
= help: the trait `bevy::prelude::IntoSystem<u32, _, _>` is not implemented for fn item `fn(bevy::prelude::In<u16>) {consumer}`
= note: expecting a system which consumes `u32` and produces `_`
note: required by a bound in `pipe`
--> C:\Users\Zac\Documents\GitHub\bevy\crates\bevy_ecs\src\system\mod.rs:168:12
|
166 | fn pipe<B, Final, MarkerB>(self, system: B) -> PipeSystem<Self::System, B::System>
| ---- required by a bound in this associated function
167 | where
168 | B: IntoSystem<Out, Final, MarkerB>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `IntoSystem::pipe`
```
</details>
### Missing Reflection
<details>
<summary>Example Code</summary>
```rust
use bevy::prelude::*;
#[derive(Component)]
struct MyComponent;
fn main() {
App::new()
.register_type::<MyComponent>()
.run();
}
```
</details>
<details>
<summary>Error Generated</summary>
```error
error[E0277]: `MyComponent` does not provide type registration information
--> examples/app/empty.rs:8:26
|
8 | .register_type::<MyComponent>()
| ------------- ^^^^^^^^^^^ the trait `GetTypeRegistration` is not implemented for `MyComponent`
| |
| required by a bound introduced by this call
|
= note: consider annotating `MyComponent` with `#[derive(Reflect)]`
= help: the following other types implement trait `GetTypeRegistration`:
bool
char
isize
i8
i16
i32
i64
i128
and 443 others
note: required by a bound in `bevy::prelude::App::register_type`
--> C:\Users\Zac\Documents\GitHub\bevy\crates\bevy_app\src\app.rs:619:29
|
619 | pub fn register_type<T: bevy_reflect::GetTypeRegistration>(&mut self) -> &mut Self {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `App::register_type`
```
</details>
### Missing `#[derive(States)]` Implementation
<details>
<summary>Example Code</summary>
```rust
use bevy::prelude::*;
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash)]
enum AppState {
#[default]
Menu,
InGame {
paused: bool,
turbo: bool,
},
}
fn main() {
App::new()
.init_state::<AppState>()
.run();
}
```
</details>
<details>
<summary>Error Generated</summary>
```error
error[E0277]: the trait bound `AppState: FreelyMutableState` is not satisfied
--> examples/app/empty.rs:15:23
|
15 | .init_state::<AppState>()
| ---------- ^^^^^^^^ the trait `FreelyMutableState` is not implemented for `AppState`
| |
| required by a bound introduced by this call
|
= note: consider annotating `AppState` with `#[derive(States)]`
note: required by a bound in `bevy::prelude::App::init_state`
--> C:\Users\Zac\Documents\GitHub\bevy\crates\bevy_app\src\app.rs:282:26
|
282 | pub fn init_state<S: FreelyMutableState + FromWorld>(&mut self) -> &mut Self {
| ^^^^^^^^^^^^^^^^^^ required by this bound in `App::init_state`
```
</details>
### Adding a `System` with Unhandled Output
<details>
<summary>Example Code</summary>
```rust
use bevy::prelude::*;
fn producer() -> u32 {
123
}
fn main() {
App::new()
.add_systems(Update, consumer)
.run();
}
```
</details>
<details>
<summary>Error Generated</summary>
```error
error[E0277]: `fn() -> u32 {producer}` does not describe a valid system configuration
--> examples/app/empty.rs:9:30
|
9 | .add_systems(Update, producer)
| ----------- ^^^^^^^^ invalid system configuration
| |
| required by a bound introduced by this call
|
= help: the trait `IntoSystem<(), (), _>` is not implemented for fn item `fn() -> u32 {producer}`, which is required by `fn() -> u32 {producer}: IntoSystemConfigs<_>`
= help: the following other types implement trait `IntoSystemConfigs<Marker>`:
<Box<(dyn bevy::prelude::System<In = (), Out = ()> + 'static)> as IntoSystemConfigs<()>>
<NodeConfigs<Box<(dyn bevy::prelude::System<In = (), Out = ()> + 'static)>> as IntoSystemConfigs<()>>
<(S0,) as IntoSystemConfigs<(SystemConfigTupleMarker, P0)>>
<(S0, S1) as IntoSystemConfigs<(SystemConfigTupleMarker, P0, P1)>>
<(S0, S1, S2) as IntoSystemConfigs<(SystemConfigTupleMarker, P0, P1, P2)>>
<(S0, S1, S2, S3) as IntoSystemConfigs<(SystemConfigTupleMarker, P0, P1, P2, P3)>>
<(S0, S1, S2, S3, S4) as IntoSystemConfigs<(SystemConfigTupleMarker, P0, P1, P2, P3, P4)>>
<(S0, S1, S2, S3, S4, S5) as IntoSystemConfigs<(SystemConfigTupleMarker, P0, P1, P2, P3, P4, P5)>>
and 14 others
= note: required for `fn() -> u32 {producer}` to implement `IntoSystemConfigs<_>`
note: required by a bound in `bevy::prelude::App::add_systems`
--> C:\Users\Zac\Documents\GitHub\bevy\crates\bevy_app\src\app.rs:342:23
|
339 | pub fn add_systems<M>(
| ----------- required by a bound in this associated function
...
342 | systems: impl IntoSystemConfigs<M>,
| ^^^^^^^^^^^^^^^^^^^^ required by this bound in `App::add_systems`
```
</details>
</details>
## Testing
CI passed locally.
## Migration Guide
Upgrade to version 1.78 (or higher) of Rust.
## Future Work
- Currently, hints are not supported in this diagnostic. Ideally,
suggestions like _"consider using ..."_ would be in a hint rather than a
note, but that is the best option for now.
- System chaining and other `all_tuples!(...)`-based traits have bad
error messages due to the slightly different error message format.
---------
Co-authored-by: Jamie Ridding <Themayu@users.noreply.github.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: BD103 <59022059+BD103@users.noreply.github.com>
# Objective
Passing `&World` in the `WorldQuery::get_state` method is unnecessary,
as all implementations of this method in the engine either only access
`Components` in `&World`, or do nothing with it.
It can introduce UB by necessitating the creation of a `&World` from a
`UnsafeWorldCell`.
This currently happens in `Query::transmute_lens`, which obtains a
`&World` from the internal `UnsafeWorldCell` solely to pass to
`get_state`. `Query::join` suffers from the same issue.
Other cases of UB come from allowing implementors of `WorldQuery` to
freely access `&World`, like in the `bevy-trait-query` crate, where a
[reference to a resource is
obtained](0c0e7dd646/src/lib.rs (L445))
inside of
[`get_state`](0c0e7dd646/src/one.rs (L245)),
potentially aliasing with a `ResMut` parameter in the same system.
`WorldQuery::init_state` currently requires `&mut World`, which doesn't
suffer from these issues.
But that too can be changed to receive a wrapper around `&mut
Components` and `&mut Storages` for consistency in a follow-up PR.
## Solution
Replace the `&World` parameter in `get_state` with `&Components`.
## Changelog
`WorldQuery::get_state` now takes `&Components` instead of `&World`.
The `transmute`, `transmute_filtered`, `join` and `join_filtered`
methods on `QueryState` now similarly take `&Components` instead of
`&World`.
## Migration Guide
Users of `WorldQuery::get_state` or `transmute`, `transmute_filtered`,
`join` and `join_filtered` methods on `QueryState` now need to pass
`&Components` instead of `&World`.
`&Components` can be trivially obtained from either `components` method
on `&World` or `UnsafeWorldCell`.
For implementors of `WorldQuery::get_state` that were accessing more
than the `Components` inside `&World` and its methods, this is no longer
allowed.
# Objective
I'm reading through the schedule code, which is somewhat lacking
documentation.
I've been adding some docstrings to help me understand the code; I feel
like some of them could be useful to also help others read this code.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- Better `SystemId` <-> `Entity` conversion.
## Solution
- Provide a method `SystemId::from_entity` to create a `SystemId<I, O>`
form an `Entity`. When users want to deal with the entities manually
they need a way to convert the `Entity` back to a `SystemId` to actually
run the system with `Commands` or `World`.
- Provide a method `SystemId::entity` that returns an `Entity` from
`SystemId`. The current `From` impl is not very discoverable as it does
not appear on the `SystemId` doc page.
- Remove old `From` impl.
## Migration Guide
```rust
let system_id = world.register_system(my_sys);
// old
let entity = Entity::from(system_id);
// new
let entity = system_id.entity();
```
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- Closes#12958
## Solution
- Find all methods under `Query` that mention panicking, and add
`#[track_caller]` to them.
---
## Changelog
- Added `#[track_caller]` to `Query::many`, `Query::many_mut`,
`Query::transmute_lens`, and `Query::transmute_lens_filtered`.
## For reviewers
I'm unfamiliar with the depths of the `Query` struct. Please check
whether it makes since for the updated methods to have
`#[track_caller]`, and if I missed any!
# Objective
Allow parallel iteration over events, resolve#10766
## Solution
- Add `EventParIter` which works similarly to `QueryParIter`,
implementing a `for_each{_with_id}` operator.
I chose to not mirror `EventIteratorWithId` and instead implement both
operations on a single struct.
- Reuse `BatchingStrategy` from `QueryParIter`
## Changelog
- `EventReader` now supports parallel event iteration using
`par_read().for_each(|event| ...)`.
---------
Co-authored-by: James Liu <contact@jamessliu.com>
Co-authored-by: Pablo Reinhardt <126117294+pablo-lua@users.noreply.github.com>
# Objective
Fix#2128. Both `Query::new_archetype` and `SystemParam::new_archetype`
do not check if the `Archetype` comes from the same World the state is
initialized from. This could result in unsoundness via invalid accesses
if called incorrectly.
## Solution
Make them `unsafe` functions and lift the invariant to the caller. This
also caught one instance of us not validating the World in
`SystemState::update_archetypes_unsafe_world_cell`'s implementation.
---
## Changelog
Changed: `QueryState::new_archetype` is now an unsafe function.
Changed: `SystemParam::new_archetype` is now an unsafe function.
## Migration Guide
`QueryState::new_archetype` and `SystemParam::new_archetype` are now an
unsafe functions that must be sure that the provided `Archetype` is from
the same `World` that the state was initialized from. Callers may need
to add additional assertions or propagate the safety invariant upwards
through the callstack to ensure safety.
# Objective
- Add `remove_by_id` method to `EntityWorldMut` and `EntityCommands`
- This is a duplicate of the awesome work by @mateuseap, last updated
04/09/23 - #9663
- I'm opening a second one to ensure the feature makes it into `0.14`
- Fixes#9261
## Solution
Almost identical to #9663 with three exceptions
- Uses a closure instead of struct for commands, consistent with other
similar commands
- Does not refactor `EntityCommands::insert`, so no migration guide
- `EntityWorldMut::remove_by_id` is now safe containing unsafe blocks, I
think thats what @SkiFire13 was indicating should happen [in this
comment](https://github.com/bevyengine/bevy/pull/9663#discussion_r1314307525)
## Changelog
- Added `EntityWorldMut::remove_by_id` method and its tests.
- Added `EntityCommands::remove_by_id` method and its tests.
---------
Co-authored-by: James Liu <contact@jamessliu.com>
# Objective
- There are several redundant imports in the tests and examples that are
not caught by CI because additional flags need to be passed.
## Solution
- Run `cargo check --workspace --tests` and `cargo check --workspace
--examples`, then fix all warnings.
- Add `test-check` to CI, which will be run in the check-compiles job.
This should catch future warnings for tests. Examples are already
checked, but I'm not yet sure why they weren't caught.
## Discussion
- Should the `--tests` and `--examples` flags be added to CI, so this is
caught in the future?
- If so, #12818 will need to be merged first. It was also a warning
raised by checking the examples, but I chose to split off into a
separate PR.
---------
Co-authored-by: François Mockers <francois.mockers@vleue.com>
# Objective
- The `bundles` parameter in `insert_or_spawn_batch` method has
inconsistent naming with docs (e.g. `bundles_iter`) since #11107.
## Solution
- Replace `bundles` with `bundles_iter`, as `bundles_iter` is more
expressive to its type.
# Objective
Fixes#12752. Fixes#12750. Document the runtime complexity of all of
the `O(1)` operations on the individual APIs.
## Solution
* Mirror `Query::contains` onto `QueryState::contains`
* Make `QueryState::as_nop` pub(crate)
* Make `NopWorldQuery` pub(crate)
* Document all of the O(1) operations on Query and QueryState.
# Objective
Fixes#12392, fixes#12393, and fixes#11387. Implement QueryData for
Archetype and EntityLocation.
## Solution
Add impls for both of the types.
---
## Changelog
Added: `&Archetype` now implements `QueryData`
Added: `EntityLocation` now implements `QueryData`
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- Allow registering of systems from Commands with
`Commands::register_one_shot_system`
- Make registering of one shot systems more easy
## Solution
- Add the Command `RegisterSystem` for Commands use.
- Creation of SystemId based on lazy insertion of the System
- Changed the privacy of the fields in SystemId so Commands can return
the SystemId
---
## Changelog
### Added
- Added command `RegisterSystem`
- Added function `Commands::register_one_shot_system`
- Added function `App::register_one_shot_system`
### Changed
- Changed the privacy and the type of struct tuple to regular struct of
SystemId
## Migration Guide
- Changed SystemId fields from tuple struct to a normal struct
If you want to access the entity field, you should use
`SystemId::entity` instead of `SystemId::0`
## Showcase
> Before, if you wanted to register a system with `Commands`, you would
need to do:
```rust
commands.add(|world: &mut World| {
let id = world.register_system(your_system);
// You would need to insert the SystemId inside an entity or similar
})
```
> Now, you can:
```rust
let id = commands.register_one_shot_system(your_system);
// Do what you want with the Id
```
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Pablo Reinhardt <pabloreinhardt@gmail.com>
# Objective
I'm reading through the ecs query code for the first time, and updating
the docs:
- fixed some typos
- added some docs about things I was confused about (in particular what
the difference between `matches_component_set` and
`update_component_access` was)
# Objective
Fix Pr CI failing over dead code in tests and main branch CI failing
over a missing semicolon. Fixes#12620.
## Solution
Add dead_code annotations and a semicolon.
# Objective
`QueryState::archetype_component_access` is only really ever used to
extend `SystemMeta`'s. It can be removed to save some memory for every
`Query` in an app.
## Solution
* Remove it.
* Have `new_archetype` pass in a `&mut Access<ArchetypeComponentId>`
instead and pull it from `SystemMeta` directly.
* Split `QueryState::new` from `QueryState::new_with_access` and a
common `QueryState::new_uninitialized`.
* Split `new_archetype` into an internal and public version. Call the
internal version in `update_archetypes`.
This should make it faster to construct new QueryStates, and by proxy
lenses and joins as well.
`matched_tables` also similarly is only used to deduplicate inserting
into `matched_table_ids`. If we can find another efficient way to do so,
it might also be worth removing.
The [generated
assembly](https://github.com/james7132/bevy_asm_tests/compare/main...remove-query-state-archetype-component-access#diff-496530101f0b16e495b7e9b77c0e906ae3068c8adb69ed36c92d5a1be5a9efbe)
reflects this well, with all of the access related updates in
`QueryState` being removed.
---
## Changelog
Removed: `QueryState::archetype_component_access`.
Changed: `QueryState::new_archetype` now takes a `&mut
Access<ArchetypeComponentId>` argument, which will be updated with the
new accesses.
Changed: `QueryState::update_archetype_component_access` now takes a
`&mut Access<ArchetypeComponentId>` argument, which will be updated with
the new accesses.
## Migration Guide
TODO
# Objective
`System<f32>` currently does not implement `Eq` even though it should
## Solution
Manually implement `Eq` like other traits are manually implemented
# Objective
- Add a way to combine 2 queries together in a similar way to
`Query::transmute_lens`
- Fixes#1658
## Solution
- Use a similar method to query transmute, but take the intersection of
matched archetypes between the 2 queries and the union of the accesses
to create the new underlying QueryState.
---
## Changelog
- Add query joins
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Fix#10876. Improve `Query` and `QueryState`'s docs.
## Solution
Explicitly denote that Query is always guaranteed to return results from
all matching entities once and only once for each entity, and that
iteration order is not guaranteed in any way.
# Objective
`initialize_resource<T>` and it's non-send equivalent is only used in
two locations each. Fix#6285.
## Solution
Remove them, replace their calls with their internals. Cut down on a bit
of generic codegen.
This does mean that `initialize_resource_internal` is now `pub(crate)`,
but that's likely OK given that only one variant will remain once
NonSend resources are removed from the World.
- Explain it is flushed in the same schedule run (was not obvious to me)
- Point to `apply_deferred` example
- Remove mentions of `System::apply_deferred` and
`Schedule::apply_deferred` which are probably too low level for the most
users
Co-authored-by: James Liu <contact@jamessliu.com>
# Objective
- The doc example for `World::run_system_with_input` mistakenly
indicates that systems share state
- Some of the doc example code is unnecessary and/or could be cleaned up
## Solution
Replace the incorrect result value for the correct one in the doc
example. I also went with an explicit `assert_eq` check as it presents
the same information but can be validated by CI via doc tests.
Also removed some unnecessary code, such as the `Resource` derives on
`Counter`. In fact, I just replaced `Counter` with a `u8` in the
`Local`. I think it makes the example a little cleaner.
---
## Changelog
- Update docs for `World::run_system` and `World::run_system_with_input`
# Objective
Fixes https://github.com/bevyengine/bevy/issues/11628
## Migration Guide
`Command` and `CommandQueue` have migrated from `bevy_ecs::system` to
`bevy_ecs::world`, so `use bevy_ecs::world::{Command, CommandQueue};`
when necessary.
# Objective
- Provide a reliable and performant mechanism to allows users to keep
components synchronized with external sources: closing/opening sockets,
updating indexes, debugging etc.
- Implement a generic mechanism to provide mutable access to the world
without allowing structural changes; this will not only be used here but
is a foundational piece for observers, which are key for a performant
implementation of relations.
## Solution
- Implement a new type `DeferredWorld` (naming is not important,
`StaticWorld` is also suitable) that wraps a world pointer and prevents
user code from making any structural changes to the ECS; spawning
entities, creating components, initializing resources etc.
- Add component lifecycle hooks `on_add`, `on_insert` and `on_remove`
that can be assigned callbacks in user code.
---
## Changelog
- Add new `DeferredWorld` type.
- Add new world methods: `register_component::<T>` and
`register_component_with_descriptor`. These differ from `init_component`
in that they provide mutable access to the created `ComponentInfo` but
will panic if the component is already in any archetypes. These
restrictions serve two purposes:
1. Prevent users from defining hooks for components that may already
have associated hooks provided in another plugin. (a use case better
served by observers)
2. Ensure that when an `Archetype` is created it gets the appropriate
flags to early-out when triggering hooks.
- Add methods to `ComponentInfo`: `on_add`, `on_insert` and `on_remove`
to be used to register hooks of the form `fn(DeferredWorld, Entity,
ComponentId)`
- Modify `BundleInserter`, `BundleSpawner` and `EntityWorldMut` to
trigger component hooks when appropriate.
- Add bit flags to `Archetype` indicating whether or not any contained
components have each type of hook, this can be expanded for other flags
as needed.
- Add `component_hooks` example to illustrate usage. Try it out! It's
fun to mash keys.
## Safety
The changes to component insertion, removal and deletion involve a large
amount of unsafe code and it's fair for that to raise some concern. I
have attempted to document it as clearly as possible and have confirmed
that all the hooks examples are accepted by `cargo miri` as not causing
any undefined behavior. The largest issue is in ensuring there are no
outstanding references when passing a `DeferredWorld` to the hooks which
requires some use of raw pointers (as was already happening to some
degree in those places) and I have taken some time to ensure that is the
case but feel free to let me know if I've missed anything.
## Performance
These changes come with a small but measurable performance cost of
between 1-5% on `add_remove` benchmarks and between 1-3% on `insert`
benchmarks. One consideration to be made is the existence of the current
`RemovedComponents` which is on average more costly than the addition of
`on_remove` hooks due to the early-out, however hooks doesn't completely
remove the need for `RemovedComponents` as there is a chance you want to
respond to the removal of a component that already has an `on_remove`
hook defined in another plugin, so I have not removed it here. I do
intend to deprecate it with the introduction of observers in a follow up
PR.
## Discussion Questions
- Currently `DeferredWorld` implements `Deref` to `&World` which makes
sense conceptually, however it does cause some issues with rust-analyzer
providing autocomplete for `&mut World` references which is annoying.
There are alternative implementations that may address this but involve
more code churn so I have attempted them here. The other alternative is
to not implement `Deref` at all but that leads to a large amount of API
duplication.
- `DeferredWorld`, `StaticWorld`, something else?
- In adding support for hooks to `EntityWorldMut` I encountered some
unfortunate difficulties with my desired API. If commands are flushed
after each call i.e. `world.spawn() // flush commands .insert(A) //
flush commands` the entity may be despawned while `EntityWorldMut` still
exists which is invalid. An alternative was then to add
`self.world.flush_commands()` to the drop implementation for
`EntityWorldMut` but that runs into other problems for implementing
functions like `into_unsafe_entity_cell`. For now I have implemented a
`.flush()` which will flush the commands and consume `EntityWorldMut` or
users can manually run `world.flush_commands()` after using
`EntityWorldMut`.
- In order to allowing querying on a deferred world we need
implementations of `WorldQuery` to not break our guarantees of no
structural changes through their `UnsafeWorldCell`. All our
implementations do this, but there isn't currently any safety
documentation specifying what is or isn't allowed for an implementation,
just for the caller, (they also shouldn't be aliasing components they
didn't specify access for etc.) is that something we should start doing?
(see 10752)
Please check out the example `component_hooks` or the tests in
`bundle.rs` for usage examples. I will continue to expand this
description as I go.
See #10839 for a more ergonomic API built on top of this one that isn't
subject to the same restrictions and supports `SystemParam` dependency
injection.
# Objective
Right now when using egui, systems are inserted without any identifier
and to the root. I'd like to name those systems and insert them as
children to a root entity. This helps to keep the editor organized.
## Solution
- Although the `SystemId` is documented as an opaque type, examples
depicted above benefit from tear down of the abstraction.
---
## Changelog
### Added
- Implemented `From<SystemId>` for `Entity`
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- A tiny nit I noticed; I think the type of these function is
`EntityCommand`, not `Command`
Co-authored-by: Charles Bournhonesque <cbournhonesque@snapchat.com>
# Objective
Fixes#11821.
## Solution
* Run `System::apply_deferred` in `System::run` after executing the
system.
* Switch to using `System::run_unsafe` in `SingleThreadedExecutor` to
preserve the current behavior.
* Remove the `System::apply_deferred` in `SimpleExecutor` as it's now
redundant.
* Remove the `System::apply_deferred` when running one-shot systems, as
it's now redundant.
---
## Changelog
Changed: `System::run` will now immediately apply deferred system params
after running the system.
## Migration Guide
`System::run` will now always run `System::apply_deferred` immediately
after running the system now. If you were running systems and then
applying their deferred buffers at a later point in time, you can
eliminate the latter.
```rust
// in 0.13
system.run(world);
// .. sometime later ...
system.apply_deferred(world);
// in 0.14
system.run(world);
```
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- Part of #11590
- Fix `unsafe_op_in_unsafe_fn` for trivial cases in bevy_ecs
## Solution
Fix `unsafe_op_in_unsafe_fn` in bevy_ecs for trivial cases, i.e., add an
`unsafe` block when the safety comment already exists or add a comment
like "The invariants are uphold by the caller".
---------
Co-authored-by: James Liu <contact@jamessliu.com>
## Objective
Always have `some_system.into_system().type_id() ==
some_system.into_system_set().system_type().unwrap()`.
System sets have a `fn system_type() -> Option<TypeId>` that is
implemented by `SystemTypeSet` to returning the TypeId of the system's
function type. This was implemented in
https://github.com/bevyengine/bevy/pull/7715 and is used in
`bevy_mod_debugdump` to handle `.after(function)` constraints.
Back then, `System::type_id` always also returned the type id of the
function item, not of `FunctionSystem<M, F>`.
https://github.com/bevyengine/bevy/pull/11728 changes the behaviour of
`System::type_id` so that it returns the id of the
`FunctionSystem`/`ExclusiveFunctionSystem` wrapper, but it did not
change `SystemTypeSet::system_type`, so doing the lookup breaks in
`bevy_mod_debugdump`.
## Solution
Change `IntoSystemSet` for functions to return a
`SystemTypeSet<FunctionSystem>` /
`SystemTypeSet<ExclusiveFunctionSystem>` instead of `SystemTypeSet<F>`.
# Objective
We deprecated quite a few APIs in 0.13. 0.13 has shipped already. It
should be OK to remove them in 0.14's release. Fixes#4059. Fixes#9011.
## Solution
Remove them.
# Objective
There's a repeating pattern of `ThreadLocal<Cell<Vec<T>>>` which is very
useful for low overhead, low contention multithreaded queues that have
cropped up in a few places in the engine. This pattern is surprisingly
useful when building deferred mutation across multiple threads, as noted
by it's use in `ParallelCommands`.
However, `ThreadLocal<Cell<Vec<T>>>` is not only a mouthful, it's also
hard to ensure the thread-local queue is replaced after it's been
temporarily removed from the `Cell`.
## Solution
Wrap the pattern into `bevy_utils::Parallel<T>` which codifies the
entire pattern and ensures the user follows the contract. Instead of
fetching indivdual cells, removing the value, mutating it, and replacing
it, `Parallel::get` returns a `ParRef<'a, T>` which contains the
temporarily removed value and a reference back to the cell, and will
write the mutated value back to the cell upon being dropped.
I would like to use this to simplify the remaining part of #4899 that
has not been adopted/merged.
---
## Changelog
TODO
---------
Co-authored-by: Joseph <21144246+JoJoJet@users.noreply.github.com>
# Objective
When applying a command, we currently use double indirection for the
world reference `&mut Option<&mut World>`. Since this is used across a
`fn` pointer boundary, this can't get optimized away.
## Solution
Reborrow the world reference and pass `Option<&mut World>` instead.
# Objective
Bevy's change detection functionality is invaluable for writing robust
apps, but it only works in the context of systems and exclusive systems.
Oftentimes it is necessary to detect changes made in earlier code
without having to place the code in separate systems, but it is not
currently possible to do so since there is no way to set the value of
`World::last_change_tick`.
`World::clear_trackers` allows you to update the change tick, but this
has unintended side effects, since it irreversibly affects the behavior
of change and removal detection for the entire app.
## Solution
Add a method `World::last_change_tick_scope`. This allows you to set
`last_change_tick` to a specific value for a region of code. To ensure
that misuse doesn't break unrelated functions, we restore the world's
original change tick at the end of the provided scope.
### Example
A function that uses this to run an update loop repeatedly, allowing
each iteration of the loop to react to changes made in the previous loop
iteration.
```rust
fn update_loop(
world: &mut World,
mut update_fn: impl FnMut(&mut World) -> std::ops::ControlFlow<()>,
) {
let mut last_change_tick = world.last_change_tick();
// Repeatedly run the update function until it requests a break.
loop {
// Update once.
let control_flow = world.last_change_tick_scope(last_change_tick, |world| {
update_fn(world)
});
// End the loop when the closure returns `ControlFlow::Break`.
if control_flow.is_break() {
break;
}
// Increment the change tick so the next update can detect changes from this update.
last_change_tick = world.change_tick();
world.increment_change_tick();
}
}
```
---
## Changelog
+ Added `World::last_change_tick_scope`, which allows you to specify the
reference for change detection within a certain scope.
# Objective
- Fixes#11679
## Solution
- Added `IntoSystem::system_type_id` which returns the equivalent of
`system.into_system().type_id()` without construction. This allows for
getting the `TypeId` of functions (a function is an unnamed type and
therefore you cannot call `TypeId::of::<apply_deferred::System>()`)
- Added default implementation of `System::type_id` to ensure
consistency between implementations. Some returned `Self`, while others
were returning an inner value instead. This ensures consistency with
`IntoSystem::system_type_id`.
## Migration Guide
If you use `System::type_id()` on function systems (exclusive or not),
ensure you are comparing its value to other `System::type_id()` calls,
or `IntoSystem::system_type_id()`.
This code wont require any changes, because `IntoSystem`'s are directly
compared to each other.
```rust
fn test_system() {}
let type_id = test_system.type_id();
// ...
// No change required
assert_eq!(test_system.type_id(), type_id);
```
Likewise, this code wont, because `System`'s are directly compared.
```rust
fn test_system() {}
let type_id = IntoSystem::into_system(test_system).type_id();
// ...
// No change required
assert_eq!(IntoSystem::into_system(test_system).type_id(), type_id);
```
The below _does_ require a change, since you're comparing a `System`
type to a `IntoSystem` type.
```rust
fn test_system() {}
// Before
assert_eq!(test_system.type_id(), IntoSystem::into_system(test_system).type_id());
// After
assert_eq!(test_system.system_type_id(), IntoSystem::into_system(test_system).type_id());
```
# Objective
- (Partially) Fixes#9904
- Acts on #9910
## Solution
- Deprecated the relevant methods from `Query`, cascading changes as
required across Bevy.
---
## Changelog
- Deprecated `QueryState::get_component_unchecked_mut` method
- Deprecated `Query::get_component` method
- Deprecated `Query::get_component_mut` method
- Deprecated `Query::component` method
- Deprecated `Query::component_mut` method
- Deprecated `Query::get_component_unchecked_mut` method
## Migration Guide
### `QueryState::get_component_unchecked_mut`
Use `QueryState::get_unchecked_manual` and select for the exact
component based on the structure of the exact query as required.
### `Query::(get_)component(_unchecked)(_mut)`
Use `Query::get` and select for the exact component based on the
structure of the exact query as required.
- For mutable access (`_mut`), use `Query::get_mut`
- For unchecked access (`_unchecked`), use `Query::get_unchecked`
- For panic variants (non-`get_`), add `.unwrap()`
## Notes
- `QueryComponentError` can be removed once these deprecated methods are
also removed. Due to an interaction with `thiserror`'s derive macro, it
is not marked as deprecated.
# Objective
Fixes#11311
## Solution
Adds an example to the documentation for `par_iter_mut`. I didn't add
any examples to `par_iter`, because I couldn't think of a good example
and I figure users can infer that `par_iter` and `par_iter_mut` are
similar.
# Objective
It would be convenient to be able to call functions with `Commands` as a
parameter without having to move your own instance of `Commands`. Since
this struct is composed entirely of references, we can easily get an
owned instance of `Commands` by shortening the lifetime.
## Solution
Add `Commands::reborrow`, `EntiyCommands::reborrow`, and
`Deferred::reborrow`, which returns an owned version of themselves with
a shorter lifetime.
Remove unnecessary lifetimes from `EntityCommands`. The `'w` and `'s`
lifetimes only have to be separate for `Commands` because it's used as a
`SystemParam` -- this is not the case for `EntityCommands`.
---
## Changelog
Added `Commands::reborrow`. This is useful if you have `&mut Commands`
but need `Commands`. Also added `EntityCommands::reborrow` and
`Deferred:reborrow` which serve the same purpose.
## Migration Guide
The lifetimes for `EntityCommands` have been simplified.
```rust
// Before (Bevy 0.12)
struct MyStruct<'w, 's, 'a> {
commands: EntityCommands<'w, 's, 'a>,
}
// After (Bevy 0.13)
struct MyStruct<'a> {
commands: EntityCommands<'a>,
}
```
The method `EntityCommands::commands` now returns `Commands` rather than
`&mut Commands`.
```rust
// Before (Bevy 0.12)
let commands = entity_commands.commands();
commands.spawn(...);
// After (Bevy 0.13)
let mut commands = entity_commands.commands();
commands.spawn(...);
```
# Objective
Document a few common cases of which lifetime is required when using
SystemParam Derive
## Solution
Added a table in the doc comment
---------
Co-authored-by: laund <me@laund.moe>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Expand the existing `Query` API to support more dynamic use cases i.e.
scripting.
## Prior Art
- #6390
- #8308
- #10037
## Solution
- Create a `QueryBuilder` with runtime methods to define the set of
component accesses for a built query.
- Create new `WorldQueryData` implementations `FilteredEntityMut` and
`FilteredEntityRef` as variants of `EntityMut` and `EntityRef` that
provide run time checked access to the components included in a given
query.
- Add new methods to `Query` to create "query lens" with a subset of the
access of the initial query.
### Query Builder
The `QueryBuilder` API allows you to define a query at runtime. At it's
most basic use it will simply create a query with the corresponding type
signature:
```rust
let query = QueryBuilder::<Entity, With<A>>::new(&mut world).build();
// is equivalent to
let query = QueryState::<Entity, With<A>>::new(&mut world);
```
Before calling `.build()` you also have the opportunity to add
additional accesses and filters. Here is a simple example where we add
additional filter terms:
```rust
let entity_a = world.spawn((A(0), B(0))).id();
let entity_b = world.spawn((A(0), C(0))).id();
let mut query_a = QueryBuilder::<Entity>::new(&mut world)
.with::<A>()
.without::<C>()
.build();
assert_eq!(entity_a, query_a.single(&world));
```
This alone is useful in that allows you to decide which archetypes your
query will match at runtime. However it is also very limited, consider a
case like the following:
```rust
let query_a = QueryBuilder::<&A>::new(&mut world)
// Add an additional access
.data::<&B>()
.build();
```
This will grant the query an additional read access to component B
however we have no way of accessing the data while iterating as the type
signature still only includes &A. For an even more concrete example of
this consider dynamic components:
```rust
let query_a = QueryBuilder::<Entity>::new(&mut world)
// Adding a filter is easy since it doesn't need be read later
.with_id(component_id_a)
// How do I access the data of this component?
.ref_id(component_id_b)
.build();
```
With this in mind the `QueryBuilder` API seems somewhat incomplete by
itself, we need some way method of accessing the components dynamically.
So here's one:
### Query Transmutation
If the problem is not having the component in the type signature why not
just add it? This PR also adds transmute methods to `QueryBuilder` and
`QueryState`. Here's a simple example:
```rust
world.spawn(A(0));
world.spawn((A(1), B(0)));
let mut query = QueryBuilder::<()>::new(&mut world)
.with::<B>()
.transmute::<&A>()
.build();
query.iter(&world).for_each(|a| assert_eq!(a.0, 1));
```
The `QueryState` and `QueryBuilder` transmute methods look quite similar
but are different in one respect. Transmuting a builder will always
succeed as it will just add the additional accesses needed for the new
terms if they weren't already included. Transmuting a `QueryState` will
panic in the case that the new type signature would give it access it
didn't already have, for example:
```rust
let query = QueryState::<&A, Option<&B>>::new(&mut world);
/// This is fine, the access for Option<&A> is less restrictive than &A
query.transmute::<Option<&A>>(&world);
/// Oh no, this would allow access to &B on entities that might not have it, so it panics
query.transmute::<&B>(&world);
/// This is right out
query.transmute::<&C>(&world);
```
This is quite an appealing API to also have available on `Query` however
it does pose one additional wrinkle: In order to to change the iterator
we need to create a new `QueryState` to back it. `Query` doesn't own
it's own state though, it just borrows it, so we need a place to borrow
it from. This is why `QueryLens` exists, it is a place to store the new
state so it can be borrowed when you call `.query()` leaving you with an
API like this:
```rust
fn function_that_takes_a_query(query: &Query<&A>) {
// ...
}
fn system(query: Query<(&A, &B)>) {
let lens = query.transmute_lens::<&A>();
let q = lens.query();
function_that_takes_a_query(&q);
}
```
Now you may be thinking: Hey, wait a second, you introduced the problem
with dynamic components and then described a solution that only works
for static components! Ok, you got me, I guess we need a bit more:
### Filtered Entity References
Currently the only way you can access dynamic components on entities
through a query is with either `EntityMut` or `EntityRef`, however these
can access all components and so conflict with all other accesses. This
PR introduces `FilteredEntityMut` and `FilteredEntityRef` as
alternatives that have additional runtime checking to prevent accessing
components that you shouldn't. This way you can build a query with a
`QueryBuilder` and actually access the components you asked for:
```rust
let mut query = QueryBuilder::<FilteredEntityRef>::new(&mut world)
.ref_id(component_id_a)
.with(component_id_b)
.build();
let entity_ref = query.single(&world);
// Returns Some(Ptr) as we have that component and are allowed to read it
let a = entity_ref.get_by_id(component_id_a);
// Will return None even though the entity does have the component, as we are not allowed to read it
let b = entity_ref.get_by_id(component_id_b);
```
For the most part these new structs have the exact same methods as their
non-filtered equivalents.
Putting all of this together we can do some truly dynamic ECS queries,
check out the `dynamic` example to see it in action:
```
Commands:
comp, c Create new components
spawn, s Spawn entities
query, q Query for entities
Enter a command with no parameters for usage.
> c A, B, C, Data 4
Component A created with id: 0
Component B created with id: 1
Component C created with id: 2
Component Data created with id: 3
> s A, B, Data 1
Entity spawned with id: 0v0
> s A, C, Data 0
Entity spawned with id: 1v0
> q &Data
0v0: Data: [1, 0, 0, 0]
1v0: Data: [0, 0, 0, 0]
> q B, &mut Data
0v0: Data: [2, 1, 1, 1]
> q B || C, &Data
0v0: Data: [2, 1, 1, 1]
1v0: Data: [0, 0, 0, 0]
```
## Changelog
- Add new `transmute_lens` methods to `Query`.
- Add new types `QueryBuilder`, `FilteredEntityMut`, `FilteredEntityRef`
and `QueryLens`
- `update_archetype_component_access` has been removed, archetype
component accesses are now determined by the accesses set in
`update_component_access`
- Added method `set_access` to `WorldQuery`, this is called before
`update_component_access` for queries that have a restricted set of
accesses, such as those built by `QueryBuilder` or `QueryLens`. This is
primarily used by the `FilteredEntity*` variants and has an empty trait
implementation.
- Added method `get_state` to `WorldQuery` as a fallible version of
`init_state` when you don't have `&mut World` access.
## Future Work
Improve performance of `FilteredEntityMut` and `FilteredEntityRef`,
currently they have to determine the accesses a query has in a given
archetype during iteration which is far from ideal, especially since we
already did the work when matching the archetype in the first place. To
avoid making more internal API changes I have left it out of this PR.
---------
Co-authored-by: Mike Hsu <mike.hsu@gmail.com>
# Objective
In #9604 we removed the ability to define an `EntityCommand` as
`fn(Entity, &mut World)`. However I have since realized that `fn(Entity,
&mut World)` is an incredibly expressive and powerful way to define a
command for an entity that may or may not exist (`fn(EntityWorldMut)`
only works on entities that are alive).
## Solution
Support `EntityCommand`s in the style of `fn(Entity, &mut World)`, as
well as `fn(EntityWorldMut)`. Use a marker generic on the
`EntityCommand` trait to allow multiple impls.
The second commit in this PR replaces all of the internal command
definitions with ones using `fn` definitions. This is mostly just to
show off how expressive this style of command is -- we can revert this
commit if we'd rather avoid breaking changes.
---
## Changelog
Re-added support for expressively defining an `EntityCommand` as a
function that takes `Entity, &mut World`.
## Migration Guide
All `Command` types in `bevy_ecs`, such as `Spawn`, `SpawnBatch`,
`Insert`, etc., have been made private. Use the equivalent methods on
`Commands` or `EntityCommands` instead.