# Objective
Don't ignore default query filters for `EntityRef` or `EntityMut`.
Currently, `Query<EntityRef>` will include entities with a `Disabled`
component, even though queries like `Query<()>` or `Query<Entity>` would
not. This was noticed in
https://github.com/bevyengine/bevy/pull/19711#discussion_r2205981065.
## Solution
Change `Access::contains` to completely ignore read access and just look
at filters and archetypal access. Filters covers `With`, `Without`, `&`,
and `&mut`, while archetypal covers `Has` and `Allows`.
Note that `Option<&Disabled>` will no longer count as a use of
`Disabled`, though.
# Objective
The ECS code to do with Observers was recently refactored to use an
`EventKey` newtype. On reading through the PR, I was a bit confused that
sometimes a variable called `event` refers to an `Event` and sometimes
it refers to an `EventKey`. I think the code is clearer when `event`
refers to an `Event` and `event_key` refers to an `EventKey`.
## Solution
This PR renames some uses of `event` to `event_key`.
## Testing
- Did you test these changes? If so, how?
I ran `cargo run -p ci -- tests`
- Are there any parts that need more testing?
No
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
No.
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
Probably not relevant, but MacOS.
---------
Co-authored-by: Steve Alexander <steve.alexander@priva.com>
# Objective
Improvement of the documentation for SystemParam derive section so that
it mentions how to use a Query<&SomeComponent> as a SystemParam for a
struct that should have #[derive(SystemParam)].
## Solution
Added the documentation
---
## Showcase
the previous documentation
```rust
Query<'w, 's, Entity>,
Res<'w, SomeResource>,
ResMut<'w, SomeOtherResource>,
Local<'s, u8>,
Commands<'w, 's>,
EventReader<'w, 's, SomeEvent>,
EventWriter<'w, SomeEvent>
```
the new documentation
```rust
Query<'w, 's, Entity>,
Query<'w, 's, &'static SomeComponent>, <================== the new thing
Res<'w, SomeResource>,
ResMut<'w, SomeOtherResource>,
Local<'s, u8>,
Commands<'w, 's>,
EventReader<'w, 's, SomeEvent>,
EventWriter<'w, SomeEvent>
```
# Objective
Since we are planning to remove the need to derive both `Event` and
`EntityEvent` in 0.17 either way, I'm choosing to do the easy thing in
this PR so we can get the churn out of the way early.
Context from
[discord](https://discordapp.com/channels/691052431525675048/1383928409784193024/1393463673137401946).
Related to, and will conflict slightly with #20101.
## Solution
- Derive `Event` as part of the `EntityEvent` derive
- Remove any `Event` derives that were made unnecessary
- Update release notes
# Objective
- Part of #20115
We want to encapsulate each part of `ScheduleGraph` into its own
specific struct to make parts of it easier to reuse and maintain.
## Solution
- Pulled `ScheduleGraph::systems` and `ScheduleGraph::system_conditions`
into a `Systems` struct and added a field for this new struct to
`ScheduleGraph`
- Broke up `ScheduleGraph::uninit` into `Systems::uninit` and
`SystemSets::uninit` to eliminate `ScheduleGraph`'s direct field access
of these types
- Removed node and condition accessors from `ScheduleGraph`; the same
operations are now available on `Systems` and `SystemSets` instead
(accessible via their `pub` fields on `ScheduleGraph`)
- Moved `Systems`, `SystemSets`, `SystemNode`, `SystemWithAccess`, and
`ConditionWithAccess` into a separate file.
## Testing
Added two new tests covering the API surface of `Systems` and
`SystemSets`, respectively.
---------
Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
# Objective
- Improve usability of read-only systems.
## Solution
- Added `on_unimplemented` diagnostics for types/functions that aren't
read-only systems.
- Added `BoxedReadOnlySystem` type alias, similar to `BoxedSystem`.
## Testing
Can/should we test these diagnostics?
# Objective
Fix#18079
## Solution
- `EntityCloner` can now move components that don't have `Clone` or
`Reflect` implementation.
- Components with `ComponentCloneBehavior::Ignore` will not be moved.
- Components with `ComponentCloneBehavior::Custom` will be cloned using
their defined `ComponentCloneFn` and then removed from the source entity
to respect their `queue_deferred` logic.
- Relationships still need to be `Clone` or `Reflect` to be movable.
- Custom relationship data is now correctly preserved when cloned or
moved using `EntityCloner`.
## Testing
- Added new tests for moving components
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Fixes https://github.com/bevyengine/bevy/issues/19535. Improve
interoperability of type documentation to make it easier for users to
find related types
## Solution
- Add a reference to
[`ComponentIdFor`](crate::component::ComponentIdFor) in the
`component_id` function documentation in
`crates/bevy_ecs/src/world/mod.rs`
- Add a reference to [`ComponentIdFor`](super::ComponentIdFor) in the
`component_id` function documentation in
`crates/bevy_ecs/src/component/info.rs`
## Testing
- Verify documentation generation: `cargo doc`
- Check the validity of cross-reference links in the documentation
- Confirm that the documentation generated by rustdoc can correctly jump
to the type definition of `ComponentIdFor`
# Objective
Implement `Clone` for `IntoPipeSystem`, allowing for `T: IntoSystem +
Clone` patterns.
## Precedence
Same clone implementation/docs as `CombinatorSystem`
# Objective
> I think we should axe the shared `Event` trait entirely
It doesn't serve any functional purpose, and I don't think it's useful
pedagogically
@alice-i-cecile on discord
## Solution
- Remove `Event` as a supertrait of `BufferedEvent`
- Remove any `Event` derives that were made unnecessary
- Update release notes
---------
Co-authored-by: SpecificProtagonist <vincentjunge@posteo.net>
# Objective
- Fix#20014
## Solution
- Don't make the `force_register_` family of functions always enqueue of
the component/resource; instead have them check again whether it was
already queued or not.
## Testing
- I added a small regression test but it's non-deterministic: if the bug
is fixed it will always pass, but if the bug is presen then it has a
(hopefully small) chance of passing. On my PC it failed after ~100
iterations, so hopefully 1000 is enough in CI (assuming it doesn't have
single core runners...)
---------
Co-authored-by: JaySpruce <jsprucebruce@gmail.com>
# Objective
- `bundle.rs` is also becoming quite big, let's split it
## Solution
- Split `bundle.rs` into the following:
- `bundle/mod.rs` with the main traits and their documentation
- `bundle/impls.rs` with the main trait implementations for components
and tuples
- `bundle/info.rs` with `BundleInfo` and other types for managing bundle
informations metadata
- `bundle/insert.rs` with code for inserting a bundle into an existing
entity
- `bundle/remove.rs` with code for removing a bundle from an existing
entity
- `bundle/spawner.rs` with code for inserting a bundle on a fresh entity
- `bundle/tests.rs` with code for tests
## Reviewer notes
I suggest reviewing with `--color-moved`, possibly commit-by-commit, in
order to quickly verify that most lines were only moved and not changed.
# Objective
`SystemSetNode` doesn't really add much value beyond a couple helper
functions for getting the name as a string and checking if its a
`SystemTypeSet`. We can replace it entirely and use `InternedSystemSet`
directly by inlining these helper functions' usages without sacrificing
readability.
## Solution
Remove it and replace it with direct `InternedSystemSet` usage.
## Testing
Reusing current tests.
# Objective
Clean up documentation around `UninitializedId`, which has slightly
confusing semantics.
## Solution
Added documentation comments on `UninitializedId`.
---------
Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
# Objective
- `component.rs` is becoming quite big, let's split it.
## Solution
- Split `component.rs` into the following:
- `component/mod.rs`: the new root of the `component` module: contains
the `Component` trait and a few other very generic items
- `component/clone.rs`: contains component cloning related items
- `component/tick.rs`: contains `Tick` and other tick related items
- future possibilities: move these into `change_detection`; however I
wanted to keep this PR without breaking changes
- `component/register.rs`: contains component registration (included
queued) related items
- `component/required.rs`: contains items and functions for properly
computing required components
- `component/info.rs`: contains items for storing component info and
metadata in the `World`
# Objective
The current Entity Debug impl prints the bit representation. This is an
"overshare". Debug is in many ways the primary interface into Entity, as
people derive Debug on their entity-containing types when they want to
inspect them. The bits take up too much space in the console and
obfuscate the useful information (entity index and generation).
## Solution
Use the Display implementation in Debug as well. Direct people
interested in bits to `Entity::to_bits` in the docs.
# Objective
Make the schedule graph code more understandable, and replace some
panics with `Result`s.
I found the `check_edges` and `check_hierarchy` functions [a little
confusing](https://github.com/bevyengine/bevy/pull/19352#discussion_r2181486099),
as they combined two concerns: Initializing graph nodes for system sets,
and checking for self-edges on system sets. It was hard to understand
the self-edge checks because it wasn't clear what `NodeId` was being
checked against! So, let's separate those concerns, and move them to
more appropriate locations.
Fix a bug where `schedule.configure_sets((SameSet, SameSet).chain());`
would panic with an unhelpful message: `assertion failed: index_a <
index_b`.
## Solution
Remove the `check_edges` and `check_hierarchy` functions, separating the
initialization behavior and the checking behavior and moving them where
they are easier to understand.
For initializing graph nodes, do this on-demand using the `entry` API by
replacing later `self.system_set_ids[&set]` calls with a
`self.system_sets.get_or_add_set(set)` method. This should avoid the
need for an extra pass over the graph and an extra lookup.
Unfortunately, implementing that method directly on `ScheduleGraph`
leads to borrowing errors as it borrows the entire `struct`. So, split
out the collections managing system sets into a separate `struct`.
For checking self-edges, move this check later so that it can be
reported by returning a `Result` from `Schedule::initialize` instead of
having to panic in `configure_set_inner`. The issue was that `iter_sccs`
does not report self-edges as cycles, since the resulting components
only have one node, but that later code assumes all edges point forward.
So, check for self-edges directly, immediately before calling
`iter_sccs`.
This also ensures we catch *every* way that self-edges can be added. The
previous code missed an edge case where `chain()`ing a set to itself
would create a self-edge and would trigger a `debug_assert`.
## Objective
Fixes#19884.
## Solution
- Add an internal entity command `insert_with`, which takes a function
returning a component and checks if the component would actually be
inserted before invoking the function.
- Add the same check to `insert_from_world`, since it's a similar
situation.
- Update the `or_insert_with`, `or_try_insert_with`, and `or_default`
methods on `EntityEntryCommands` to use the new command.
Since the function/closure returning the component now needs to be sent
into the command (rather than being invoked before the command is
created), the function now has `Send + 'static` bounds. Pretty typical
for command stuff, but I don't know how/if it'll affect existing users.
---------
Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
# Objective
#19649 introduced new `*_if_new` and `*_by_bundle_id_*` variations to
`EntityClonerBuilder` filtering functionality, which resulted in
increase in method permutations - there are now 8 allow variants to
support various id types and 2 different insert modes.
## Solution
This PR introduces a new trait `FilterableIds` to unify all id types and
their `IntoIterator` implementations, which is somewhat similar to
`WorldEntityFetch`. It supports `TypeId`, `ComponentId` and `BundleId`,
allowing us to reduce the number of `allow` methods to 4: `allow`,
`allow_if_new`, `allow_by_ids`, `allow_by_ids_if_new`. The function
signature is a bit less readable now, but the docs mention types that
can be passed in.
## Testing
All existing tests pass, performance is unchanged.
---------
Co-authored-by: urben1680 <55257931+urben1680@users.noreply.github.com>
# Objective
- The usage of ComponentId is quite confusing: events are not
components. By newtyping this, we can prevent stupid mistakes, avoid
leaking internal details and make the code clearer for users and engine
devs reading it.
- Adopts https://github.com/bevyengine/bevy/pull/19755
---------
Co-authored-by: oscar-benderstone <oscarbenderstone@gmail.com>
Co-authored-by: Oscar Bender-Stone <88625129+oscar-benderstone@users.noreply.github.com>
# Objective
- I accidentally left a `register_component_hooks` without actually
adding a hook and didnt notice
## Solution
- mark it must_use so it doesnt happen to other people (maybe this is
just skill issue on me though)
# Objective
Allow combinator and pipe systems to delay validation of the second
system, while still allowing the second system to be skipped.
Fixes#18796
Allow fallible systems to be used as one-shot systems, reporting errors
to the error handler when used through commands.
Fixes#19722
Allow fallible systems to be used as run conditions, including when used
with combinators. Alternative to #19580.
Always validate parameters when calling the safe
`run_without_applying_deferred`, `run`, and `run_readonly` methods on a
`System`.
## Solution
Have `System::run_unsafe` return a `Result`.
We want pipe systems to run the first system before validating the
second, since the first system may affect whether the second system has
valid parameters. But if the second system skips then we have no output
value to return! So, pipe systems must return a `Result` that indicates
whether the second system ran.
But if we just make pipe systems have `Out = Result<B::Out>`, then
chaining `a.pipe(b).pipe(c)` becomes difficult. `c` would need to accept
the `Result` from `a.pipe(b)`, which means it would likely need to
return `Result` itself, giving `Result<Result<Out>>`!
Instead, we make *all* systems return a `Result`! We move the handling
of fallible systems from `IntoScheduleConfigs` and `IntoObserverSystem`
to `SystemParamFunction` and `ExclusiveSystemParamFunction`, so that an
infallible system can be wrapped before being passed to a combinator.
As a side effect, this enables fallible systems to be used as run
conditions and one-shot systems.
Now that the safe `run_without_applying_deferred`, `run`, and
`run_readonly` methods return a `Result`, we can have them perform
parameter validation themselves instead of requiring each caller to
remember to call them. `run_unsafe` will continue to not validate
parameters, since it is used in the multi-threaded executor when we want
to validate and run in separate tasks.
Note that this makes type inference a little more brittle. A function
that returns `Result<T>` can be considered either a fallible system
returning `T` or an infallible system returning `Result<T>` (and this is
important to continue supporting `pipe`-based error handling)! So there
are some cases where the output type of a system can no longer be
inferred. It will work fine when directly adding to a schedule, since
then the output type is fixed to `()` (or `bool` for run conditions).
And it will work fine when `pipe`ing to a system with a typed input
parameter.
I used a dedicated `RunSystemError` for the error type instead of plain
`BevyError` so that skipping a system does not box an error or capture a
backtrace.
...which previously used a HashSet, whos iter has no ordering guarantee
fixes#19687
i also discovered that the asserted order in the unit test is reversed,
so i fixed that. I dont know if that reversed order is intentional
Edit: i referenced the wrong issue oops
# Objective
- First step towards #279
## Solution
Makes the necessary internal data structure changes in order to allow
system removal to be added in a future PR: `Vec`s storing systems and
system sets in `ScheduleGraph` have been replaced with `SlotMap`s.
See the included migration guide for the required changes.
## Testing
Internal changes only and no new features *should* mean no new tests are
requried.
# Objective
- `MapEntities` is not implemented for arrays, `HashMap`, `BTreeMap`,
and `IndexMap`.
## Solution
- Implement `MapEntities` for arrays, `HashMap`, `BTreeMap`, `IndexMap`
## Testing
- I didn't add a test for this as the implementations seems pretty
trivial
# Objective
Fixes#19356
Issue: Spawning a batch of entities in relationship with the same target
adds the relationship between the target and only the last entity of the
batch. `spawn_batch` flushes only after having spawned all entities.
This means each spawned entity will have run the `on_insert` hook of its
`Relationship` component. Here is the relevant part of that hook:
```Rust
if let Some(mut relationship_target) =
target_entity_mut.get_mut::<Self::RelationshipTarget>()
{
relationship_target.collection_mut_risky().add(entity);
} else {
let mut target = <Self::RelationshipTarget as RelationshipTarget>::with_capacity(1);
target.collection_mut_risky().add(entity);
world.commands().entity(target_entity).insert(target);
}
```
Given the above snippet and since there's no flush between spawns, each
entity finds the target without a `RelationshipTarget` component and
defers the insertion of that component with the entity's id as the sole
member of its collection. When the commands are finally flushed, each
insertion after the first replaces the one before and in the process
triggers the `on_replace` hook of `RelationshipTarget` which removes the
`Relationship` component from the corresponding entity. That's how we
end up in the invalid state.
## Solution
I see two possible solutions
1. Flush after every spawn
2. Defer the whole code snippet above
I don't know enough about bevy as a whole but 2. seems much more
efficient to me. This is what I'm proposing here. I have a doubt though
because I've started to look at #19348 that 1. would fix as well.
## Testing
I added a test for the issue. I've put it in `relationship/mod.rs` but I
could see it in `world/spawn_batch.rs` or `lib.rs` because the test is
as much about `spawn_batch` as it is about relationships.
# Objective
- bevy_ecs has a expected lint that is both needed and unneeded
## Solution
- Change the logic so that it's always not needed
## Testing
`cargo clippy -p bevy_ecs --no-default-features --no-deps -- -D
warnings`
# Objective
1. Reduce overhead from error handling for ECS commands that
intentionally ignore errors, such as `try_despawn`. These commands
currently allocate error objects and pass them to a no-op handler
(`ignore`), which can impact performance when many operations fail.
2. Fix a hang when removing `ChildOf` components during entity
despawning. Excessive logging of these failures can cause significant
hangs (I'm noticing around 100ms).
- Fixes https://github.com/bevyengine/bevy/issues/19777
- Fixes https://github.com/bevyengine/bevy/issues/19753
<img width="1387" alt="image"
src="https://github.com/user-attachments/assets/5c67ab77-97bb-46e5-b287-2c502bef9358"
/>
## Solution
* Added a `ignore_error` method to the `HandleError` trait to use
instead of `handle_error_with(ignore)`. It swallows errors and does not
create error objects.
* Replaced `remove::<ChildOf>` with `try_remove::<ChildOf>` to suppress
expected (?) errors and reduce log noise.
## Testing
- I ran these changes on a local project.
# Objective
Further tests after #19326 showed that configuring `EntityCloner` with
required components is bug prone and the current design has several
weaknesses in it's API:
- Mixing `EntityClonerBuilder::allow` and `EntityClonerBuilder::deny`
requires extra care how to support that which has an impact on
surrounding code that has to keep edge cases in mind. This is especially
true for attempts to fix the following issues. There is no use-case
known (to me) why someone would mix those.
- A builder with `EntityClonerBuilder::allow_all` configuration tries to
support required components like `EntityClonerBuilder::deny_all` does,
but the meaning of that is conflicting with how you'd expect things to
work:
- If all components should be cloned except component `A`, do you also
want to exclude required components of `A` too? Or are these also valid
without `A` at the target entity?
- If `EntityClonerBuilder::allow_all` should ignore required components
and not add them to be filtered away, which purpose has
`EntityClonerBuilder::without_required_components` for this cloner?
- Other bugs found with the linked PR are:
- Denying `A` also denies required components of `A` even when `A` does
not exist at the source entity
- Allowing `A` also allows required components of `A` even when `A` does
not exist at the source entity
- Adding `allow_if_new` filters to the cloner faces the same issues and
require a common solution to dealing with source-archetype sensitive
cloning
Alternative to #19632 and #19635.
# Solution
`EntityClonerBuilder` is made generic and split into
`EntityClonerBuilder<OptOut>` and `EntityClonerBuilder<OptIn>`
For an overview of the changes, see the migration guide. It is generally
a good idea to start a review of that.
## Algorithm
The generic of `EntityClonerBuilder` contains the filter data that is
needed to build and clone the entity components.
As the filter needs to be borrowed mutably for the duration of the
clone, the borrow checker forced me to separate the filter value and all
other fields in `EntityCloner`. The latter are now in the
`EntityClonerConfig` struct. This caused many changed LOC, sorry.
To make reviewing easier:
1. Check the migration guide
2. Many methods of `EntityCloner` now just call identitcal
`EntityClonerConfig` methods with a mutable borrow of the filter
3. Check `EntityClonerConfig::clone_entity_internal` which changed a bit
regarding the filter usage that is now trait powered (`CloneByFilter`)
to support `OptOut`, `OptIn` and `EntityClonerFilter` (an enum combining
the first two)
4. Check `OptOut` type that no longer tracks required components but has
a `insert_mode` field
5. Check `OptIn` type that has the most logic changes
# Testing
I added a bunch of tests that cover the new logic parts and the fixed
issues.
Benchmarks are in a comment a bit below which shows ~4% to 9%
regressions, but it varied wildly for me. For example at one run the
reflection-based clonings were on-par with main while the other are not,
and redoing that swapped the situation for both.
It would be really cool if I could get some hints how to get better
benchmark results or if you could run them on your machine too.
Just be aware this is not a Performance PR but a Bugfix PR, even if I
smuggled in some more functionalities. So doing changes to
`EntityClonerBuilder` is kind of required here which might make us bite
the bullet.
---------
Co-authored-by: eugineerd <70062110+eugineerd@users.noreply.github.com>
# Objective
- Notice a word duplication typo
- Small quest to fix similar or nearby typos with my faithful companion
`\b(\w+)\s+\1\b`
## Solution
Fix em
# Objective
The objective of this PR is to enable Components to use their
`MapEntities` implementation for `Component::map_entities`.
With the improvements to the entity mapping system, there is definitely
a huge reduction in boilerplate. However, especially since
`(Entity)HashMap<..>` doesn't implement `MapEntities` (I presume because
the lack of specialization in rust makes `HashMap<Entity|X, Entity|X>`
complicated), when somebody has types that contain these hashmaps they
can't use this approach.
More so, we can't even depend on the previous implementation, since
`Component::map_entities` is used instead of
`MapEntities::map_entities`. Outside of implementing `Component `and
`Component::map_entities` on these types directly, the only path forward
is to create a custom type to wrap the hashmaps and implement map
entities on that, or split these components into a wrapper type that
implement `Component`, and an inner type that implements `MapEntities`.
## Current Solution
The solution was to allow adding `#[component(map_entities)]` on the
component. By default this will defer to the `MapEntities`
implementation.
```rust
#[derive(Component)]
#[component(map_entities)]
struct Inventory {
items: HashMap<Entity, usize>
}
impl MapEntities for Inventory {
fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
self.items = self.items
.drain()
.map(|(id, count)|(entity_mapper.get_mapped(id), count))
.collect();
}
}
```
You can use `#[component(map_entities = <function path>)]` instead to
substitute other code in for components. This function can also include
generics, but sso far I haven't been able to find a case where they are
needed.
```rust
#[derive(Component)]
#[component(map_entities = map_the_map)]
// Also works #[component(map_entities = map_the_map::<T,_>)]
struct Inventory<T> {
items: HashMap<Entity, T>
}
fn map_the_map<T, M: EntityMapper>(inv: &mut Inventory<T>, entity_mapper: &mut M) {
inv.items = inv.items
.drain()
.map(|(id, count)|(entity_mapper.get_mapped(id), count))
.collect();
}
```
The idea is that with the previous changes to MapEntities, MapEntities
is implemented more for entity collections than for Components. If you
have a component that makes sense as both, `#[component(map_entities)]`
would work great, while otherwise a component can use
`#[component(map_entities = <function>)]` to change the behavior of
`Component::map_entities` without opening up the component type to be
included in other components.
## (Original Solution if you want to follow the PR)
The solution was to allow adding `#[component(entities)]` on the
component itself to defer to the `MapEntities` implementation
```rust
#[derive(Component)]
#[component(entities)]
struct Inventory {
items: HashMap<Entity, usize>
}
impl MapEntities for Inventory {
fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
self.items = self.items
.drain()
.map(|(id, count)|(entity_mapper.get_mapped(id), count))
.collect();
}
}
```
## Testing
I tested this by patching my local changes into my own bevy project. I
had a system that loads a scene file and executes some logic with a
Component that contains a `HashMap<Entity, UVec2>`, and it panics when
Entity is not found from another query. Since the 0.16 update this
system has reliably panicked upon attempting to the load the scene.
After patching my code in, I added `#[component(entities)]` to this
component, and I was able to successfully load the scene.
Additionally, I wrote a doc test.
## Call-outs
### Relationships
This overrules the default mapping of relationship fields. Anything else
seemed more problematic, as you'd have inconsistent behavior between
`MapEntities` and `Component`.