Commit Graph

1852 Commits

Author SHA1 Message Date
Periwink
f33074116b
Make SystemChangeTick Clone (#18991)
# Objective

It can be useful to store the `SystemChangeTick` for a given System. I
wanted to copy them but I noticed that it doesn't implement Clone.
2025-05-26 15:43:06 +00:00
Tim
4924cf5828
Remove upcasting methods + Cleanup interned label code (#18984)
Hiya!

# Objective

- Remove upcasting methods that are no longer necessary since Rust 1.86.
- Cleanup the interned label code.
 
## Notes
- I didn't try to remove the upcasting methods from `bevy_reflect`, as
there appears to be some complexity related to remote type reflection.
- There are likely some other upcasting methods floating around.

## Testing
I ran the `breakout` example to check that the hashing/eq
implementations of the labels are still correct.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-05-26 15:38:12 +00:00
Jakob Hellermann
93b8f9a303
bevy_ecs: forward type_id in InfallibleSystemWrapper (#18931)
similar to https://github.com/bevyengine/bevy/pull/12030

# Objective

`bevy_mod_debugdump` uses the `SystemTypeSet::system_type` to look up
constrains like `(system_1, system_2.after(system_1))`. For that it
needs to find the type id in `schedule.graph().systems()`

Now with systems being wrapped in an `InfallibleSystemWrapper` this
association was no longer possible.

## Solution

By forwarding the type id in `InfallibleSystemWrapper`,
`bevy_mod_debugdump` can resolve the dependencies as before, and the
wrapper is an unnoticable implementation detail.

## Testing

- `cargo test -p bevy_ecs`
I'm not sure what exactly could break otherwise.
2025-05-26 15:33:05 +00:00
Zachary Harrold
3d3746e5d0
Simplify bevy_utils Features (#19090)
# Objective

Now that `bevy_platform::cfg` is merged, we can start tidying up
features. This PR starts with `bevy_utils`.

## Solution

- Removed `serde` and `critical-section` features (they were just
re-exports of `bevy_platform` anyway)
- Removed `std`, `alloc` features, relying on `bevy_platform::cfg` to
check for availability.
- Added `parallel` feature to provide access to the `Parallel` type.
- Moved the `HashMap` type aliases into `map.rs` for better
organisation.

## Testing

- CI
2025-05-24 01:46:11 +00:00
theotherphil
88e73f8eda
Fix one-character typo in SystemParam docs (#19338)
# Objective

Remove errant "a" from docs.

(I'm assuming that this sort of trivial fix is easy enough to merge that
it's worth doing, but let me know if you'd prefer me to not bother.)
2025-05-22 18:54:02 +00:00
Lucas
e2d087551e
feat: derive Serialize on Childof (#19336)
# Objective

allow serialization / deserialization on the `ChildOf` entity, for
example in network usage.
my usage was for the bevy_replicon crate, to replicate `ChildOf`.

## Solution

same implementation of serde as other types in the bevy repo

---------

Co-authored-by: Hennadii Chernyshchyk <genaloner@gmail.com>
2025-05-22 18:30:14 +00:00
Kevin Reid
870ad21238
Add documentation and examples of [ScheduleLabel] usage. (#19329)
## Objective

Add documentation useful to users of `bevy_ecs` not also using `App`.

Fixes #19270.

## Solution

* Add explanation of labels to `Schedule` documentation.
* Add example of `derive(ScheduleLabel)` to `trait ScheduleLabel`.
* Add a third example to `Schedule` which demonstrates using a schedule
via label instead of owning it directly.
* Add further explanation and links to `World::add_schedule()`, and
`World::run_schedule()`.

## Testing

Reviewed generated documentation.

Please review this documentation carefully for correctness, as I have
little experience with `bevy_ecs` and I am adding this information
because it would have helped my own past confusion, but I may still be
wrong about how things should be done.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: theotherphil <phil.j.ellison@gmail.com>
2025-05-22 15:55:35 +00:00
stevehello166
c9e69ac65e
Rename Condition to SystemCondition` (#19328)
# Objective
Fixes #19120 

## Solution
Use the find and replace token feature in VSCode to replace all the
`Condition`s with `SystemCondition`s. Then look through all the
documentation with find and replace to replace all the `Condition`s
there.

## Testing

- Did you test these changes? If so, how?
Yes, used cargo clippy, cargo build and cargo test.
- Are there any parts that need more testing?
Nope
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
By compiling and running bevy
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
Shouldn't be, but Fedora Linux with KDE Wayland
2025-05-22 15:50:19 +00:00
theotherphil
70e6a9010d
Add missing words in Traversal doc comment (#19298)
# Objective

Minor docs fix - add missing "is responsible".
2025-05-19 19:34:59 +00:00
SpecificProtagonist
e7e9973c80
Per world error handler (#18810)
# Objective

[see original
comment](https://github.com/bevyengine/bevy/pull/18801#issuecomment-2796981745)
> Alternately, could we store it on the World instead of a global? I
think we have a World nearby whenever we call default_error_handler().
That would avoid the need for atomics or locks, since we could do
ordinary reads and writes to the World.

Global error handlers don't actually need to be global – per world is
enough. This allows using different handlers for different worlds and
also removes the restrictions on changing the handler only once.

## Solution

Each `World` can now store its own error handler in a resource.

For convenience, you can also set the default error handler for an
`App`, which applies it to the worlds of all `SubApp`s. The old behavior
of only being able to set the error handler once is kept for apps.

We also don't need the `configurable_error_handler` feature anymore now.

## Testing

New/adjusted tests for failing schedule systems & observers.

---

## Showcase

```rust
App::new()
    .set_error_handler(info)
    …
```
2025-05-19 01:35:07 +00:00
atlv
415ffa5028
clippy: expect large variants and other small fixes (#19222)
# Objective

- Fix CI

## Solution

- Expect new lint
- See #19220

## Testing

- cargo clippy
2025-05-15 22:29:59 +00:00
mgi388
01d2b8571c
Remove dead states code from bevy_ecs (#19210)
`bevy_ecs` was meant to have the `States` and `SubStates`
`proc_macro_derive`s removed when the separate `bevy_state` [was
created](https://github.com/bevyengine/bevy/issues/13216) but they were
missed.
2025-05-14 13:19:20 +00:00
Jordan Dominion
86cc02dca2
Fix macro pollution in SystemParam derive (#19155)
# Objective

Fixes #19130 

## Solution

Fully quality `Result::Ok` so as to not accidentally invoke the anyhow
function of the same name

## Testing

Tested on this minimal repro with and without change.

main.rs
```rs
use anyhow::Ok;
use bevy::ecs::system::SystemParam;

#[derive(SystemParam)]
pub struct SomeParams;

fn main() {
}
```
Cargo.toml
```toml
[package]
name = "bevy-playground"
version = "0.1.0"
edition = "2024"

[dependencies]
anyhow = "1.0.98"
bevy = { path = "../bevy" }
```
2025-05-10 02:45:25 +00:00
databasedav
95470df3c8
fix .insert_related index bound (#19134)
# Objective

resolves #19092

## Solution

- remove the `.saturating_sub` from the index transformation
- add `.saturating_add` to the internal offset calculation

## Testing

- added regression test, confirming 0 index order + testing max bound
2025-05-09 17:10:54 +00:00
urben1680
732b2e0c79
Track spawn Tick of entities, offer methods, query data SpawnDetails and query filter Spawned (#19047)
# Objective

In my own project I was encountering the issue to find out which
entities were spawned after applying commands. I began maintaining a
vector of all entities with generational information before and after
applying the command and diffing it. This was awfully complicated though
and has no constant complexity but grows with the number of entities.

## Solution

Looking at `EntyMeta` it seemed obvious to me that struct can track the
tick just as it does with `MaybeLocation`, updated from the same call.
After that it became almost a given to also introduce query data
`SpawnDetails` which offers methods to get the spawn tick and location,
and query filter `Spawned` that filters entities out that were not
spawned since the last run.

## Testing

I expanded a few tests and added new ones, though maybe I forgot a group
of tests that should be extended too. I basically searched `bevy_ecs`
for mentions of `Changed` and `Added` to see where the tests and docs
are.

Benchmarks of spawn/despawn can be found
[here](https://github.com/bevyengine/bevy/pull/19047#issuecomment-2852181374).

---

## Showcase

From the added docs, systems with equal complexity since the filter is
not archetypal:
```rs
fn system1(q: Query<Entity, Spawned>) {
    for entity in &q { /* entity spawned */ }
}

fn system2(query: Query<(Entity, SpawnDetails)>) {
    for (entity, spawned) in &query {
        if spawned.is_spawned() { /* entity spawned */ }
    }
}
```

`SpawnedDetails` has a few more methods:

```rs
fn print_spawn_details(query: Query<(Entity, SpawnDetails)>) {
    for (entity, spawn_details) in &query {
        if spawn_details.is_spawned() {
            print!("new ");
        }
        println!(
            "entity {:?} spawned at {:?} by {:?}",
            entity,
            spawn_details.spawned_at(),
            spawn_details.spawned_by()
        );        
    }
}
```

## Changes

No public api was changed, I only added to it. That is why I added no
migration guide.

- query data `SpawnDetails`
- query filter `Spawned`
- method `Entities::entity_get_spawned_or_despawned_at`
- method `EntityRef::spawned_at`
- method `EntityMut::spawned_at`
- method `EntityWorldMut::spawned_at`
- method `UnsafeEntityCell::spawned_at`
- method `FilteredEntityRef::spawned_at`
- method `FilteredEntityMut::spawned_at`
- method `EntityRefExcept::spawned_at`
- method `EntityMutExcept::spawned_at`

---------

Co-authored-by: Eagster <79881080+ElliottjPierce@users.noreply.github.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-05-08 14:57:33 +00:00
Eagster
12aba64900
Make entity generation a new type and remove identifier (#19121)
# Objective

This is a followup to #18704 . There's lots more followup work, but this
is the minimum to unblock #18670, etc.

This direction has been given the green light by Alice
[here](https://github.com/bevyengine/bevy/pull/18704#issuecomment-2853368129).

## Solution

I could have split this over multiple PRs, but I figured skipping
straight here would be easiest for everyone and would unblock things the
quickest.

This removes the now no longer needed `identifier` module and makes
`Entity::generation` go from `NonZeroU32` to `struct
EntityGeneration(u32)`.

## Testing

CI

---------

Co-authored-by: Mark Nokalt <marknokalt@live.com>
2025-05-08 04:03:05 +00:00
Eagster
0b4858726c
Make entity::index non max (#18704)
# Objective

There are two problems this aims to solve. 

First, `Entity::index` is currently a `u32`. That means there are
`u32::MAX + 1` possible entities. Not only is that awkward, but it also
make `Entity` allocation more difficult. I discovered this while working
on remote entity reservation, but even on main, `Entities` doesn't
handle the `u32::MAX + 1` entity very well. It can not be batch reserved
because that iterator uses exclusive ranges, which has a maximum upper
bound of `u32::MAX - 1`. In other words, having `u32::MAX` as a valid
index can be thought of as a bug right now. We either need to make that
invalid (this PR), which makes Entity allocation cleaner and makes
remote reservation easier (because the length only needs to be u32
instead of u64, which, in atomics is a big deal), or we need to take
another pass at `Entities` to make it handle the `u32::MAX` index
properly.

Second, `TableRow`, `ArchetypeRow` and `EntityIndex` (a type alias for
u32) all have `u32` as the underlying type. That means using these as
the index type in a `SparseSet` uses 64 bits for the sparse list because
it stores `Option<IndexType>`. By using `NonMaxU32` here, we cut the
memory of that list in half. To my knowledge, `EntityIndex` is the only
thing that would really benefit from this niche. `TableRow` and
`ArchetypeRow` I think are not stored in an `Option` in bulk. But if
they ever are, this would help. Additionally this ensures
`TableRow::INVALID` and `ArchetypeRow::INVALID` never conflict with an
actual row, which in a nice bonus.

As a related note, if we do components as entities where `ComponentId`
becomes `Entity`, the the `SparseSet<ComponentId>` will see a similar
memory improvement too.

## Solution

Create a new type `EntityRow` that wraps `NonMaxU32`, similar to
`TableRow` and `ArchetypeRow`.
Change `Entity::index` to this type.

## Downsides

`NonMax` is implemented as a `NonZero` with a binary inversion. That
means accessing and storing the value takes one more instruction. I
don't think that's a big deal, but it's worth mentioning.

As a consequence, `to_bits` uses `transmute` to skip the inversion which
keeps it a nop. But that also means that ordering has now flipped. In
other words, higher indices are considered less than lower indices. I
don't think that's a problem, but it's also worth mentioning.

## Alternatives

We could keep the index as a u32 type and just document that `u32::MAX`
is invalid, modifying `Entities` to ensure it never gets handed out.
(But that's not enforced by the type system.) We could still take
advantage of the niche here in `ComponentSparseSet`. We'd just need some
unsafe manual conversions, which is probably fine, but opens up the
possibility for correctness problems later.

We could change `Entities` to fully support the `u32::MAX` index. (But
that makes `Entities` more complex and potentially slightly slower.)

## Testing

- CI
- A few tests were changed because they depend on different ordering and
`to_bits` values.

## Future Work

- It might be worth removing the niche on `Entity::generation` since
there is now a different niche.
- We could move `Entity::generation` into it's own type too for clarity.
- We should change `ComponentSparseSet` to take advantage of the new
niche. (This PR doesn't change that yet.)
- Consider removing or updating `Identifier`. This is only used for
`Entity`, so it might be worth combining since `Entity` is now more
unique.

---------

Co-authored-by: atlv <email@atlasdostal.com>
Co-authored-by: Zachary Harrold <zac@harrold.com.au>
2025-05-07 18:20:30 +00:00
Chris Russell
9e2bd8ac18
Generic SystemParam impls for Option and Result (#18766)
# Objective

Provide a generic `impl SystemParam for Option<P>` that uses system
parameter validation. This immediately gives useful impls for params
like `EventReader` and `GizmosState` that are defined in terms of `Res`.
It also allows third-party system parameters to be usable with `Option`,
which was previously impossible due to orphan rules.

Note that this is a behavior change for `Option<Single>`. It currently
fails validation if there are multiple matching entities, but with this
change it will pass validation and produce `None`.

Also provide an impl for `Result<P, SystemParamValidationError>`. This
allows systems to inspect the error if necessary, either for bubbling it
up or for checking the `skipped` flag.

Fixes #12634
Fixes #14949
Related to #18516

## Solution

Add generic `SystemParam` impls for `Option` and `Result`, and remove
the impls for specific types.

Update documentation and `fallible_params` example with the new
semantics for `Option<Single>`.
2025-05-07 18:20:08 +00:00
Periwink
60ea43d01d
Add system ticks to EntityRef/Mut WorldQuery (#19115)
# Objective

- Fixes a subset of https://github.com/bevyengine/bevy/issues/13735 by
making `EntityRef`, `EntityMut` + similar WorldQueries use the system's
change ticks when being created from within a system.
In particular, this means that `entity_ref.get_ref::<T>()` will use the
correct change ticks (the ones from the system), which matches the
behaviour of querying for `Ref<T>` directly in the system parameters.

## Solution

- Implements the solution described by
https://github.com/bevyengine/bevy/issues/13735#issuecomment-2652482918
which is to add change ticks to the `UnsafeEntityCell`

## Testing

- Added a unit test that is close to what users would encounter: before
this PR the `Added`/`Changed` filters on `Ref`s created from `EntityRef`
are incorrect.
2025-05-07 18:19:35 +00:00
Zachary Harrold
63e78fe489
Deprecated Begone! 0.16 Cleanup (#19108)
# Objective

A fair few items were deprecated in 0.16. Let's delete them now that
we're in the 0.17 development cycle!

## Solution

- Deleted items marked deprecated in 0.16.

## Testing

- CI

---

## Notes

I'm making the assumption that _everything_ deprecated in 0.16 should be
removed in 0.17. That may be a false assumption in certain cases. Please
check the items to be removed to see if there are any exceptions we
should keep around for another cycle!
2025-05-07 18:17:41 +00:00
Zachary Harrold
4051465b06
Make NonSendMarker !Send (#19107)
# Objective

In #18301, `NonSendMarker` was defined in such a way that it actually
implements `Send`. This isn't strictly a soundness issue, as its goal is
to be used as a `SystemParam`, and it _does_ appropriately mark system
access as `!Send`. It just seems odd that `NonSendMarker: Send`.

## Solution

- Made `NonSendMarker` wrap `PhantomData<*mut ()>`, which forces it to
be `!Send`.

## Testing

- CI

---

## Notes

This does mean constructing a `NonSendMarker` _value_ will require using
the `SystemParam` trait, but I think that's acceptable as the marker as
a value should be rarely required if at all.
2025-05-07 00:40:35 +00:00
Joona Aalto
7b1c9f192e
Adopt consistent FooSystems naming convention for system sets (#18900)
# Objective

Fixes a part of #14274.

Bevy has an incredibly inconsistent naming convention for its system
sets, both internally and across the ecosystem.

<img alt="System sets in Bevy"
src="https://github.com/user-attachments/assets/d16e2027-793f-4ba4-9cc9-e780b14a5a1b"
width="450" />

*Names of public system set types in Bevy*

Most Bevy types use a naming of `FooSystem` or just `Foo`, but there are
also a few `FooSystems` and `FooSet` types. In ecosystem crates on the
other hand, `FooSet` is perhaps the most commonly used name in general.
Conventions being so wildly inconsistent can make it harder for users to
pick names for their own types, to search for system sets on docs.rs, or
to even discern which types *are* system sets.

To reign in the inconsistency a bit and help unify the ecosystem, it
would be good to establish a common recommended naming convention for
system sets in Bevy itself, similar to how plugins are commonly suffixed
with `Plugin` (ex: `TimePlugin`). By adopting a consistent naming
convention in first-party Bevy, we can softly nudge ecosystem crates to
follow suit (for types where it makes sense to do so).

Choosing a naming convention is also relevant now, as the [`bevy_cli`
recently adopted
lints](https://github.com/TheBevyFlock/bevy_cli/pull/345) to enforce
naming for plugins and system sets, and the recommended naming used for
system sets is still a bit open.

## Which Name To Use?

Now the contentious part: what naming convention should we actually
adopt?

This was discussed on the Bevy Discord at the end of last year, starting
[here](<https://discord.com/channels/691052431525675048/692572690833473578/1310659954683936789>).
`FooSet` and `FooSystems` were the clear favorites, with `FooSet` very
narrowly winning an unofficial poll. However, it seems to me like the
consensus was broadly moving towards `FooSystems` at the end and after
the poll, with Cart
([source](https://discord.com/channels/691052431525675048/692572690833473578/1311140204974706708))
and later Alice
([source](https://discord.com/channels/691052431525675048/692572690833473578/1311092530732859533))
and also me being in favor of it.

Let's do a quick pros and cons list! Of course these are just what I
thought of, so take it with a grain of salt.

`FooSet`:

- Pro: Nice and short!
- Pro: Used by many ecosystem crates.
- Pro: The `Set` suffix comes directly from the trait name `SystemSet`.
- Pro: Pairs nicely with existing APIs like `in_set` and
`configure_sets`.
- Con: `Set` by itself doesn't actually indicate that it's related to
systems *at all*, apart from the implemented trait. A set of what?
- Con: Is `FooSet` a set of `Foo`s or a system set related to `Foo`? Ex:
`ContactSet`, `MeshSet`, `EnemySet`...

`FooSystems`:

- Pro: Very clearly indicates that the type represents a collection of
systems. The actual core concept, system(s), is in the name.
- Pro: Parallels nicely with `FooPlugins` for plugin groups.
- Pro: Low risk of conflicts with other names or misunderstandings about
what the type is.
- Pro: In most cases, reads *very* nicely and clearly. Ex:
`PhysicsSystems` and `AnimationSystems` as opposed to `PhysicsSet` and
`AnimationSet`.
- Pro: Easy to search for on docs.rs.
- Con: Usually results in longer names.
- Con: Not yet as widely used.

Really the big problem with `FooSet` is that it doesn't actually
describe what it is. It describes what *kind of thing* it is (a set of
something), but not *what it is a set of*, unless you know the type or
check its docs or implemented traits. `FooSystems` on the other hand is
much more self-descriptive in this regard, at the cost of being a bit
longer to type.

Ultimately, in some ways it comes down to preference and how you think
of system sets. Personally, I was originally in favor of `FooSet`, but
have been increasingly on the side of `FooSystems`, especially after
seeing what the new names would actually look like in Avian and now
Bevy. I prefer it because it usually reads better, is much more clearly
related to groups of systems than `FooSet`, and overall *feels* more
correct and natural to me in the long term.

For these reasons, and because Alice and Cart also seemed to share a
preference for it when it was previously being discussed, I propose that
we adopt a `FooSystems` naming convention where applicable.

## Solution

Rename Bevy's system set types to use a consistent `FooSet` naming where
applicable.

- `AccessibilitySystem` → `AccessibilitySystems`
- `GizmoRenderSystem` → `GizmoRenderSystems`
- `PickSet` → `PickingSystems`
- `RunFixedMainLoopSystem` → `RunFixedMainLoopSystems`
- `TransformSystem` → `TransformSystems`
- `RemoteSet` → `RemoteSystems`
- `RenderSet` → `RenderSystems`
- `SpriteSystem` → `SpriteSystems`
- `StateTransitionSteps` → `StateTransitionSystems`
- `RenderUiSystem` → `RenderUiSystems`
- `UiSystem` → `UiSystems`
- `Animation` → `AnimationSystems`
- `AssetEvents` → `AssetEventSystems`
- `TrackAssets` → `AssetTrackingSystems`
- `UpdateGizmoMeshes` → `GizmoMeshSystems`
- `InputSystem` → `InputSystems`
- `InputFocusSet` → `InputFocusSystems`
- `ExtractMaterialsSet` → `MaterialExtractionSystems`
- `ExtractMeshesSet` → `MeshExtractionSystems`
- `RumbleSystem` → `RumbleSystems`
- `CameraUpdateSystem` → `CameraUpdateSystems`
- `ExtractAssetsSet` → `AssetExtractionSystems`
- `Update2dText` → `Text2dUpdateSystems`
- `TimeSystem` → `TimeSystems`
- `AudioPlaySet` → `AudioPlaybackSystems`
- `SendEvents` → `EventSenderSystems`
- `EventUpdates` → `EventUpdateSystems`

A lot of the names got slightly longer, but they are also a lot more
consistent, and in my opinion the majority of them read much better. For
a few of the names I took the liberty of rewording things a bit;
definitely open to any further naming improvements.

There are still also cases where the `FooSystems` naming doesn't really
make sense, and those I left alone. This primarily includes system sets
like `Interned<dyn SystemSet>`, `EnterSchedules<S>`, `ExitSchedules<S>`,
or `TransitionSchedules<S>`, where the type has some special purpose and
semantics.

## Todo

- [x] Should I keep all the old names as deprecated type aliases? I can
do this, but to avoid wasting work I'd prefer to first reach consensus
on whether these renames are even desired.
- [x] Migration guide
- [x] Release notes
2025-05-06 15:18:03 +00:00
Christian Hughes
7e51f60de1
Add IntoSystem::with_input and ::with_input_from system wrappers (#18067)
# Objective

Originally [provided as a solution to a user's problem in
Discord](https://discord.com/channels/691052431525675048/1247654592838111302/1344431131277394042),
library authors might find the need to present user-registered systems
with system-specific data. Typically `Local<T>` is used for this type of
thing, but its not generally feasible or possible to configure/set the
underlying `T` data for locals. Alternatively, we can use `SystemInput`
to pass the data.

## Solution

- Added `IntoSystem::with_input`: Allows system-specific data to be
passed in explicitly.
- Added `IntoSystem::with_input_from`: Allows system-specific data to be
created at initialization time via `FromWorld`.

## Testing

Added two new tests, testing each of `with_input` and `with_input_from`.
2025-05-06 05:46:30 +00:00
Han Kruiger
b8724c21ce
implement MapEntities for higher-order types (#19071)
# Objective

With the current `MapEntities` `impl`s, it is not possible to derive
things like this:

```rust
#[derive(Component)]
pub struct Inventory {
  #[entities]
  slots: Vec<Option<Entity>>,
}
```

This is because `MapEntities` is only implemented for `Vec<Entity>` &
`Option<Entity>`, and not arbitrary combinations of those.

It would be nice to also support those types.

## Solution

I replaced the `impl`s of the following types

- `Option<Entity>`: replaced with `Option<T>` 
- `Vec<Entity>`: replaced with `Vec<T>`
- `HashSet<Entity, S>`: replaced with `HashSet<T, S>`
- `T` also had to be `Eq + core:#️⃣:Hash` here. **Not sure if this is
too restrictive?**
- `IndexSet<Entity, S>`: replaced with `IndexSet <T, S>`
- `T` also had to be `Eq + core:#️⃣:Hash` here. **Not sure if this is
too restrictive?**
- `BTreeSet<Entity>`: replaced with `BTreeSet<T>`
- `VecDeque<Entity>`: replaced with `VecDeque<T>`
- `SmallVec<A: smallvec::Array<Item = Entity>>`: replaced with
`SmallVec<A: smallvec::Array<Item = T>>`

(in all of the above, `T` is a generic type that implements
`MapEntities` (`Entity` being one of them).)

## Testing

I did not test any of this, but extended the `Component::map_entities`
doctest with an example usage of the newly supported types.

---

## Showcase

With these changes, this is now possible:

```rust
#[derive(Component)]
pub struct Inventory {
  #[entities]
  slots: Vec<Option<Entity>>,
}
```
2025-05-06 05:24:37 +00:00
urben1680
2ae1510f89
Add world and world_mut methods to RelatedSpawner (#18880)
# Objective

`RelatedSpawnerCommands` offers methods to get the underlying
`Commands`.
`RelatedSpawner` does not expose the inner `World` reference so far.

I currently want to write extension traits for both of them but I need
to duplicate the whole API for the latter because I cannot get it's
`&mut World`.

## Solution

Add methods for immutable and mutable `World` access
2025-05-06 05:18:56 +00:00
Corvus
a312170749
Increase upper limit of children! (#18865)
# Objective

Currently, `bevy_ecs`'s `children!` macro only supports spawning up to
twelve children at once. Ideally there would be no limit.

## Solution

`children!` is limited because `SpawnableList`, [the primary trait bound
here](https://docs.rs/bevy/0.16.0-rc.5/bevy/ecs/hierarchy/struct.Children.html#method.spawn),
uses the fake variadics pattern on tuples of up to twelve elements.
However, since a tuple itself implements `SpawnableList`, we can simply
nest tuples of entities when we run out of room.

This PR achieves this using `macro_rules` macros with a bit of brute
force, following [some discussion on
Discord](https://discord.com/channels/691052431525675048/692572690833473578/1362174415458013314).
If we create patterns for lists of up to eleven bundles, then use a
repetition pattern to handle the rest, we can "special-case" the
recursion into a nested tuple.

In principle, this would permit an arbitrary number of children, but
Rust's recursion limits will cut things short at around 1400 elements by
default. Of course, it's generally not a good idea to stick that many
bundles in a single invocation, but it might be worth mentioning in the
docs.

## Implementation notes

### Why are cases 0-11 expanded by hand?

We could make use of a tertiary macro:

```rs
macro_rules! recursive_spawn {
    // so that this...
    ($a:expr, $b:expr) => {
        (
            $crate::spawn::Spawn($a),
            $crate::spawn::Spawn($b),
        )
    };
    
    // becomes this...
    ($a:expr, $b:expr) => {
        $crate::spawn_tuple!($a, $b)
    };
}
```

But I already feel a little bad exporting `recursive_spawn`. I'd really
like to avoid exposing more internals, even if they are annotated with
`#[doc(hidden)]`. If I had to guess, I'd say it'll also make the
expansion a tiny bit slower.

### Do we really need to handle up to twelve elements in the macro?

The macro is a little long, but doing it this way maximizes the
"flatness" of the types to be spawned. This should improve the codegen a
bit and makes the macro output a little bit easier to look at.

## Future work

The `related!` macro is essentially the same as `children!`, so if this
direction is accepted, `related!` should receive the same treatment. I
imagine we'd want to extract out the `recursive_spawn` macro into its
own file since it can be used for both. If this should be tackled in
this PR, let me know!

## Testing

This change is fairly trivial, but I added a single test to verify that
it compiles and nothing goes wrong once recursion starts happening. It's
pretty easy to verify that the change works in practice -- just spawn
over twelve entities as children at once!
2025-05-06 00:58:30 +00:00
Tim Overbeek
60cdefd128
Derive clone_behavior for Components (#18811)
Allow Derive(Component) to specify a clone_behavior

```rust
#[derive(Component)]
#[component(clone_behavior = Ignore)]
MyComponent;
```
2025-05-06 00:32:59 +00:00
Eagster
af8d12c3e1
deprecate SimpleExecutor (#18753)
# Objective

Contributes to #18741 and #18453.

## Solution

Deprecate `SimpleExecutor`. If users run into migration issues, we can
backtrack. Otherwise, we follow this up with #18741

We can't easily deprecate the module too because of
[this](https://github.com/rust-lang/rust/issues/47238).

## Testing

CI

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Cyrill Schenkel <cyrill.schenkel@gmail.com>
2025-05-06 00:21:57 +00:00
Jonathan Chan Kwan Yin
cdcb773e9b
Add EntityWorldMut::reborrow_scope() (#18730)
# Objective

Allow `EntityCommand` implementors to delegate to other entity commands
easily:

```rs
impl EntityCommand for Foo {
    fn apply(self, mut entity: EntityWorldMut) {
        entity.reborrow_scope(|e| StepOne.apply(e));
        entity.reborrow_scope(|e| StepTwo.apply(e));
    }
}
```
2025-05-06 00:19:56 +00:00
re0312
5ed8e0639a
Merge ObserverState and Observer into single component (#18728)
# Objective

- bevy removed `Observe` type parameters in #15151 ,it enables merging
`Observer` and `ObserverState ` into a single component. with this
consolidation ,we can improve efficiency while reducing boilerplate.

## Solution

- remove `ObserverState `and merge it  into `Observer`

## Testing

40%~60% performance win due to removal of redundant look up.

![image](https://github.com/user-attachments/assets/eb1d46cb-cca3-4c2b-948c-bf4ecb617de9)

This also improves ergonomics when using dynamic observer
```rust
// previously 
world.spawn(ObserverState {
            // SAFETY: we registered `event_a` above and it matches the type of EventA
            descriptor: unsafe { ObserverDescriptor::default().with_events(vec![event_a]) },
            runner: |mut world, _trigger, _ptr, _propagate| {
                world.resource_mut::<Order>().observed("event_a");
            },
            ..Default::default()
        });

// now
let observe = unsafe {
    Observer::with_dynamic_runner(|mut world, _trigger, _ptr, _propagate| {
        world.resource_mut::<Order>().observed("event_a");
    })
    .with_event(event_a)
};
world.spawn(observe);
```
2025-05-06 00:12:27 +00:00
Chris Russell
3442e2556d
Use new run_without_applying_deferred method in SingleThreadedExecutor (#18684)
# Objective

Simplify code in the `SingleThreadedExecutor` by removing a special case
for exclusive systems.

The `SingleThreadedExecutor` runs systems without immediately applying
deferred buffers. That required calling `run_unsafe()` instead of
`run()`, but that would `panic` for exclusive systems, so the code also
needed a special case for those. Following #18076 and #18406, we have a
`run_without_applying_deferred` method that has the exact behavior we
want and works on exclusive systems.

## Solution

Replace the code in `SingleThreadedExecutor` that runs systems with a
single call to `run_without_applying_deferred()`. Also add this as a
wrapper in the `__rust_begin_short_backtrace` module to preserve the
special behavior for backtraces.
2025-05-06 00:09:02 +00:00
Eagster
f6543502b4
Add BundleRemover (#18521)
# Objective

It has long been a todo item in the ecs to create a `BundleRemover`
alongside the inserter, spawner, etc.

This is an uncontroversial first step of #18514.

## Solution

Move existing code from complex helper functions to one generalized
`BundleRemover`.

## Testing

Existing tests.
2025-05-05 23:55:04 +00:00
Chris Russell
bea0a0a9bc
Let FilteredEntity(Ref|Mut) receive access when nested. (#18236)
# Objective

Let `FilteredEntityRef` and `FilteredEntityMut` receive access when
nested inside tuples or `#[derive(QueryData)]` types. Make sure to
exclude any access that would conflict with other subqueries!

Fixes #14349

## Solution

Replace `WorldQuery::set_access(state, access)` with a new method,
`QueryData::provide_extra_access(state, access, available_access)`, that
passes both the total available access and the currently used access.
This is called after `WorldQuery::update_component_access()`, so any
access used by ordinary subqueries will be known. `FilteredEntityRef`
and `FilteredEntityMut` can use the combination to determine how much
access they can safely take, while tuples can safely pass those
parameters directly to their subqueries.

This requires a new `Access::remove_conflicting_access()` method that
can be used to remove any access that would conflict with existing
access. Implementing this method was easier by first factoring some
common set manipulation code out of `Access::extend`. I can extract that
refactoring to a separate PR if desired.

Have `FilteredEntity(Ref|Mut)` store `Access` instead of
`FilteredAccess` because they do not need to keep track of the filter.
This was necessary in an early draft but no longer is. I left it in
because it's small and I'm touching that code anyway, but I can extract
it to a separate PR if desired.
2025-05-05 23:23:46 +00:00
NiseVoid
02d569d0e4
Add Allows filter to bypass DefaultQueryFilters (#18192)
# Objective

Fixes #17803 

## Solution

- Add an `Allows<T>` `QueryFilter` that adds archetypal access for `T`
- Fix access merging to include archetypal from both sides

## Testing

- Added a case to the unit test for the application of
`DefaultQueryFilters`
2025-05-05 23:21:26 +00:00
Eagster
bfc76c589e
Remove insert_or_spawn function family (#18148)
# Objective

Based on and closes #18054, this PR builds on #18035 and #18147 to
remove:

- `Commands::insert_or_spawn_batch`
- `Entities::alloc_at_without_replacement`
- `Entities::alloc_at`
- `entity::AllocAtWithoutReplacement`
- `World::insert_or_spawn_batch`
- `World::insert_or_spawn_batch_with_caller`

## Testing

Just removing unused, deprecated code, so no new tests. Note that as of
writing, #18035 is still under testing and review.

## Future Work

Per
[this](https://github.com/bevyengine/bevy/issues/18054#issuecomment-2689088899)
comment on #18054, there may be additional performance improvements
possible to the entity allocator now that `alloc_at` no longer is
supported. At a glance, I don't see anything obvious to improve, but it
may be worth further investigation in the future.

---------

Co-authored-by: JaySpruce <jsprucebruce@gmail.com>
2025-05-05 23:14:32 +00:00
Chris Russell
55bb59b844
Stop using ArchetypeComponentId in the executor (#16885)
# Objective

Stop using `ArchetypeComponentId` in the executor. These IDs will grow
even more quickly with relations, and the size may start to degrade
performance.

## Solution

Have systems expose their `FilteredAccessSet<ComponentId>`, and have the
executor use that to determine which systems conflict. This can be
determined statically, so determine all conflicts during initialization
and only perform bit tests when running.

## Testing

I ran many_foxes and didn't see any performance changes. It's probably
worth testing this with a wider range of realistic schedules to see
whether the reduced concurrency has a cost in practice, but I don't know
what sort of test cases to use.

## Migration Guide

The schedule will now prevent systems from running in parallel if there
*could* be an archetype that they conflict on, even if there aren't
actually any. For example, these systems will now conflict even if no
entity has both `Player` and `Enemy` components:
```rust
fn player_system(query: Query<(&mut Transform, &Player)>) {}
fn enemy_system(query: Query<(&mut Transform, &Enemy)>) {}
```

To allow them to run in parallel, use `Without` filters, just as you
would to allow both queries in a single system:
```rust
// Either one of these changes alone would be enough
fn player_system(query: Query<(&mut Transform, &Player), Without<Enemy>>) {}
fn enemy_system(query: Query<(&mut Transform, &Enemy), Without<Player>>) {}
```
2025-05-05 22:52:44 +00:00
Chris Russell
5f936aefc8
Prevent exclusive systems from being used as observers (#19033)
# Objective

Prevent using exclusive systems as observers. Allowing them is unsound,
because observers are only expected to have `DeferredWorld` access, and
the observer infrastructure will keep pointers that are invalidated by
the creation of `&mut World`.

See
https://github.com/bevyengine/bevy/actions/runs/14778342801/job/41491517847?pr=19011
for a MIRI failure in a recent PR caused by an exclusive system being
used as an observer in a test.

## Solution

Have `Observer::new` panic if `System::is_exclusive()` is true. Document
that method, and methods that call it, as panicking.

(It should be possible to express this in the type system so that the
calls won't even compile, but I did not want to attempt that.)

## Testing

Added a unit test that calls `World::add_observer` with an exclusive
system.
2025-05-05 17:46:25 +00:00
JaySpruce
113d1b7dc1
Fix sparse set components ignoring insert_if_new/InsertMode (#19059)
# Objective

I've been tinkering with ECS insertion/removal lately, and noticed that
sparse sets just... don't interact with `InsertMode` at all. Sure
enough, using `insert_if_new` with a sparse component does the same
thing as `insert`.

# Solution

- Add a check in `BundleInfo::write_components` to drop the new value if
the entity already has the component and `InsertMode` is `Keep`.
- Add necessary methods to sparse set internals to fetch the drop
function.

# Testing

Minimal reproduction:
<details>
<summary>Code</summary>

```
use bevy::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, setup)
        .add_systems(PostStartup, component_print)
        .run();
}

#[derive(Component)]
#[component(storage = "SparseSet")]
struct SparseComponent(u32);

fn setup(mut commands: Commands) {
    let mut entity = commands.spawn_empty();
    entity.insert(SparseComponent(1));
    entity.insert(SparseComponent(2));

    let mut entity = commands.spawn_empty();
    entity.insert(SparseComponent(3));
    entity.insert_if_new(SparseComponent(4));
}

fn component_print(query: Query<&SparseComponent>) {
    for component in &query {
        info!("{}", component.0);
    }
}
```

</details>

Here it is on Bevy Playground (0.15.3): 

https://learnbevy.com/playground?share=2a96a68a81e804d3fdd644a833c1d51f7fa8dd33fc6192fbfd077b082a6b1a41

Output on `main`:
```
2025-05-04T17:50:50.401328Z  INFO system{name="fork::component_print"}: fork: 2
2025-05-04T17:50:50.401583Z  INFO system{name="fork::component_print"}: fork: 4
```

Output with this PR :
```
2025-05-04T17:51:33.461835Z  INFO system{name="fork::component_print"}: fork: 2
2025-05-04T17:51:33.462091Z  INFO system{name="fork::component_print"}: fork: 3
```
2025-05-05 17:42:36 +00:00
Greeble
b516e78317
Bump crate-ci/typos from 1.31.1 to 1.32.0 (#19072)
Adopted #19066. Bumps
[crate-ci/typos](https://github.com/crate-ci/typos) from 1.31.1 to
1.32.0.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-05 17:27:36 +00:00
Brezak
e05e74a76a
Implement RelationshipSourceCollection for IndexSet (#18471)
# Objective

`IndexSet` doesn't implement `RelationshipSourceCollection`

## Solution

Implement `MapEntities` for `IndexSet`
Implement `RelationshipSourceCollection` for `IndexSet`

## Testing

`cargo clippy`

---------

Co-authored-by: François Mockers <mockersf@gmail.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
2025-05-04 10:17:29 +00:00
Brezak
c6d41a0d34
Implement RelationshipSourceCollection for BTreeSet (#18469)
# Objective

`BTreeSet` doesn't implement `RelationshipSourceCollection`.

## Solution

Implement it.

## Testing

`cargo clippy`

---

## Showcase

You can now use `BTreeSet` in a `RelationshipTarget`

---------

Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
Co-authored-by: François Mockers <mockersf@gmail.com>
2025-05-04 09:18:07 +00:00
Chris Russell
d28e4908ca
Create a When system param wrapper for skipping systems that fail validation (#18765)
# Objective

Create a `When` system param wrapper for skipping systems that fail
validation.

Currently, the `Single` and `Populated` parameters cause systems to skip
when they fail validation, while the `Res` family causes systems to
error. Generalize this so that any fallible parameter can be used either
to skip a system or to raise an error. A parameter used directly will
always raise an error, and a parameter wrapped in `When<P>` will always
cause the system to be silently skipped.

~~Note that this changes the behavior for `Single` and `Populated`. The
current behavior will be available using `When<Single>` and
`When<Populated>`.~~

Fixes #18516

## Solution

Create a `When` system param wrapper that wraps an inner parameter and
converts all validation errors to `skipped`.

~~Change the behavior of `Single` and `Populated` to fail by default.~~

~~Replace in-engine use of `Single` with `When<Single>`. I updated the
`fallible_systems` example, but not all of the others. The other
examples I looked at appeared to always have one matching entity, and it
seemed more clear to use the simpler type in those cases.~~

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Zachary Harrold <zac@harrold.com.au>
Co-authored-by: François Mockers <mockersf@gmail.com>
2025-05-04 08:41:42 +00:00
Brezak
3631a64a3d
Add a method to clear all related entity to EntityCommands and friends (#18907)
# Objective

We have methods to:
- Add related entities
- Replace related entities
- Remove specific related entities

We don't have a method the remove all related entities so.

## Solution

Add a method to remove all related entities.

## Testing

A new test case.
2025-04-30 20:59:29 +00:00
1.11e-1f64
9fca353782
Make AccessConflicts::is_empty public (#18688)
# Objective

When implementing `SystemParam` for an object which contains a mutable
reference to World, which cannot be derived due to a required lifetime
parameter, it's necessary to check that there aren't any conflicts.

As far as I know, the is_empty method is the only way provided to check
for no conflicts at all
2025-04-28 21:48:46 +00:00
Olle Lukowski
9167f02bdf
Create EntityCommands::remove_if (#18899)
# Objective

Fixes #18857.

## Solution

Add the requested method, and a `try_` variant as well.

## Testing

It compiles, doctests succeed, and is trivial enough that I don't think
it needs a unit test (correct me if I'm wrong though).
2025-04-26 21:32:02 +00:00
Rahmat Nazali Salimi
26f0ce272e
Fix minor typo on bevy_ecs example (#18926)
# Objective

A small typo was found on `bevy_ecs/examples/event.rs`.
I know it's very minor but I'd think fixing it would still help others
in the long run.

## Solution

Fix the typo.

## Testing

I don't think this is necessary.
2025-04-26 21:16:09 +00:00
François Mockers
12f71a8936
don't overflow when relations are empty (#18891)
# Objective

- Fixes #18890 

## Solution

- Don't overflow when substracting, bound at 0

## Testing

- Reproducer from the issue now works
2025-04-21 20:38:43 +00:00
Carter Anderson
f3f6cad43c
Panic on overlapping one-to-one relationships (#18833)
# Objective

One to one relationships (added in
https://github.com/bevyengine/bevy/pull/18087) can currently easily be
invalidated by having two entities relate to the same target.

Alternative to #18817 (removing one-to-one relationships)

## Solution

Panic if a RelationshipTarget is already targeted. Thanks @urben1680 for
the idea!

---------

Co-authored-by: François Mockers <mockersf@gmail.com>
2025-04-15 01:25:37 +00:00
JaySpruce
045ef4c307
Add remove_children and remove_related to EntityWorldMut and EntityCommands (#18835)
Fixes #18834.

`EntityWorldMut::remove_children` and `EntityCommands::remove_children`
were removed in the relationships overhaul (#17398) and never got
replaced.

I don't *think* this was intentional (the methods were never mentioned
in the PR or its comments), but I could've missed something.
2025-04-14 20:27:08 +00:00
JaySpruce
e3384bb8f0
Fix wrong method call in relationship replacement command (#18824)
Fixes a small mix-up from #18058, which added bulk relationship
replacement methods.

`EntityCommands::replace_related_with_difference` calls
`EntityWorldMut::replace_children_with_difference` instead of
`EntityWorldMut::replace_related_with_difference`, which means it always
operates on the `ChildOf` relationship instead of the `R: Relationship`
generic it's provided.

`EntityCommands::replace_children_with_difference` takes an `R:
Relationship` generic that it shouldn't, but it accidentally works
correctly on `main` because it calls the above method.
2025-04-14 20:15:33 +00:00