## Objective
Most `try` methods on `World` return a `Result`, but `try_despawn` and
`try_insert_batch` don't. Since Bevy's error handling is advancing,
these should be brought in line.
## Solution
- Added `TryDespawnError` and `TryInsertBatchError`.
- `try_despawn`, `try_insert_batch`, and `try_insert_batch_if_new` now
return their respective errors.
- Fixed slightly incorrect behavior in `try_insert_batch_with_caller`.
- The method was always meant to continue with the rest of the batch if
an entity was missing, but that only worked after the first entity; if
the first entity was missing, the method would exit early. This has been
resolved.
## Migration Guide
- `World::try_despawn` now returns a `Result` rather than a `bool`.
- `World::try_insert_batch` and `World::try_insert_batch_if_new` now
return a `Result` where they previously returned nothing.
# Objective
`bevy_ecs`'s `system` module is something of a grab bag, and *very*
large. This is particularly true for the `system_param` module, which is
more than 2k lines long!
While it could be defensible to put `Res` and `ResMut` there (lol no
they're in change_detection.rs, obviously), it doesn't make any sense to
put the `Resource` trait there. This is confusing to navigate (and
painful to work on and review).
## Solution
- Create a root level `bevy_ecs/resource.rs` module to mirror
`bevy_ecs/component.rs`
- move the `Resource` trait to that module
- move the `Resource` derive macro to that module as well (Rust really
likes when you pun on the names of the derive macro and trait and put
them in the same path)
- fix all of the imports
## Notes to reviewers
- We could probably move more stuff into here, but I wanted to keep this
PR as small as possible given the absurd level of import changes.
- This PR is ground work for my upcoming attempts to store resource data
on components (resources-as-entities). Splitting this code out will make
the work and review a bit easier, and is the sort of overdue refactor
that's good to do as part of more meaningful work.
## Testing
cargo build works!
## Migration Guide
`bevy_ecs::system::Resource` has been moved to
`bevy_ecs::resource::Resource`.
# Objective
While being able to quickly add / remove components down a tree is
broadly useful (material changing!), it's particularly necessary when
combined with the newly added #13120.
## Solution
Write four methods: covering both adding and removal on both
`EntityWorldMut` and `EntityCommands`.
These methods are generic over the `RelationshipTarget`, thanks to the
freshly merged relations 🎉
## Testing
I've added a simple unit test for these methods.
---------
Co-authored-by: Zachary Harrold <zac@harrold.com.au>
# Objective
After #17398, Bevy now has relations! We don't teach users how to make /
work with these in the examples yet though, but we definitely should.
## Solution
- Add a simple abstract example that goes over defining, spawning,
traversing and removing a custom relations.
- ~~Add `Relationship` and `RelationshipTarget` to the prelude: the
trait methods are really helpful here.~~
- this causes subtle ambiguities with method names and weird compiler
errors. Not doing it here!
- Clean up related documentation that I referenced when writing this
example.
## Testing
`cargo run --example relationships`
## Notes to reviewers
1. Yes, I know that the cycle detection code could be more efficient. I
decided to reduce the caching to avoid distracting from the broader
point of "here's how you traverse relationships".
2. Instead of using an `App`, I've decide to use
`World::run_system_once` + system functions defined inside of `main` to
do something closer to literate programming.
---------
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
Co-authored-by: MinerSebas <66798382+MinerSebas@users.noreply.github.com>
Co-authored-by: Kristoffer Søholm <k.soeholm@gmail.com>
Fixes#17412
## Objective
`Parent` uses the "has a X" naming convention. There is increasing
sentiment that we should use the "is a X" naming convention for
relationships (following #17398). This leaves `Children` as-is because
there is prevailing sentiment that `Children` is clearer than `ParentOf`
in many cases (especially when treating it like a collection).
This renames `Parent` to `ChildOf`.
This is just the implementation PR. To discuss the path forward, do so
in #17412.
## Migration Guide
- The `Parent` component has been renamed to `ChildOf`.
# Objective
Some usecases in the ecosystems are blocked by the inability to stop
bevy internals and third party plugins from touching their entities.
However the specifics of a general purpose entity disabling system are
controversial and further complicated by hierarchies. We can partially
unblock these usecases with an opt-in approach: default query filters.
## Solution
- Introduce DefaultQueryFilters, these filters are automatically applied
to queries that don't otherwise mention the filtered component.
- End users and third party plugins can register default filters and are
responsible for handling entities they have hidden this way.
- Extra features can be left for after user feedback
- The default value could later include official ways to hide entities
---
## Changelog
- Add DefaultQueryFilters
# Objective
Diagnostics for labels don't suggest how to best implement them.
```
error[E0277]: the trait bound `Label: ScheduleLabel` is not satisfied
--> src/main.rs:15:35
|
15 | let mut sched = Schedule::new(Label);
| ------------- ^^^^^ the trait `ScheduleLabel` is not implemented for `Label`
| |
| required by a bound introduced by this call
|
= help: the trait `ScheduleLabel` is implemented for `Interned<(dyn ScheduleLabel + 'static)>`
note: required by a bound in `bevy_ecs::schedule::Schedule::new`
--> /home/vj/workspace/rust/bevy/crates/bevy_ecs/src/schedule/schedule.rs:297:28
|
297 | pub fn new(label: impl ScheduleLabel) -> Self {
| ^^^^^^^^^^^^^ required by this bound in `Schedule::new`
```
## Solution
`diagnostics::on_unimplemented` and `diagnostics::do_not_recommend`
## Showcase
New error message:
```
error[E0277]: the trait bound `Label: ScheduleLabel` is not satisfied
--> src/main.rs:15:35
|
15 | let mut sched = Schedule::new(Label);
| ------------- ^^^^^ the trait `ScheduleLabel` is not implemented for `Label`
| |
| required by a bound introduced by this call
|
= note: consider annotating `Label` with `#[derive(ScheduleLabel)]`
note: required by a bound in `bevy_ecs::schedule::Schedule::new`
--> /home/vj/workspace/rust/bevy/crates/bevy_ecs/src/schedule/schedule.rs:297:28
|
297 | pub fn new(label: impl ScheduleLabel) -> Self {
| ^^^^^^^^^^^^^ required by this bound in `Schedule::new`
```
docs: enhance documentation in `query.rs` to clarify borrowing rules.
Please, let me know if you don't agree with the wording.. There is
always room for improvement.
Tested locally and it looks like this:

---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Noticed while doing #17449, I had left these `DerefMut` impls in.
Obtaining mutable references to those inner iterator types allows for
`mem::swap`, which can be used to swap an incorrectly behaving instance
into the wrappers.
## Solution
Remove them!
# Objective
The existing `RelationshipSourceCollection` uses `Vec` as the only
possible backing for our relationships. While a reasonable choice,
benchmarking use cases might reveal that a different data type is better
or faster.
For example:
- Not all relationships require a stable ordering between the
relationship sources (i.e. children). In cases where we a) have many
such relations and b) don't care about the ordering between them, a hash
set is likely a better datastructure than a `Vec`.
- The number of children-like entities may be small on average, and a
`smallvec` may be faster
## Solution
- Implement `RelationshipSourceCollection` for `EntityHashSet`, our
custom entity-optimized `HashSet`.
-~~Implement `DoubleEndedIterator` for `EntityHashSet` to make things
compile.~~
- This implementation was cursed and very surprising.
- Instead, by moving the iterator type on `RelationshipSourceCollection`
from an erased RPTIT to an explicit associated type we can add a trait
bound on the offending methods!
- Implement `RelationshipSourceCollection` for `SmallVec`
## Testing
I've added a pair of new tests to make sure this pattern compiles
successfully in practice!
## Migration Guide
`EntityHashSet` and `EntityHashMap` are no longer re-exported in
`bevy_ecs::entity` directly. If you were not using `bevy_ecs` / `bevy`'s
`prelude`, you can access them through their now-public modules,
`hash_set` and `hash_map` instead.
## Notes to reviewers
The `EntityHashSet::Iter` type needs to be public for this impl to be
allowed. I initially renamed it to something that wasn't ambiguous and
re-exported it, but as @Victoronz pointed out, that was somewhat
unidiomatic.
In
1a8564898f,
I instead made the `entity_hash_set` public (and its `entity_hash_set`)
sister public, and removed the re-export. I prefer this design (give me
module docs please), but it leads to a lot of churn in this PR.
Let me know which you'd prefer, and if you'd like me to split that
change out into its own micro PR.
simple derive macro for `FromWorld`. Going to be needed for composable
pipeline specializers but probably a nice thing to have regardless
## Testing
simple manual testing, nothing seemed to blow up. I'm no proc macro pro
though, so there's a chance I've mishandled spans somewhere or
something.
# Objective
- Contributes to #16877
## Solution
- Initial creation of `bevy_platform_support` crate.
- Moved `bevy_utils::Instant` into new `bevy_platform_support` crate.
- Moved `portable-atomic`, `portable-atomic-util`, and
`critical-section` into new `bevy_platform_support` crate.
## Testing
- CI
---
## Showcase
Instead of needing code like this to import an `Arc`:
```rust
#[cfg(feature = "portable-atomic")]
use portable_atomic_util::Arc;
#[cfg(not(feature = "portable-atomic"))]
use alloc::sync::Arc;
```
We can now use:
```rust
use bevy_platform_support::sync::Arc;
```
This applies to many other types, but the goal is overall the same:
allowing crates to use `std`-like types without the boilerplate of
conditional compilation and platform-dependencies.
## Migration Guide
- Replace imports of `bevy_utils::Instant` with
`bevy_platform_support::time::Instant`
- Replace imports of `bevy::utils::Instant` with
`bevy::platform_support::time::Instant`
## Notes
- `bevy_platform_support` hasn't been reserved on `crates.io`
- ~~`bevy_platform_support` is not re-exported from `bevy` at this time.
It may be worthwhile exporting this crate, but I am unsure of a
reasonable name to export it under (`platform_support` may be a bit
wordy for user-facing).~~
- I've included an implementation of `Instant` which is suitable for
`no_std` platforms that are not Wasm for the sake of eliminating feature
gates around its use. It may be a controversial inclusion, so I'm happy
to remove it if required.
- There are many other items (`spin`, `bevy_utils::Sync(Unsafe)Cell`,
etc.) which should be added to this crate. I have kept the initial scope
small to demonstrate utility without making this too unwieldy.
---------
Co-authored-by: TimJentzsch <TimJentzsch@users.noreply.github.com>
Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
This adds support for one-to-many non-fragmenting relationships (with
planned paths for fragmenting and non-fragmenting many-to-many
relationships). "Non-fragmenting" means that entities with the same
relationship type, but different relationship targets, are not forced
into separate tables (which would cause "table fragmentation").
Functionally, this fills a similar niche as the current Parent/Children
system. The biggest differences are:
1. Relationships have simpler internals and significantly improved
performance and UX. Commands and specialized APIs are no longer
necessary to keep everything in sync. Just spawn entities with the
relationship components you want and everything "just works".
2. Relationships are generalized. Bevy can provide additional built in
relationships, and users can define their own.
**REQUEST TO REVIEWERS**: _please don't leave top level comments and
instead comment on specific lines of code. That way we can take
advantage of threaded discussions. Also dont leave comments simply
pointing out CI failures as I can read those just fine._
## Built on top of what we have
Relationships are implemented on top of the Bevy ECS features we already
have: components, immutability, and hooks. This makes them immediately
compatible with all of our existing (and future) APIs for querying,
spawning, removing, scenes, reflection, etc. The fewer specialized APIs
we need to build, maintain, and teach, the better.
## Why focus on one-to-many non-fragmenting first?
1. This allows us to improve Parent/Children relationships immediately,
in a way that is reasonably uncontroversial. Switching our hierarchy to
fragmenting relationships would have significant performance
implications. ~~Flecs is heavily considering a switch to non-fragmenting
relations after careful considerations of the performance tradeoffs.~~
_(Correction from @SanderMertens: Flecs is implementing non-fragmenting
storage specialized for asset hierarchies, where asset hierarchies are
many instances of small trees that have a well defined structure)_
2. Adding generalized one-to-many relationships is currently a priority
for the [Next Generation Scene / UI
effort](https://github.com/bevyengine/bevy/discussions/14437).
Specifically, we're interested in building reactions and observers on
top.
## The changes
This PR does the following:
1. Adds a generic one-to-many Relationship system
3. Ports the existing Parent/Children system to Relationships, which now
lives in `bevy_ecs::hierarchy`. The old `bevy_hierarchy` crate has been
removed.
4. Adds on_despawn component hooks
5. Relationships can opt-in to "despawn descendants" behavior, meaning
that the entire relationship hierarchy is despawned when
`entity.despawn()` is called. The built in Parent/Children hierarchies
enable this behavior, and `entity.despawn_recursive()` has been removed.
6. `world.spawn` now applies commands after spawning. This ensures that
relationship bookkeeping happens immediately and removes the need to
manually flush. This is in line with the equivalent behaviors recently
added to the other APIs (ex: insert).
7. Removes the ValidParentCheckPlugin (system-driven / poll based) in
favor of a `validate_parent_has_component` hook.
## Using Relationships
The `Relationship` trait looks like this:
```rust
pub trait Relationship: Component + Sized {
type RelationshipSources: RelationshipSources<Relationship = Self>;
fn get(&self) -> Entity;
fn from(entity: Entity) -> Self;
}
```
A relationship is a component that:
1. Is a simple wrapper over a "target" Entity.
2. Has a corresponding `RelationshipSources` component, which is a
simple wrapper over a collection of entities. Every "target entity"
targeted by a "source entity" with a `Relationship` has a
`RelationshipSources` component, which contains every "source entity"
that targets it.
For example, the `Parent` component (as it currently exists in Bevy) is
the `Relationship` component and the entity containing the Parent is the
"source entity". The entity _inside_ the `Parent(Entity)` component is
the "target entity". And that target entity has a `Children` component
(which implements `RelationshipSources`).
In practice, the Parent/Children relationship looks like this:
```rust
#[derive(Relationship)]
#[relationship(relationship_sources = Children)]
pub struct Parent(pub Entity);
#[derive(RelationshipSources)]
#[relationship_sources(relationship = Parent)]
pub struct Children(Vec<Entity>);
```
The Relationship and RelationshipSources derives automatically implement
Component with the relevant configuration (namely, the hooks necessary
to keep everything in sync).
The most direct way to add relationships is to spawn entities with
relationship components:
```rust
let a = world.spawn_empty().id();
let b = world.spawn(Parent(a)).id();
assert_eq!(world.entity(a).get::<Children>().unwrap(), &[b]);
```
There are also convenience APIs for spawning more than one entity with
the same relationship:
```rust
world.spawn_empty().with_related::<Children>(|s| {
s.spawn_empty();
s.spawn_empty();
})
```
The existing `with_children` API is now a simpler wrapper over
`with_related`. This makes this change largely non-breaking for existing
spawn patterns.
```rust
world.spawn_empty().with_children(|s| {
s.spawn_empty();
s.spawn_empty();
})
```
There are also other relationship APIs, such as `add_related` and
`despawn_related`.
## Automatic recursive despawn via the new on_despawn hook
`RelationshipSources` can opt-in to "despawn descendants" behavior,
which will despawn all related entities in the relationship hierarchy:
```rust
#[derive(RelationshipSources)]
#[relationship_sources(relationship = Parent, despawn_descendants)]
pub struct Children(Vec<Entity>);
```
This means that `entity.despawn_recursive()` is no longer required.
Instead, just use `entity.despawn()` and the relevant related entities
will also be despawned.
To despawn an entity _without_ despawning its parent/child descendants,
you should remove the `Children` component first, which will also remove
the related `Parent` components:
```rust
entity
.remove::<Children>()
.despawn()
```
This builds on the on_despawn hook introduced in this PR, which is fired
when an entity is despawned (before other hooks).
## Relationships are the source of truth
`Relationship` is the _single_ source of truth component.
`RelationshipSources` is merely a reflection of what all the
`Relationship` components say. By embracing this, we are able to
significantly improve the performance of the system as a whole. We can
rely on component lifecycles to protect us against duplicates, rather
than needing to scan at runtime to ensure entities don't already exist
(which results in quadratic runtime). A single source of truth gives us
constant-time inserts. This does mean that we cannot directly spawn
populated `Children` components (or directly add or remove entities from
those components). I personally think this is a worthwhile tradeoff,
both because it makes the performance much better _and_ because it means
theres exactly one way to do things (which is a philosophy we try to
employ for Bevy APIs).
As an aside: treating both sides of the relationship as "equivalent
source of truth relations" does enable building simple and flexible
many-to-many relationships. But this introduces an _inherent_ need to
scan (or hash) to protect against duplicates.
[`evergreen_relations`](https://github.com/EvergreenNest/evergreen_relations)
has a very nice implementation of the "symmetrical many-to-many"
approach. Unfortunately I think the performance issues inherent to that
approach make it a poor choice for Bevy's default relationship system.
## Followup Work
* Discuss renaming `Parent` to `ChildOf`. I refrained from doing that in
this PR to keep the diff reasonable, but I'm personally biased toward
this change (and using that naming pattern generally for relationships).
* [Improved spawning
ergonomics](https://github.com/bevyengine/bevy/discussions/16920)
* Consider adding relationship observers/triggers for "relationship
targets" whenever a source is added or removed. This would replace the
current "hierarchy events" system, which is unused upstream but may have
existing users downstream. I think triggers are the better fit for this
than a buffered event queue, and would prefer not to add that back.
* Fragmenting relations: My current idea hinges on the introduction of
"value components" (aka: components whose type _and_ value determines
their ComponentId, via something like Hashing / PartialEq). By labeling
a Relationship component such as `ChildOf(Entity)` as a "value
component", `ChildOf(e1)` and `ChildOf(e2)` would be considered
"different components". This makes the transition between fragmenting
and non-fragmenting a single flag, and everything else continues to work
as expected.
* Many-to-many support
* Non-fragmenting: We can expand Relationship to be a list of entities
instead of a single entity. I have largely already written the code for
this.
* Fragmenting: With the "value component" impl mentioned above, we get
many-to-many support "for free", as it would allow inserting multiple
copies of a Relationship component with different target entities.
Fixes#3742 (If this PR is merged, I think we should open more targeted
followup issues for the work above, with a fresh tracking issue free of
the large amount of less-directed historical context)
Fixes#17301Fixes#12235Fixes#15299Fixes#15308
## Migration Guide
* Replace `ChildBuilder` with `ChildSpawnerCommands`.
* Replace calls to `.set_parent(parent_id)` with
`.insert(Parent(parent_id))`.
* Replace calls to `.replace_children()` with `.remove::<Children>()`
followed by `.add_children()`. Note that you'll need to manually despawn
any children that are not carried over.
* Replace calls to `.despawn_recursive()` with `.despawn()`.
* Replace calls to `.despawn_descendants()` with
`.despawn_related::<Children>()`.
* If you have any calls to `.despawn()` which depend on the children
being preserved, you'll need to remove the `Children` component first.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Occasionally bevy users will want to store systems or observer systems
in a component or resource, but they first try to store `IntoSystem`
instead of `System`, which leads to some headaches having to deal with
the `M` marker type parameter. We should recommend they use the `X`
trait instead of the `IntoX` trait in that case, as well for returning
from a function.
## Solution
Add usage notes to the `IntoX` traits about using `X` instead.
# Objective
- Fix issue identified on the [Discord
server](https://discord.com/channels/691052431525675048/691052431974465548/1328922812530036839)
## Solution
- Implement `Clone` for `QueryIter` using the existing
`QueryIter::remaining` method
## Testing
- CI
---
## Showcase
Users can now explicitly clone a read-only `QueryIter`:
```rust
fn combinations(query: Query<&ComponentA>) {
let mut iter = query.iter();
while let Some(a) = iter.next() {
// Can now clone rather than use remaining
for b in iter.clone() {
// Check every combination (a, b)
}
}
}
```
## Notes
This doesn't add any new functionality outside the context of generic
code (e.g., `T: Iterator<...> + Clone`), it's mostly for
discoverability. Users are more likely to be familiar with
`Clone::clone` than they are with the methods on `QueryIter`.
# Objective
As raised in https://github.com/bevyengine/bevy/pull/17317, the `Event:
Component` trait bound is confusing to users.
In general, a type `E` (like `AppExit`) which implements `Event` should
not:
- be stored as a component on an entity
- be a valid option for `Query<&AppExit>`
- require the storage type and other component metadata to be specified
Events are not components (even if they one day use some of the same
internal mechanisms), and this trait bound is confusing to users.
We're also automatically generating `Component` impls with our derive
macro, which should be avoided when possible to improve explicitness and
avoid conflicts with user impls.
Closes#17317, closes#17333
## Solution
- We only care that each unique event type gets a unique `ComponentId`
- dynamic events need their own tools for getting identifiers anyways
- This avoids complicating the internals of `ComponentId` generation.
- Clearly document why this cludge-y solution exists.
In the medium term, I think that either a) properly generalizing
`ComponentId` (and moving it into `bevy_reflect?) or b) using a
new-typed `Entity` as the key for events is more correct. This change is
stupid simple though, and removes the offending trait bound in a way
that doesn't introduce complex tech debt and does not risk changes to
the internals.
This change does not:
- restrict our ability to implement dynamic buffered events (the main
improvement over #17317)
- there's still a fair bit of work to do, but this is a step in the
right direction
- limit our ability to store event metadata on entities in the future
- make it harder for users to work with types that are both events and
components (just add the derive / trait bound)
## Migration Guide
The `Event` trait no longer requires the `Component` trait. If you were
relying on this behavior, change your trait bounds from `Event` to
`Event + Component`. If you also want your `Event` type to implement
`Component`, add a derive.
---------
Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
# Objective
Fixes https://github.com/bevyengine/bevy/issues/17111
## Solution
Move `#![warn(clippy::allow_attributes,
clippy::allow_attributes_without_reason)]` to the workspace `Cargo.toml`
## Testing
Lots of CI testing, and local testing too.
---------
Co-authored-by: Benjamin Brienen <benjamin.brienen@outlook.com>
# Objective
- Currently, the `ObservedBy`-component is only public within the
`bevy_ecs` crate. Sometimes it is desirable to refer to this component
in the "game-code". Two examples that come in mind:
- Clearing all components in an entity, but intending to keep the
existing observers: Making `ObservedBy` public allows us to use
`commands.entity(entity).retain::<ObservedBy>();`, which clears all
other components, but keeps `ObservedBy`, which prevents the Observers
from despawning.
- The opposite of the above, clearing all of entities' Observers:
`commands.entity(entity).remove::<ObservedBy>` will despawn all
associated Observers. Admittedly, a cleaner solution would be something
like `commands.entity(entity).clear_observers()`, but this is
sufficient.
## Solution
- Removed `(crate)` "rule" and added `ObservedBy` to the prelude-module
## Testing
- Linked `bevy_ecs` locally with another project to see if `ObservedBy`
could be referenced.
# Objective
resolves#17326.
## Solution
Simply added the suggested run condition.
## Testing
A self-explanatory run condition. Fully verified by the operation of
`QueryFilter` in a system.
# Objective
- https://github.com/bevyengine/bevy/issues/17111
## Solution
Set the `clippy::allow_attributes` and
`clippy::allow_attributes_without_reason` lints to `warn`, and bring
`bevy_ecs` in line with the new restrictions.
## Testing
This PR is a WIP; testing will happen after it's finished.
# Objective
- Use `Clone` on `SystemParam`, when applicable, in a generic context.
## Solution
- Add some derives
## Testing
- I ran `cargo test` once.
- I didn't even look at the output.
---------
Co-authored-by: François Mockers <mockersf@gmail.com>
- `Once` renamed to `Warn`.
- `param_warn_once()` renamed to `warn_param_missing()`.
- `never_param_warn()` renamed to `ignore_param_missing()`.
Also includes changes to the documentation of the above methods.
Fixes#17262.
## Migration Guide
- `ParamWarnPolicy::Once` has been renamed to `ParamWarnPolicy::Warn`.
- `ParamWarnPolicy::param_warn_once` has been renamed to
`ParamWarnPolicy::warn_param_missing`.
- `ParamWarnPolicy::never_param_warn` has been renamed to
`ParamWarnPolicy::ignore_param_missing`.
# Objective
With the `track_location` feature, the error message of trying to
acquire an entity that was despawned pointed to the wrong line if the
entity index has been reused.
## Showcase
```rust
use bevy_ecs::prelude::*;
fn main() {
let mut world = World::new();
let e = world.spawn_empty().id();
world.despawn(e);
world.flush();
let _ = world.spawn_empty();
world.entity(e);
}
```
Old message:
```
Entity 0v1 was despawned by src/main.rs:8:19
```
New message:
```
Entity 0v1 does not exist (its index has been reused)
```
# Objective
Stumbled upon a `from <-> form` transposition while reviewing a PR,
thought it was interesting, and went down a bit of a rabbit hole.
## Solution
Fix em
# Objective
Rework / build on #17043 to simplify the implementation. #17043 should
be merged first, and the diff from this PR will get much nicer after it
is merged (this PR is net negative LOC).
## Solution
1. Command and EntityCommand have been vastly simplified. No more marker
components. Just one function.
2. Command and EntityCommand are now generic on the return type. This
enables result-less commands to exist, and allows us to statically
distinguish between fallible and infallible commands, which allows us to
skip the "error handling overhead" for cases that don't need it.
3. There are now only two command queue variants: `queue` and
`queue_fallible`. `queue` accepts commands with no return type.
`queue_fallible` accepts commands that return a Result (specifically,
one that returns an error that can convert to
`bevy_ecs::result::Error`).
4. I've added the concept of the "default error handler", which is used
by `queue_fallible`. This is a simple direct call to the `panic()` error
handler by default. Users that want to override this can enable the
`configurable_error_handler` cargo feature, then initialize the
GLOBAL_ERROR_HANDLER value on startup. This is behind a flag because
there might be minor overhead with `OnceLock` and I'm guessing this will
be a niche feature. We can also do perf testing with OnceLock if someone
really wants it to be used unconditionally, but I don't personally feel
the need to do that.
5. I removed the "temporary error handler" on Commands (and all code
associated with it). It added more branching, made Commands bigger /
more expensive to initialize (note that we construct it at high
frequencies / treat it like a pointer type), made the code harder to
follow, and introduced a bunch of additional functions. We instead rely
on the new default error handler used in `queue_fallible` for most
things. In the event that a custom handler is required,
`handle_error_with` can be used.
6. EntityCommand now _only_ supports functions that take
`EntityWorldMut` (and all existing entity commands have been ported).
Removing the marker component from EntityCommand hinged on this change,
but I strongly believe this is for the best anyway, as this sets the
stage for more efficient batched entity commands.
7. I added `EntityWorldMut::resource` and the other variants for more
ergonomic resource access on `EntityWorldMut` (removes the need for
entity.world_scope, which also incurs entity-lookup overhead).
## Open Questions
1. I believe we could merge `queue` and `queue_fallible` into a single
`queue` which accepts both fallible and infallible commands (via the
introduction of a `QueueCommand` trait). Is this desirable?
# Objective
- Shrink `bevy_utils` more.
- Refs #11478
## Solution
- Removes `assert_object_safe` from `bevy_utils` by using a compile time
check instead.
## Testing
- CI.
---
## Migration Guide
`assert_object_safe` is no longer exported by `bevy_utils`. Instead, you
can write a compile time check that your trait is "dyn compatible":
```rust
/// Assert MyTrait is dyn compatible
const _: Option<Box<dyn MyTrait>> = None;
```
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Many instances of `clippy::too_many_arguments` linting happen to be on
systems - functions which we don't call manually, and thus there's not
much reason to worry about the argument count.
## Solution
Allow `clippy::too_many_arguments` globally, and remove all lint
attributes related to it.
## Objective
Fixes#2004Fixes#3845Fixes#7118Fixes#10166
## Solution
- The crux of this PR is the new `Command::with_error_handling` method.
This wraps the relevant command in another command that, when applied,
will apply the original command and handle any resulting errors.
- To enable this, `Command::apply` and `EntityCommand::apply` now return
`Result`.
- `Command::with_error_handling` takes as a parameter an error handler
of the form `fn(&mut World, CommandError)`, which it passes the error
to.
- `CommandError` is an enum that can be either `NoSuchEntity(Entity)` or
`CommandFailed(Box<dyn Error>)`.
### Closures
- Closure commands can now optionally return `Result`, which will be
passed to `with_error_handling`.
### Commands
- Fallible commands can be queued with `Commands::queue_fallible` and
`Commands::queue_fallible_with`, which call `with_error_handling` before
queuing them (using `Commands::queue` will queue them without error
handling).
- `Commands::queue_fallible_with` takes an `error_handler` parameter,
which will be used by `with_error_handling` instead of a command's
default.
- The `command` submodule provides unqueued forms of built-in fallible
commands so that you can use them with `queue_fallible_with`.
- There is also an `error_handler` submodule that provides simple error
handlers for convenience.
### Entity Commands
- `EntityCommand` now automatically checks if the entity exists before
executing the command, and returns `NoSuchEntity` if it doesn't.
- Since all entity commands might need to return an error, they are
always queued with error handling.
- `EntityCommands::queue_with` takes an `error_handler` parameter, which
will be used by `with_error_handling` instead of a command's default.
- The `entity_command` submodule provides unqueued forms of built-in
entity commands so that you can use them with `queue_with`.
### Defaults
- In the future, commands should all fail according to the global error
handling setting. That doesn't exist yet though.
- For this PR, commands all fail the way they do on `main`.
- Both now and in the future, the defaults can be overridden by
`Commands::override_error_handler` (or equivalent methods on
`EntityCommands` and `EntityEntryCommands`).
- `override_error_handler` takes an error handler (`fn(&mut World,
CommandError)`) and passes it to every subsequent command queued with
`Commands::queue_fallible` or `EntityCommands::queue`.
- The `_with` variants of the queue methods will still provide an error
handler directly to the command.
- An override can be reset with `reset_error_handler`.
## Future Work
- After a universal error handling mode is added, we can change all
commands to fail that way by default.
- Once we have all commands failing the same way (which would require
either the full removal of `try` variants or just making them useless
while they're deprecated), `queue_fallible_with_default` could be
removed, since its only purpose is to enable commands having different
defaults.
# Objective
Cleanup `EntityRef`, `EntityMut`, and `EntityWorldMut` in preparation
for my "Scoped Entity References" PR.
## Solution
- Switched `EntityRef`/`EntityMut` from tuple structs to normal ones.
- Ensured all conversion trait impls use the same `entity` argument
name.
- Replaced some `unsafe` with delegated calls from `EntityMut` to
`EntityRef`
- Added `EntityMut::into_readonly` to make the replacements clearer
- Replaced some `unsafe` with delegated calls from `EntityWorldMut` to
`EntityMut` and `EntityRef`
- Added `EntityWorldMut::into_readonly`, `::as_readonly`,
`::into_mutable`, `::as_mutable` to make the replacements clearer
## Testing
Reusing current tests.
Related to https://github.com/bevyengine/bevy/pull/16843
Since `WorldQuery::Fetch` is `Clone`, it can't store mutable references
to resources, so it doesn't make sense to mutably access resources. In
that sense, it is hard to find usecases of mutably accessing resources
and to clearly define, what mutably accessing resources would mean, so
it's been decided to disallow write resource access.
Also changed documentation of safety requirements of
`WorldQuery::init_fetch` and `WorldQuery::fetch` to clearly state to the
caller, what safety invariants they need to uphold.
Bump version after release
This PR has been auto-generated
---------
Co-authored-by: Bevy Auto Releaser <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: François Mockers <mockersf@gmail.com>
# Objective
- Contributes to #11478
## Solution
- Made `bevy_utils::tracing` `doc(hidden)`
- Re-exported `tracing` from `bevy_log` for end-users
- Added `tracing` directly to crates that need it.
## Testing
- CI
---
## Migration Guide
If you were importing `tracing` via `bevy::utils::tracing`, instead use
`bevy::log::tracing`. Note that many items within `tracing` are also
directly re-exported from `bevy::log` as well, so you may only need
`bevy::log` for the most common items (e.g., `warn!`, `trace!`, etc.).
This also applies to the `log_once!` family of macros.
## Notes
- While this doesn't reduce the line-count in `bevy_utils`, it further
decouples the internal crates from `bevy_utils`, making its eventual
removal more feasible in the future.
- I have just imported `tracing` as we do for all dependencies. However,
a workspace dependency may be more appropriate for version management.
## Objective
The error `EntityFetchError::NoSuchEntity` has an `UnsafeWorldCell`
inside it, which it uses to call
`Entities::entity_does_not_exist_error_details_message` when being
printed. That method returns a `String` that, if the `track_location`
feature is enabled, contains the location of whoever despawned the
relevant entity.
I initially had to modify this error while working on #17043. The
`UnsafeWorldCell` was causing borrow problems when being returned from a
command, so I tried replacing it with the `String` that the method
returns, since that was the world cell's only purpose.
Unfortunately, `String`s are slow, and it significantly impacted
performance (on top of that PR's performance hit):
<details>
<summary>17043 benchmarks</summary>
### With `String`

### No `String`

</details>
For that PR, I just removed the error details entirely, but I figured
I'd try to find a way to keep them around.
## Solution
- Replace the `String` with a helper struct that holds the location, and
only turn it into a string when someone actually wants to print it.
- Replace the `UnsafeWorldCell` with the aforementioned struct.
- Do the same for `QueryEntityError::NoSuchEntity`.
## Benchmarking
This had some interesting performance impact:
<details>
<summary>This PR vs main</summary>



</details>
## Other work
`QueryEntityError::QueryDoesNotMatch` also has an `UnsafeWorldCell`
inside it. This one would be more complicated to rework while keeping
the same functionality.
## Migration Guide
The errors `EntityFetchError::NoSuchEntity` and
`QueryEntityError::NoSuchEntity` now contain an
`EntityDoesNotExistDetails` struct instead of an `UnsafeWorldCell`. If
you were just printing these, they should work identically.
---------
Co-authored-by: Benjamin Brienen <benjamin.brienen@outlook.com>
# Objective
Use the latest version of `typos` and fix the typos that it now detects
# Additional Info
By the way, `typos` has a "low priority typo suggestions issue" where we
can throw typos we find that `typos` doesn't catch.
(This link may go stale) https://github.com/crate-ci/typos/issues/1200
# Background
In `no_std` compatible crates, there is often an `std` feature which
will allow access to the standard library. Currently, with the `std`
feature _enabled_, the
[`std::prelude`](https://doc.rust-lang.org/std/prelude/index.html) is
implicitly imported in all modules. With the feature _disabled_, instead
the [`core::prelude`](https://doc.rust-lang.org/core/prelude/index.html)
is implicitly imported. This creates a subtle and pervasive issue where
`alloc` items _may_ be implicitly included (if `std` is enabled), or
must be explicitly included (if `std` is not enabled).
# Objective
- Make the implicit imports for `no_std` crates consistent regardless of
what features are/not enabled.
## Solution
- Replace the `cfg_attr` "double negative" `no_std` attribute with
conditional compilation to _include_ `std` as an external crate.
```rust
// Before
#![cfg_attr(not(feature = "std"), no_std)]
// After
#![no_std]
#[cfg(feature = "std")]
extern crate std;
```
- Fix imports that are currently broken but are only now visible with
the above fix.
## Testing
- CI
## Notes
I had previously used the "double negative" version of `no_std` based on
general consensus that it was "cleaner" within the Rust embedded
community. However, this implicit prelude issue likely was considered
when forming this consensus. I believe the reason why is the items most
affected by this issue are provided by the `alloc` crate, which is
rarely used within embedded but extensively used within Bevy.
# Objective
Fix incorrect comment on `IntoSystemSetConfigs::after` likely caused by
copy-paste error. It said "before" instead of "after".
## Solution
Update the comment to the correct text.
## Testing
CI tests pass. This is just updating a comment.
# Objective
Just being fussy but I hate this `.map(|v|
v.is_some()).unwrap_or(false)` stuff.
## Solution
Reduce it using `and_then`.
---------
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
# Objective
- As stated in the related issue, this PR is to better align the feature
flag name with what it actually does and the plans for the future.
- Fixes#16852
## Solution
- Simple find / replace
## Testing
- Local run of `cargo run -p ci`
## Migration Guide
The `track_change_detection` feature flag has been renamed to
`track_location` to better reflect its extended capabilities.
# Objective
- Support more ergonomic conditional updates for types that can be
modified by `clone_into`.
## Solution
- Use `ToOwned::clone_into` to copy a reference provided by the caller
in `Mut::clone_from_if_neq`.
## Testing
- See doc tests.
# Objective
- #16589 added an enum to switch between fallible and infallible system.
This branching should be unnecessary if we wrap infallible systems in a
function to return `Ok(())`.
## Solution
- Create a wrapper system for `System<(), ()>`s that returns `Ok` on the
call to `run` and `run_unsafe`. The wrapper should compile out, but I
haven't checked.
- I removed the `impl IntoSystemConfigs for BoxedSystem<(), ()>` as I
couldn't figure out a way to keep the impl without double boxing.
## Testing
- ran `many_foxes` example to check if it still runs.
## Migration Guide
- `IntoSystemConfigs` has been removed for `BoxedSystem<(), ()>`. Either
use `InfallibleSystemWrapper` before boxing or make your system return
`bevy::ecs::prelude::Result`.
# Objective
- Make working with immutable components more ergonomic
- Assist #16662
## Solution
Added `modify_component` to `World` and `EntityWorldMut`. This method
"removes" a component from an entity, gives a mutable reference to it to
a provided closure, and then "re-inserts" the component back onto the
entity. This replacement triggers the `OnReplace` and `OnInsert` hooks,
but does _not_ cause an archetype move, as the removal is purely
simulated.
## Testing
- Added doc-tests and a unit test.
---
## Showcase
```rust
use bevy_ecs::prelude::*;
/// An immutable component.
#[derive(Component, PartialEq, Eq, Debug)]
#[component(immutable)]
struct Foo(bool);
let mut world = World::default();
let mut entity = world.spawn(Foo(false));
assert_eq!(entity.get::<Foo>(), Some(&Foo(false)));
// Before the closure is executed, the `OnReplace` hooks/observers are triggered
entity.modify_component(|foo: &mut Foo| {
foo.0 = true;
});
// After the closure is executed, `OnInsert` hooks/observers are triggered
assert_eq!(entity.get::<Foo>(), Some(&Foo(true)));
```
## Notes
- If the component is not available on the entity, the closure and hooks
aren't executed, and `None` is returned. I chose this as an alternative
to returning an error or panicking, but I'm open to changing that based
on feedback.
- This relies on `unsafe`, in particular for accessing the `Archetype`
to trigger hooks. All the unsafe operations are contained within
`DeferredWorld::modify_component`, and I would appreciate that this
function is given special attention to ensure soundness.
- The `OnAdd` hook can never be triggered by this method, since the
component must already be inserted. I have chosen to not trigger
`OnRemove`, as I believe it makes sense that this method is purely a
replacement operation, not an actual removal/insertion.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Malek <50841145+MalekiRe@users.noreply.github.com>
# Objective
- Made certain methods public for advanced use cases. Methods that
returns mutable references are marked as unsafe due to the possibility
of violating internal lifetime constraint assumptions.
- Fixes an issue introduced by #15184
# Objective
Some sort calls and `Ord` impls are unnecessarily complex.
## Solution
Rewrite the "match on cmp, if equal do another cmp" as either a
comparison on tuples, or `Ordering::then_with`, depending on whether the
compare keys need construction.
`sort_by` -> `sort_by_key` when symmetrical. Do the same for
`min_by`/`max_by`.
Note that `total_cmp` can only work with `sort_by`, and not on tuples.
When sorting collected query results that contain
`Entity`/`MainEntity`/`RenderEntity` in their `QueryData`, with that
`Entity` in the sort key:
stable -> unstable sort (all queried entities are unique)
If key construction is not simple, switch to `sort_by_cached_key` when
possible.
Sorts that are only performed to discover the maximal element are
replaced by `max_by_key`.
Dedicated comparison functions and structs are removed where simple.
Derive `PartialOrd`/`Ord` when useful.
Misc. closure style inconsistencies.
## Testing
- Existing tests.
# Objective
`EntityMutExcept` can currently be cloned, which can easily violate
aliasing rules.
## Solution
- Remove the `Clone` impl for `EntityMutExcept`
- Also manually derived `Clone` impl for `EntityRefExcept` so that `B:
Clone` isn't required, and also impl'd `Copy`
## Testing
Compile failure tests would be good for this, but I'm not exactly sure
how to set that up.
## Migration Guide
- `EntityMutExcept` can no-longer be cloned, as this violates Rust's
memory safety rules.
# Objective
- Contributes to #15460
## Solution
- Added the following features:
- `std` (default)
- `smol_str` (default)
- `portable-atomic`
- `critical-section`
- `libm`
- Fixed an existing issue where `bevy_reflect` wasn't properly feature
gated.
## Testing
- CI
## Notes
- There were some minor issues with `bevy_math` and `bevy_ecs` noticed
in this PR which I have also resolved here. I can split these out if
desired, but I've left them here for now as they're very small changes
and I don't consider this PR itself to be very controversial.
- `libm`, `portable-atomic`, and `critical-section` are shortcuts to
enable the relevant features in dependencies, making the usage of this
crate on atomically challenged platforms possible and simpler.
- `smol_str` is gated as it doesn't support atomically challenged
platforms (e.g., Raspberry Pi Pico). I have an issue and a
[PR](https://github.com/rust-analyzer/smol_str/pull/91) to discuss this
upstream.
## Objective
Commands were previously limited to structs that implemented `Command`.
Now there are blanket implementations for closures, which (in my
opinion) are generally preferable.
Internal commands within `commands/mod.rs` have been switched from
structs to closures, but there are a number of internal commands in
other areas of the engine that still use structs. I'd like to tidy these
up by moving their implementations to methods on
`World`/`EntityWorldMut` and changing `Commands` to use those methods
through closures.
This PR handles the following:
- `TriggerEvent` and `EmitDynamicTrigger` double as commands and helper
structs, and can just be moved to `World` methods.
- Four structs that enabled insertion/removal of components via
reflection. This functionality shouldn't be exclusive to commands, and
can be added to `EntityWorldMut`.
- Five structs that mostly just wrapped `World` methods, and can be
replaced with closures that do the same thing.
## Solution
- __Observer Triggers__ (`observer/trigger_event.rs` and
`observer/mod.rs`)
- Moved the internals of `TriggerEvent` to the `World` methods that used
it.
- Replaced `EmitDynamicTrigger` with two `World` methods:
- `trigger_targets_dynamic`
- `trigger_targets_dynamic_ref`
- `TriggerTargets` was now the only thing in
`observer/trigger_event.rs`, so it's been moved to `observer/mod.rs` and
`trigger_event.rs` was deleted.
- __Reflection Insert/Remove__ (`reflect/entity_commands.rs`)
- Replaced the following `Command` impls with equivalent methods on
`EntityWorldMut`:
- `InsertReflect` -> `insert_reflect`
- `InsertReflectWithRegistry` -> `insert_reflect_with_registry`
- `RemoveReflect` -> `remove_reflect`
- `RemoveReflectWithRegistry` -> `remove_reflect_with_registry`
- __System Registration__ (`system/system_registry.rs`)
- The following `Command` impls just wrapped a `World` method and have
been replaced with closures:
- `RunSystemWith`
- `UnregisterSystem`
- `RunSystemCachedWith`
- `UnregisterSystemCached`
- `RegisterSystem` called a helper function that basically worked as a
constructor for `RegisteredSystem` and made sure it came with a marker
component. That helper function has been replaced with
`RegisteredSystem::new` and a `#[require]`.
## Possible Addition
The extension trait that adds the reflection commands,
`ReflectCommandExt`, isn't strictly necessary; we could just `impl
EntityCommands`. We could even move them to the same files as the main
impls and put it behind a `#[cfg]`.
The PR that added it [had a similar
conversation](https://github.com/bevyengine/bevy/pull/8895#discussion_r1234713671)
and decided to stick with the trait, but we could revisit it here if so
desired.
# Objective
The rust-versions are out of date.
Fixes#17008
## Solution
Update the values
Cherry-picked from #17006 in case it is controversial
## Testing
Validated locally and in #17006
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Fixes#16104
## Solution
I removed all instances of `:?` and put them back one by one where it
caused an error.
I removed some bevy_utils helper functions that were only used in 2
places and don't add value. See: #11478
## Testing
CI should catch the mistakes
## Migration Guide
`bevy::utils::{dbg,info,warn,error}` were removed. Use
`bevy::utils::tracing::{debug,info,warn,error}` instead.
---------
Co-authored-by: SpecificProtagonist <vincentjunge@posteo.net>
# Objective
- First step for #16718
- #16589 introduced an api that can only ignore errors, which is risky
## Solution
- Panic instead of just ignoring the errors
## Testing
- Changed the `fallible_systems` example to return an error
```
Encountered an error in system `fallible_systems::setup`: TooManyVertices { subdivisions: 300, number_of_resulting_points: 906012 }
Encountered a panic in system `fallible_systems::setup`!
Encountered a panic in system `bevy_app::main_schedule::Main::run_main`!
```
## Objective
I believe these started as structs, back when that was how commands had
to be implemented. Now they just hide implementation details.
## Solution
Remove the helper functions and move each implementation into its
respective method, except for the ones that actually reduce code
duplication.
# Objective
Some types like `RenderEntity` and `MainEntity` are just wrappers around
`Entity`, so they should be able to implement
`EntityBorrow`/`TrustedEntityBorrow`. This allows using them with
`EntitySet` functionality.
The `EntityRef` family are more than direct wrappers around `Entity`,
but can still benefit from being unique in a collection.
## Solution
Implement `EntityBorrow` and `TrustedEntityBorrow` for simple `Entity`
newtypes and `EntityRef` types.
These impls are an explicit decision to have the `EntityRef` types
compare like just `Entity`.
`EntityWorldMut` is omitted from this impl, because it explicitly
contains a `&mut World` as well, and we do not ever use more than one at
a time.
Add `EntityBorrow` to the `bevy_ecs` prelude.
## Migration Guide
`NormalizedWindowRef::entity` has been replaced with an
`EntityBorrow::entity` impl.
# Objective
Fixes: #16578
## Solution
This is a patch fix, proper fix requires a breaking change.
Added `Panic` enum variant and using is as the system meta default.
Warn once behavior can be enabled same way disabling panic (originally
disabling wans) is.
To fix an issue with the current architecture, where **all** combinator
system params get checked together,
combinator systems only check params of the first system.
This will result in old, panicking behavior on subsequent systems and
will be fixed in 0.16.
## Testing
Ran unit tests and `fallible_params` example.
---------
Co-authored-by: François Mockers <mockersf@gmail.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
# Objective
- To fix a tiny bug in `bevy_ecs::storage::Tables` that, in one case,
means it accidentally allocates an additional "empty" `Table`, resulting
in two "empty" `Table`s:
- The one pre-allocated empty table at index 0 whose index is designed
to match up with `TableId::empty()`
- One extra empty table, at some non-0 index, that does not match up
with `TableId::empty()`.
- This PR aims to prevent this extraneous `Table`, ensuring that
entities with no components in table-storage reliably have their
archetype's table ID be equal to `TableId::empty()`.
## Solution
### Background
The issue occurs because:
- `Tables` contains:
- `tables: Vec<Table>` - The set of all `Table`s allocated in the world.
- `table_ids: HashMap<Box<[ComponentId]>, TableId>` - An index to
rapidly lookup the `Table` in `tables` by a set of `ComponentId`s.
- When `Tables` is constructed it pre-populates the `tables` `Vec` with
an empty `Table`.
- This ensures that the first entry (index 0) is always the `Table` for
entities with no components in table storage.
- In particular, `TableId::empty()` is a utility that returns a
`TableId` of `0`.
- However, the `table_ids` map is not initialised to associate an empty
`[ComponentId]` with `TableId` `0`.
- This means, the first time a structural change tries to access a
`Table` for an archetype with 0 table components:
- `Tables::get_id_or_insert` is used to retrieve the target `Table`
- The function attempts to lookup the entry in the `table_ids` `HashMap`
whose key is the empty `ComponentId` set
- The empty `Table` created at startup won't be found, because it was
never inserted into `table_ids`
- It will instead create a new table, insert it into the `HashMap`
(preventing further instances of this issue), and return it.
### Changes
- I considered simply initialising the `table_ids` `HashMap` to know
about the pre-allocated `Table`
- However, I ended up using the proposed solution discussed on Discord
[#ecs-dev](https://discord.com/channels/691052431525675048/749335865876021248/1320430933152759958):
- Make `Tables::get_id_or_insert` simply early-exit if the requested
`component_ids` was empty.
- This avoids unnecessarily hashing the empty slice and looking it up in
the `HashMap`.
- The `table_ids` `HashMap` is not exposed outside this struct, and is
only used within `get_id_or_insert`, so it seems wasteful to defensively
populate it with the empty `Table`.
## Testing
This is my first Bevy contribution, so I don't really know the processes
that well. That said:
- I have introduced a little test that exercises the original issue and
shows that it is now resolved.
- I have run the `bevy_ecs` tests locally, so I have reasonable
confidence I haven't broken that.
- I haven't run any further test suites, mostly as when I tried to run
test suites for the whole project it filled my entire SSD with >600GB of
target directory output 😱😱😱
# Objective
`EntityHashMap` and `EntityHashSet` iterators do not implement
`EntitySetIterator`.
## Solution
Make them newtypes instead of aliases. The methods that create the
iterators can then produce their own newtypes that carry the `Hasher`
generic and implement `EntitySetIterator`. Functionality remains the
same otherwise.
There are some other small benefits, f.e. the removal of `with_hasher`
associated functions, and the ability to implement more traits
ourselves.
`MainEntityHashMap` and `MainEntityHashSet` are currently left as the
previous type aliases, because supporting general `TrustedEntityBorrow`
hashing is more complex. However, it can also be done.
## Testing
Pre-existing `EntityHashMap` tests.
## Migration Guide
Users of `with_hasher` and `with_capacity_and_hasher` on
`EntityHashMap`/`Set` must now use `new` and `with_capacity`
respectively.
If the non-newtyped versions are required, they can be obtained via
`Deref`, `DerefMut` or `into_inner` calls.
# Objective
- Fixes#16892
## Solution
- Removed `TypeRegistryPlugin` (`Name` is now automatically registered
with a default `App`)
- Moved `TaskPoolPlugin` to `bevy_app`
- Moved `FrameCountPlugin` to `bevy_diagnostic`
- Deleted now-empty `bevy_core`
## Testing
- CI
## Migration Guide
- `TypeRegistryPlugin` no longer exists. If you can't use a default
`App` but still need `Name` registered, do so manually with
`app.register_type::<Name>()`.
- References to `TaskPoolPlugin` and associated types will need to
import it from `bevy_app` instead of `bevy_core`
- References to `FrameCountPlugin` and associated types will need to
import it from `bevy_diagnostic` instead of `bevy_core`
## Notes
This strategy was agreed upon by Cart and several other members in
[Discord](https://discord.com/channels/691052431525675048/692572690833473578/1319137218312278077).
# Objective
- Contributes to #16892
## Solution
- Moved `Name` and `NameOrEntity` into `bevy_ecs::name`, and added them
to the prelude.
## Testing
- CI
## Migration Guide
If you were importing `Name` or `NameOrEntity` from `bevy_core`, instead
import from `bevy_ecs::name`.
---------
Co-authored-by: Christian Hughes <9044780+ItsDoot@users.noreply.github.com>
# Objective
- Contributes to #15460
## Solution
- Added the following features:
- `std` (default)
- `bevy_tasks` (default)
- `downcast ` (default)
- `portable-atomic`
- `critical-section`
- `downcast` and `bevy_tasks` are now optional dependencies for
`bevy_app`.
## Testing
- CI
- Personal UEFI and Raspberry Pi Pico demo applications compile and run
against this branch
## Draft Release Notes
Bevy's application framework now supports `no_std` platforms.
Following up on `bevy_ecs` gaining `no_std` support, `bevy_app` extends
the functionality available on these targets to include the powerful
`App` and `Plugin` abstractions. With this, library authors now have the
option of making their plugins `no_std` compatible, or even offering
plugins specifically to improve Bevy on certain embedded platforms!
To start making a `no_std` compatible plugin, simply disable default
features when including `bevy_app`:
```toml
[dependencies]
bevy_app = { version = "0.16", default-features = false }
```
We encourage library authors to do this anyway, as it can also help with
compile times and binary size on all platforms.
Keep an eye out for future `no_std` updates as we continue to improve
the parity between `std` and `no_std`. We look forward to seeing what
kinds of applications are now possible with Bevy!
## Notes
- `downcast-rs` is optional as it isn't compatible with
`portable-atomic`. I will investigate making a PR upstream to add
support for this functionality, as it should be very straightforward.
- In line with the `bevy_ecs` no-std-ification, I've added documentation
to all features, and grouped them as well.
- ~~Creating this PR in draft while CI runs and so I can polish before
review.~~
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
#16132 introduced entity cloning functionality, and while it works and
is useful, it can be made faster. This is the promised follow-up to
improve performance.
## Solution
**PREFACE**: This is my first time writing `unsafe` in rust and I have
only vague idea about what I'm doing. I would encourage reviewers to
scrutinize `unsafe` parts in particular.
The solution is to clone component data to an intermediate buffer and
use `EntityWorldMut::insert_by_ids` to insert components without
additional archetype moves.
To facilitate this, `EntityCloner::clone_entity` now reads all
components of the source entity and provides clone handlers with the
ability to read component data straight from component storage using
`read_source_component` and write to an intermediate buffer using
`write_target_component`. `ComponentId` is used to check that requested
type corresponds to the type available on source entity.
Reflect-based handler is a little trickier to pull of: we only have
`&dyn Reflect` and no direct access to the underlying data.
`ReflectFromPtr` can be used to get `&dyn Reflect` from concrete
component data, but to write it we need to create a clone of the
underlying data using `Reflect`. For this reason only components that
have `ReflectDefault` or `ReflectFromReflect` or `ReflectFromWorld` can
be cloned, all other components will be skipped. The good news is that
this is actually only a temporary limitation: once #13432 lands we will
be able to clone component without requiring one of these `type data`s.
This PR also introduces `entity_cloning` benchmark to better compare
changes between the PR and main, you can see the results in the
**showcase** section.
## Testing
- All previous tests passing
- Added test for fast reflect clone path (temporary, will be removed
after reflection-based cloning lands)
- Ran miri
## Showcase
Here's a table demonstrating the improvement:
| **benchmark** | **main, avg** | **PR, avg** | **change, avg** |
| ----------------------- | ------------- | ----------- |
--------------- |
| many components reflect | 18.505 µs | 2.1351 µs | -89.095% |
| hierarchy wide reflect* | 22.778 ms | 4.1875 ms | -81.616% |
| hierarchy tall reflect* | 107.24 µs | 26.322 µs | -77.141% |
| hierarchy many reflect | 78.533 ms | 9.7415 ms | -87.596% |
| many components clone | 1.3633 µs | 758.17 ns | -45.937% |
| hierarchy wide clone* | 2.7716 ms | 3.3411 ms | +20.546% |
| hierarchy tall clone* | 17.646 µs | 20.190 µs | +17.379% |
| hierarchy many clone | 5.8779 ms | 4.2650 ms | -27.439% |
*: these benchmarks have entities with only 1 component
## Considerations
Once #10154 is resolved a large part of the functionality in this PR
will probably become obsolete. It might still be a little bit faster
than using command batching, but the complexity might not be worth it.
## Migration Guide
- `&EntityCloner` in component clone handlers is changed to `&mut
ComponentCloneCtx` to better separate data.
- Changed `EntityCloneHandler` from enum to struct and added convenience
functions to add default clone and reflect handler more easily.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
# Objective
Simplify the code by using `macro_rules` instead of a proc macro where
possible.
## Solution
Replace `impl_param_set` proc macro with a `macro_rules` macro.
# Objective
In current Bevy, it is very inconvenient to mutably retrieve a
user-provided list of entities more than one element at a time.
If the list contains any duplicate entities, we risk mutable aliasing.
Users of `Query::iter_many_mut` do not have access to `Iterator` trait,
and thus miss out on common functionality, for instance collecting their
`QueryManyIter`.
We can circumvent this issue with validation, however that entails
checking every entity against all others for inequality, or utilizing an
`EntityHashSet`. Even if an entity list remains unchanged, this
validation is/would have to be redone every time we wish to fetch with
the list.
This presents a lot of wasted work, as we often trivially know an entity
list to be unique f.e.: `QueryIter` will fetch every `Entity` once and
only once.
As more things become entities – assets, components, queries – this
issue will become more pronounced.
`get_many`/`many`/`iter_many`/`par_iter_many`-like functionality is all
affected.
## Solution
The solution this PR proposes is to introduce functionality built around
a new trait: `EntitySet`.
The goal is to preserve the property of "uniqueness" in a list wherever
possible, and then rely on it as a bound within new `*_many_unique`
methods to avoid the need for validation.
This is achieved using `Iterator`:
`EntitySet` is blanket implemented for any `T` that implements
`IntoIterator<IntoIter: EntitySetIterator>`.
`EntitySetIterator` is the unsafe trait that actually guarantees an
iterator to be "unique" via its safety contract.
We define an "Iterator over unique entities" as: "No two entities
returned by the iterator may compare equal."
For iterators that cannot return more than 1 element, this is trivially
true.
Whether an iterator can satisfy this is up to the `EntitySetIterator`
implementor to ensure, hence the unsafe.
However, this is not yet a complete solution. Looking at the signature
of `iter_many`, we find that `IntoIterator::Item` is not `Entity`, but
is instead bounded by the `Borrow<Entity>` trait. That is because
iteration without consuming the collection will often yield us
references, not owned items.
`Borrow<Entity>` presents an issue: The `Borrow` docs state that `x = y`
should equal `x.borrow() = y.borrow()`, but unsafe cannot rely on this
for soundness. We run into similar problems with other trait
implementations of any `Borrow<Entity>` type: `PartialEq`, `Eq`,
`PartialOrd`, `Ord`, `Hash`, `Clone`, `Borrow`, and `BorrowMut`.
This PR solves this with the unsafe `TrustedEntityBorrow` trait:
Any implementor promises that the behavior of the aforementioned traits
matches that of the underlying entity.
While `Borrow<Entity>` was the inspiration, we use our own counterpart
trait `EntityBorrow` as the supertrait to `TrustedEntityBorrow`, so we
can circumvent the limitations of the existing `Borrow<T>` blanket
impls.
All together, these traits allow us to implement `*_many_unique`
functionality with a lone `EntitySet` bound.
`EntitySetIterator` is implemented for all the std iterators and
iterator adapters that guarantee or preserve uniqueness, so we can
filter, skip, take, step, reverse, ... our unique entity iterators
without worry!
Sadly, current `HashSet` iterators do not carry the necessary type
information with them to determine whether the source `HashSet` produces
logic errors; A malicious `Hasher` could compromise a `HashSet`.
`HashSet` iteration is generally discouraged in the first place, so we
also exclude the set operation iterators, even though they do carry the
`Hasher` type parameter.
`BTreeSet` implements `EntitySet` without any problems.
If an iterator type cannot guarantee uniqueness at compile time, then a
user can still attach `EntitySetIterator` to an individual instance of
that type via `UniqueEntityIter::from_iterator_unchecked`.
With this, custom types can use `UniqueEntityIter<I>` as their
`IntoIterator::IntoIter` type, if necessary.
This PR is focused on the base concept, and expansions on it are left
for follow-up PRs. See "Potential Future Work" below.
## Testing
Doctests on `iter_many_unique`/`iter_many_unique_mut` + 2 tests in
entity_set.rs.
## Showcase
```rust
// Before:
fn system(player_list: Res<SomeUniquePlayerList>, players: Query<&mut Player>) {
let value = 0;
while let Some(player) = players.iter_many_mut(player_list).fetch_next() {
value += mem::take(player.value_mut())
}
}
// After:
fn system(player_list: Res<SomeUniquePlayerList>, players: Query<&mut Player>) {
let value = players
.iter_many_unique_mut(player_list)
.map(|player| mem::take(player.value_mut()))
.sum();
}
```
## Changelog
- added `EntityBorrow`, `TrustedEntityBorrow`, `EntitySet` and
`EntitySetIterator` traits
- added `iter_many_unique`, `iter_many_unique_mut`,
`iter_many_unique_unsafe` methods on `Query`
- added `iter_many_unique`, `iter_many_unique_mut`,
`iter_many_unique_manual` and `iter_many_unique_unchecked_manual`
methods on `QueryState`
- added corresponding `QueryManyUniqueIter`
- added `UniqueEntityIter`
## Migration Guide
Any custom type used as a `Borrow<Entity>` entity list item for an
`iter_many` method now has to implement `EntityBorrow` instead. Any type
that implements `Borrow<Entity>` can trivially implement `EntityBorrow`.
## Potential Future Work
- `ToEntitySet` trait for converting any entity iterator into an
`EntitySetIterator`
- `EntityIndexSet/Map` to tie in hashing with `EntitySet`
- add `EntityIndexSetSlice/MapSlice`
- requires: `EntityIndexSet/Map`
- Implementing `par_iter_many_unique_mut` for parallel mutable iteration
- requires: `par_iter_many`
- allow collecting into `UniqueEntityVec` to store entity sets
- add `UniqueEntitySlice`s
- Doesn't require, but should be done after: `UniqueEntityVec`
- add `UniqueEntityArray`s
- Doesn't require, but should be done after: `UniqueEntitySlice`
- `get_many_unique`/`many_unique` methods
- requires: `UniqueEntityArray`
- `World::entity_unique` to match `World::entity` methods
- Doesn't require, but makes sense after:
`get_many_unique`/`many_unique`
- implement `TrustedEntityBorrow` for the `EntityRef` family
- Doesn't require, but makes sense after: `UniqueEntityVec`
# Objective
- Contributes to #15460
## Solution
- Added the following features:
- `std` (default)
- `async_executor` (default)
- `edge_executor`
- `critical-section`
- `portable-atomic`
- Gated `tracing` in `bevy_utils` to allow compilation on certain
platforms
- Switched from `tracing` to `log` for simple message logging within
`bevy_ecs`. Note that `tracing` supports capturing from `log` so this
should be an uncontroversial change.
- Fixed imports and added feature gates as required
- Made `bevy_tasks` optional within `bevy_ecs`. Turns out it's only
needed for parallel operations which are already gated behind
`multi_threaded` anyway.
## Testing
- Added to `compile-check-no-std` CI command
- `cargo check -p bevy_ecs --no-default-features --features
edge_executor,critical-section,portable-atomic --target
thumbv6m-none-eabi`
- `cargo check -p bevy_ecs --no-default-features --features
edge_executor,critical-section`
- `cargo check -p bevy_ecs --no-default-features`
## Draft Release Notes
Bevy's core ECS now supports `no_std` platforms.
In prior versions of Bevy, it was not possible to work with embedded or
niche platforms due to our reliance on the standard library, `std`. This
has blocked a number of novel use-cases for Bevy, such as an embedded
database for IoT devices, or for creating games on retro consoles.
With this release, `bevy_ecs` no longer requires `std`. To use Bevy on a
`no_std` platform, you must disable default features and enable the new
`edge_executor` and `critical-section` features. You may also need to
enable `portable-atomic` and `critical-section` if your platform does
not natively support all atomic types and operations used by Bevy.
```toml
[dependencies]
bevy_ecs = { version = "0.16", default-features = false, features = [
# Required for platforms with incomplete atomics (e.g., Raspberry Pi Pico)
"portable-atomic",
"critical-section",
# Optional
"bevy_reflect",
"serialize",
"bevy_debug_stepping",
"edge_executor"
] }
```
Currently, this has been tested on bare-metal x86 and the Raspberry Pi
Pico. If you have trouble using `bevy_ecs` on a particular platform,
please reach out either through a GitHub issue or in the `no_std`
working group on the Bevy Discord server.
Keep an eye out for future `no_std` updates as we continue to improve
the parity between `std` and `no_std`. We look forward to seeing what
kinds of applications are now possible with Bevy!
## Notes
- Creating PR in draft to ensure CI is passing before requesting
reviews.
- This implementation has no support for multithreading in `no_std`,
especially due to `NonSend` being unsound if allowed in multithreading.
The reason is we cannot check the `ThreadId` in `no_std`, so we have no
mechanism to at-runtime determine if access is sound.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Vic <59878206+Victoronz@users.noreply.github.com>
# Objective
Example error message beforehand:
```
error[B0001]: Query<&mut Data, ()> in system bevytest::main::{{closure}} accesses component(s)Data in a way that conflicts with a previous…
```
# Objective
- Cleanup deprecated code
## Solution
- Removed `#[deprecated]` items which were marked as such in 0.15 or
prior versions.
## Migration Guide
- The following deprecated items were removed: `Events::get_reader`,
`Events::get_reader_current`, `ManualEventReader`,
`Condition::and_then`, `Condition::or_else`, `World::,many_entities`,
`World::many_entities_mut`, `World::get_many_entities`,
`World::get_many_entities_dynamic`, `World::get_many_entities_mut`,
`World::get_many_entities_dynamic_mut`,
`World::get_many_entities_from_set_mut`
# Objective
Expand `track_change_detection` feature to also track entity spawns and
despawns. Use this to create better error messages.
# Solution
Adds `Entities::entity_get_spawned_or_despawned_by` as well as `{all
entity reference types}::spawned_by`.
This also removes the deprecated `get_many_entities_mut` & co (and
therefore can't land in 0.15) because we don't yet have no Polonius.
## Testing
Added a test that checks that the locations get updated and these
updates are ordered correctly vs hooks & observers.
---
## Showcase
Access location:
```rust
let mut world = World::new();
let entity = world.spawn_empty().id();
println!("spawned by: {}", world.entity(entity).spawned_by());
```
```
spawned by: src/main.rs:5:24
```
Error message (with `track_change_detection`):
```rust
world.despawn(entity);
world.entity(entity);
```
```
thread 'main' panicked at src/main.rs:11:11:
Entity 0v1#4294967296 was despawned by src/main.rs:10:11
```
and without:
```
thread 'main' panicked at src/main.rs:11:11:
Entity 0v1#4294967296 does not exist (enable `track_change_detection` feature for more details)
```
Similar error messages now also exists for `Query::get`,
`World::entity_mut`, `EntityCommands` creation and everything that
causes `B0003`, e.g.
```
error[B0003]: Could not insert a bundle (of type `MaterialMeshBundle<StandardMaterial>`) for entity Entity { index: 7, generation: 1 }, which was despawned by src/main.rs:10:11. See: https://bevyengine.org/learn/errors/#b0003
```
---------
Co-authored-by: kurk070ff <108901106+kurk070ff@users.noreply.github.com>
Co-authored-by: Freya Pines <freya@MacBookAir.lan>
Co-authored-by: Freya Pines <freya@Freyas-MacBook-Air.local>
Co-authored-by: Matty Weatherley <weatherleymatthew@gmail.com>
# Objective
When calling any of the `sort` methods on a `QueryManyIter` with mutable
data, `collect_inner()` must be called before fetching items. Remove the
need for that call.
## Solution
Have the `sort` methods `collect()` the entity list into a `Vec` before
returning.
# Objective
Allow resources to be accessed soundly by `QueryData` and `QueryFilter`
implementations.
This mostly works today, and is used in `bevy-trait-query` and will be
used by #16810. The problem is that the access is not made visible to
the executor, so it would be possible for a system with resource access
in a query to run concurrently with a system that accesses the resource
with `ResMut`, resulting in Undefined Behavior.
## Solution
Define calling `add_resource_read` or `add_resource_write` in
`WorldQuery::update_component_access` to be a supported way to declare
resource access in a query.
Modify `QueryState::new_with_access` to check for resource access and
report it in `archetype_component_acccess`.
Modify `FilteredAccess::is_compatible` to consider resource access
conflicting even on queries with disjoint filters.
# Objective
We were waiting for 1.83 to address most of these, due to a bug with
`missing_docs` and `expect`. Relates to, but does not entirely complete,
#15059.
## Solution
- Upgrade to 1.83
- Switch `allow(missing_docs)` to `expect(missing_docs)`
- Remove a few now-unused `allow`s along the way, or convert to `expect`
## Objective
Thanks to @eugineerd's work on entity cloning (#16132), we now have a
robust way to copy components between entities. We can extend this to
implement some useful functionality that would have been more
complicated before.
Closes#15350.
## Solution
`EntityCloneBuilder` now automatically includes required components
alongside any component added/removed from the component filter.
Added the following methods to `EntityCloneBuilder`:
- `move_components`
- `without_required_components`
Added the following methods to `EntityWorldMut` and `EntityCommands`:
- `clone_with`
- `clone_components`
- `move_components`
Also added `clone_and_spawn` and `clone_and_spawn_with` to
`EntityWorldMut` (`EntityCommands` already had them).
## Showcase
```
assert_eq!(world.entity(entity_a).get::<B>(), Some(&B));
assert_eq!(world.entity(entity_b).get::<B>(), None);
world.entity_mut(entity_a).clone_components::<B>(entity_b);
assert_eq!(world.entity(entity_a).get::<B>(), Some(&B));
assert_eq!(world.entity(entity_b).get::<B>(), Some(&B));
assert_eq!(world.entity(entity_a).get::<C>(), Some(&C(5)));
assert_eq!(world.entity(entity_b).get::<C>(), None);
world.entity_mut(entity_a).move_components::<C>(entity_b);
assert_eq!(world.entity(entity_a).get::<C>(), None);
assert_eq!(world.entity(entity_b).get::<C>(), Some(&C(5)));
```
# Objective
- Minor consistency improvement in proc macro code.
- Remove `get_path_direct` since it was only used once anyways and
doesn't add much.
## Solution
- Possibly a minor performance improvement since the `Cargo.toml` wont
be parsed as often.
## Testing
- I don't think it breaks anything.
- This is my first time working on bevy itself. Is there a script to do
a quick verify of my pr?
## Other PR
Similar to #7536 but has no extra dependencies.
Co-authored-by: François Mockers <mockersf@gmail.com>
# Objective
- Writing an API, and I want to allow users to pass in extra data
alongside the API provided input, and tuples are the most natural
extension in this case.
- Bring `SystemInput` up to par with `SystemParam` for tuple support.
## Solution
- Added impls for tuples up to 8 elements. If you need a 9-arity tuple
or more, write your own `SystemInput` type (it's incredibly simple to
do).
## Testing
- Added a test demonstrating this.
---
## Showcase
Tuples of arbitrary`SystemInput`s are now supported:
```rust
fn by_value((In(a), In(b)): (In<usize>, In<usize>)) -> usize {
a + b
}
fn by_mut((InMut(a), In(b)): (InMut<usize>, In<usize>)) {
*a += b;
}
let mut world = World::new();
let mut by_value = IntoSystem::into_system(by_value);
let mut by_mut = IntoSystem::into_system(by_mut);
by_value.initialize(&mut world);
by_mut.initialize(&mut world);
assert_eq!(by_value.run((12, 24), &mut world), 36);
let mut a = 10;
let b = 5;
by_mut.run((&mut a, b), &mut world);
assert_eq!(*a, 15);
```
## Objective
Some structs and methods in the ECS internals have names that don't
describe their purpose very well, and sometimes don't have docs either.
Also, the function `remove_bundle_from_archetype` is a counterpart to
`BundleInfo::add_bundle_to_archetype`, but isn't a method and is in a
different file.
## Solution
- Renamed the following structs and added docs:
| Before | After |
|----------------------|------------------------------|
| `AddBundle` | `ArchetypeAfterBundleInsert` |
| `InsertBundleResult` | `ArchetypeMoveType` |
- Renamed the following methods:
| Before | After |
|---------------------------------------|----------------------------------------------|
| `Edges::get_add_bundle` | `Edges::get_archetype_after_bundle_insert` |
| `Edges::insert_add_bundle` |
`Edges::cache_archetype_after_bundle_insert` |
| `Edges::get_remove_bundle` |
`Edges::get_archetype_after_bundle_remove` |
| `Edges::insert_remove_bundle` |
`Edges::cache_archetype_after_bundle_remove` |
| `Edges::get_take_bundle` | `Edges::get_archetype_after_bundle_take` |
| `Edges::insert_take_bundle` |
`Edges::cache_archetype_after_bundle_take` |
- Moved `remove_bundle_from_archetype` from `world/entity_ref.rs` to
`BundleInfo`. I left the function in entity_ref in the first commit for
comparison, look there for the diff of comments and whatnot.
- Tidied up docs:
- General grammar and spacing.
- Made the usage of "insert" and "add" more consistent.
- Removed references to information that isn't there.
- Renamed `BundleInfo::add_bundle_to_archetype` to
`BundleInfo::insert_bundle_into_archetype` for consistency.
# Objective
Fixes#16776
## Solution
- reflect `&'static Location` as an opaque type
- I've added this to `impls/std.rs` because other core types are there
too. Maybe they should be split out into a `core.rs` in another PR.
- add source location to `EventId` (behind the
`tracking_change_detection` feature flag)
## Testing
---
## Showcase
```rust
fn apply_damage_to_health(
mut dmg_events: EventReader<DealDamage>,
) {
for (event, event_id) in dmg_events.read_with_id() {
info!(
"Applying {} damage, triggered by {}",
event.amount, event_id.caller
);
…
```
```
2024-12-12T01:21:50.126827Z INFO event: Applying 9 damage, triggered by examples/ecs/event.rs:47:16
```
## Migration Guide
- If you manually construct a `SendEvent`, use `SendEvent::new()`
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Fixes#16645
## Solution
Keep track of components in callstack when registering required
components.
## Testing
Added a test checking that the error fires.
---
## Showcase
```rust
#[derive(Component, Default)]
#[require(B)]
struct A;
#[derive(Component, Default)]
#[require(A)]
struct B;
World::new().spawn(A);
```
```
thread 'main' panicked at /home/vj/workspace/rust/bevy/crates/bevy_ecs/src/component.rs:415:13:
Recursive required components detected: A → B → A
```
---------
Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
Updating dependencies; adopted version of #15696. (Supercedes #15696.)
Long answer: hashbrown is no longer using ahash by default, meaning that
we can't use the default-hasher methods with ahasher. So, we have to use
the longer-winded versions instead. This takes the opportunity to also
switch our default hasher as well, but without actually enabling the
default-hasher feature for hashbrown, meaning that we'll be able to
change our hasher more easily at the cost of all of these method calls
being obnoxious forever.
One large change from 0.15 is that `insert_unique_unchecked` is now
`unsafe`, and for cases where unsafe code was denied at the crate level,
I replaced it with `insert`.
## Migration Guide
`bevy_utils` has updated its version of `hashbrown` to 0.15 and now
defaults to `foldhash` instead of `ahash`. This means that if you've
hard-coded your hasher to `bevy_utils::AHasher` or separately used the
`ahash` crate in your code, you may need to switch to `foldhash` to
ensure that everything works like it does in Bevy.
# Objective
- Fixes#16497
- This is my first PR, so I'm still learning to contribute to the
project
## Solution
- Added struct `UnregisterSystemCached` and function
`unregister_system_cached`
- renamed `World::run_system_with_input` to `run_system_with`
- reordered input parameters for `World::run_system_once_with`
## Testing
- Added a crude test which registers a system via
`World::register_system_cached`, and removes it via
`Command::unregister_system_cached`.
## Migration Guide
- Change all occurrences of `World::run_system_with_input` to
`World::run_system_with`.
- swap the order of input parameters for `World::run_system_once_with`
such that the system comes before the input.
---------
Co-authored-by: Paul Mattern <mail@paulmattern.dev>
## Objective
Follow-up to #16672.
`EntityCommands::clone` looks the same as the `Clone` trait, which could
be confusing. A discord discussion has made me realize that's probably a
bigger problem than I thought. Oops :P
## Solution
Renamed `EntityCommands::clone` to `EntityCommands::clone_and_spawn`,
renamed `EntityCommands::clone_with` to
`EntityCommands::clone_and_spawn_with`. Also added some docs explaining
the commands' relation to `Clone` (components need to implement it (or
`Reflect`)).
## Showcase
```
// Create a new entity and keep its EntityCommands
let mut entity = commands.spawn((ComponentA(10), ComponentB(20)));
// Create a clone of the first entity
let mut entity_clone = entity.clone_and_spawn();
```
## The Bikeshed
- `clone_and_spawn` (Alice's suggestion)
- `spawn_clone` (benfrankel's suggestion)
- `spawn_cloned` (rparrett's suggestion)
# Objective
The documentation for `Query::transmute_lens` lists some allowed
transmutes, but the list is incomplete.
## Solution
Document the underlying rules for what transmutes are allowed.
Add a longer list of examples. Write them as doc tests to ensure that
those examples are actually allowed.
I'm assuming that anything that can be done today is intended to be
supported! If any of these examples are things we plan to prohibit in
the future then we can add some warnings to that effect.
# Objective
- A `Trigger` has multiple associated `Entity`s - the entity observing
the event, and the entity that was targeted by the event.
- The field `entity: Entity` encodes no semantic information about what
the entity is used for, you can already tell that it's an `Entity` by
the type signature!
## Solution
- Rename `trigger.entity()` to `trigger.target()`
---
## Changelog
- `Trigger`s are associated with multiple entities. `Trigger::entity()`
has been renamed to `Trigger::target()` to reflect the semantics of the
entity being returned.
## Migration Guide
- Rename `Trigger::entity()` to `Trigger::target()`.
- Rename `ObserverTrigger::entity` to `ObserverTrigger::target`
# Objective
Fixes#16706
## Solution
- Added new method: `try_resource_scope` which returns `None` if the
requested resource doesn't exist.
- Changed the `resource_scope` test to use `try_resource_scope` as well
to test for the `None` case.
---
## Showcase
```rust
world.try_resource_scope::<MyResource, _>(|world, mut my_resource| {
// do something with the resource if it exists
});
```
# Objective
Fixes typos in bevy project, following suggestion in
https://github.com/bevyengine/bevy-website/pull/1912#pullrequestreview-2483499337
## Solution
I used https://github.com/crate-ci/typos to find them.
I included only the ones that feel undebatable too me, but I am not in
game engine so maybe some terms are expected.
I left out the following typos:
- `reparametrize` => `reparameterize`: There are a lot of occurences, I
believe this was expected
- `semicircles` => `hemicircles`: 2 occurences, may mean something
specific in geometry
- `invertation` => `inversion`: may mean something specific
- `unparented` => `parentless`: may mean something specific
- `metalness` => `metallicity`: may mean something specific
## Testing
- Did you test these changes? If so, how? I did not test the changes,
most changes are related to raw text. I expect the others to be tested
by the CI.
- Are there any parts that need more testing? I do not think
- How can other people (reviewers) test your changes? Is there anything
specific they need to know? To me there is nothing to test
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
---
## Migration Guide
> This section is optional. If there are no breaking changes, you can
delete this section.
(kept in case I include the `reparameterize` change here)
- If this PR is a breaking change (relative to the last release of
Bevy), describe how a user might need to migrate their code to support
these changes
- Simply adding new functionality is not a breaking change.
- Fixing behavior that was definitely a bug, rather than a questionable
design choice is not a breaking change.
## Questions
- [x] Should I include the above typos? No
(https://github.com/bevyengine/bevy/pull/16702#issuecomment-2525271152)
- [ ] Should I add `typos` to the CI? (I will check how to configure it
properly)
This project looks awesome, I really enjoy reading the progress made,
thanks to everyone involved.
# Objective
- Remove `derive_more`'s error derivation and replace it with
`thiserror`
## Solution
- Added `derive_more`'s `error` feature to `deny.toml` to prevent it
sneaking back in.
- Reverted to `thiserror` error derivation
## Notes
Merge conflicts were too numerous to revert the individual changes, so
this reversion was done manually. Please scrutinise carefully during
review.
## Objective
I was resolving a conflict between #16132 and my PR #15929 and thought
the `clone_entity` commands made more sense in `EntityCommands`.
## Solution
Moved `Commands::clone_entity` to `EntityCommands::clone`, moved
`Commands::clone_entity_with` to `EntityCommands::clone_with`.
## Testing
Ran the two tests that used the old methods.
## Showcase
```
// Create a new entity and keep its EntityCommands.
let mut entity = commands.spawn((ComponentA(10), ComponentB(20)));
// Create a clone of the first entity
let mut entity_clone = entity.clone();
```
The only potential downside is that the method name is now the same as
the one from the `Clone` trait. `EntityCommands` doesn't implement
`Clone` though, so there's no actual conflict.
Maybe I'm biased because this'll work better with my PR, but I think the
UX is nicer regardless.
# Objective
- Fixes#16498
## Solution
- Trivially swaps ordering of hooks and observers for all call sites
where they are triggered for `on_replace` or `on_remove`
## Testing
- Just CI
---
## Migration Guide
The order of hooks and observers for `on_replace` and `on_remove` has
been swapped. Observers are now run before hooks. This is a more natural
ordering where the removal ordering is inverted compared to the
insertion ordering.
# Objective
Error handling in bevy is hard. See for reference
https://github.com/bevyengine/bevy/issues/11562,
https://github.com/bevyengine/bevy/issues/10874 and
https://github.com/bevyengine/bevy/issues/12660. The goal of this PR is
to make it better, by allowing users to optionally return `Result` from
systems as outlined by Cart in
<https://github.com/bevyengine/bevy/issues/14275#issuecomment-2223708314>.
## Solution
This PR introduces a new `ScheuleSystem` type to represent systems that
can be added to schedules. Instances of this type contain either an
infallible `BoxedSystem<(), ()>` or a fallible `BoxedSystem<(),
Result>`. `ScheuleSystem` implements `System<In = (), Out = Result>` and
replaces all uses of `BoxedSystem` in schedules. The async executor now
receives a result after executing a system, which for infallible systems
is always `Ok(())`. Currently it ignores this result, but more useful
error handling could also be implemented.
Aliases for `Error` and `Result` have been added to the `bevy_ecs`
prelude, as well as const `OK` which new users may find more friendly
than `Ok(())`.
## Testing
- Currently there are not actual semantics changes that really require
new tests, but I added a basic one just to make sure we don't break
stuff in the future.
- The behavior of existing systems is totally unchanged, including
logging.
- All of the existing systems tests pass, and I have not noticed
anything strange while playing with the examples
## Showcase
The following minimal example prints "hello world" once, then completes.
```rust
use bevy::prelude::*;
fn main() {
App::new().add_systems(Update, hello_world_system).run();
}
fn hello_world_system() -> Result {
println!("hello world");
Err("string")?;
println!("goodbye world");
OK
}
```
## Migration Guide
This change should be pretty much non-breaking, except for users who
have implemented their own custom executors. Those users should use
`ScheduleSystem` in place of `BoxedSystem<(), ()>` and import the
`System` trait where needed. They can choose to do whatever they wish
with the result.
## Current Work
+ [x] Fix tests & doc comments
+ [x] Write more tests
+ [x] Add examples
+ [X] Draft release notes
## Draft Release Notes
As of this release, systems can now return results.
First a bit of background: Bevy has hisotrically expected systems to
return the empty type `()`. While this makes sense in the context of the
ecs, it's at odds with how error handling is typically done in rust:
returning `Result::Error` to indicate failure, and using the
short-circuiting `?` operator to propagate that error up the call stack
to where it can be properly handled. Users of functional languages will
tell you this is called "monadic error handling".
Not being able to return `Results` from systems left bevy users with a
quandry. They could add custom error handling logic to every system, or
manually pipe every system into an error handler, or perhaps sidestep
the issue with some combination of fallible assignents, logging, macros,
and early returns. Often, users would just litter their systems with
unwraps and possible panics.
While any one of these approaches might be fine for a particular user,
each of them has their own drawbacks, and none makes good use of the
language. Serious issues could also arrise when two different crates
used by the same project made different choices about error handling.
Now, by returning results, systems can defer error handling to the
application itself. It looks like this:
```rust
// Previous, handling internally
app.add_systems(my_system)
fn my_system(window: Query<&Window>) {
let Ok(window) = query.get_single() else {
return;
};
// ... do something to the window here
}
// Previous, handling externally
app.add_systems(my_system.pipe(my_error_handler))
fn my_system(window: Query<&Window>) -> Result<(), impl Error> {
let window = query.get_single()?;
// ... do something to the window here
Ok(())
}
// Previous, panicking
app.add_systems(my_system)
fn my_system(window: Query<&Window>) {
let window = query.single();
// ... do something to the window here
}
// Now
app.add_systems(my_system)
fn my_system(window: Query<&Window>) -> Result {
let window = query.get_single()?;
// ... do something to the window here
Ok(())
}
```
There are currently some limitations. Systems must either return `()` or
`Result<(), Box<dyn Error + Send + Sync + 'static>>`, with no
in-between. Results are also ignored by default, and though implementing
a custom handler is possible, it involves writing your own custom ecs
executor (which is *not* recomended).
Systems should return errors when they cannot perform their normal
behavior. In turn, errors returned to the executor while running the
schedule will (eventually) be treated as unexpected. Users and library
authors should prefer to return errors for anything that disrupts the
normal expected behavior of a system, and should only handle expected
cases internally.
We have big plans for improving error handling further:
+ Allowing users to change the error handling logic of the default
executors.
+ Adding source tracking and optional backtraces to errors.
+ Possibly adding tracing-levels (Error/Warn/Info/Debug/Trace) to
errors.
+ Generally making the default error logging more helpful and
inteligent.
+ Adding monadic system combininators for fallible systems.
+ Possibly removing all panicking variants from our api.
---------
Co-authored-by: Zachary Harrold <zac@harrold.com.au>
# Objective
On the web, it's common to attach observers to windows. As @viridia has
discovered, this can be quite a nice paradigm in bevy as well when
applied to observers. The changes here are intended to make this
possible.
+ Adds a new default picking back-end as part to the core picking plugin
(which can be disabled) that causes pointers on windows to treat the
window entity as the final hit, behind everything else. This means
clicking empty space now dispatches normal picking events to the window,
and is especially nice for drag-and-drop functionality.
+ Adds a new traversal type, specific to picking events, that causes
them to bubble up to the window entity after they reach the root of the
hierarchy.
## Solution
The window picking back-end is extremely simple, but the bubbling
changes are much more complex, since they require doing a different
traversal depending on the picking event.
To achieve this, `Traversal` has been made generic over an associated
sized data type `D`. Observer bounds have been changed such that
`Event::Traversal<D>` is required for `Trigger<D>`. A blanket
implementation has been added for `()` and `Parent` that preserves the
existing functionality. A new `PointerTraversal` traversal has been
implemented, with a blanket implementation for `Traversal<Pointer<E>>`.
It is still possible to use `Parent` as the traversal for any event,
because of the blanket implementation. It is now possible for users to
add other custom traversals, which read event data during traversal.
## Testing
I tested these changes locally on some picking UI prototypes I have been
playing with. I also tested them on the picking examples.
---------
Co-authored-by: Martín Maita <47983254+mnmaita@users.noreply.github.com>