Commit Graph

1903 Commits

Author SHA1 Message Date
Trent
29cfad63a1
Fix typos (#19651)
Minor typo fix
2025-06-15 07:49:54 +00:00
urben1680
a292ac539e
System::check_change_tick and similar methods take CheckChangeTicks (#19600)
Follow-up of #19274.

Make the `check_change_tick` methods, of which some are now public, take
`CheckChangeTicks` to make it obvious where this tick comes from, see
other PR.

This also affects the `System` trait, hence the many changed files.

---------

Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
2025-06-13 19:24:27 +00:00
Chris Russell
bb4ea9c28b
Stop storing access for all systems (#19477)
# Objective

Reduce memory usage by storing fewer copies of
`FilteredAccessSet<ComponentId>`.

Currently, the `System` trait exposes the `component_access_set` for the
system, which is used by the multi-threaded executor to determine which
systems can run concurrently. But because it is available on the trait,
it needs to be stored for *every* system, even ones that are not run by
the executor! In particular, it is never needed for observers, or for
the inner systems in a `PipeSystem` or `CombinatorSystem`.


## Solution

Instead of exposing the access from a method on `System`, return it from
`System::initialize`. Since it is still needed during scheduling, store
the access alongside the boxed system in the schedule.

That's not quite enough for systems built using `SystemParamBuilder`s,
though. Those calculate the access in `SystemParamBuilder::build`, which
happens earlier than `System::initialize`. To handle those, we separate
`SystemParam::init_state` into `init_state`, which creates the state
value, and `init_access`, which calculates the access. This lets
`System::initialize` call `init_access` on a state that was provided by
the builder.

An additional benefit of that separation is that it removes the need to
duplicate access checks between `SystemParamBuilder::build` and
`SystemParam::init_state`.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-06-13 17:56:09 +00:00
Joel Singh
fa449e6267
Add example to Single docs (#19461) (#19603)
# Objective

- Add example to `Single` docs, highlighting that you can use methods
and properties directly.
- Fixes #19461

## Solution

- Added example to inline docs of `Single`

## Testing

- `cargo test --doc`
- `cargo doc --open`

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-06-13 00:46:11 +00:00
Alice Cecile
58c276ab44
Make the ObservedBy component useful to public consumers (#19591)
# Objective

As raised by @Jondolf, this type is `pub`, and useful for various
consumers to ensure cleanup or debugging.

However, it doesn't offer any way to actually view the data.

## Solution

- Add a read-only view of the data.
- Don't add any (easy) way to mutate the data, as this presents a huge
footgun.
- Implement Reflect and register the component so you can see it in
inspectors nicely.
2025-06-12 20:07:11 +00:00
Joona Aalto
e5dc177b4b
Rename Trigger to On (#19596)
# Objective

Currently, the observer API looks like this:

```rust
app.add_observer(|trigger: Trigger<Explode>| {
    info!("Entity {} exploded!", trigger.target());
});
```

Future plans for observers also include "multi-event observers" with a
trigger that looks like this (see [Cart's
example](https://github.com/bevyengine/bevy/issues/14649#issuecomment-2960402508)):

```rust
trigger: Trigger<(
    OnAdd<Pressed>,
    OnRemove<Pressed>,
    OnAdd<InteractionDisabled>,
    OnRemove<InteractionDisabled>,
    OnInsert<Hovered>,
)>,
```

In scenarios like this, there is a lot of repetition of `On`. These are
expected to be very high-traffic APIs especially in UI contexts, so
ergonomics and readability are critical.

By renaming `Trigger` to `On`, we can make these APIs read more cleanly
and get rid of the repetition:

```rust
app.add_observer(|trigger: On<Explode>| {
    info!("Entity {} exploded!", trigger.target());
});
```

```rust
trigger: On<(
    Add<Pressed>,
    Remove<Pressed>,
    Add<InteractionDisabled>,
    Remove<InteractionDisabled>,
    Insert<Hovered>,
)>,
```

Names like `On<Add<Pressed>>` emphasize the actual event listener nature
more than `Trigger<OnAdd<Pressed>>`, and look cleaner. This *also* frees
up the `Trigger` name if we want to use it for the observer event type,
splitting them out from buffered events (bikeshedding this is out of
scope for this PR though).

For prior art:
[`bevy_eventlistener`](https://github.com/aevyrie/bevy_eventlistener)
used
[`On`](https://docs.rs/bevy_eventlistener/latest/bevy_eventlistener/event_listener/struct.On.html)
for its event listener type. Though in our case, the observer is the
event listener, and `On` is just a type containing information about the
triggered event.

## Solution

Steal from `bevy_event_listener` by @aevyrie and use `On`.

- Rename `Trigger` to `On`
- Rename `OnAdd` to `Add`
- Rename `OnInsert` to `Insert`
- Rename `OnReplace` to `Replace`
- Rename `OnRemove` to `Remove`
- Rename `OnDespawn` to `Despawn`

## Discussion

### Naming Conflicts??

Using a name like `Add` might initially feel like a very bad idea, since
it risks conflict with `core::ops::Add`. However, I don't expect this to
be a big problem in practice.

- You rarely need to actually implement the `Add` trait, especially in
modules that would use the Bevy ECS.
- In the rare cases where you *do* get a conflict, it is very easy to
fix by just disambiguating, for example using `ops::Add`.
- The `Add` event is a struct while the `Add` trait is a trait (duh), so
the compiler error should be very obvious.

For the record, renaming `OnAdd` to `Add`, I got exactly *zero* errors
or conflicts within Bevy itself. But this is of course not entirely
representative of actual projects *using* Bevy.

You might then wonder, why not use `Added`? This would conflict with the
`Added` query filter, so it wouldn't work. Additionally, the current
naming convention for observer events does not use past tense.

### Documentation

This does make documentation slightly more awkward when referring to
`On` or its methods. Previous docs often referred to `Trigger::target`
or "sends a `Trigger`" (which is... a bit strange anyway), which would
now be `On::target` and "sends an observer `Event`".

You can see the diff in this PR to see some of the effects. I think it
should be fine though, we may just need to reword more documentation to
read better.
2025-06-12 18:22:33 +00:00
Alice Cecile
12f8f9c07c
Thoroughly document the current state of observers (#19590)
# Objective

The documentation for observers is not very good. This poses a problem
to users, but *also* causes serious problems for engine devs, as they
attempt to improve assorted issues surrounding observers.

This PR:

- Fixes #14084.
- Fixes #14726.
- Fixes #16538.
- Closes #18914, by attempting to solve the same issue.

To keep this PR at all reviewable, I've opted to simply note the various
limitations (some may call them bugs!) in place, rather than attempting
to fix them. There is a huge amount of cleanup work to be done here: see
https://github.com/orgs/bevyengine/projects/17.

## Solution

- Write good module docs for observers, offering bread crumbs to the
most common methods and techniques and comparing-and-contrasting as
needed.
- Fix any actively misleading documentation.
- Try to explain how the various bits of the (public?!) internals are
related.

---------

Co-authored-by: Chris Biscardi <chris@christopherbiscardi.com>
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
2025-06-11 22:04:52 +00:00
Alice Cecile
030edbf3fe
Rename bevy_ecs::world::Entry to ComponentEntry (#19517)
# Objective

As discussed in #19285, some of our names conflict. `Entry` in bevy_ecs
is one of those overly general names.

## Solution

Rename this type (and the related types) to `ComponentEntry`.

---------

Co-authored-by: urben1680 <55257931+urben1680@users.noreply.github.com>
2025-06-10 01:12:40 +00:00
Alice Cecile
6ddd0f16a8
Component lifecycle reorganization and documentation (#19543)
# Objective

I set out with one simple goal: clearly document the differences between
each of the component lifecycle events via module docs.

Unfortunately, no such module existed: the various lifecycle code was
scattered to the wind.
Without a unified module, it's very hard to discover the related types,
and there's nowhere good to put my shiny new documentation.

## Solution

1. Unify the assorted types into a single
`bevy_ecs::component_lifecycle` module.
2. Write docs.
3. Write a migration guide.

## Testing

Thanks CI!

## Follow-up

1. The lifecycle event names are pretty confusing, especially
`OnReplace`. We should consider renaming those. No bikeshedding in my PR
though!
2. Observers need real module docs too :(
3. Any additional functional changes should be done elsewhere; this is a
simple docs and re-org PR.

---------

Co-authored-by: theotherphil <phil.j.ellison@gmail.com>
2025-06-10 00:59:16 +00:00
Guillaume Wafo-Tapa
0e805eb49c
Implement SystemCondition for systems returning Result<bool, BevyError> and Result<(), BevyError> (#19553)
# Objective

Fixes #19403
As described in the issue, the objective is to support the use of
systems returning `Result<(), BevyError>` and
`Result<bool, BevyError>` as run conditions. In these cases, the run
condition would hold on `Ok(())` and `Ok(true)` respectively.


## Solution

`IntoSystem<In, bool, M>` cannot be implemented for systems returning
`Result<(), BevyError>` and `Result<bool, BevyError>` as that would
conflict with their trivial implementation of the trait. That led me to
add a method to the sealed trait `SystemCondition` that does the
conversion. In the original case of a system returning `bool`, the
system is returned as is. With the new types, the system is combined
with `map()` to obtain a `bool`.

By the way, I'm confused as to why `SystemCondition` has a generic `In`
parameter as it is only ever used with `In = ()` as far as I can tell.

## Testing

I added a simple test for both type of system. That's minimal but it
felt enough. I could not picture the more complicated tests passing for
a run condition returning `bool` and failing for the new types.

## Doc

I documenting the change on the page of the trait. I had trouble wording
it right but I'm not sure how to improve it. The phrasing "the condition
returns `true`" which reads naturally is now technically incorrect as
the new types return a `Result`. However, the underlying condition
system that the implementing system turns into does indeed return
`bool`. But talking about the implementation details felt too much.
Another possibility is to use another turn of phrase like "the condition
holds" or "the condition checks out". I've left "the condition returns
`true`" in the documentation of `run_if` and the provided methods for
now.

I'm perplexed about the examples. In the first one, why not implement
the condition directly instead of having a system returning it? Is it
from a time of Bevy where you had to implement your conditions that way?
In that case maybe that should be updated. And in the second example I'm
missing the point entirely. As I stated above, I've only seen conditions
used in contexts where they have no input parameter. Here we create a
condition with an input parameter (cannot be used by `run_if`) and we
are using it with `pipe()` which actually doesn't need our system to
implement `SystemCondition`. Both examples are also calling
`IntoSystem::into_system` which should not be encouraged. What am I
missing?
2025-06-10 00:04:10 +00:00
Lucas Franca
f5f092f2f3
Fix new typos (#19562)
# Objective

Fix new typos found on new version of `typos` (#19551)

## Solution

Fix typos
2025-06-09 22:55:14 +00:00
andriyDev
0381a798e2
Delete System::component_access(). (#19496)
# Objective

- Cleanup related to #19495.

## Solution

- Delete `System::component_access()`. It is redundant with
`System::component_access_set().combined_access()`.

## Testing

- None. There are no callers of this function.
2025-06-09 22:54:52 +00:00
Zion Klinger
a4dd873df8
Fix uninlined format argument lint (#19561)
# Objective
Fixes #19370 

## Solution
Implemented the lint as suggested by clippy.

## Testing
CI tests passed and lint was resolved.
2025-06-09 20:53:19 +00:00
urben1680
1294b71e35
Introduce CheckChangeTicks event that is triggered by World::check_change_ticks (#19274)
# Objective

In the past I had custom data structures containing `Tick`s. I learned
that these need to be regularly checked to clamp them. But there was no
way to hook into that logic so I abandoned storing ticks since then.

Another motivation to open this up some more is to be more able to do a
correct implementation of `System::check_ticks`.

## Solution

Add `CheckChangeTicks` and trigger it in `World::check_change_ticks`.
Make `Tick::check_tick` public.

This event makes it possible to store ticks in components or resources
and have them checked.

I also made `Schedules::check_change_ticks` public so users can store
schedules in custom resources/components for whatever reasons.

## Testing

The logic boils down to a single `World::trigger` call and I don't think
this needs more tests.

## Alternatives

Making this obsolete like with #15683.

---

## Showcase

From the added docs:

```rs
use bevy_ecs::prelude::*;
use bevy_ecs::component::CheckChangeTicks;

#[derive(Resource)]
struct CustomSchedule(Schedule);

let mut world = World::new();
world.add_observer(|tick: Trigger<CheckChangeTicks>, mut schedule: ResMut<CustomSchedule>| {
    schedule.0.check_change_ticks(tick.get());
});
```

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-06-09 20:44:49 +00:00
Marcel Müller
2768af5d2d
Allow not emitting BundleFromComponents with Bundle derive macro (#19249)
# Objective

Fixes #19136

## Solution

- Add a new container attribute which when set does not emit
`BundleFromComponents`

## Testing

- Did you test these changes?

Yes, a new test was added.

- Are there any parts that need more testing?

Since `BundleFromComponents` is unsafe I made extra sure that I did not
misunderstand its purpose. As far as I can tell, _not_ implementing it
is ok.

- How can other people (reviewers) test your changes? Is there anything
specific they need to know?

Nope

- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?

I don't think the platform is relevant

---



One thing I am not sure about is how to document this? I'll gladly add
it

---------

Signed-off-by: Marcel Müller <neikos@neikos.email>
2025-06-09 20:15:42 +00:00
Alice Cecile
155ebf7898
Write real docs for SystemSet (#19538)
# Objective

`SystemSet`s are surprisingly rich and nuanced, but are extremely poorly
documented.

Fixes #19536.

## Solution

Explain the basic concept of system sets, how to create them, and give
some opinionated advice about their more advanced functionality.

## Follow-up

I'd like proper module level docs on system ordering that I can link to
here, but they don't exist. Punting to follow-up!

---------

Co-authored-by: theotherphil <phil.j.ellison@gmail.com>
2025-06-09 20:03:02 +00:00
andriyDev
f163649b48
Use component_access_set to determine the set of conflicting accesses between two systems. (#19495)
# Objective

- Fixes #4381

## Solution

- Replace `component_access` with `component_access_set` when
determining conflicting systems during schedule building.
- All `component_access()` impls just forward to
`&component_access_set().combined_access`, so we are essentially trading
`Access::is_compatible` for `FilteredAccessSet::is_compatible`.
- `FilteredAccessSet::get_conflicts` internally calls
`combined_access.is_compatible` as the first step, so we can remove that
redundant check.

## Testing

- Un-ignored a previously failing test now that it passes!
- Ran the `build_schedule` benchmark and got basically no change in the
results. Perhaps are benchmarks are just not targetted towards this
situation.
```
$ critcmp main fix-ambiguity -f 'build_schedule'
group                                          fix-ambiguity                          main
-----                                          -------------                          ----
build_schedule/1000_schedule                   1.00       2.9±0.02s        ? ?/sec    1.01       2.9±0.05s        ? ?/sec
build_schedule/1000_schedule_no_constraints    1.02     48.3±1.48ms        ? ?/sec    1.00     47.4±1.78ms        ? ?/sec
build_schedule/100_schedule                    1.00      9.9±0.17ms        ? ?/sec    1.06     10.5±0.32ms        ? ?/sec
build_schedule/100_schedule_no_constraints     1.00   804.7±21.85µs        ? ?/sec    1.03   828.7±19.36µs        ? ?/sec
build_schedule/500_schedule                    1.00    451.7±7.25ms        ? ?/sec    1.04   468.9±11.70ms        ? ?/sec
build_schedule/500_schedule_no_constraints     1.02     12.7±0.46ms        ? ?/sec    1.00     12.5±0.44ms        ? ?/sec
```
2025-06-09 19:40:52 +00:00
Eagster
064e5e48b4
Remove entity placeholder from observers (#19440)
# Objective

`Entity::PLACEHOLDER` acts as a magic number that will *probably* never
really exist, but it certainly could. And, `Entity` has a niche, so the
only reason to use `PLACEHOLDER` is as an alternative to `MaybeUninit`
that trades safety risks for logic risks.

As a result, bevy has generally advised against using `PLACEHOLDER`, but
we still use if for a lot internally. This pr starts removing internal
uses of it, starting from observers.

## Solution

Change all trigger target related types from `Entity` to
`Option<Entity>`

Small migration guide to come.

## Testing

CI

## Future Work

This turned a lot of code from 

```rust
trigger.target()
```

to 

```rust
trigger.target().unwrap()
```

The extra panic is no worse than before; it's just earlier than
panicking after passing the placeholder to something else.

But this is kinda annoying. 

I would like to add a `TriggerMode` or something to `Event` that would
restrict what kinds of targets can be used for that event. Many events
like `Removed` etc, are always triggered with a target. We can make
those have a way to assume Some, etc. But I wanted to save that for a
future pr.
2025-06-09 19:37:56 +00:00
Sigma-dev
8cd53162bf
Add a despawn_children method to EntityWorldMut and EntityCommands (#19283)
# Objective

At the moment, if someone wants to despawn all the children of an
entity, they would need to use `despawn_related::<Children>();`.
In my opinion, this makes a very common operation less easily
discoverable and require some understanding of Entity Relationships.

## Solution

Adding a `despawn_children ` makes a very simple, discoverable and
readable way to despawn all the children while maintaining cohesion with
other similar methods.

## Testing

The implementation itself is very simple as it simply wraps around
`despawn_related` with `Children` as the generic type.
I gave it a quick try by modifying the parenting example and it worked
as expected.

---------

Co-authored-by: Zachary Harrold <zac@harrold.com.au>
2025-06-09 19:31:40 +00:00
theotherphil
20cd383b31
Mention Mut in QueryData docs, clarify behaviour of Mut vs &mut in Mut docs (#19254)
# Objective

- Fix https://github.com/bevyengine/bevy/issues/13843
- Clarify the difference between Mut and &mut when accessing query data

## Solution

- Mention `Mut` in `QueryData` docs as an example of a type that
implements this trait
- Give example of `iter_mut` vs `iter` access to `Mut` and `& mut`
parameters

## Testing

-
2025-06-09 19:21:04 +00:00
theotherphil
2bda628ecf
Clarify docs for transmute_lens functions (#19233)
# Objective

Make the restrictions of `transmute_lens` and related functions clearer.

Related issue: https://github.com/bevyengine/bevy/issues/12156
Related PR: https://github.com/bevyengine/bevy/pull/12157

## Solution

* Make it clearer that the set of returned entities is a subset of those
from the original query
* Move description of read/write/required access to a table
* Reference the new table in `transmute_lens` docs from the other
`transmute_lens*` functions

## Testing

cargo doc --open locally to check this render correctly

---------

Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
2025-06-09 19:10:59 +00:00
re0312
56f26cfb02
Unify system state (#19506)
# Objective

- A preparation for the 'system as entities'
- The current system has a series of states such as `is_send`,
`is_exclusive`, `has_defered`, As `system as entites` landed, it may
have more states. Using Bitflags to unify all states is a more concise
and performant approach

## Solution

- Using Bitflags to  unify system state.
2025-06-08 18:18:43 +00:00
theotherphil
6b5289bd5e
deny(missing_docs) for bevy_ecs_macros (#19523)
# Objective

Deny missing docs for bevy_ecs_macros, towards
https://github.com/bevyengine/bevy/issues/3492.

## Solution

More docs of the form

```
/// Does the thing
fn do_the_thing() {}
```

But I don't think the derive macros are where anyone is going to be
looking for details of these concepts and deny(missing_docs) inevitably
results in some items having noddy docs.
2025-06-08 16:28:31 +00:00
urben1680
76b8310da5
Replace (Partial)Ord for EntityGeneration with corrected standalone method (#19432)
# Objective

#19421 implemented `Ord` for `EntityGeneration` along the lines of [the
impl from
slotmap](https://docs.rs/slotmap/latest/src/slotmap/util.rs.html#8):
```rs
/// Returns if a is an older version than b, taking into account wrapping of
/// versions.
pub fn is_older_version(a: u32, b: u32) -> bool {
    let diff = a.wrapping_sub(b);
    diff >= (1 << 31)
}
```

But that PR and the slotmap impl are different:

**slotmap impl**
- if `(1u32 << 31)` is greater than `a.wrapping_sub(b)`, then `a` is
older than `b`
- if `(1u32 << 31)` is equal to `a.wrapping_sub(b)`, then `a` is older
than `b`
- if `(1u32 << 31)` is less than `a.wrapping_sub(b)`, then `a` is equal
or newer than `b`

**previous PR impl**
- if `(1u32 << 31)` is greater than `a.wrapping_sub(b)`, then `a` is
older than `b`
- if `(1u32 << 31)` is equal to `a.wrapping_sub(b)`, then `a` is equal
to `b` ⚠️
- if `(1u32 << 31)` is less than `a.wrapping_sub(b)`, then `a` is newer
than `b` ⚠️

This ordering is also not transitive, therefore it should not implement
`PartialOrd`.

## Solution

Fix the impl in a standalone method, remove the `Partialord`/`Ord`
implementation.

## Testing

Given the first impl was wrong and got past reviews, I think a new unit
test is justified.
2025-06-07 22:29:13 +00:00
re0312
5df9c53977
Fix regression on the get/get_mut/get_not_found (#19505)
# Objective

- Partial fix #19504
- As more features were added to Bevy ECS, certain core hot-path
function calls exceeded LLVM's automatic inlining threshold, leading to
significant performance regressions in some cases.



## Solution

- inline more functions.


## Performance
This brought nearly 3x improvement in Windows bench (using Sander's
testing code)

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-06-06 21:04:27 +00:00
Eagster
8ad7118443
Only get valid component ids (#19510)
# Objective

- #19504 showed a 11x regression in getting component values for
unregistered components. This pr should fix that and improve others a
little too.
- This is some cleanup work from #18173 .

## Solution

- Whenever we expect a component value to exist, we only care about
fully registered components, not queued to be registered components
since, for the value to exist, it must be registered.
- So we can use the faster `get_valid_*` instead of `get_*` in a lot of
places.
- Also found a bug where `valid_*` did not forward to `get_valid_*`
properly. That's fixed.

## Testing

CI
2025-06-06 20:59:57 +00:00
Carter Anderson
7e9d6d852b
bevyengine.org -> bevy.org (#19503)
We have acquired [bevy.org](https://bevy.org) and the migration has
finished! Meaning we can now update all of the references in this repo.
2025-06-05 23:09:28 +00:00
Chris Russell
bd4c960f26
Mention Option and When in the error message for a failing system parameter (#19490)
# Objective

Help users discover how to use `Option<T>` and `When<T>` to handle
failing parameters.

## Solution

Have the error message for a failed parameter mention that `Option<T>`
and `When<T>` can be used to handle the failure.

## Showcase

```
Encountered an error in system `system_name`: Parameter `Res<ResourceType>` failed validation: Resource does not exist
If this is an expected state, wrap the parameter in `Option<T>` and handle `None` when it happens, or wrap the parameter in `When<T>` to skip the system when it happens.
```
2025-06-04 16:39:54 +00:00
François Mockers
7a7bff8c17
Hot patching systems with subsecond (#19309)
# Objective

- Enable hot patching systems with subsecond
- Fixes #19296 

## Solution

- First commit is the naive thin layer
- Second commit only check the jump table when the code is hot patched
instead of on every system execution
- Depends on https://github.com/DioxusLabs/dioxus/pull/4153 for a nicer
API, but could be done without
- Everything in second commit is feature gated, it has no impact when
the feature is not enabled

## Testing

- Check dependencies without the feature enabled: nothing dioxus in tree
- Run the new example: text and color can be changed

---------

Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
Co-authored-by: JMS55 <47158642+JMS55@users.noreply.github.com>
2025-06-03 21:12:38 +00:00
re0312
50aa40e980
Trigger ArchetypeCreated event when new archetype is created (#19455)
# Objective

- Part 1 of #19454 .
- Split from PR #18860(authored by @notmd) for better review and limit
implementation impact. so all credit for this work belongs to @notmd .

## Solution

- Trigger `ArchetypeCreated ` when new archetype is createed

---------

Co-authored-by: mgi388 <135186256+mgi388@users.noreply.github.com>
2025-06-02 22:27:45 +00:00
zacryol
4d4170d834
Implement IntoIterator for Populated and borrows (#19441)
# Objective

`Populated`, a loose wrapper around `Query`, does not implement
`IntoIterator`, requiring either a deref or `into_inner()` call to
access the `Query` and iterate over that.

## Solution

This pr implements `IntoIterator` for `Populated`, `&Populated`, and
`&mut Populated`, each of which forwards the call to the inner `Query`.
This allows the `Populated` to be used directly for any API that takes
an `impl IntoIterator`.

## Testing

`cargo test` was run on the `bevy_ecs` crate
```
test result: ok. 390 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 46.38s
```
2025-06-02 22:19:43 +00:00
AlephCubed
415f6d8ca7
Simplified on_replace and on_despawn relationship hooks. (#19378)
Fixes #18364.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-06-02 22:15:18 +00:00
Eagster
61bd3af7c7
Remove invalid entity locations (#19433)
# Objective

This is the first step of #19430 and is a follow up for #19132.

Now that `ArchetypeRow` has a niche, we can use `Option` instead of
needing `INVALID` everywhere.

This was especially concerning since `INVALID` *really was valid!*

Using options here made the code clearer and more data-driven. 

## Solution

Replace all uses of `INVALID` entity locations (and archetype/table
rows) with `None`.

## Testing

CI

---------

Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-05-31 16:34:33 +00:00
eugineerd
0694743d8d
Fix EntityCloner replacing required components. (#19326)
# Objective
Fix #19324

## Solution
`EntityCloner` replaces required components when filtering. This is
unexpected when comparing with the way the rest of bevy handles required
components. This PR separates required components from explicit
components when filtering in `EntityClonerBuilder`.

## Testing
Added a regression test for this case.
2025-05-30 19:28:53 +00:00
theotherphil
0ee8bf978c
Clarify Resource change detection behaviour in condition docs (#19252)
# Objective

Fixes https://github.com/bevyengine/bevy/issues/17933

## Solution

Correct "value has changed'" in docs to "value has been added or mutably
dereferenced", with a note for emphasis copied from the docs for
Changed.

## Testing

-
2025-05-30 00:47:25 +00:00
Eagster
1966e44400
EntityGeneration ordering (#19421)
# Objective

Recently the `u32` `Entity::generation` was replaced with the new
`EntityGeneration` in #19121.
This made meanings a lot more clear, and prevented accidental misuse.

One common misuse was assuming that `u32`s that were greater than others
came after those others.
Wrapping makes this assumption false.
When `EntityGeneration` was created, it retained the `u32` ordering,
which was useless at best and wrong at worst.
This pr fixes the ordering implementation, so new generations are
greater than older generations.

Some users were already accounting for this ordering issue (which was
still present in 0.16 and before) by manually accessing the `u32`
representation. This made migrating difficult for avian physics; see
[here](https://discord.com/channels/691052431525675048/749335865876021248/1377431569228103780).

I am generally of the opinion that this type should be kept opaque to
prevent accidental misuse.
As we find issues like this, the functionality should be added to
`EntityGeneration` directly.

## Solution

Fix the ordering implementation through `Ord`.

Alternatively, we could keep `Ord` the same and make a `cmp_age` method,
but I think this is better, even though sorting entity ids may be
*marginally* slower now (but more correct). This is a tradeoff.

## Testing

I improved documentation for aliasing and ordering, adding some doc
tests.
2025-05-29 05:48:32 +00:00
SpecificProtagonist
a266e7e642
More uninlined_format_args fixes (#19396)
# Objective

There are several uninlined format args (seems to be in more formatting
macros and in more crates) that are not detected on stable, but are on
nightly.

## Solution

Fix them.
2025-05-28 02:35:18 +00:00
SpecificProtagonist
13e89a1678
Fix EntityMeta.spawned_or_despawned unsoundness (#19350)
# Objective

#19047 added an `MaybeUninit` field to `EntityMeta`, but did not
guarantee that it will be initialized before access:

```rust
let mut world = World::new();
let id = world.entities().reserve_entity();
world.flush();
world.entity(id);
```

<details>
<summary>Miri Error</summary>

```
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
    --> /home/vj/workspace/rust/bevy/crates/bevy_ecs/src/entity/mod.rs:1121:26
     |
1121 |                 unsafe { meta.spawned_or_despawned.assume_init() }
     |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
     |
     = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
     = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
     = note: BACKTRACE:
     = note: inside closure at /home/vj/workspace/rust/bevy/crates/bevy_ecs/src/entity/mod.rs:1121:26: 1121:65
     = note: inside `std::option::Option::<&bevy_ecs::entity::EntityMeta>::map::<bevy_ecs::entity::SpawnedOrDespawned, {closure@bevy_ecs::entity::Entities::entity_get_spawned_or_despawned::{closure#1}}>` at /home/vj/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:1144:29: 1144:33
     = note: inside `bevy_ecs::entity::Entities::entity_get_spawned_or_despawned` at /home/vj/workspace/rust/bevy/crates/bevy_ecs/src/entity/mod.rs:1112:9: 1122:15
     = note: inside closure at /home/vj/workspace/rust/bevy/crates/bevy_ecs/src/entity/mod.rs:1094:13: 1094:57
     = note: inside `bevy_ecs::change_detection::MaybeLocation::<std::option::Option<&std::panic::Location<'_>>>::new_with_flattened::<{closure@bevy_ecs::entity::Entities::entity_get_spawned_or_despawned_by::{closure#0}}>` at /home/vj/workspace/rust/bevy/crates/bevy_ecs/src/change_detection.rs:1371:20: 1371:24
     = note: inside `bevy_ecs::entity::Entities::entity_get_spawned_or_despawned_by` at /home/vj/workspace/rust/bevy/crates/bevy_ecs/src/entity/mod.rs:1093:9: 1096:11
     = note: inside `bevy_ecs::entity::Entities::entity_does_not_exist_error_details` at /home/vj/workspace/rust/bevy/crates/bevy_ecs/src/entity/mod.rs:1163:23: 1163:70
     = note: inside `bevy_ecs::entity::EntityDoesNotExistError::new` at /home/vj/workspace/rust/bevy/crates/bevy_ecs/src/entity/mod.rs:1182:22: 1182:74
     = note: inside `bevy_ecs::world::unsafe_world_cell::UnsafeWorldCell::<'_>::get_entity` at /home/vj/workspace/rust/bevy/crates/bevy_ecs/src/world/unsafe_world_cell.rs:368:20: 368:73
     = note: inside `<bevy_ecs::entity::Entity as bevy_ecs::world::WorldEntityFetch>::fetch_ref` at /home/vj/workspace/rust/bevy/crates/bevy_ecs/src/world/entity_fetch.rs:207:21: 207:42
     = note: inside `bevy_ecs::world::World::get_entity::<bevy_ecs::entity::Entity>` at /home/vj/workspace/rust/bevy/crates/bevy_ecs/src/world/mod.rs:911:18: 911:42
note: inside `main`
    --> src/main.rs:12:15
     |
12   |     world.entity(id);
     |
```

</details>

## Solution

- remove the existing `MaybeUninit` in `EntityMeta.spawned_or_despawned`
- initialize during flush. This is not needed for soundness, but not
doing this means we can't return a sensible location/tick for flushed
entities.

## Testing

Test via the snippet above (also added equivalent test).

---------

Co-authored-by: urben1680 <55257931+urben1680@users.noreply.github.com>
2025-05-27 22:45:07 +00:00
HeartofPhos
131f99de23
Fix custom relations panics with parent/child relations (#19341)
# Objective

Fixes #18905

## Solution

`world.commands().entity(target_entity).queue(command)` calls
`commands.with_entity` without an error handler, instead queue on
`Commands` with an error handler

## Testing

Added unit test

Co-authored-by: Heart <>
2025-05-27 21:05:31 +00:00
Chris Russell
571b3ba475
Remove ArchetypeComponentId and archetype_component_access (#19143)
# Objective

Remove `ArchetypeComponentId` and `archetype_component_access`.
Following #16885, they are no longer used by the engine, so we can stop
spending time calculating them or space storing them.

## Solution

Remove `ArchetypeComponentId` and everything that touches it.  

The `System::update_archetype_component_access` method no longer needs
to update `archetype_component_access`. We do still need to update query
caches, but we no longer need to do so *before* running the system. We'd
have to touch every caller anyway if we gave the method a better name,
so just remove `System::update_archetype_component_access` and
`SystemParam::new_archetype` entirely, and update the query cache in
`Query::get_param`.

The `Single` and `Populated` params also need their query caches updated
in `SystemParam::validate_param`, so change `validate_param` to take
`&mut Self::State` instead of `&Self::State`.
2025-05-27 19:04:32 +00:00
atlv
d4985af7cb
refactor(utils): move SyncCell and SyncUnsafeCell to bevy_platform (#19305)
# Objective

- move SyncCell and SyncUnsafeCell to bevy_platform

## Solution

- move SyncCell and SyncUnsafeCell to bevy_platform

## Testing

- cargo clippy works
2025-05-27 04:57:26 +00:00
AlephCubed
7d32dfec18
Add insert_if_new test for sparse set. (#19387)
Fixes #19081.
Simply created a duplicate of the existing `insert_if_new` test, but
using sparse sets.

## Testing:
The test passes on main, but fails if #19059 is reverted.
2025-05-27 03:15:30 +00:00
theotherphil
16a286dac3
Update .entry() docs to show both insert-then-modify and modify-or-insert examples (#19327)
# Objective

Fix https://github.com/bevyengine/bevy/issues/16379
2025-05-26 20:27:20 +00:00
SpecificProtagonist
158d9aff0e
Fix spawn tracking for spawn commands (#19351)
# Objective

See also
https://discord.com/channels/691052431525675048/1374187654425481266/1375553989185372292.

## Solution

Set spawn info in `Commands::spawn_empty`.
Also added a benchmark for `Commands::spawn`.

## Testing

See added test.
2025-05-26 20:15:21 +00:00
theotherphil
54c9f03021
Mention in .add_observer() docs that first parameter must be a Trigger (#19315)
# Objective

Fix https://github.com/bevyengine/bevy/issues/13860

## Solution

Add note in docs that Trigger must be the first parameter of observer
systems
2025-05-26 20:06:08 +00:00
theotherphil
f8cb8f237d
Fix a few typos in bevy_ecs docs (#19280)
# Objective

Fix a few minor typos that I noticed when reading the docs.
2025-05-26 20:02:13 +00:00
theotherphil
3690ad5b0b
Remove apostrophes in possessive its (#19244)
# Objective

Fix some grammatical errors: it's -> its

Not the most useful commit in the world, but I saw a couple of these and
decided to fix the lot.

## Solution
-

## Testing
-
2025-05-26 19:53:14 +00:00
theotherphil
a521998eea
Make remove_reflect parameter names consistent between ReflectCommandExt and impl for EntityCommands (#19243)
# Objective

Fix https://github.com/bevyengine/bevy/issues/13390

## Solution

The second parameter of the remove_reflect function is called
component_type_name in ReflectCommandExt but component_type_path in the
implementation for EntityCommands. Use component_type_path in both
places.

## Testing

None
2025-05-26 19:49:56 +00:00
urben1680
b92c0ebd3d
No schedule build pass overwrite if build settings do not change auto_insert_apply_deferred from true (#19217)
# Objective

Fixes #18790.
Simpler alternative to #19195.

## Solution

As suggested by @PixelDust22, simply avoid overwriting the pass if the
schedule already has auto sync points enabled.
Leave pass logic untouched.

It still is probably a bad idea to add systems/set configs before
changing the build settings, but that is not important as long there are
no more complex build passes.

## Testing

Added a test.

---------

Co-authored-by: Thierry Berger <contact@thierryberger.com>
2025-05-26 19:28:56 +00:00
Eagster
b6b54912fa
Nonmax all rows (#19132)
# Objective

Since #18704 is done, we can track the length of unique entity row
collections with only a `u32` and identify an index within that
collection with only a `NonMaxU32`. This leaves an opportunity for
performance improvements.

## Solution

- Use `EntityRow` in sparse sets.
- Change table, entity, and query lengths to be `u32` instead of
`usize`.
- Keep `batching` module `usize` based since that is reused for events,
which may exceed `u32::MAX`.
- Change according `Range<usize>` to `Range<u32>`. This is more
efficient and helps justify safety.
- Change `ArchetypeRow` and `TableRow` to wrap `NonMaxU32` instead of
`u32`.

Justifying `NonMaxU32::new_unchecked` everywhere is predicated on this
safety comment in `Entities::set`: "`location` must be valid for the
entity at `index` or immediately made valid afterwards before handing
control to unknown code." This ensures no entity is in two table rows
for example. That fact is used to argue uniqueness of the entity rows in
each table, archetype, sparse set, query, etc. So if there's no
duplicates, and a maximum total entities of `u32::MAX` none of the
corresponding row ids / indexes can exceed `NonMaxU32`.

## Testing

CI

---------

Co-authored-by: Christian Hughes <9044780+ItsDoot@users.noreply.github.com>
2025-05-26 17:39:55 +00:00