# Objective
Alternative to #9660, which is outdated since "required components"
landed.
Fixes#9655
## Solution
This is a different approach than the linked PR, slotting the warning
into an existing check for zero or negative font sizes in the text
pipeline.
## Testing
Replaced a font size with `0.0` in `examples/ui/text.rs`.
```
2025-01-22T23:26:08.239688Z INFO bevy_winit::system: Creating new window App (0v1)
2025-01-22T23:26:08.617505Z WARN bevy_text::pipeline: Text span 10v1 has a font size <= 0.0. Nothing will be displayed.
```
# Objective
- Contributes to #15460
## Solution
- Switched `tracing` for `log` for the atomically challenged platforms
- Setup feature flags as required
- Added to `compile-check-no-std` CI task
- Made `crossbeam-channel` optional depending on `std`.
## Testing
- CI
---
## Notes
- `crossbeam-channel` provides a MPMC channel type which isn't readily
replicable in `no_std`, and is only used for a `bevy_render`
integration. As such, I've feature-gated the `TimeReceiver` and
`TimeSender` types.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Fixes#14708
Also fixes some commands not updating tracked location.
## Solution
`ObserverTrigger` has a new `caller` field with the
`track_change_detection` feature;
hooks take an additional caller parameter (which is `Some(…)` or `None`
depending on the feature).
## Testing
See the new tests in `src/observer/mod.rs`
---
## Showcase
Observers now know from where they were triggered (if
`track_change_detection` is enabled):
```rust
world.observe(move |trigger: Trigger<OnAdd, Foo>| {
println!("Added Foo from {}", trigger.caller());
});
```
## Migration
- hooks now take an additional `Option<&'static Location>` argument
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- Contributes to #15460
## Solution
- Switched `tracing` for `log` for the atomically challenged platforms
- Setup feature flags as required
- Added to `compile-check-no-std` CI task
## Testing
- CI
---
## Notes
- _Very_ easy one this time. Most of the changes here are just feature
definitions and documentation within the `Cargo.toml`
# Objective
Add reflection support to more `glam` `Vec` types, specifically
* I8Vec2
* I8Vec3
* I8Vec4
* U8Vec2
* U8Vec3
* U8Vec4
* I16Vec2
* I16Vec3
* I16Vec4
* U16Vec2
* U16Vec3
* U16Vec4
I needed to do this because I'm using various of these in my Bevy types,
and due to the orphan rules, I can't make these impls locally.
## Solution
Used `impl_reflect!` like for the existing types.
## Testing
This should not require additional testing, though I have verified that
reflection now works for these types in my own project.
This commit makes Bevy use change detection to only update
`RenderMaterialInstances` and `RenderMeshMaterialIds` when meshes have
been added, changed, or removed. `extract_mesh_materials`, the system
that extracts these, now follows the pattern that
`extract_meshes_for_gpu_building` established.
This improves frame time of `many_cubes` from 3.9ms to approximately
3.1ms, which slightly surpasses the performance of Bevy 0.14.
(Resubmitted from #16878 to clean up history.)

---------
Co-authored-by: Charlotte McElwain <charlotte.c.mcelwain@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
## 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
Fixes#17416
## Solution
I just included ReflectFromReflect in all macros and implementations. I
think this should be ok, at least it compiles properly and does fix the
errors in my test code.
## Testing
I generated a DynamicMap and tried to convert it into a concrete
`HashMap` as a `Box<dyn Reflect>`. Without my fix, it doesn't work,
because this line panics:
```rust
let rfr = ty.data::<ReflectFromReflect>().unwrap();
```
where `ty` is the `TypeRegistration` for the (matching) `HashMap`.
I don't know why `ReflectFromReflect` wasn't included everywhere, I
assume that it was an oversight and not an architecture decision I'm not
aware of.
# Migration Guide
The hasher in reflected `HashMap`s and `HashSet`s now have to implement
`Default`. This is the case for the ones provided by Bevy already, and
is generally a sensible thing to do.
# 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
Fixes#14970
## Solution
It seems the clamp call in `ui.wgsl` had the parameters order incorrect.
## Testing
Tested using examples/ui in native and my current project in wasm - both
in linux.
Could use some help with testing in other platforms.
---
# 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.
# Objective
The gltf-json crate seems like it strips/adds an `_` when doing the name
comparison for custom vertex attributes.
* gltf-json
[add](88e719d5de/gltf-json/src/mesh.rs (L341))
* gltf-json
[strip](88e719d5de/gltf-json/src/mesh.rs (L298C12-L298C42))
* [bevy's
handling](b66c3ceb0e/crates/bevy_gltf/src/vertex_attributes.rs (L273-L276))
seems like it uses the non-underscore'd version.
The bevy example gltf:
[barycentric.gltf](b66c3ceb0e/assets/models/barycentric/barycentric.gltf),
includes two underscores: `__BARYCENTRIC` in the gltf file, resulting in
needing `_BARYCENTRIC` (one underscore) as the attribute name in Bevy.
This extra underscore is redundant and does not appear if exporting from
blender, which only requires a single underscore to trigger the
attribute export.
I'm not sure if we want to change the example itself (maybe there's a
reason it has two underscores, I couldn't find a reason), but a docs
comment would help.
## Solution
add docs detailing the behavior
# Objective
Make the `animated_mesh` example more intuitive and easier for the user
to extend.
# Solution
The `animated_mesh` example shows how to spawn a single mesh and play a
single animation. The original code is roughly:
1. In `setup_mesh_and_animation`, spawn an entity with a SceneRoot that
will load and spawn the mesh. Also record the animation to play as a
resource.
2. Use `play_animation_once_loaded` to detect when any animation players
are spawned, then play the animation from the resource.
When I used this example as a starting point for my own app, I hit a
wall when trying to spawn multiple meshes with different animations.
`play_animation_once_loaded` tells me an animation player spawned
somewhere, but how do I get from there to the right animation? The
entity it runs on is spawned by the scene so I can't attach any data to
it?
The new code takes a different approach. Instead of a global resource,
the animation is recorded as a component on the entity with the
SceneRoot. Instead of detecting animation players spawning wherever, an
observer is attached to that specific entity.
This feels more intuitive and localised, and I think most users will
work out how to get from there to different animations and meshes. The
downside is more lines of code, and the "find the animation players"
part still feels a bit magical and inefficient.
# Side Notes
- The solution was mostly stolen from
https://github.com/bevyengine/bevy/issues/14852#issuecomment-2481401769.
- The example still feels too complicated.
- "Why do I have to make this graph to play one animation?"
- "Why can't I choose and play the animation in one step and avoid this
temporary component?"
- I think this requires engine changes.
- I originally started on a separate example of multiple meshes
([branch](https://github.com/bevyengine/bevy/compare/main...greeble-dev:bevy:animated-mesh-multiple)).
- I decided that the user could probably work this out themselves from
the single animation example.
- But maybe still worth following through.
# Testing
`cargo run --example animated_mesh`
---------
Co-authored-by: Rob Parrett <robparrett@gmail.com>
# Objective
`Text2d` ignores `TextBounds` when calculating the offset for text
aligment.
On main a text entity positioned in the center of the window with center
justification and 600px horizontal text bounds isn't centered like it
should be but shifted off to the right:
<img width="305" alt="hellox"
src="https://github.com/user-attachments/assets/8896c6f0-1b9f-4633-9c12-1de6eff5f3e1"
/>
(second example in the testing section below)
Fixes#14266
I already had a PR in review for this (#14270) but it used post layout
adjustment (which we want to avoid) and ignored `TextBounds`.
## Solution
* If `TextBounds` are present for an axis, use them instead of the size
of the computed text layout size to calculate the offset.
* Adjust the vertical offset of text so it's top is aligned with the top
of the texts bounding rect (when present).
## Testing
```
use bevy::prelude::*;
use bevy::color::palettes;
use bevy::sprite::Anchor;
use bevy::text::TextBounds;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.run();
}
fn example(commands: &mut Commands, dest: Vec3, justify: JustifyText) {
commands.spawn((
Sprite {
color: palettes::css::YELLOW.into(),
custom_size: Some(10. * Vec2::ONE),
anchor: Anchor::Center,
..Default::default()
},
Transform::from_translation(dest),
));
for a in [
Anchor::TopLeft,
Anchor::TopRight,
Anchor::BottomRight,
Anchor::BottomLeft,
] {
commands.spawn((
Text2d(format!("L R\n{:?}\n{:?}", a, justify)),
TextFont {
font_size: 14.0,
..default()
},
TextLayout {
justify,
..Default::default()
},
TextBounds::new(300., 75.),
Transform::from_translation(dest + Vec3::Z),
a,
));
}
}
fn setup(mut commands: Commands) {
commands.spawn(Camera2d::default());
for (i, j) in [
JustifyText::Left,
JustifyText::Right,
JustifyText::Center,
JustifyText::Justified,
]
.into_iter()
.enumerate()
{
example(&mut commands, (300. - 150. * i as f32) * Vec3::Y, j);
}
commands.spawn(Sprite {
color: palettes::css::YELLOW.into(),
custom_size: Some(10. * Vec2::ONE),
anchor: Anchor::Center,
..Default::default()
});
}
```
<img width="566" alt="cap"
src="https://github.com/user-attachments/assets/e6a98fa5-80b2-4380-a9b7-155bb49635b8"
/>
This probably looks really confusing but it should make sense if you
imagine each block of text surrounded by a 300x75 rectangle that is
anchored to the center of the yellow square.
#
```
use bevy::prelude::*;
use bevy::sprite::Anchor;
use bevy::text::TextBounds;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.run();
}
fn setup(mut commands: Commands) {
commands.spawn(Camera2d::default());
commands.spawn((
Text2d::new("hello"),
TextFont {
font_size: 60.0,
..default()
},
TextLayout::new_with_justify(JustifyText::Center),
TextBounds::new(600., 200.),
Anchor::Center,
));
}
```
<img width="338" alt="hello"
src="https://github.com/user-attachments/assets/e5e89364-afda-4baa-aca8-df4cdacbb4ed"
/>
The text being above the center is intended. When `TextBounds` are
present, the text block's offset is calculated using its `TextBounds`
not the layout size returned by cosmic-text.
#
Probably we should add a vertical alignment setting for Text2d. Didn't
do it here as this is intended for a 0.15.2 release.
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>
# Objective
Fixes#17164
## Solution
- Switch to `ubuntu-latest`
- Remove `libegl1-mesa`. It seems that whatever this was providing is
now covered by other deps or their deps?
## Testing
Tested [over here](https://github.com/rparrett/bevy/pull/21) by
commenting out workflow `if` condition.
Makes use of `std` explicit, simplifying a possible `no_std` port.
# Objective
- Contributes to #15460
- Simplify future `no_std` work on `bevy_asset`
## Solution
- Add `#![no_std]` to switch to `core::prelude` instead of
`std::prelude`
## Testing
- CI
---
## Notes
This is entirely a change around the names of imports and has no impact
on functionality. This just reduces the quantity of changes involved in
the (likely more controversial) `no_std`-ification of `bevy_asset`.
Fixes#17397.
Also renamed all variants into present-tense.
## Migration Guide
- `PointerAction::Pressed` has been seperated into two variants,
`PointerAction::Press` and `PointerAction::Release`.
- `PointerAction::Moved` has been renamed to `PointerAction::Move`.
- `PointerAction::Canceled` has been renamed to `PointerAction::Cancel`.
This commit overhauls the documentation in the Bevy scene loading
example. It adds thorough explanatory comments to guide new Rust and
Bevy developers. The rewritten docs clarify how to:
- Register types for reflection, enabling serialization and dynamic
property access
- Skip serializing certain fields with `#[reflect(skip_serializing)]`
- Use `FromWorld` for components that require runtime initialization
- Store and serialize `Resources` in scene files
- Load scenes using a `DynamicSceneRoot` and handle updates in a system
- Serialize a brand-new scene to a separate file asynchronously using
`IoTaskPool`
These additions aim to provide a clear, step-by-step reference that
demonstrates how to implement a scene-based workflow, making it easier
for beginners and experienced developers alike to use Bevy’s scene
system effectively.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
It's not immediately obvious that `TargetCamera` only works with UI node
entities. It's natural to assume from looking at something like the
`multiple_windows` example that it will work with everything.
## Solution
Rename `TargetCamera` to `UiTargetCamera`.
## Migration Guide
`TargetCamera` has been renamed to `UiTargetCamera`.
# Objective
Segment2d and Segment3d are currently hard to work with because unlike
many other primary shapes, they are bound to the origin.
The objective of this PR is to allow these segments to exist anywhere in
cartesian space, making them much more useful in a variety of contexts.
## Solution
Reworking the existing segment type's internal fields and methods to
allow them to exist anywhere in cartesian space.
I have done both reworks for 2d and 3d segments but I was unsure if I
should just have it all here or not so feel free to tell me how I should
proceed, for now I have only pushed Segment2d changes.
As I am not a very seasoned contributor, this first implementation is
very likely sloppy and will need some additional work from my end, I am
open to all criticisms and willing to work to get this to bevy's
standards.
## Testing
I am not very familiar with the standards of testing. Of course my
changes had to pass the thorough existing tests for primitive shapes.
I also checked the gizmo 2d shapes intersection example and everything
looked fine.
I did add a few utility methods to the types that have no tests yet. I
am willing to implement some if it is deemed necessary
## Migration Guide
The segment type constructors changed so if someone previously created a
Segment2d with a direction and length they would now need to use the
`from_direction` constructor
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Joona Aalto <jondolf.dev@gmail.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>
Added an external assets section to .gitignore. This prevents
contributors from accidentally adding or committing them.
I believe currently the only externel asset is the meshlet bunny.
This allows this:
```rust
#[derive(Component)]
#[require(StateScoped<MyState>(StateScoped(MyState)))]
struct ComponentA;
```
To be shortened to this:
```rust
#[derive(Component)]
#[require(StateScoped<MyState>)]
struct ComponentA;
```
When `MyState` implements `Default`.
Signed-off-by: Jean Mertz <git@jeanmertz.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
While working on more complex directional navigation work, I noticed a
few small things.
## Solution
Rather than stick them in a bigger PR, split them out now.
- Include more useful information when responding to
`DirectionalNavigationError`.
- Use the less controversial `Click` events (rather than `Pressed`) in
the example
- Implement add_looping_edges in terms of `add_edges`. Thanks @rparrett
for the idea.
## Testing
Ran the `directional_navigation` example and things still work.
# Objective
The safety documentation for `Ptr::assert_unique` is incomplete.
Currently it only mentions the existence of other `Ptr` instances, but
it should also mention that the underlying data must be mutable and that
there cannot be active references to it.
# Objective
While `add_looping_edges` is a helpful method for manually defining
directional navigation maps, we don't always want to loop around!
## Solution
Add a non-looping variant.
These commits are cherrypicked from the more complex #17247.
## Testing
I've updated the `directional_navigation` example to use these changes,
and verified that it works.
---------
Co-authored-by: Rob Parrett <robparrett@gmail.com>
Co-authored-by: Benjamin Brienen <benjamin.brienen@outlook.com>
# 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
UI node Outlines are clipped using their parent's clipping rect instead
of their own.
## Solution
Clip outlines using the UI node's own clipping rect.
I noticed that this component was not being returned correctly by the
`bevy_remote` api
```json
"errors": {
"bevy_picking::focus::PickingInteraction": {
"code": -23402,
"message": "Unknown component type: `bevy_picking::focus::PickingInteraction`"
}
}
```
# Objective
- Follow up work from
https://github.com/bevyengine/bevy/pull/17121#issuecomment-2576615700 to
keep the `cursor.rs` file more manageable.
## Solution
- Move `CustomCursor` and make it compile.
## Testing
- Ran the example: `cargo run --example custom_cursor_image
--features=custom_cursor`
- CI
# 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
- Bevy 0.15 added support for custom cursor images in
https://github.com/bevyengine/bevy/pull/14284.
- However, to do animated cursors using the initial support shipped in
0.15 means you'd have to animate the `Handle<Image>`: You can't use a
`TextureAtlas` like you can with sprites and UI images.
- For my use case, my cursors are spritesheets. To animate them, I'd
have to break them down into multiple `Image` assets, but that seems
less than ideal.
## Solution
- Allow users to specify a `TextureAtlas` field when creating a custom
cursor image.
- To create parity with Bevy's `TextureAtlas` support on `Sprite`s and
`ImageNode`s, this also allows users to specify `rect`, `flip_x` and
`flip_y`. In fact, for my own use case, I need to `flip_y`.
## Testing
- I added unit tests for `calculate_effective_rect` and
`extract_and_transform_rgba_pixels`.
- I added a brand new example for custom cursor images. It has controls
to toggle fields on and off. I opted to add a new example because the
existing cursor example (`window_settings`) would be far too messy for
showcasing these custom cursor features (I did start down that path but
decided to stop and make a brand new example).
- The new example uses a [Kenny cursor icon] sprite sheet. I included
the licence even though it's not required (and it's CC0).
- I decided to make the example just loop through all cursor icons for
its animation even though it's not a _realistic_ in-game animation
sequence.
- I ran the PNG through https://tinypng.com. Looks like it's about 35KB.
- I'm open to adjusting the example spritesheet if required, but if it's
fine as is, great.
[Kenny cursor icon]: https://kenney-assets.itch.io/crosshair-pack
---
## Showcase
https://github.com/user-attachments/assets/8f6be8d7-d1d4-42f9-b769-ef8532367749
## Migration Guide
The `CustomCursor::Image` enum variant has some new fields. Update your
code to set them.
Before:
```rust
CustomCursor::Image {
handle: asset_server.load("branding/icon.png"),
hotspot: (128, 128),
}
```
After:
```rust
CustomCursor::Image {
handle: asset_server.load("branding/icon.png"),
texture_atlas: None,
flip_x: false,
flip_y: false,
rect: None,
hotspot: (128, 128),
}
```
## References
- Feature request [originally raised in Discord].
[originally raised in Discord]:
https://discord.com/channels/691052431525675048/692572690833473578/1319836362219847681