# Objective
- Fixes#15236
## Solution
- Use bevy_math::ops instead of std floating point operations.
## Testing
- Did you test these changes? If so, how?
Unit tests and `cargo run -p ci -- test`
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
Execute `cargo run -p ci -- test` on Windows.
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
Windows
## Migration Guide
- Not a breaking change
- Projects should use bevy math where applicable
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: IQuick 143 <IQuick143cz@gmail.com>
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
# Objective
- fix#12853
- Make `Table::allocate` faster
## Solution
The PR consists of multiple steps:
1) For the component data: create a new data-structure that's similar to
`BlobVec` but doesn't store `len` & `capacity` inside of it: "BlobArray"
(name suggestions welcome)
2) For the `Tick` data: create a new data-structure that's similar to
`ThinSlicePtr` but supports dynamic reallocation: "ThinArrayPtr" (name
suggestions welcome)
3) Create a new data-structure that's very similar to `Column` that
doesn't store `len` & `capacity` inside of it: "ThinColumn"
4) Adjust the `Table` implementation to use `ThinColumn` instead of
`Column`
The result is that only one set of `len` & `capacity` is stored in
`Table`, in `Table::entities`
### Notes Regarding Performance
Apart from shaving off some excess memory in `Table`, the changes have
also brought noteworthy performance improvements:
The previous implementation relied on `Vec::reserve` &
`BlobVec::reserve`, but that redundantly repeated the same if statement
(`capacity` == `len`). Now that check could be made at the `Table` level
because the capacity and length of all the columns are synchronized;
saving N branches per allocation. The result is a respectable
performance improvement per every `Table::reserve` (and subsequently
`Table::allocate`) call.
I'm hesitant to give exact numbers because I don't have a lot of
experience in profiling and benchmarking, but these are the results I
got so far:
*`add_remove_big/table` benchmark after the implementation:*
![after_add_remove_big_table](https://github.com/bevyengine/bevy/assets/46227443/b667da29-1212-4020-8bb0-ec0f15bb5f8a)
*`add_remove_big/table` benchmark in main branch (measured in comparison
to the implementation):*
![main_add_remove_big_table](https://github.com/bevyengine/bevy/assets/46227443/41abb92f-3112-4e01-b935-99696eb2fe58)
*`add_remove_very_big/table` benchmark after the implementation:*
![after_add_remove_very_big](https://github.com/bevyengine/bevy/assets/46227443/f268a155-295b-4f55-ab02-f8a9dcc64fc2)
*`add_remove_very_big/table` benchmark in main branch (measured in
comparison to the implementation):*
![main_add_remove_very_big](https://github.com/bevyengine/bevy/assets/46227443/78b4e3a6-b255-47c9-baee-1a24c25b9aea)
cc @james7132 to verify
---
## Changelog
- New data-structure that's similar to `BlobVec` but doesn't store `len`
& `capacity` inside of it: `BlobArray`
- New data-structure that's similar to `ThinSlicePtr` but supports
dynamic allocation:`ThinArrayPtr`
- New data-structure that's very similar to `Column` that doesn't store
`len` & `capacity` inside of it: `ThinColumn`
- Adjust the `Table` implementation to use `ThinColumn` instead of
`Column`
- New benchmark: `add_remove_very_big` to benchmark the performance of
spawning a lot of entities with a lot of components (15) each
## Migration Guide
`Table` now uses `ThinColumn` instead of `Column`. That means that
methods that previously returned `Column`, will now return `ThinColumn`
instead.
`ThinColumn` has a much more limited and low-level API, but you can
still achieve the same things in `ThinColumn` as you did in `Column`.
For example, instead of calling `Column::get_added_tick`, you'd call
`ThinColumn::get_added_ticks_slice` and index it to get the specific
added tick.
---------
Co-authored-by: James Liu <contact@jamessliu.com>
# Objective
It's possible to create UB using an implementation of `QueryFilter` that
performs mutable access, but that does not violate any documented safety
invariants.
This code:
```rust
#[derive(Component)]
struct Foo(usize);
// This derive is a simple way to get a valid WorldQuery impl. The QueryData impl isn't used.
#[derive(QueryData)]
#[query_data(mutable)]
struct BadFilter<'w> {
foo: &'w mut Foo,
}
impl QueryFilter for BadFilter<'_> {
const IS_ARCHETYPAL: bool = false;
unsafe fn filter_fetch(
fetch: &mut Self::Fetch<'_>,
entity: Entity,
table_row: TableRow,
) -> bool {
// SAFETY: fetch and filter_fetch have the same safety requirements
let f: &mut usize = &mut unsafe { Self::fetch(fetch, entity, table_row) }.foo.0;
println!("Got &mut at {f:p}");
true
}
}
let mut world = World::new();
world.spawn(Foo(0));
world.run_system_once(|query: Query<&Foo, BadFilter>| {
let f: &usize = &query.iter().next().unwrap().0;
println!("Got & at {f:p}");
query.iter().next().unwrap();
println!("Still have & at {f:p}");
});
```
prints:
```
Got &mut at 0x1924b92dfb0
Got & at 0x1924b92dfb0
Got &mut at 0x1924b92dfb0
Still have & at 0x1924b92dfb0
```
Which means it had an `&` and `&mut` alive at the same time.
The only `unsafe` there is around `Self::fetch`, but I believe that call
correctly upholds the safety invariant, and matches what `Added` and
`Changed` do.
## Solution
Make `QueryFilter` an unsafe trait and document the requirement that the
`WorldQuery` implementation be read-only.
## Migration Guide
`QueryFilter` is now an `unsafe trait`. If you were manually
implementing it, you will need to verify that the `WorldQuery`
implementation is read-only and then add the `unsafe` keyword to the
`impl`.
# Objective
- follow of #14049 ,we could use it on our Parallel Iterator,this pr
also unified the used function in both regular iter and parallel
iterations.
## Performance
![image](https://github.com/user-attachments/assets/cba700bc-169c-4b58-b504-823bdca8ec05)
no performance regression for regular itertaion
3.5X faster in hybrid parallel iteraion,this number is far greater than
the benefits obtained in regular iteration(~1.81) because mutable
iterations on continuous memory can effectively reduce the cost of
mataining core cache coherence
# Objective
- Fixes#14348
- Fixes#14528
- Less complex (but also likely less performant) alternative to #14611
## Solution
- Add a `is_dense` field flag to `QueryIter` indicating whether it is
dense or not, that is whether it can perform dense iteration or not;
- Check this flag any time iteration over a query is performed.
---
It would be nice if someone could try benching this change to see if it
actually matters.
~Note that this not 100% ready for mergin, since there are a bunch of
safety comments on the use of the various `IS_DENSE` for checks that
still need to be updated.~ This is ready modulo benchmarks
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Fixes#14782
## Solution
Enable the lint and fix all upcoming hints (`--fix`). Also tried to
figure out the false-positive (see review comment). Maybe split this PR
up into multiple parts where only the last one enables the lint, so some
can already be merged resulting in less many files touched / less
potential for merge conflicts?
Currently, there are some cases where it might be easier to read the
code with the qualifier, so perhaps remove the import of it and adapt
its cases? In the current stage it's just a plain adoption of the
suggestions in order to have a base to discuss.
## Testing
`cargo clippy` and `cargo run -p ci` are happy.
# Objective
- Sometimes some method or function takes an owned `Query`, but we don't
want to give up ours;
- transmuting it technically a solution, but it more costly than
necessary.
- Make query iterators more flexible
- this would allow the equivalent of
`slice::split_first`/`slice::split_first_mut` for query iterators
- helps with requests like #14685
## Solution
- Add a way for reborrowing queries, that is going from a `&'a mut
Query<'w, 's, D, F>` to a `Query<'a, 's, D, F>`:
- this is safe because the original query will be borrowed while the new
query exists and thus no aliased access can happen;
- it's basically the equivalent of going from `&'short mut &'long mut T`
to `&'short mut T` the the compiler automatically implements.
- Add a way for getting the remainder of a query iterator:
- this is interesting also because the original iterator keeps its
position, which was not possible before;
- this in turn requires a way to reborrow query fetches, which I had to
add to `WorldQuery`.
## Showcase
- You can now reborrow a `Query`, getting an equivalent `Query` with a
shorter lifetime. Previously this was possible for read-only queries by
using `Query::to_readonly`, now it's possible for mutable queries too;
- You can now separately iterate over the remainder of `QueryIter`.
## Migration Guide
- `WorldQuery` now has an additional `shrink_fetch` method you have to
implement if you were implementing `WorldQuery` manually.
# Objective
- Fixes#14697
## Solution
This PR modifies the existing `all_tuples!` macro to optionally accept a
`#[doc(fake_variadic)]` attribute in its input. If the attribute is
present, each invocation of the impl macro gets the correct attributes
(i.e. the first impl receives `#[doc(fake_variadic)]` while the other
impls are hidden using `#[doc(hidden)]`.
Impls for the empty tuple (unit type) are left untouched (that's what
the [standard
library](https://doc.rust-lang.org/std/cmp/trait.PartialEq.html#impl-PartialEq-for-())
and
[serde](https://docs.rs/serde/latest/serde/trait.Serialize.html#impl-Serialize-for-())
do).
To work around https://github.com/rust-lang/cargo/issues/8811 and to get
impls on re-exports to correctly show up as variadic, `--cfg docsrs_dep`
is passed when building the docs for the toplevel `bevy` crate.
`#[doc(fake_variadic)]` only works on tuples and fn pointers, so impls
for structs like `AnyOf<(T1, T2, ..., Tn)>` are unchanged.
## Testing
I built the docs locally using `RUSTDOCFLAGS='--cfg docsrs'
RUSTFLAGS='--cfg docsrs_dep' cargo +nightly doc --no-deps --workspace`
and checked the documentation page of a trait both in its original crate
and the re-exported version in `bevy`.
The description should correctly mention for how many tuple items the
trait is implemented.
I added `rustc-args` for docs.rs to the `bevy` crate, I hope there
aren't any other notable crates that re-export `#[doc(fake_variadic)]`
traits.
---
## Showcase
`bevy_ecs::query::QueryData`:
<img width="1015" alt="Screenshot 2024-08-12 at 16 41 28"
src="https://github.com/user-attachments/assets/d40136ed-6731-475f-91a0-9df255cd24e3">
`bevy::ecs::query::QueryData` (re-export):
<img width="1005" alt="Screenshot 2024-08-12 at 16 42 57"
src="https://github.com/user-attachments/assets/71d44cf0-0ab0-48b0-9a51-5ce332594e12">
## Original Description
<details>
Resolves#14697
Submitting as a draft for now, very WIP.
Unfortunately, the docs don't show the variadics nicely when looking at
reexported items.
For example:
`bevy_ecs::bundle::Bundle` correctly shows the variadic impl:
![image](https://github.com/user-attachments/assets/90bf8af1-1d1f-4714-9143-cdd3d0199998)
while `bevy::ecs::bundle::Bundle` (the reexport) shows all the impls
(not good):
![image](https://github.com/user-attachments/assets/439c428e-f712-465b-bec2-481f7bf5870b)
Built using `RUSTDOCFLAGS='--cfg docsrs' cargo +nightly doc --workspace
--no-deps` (`--no-deps` because of wgpu-core).
Maybe I missed something or this is a limitation in the *totally not
private* `#[doc(fake_variadic)]` thingy. In any case I desperately need
some sleep now :))
</details>
# Objective
- fix#14679
- bevy's performance highly depends on compiler optimization,inline hot
function could greatly help compiler to optimize our program
# Objective
- after #14502 ,explicit using clone_from should has better performance
because it could reuse the resources to avoid unnecessary allocations.
# Objective
- I made a mistake when fixing the merge conflicts here:
https://github.com/bevyengine/bevy/pull/14579#discussion_r1705377452
It wasn't caught because there's no easy way to trigger access conflicts
with resources without triggering them with components first.
# Objective
- Fixes https://github.com/bevyengine/bevy/issues/14575
- There is a soundness issue because we use `conflicts()` to check for
system ambiguities + soundness issues. However since the current
conflicts is a `Vec<T>`, we cannot express conflicts where there is no
specific `ComponentId` at fault. For example `q1: Query<EntityMut>, q2:
Query<EntityMut>`
There was a TODO to handle the `write_all` case but it was never
resolved
## Solution
- Introduce an `AccessConflict` enum that is either a list of specific
ids that are conflicting or `All` if all component ids are conflicting
## Testing
- Introduced a new unit test to check for the `EntityMut` case
## Migration guide
The `get_conflicts` method of `Access` now returns an `AccessConflict`
enum instead of simply a `Vec` of `ComponentId`s that are causing the
access conflict. This can be useful in cases where there are no
particular `ComponentId`s conflicting, but instead **all** of them are;
for example `fn system(q1: Query<EntityMut>, q2: Query<EntityRef>)`
# Objective
To implement relations we will need to add a `ComponentIndex`, which is
a map from a Component to the list of archetypes that contain this
component.
One of the reasons is that with fragmenting relations the number of
archetypes will explode, so it will become inefficient to create and
update the query caches by iterating through the list of all archetypes.
In this PR, we introduce the `ComponentIndex`, and we update the
`QueryState` to make use of it:
- if a query has at least 1 required component (i.e. something other
than `()`, `Entity` or `Option<>`, etc.): for each of the required
components we find the list of archetypes that contain it (using the
ComponentIndex). Then, we select the smallest list among these. This
gives a small subset of archetypes to iterate through compared with
iterating through all new archetypes
- if it doesn't, then we keep using the current approach of iterating
through all new archetypes
# Implementation
- This breaks query iteration order, in the sense that we are not
guaranteed anymore to return results in the order in which the
archetypes were created. I think this should be fine because this wasn't
an explicit bevy guarantee so users should not be relying on this. I
updated a bunch of unit tests that were failing because of this.
- I had an issue with the borrow checker because iterating the list of
potential archetypes requires access to `&state.component_access`, which
was conflicting with the calls to
```
if state.new_archetype_internal(archetype) {
state.update_archetype_component_access(archetype, access);
}
```
which need a mutable access to the state.
The solution I chose was to introduce a `QueryStateView` which is a
temporary view into the `QueryState` which enables a "split-borrows"
kind of approach. It is described in detail in this blog post:
https://smallcultfollowing.com/babysteps/blog/2018/11/01/after-nll-interprocedural-conflicts/
# Test
The unit tests pass.
Benchmark results:
```
❯ critcmp main pr
group main pr
----- ---- --
iter_fragmented/base 1.00 342.2±25.45ns ? ?/sec 1.02 347.5±16.24ns ? ?/sec
iter_fragmented/foreach 1.04 165.4±11.29ns ? ?/sec 1.00 159.5±4.27ns ? ?/sec
iter_fragmented/foreach_wide 1.03 3.3±0.04µs ? ?/sec 1.00 3.2±0.06µs ? ?/sec
iter_fragmented/wide 1.03 3.1±0.06µs ? ?/sec 1.00 3.0±0.08µs ? ?/sec
iter_fragmented_sparse/base 1.00 6.5±0.14ns ? ?/sec 1.02 6.6±0.08ns ? ?/sec
iter_fragmented_sparse/foreach 1.00 6.3±0.08ns ? ?/sec 1.04 6.6±0.08ns ? ?/sec
iter_fragmented_sparse/foreach_wide 1.00 43.8±0.15ns ? ?/sec 1.02 44.6±0.53ns ? ?/sec
iter_fragmented_sparse/wide 1.00 29.8±0.44ns ? ?/sec 1.00 29.8±0.26ns ? ?/sec
iter_simple/base 1.00 8.2±0.10µs ? ?/sec 1.00 8.2±0.09µs ? ?/sec
iter_simple/foreach 1.00 3.8±0.02µs ? ?/sec 1.02 3.9±0.03µs ? ?/sec
iter_simple/foreach_sparse_set 1.00 19.0±0.26µs ? ?/sec 1.01 19.3±0.16µs ? ?/sec
iter_simple/foreach_wide 1.00 17.8±0.24µs ? ?/sec 1.00 17.9±0.31µs ? ?/sec
iter_simple/foreach_wide_sparse_set 1.06 95.6±6.23µs ? ?/sec 1.00 90.6±0.59µs ? ?/sec
iter_simple/sparse_set 1.00 19.3±1.63µs ? ?/sec 1.01 19.5±0.29µs ? ?/sec
iter_simple/system 1.00 8.1±0.10µs ? ?/sec 1.00 8.1±0.09µs ? ?/sec
iter_simple/wide 1.05 37.7±2.53µs ? ?/sec 1.00 35.8±0.57µs ? ?/sec
iter_simple/wide_sparse_set 1.00 95.7±1.62µs ? ?/sec 1.00 95.9±0.76µs ? ?/sec
par_iter_simple/with_0_fragment 1.04 35.0±2.51µs ? ?/sec 1.00 33.7±0.49µs ? ?/sec
par_iter_simple/with_1000_fragment 1.00 50.4±2.52µs ? ?/sec 1.01 51.0±3.84µs ? ?/sec
par_iter_simple/with_100_fragment 1.02 40.3±2.23µs ? ?/sec 1.00 39.5±1.32µs ? ?/sec
par_iter_simple/with_10_fragment 1.14 38.8±7.79µs ? ?/sec 1.00 34.0±0.78µs ? ?/sec
```
# Objective
- Fix#14629
## Solution
- Make `QueryState::transmute`, `QueryState::transmute_filtered`,
`QueryState::join` and `QueryState::join_filtered` take a `impl
Into<UnsafeWorldCell>` instead of a `&Components` and validate their
`WorldId`
## Migration Guide
- `QueryState::transmute`, `QueryState::transmute_filtered`,
`QueryState::join` and `QueryState::join_filtered` now take a `impl
Into<UnsafeWorldCell>` instead of a `&Components`
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
# Objective
- currently, bevy employs sparse iteration if any of the target
components in the query are stored in a sparse set. it may lead to
increased cache misses in some cases, potentially impacting performance.
- partial fixes#12381
## Solution
- use dense iteration when an archetype and its table have the same
entity count.
- to avoid introducing complicate unsafe noise, this pr only implement
for `for_each ` style iteration.
- added a benchmark to test performance for hybrid iteration.
## Performance
![image](https://github.com/bevyengine/bevy/assets/45868716/5cce13cf-6ff2-4861-9576-e75edc63bd46)
nearly 2x win in specific scenarios, and no performance degradation in
other test cases.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Christian Hughes <9044780+ItsDoot@users.noreply.github.com>
# Objective
- Make it possible to know *what* changed your component or resource.
- Common need when debugging, when you want to know the last code
location that mutated a value in the ECS.
- This feature would be very useful for the editor alongside system
stepping.
## Solution
- Adds the caller location to column data.
- Mutations now `track_caller` all the way up to the public API.
- Commands that invoke these functions immediately call
`Location::caller`, and pass this into the functions, instead of the
functions themselves attempting to get the caller. This would not work
for commands which are deferred, as the commands are executed by the
scheduler, not the user's code.
## Testing
- The `component_change_detection` example now shows where the component
was mutated:
```
2024-07-28T06:57:48.946022Z INFO component_change_detection: Entity { index: 1, generation: 1 }: New value: MyComponent(0.0)
2024-07-28T06:57:49.004371Z INFO component_change_detection: Entity { index: 1, generation: 1 }: New value: MyComponent(1.0)
2024-07-28T06:57:49.012738Z WARN component_change_detection: Change detected!
-> value: Ref(MyComponent(1.0))
-> added: false
-> changed: true
-> changed by: examples/ecs/component_change_detection.rs:36:23
```
- It's also possible to inspect change location from a debugger:
<img width="608" alt="image"
src="https://github.com/user-attachments/assets/c90ecc7a-0462-457a-80ae-42e7f5d346b4">
---
## Changelog
- Added source locations to ECS change detection behind the
`track_change_detection` flag.
## Migration Guide
- Added `changed_by` field to many internal ECS functions used with
change detection when the `track_change_detection` feature flag is
enabled. Use Location::caller() to provide the source of the function
call.
---------
Co-authored-by: BD103 <59022059+BD103@users.noreply.github.com>
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
# Objective
Optimize the cloning process for Access-related structs in the ECS
system, specifically targeting the `clone_from` method.
Previously, profiling showed that 1% of CPU time was spent in
`FixedBitSet`'s `drop_in_place`, due to the default `clone_from`
implementation:
```rust
fn clone_from(&mut self, source: &Self) {
*self = source.clone()
}
```
This implementation causes unnecessary allocations and deallocations.
However, [FixedBitSet provides a more optimized clone_from
method](https://github.com/petgraph/fixedbitset/blob/master/src/lib.rs#L1445-L1465)
that avoids these allocations and utilizes SIMD instructions for better
performance.
This PR aims to leverage the optimized clone_from method of FixedBitSet
and implement custom clone_from methods for Access-related structs to
take full advantage of this optimization. By doing so, we expect to
significantly reduce CPU time spent on cloning operations and improve
overall system performance.
![image](https://github.com/user-attachments/assets/7526a5c5-c75b-4a9a-b8d2-891f64fd553b)
## Solution
- Implemented custom `clone` and `clone_from` methods for `Access`,
`FilteredAccess`, `AccessFilters`, and `FilteredAccessSet` structs.
- Removed `#[derive(Clone)]` and manually implemented `Clone` trait to
use optimized `clone_from` method from `FixedBitSet`.
- Added unit tests for cloning and `clone_from` methods to ensure
correctness.
## Testing
- Conducted performance testing comparing the original and optimized
versions.
- Measured CPU time consumption for the `clone_from` method:
- Original version: 1.34% of CPU time
- Optimized version: 0.338% of CPU time
- Compared FPS before and after the changes (results may vary depending
on the run):
Before optimization:
```
2024-07-28T12:49:11.864019Z INFO bevy diagnostic: fps : 213.489463 (avg 214.502488)
2024-07-28T12:49:11.864037Z INFO bevy diagnostic: frame_time : 4.704746ms (avg 4.682251ms)
2024-07-28T12:49:11.864042Z INFO bevy diagnostic: frame_count: 7947.000000 (avg 7887.500000)
```
![image](https://github.com/user-attachments/assets/7865a365-0569-4b46-814a-964779d90973)
After optimization:
```
2024-07-28T12:29:42.705738Z INFO bevy diagnostic: fps : 220.273721 (avg 220.912227)
2024-07-28T12:29:42.705762Z INFO bevy diagnostic: frame_time : 4.559127ms (avg 4.544905ms)
2024-07-28T12:29:42.705769Z INFO bevy diagnostic: frame_count: 7596.000000 (avg 7536.500000)
```
![image](https://github.com/user-attachments/assets/8dd96908-86d0-4850-8e29-f80176a005d6)
---
Reviewers can test these changes by running `cargo run --release
--example ssr`
# Objective
- The implementation of `update_component_access` for `AnyOf`/`Or` is
kinda weird due to special casing the first filter, let's simplify it;
- Fundamentally we want to fold/reduce the various filters using an OR
operation, however in order to do a proper fold we need a neutral
element for the initial accumulator, which for OR is FALSE. However we
didn't have a way to create a `FilteredAccess` value corresponding to
FALSE and thus the only option was reducing, which special cases the
first element as being the initial accumulator.
This is an alternative to https://github.com/bevyengine/bevy/pull/14026
## Solution
- Introduce `FilteredAccess::empty` as a way to create a
`FilteredAccess` corresponding to the logical proposition FALSE;
- Use it as the initial accumulator for the above operations, allowing
to handle all the elements to fold in the same way.
---
## Migration Guide
- The behaviour of `AnyOf<()>` and `Or<()>` has been changed to match no
archetypes rather than all archetypes to naturally match the
corresponding logical operation. Consider replacing them with `()`
instead.
# Objective
We currently cannot iterate from the back of `QueryManyIter`.
## Solution
Implement `DoubleEndedIterator` for `QueryManyIter` and add a
`fetch_next_back` method. These impls are bounded on the underlying
`entity_iter` implementing `DoubleEndedIterator`.
## Changelog
Added `DoubleEndedIterator` implementation for `QueryManyIter`.
Added the `fetch_next_back` method to `QueryManyIter`.
# Objective
The bounds for query iterators are quite intimidating.
## Solution
With Rust 1.79, [associated type
bounds](https://github.com/rust-lang/rust/pull/122055/) stabilized,
which can simplify the bounds slightly.
# Objective
- Fixes a correctness error introduced in
https://github.com/bevyengine/bevy/pull/14013 ...
## Solution
I've been playing around a lot of with the access code and I realized
that I introduced a soundness error when trying to simplify the code.
When we have a `Or<(With<A>, With<B>)>` filter, we cannot call
```
let mut intermediate = FilteredAccess::default();
$name::update_component_access($name, &mut intermediate);
_new_access.append_or(&intermediate);
```
because that's just equivalent to adding the new components as `Or`
clauses.
For example if the existing `filter_sets` was `vec![With<C>]`, we would
then get `vec![With<C>, With<A>, With<B>]` which translates to `A or B
or C`.
Instead what we want is `(A and B) or (A and C)`, so we need to have
each new OR clause compose with the existing access like so:
```
let mut intermediate = _access.clone();
// if we previously had a With<C> in the filter_set, this will become `With<C> AND With<A>`
$name::update_component_access($name, &mut intermediate);
_new_access.append_or(&intermediate);
```
## Testing
- Added a unit test that is broken in main, but passes in this PR
# Objective
Fixes https://github.com/bevyengine/bevy/issues/13993
PR inspired by https://github.com/bevyengine/bevy/pull/14007 to
accomplish the same thing, but maybe in a clearer fashion.
@Gingeh feel free to take my changes and add them to your PR, I don't
want to steal any credit
---------
Co-authored-by: Gingeh <39150378+Gingeh@users.noreply.github.com>
Co-authored-by: Bob Gardner <rgardner@inworld.ai>
Co-authored-by: Martín Maita <47983254+mnmaita@users.noreply.github.com>
# Objective
- Provide an expressive way to register dynamic behavior in response to
ECS changes that is consistent with existing bevy types and traits as to
provide a smooth user experience.
- Provide a mechanism for immediate changes in response to events during
command application in order to facilitate improved query caching on the
path to relations.
## Solution
- A new fundamental ECS construct, the `Observer`; inspired by flec's
observers but adapted to better fit bevy's access patterns and rust's
type system.
---
## Examples
There are 3 main ways to register observers. The first is a "component
observer" that looks like this:
```rust
world.observe(|trigger: Trigger<OnAdd, Transform>, query: Query<&Transform>| {
let transform = query.get(trigger.entity()).unwrap();
});
```
The above code will spawn a new entity representing the observer that
will run it's callback whenever the `Transform` component is added to an
entity. This is a system-like function that supports dependency
injection for all the standard bevy types: `Query`, `Res`, `Commands`
etc. It also has a `Trigger` parameter that provides information about
the trigger such as the target entity, and the event being triggered.
Importantly these systems run during command application which is key
for their future use to keep ECS internals up to date. There are similar
events for `OnInsert` and `OnRemove`, and this will be expanded with
things such as `ArchetypeCreated`, `TableEmpty` etc. in follow up PRs.
Another way to register an observer is an "entity observer" that looks
like this:
```rust
world.entity_mut(entity).observe(|trigger: Trigger<Resize>| {
// ...
});
```
Entity observers run whenever an event of their type is triggered
targeting that specific entity. This type of observer will de-spawn
itself if the entity (or entities) it is observing is ever de-spawned so
as to not leave dangling observers.
Entity observers can also be spawned from deferred contexts such as
other observers, systems, or hooks using commands:
```rust
commands.entity(entity).observe(|trigger: Trigger<Resize>| {
// ...
});
```
Observers are not limited to in built event types, they can be used with
any type that implements `Event` (which has been extended to implement
Component). This means events can also carry data:
```rust
#[derive(Event)]
struct Resize { x: u32, y: u32 }
commands.entity(entity).observe(|trigger: Trigger<Resize>, query: Query<&mut Size>| {
let event = trigger.event();
// ...
});
// Will trigger the observer when commands are applied.
commands.trigger_targets(Resize { x: 10, y: 10 }, entity);
```
You can also trigger events that target more than one entity at a time:
```rust
commands.trigger_targets(Resize { x: 10, y: 10 }, [e1, e2]);
```
Additionally, Observers don't _need_ entity targets:
```rust
app.observe(|trigger: Trigger<Quit>| {
})
commands.trigger(Quit);
```
In these cases, `trigger.entity()` will be a placeholder.
Observers are actually just normal entities with an `ObserverState` and
`Observer` component! The `observe()` functions above are just shorthand
for:
```rust
world.spawn(Observer::new(|trigger: Trigger<Resize>| {});
```
This will spawn the `Observer` system and use an `on_add` hook to add
the `ObserverState` component.
Dynamic components and trigger types are also fully supported allowing
for runtime defined trigger types.
## Possible Follow-ups
1. Deprecate `RemovedComponents`, observers should fulfill all use cases
while being more flexible and performant.
2. Queries as entities: Swap queries to entities and begin using
observers listening to archetype creation triggers to keep their caches
in sync, this allows unification of `ObserverState` and `QueryState` as
well as unlocking several API improvements for `Query` and the
management of `QueryState`.
3. Trigger bubbling: For some UI use cases in particular users are
likely to want some form of bubbling for entity observers, this is
trivial to implement naively but ideally this includes an acceleration
structure to cache hierarchy traversals.
4. All kinds of other in-built trigger types.
5. Optimization; in order to not bloat the complexity of the PR I have
kept the implementation straightforward, there are several areas where
performance can be improved. The focus for this PR is to get the
behavior implemented and not incur a performance cost for users who
don't use observers.
I am leaving each of these to follow up PR's in order to keep each of
them reviewable as this already includes significant changes.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: MiniaczQ <xnetroidpl@gmail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
…izer (#13442)"
This reverts commit 5cfb063d4a.
- This PR broke bevy-trait-query, which needs to be able to write a
resource in init_state. See #13798 for more details.
- Note this doesn't fix everything as transmutes for bevy-trait-query
will still be broken,. But the current usage in that crate is UB, so we
need to find another solution.
# Objective
In #13343, `WorldQuery::get_state` was constrained from `&World` as the
argument to `&Components`, but `WorldQuery::init_state` hasn't yet been
changed from `&mut World` to match.
Fixes#13358
## Solution
Create a wrapper around `&mut Components` and `&mut Storages` that can
be obtained from `&mut World` with a `component_initializer` method.
This new `ComponentInitializer` re-exposes the API on `&mut Components`
minus the `&mut Storages` parameter where it was present. For the
`&Components` API, it simply derefs to its `components` field.
## Changelog
### Added
The `World::component_initializer` method.
The `ComponentInitializer` struct that re-exposes `Components` API.
### Changed
`WorldQuery::init_state` now takes `&mut ComponentInitializer` instead
of `&mut World`.
## Migration Guide
Instead of passing `&mut World` to `WorldQuery::init_state` directly,
pass in a mutable reference to the struct returned from
`World::component_initializer`.
# Objective
The current query iterators cannot be used in positions with a `Debug`
bound.
F.e. when they are packaged in `Result` in the error position, `expect`
cannot be called on them.
Required for `QueryManyIter::entities_all_unique` in #13477.
## Solution
Add simple `Debug` impls that print the query iterator names.
## Changelog
`QueryIter`, `QueryManyIter`, `QueryCombinationIter`, and
`QuerySortedIter` now implement `Debug`.
# Objective
Currently, a query iterator can be collected into a `Vec` and sorted,
but this can be quite unwieldy, especially when many `Component`s are
involved. The `itertools` crate helps somewhat, but the need to write a
closure over all of `QueryData`
can sometimes hurt ergonomics, anywhere from slightly to strongly. A key
extraction function only partially helps, as `sort_by_key` does not
allow returning non-`Copy` data. `sort_by` does not suffer from the
`Copy` restriction, but now the user has to write out a `cmp` function
over two `QueryData::Item`s when it could have just been handled by the
`Ord` impl for the key.
`sort` requires the entire `Iterator` Item to be `Ord`, which is rarely
usable without manual helper functionality. If the user wants to hide
away unused components with a `..` range, they need to track item tuple
order across their function. Mutable `QueryData` can also introduce
further complexity.
Additionally, sometimes users solely include `Component`s /`Entity` to
guarantee iteration order.
For a user to write a function to abstract away repeated sorts over
various `QueryData` types they use would require reaching for the
`all_tuples!` macro, and continue tracking tuple order afterwards.
Fixes https://github.com/bevyengine/bevy/issues/1470.
## Solution
Custom sort methods on `QueryIter`, which take a query lens as a generic
argument, like `transmute_lens` in `Query`.
This allows users to choose what part of their queries they pass to
their sort function calls, serving as a kind of "key extraction
function" before the sort call. F.e. allowing users to implement `Ord`
for a Component, then call `query.iter().sort::<OrdComponent>()`
This works independent of mutability in `QueryData`, `QueryData` tuple
order, or the underlying `iter/iter_mut` call.
Non-`Copy` components could also be used this way, an internal
`Arc<usize>` being an example.
If `Ord` impls on components do not suffice, other sort methods can be
used. Notably useful when combined with `EntityRef` or `EntityMut`.
Another boon from using underlying `transmute` functionality, is that
with the [allowed
transmutes](http://dev-docs.bevyengine.org/bevy/ecs/prelude/struct.Query.html#allowed-transmutes),
it is possible to sort a `Query` with `Entity` even if it wasn't
included in the original `Query`.
The additional generic parameter on the methods other than `sort` and
`sort_unstable` currently cannot be removed due to Rust limitations,
however their types can be inferred.
The new methods do not conflict with the `itertools` sort methods, as
those use the "sorted" prefix.
This is implemented barely touching existing code. That change to
existing code being that `QueryIter` now holds on to the reference to
`UnsafeWorldCell` that is used to initialize it.
A lens query is constructed with `Entity` attached at the end, sorted,
and turned into an iterator. The iterator maps away the lens query,
leaving only an iterator of `Entity`, which is used by `QuerySortedIter`
to retrieve the actual items.
`QuerySortedIter` resembles a combination of `QueryManyIter` and
`QueryIter`, but it uses an entity list that is guaranteed to contain
unique entities, and implements `ExactSizeIterator`,
`DoubleEndedIterator`, `FusedIterator` regardless of mutability or
filter kind (archetypal/non-archetypal).
The sort methods are not allowed to be called after `next`, and will
panic otherwise. This is checked using `QueryIterationCursor` state,
which is unique on initialization. Empty queries are an exception to
this, as they do not return any item in the first place.
That is because tracking how many iterations have already passed would
require regressing either normal query iteration a slight bit, or sorted
iteration by a lot. Besides, that would not be the intended use of these
methods.
## Testing
To ensure that `next` being called before `sort` results in a panic, I
added some tests. I also test that empty `QueryIter`s do not exhibit
this restriction.
The query sorts test checks for equivalence to the underlying sorts.
This change requires that `Query<(Entity, Entity)>` remains legal, if
that is not already guaranteed, which is also ensured by the
aforementioned test.
## Next Steps
Implement the set of sort methods for `QueryManyIter` as well.
- This will mostly work the same, other than needing to return a new
`QuerySortedManyIter` to account for iteration
over lists of entities that are not guaranteed to be unique. This new
query iterator will need a bit of internal restructuring
to allow for double-ended mutable iteration, while not regressing
read-only iteration.
The implementations for each pair of
- `sort`, `sort_unstable`,
- `sort_by`, sort_unstable_by,
- `sort_by_key,` `sort_by_cached_key`
are the same aside from the panic message and the sort call, so they
could be merged with an inner function.
That would require the use of higher-ranked trait bounds on
`WorldQuery::Item<'1>`, and is unclear to me whether it is currently
doable.
Iteration in QuerySortedIter might have space for improvement.
When sorting by `Entity`, an `(Entity, Entity)` lens `QueryData` is
constructed, is that worth remedying?
When table sorts are implemented, a fast path could be introduced to
these sort methods.
## Future Possibilities
Implementing `Ord` for EntityLocation might be useful.
Some papercuts in ergonomics can be improved by future Rust features:
- The additional generic parameter aside from the query lens can be
removed once this feature is stable:
`Fn -> impl Trait` (`impl Trait` in `Fn` trait return position)
- With type parameter defaults, the query lens generic can be defaulted
to `QueryData::Item`, allowing the sort methods
to look and behave like `slice::sort` when no query lens is specified.
- With TAIT, the iterator generic on `QuerySortedIter` and thus the huge
visible `impl Iterator` type in the sort function
signatures can be removed.
- With specialization, the bound on `L` could be relaxed to `QueryData`
when the underlying iterator is mutable.
## Changelog
Added `sort`, `sort_unstable`, `sort_by`, `sort_unstable_by`,
`sort_by_key`, `sort_by_cached_key` to `QueryIter`.
# 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
Provides a `WorldQuery` implementation on `Mut<T>` that forwards to the
implementation on `&mut T`, and give users a way to opt-in to change
detection in auto-generated `QueryData::ReadOnly` types.
Fixes#13329.
## Solution
I implemented `WorldQuery` on `Mut<'w, T>` as a forwarding
implementation to `&mut T`, setting the `QueryData::ReadOnly` associated
type to `Ref<'w, T>`. This provides users the ability to explicitly
opt-in to change detection in the read-only forms of queries.
## Testing
A documentation test was added to `Mut` showcasing the new
functionality.
---
## Changelog
### Added
- Added an implementation of `WorldQuery` and `QueryData` on
`bevy_ecs::change_detection::Mut`.
# 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
Fixes#12966
## Solution
Renaming multi_threaded feature to match snake case
## Migration Guide
Bevy feature multi-threaded should be refered to multi_threaded from now
on.
# Objective
- bevy usually use `Parallel::scope` to collect items from `par_iter`,
but `scope` will be called with every satifified items. it will cause a
lot of unnecessary lookup.
## Solution
- similar to Rayon ,we introduce `for_each_init` for `par_iter` which
only be invoked when spawn a task for a group of items.
---
## Changelog
- added `for_each_init`
## Performance
`check_visibility ` in `many_foxes `
![image](https://github.com/bevyengine/bevy/assets/45868716/030c41cf-0d2f-4a36-a071-35097d93e494)
~40% performance gain in `check_visibility`.
---------
Co-authored-by: James Liu <contact@jamessliu.com>
# 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
- I daily drive nightly Rust when developing Bevy, so I notice when new
warnings are raised by `cargo check` and Clippy.
- `cargo +nightly clippy` raises a few of these new warnings.
## Solution
- Fix most warnings from `cargo +nightly clippy`
- I skipped the docs-related warnings because some were covered by
#12692.
- Use `Clone::clone_from` in applicable scenarios, which can sometimes
avoid an extra allocation.
- Implement `Default` for structs that have a `pub const fn new() ->
Self` method.
- Fix an occurrence where generic constraints were defined in both `<C:
Trait>` and `where C: Trait`.
- Removed generic constraints that were implied by the `Bundle` trait.
---
## Changelog
- `BatchingStrategy`, `NonGenericTypeCell`, and `GenericTypeCell` now
implement `Default`.
# Objective
- Fix#7303
- bevy would spawn a lot of tasks in parallel iteration when it matchs a
large storage and many small storage ,it significantly increase the
overhead of schedule.
## Solution
- collect small storage into one task