# Objective
Now that #13432 has been merged, it's important we update our reflected
types to properly opt into this feature. If we do not, then this could
cause issues for users downstream who want to make use of
reflection-based cloning.
## Solution
This PR is broken into 4 commits:
1. Add `#[reflect(Clone)]` on all types marked `#[reflect(opaque)]` that
are also `Clone`. This is mandatory as these types would otherwise cause
the cloning operation to fail for any type that contains it at any
depth.
2. Update the reflection example to suggest adding `#[reflect(Clone)]`
on opaque types.
3. Add `#[reflect(clone)]` attributes on all fields marked
`#[reflect(ignore)]` that are also `Clone`. This prevents the ignored
field from causing the cloning operation to fail.
Note that some of the types that contain these fields are also `Clone`,
and thus can be marked `#[reflect(Clone)]`. This makes the
`#[reflect(clone)]` attribute redundant. However, I think it's safer to
keep it marked in the case that the `Clone` impl/derive is ever removed.
I'm open to removing them, though, if people disagree.
4. Finally, I added `#[reflect(Clone)]` on all types that are also
`Clone`. While not strictly necessary, it enables us to reduce the
generated output since we can just call `Clone::clone` directly instead
of calling `PartialReflect::reflect_clone` on each variant/field. It
also means we benefit from any optimizations or customizations made in
the `Clone` impl, including directly dereferencing `Copy` values and
increasing reference counters.
Along with that change I also took the liberty of adding any missing
registrations that I saw could be applied to the type as well, such as
`Default`, `PartialEq`, and `Hash`. There were hundreds of these to
edit, though, so it's possible I missed quite a few.
That last commit is **_massive_**. There were nearly 700 types to
update. So it's recommended to review the first three before moving onto
that last one.
Additionally, I can break the last commit off into its own PR or into
smaller PRs, but I figured this would be the easiest way of doing it
(and in a timely manner since I unfortunately don't have as much time as
I used to for code contributions).
## Testing
You can test locally with a `cargo check`:
```
cargo check --workspace --all-features
```
# Objective
Add a `UiRect::AUTO` const which is a `UiRect` with all its edge values
set to `Val::Auto`.
IIRC `UiRect`'s default for its fields a few versions ago was
`Val::Auto` because positions were represented using a `UiRect` and they
required `Val::Auto` as a default. Then when position was split up and
the `UiRect` default was changed, we forgot add a `UiRect::AUTO` const.
Extracted from my DLSS branch.
## Changelog
* Added `source_texture` and `destination_texture` to
`PostProcessWrite`, in addition to the existing texture views.
obtaining a reference to an empty enum is not possible in Rust, so I
just replaced any match on self with an `unreachable!()`
I checked if an enum is empty by checking if the `variant_patterns` vec
of the `EnumVariantOutputData` struct is empty
Fixes#18277
## Testing
I added one new unit test.
``` rust
#[test]
fn should_allow_empty_enums() {
#[derive(Reflect)]
enum Empty {}
assert_impl_all!(Empty: Reflect);
}
```
# Objective
In its existing form, the clamping that's done in `camera_system`
doesn't work well when the `physical_position` of the associated
viewport is nonzero. In such cases, it may produce invalid viewport
rectangles (i.e. not lying inside the render target), which may result
in crashes during the render pass.
The goal of this PR is to eliminate this possibility by making the
clamping behavior always result in a valid viewport rectangle when
possible.
## Solution
Incorporate the `physical_position` information into the clamping
behavior. In particular, always cut off enough so that it's contained in
the render target rather than clamping it to the same dimensions as the
target itself. In weirder situations, still try to produce a valid
viewport rectangle to avoid crashes.
## Testing
Tested these changes on my work branch where I encountered the crash.
# Objective
Currently experimenting with manually implementing
`Relationship`/`RelationshipTarget` to support associated edge data,
which means I need to replace the default hook implementations provided
by those traits. However, copying them over for editing revealed that
`UnsafeWorldCell::get_raw_command_queue` is `pub(crate)`, and I would
like to not have to clone the source collection, like the default impl.
So instead, I've taken to providing a safe abstraction for being able to
access entities and queue commands simultaneously.
## Solution
Added `World::entities_and_commands` and
`DeferredWorld::entities_and_commands`, which can be used like so:
```rust
let eid: Entity = /* ... */;
let (mut fetcher, mut commands) = world.entities_and_commands();
let emut = fetcher.get_mut(eid).unwrap();
commands.entity(eid).despawn();
```
## Testing
- Added a new test for each of the added functions.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Continuation to #16547 and #17954.
The `get_many` family are the last methods on `Query`/`QueryState` for
which we're still missing a `unique` version.
## Solution
Offer `get_many_unique`/`get_many_unique_mut` and
`get_many_unique_inner`!
Their implementation is the same as `get_many`, the difference lies in
their guaranteed-to-be unique inputs, meaning we never do any aliasing
checks.
To reduce confusion, we also rename `get_many_readonly` into
`get_many_inner` and the current `get_many_inner` into
`get_many_mut_inner` to clarify their purposes.
## Testing
Doc examples.
## Migration Guide
`get_many_inner` is now called `get_many_mut_inner`.
`get_many_readonly` is now called `get_many_inner`.
# Objective
- Fixes#18342.
## Solution
- Canonicalize the root path so that when we try to strip the prefix, it
matches the canonicalized asset path.
- This is basically just a followup to #18023.
## Testing
- Ran the hot_asset_reloading example and it no longer panics.
# Objective
The `ViewportConversionError` error type does not implement `Error`,
making it incompatible with `BevyError`.
## Solution
Derive `Error` for `ViewportConversionError`.
I chose to use `thiserror` since it's already a dependency, but do let
me know if we should be preferring `derive_more`.
## Testing
You can test this by trying to compile the following:
```rust
let error: BevyError = ViewportConversionError::InvalidData.into();
```
Registering dynamic bundles was not possible for the user yet.
It is alone not very useful though as there are no methods to clone,
move or remove components via a `BundleId`. This could be a follow-up
work if this PR is approved and such a third (besides `T: Bundle` and
`ComponentId`(s)) API for structural operation is desired. I certainly
would use a hypothetical `EntityClonerBuilder::allow_by_bundle_id`.
I personally still would like this register method because I have a
`Bundles`-like custom data structure and I would like to not reinvent
the wheel. Then instead of having boxed `ComponentId` slices in my
collection I could look up explicit and required components there.
For reference scroll up to the typed version right above the new one.
# Objective
I was setting up an asset loader that passes settings through to
`ImageLoader`, and i have to clone the settings to achieve this.
## Solution
Derive `Clone` for `ImageLoaderSettings` and `ImageFormatSetting`.
## Testing
Full CI passed.
I mistakenly thought that with the wgpu upgrade we'd have
`PARTIALLY_BOUND_BINDING_ARRAY` everywhere. Unfortunately this is not
the case. This PR adds a workaround back in.
Closes#18098.
Fix https://github.com/bevyengine/bevy/issues/17763.
Attachment info needs to be created outside of the command encoding
task, as it needs to be part of the serial node runners in order to get
the ordering correct.
Less data accessed and compared gives better batching performance.
# Objective
- Use a smaller id to represent the lightmap in batch data to enable a
faster implementation of draw streams.
- Improve batching performance for 3D sorted render phases.
## Solution
- 3D batching can use `LightmapSlabIndex` (a `NonMaxU32` which is 4
bytes) instead of the lightmap `AssetId<Image>` (an enum where the
largest variant is a 16-byte UUID) to discern the ability to batch.
## Testing
Tested main (yellow) vs this PR (red) on an M4 Max using the
`many_cubes` example with `WGPU_SETTINGS_PRIO=webgl2` to avoid
GPU-preprocessing, and modifying the materials in `many_cubes` to have
`AlphaMode::Blend` so that they would rely on the less efficient sorted
render phase batching.
<img width="1500" alt="Screenshot_2025-03-15_at_12 17 21"
src="https://github.com/user-attachments/assets/14709bd3-6d06-40fb-aa51-e1d2d606ebe3"
/>
A 44.75us or 7.5% reduction in median execution time of the batch and
prepare sorted render phase system for the `Transparent3d` phase
(handling 160k cubes).
---
## Migration Guide
- Changed: `RenderLightmap::new()` no longer takes an `AssetId<Image>`
argument for the asset id of the lightmap image.
# Objective
Installment of the #16547 series.
The vast majority of uses for these types will be the `Entity` case, so
it makes sense for it to be the default.
## Solution
`UniqueEntityVec`, `UniqueEntitySlice`, `UniqueEntityArray` and their
helper iterator aliases now have `Entity` as a default.
Unfortunately, this means the the `T` parameter for `UniqueEntityArray`
now has to be ordered after the `N` constant, which breaks the
consistency to `[T; N]`.
Same with about a dozen iterator aliases that take some `P`/`F`
predicate/function parameter.
This should however be an ergonomic improvement in most cases, so we'll
just have to live with this inconsistency.
## Migration Guide
Switch type parameter order for the relevant wrapper types/aliases.
# Objective
#13432 added proper reflection-based cloning. This is a better method
than cloning via `clone_value` for reasons detailed in the description
of that PR. However, it may not be immediately apparent to users why one
should be used over the other, and what the gotchas of `clone_value`
are.
## Solution
This PR marks `PartialReflect::clone_value` as deprecated, with the
deprecation notice pointing users to `PartialReflect::reflect_clone`.
However, it also suggests using a new method introduced in this PR:
`PartialReflect::to_dynamic`.
`PartialReflect::to_dynamic` is essentially a renaming of
`PartialReflect::clone_value`. By naming it `to_dynamic`, we make it
very obvious that what's returned is a dynamic type. The one caveat to
this is that opaque types still use `reflect_clone` as they have no
corresponding dynamic type.
Along with changing the name, the method is now optional, and comes with
a default implementation that calls out to the respective reflection
subtrait method. This was done because there was really no reason to
require manual implementors provide a method that almost always calls
out to a known set of methods.
Lastly, to make this default implementation work, this PR also did a
similar thing with the `clone_dynamic ` methods on the reflection
subtraits. For example, `Struct::clone_dynamic` has been marked
deprecated and is superseded by `Struct::to_dynamic_struct`. This was
necessary to avoid the "multiple names in scope" issue.
### Open Questions
This PR maintains the original signature of `clone_value` on
`to_dynamic`. That is, it takes `&self` and returns `Box<dyn
PartialReflect>`.
However, in order for this to work, it introduces a panic if the value
is opaque and doesn't override the default `reflect_clone`
implementation.
One thing we could do to avoid the panic would be to make the conversion
fallible, either returning `Option<Box<dyn PartialReflect>>` or
`Result<Box<dyn PartialReflect>, ReflectCloneError>`.
This makes using the method a little more involved (i.e. users have to
either unwrap or handle the rare possibility of an error), but it would
set us up for a world where opaque types don't strictly need to be
`Clone`. Right now this bound is sort of implied by the fact that
`clone_value` is a required trait method, and the default behavior of
the macro is to use `Clone` for opaque types.
Alternatively, we could keep the signature but make the method required.
This maintains that implied bound where manual implementors must provide
some way of cloning the value (or YOLO it and just panic), but also
makes the API simpler to use.
Finally, we could just leave it with the panic. It's unlikely this would
occur in practice since our macro still requires `Clone` for opaque
types, and thus this would only ever be an issue if someone were to
manually implement `PartialReflect` without a valid `to_dynamic` or
`reflect_clone` method.
## Testing
You can test locally using the following command:
```
cargo test --package bevy_reflect --all-features
```
---
## Migration Guide
`PartialReflect::clone_value` is being deprecated. Instead, use
`PartialReflect::to_dynamic` if wanting to create a new dynamic instance
of the reflected value. Alternatively, use
`PartialReflect::reflect_clone` to attempt to create a true clone of the
underlying value.
Similarly, the following methods have been deprecated and should be
replaced with these alternatives:
- `Array::clone_dynamic` → `Array::to_dynamic_array`
- `Enum::clone_dynamic` → `Enum::to_dynamic_enum`
- `List::clone_dynamic` → `List::to_dynamic_list`
- `Map::clone_dynamic` → `Map::to_dynamic_map`
- `Set::clone_dynamic` → `Set::to_dynamic_set`
- `Struct::clone_dynamic` → `Struct::to_dynamic_struct`
- `Tuple::clone_dynamic` → `Tuple::to_dynamic_tuple`
- `TupleStruct::clone_dynamic` → `TupleStruct::to_dynamic_tuple_struct`
# Objective
- Prevents #18291.
- Previously, attempting to direct-nested-load a subasset would return
the root of the nested-loaded asset. This is most problematic when doing
direct-nested-**untyped**-loads of subassets, where you may not even
realize you're dealing with the entirely wrong asset (at least with
typed loads, *most of the time* the root asset has a different type from
the subasset, and so at least you'd get an error that the types don't
match).
## Solution
- We now return an error when doing these kinds of loads.
Note an alternative would be to "solve" this problem, by just looking up
the appropriate subasset after doing the nested load. However there's
two problems: 1) we don't know which subassets of the root asset are
necessary for the subasset we are looking up (so any handles in that
subasset may never get registered), 2) a solution will likely hamper
attempts to resolve#18010. AFAICT, no one has complained about this
issue, so it doesn't seem critical to fix this for now.
## Testing
- Added a test to ensure this returns an error. I also checked that the
error before this was just a mismatched type error, meaning it was
trying to pass off the root asset type `CoolText` as the subasset type
`SubText` (which would have worked had I not been using typed loads).
# Objective
While poking at https://github.com/bevyengine/bevy/issues/17272, I
noticed a few small things to clean up.
## Solution
- Improve the docs
- ~~move `SystemErrorContext` out of the `handler.rs` module: it's not
an error handler~~
# Objective
Probably just because of an oversight, bounding primitives like `Aabb3d`
did not implement `Serialize`/`Deserialize` with the `serialize` feature
enabled, so the goal of this PR is to fill the gap.
## Solution
Derive it conditionally, just like we do for everything else. Also added
in `PartialEq`, just because I touched the files.
## Testing
Compiled with different feature combinations.
# Objective
When reviewing #18263, I noticed that `BevyManifest` internally stores a
`DocumentMut`, a mutable TOML document, instead of an `ImDocument`, an
immutable one. The process of creating a `DocumentMut` first involves
creating a `ImDocument` and then cloning all the referenced spans of
text into their own allocations (internally referred to as `despan` in
`toml_edit`). As such, using a `DocumentMut` without mutation is
strictly additional overhead.
In addition, I noticed that the filesystem operations associated with
reading a manifest and parsing it were written to be completed _while_ a
write-lock was held on `MANIFESTS`. This likely doesn't translate into a
performance or deadlock issue as the manifest files are generally small
and can be read quickly, but it is generally considered a bad practice.
## Solution
- Switched to `ImDocument<Box<str>>` instead of `DocumentMut`
- Re-ordered operations in `BevyManifest::shared` to minimise time spent
holding open the write-lock on `MANIFESTS`
## Testing
- CI
---
## Notes
I wasn't able to measure a meaningful performance difference with this
PR, so this is purely a code quality change and not one for performance.
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
# Objective
Upgrade to `cosmic-text` 0.13
https://github.com/pop-os/cosmic-text/releases
This should include some performance improvements for layout and system
font loading.
## Solution
Bump version, fix the one changed API.
## Testing
Tested some examples locally, will invoke the example runner.
## Layout Perf
||main fps|cosmic-13 fps|
|-|-|-|
|many_buttons --recompute-text --no-borders|6.79|9.42 🟩 +38.7%|
|many_text2d --no-frustum-culling --recompute|3.19|4.28 🟩 +34.0%|
|many_glyphs --recompute-text|7.09|11.17 🟩 +57.6%|
|text_pipeline |140.15|139.90 ⬜ -0.2%|
## System Font Loading Perf
I tested on macOS somewhat lazily by adding the following system to the
`system_fonts` example from #16365.
<details>
<summary>Expand code</summary>
```rust
fn exit_on_load(
mut reader: EventReader<bevy::text::SystemFontsAvailable>,
mut writer: EventWriter<AppExit>,
) {
for _evt in reader.read() {
writer.write(AppExit::Success);
}
}
```
</details>
And running `hyperfine 'cargo run --release --example system_fonts
--features=system_font'`.
The results were nearly identical with and without this PR cherry-picked
there.
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
The sort key for the transparent UI phase is a (float32, u32) pair
consisting of the stack index and the render entity's index.
I guess the render entity index was intended to break ties but it's not
needed as the sort is stable. It also assumes the indices of the render
entities are generated sequentially, which isn't guaranteed.
Fixes the issues with the text wrap example seen in #18266
## Solution
Change the sort key to just use the stack index alone.
# Objective
Fixes#18103#17330 introduced a significant compile time performance regression
(affects normal builds, clippy, and Rust Analyzer). While it did fix the
type-resolution bug (and the general approach there is still our best
known solution to the problem that doesn't involve [significant
maintenance
overhead](https://github.com/bevyengine/bevy/issues/18103#issuecomment-2702724676)),
the changes had a couple of issues:
1. It used a Mutex, which poses a significant threat to parallelization.
2. It externalized existing, relatively simple, performance critical
Bevy code to a crate outside of our control. I am not comfortable doing
that for cases like this. Going forward @bevyengine/maintainer-team
should be much stricter about this.
3. There were a number of other areas that introduced complexity and
overhead that I consider unnecessary for our use case. On a case by case
basis, if we encounter a need for more capabilities we can add them (and
weigh them against the cost of doing so).
## Solution
1. I moved us back to our original code as a baseline
2. I selectively ported over the minimal changes required to fix the
type resolution bug
3. I swapped `Mutex<BTreeMap<PathBuf, &'static Mutex<CargoManifest>>>`
for `RwLock<BTreeMap<PathBuf, CargoManifest>>`. Note that I used the
`parking_lot` RwLock because it has a mapping API that enables us to
return mapped guards.
# Objective
Prevents duplicate implementation between IntoSystemConfigs and
IntoSystemSetConfigs using a generic, adds a NodeType trait for more
config flexibility (opening the door to implement
https://github.com/bevyengine/bevy/issues/14195?).
## Solution
Followed writeup by @ItsDoot:
https://hackmd.io/@doot/rJeefFHc1x
Removes IntoSystemConfigs and IntoSystemSetConfigs, instead using
IntoNodeConfigs with generics.
## Testing
Pending
---
## Showcase
N/A
## Migration Guide
SystemSetConfigs -> NodeConfigs<InternedSystemSet>
SystemConfigs -> NodeConfigs<ScheduleSystem>
IntoSystemSetConfigs -> IntoNodeConfigs<InternedSystemSet, M>
IntoSystemConfigs -> IntoNodeConfigs<ScheduleSystem, M>
---------
Co-authored-by: Christian Hughes <9044780+ItsDoot@users.noreply.github.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
In updating examples to use the Improved Spawning API I got tripped up
on being able to spawn children with a Vec. I eventually figured out
that I could use `Children::spawn(SpawnIter(my_vec.into_iter()))` but
thought there might be a more ergonomic way to approach it. After
tinkering with it for a while I came up with the implementation here. It
allows authors to use `Children::spawn(my_vec)` as an equivalent
implementation.
## Solution
- Implements `<R: Relationship, B: Bundle SpawnableList<R> for Vec<B>`
- uses `alloc::vec::Vec` for compatibility with `no_std` (`std::Vec`
also inherits implementations against the `alloc::vec::Vec` because std
is a re-export of the alloc struct, thanks @bushrat011899 for the info
on this!)
## Testing
- Did you test these changes? If so, how?
- Opened the examples before and after and verified the same behavior
was observed. I did this on Ubuntu 24.04.2 LTS using `--features
wayland`.
- Are there any parts that need more testing?
- Other OS's and features can't hurt, but this is such a small change it
shouldn't be a problem.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Run the examples yourself with and without these changes.
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- see above
## Showcase
n/a
## Migration Guide
- Optional: you may use the new API to spawn `Vec`s of `Bundle` instead
of using the `SpawnIter` approach.
# Objective
Add `#[derive(Clone, PartialEq, Debug, Reflect)]` to DragEntry so it
matches the other picking events.
## Solution
Copy/paste (RIP Larry Tesler)
## Testing
Just ran cargo check. I don't believe this should break anything because
I did not remove any derives it had before.
---
# Objective
- Prevent usage of `println!`, `eprintln!` and the like because they
require `std`
- Fixes#17446
## Solution
- Enable the `print_stdout` and `print_stderr` clippy lints
- Replace all `println!` and `eprintln!` occurrences with `log::*` where
applicable or alternatively ignore the warnings
## Testing
- Run `cargo clippy --workspace` to ensure that there are no warnings
relating to printing to `stdout` or `stderr`
# Objective
Using `Reflect::clone_value` can be somewhat confusing to those
unfamiliar with how Bevy's reflection crate works. For example take the
following code:
```rust
let value: usize = 123;
let clone: Box<dyn Reflect> = value.clone_value();
```
What can we expect to be the underlying type of `clone`? If you guessed
`usize`, then you're correct! Let's try another:
```rust
#[derive(Reflect, Clone)]
struct Foo(usize);
let value: Foo = Foo(123);
let clone: Box<dyn Reflect> = value.clone_value();
```
What about this code? What is the underlying type of `clone`? If you
guessed `Foo`, unfortunately you'd be wrong. It's actually
`DynamicStruct`.
It's not obvious that the generated `Reflect` impl actually calls
`Struct::clone_dynamic` under the hood, which always returns
`DynamicStruct`.
There are already some efforts to make this a bit more apparent to the
end-user: #7207 changes the signature of `Reflect::clone_value` to
instead return `Box<dyn PartialReflect>`, signaling that we're
potentially returning a dynamic type.
But why _can't_ we return `Foo`?
`Foo` can obviously be cloned— in fact, we already derived `Clone` on
it. But even without the derive, this seems like something `Reflect`
should be able to handle. Almost all types that implement `Reflect`
either contain no data (trivially clonable), they contain a
`#[reflect_value]` type (which, by definition, must implement `Clone`),
or they contain another `Reflect` type (which recursively fall into one
of these three categories).
This PR aims to enable true reflection-based cloning where you get back
exactly the type that you think you do.
## Solution
Add a `Reflect::reflect_clone` method which returns `Result<Box<dyn
Reflect>, ReflectCloneError>`, where the `Box<dyn Reflect>` is
guaranteed to be the same type as `Self`.
```rust
#[derive(Reflect)]
struct Foo(usize);
let value: Foo = Foo(123);
let clone: Box<dyn Reflect> = value.reflect_clone().unwrap();
assert!(clone.is::<Foo>());
```
Notice that we didn't even need to derive `Clone` for this to work: it's
entirely powered via reflection!
Under the hood, the macro generates something like this:
```rust
fn reflect_clone(&self) -> Result<Box<dyn Reflect>, ReflectCloneError> {
Ok(Box::new(Self {
// The `reflect_clone` impl for `usize` just makes use of its `Clone` impl
0: Reflect::reflect_clone(&self.0)?.take().map_err(/* ... */)?,
}))
}
```
If we did derive `Clone`, we can tell `Reflect` to rely on that instead:
```rust
#[derive(Reflect, Clone)]
#[reflect(Clone)]
struct Foo(usize);
```
<details>
<summary>Generated Code</summary>
```rust
fn reflect_clone(&self) -> Result<Box<dyn Reflect>, ReflectCloneError> {
Ok(Box::new(Clone::clone(self)))
}
```
</details>
Or, we can specify our own cloning function:
```rust
#[derive(Reflect)]
#[reflect(Clone(incremental_clone))]
struct Foo(usize);
fn incremental_clone(value: &usize) -> usize {
*value + 1
}
```
<details>
<summary>Generated Code</summary>
```rust
fn reflect_clone(&self) -> Result<Box<dyn Reflect>, ReflectCloneError> {
Ok(Box::new(incremental_clone(self)))
}
```
</details>
Similarly, we can specify how fields should be cloned. This is important
for fields that are `#[reflect(ignore)]`'d as we otherwise have no way
to know how they should be cloned.
```rust
#[derive(Reflect)]
struct Foo {
#[reflect(ignore, clone)]
bar: usize,
#[reflect(ignore, clone = "incremental_clone")]
baz: usize,
}
fn incremental_clone(value: &usize) -> usize {
*value + 1
}
```
<details>
<summary>Generated Code</summary>
```rust
fn reflect_clone(&self) -> Result<Box<dyn Reflect>, ReflectCloneError> {
Ok(Box::new(Self {
bar: Clone::clone(&self.bar),
baz: incremental_clone(&self.baz),
}))
}
```
</details>
If we don't supply a `clone` attribute for an ignored field, then the
method will automatically return
`Err(ReflectCloneError::FieldNotClonable {/* ... */})`.
`Err` values "bubble up" to the caller. So if `Foo` contains `Bar` and
the `reflect_clone` method for `Bar` returns `Err`, then the
`reflect_clone` method for `Foo` also returns `Err`.
### Attribute Syntax
You might have noticed the differing syntax between the container
attribute and the field attribute.
This was purely done for consistency with the current attributes. There
are PRs aimed at improving this. #7317 aims at making the
"special-cased" attributes more in line with the field attributes
syntactically. And #9323 aims at moving away from the stringified paths
in favor of just raw function paths.
### Compatibility with Unique Reflect
This PR was designed with Unique Reflect (#7207) in mind. This method
actually wouldn't change that much (if at all) under Unique Reflect. It
would still exist on `Reflect` and it would still `Option<Box<dyn
Reflect>>`. In fact, Unique Reflect would only _improve_ the user's
understanding of what this method returns.
We may consider moving what's currently `Reflect::clone_value` to
`PartialReflect` and possibly renaming it to `partial_reflect_clone` or
`clone_dynamic` to better indicate how it differs from `reflect_clone`.
## Testing
You can test locally by running the following command:
```
cargo test --package bevy_reflect
```
---
## Changelog
- Added `Reflect::reflect_clone` method
- Added `ReflectCloneError` error enum
- Added `#[reflect(Clone)]` container attribute
- Added `#[reflect(clone)]` field attribute
# Objective
Part of the #16547 series.
The entity wrapper types often have some associated types an aliases
with them that cannot be re-exported into an outer module together.
Some helper types are best used with part of their path:
`bevy::ecs::entity::index_set::Slice` as `index_set::Slice`.
This has already been done for `entity::hash_set` and
`entity::hash_map`.
## Solution
Publicize the `index_set`, `index_map`, `unique_vec`, `unique_slice`,
and `unique_array` modules.
## Migration Guide
Any mention or import of types in the affected modules have to add the
respective module name to the import path.
F.e.:
`bevy::ecs::entity::EntityIndexSet` ->
`bevy::ecs::entity::index_set::EntityIndexSet`
# Objective
- #16883
- Improve the default behaviour of the exclusive fullscreen API.
## Solution
This PR changes the exclusive fullscreen window mode to require the type
`WindowMode::Fullscreen(MonitorSelection, VideoModeSelection)` and
removes `WindowMode::SizedFullscreen`. This API somewhat intentionally
more closely resembles Winit 0.31's upcoming fullscreen and video mode
API.
The new VideoModeSelection enum is specified as follows:
```rust
pub enum VideoModeSelection {
/// Uses the video mode that the monitor is already in.
Current,
/// Uses a given [`crate::monitor::VideoMode`]. A list of video modes supported by the monitor
/// is supplied by [`crate::monitor::Monitor::video_modes`].
Specific(VideoMode),
}
```
### Changing default behaviour
This might be contentious because it removes the previous behaviour of
`WindowMode::Fullscreen` which selected the highest resolution possible.
While the previous behaviour would be quite easy to re-implement as
additional options, or as an impl method on Monitor, I would argue that
this isn't an implementation that should be encouraged.
From the perspective of a Windows user, I prefer what the majority of
modern games do when entering fullscreen which is to preserve the OS's
current resolution settings, which allows exclusive fullscreen to be
entered faster, and to only have it change if I manually select it in
either the options of the game or the OS. The highest resolution
available is not necessarily what the user prefers.
I am open to changing this if I have just missed a good use case for it.
Likewise, the only functionality that `WindowMode::SizedFullscreen`
provided was that it selected the resolution closest to the current size
of the window so it was removed since this behaviour can be replicated
via the new `VideoModeSelection::Specific` if necessary.
## Out of scope
WindowResolution and scale factor act strangely in exclusive fullscreen,
this PR doesn't address it or regress it.
## Testing
- Tested on Windows 11 and macOS 12.7
- Linux untested
## Migration Guide
`WindowMode::SizedFullscreen(MonitorSelection)` and
`WindowMode::Fullscreen(MonitorSelection)` has become
`WindowMode::Fullscreen(MonitorSelection, VideoModeSelection)`.
Previously, the VideoMode was selected based on the closest resolution
to the current window size for SizedFullscreen and the largest
resolution for Fullscreen. It is possible to replicate that behaviour by
searching `Monitor::video_modes` and selecting it with
`VideoModeSelection::Specific(VideoMode)` but it is recommended to use
`VideoModeSelection::Current` as the default video mode when entering
fullscreen.
# Objective
While redoing #18058 I needed `RelationshipSourceCollection` (henceforth
referred to as the **Trait**) to implement `clear` so I added it.
## Solution
Add the `clear` method to the **Trait**.
Also make `add` and `remove` report if they succeeded.
## Testing
Eyeballs
---
## Showcase
The `RelationshipSourceCollection` trait now reports if adding or
removing an entity from it was successful.
It also not contains the `clear` method so you can easily clear the
collection in generic contexts.
## Changes
EDITED by Alice: We should get this into 0.16, so no migration guide
needed.
The `RelationshipSourceCollection` methods `add` and `remove` now need
to return a boolean indicating if they were successful (adding a entity
to a set that already contains it counts as failure). Additionally the
`clear` method has been added to support clearing the collection in
generic contexts.
_Note from BD103: this PR was adopted from #16148. The majority of this
PR's description is copied from the original._
# Objective
Adds tests to cover various mesh picking cases and removes sources of
panics.
It should prevent users being able to trigger panics in `bevy_picking`
code via bad mesh data such as #15891, and is a follow up to my comments
in [#15800
(review)](https://github.com/bevyengine/bevy/pull/15800#pullrequestreview-2361694213).
This is motivated by #15979
## Testing
Adds 8 new tests to cover `ray_mesh_intersection` code.
## Changes from original PR
I reverted the changes to the benchmarks, since that was the largest
factor blocking it merging. I'll open a follow-up issue so that those
benchmark changes can be implemented.
---------
Co-authored-by: Trent <2771466+tbillington@users.noreply.github.com>
# Objective
- Allow for convenient access and mutation of color saturation providing
following the `Hue`, `Luminance` traits.
- `with_saturation()` builder method
- `saturation()` to get the saturation of a `Color`
- `set_saturation()` to set the saturation of a mutable `Color`
## Solution
- Defined `Saturation` trait in `color_ops.rs`
- Implemented `Saturation` on `Hsla` and `Hsva`
- Implemented `Saturation` on `Color` which proxies to other color space
impls.
- In the case of colorspaces which don't have native saturation
components
the color is converted to 'Hsla` internally
## Testing
- Empirically tested
---
## Showcase
```rust
fn next_golden(&mut self) -> Color {
self.current
.rotate_hue((1.0 / GOLDEN_RATIO) * 360.0)
.with_saturation(self.rand_saturation())
.with_luminance(self.rand_luminance())
.into()
}
```
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
I was recently exploreing `Entities` and stumbled on something strange.
`Entities::len` (the field) has the comment `Stores the number of free
entities for [`len`](Entities::len)`, refering to the method. But that
method says `The count of currently allocated entities.` Looking at the
code, the field's comment is wrong, and the public `len()` is correct.
Phew!
## Solution
So, I was just going to fix the comment, so it didn't confuse anyone
else, but as it turns out, we can just remove the field entirely. As a
bonus, this saves some book keeping work too. We can just calculate it
on the fly.
Also, add additional length methods and documentation for completeness.
These new length methods might be useful debug tools in the future.
---------
Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
# Objective
Make component registration faster. This is a tinny, almost petty PR,
but it led to roughly 10% faster registration, according to my
benchmarks in #17871.
Up to y'all if we do this or not. It is completely unnecessary, but its
such low hanging fruit that I wanted to put it out there.
## Solution
Instead of cloning a `HashSet`, collect it into a `SmallVec`. Since this
is empty for many components, this saves a lot of allocation and hashing
work.
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
This is an alternative to #17871 and #17701 for tracking issue #18155.
This thanks to @maniwani for help with this design.
The goal is to enable component ids to be reserved from multiple threads
concurrently and with only `&World`. This contributes to assets as
entities, read-only query and system parameter initialization, etc.
## What's wrong with #17871 ?
In #17871, I used my proposed staging utilities to allow *fully*
registering components from any thread concurrently with only
`&Components`. However, if we want to pursue components as entities
(which is desirable for a great many reasons. See
[here](https://discord.com/channels/691052431525675048/692572690833473578/1346499196655505534)
on discord), this staging isn't going to work. After all, if registering
a component requires spawning an entity, and spawning an entity requires
`&mut World`, it is impossible to register a component fully with only
`&World`.
## Solution
But what if we don't have to register it all the way? What if it's
enough to just know the `ComponentId` it will have once it is registered
and to queue it to be registered at a later time? Spoiler alert: That is
all we need for these features.
Here's the basic design:
Queue a registration:
1. Check if it has already been registered.
2. Check if it has already been queued.
3. Reserve a `ComponentId`.
4. Queue the registration at that id.
Direct (normal) registration:
1. Check if this registration has been queued.
2. If it has, use the queued registration instead.
3. Otherwise, proceed like normal.
Appllying the queue:
1. Pop queued items off one by one.
2. Register them directly.
One other change:
The whole point of this design over #17871 is to facilitate coupling
component registration with the World. To ensure that this would fully
work with that, I went ahead and moved the `ComponentId` generator onto
the world itself. That stemmed a couple of minor organizational changes
(see migration guide). As we do components as entities, we will replace
this generator with `Entities`, which lives on `World` too. Doing this
move early let me verify the design and will reduce migration headaches
in the future. If components as entities is as close as I think it is, I
don't think splitting this up into different PRs is worth it. If it is
not as close as it is, it might make sense to still do #17871 in the
meantime (see the risks section). I'll leave it up to y'all what we end
up doing though.
## Risks and Testing
The biggest downside of this compared to #17871 is that now we have to
deal with correct but invalid `ComponentId`s. They are invalid because
the component still isn't registered, but they are correct because, once
registered, the component will have exactly that id.
However, the only time this becomes a problem is if some code violates
safety rules by queuing a registration and using the returned id as if
it was valid. As this is a new feature though, nothing in Bevy does
this, so no new tests were added for it. When we do use it, I left
detailed docs to help mitigate issues here, and we can test those
usages. Ex: we will want some tests on using queries initialized from
queued registrations.
## Migration Guide
Component registration can now be queued with only `&World`. To
facilitate this, a few APIs needed to be moved around.
The following functions have moved from `Components` to
`ComponentsRegistrator`:
- `register_component`
- `register_component_with_descriptor`
- `register_resource_with_descriptor`
- `register_non_send`
- `register_resource`
- `register_required_components_manual`
Accordingly, functions in `Bundle` and `Component` now take
`ComponentsRegistrator` instead of `Components`.
You can obtain `ComponentsRegistrator` from the new
`World::components_registrator`.
You can obtain `ComponentsQueuedRegistrator` from the new
`World::components_queue`, and use it to stage component registration if
desired.
# Open Question
Can we verify that it is enough to queue registration with `&World`? I
don't think it would be too difficult to package this up into a
`Arc<MyComponentsManager>` type thing if we need to, but keeping this on
`&World` certainly simplifies things. If we do need the `Arc`, we'll
need to look into partitioning `Entities` for components as entities, so
we can keep most of the allocation fast on `World` and only keep a
smaller partition in the `Arc`. I'd love an SME on assets as entities to
shed some light on this.
---------
Co-authored-by: andriyDev <andriydzikh@gmail.com>
PR #17965 mistakenly made the `AsBindGroup` macro no longer emit a bind
group layout entry and a resource descriptor for buffers. This commit
adds that functionality back, fixing the `shader_material_bindless`
example.
Closes#18124.
# Objective
Fixes#18030
## Solution
When running a one-shot system, requeue the system's command queue onto
the world's command queue, then execute the later.
If running the entire command queue of the world is undesired, I could
add a new method to `RawCommandQueue` to only apply part of it.
## Testing
See the new test.
---
## Showcase
```rust
#[derive(Resource)]
pub struct Test {
id: SystemId,
counter: u32,
}
let mut world = World::new();
let id = world.register_system(|mut commands: Commands, mut test: ResMut<Test>| {
print!("{:?} ", test.counter);
test.counter -= 1;
if test.counter > 0 {
commands.run_system(test.id);
}
});
world.insert_resource(Test { id, counter: 5 });
world.run_system(id).unwrap();
```
```
5 4 3 2 1
```
# Objective
I found a bug while working on #17871. When required components are
registered, ones that are more specific (smaller inheritance depth) are
preferred to others. So, if a ComponentA is already required, but it is
registered as required again, it will be updated if and only if the new
requirement has a smaller inheritance depth (is more specific). However,
this logic was not reflected in merging `RequriedComponents`s together.
Hence, for complicated requirement trees, the wrong initializer could be
used.
## Solution
Re-write merging to work by extending the collection via
`require_dynamic` instead of blindly combining the inner storage.
## Testing
I created this test to ensure this bug doesn't creep back in. This test
fails on main, but passes on this branch.
```rs
#[test]
fn required_components_inheritance_depth_bias() {
#[derive(Component, PartialEq, Eq, Clone, Copy, Debug)]
struct MyRequired(bool);
#[derive(Component, Default)]
#[require(MyRequired(|| MyRequired(false)))]
struct MiddleMan;
#[derive(Component, Default)]
#[require(MiddleMan)]
struct ConflictingRequire;
#[derive(Component, Default)]
#[require(MyRequired(|| MyRequired(true)))]
struct MyComponent;
let mut world = World::new();
let order_a = world
.spawn((ConflictingRequire, MyComponent))
.get::<MyRequired>()
.cloned();
let order_b = world
.spawn((MyComponent, ConflictingRequire))
.get::<MyRequired>()
.cloned();
assert_eq!(order_a, Some(MyRequired(true)));
assert_eq!(order_b, Some(MyRequired(true)));
}
```
Note that when the inheritance depth is 0 (Like if there were no middle
man above), the order of the components in the bundle still matters.
## Migration Guide
`RequiredComponents::register_dynamic` has been changed to
`RequiredComponents::register_dynamic_with`.
Old:
```rust
required_components.register_dynamic(
component_id,
component_constructor.clone(),
requirement_inheritance_depth,
);
```
New:
```rust
required_components.register_dynamic_with(
component_id,
requirement_inheritance_depth,
|| component_constructor.clone(),
);
```
This can prevent unnecessary cloning.
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
# Objective
Fix unsound lifetimes in `Query::join` and `Query::join_filtered`.
The joined query allowed access from either input query, but it only
took the `'world` lifetime from `self`, not from `other`. This meant
that after the borrow of `other` ended, the joined query would unsoundly
alias `other`.
## Solution
Change the lifetimes on `join` and `join_filtered` to require mutable
borrows of the *same* lifetime for the input queries. This ensures both
input queries are borrowed for the full lifetime of the joined query.
Change `join_inner` to take `other` by value instead of reference so
that the returned query is still usable without needing to borrow from a
local variable.
## Testing
Added a compile-fail test.
# Objective
`extract_text_shadows` was still using `UiTargetCamera` and
`DefaultUiCamera` for UI camera resolution, which no longer always
selects the right camera.
To see this modify the last lines of the `multiple_windows` example
from:
```rust
commands.spawn((
Text::new("First window"),
node.clone(),
// Since we are using multiple cameras, we need to specify which camera UI should be rendered to
UiTargetCamera(first_window_camera),
));
commands.spawn((
Text::new("Second window"),
node,
UiTargetCamera(second_window_camera),
));
```
to:
```rust
commands
.spawn((
node.clone(),
// Since we are using multiple cameras, we need to specify which camera UI should be rendered to
UiTargetCamera(first_window_camera),
))
.with_child((Text::new("First window"), TextShadow::default()));
commands
.spawn((node, UiTargetCamera(second_window_camera)))
.with_child((Text::new("Second window"), TextShadow::default()));
```
which results in the shadow that is meant to be displayed for the
"Second Window" label instead being written over the first:
<img width="800" alt="first_window_label"
src="https://github.com/user-attachments/assets/2eebccba-5749-4064-bb1c-e4f25ff0baf7">
## Solution
Remove the `UiTargetCamera` query and the `default_camera` parameter
from `extract_text_shadows` and use `UiCameraMap` with
`ComputedNodeTarget` instead.
## Testing
The `multiple_windows` example for this PR has been updated to add text
shadow to the window labels. You should see that it displays the "Second
Window" label's shadow correctly now.
# Objective
- In `Camera::viewport_to_world_2d`, `Camera::viewport_to_world`,
`Camera::world_to_viewport` and `Camera::world_to_viewport_with_depth`,
the results were incorrect when the `Camera::viewport` field was
configured with a viewport position that was non-zero. This PR attempts
to correct that.
- Fixes#16200
## Solution
- This PR now takes the viewport position into account in the functions
mentioned above.
- Extended `2d_viewport_to_world` example to test the functions with a
dynamic viewport position and size, camera positions and zoom levels. It
is probably worth discussing whether to change the example, add a new
one or just completely skip touching the examples.
## Testing
Used the modified example to test the functions with dynamic camera
transform as well as dynamic viewport size and position.
# Objective
This PR enables `bevy_gizmos` to be used without `bevy_pbr`, for user
who want to create their custom mesh rendering logic.
It can also be useful for user who just want to use bevy for drawing
lines (why not).
This work is part of a bigger effort to make the bevy rendering pipeline
more modular. I would like to contribute an exemple to render custom
meshes without `bevy_pbr`. Something like
[this](https://github.com/rambip/plant-mesh/blob/main/src/shader/mod.rs)
## Solution
Now, `bevy_pbr` is an optional dependency, and used only to debug
lights.
I query the `ViewUniforms` manually, instead of using `bevy_pbr` to get
the heavy `MeshViewLayout`
## Testing
I'm not used to testing with bevy at all, but I was able to use
successfully in my project.
It might break for some different mesh pipelines, but I don't think so.
---
## Showcase

So nice ...
## Migration Guide
I don't think there is any breaking change
# Remaining work
Before merging it, it would be useful to:
- rewrite the `pipeline_2d.rs` logic to remove the `bevy_sprite`
depedency too
- move `view.rs` to `bevy_render`, so that it can be used in a more
modular way.
~~- include the most recent changes from 0.16~~
---------
Co-authored-by: IceSentry <IceSentry@users.noreply.github.com>
# Objective
Make `bevy_error_panic_hook` threadsafe. As it relies on a global
variable, it fails when multiple threads panic.
## Solution
Switch from a global variable for storing whether an error message was
printed to a thread-local one.
`thread_local` is in `std`; the `backtrace` already relies on `std`
APIs. It didn't depend on the `std` feature though, so I've added that.
I've also put `bevy_error_panic_hook` behind the `backtrace` feature,
since it relies on the thread local variable, which fixes#18231.
## Testing
The following now loops instead of crashing:
```rust
std:🧵:scope(|s| {
use bevy_ecs::error::*;
#[derive(Debug)]
struct E;
impl std::fmt::Display for E {
fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
todo!()
}
}
impl std::error::Error for E {}
std::panic::set_hook(Box::new(bevy_error_panic_hook(|_| {
unreachable!();
})));
for _ in 0..2 {
s.spawn(|| {
loop {
let _ = std::panic::catch_unwind(|| {
panic!("{:?}", BevyError::from(E));
});
}
});
}
});
```
# Objective
Defocusing a window while a key is held (such as when Alt+tabbing), will
currently send a key release on X11 and Windows. This is likely the
behavior that most people expect.
However it's synthetic events from winit are unimplemented for WASM and
some other platforms. (See
https://github.com/rust-windowing/winit/issues/1272).
While we can implement it upstream, there is also some doubt about the
synthetic events API as a whole
(https://github.com/rust-windowing/winit/issues/3543), so I propose to
do it in bevy directly for now.
## Solution
This PR implements key tracking in bevy directly so we can synthesize
our own key release events across all platforms.
Note regarding X11 specifically:
- On `main`, pressing a keyboard shortcut to unfocus the window (`Ctrl +
Super + ArrowRight` in my case) will yield the following events:
```
Pressed Control
Pressed Super
Released Control
Released ArrowRight
Released Super
```
- On this branch, it will yield the following sequence:
```
Pressed Control
Pressed Super
Released Control
Released Super
```
To me the behavior of this branch is more expected than `main`, because
`main` produces an `ArrowRight` release without producing a press first.
## Testing
Tested in WASM and X11 with
```rust
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Update, |mut keys: EventReader<KeyboardInput>| {
for ev in keys.read() {
error!("received {ev:?}");
}
})
.run();
```
# Objective
Because `prepare_assets::<T>` had a mutable reference to the
`RenderAssetBytesPerFrame` resource, no render asset preparation could
happen in parallel. This PR fixes this by using an `AtomicUsize` to
count bytes written (if there's a limit in place), so that the system
doesn't need mutable access.
- Related: https://github.com/bevyengine/bevy/pull/12622
**Before**
<img width="1049" alt="Screenshot 2025-02-17 at 11 40 53 AM"
src="https://github.com/user-attachments/assets/040e6184-1192-4368-9597-5ceda4b8251b"
/>
**After**
<img width="836" alt="Screenshot 2025-02-17 at 1 38 37 PM"
src="https://github.com/user-attachments/assets/95488796-3323-425c-b0a6-4cf17753512e"
/>
## Testing
- Tested on a local project (with and without limiting enabled)
- Someone with more knowledge of wgpu/underlying driver guts should
confirm that this doesn't actually bite us by introducing contention
(i.e. if buffer writing really *should be* serial).
# Objective
As pointed out in #18177 this line in the doc comment for
`UiTargetCamera`:
```
/// Optional if there is only one camera in the world. Required otherwise.
```
Is incorrect, `UiTargetCamera` component is only needed when you want to
display UI nodes using a camera other than the default camera.
## Solution
Change it to:
```
/// Root node's without an explicit [`UiTargetCamera`] will be rendered to the default UI camera,
/// which is either a single camera with the [`IsDefaultUiCamera`] marker component or the highest
/// order camera targeting the primary window.
```
# Objective
- Allow bevy and wgpu developers to test newer versions of wgpu without
having to update naga_oil.
## Solution
- Currently bevy feeds wgsl through naga_oil to get a naga::Module that
it passes to wgpu.
- Added a way to pass wgsl through naga_oil, and then serialize the
naga::Module back into a wgsl string to feed to wgpu, allowing wgpu to
parse it using it's internal version of naga (and not the version of
naga bevy_render/naga_oil is using).
## Testing
1. Run 3d_scene (it works)
2. Run 3d_scene with `--features bevy_render/decoupled_naga` (it still
works)
3. Add the following patch to bevy/Cargo.toml, run cargo update, and
compile again (it will fail)
```toml
[patch.crates-io]
wgpu = { git = "https://github.com/gfx-rs/wgpu", rev = "2764e7a39920e23928d300e8856a672f1952da63" }
wgpu-core = { git = "https://github.com/gfx-rs/wgpu", rev = "2764e7a39920e23928d300e8856a672f1952da63" }
wgpu-hal = { git = "https://github.com/gfx-rs/wgpu", rev = "2764e7a39920e23928d300e8856a672f1952da63" }
wgpu-types = { git = "https://github.com/gfx-rs/wgpu", rev = "2764e7a39920e23928d300e8856a672f1952da63" }
```
4. Fix errors and compile again (it will work, and you didn't have to
touch naga_oil)
# Objective
#17404 reworked the `Segment2d` and `Segment3d` types to be defined by
two endpoints rather than a direction and half-length. However, the API
is still very minimal and limited, and documentation is inconsistent and
outdated.
## Solution
Add the following helper methods for `Segment2d` and `Segment3d`:
- `from_scaled_direction`
- `from_ray_and_length`
- `length_squared`
- `direction`
- `try_direction`
- `scaled_direction`
- `transformed`
- `reversed`
`Segment2d` has a few 2D-specific methods:
- `left_normal`
- `try_left_normal`
- `scaled_left_normal`
- `right_normal`
- `try_right_normal`
- `scaled_right_normal`
There are now also `From` implementations for converting `[Vec2; 2]` and
`(Vec2, Vec2)` to a `Segment2d`, and similarly for 3D.
I have also updated documentation to be more accurate and consistent,
and simplified a few methods.
---
## Prior Art
Parry's
[`Segment`](https://docs.rs/parry2d/latest/parry2d/shape/struct.Segment.html)
type has a lot of similar methods, though my implementation is a bit
more comprehensive. A lot of these methods can be useful for various
geometry algorithms.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Greeble <166992735+greeble-dev@users.noreply.github.com>
# Overview
Fixes https://github.com/bevyengine/bevy/issues/17869.
# Summary
`WGPU_SETTINGS_PRIO` changes various limits on `RenderDevice`. This is
useful to simulate platforms with lower limits.
However, some plugins only check the limits on `RenderAdapter` (the
actual GPU) - these limits are not affected by `WGPU_SETTINGS_PRIO`. So
the plugins try to use features that are unavailable and wgpu says "oh
no". See https://github.com/bevyengine/bevy/issues/17869 for details.
The PR adds various checks on `RenderDevice` limits. This is enough to
get most examples working, but some are not fixed (see below).
# Testing
- Tested native, with and without "WGPU_SETTINGS=webgl2".
Win10/Vulkan/Nvidia".
- Also WebGL. Win10/Chrome/Nvidia.
```
$env:WGPU_SETTINGS_PRIO = "webgl2"
cargo run --example testbed_3d
cargo run --example testbed_2d
cargo run --example testbed_ui
cargo run --example deferred_rendering
cargo run --example many_lights
cargo run --example order_independent_transparency # Still broken, see below.
cargo run --example occlusion_culling # Still broken, see below.
```
# Not Fixed
While testing I found a few other cases of limits being broken.
"Compatibility" settings (WebGPU minimums) breaks native in various
examples.
```
$env:WGPU_SETTINGS_PRIO = "compatibility"
cargo run --example testbed_3d
In Device::create_bind_group_layout, label = 'build mesh uniforms GPU early occlusion culling bind group layout'
Too many bindings of type StorageBuffers in Stage ShaderStages(COMPUTE), limit is 8, count was 9. Check the limit `max_storage_buffers_per_shader_stage` passed to `Adapter::request_device`
```
`occlusion_culling` breaks fake webgl.
```
$env:WGPU_SETTINGS_PRIO = "webgl2"
cargo run --example occlusion_culling
thread '<unnamed>' panicked at C:\Projects\bevy\crates\bevy_render\src\render_resource\pipeline_cache.rs:555:28:
index out of bounds: the len is 0 but the index is 2
Encountered a panic in system `bevy_render::renderer::render_system`!
```
`occlusion_culling` breaks real webgl.
```
cargo run --example occlusion_culling --target wasm32-unknown-unknown
ERROR app: panicked at C:\Users\T\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\glow-0.16.0\src\web_sys.rs:4223:9:
Tex storage 2D multisample is not supported
```
OIT breaks fake webgl.
```
$env:WGPU_SETTINGS_PRIO = "webgl2"
cargo run --example order_independent_transparency
In Device::create_bind_group, label = 'mesh_view_bind_group'
Number of bindings in bind group descriptor (28) does not match the number of bindings defined in the bind group layout (25)
```
OIT breaks real webgl
```
cargo run --example order_independent_transparency --target wasm32-unknown-unknown
In Device::create_render_pipeline, label = 'pbr_oit_mesh_pipeline'
Error matching ShaderStages(FRAGMENT) shader requirements against the pipeline
Shader global ResourceBinding { group: 0, binding: 34 } is not available in the pipeline layout
Binding is missing from the pipeline layout
```
# Objective
- Allow `Query` methods such as `Query::get` to have their error
short-circuited using `?` in systems using Bevy's `Error` type
## Solution
- Removed `UnsafeWorldCell<'w>` from `QueryEntityError` and instead
store `ArchetypeId` (the information the error formatter was extracting
anyway).
- Replaced trait implementations with derives now that the type is
plain-old-data.
## Testing
- CI
---
## Migration Guide
- `QueryEntityError::QueryDoesNotMatch.1` is of type `ArchetypeId`
instead of `UnsafeWorldCell`. It is up to the caller to obtain an
`UnsafeWorldCell` now.
- `QueryEntityError` no longer has a lifetime parameter, remove it from
type signatures where required.
## Notes
This was discussed on Discord and accepted by Cart as the desirable path
forward in [this
message](https://discord.com/channels/691052431525675048/749335865876021248/1346611950527713310).
Scroll up from this point for context.
---------
Co-authored-by: SpecificProtagonist <30270112+SpecificProtagonist@users.noreply.github.com>
# Objective
- Optimize static scene performance by marking unchanged subtrees.
## Solution
- Mark hierarchy subtrees with dirty bits to avoid transform propagation
where not needed
- This causes a performance regression when spawning many entities, or
when the scene is entirely dynamic.
- This results in massive speedups for largely static scenes.
- In the future we could allow the user to change this behavior, or add
some threshold based on how dynamic the scene is?
## Testing
- Caldera Hotel scene
# Objective
WESL's pre-MVP `0.1.0` has been
[released](https://docs.rs/wesl/latest/wesl/)!
Add support for WESL shader source so that we can begin playing and
testing WESL, as well as aiding in their development.
## Solution
Adds a `ShaderSource::WESL` that can be used to load `.wesl` shaders.
Right now, we don't support mixing `naga-oil`. Additionally, WESL
shaders currently need to pass through the naga frontend, which the WESL
team is aware isn't great for performance (they're working on compiling
into naga modules). Also, since our shaders are managed using the asset
system, we don't currently support using file based imports like `super`
or package scoped imports. Further work will be needed to asses how we
want to support this.
---
## Showcase
See the `shader_material_wesl` example. Be sure to press space to
activate party mode (trigger conditional compilation)!
https://github.com/user-attachments/assets/ec6ad19f-b6e4-4e9d-a00f-6f09336b08a4
# Objective
- Fixes#18200
## Solution
- Ensure `bevy_utils` is included with `bevy_transform/std`
## Testing
- `cargo build --no-default-features --features std`
## Notes
Compilation failure was caused by `bevy_transform`'s new parallel
propagation system requiring `bevy_utils/std` when `bevy_transform/std`
was active, but it was left optional. Additionally,
`bevy_transform/async_executor` wasn't being enabled by
`bevy/async_executor`.
# Objective
Adds information about the byte length and index of a glyph to
`PositionedGlyph`. Useful for text picking, allows for picking with
multi-byte characters. Also adds a `line` field that helps with
converting back and forth from cosmic's `Cursor`.
## Solution
Retrieve the relevant data from cosmic and add it to the glyph in the
text pipeline.
## Testing
`cargo r -p ci`
---
## Migration Guide
`PositionedGlyph::new()` has been removed as there is no longer an
unused field. Create new `PositionedGlyph`s directly.
also updates Relationship docs terminology
# Objective
- Contributes to #18111
## Solution
Updates Component docs with a new section linking to Relationship. Also
updates some Relationship terminology as I understand it.
## Testing
- Did you test these changes? If so, how?
- opened Docs, verified link
- Are there any parts that need more testing?
- I don't think so
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- run `cargo doc --open` and check out Component and Relationship docs,
verify their correctness
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- I think this is n/a but I ran the doc command on Ubuntu 24.04.2 LTS
---
## Showcase

## Migration Guide
n/a
# Objective
- Contributes to #15460
- Supersedes #8520
- Fixes#4906
## Solution
- Added a new `web` feature to `bevy`, and several of its crates.
- Enabled new `web` feature automatically within crates without `no_std`
support.
## Testing
- `cargo build --no-default-features --target wasm32v1-none`
---
## Migration Guide
When using Bevy crates which _don't_ automatically enable the `web`
feature, please enable it when building for the browser.
## Notes
- I added [`cfg_if`](https://crates.io/crates/cfg-if) to help manage
some of the feature gate gore that this extra feature introduces. It's
still pretty ugly, but I think much easier to read.
- Certain `wasm` targets (e.g.,
[wasm32-wasip1](https://doc.rust-lang.org/nightly/rustc/platform-support/wasm32-wasip1.html#wasm32-wasip1))
provide an incomplete implementation for `std`. I have not tested these
platforms, but I suspect Bevy's liberal use of usually unsupported
features (e.g., threading) will cause these targets to fail. As such,
consider `wasm32-unknown-unknown` as the only `wasm` platform with
support from Bevy for `std`. All others likely will need to be treated
as `no_std` platforms.
Fixes#17170
# Objective
Tangents are not currently transformed as described in #17170. I came
across this while working on #17989 and it seemed like low hanging
fruit.
# Objective
- Fixes#15460 (will open new issues for further `no_std` efforts)
- Supersedes #17715
## Solution
- Threaded in new features as required
- Made certain crates optional but default enabled
- Removed `compile-check-no-std` from internal `ci` tool since GitHub CI
can now simply check `bevy` itself now
- Added CI task to check `bevy` on `thumbv6m-none-eabi` to ensure
`portable-atomic` support is still valid [^1]
[^1]: This may be controversial, since it could be interpreted as
implying Bevy will maintain support for `thumbv6m-none-eabi` going
forward. In reality, just like `x86_64-unknown-none`, this is a
[canary](https://en.wiktionary.org/wiki/canary_in_a_coal_mine) target to
make it clear when `portable-atomic` no longer works as intended (fixing
atomic support on atomically challenged platforms). If a PR comes
through and makes supporting this class of platforms impossible, then
this CI task can be removed. I however wager this won't be a problem.
## Testing
- CI
---
## Release Notes
Bevy now has support for `no_std` directly from the `bevy` crate.
Users can disable default features and enable a new `default_no_std`
feature instead, allowing `bevy` to be used in `no_std` applications and
libraries.
```toml
# Bevy for `no_std` platforms
bevy = { version = "0.16", default-features = false, features = ["default_no_std"] }
```
`default_no_std` enables certain required features, such as `libm` and
`critical-section`, and as many optional crates as possible (currently
just `bevy_state`). For atomically-challenged platforms such as the
Raspberry Pi Pico, `portable-atomic` will be used automatically.
For library authors, we recommend depending on `bevy` with
`default-features = false` to allow `std` and `no_std` users to both
depend on your crate. Here are some recommended features a library crate
may want to expose:
```toml
[features]
# Most users will be on a platform which has `std` and can use the more-powerful `async_executor`.
default = ["std", "async_executor"]
# Features for typical platforms.
std = ["bevy/std"]
async_executor = ["bevy/async_executor"]
# Features for `no_std` platforms.
libm = ["bevy/libm"]
critical-section = ["bevy/critical-section"]
[dependencies]
# We disable default features to ensure we don't accidentally enable `std` on `no_std` targets, for example.
bevy = { version = "0.16", default-features = false }
```
While this is verbose, it gives the maximum control to end-users to
decide how they wish to use Bevy on their platform.
We encourage library authors to experiment with `no_std` support. For
libraries relying exclusively on `bevy` and no other dependencies, it
may be as simple as adding `#![no_std]` to your `lib.rs` and exposing
features as above! Bevy can also provide many `std` types, such as
`HashMap`, `Mutex`, and `Instant` on all platforms. See
`bevy::platform_support` for details on what's available out of the box!
## Migration Guide
- If you were previously relying on `bevy` with default features
disabled, you may need to enable the `std` and `async_executor`
features.
- `bevy_reflect` has had its `bevy` feature removed. If you were relying
on this feature, simply enable `smallvec` and `smol_str` instead.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Alternative to and closes#18120.
Sibling to #18082, see that PR for broader reasoning.
Folks weren't sold on the name `many` (get_many is clearer, and this is
rare), and that PR is much more complex.
## Solution
- Simply deprecate `Query::many` and `Query::many_mut`
- Clean up internal usages
Mentions of this in the docs can wait until it's fully removed in the
0.17 cycle IMO: it's much easier to catch the problems when doing that.
## Testing
CI!
## Migration Guide
`Query::many` and `Query::many_mut` have been deprecated to reduce
panics and API duplication. Use `Query::get_many` and
`Query::get_many_mut` instead, and handle the `Result`.
---------
Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
# Objective
simplify some code and improve Event macro
Closes https://github.com/bevyengine/bevy/issues/14336,
# Showcase
you can now write derive Events like so
```rust
#[derive(event)]
#[event(auto_propagate, traversal = MyType)]
struct MyEvent;
```
# Objective
I'm building a bloxel game in which I (currently) use a texture atlas to
render the blocks the world is made of. While I was coding it, I was
using the `TextureAtlas...` types to build the terrain's texture atlas
at runtime as shown in the
[example](https://github.com/bevyengine/bevy/blob/latest/examples/2d/texture_atlas.rs).
But when I was using it to build a 3D mesh out of the blocks, I found
that there was no easy way get the texture rect in UV coordinates, only
in pixels via `texture_rect()`. I had to resort to writing code like
this:
```rs
let size = layout.size.as_vec2();
if let Some(rect) = sources.texture_rect(layout, texture) {
let rect = rect.as_rect();
let uvs = Rect::from_corners(rect.min / size, rect.max / size);
// use the UVs here, such as to build vertex buffer
}
```
That is, until I wrote a helper function that's practically identical to
the one in this PR.
## Solution
Add a `uv_rect` function to `TextureAtlasSources` that will return a
`Rect` with coordinates in the range of 0.0 to 1.0 – that is, UV
coordinates – which can then be used directly to build `Vec2` UV values
to put into a buffer and send to the GPU.
I'm a little unsure about the wording of the `texture_rect`
documentation but I kept it intact and based mine on it. If you think
this could be improved and have some advice, I'd love to include that in
this PR.
## Testing
I've not done any testing with the updated bevy branch, other than
seeing that the original helper function (identical in functionality)
worked in my currently very small project, and making sure `cargo build`
doesn't error, but I'm new to making changes to Bevy so unsure if this
is sufficient.
## Showcase

## Objective
Fixes#18092
Bevy's current error type is a simple type alias for `Box<dyn Error +
Send + Sync + 'static>`. This largely works as a catch-all error, but it
is missing a critical feature: the ability to capture a backtrace at the
point that the error occurs. The best way to do this is `anyhow`-style
error handling: a new error type that takes advantage of the fact that
the `?` `From` conversion happens "inline" to capture the backtrace at
the point of the error.
## Solution
This PR adds a new `BevyError` type (replacing our old
`std::error::Error` type alias), which uses the "from conversion
backtrace capture" approach:
```rust
fn oh_no() -> Result<(), BevyError> {
// this fails with Rust's built in ParseIntError, which
// is converted into the catch-all BevyError type
let number: usize = "hi".parse()?;
println!("parsed {number}");
Ok(())
}
```
This also updates our exported `Result` type alias to default to
`BevyError`, meaning you can write this instead:
```rust
fn oh_no() -> Result {
let number: usize = "hi".parse()?;
println!("parsed {number}");
Ok(())
}
```
When a BevyError is encountered in a system, it will use Bevy's default
system error handler (which panics by default). BevyError does custom
"backtrace filtering" by default, meaning we can cut out the _massive_
amount of "rust internals", "async executor internals", and "bevy system
scheduler internals" that show up in backtraces. It also trims out the
first generally-unnecssary `From` conversion backtrace lines that make
it harder to locate the real error location. The result is a blissfully
simple backtrace by default:

The full backtrace can be shown by setting the `BEVY_BACKTRACE=full`
environment variable. Non-BevyError panics still use the default Rust
backtrace behavior.
One issue that prevented the truly noise-free backtrace during panics
that you see above is that Rust's default panic handler will print the
unfiltered (and largely unhelpful real-panic-point) backtrace by
default, in _addition_ to our filtered BevyError backtrace (with the
helpful backtrace origin) that we capture and print. To resolve this, I
have extended Bevy's existing PanicHandlerPlugin to wrap the default
panic handler. If we panic from the result of a BevyError, we will skip
the default "print full backtrace" panic handler. This behavior can be
enabled and disabled using the new `error_panic_hook` cargo feature in
`bevy_app` (which is enabled by default).
One downside to _not_ using `Box<dyn Error>` directly is that we can no
longer take advantage of the built-in `Into` impl for strings to errors.
To resolve this, I have added the following:
```rust
// Before
Err("some error")?
// After
Err(BevyError::message("some error"))?
```
We can discuss adding shorthand methods or macros for this (similar to
anyhow's `anyhow!("some error")` macro), but I'd prefer to discuss that
later.
I have also added the following extension method:
```rust
// Before
some_option.ok_or("some error")?;
// After
some_option.ok_or_message("some error")?;
```
I've also moved all of our existing error infrastructure from
`bevy_ecs::result` to `bevy_ecs::error`, as I think that is the better
home for it
## Why not anyhow (or eyre)?
The biggest reason is that `anyhow` needs to be a "generically useful
error type", whereas Bevy is a much narrower scope. By using our own
error, we can be significantly more opinionated. For example, anyhow
doesn't do the extensive (and invasive) backtrace filtering that
BevyError does because it can't operate on Bevy-specific context, and
needs to be generically useful.
Bevy also has a lot of operational context (ex: system info) that could
be useful to attach to errors. If we have control over the error type,
we can add whatever context we want to in a structured way. This could
be increasingly useful as we add more visual / interactive error
handling tools and editor integrations.
Additionally, the core approach used is simple and requires almost no
code. anyhow clocks in at ~2500 lines of code, but the impl here uses
160. We are able to boil this down to exactly what we need, and by doing
so we improve our compile times and the understandability of our code.
# Objective
The fix in #18105 includes a check for running headless, but this allows
for an extra world update during shutdown.
This commit checks if the `AppExit` event has been recorded and prevents
the additional world update.
### Before
```
2025-03-06T03:11:59.999679Z INFO bevy_window::system: No windows are open, exiting
2025-03-06T03:12:00.001942Z INFO bevy_winit::system: Closing window 0v1
2025-03-06T03:12:00.012691Z INFO bevy_window::system: No windows are open, exiting
```
### After
```
2025-03-06T03:18:45.552243Z INFO bevy_window::system: No windows are open, exiting
2025-03-06T03:18:45.554119Z INFO bevy_winit::system: Closing window 0v1
```
## Testing
Ran `window` examples
- `monitor_info` continues to run after all windows are closed (it has
`ExitCondition::DontExit`)
- `window_settings` invisible window creation works as expected
- `multiple_windows` exits after both windows are closed with a single
exit message
# Objective
- Today, enabling asset processing can generate many meta files. This
makes it a painful transition for users as they get a "mega commit"
containing tons of meta files.
## Solution
- Stop automatically generating meta files! Users can just leave the
meta files defaulted.
- Add a function `AssetServer::write_default_meta_file_for_path`
## Testing
- Tested this manually on the asset_processing example (by removing the
meta files for the assets that had default meta files).
- I did not add a unit test for the `write_default_meta_file_for_path`
since we don't have an in-memory asset writer. Writing one could be
useful in the future.
---
## Showcase
Asset processing no longer automatically generates meta files! This
makes it much easier to transition to using asset processing since you
don't suddenly get many meta files when turning it on.
You can still manually generate meta files using the new
`AssetServer::write_default_meta_file_for_path` function.
# Objective
Based on #18054, this PR builds on #18035 to deprecate:
- `Commands::insert_or_spawn_batch`
- `Entities::alloc_at_without_replacement`
- `Entities::alloc_at`
- `World::insert_or_spawn_batch`
- `World::insert_or_spawn_batch_with_caller`
## Testing
Just deprecation, so no new tests. Note that as of writing #18035 is
still under testing and review.
## Open Questions
- [x] Should `entity::AllocAtWithoutReplacement` be deprecated? It is
internal and only used in `Entities::alloc_at_without_replacement`.
**EDIT:** Now deprecated.
## Migration Guide
The following functions have been deprecated:
- `Commands::insert_or_spawn_batch`
- `World::insert_or_spawn_batch`
- `World::insert_or_spawn_batch_with_caller`
These functions, when used incorrectly, can cause major performance
problems and are generally viewed as anti-patterns and foot guns. These
are planned to be removed altogether in 0.17.
Instead of these functions consider doing one of the following:
Option A) Instead of despawing entities and re-spawning them at a
particular id, insert the new `Disabled` component without despawning
the entity, and use `try_insert_batch` or `insert_batch` and remove
`Disabled` instead of re-spawning it.
Option B) Instead of giving special meaning to an entity id, simply use
`spawn_batch` and ensure entity references are valid when despawning.
---------
Co-authored-by: JaySpruce <jsprucebruce@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
In 0.11 you could easily access the inverse model matrix inside a WGSL
shader with `transpose(mesh.inverse_transpose_model)`. This was changed
in 0.12 when `inverse_transpose_model` was removed and it's now not as
straightfoward. I wrote a helper function for my own code and thought
I'd submit a pull request in case it would be helpful to others.
# Objective
This PR adds:
- function call hook attributes `#[component(on_add = func(42))]`
- main feature of this commit
- closure hook attributes `#[component(on_add = |w, ctx| { /* ... */
})]`
- maybe too verbose
- but was easy to add
- was suggested on discord
This allows to reuse common functionality without replicating a lot of
boilerplate. A small example is a hook which just adds different default
sprites. The sprite loading code would be the same for every component.
Unfortunately we can't use the required components feature, since we
need at least an `AssetServer` or other `Resource`s or `Component`s to
load the sprite.
```rs
fn load_sprite(path: &str) -> impl Fn(DeferredWorld, HookContext) {
|mut world, ctx| {
// ... use world to load sprite
}
}
#[derive(Component)]
#[component(on_add = load_sprite("knight.png"))]
struct Knight;
#[derive(Component)]
#[component(on_add = load_sprite("monster.png"))]
struct Monster;
```
---
The commit also reorders the logic of the derive macro a bit. It's
probably a bit less lazy now, but the functionality shouldn't be
performance critical and is executed at compile time anyways.
## Solution
- Introduce `HookKind` enum in the component proc macro module
- extend parsing to allow more cases of expressions
## Testing
I have some code laying around. I'm not sure where to put it yet though.
Also is there a way to check compilation failures? Anyways, here it is:
```rs
use bevy::prelude::*;
#[derive(Component)]
#[component(
on_add = fooing_and_baring,
on_insert = fooing_and_baring,
on_replace = fooing_and_baring,
on_despawn = fooing_and_baring,
on_remove = fooing_and_baring
)]
pub struct FooPath;
fn fooing_and_baring(
world: bevy::ecs::world::DeferredWorld,
ctx: bevy::ecs::component::HookContext,
) {
}
#[derive(Component)]
#[component(
on_add = baring_and_bazzing("foo"),
on_insert = baring_and_bazzing("foo"),
on_replace = baring_and_bazzing("foo"),
on_despawn = baring_and_bazzing("foo"),
on_remove = baring_and_bazzing("foo")
)]
pub struct FooCall;
fn baring_and_bazzing(
path: &str,
) -> impl Fn(bevy::ecs::world::DeferredWorld, bevy::ecs::component::HookContext) {
|world, ctx| {}
}
#[derive(Component)]
#[component(
on_add = |w,ctx| {},
on_insert = |w,ctx| {},
on_replace = |w,ctx| {},
on_despawn = |w,ctx| {},
on_remove = |w,ctx| {}
)]
pub struct FooClosure;
#[derive(Component, Debug)]
#[relationship(relationship_target = FooTargets)]
#[component(
on_add = baring_and_bazzing("foo"),
// on_insert = baring_and_bazzing("foo"),
// on_replace = baring_and_bazzing("foo"),
on_despawn = baring_and_bazzing("foo"),
on_remove = baring_and_bazzing("foo")
)]
pub struct FooTargetOf(Entity);
#[derive(Component, Debug)]
#[relationship_target(relationship = FooTargetOf)]
#[component(
on_add = |w,ctx| {},
on_insert = |w,ctx| {},
// on_replace = |w,ctx| {},
// on_despawn = |w,ctx| {},
on_remove = |w,ctx| {}
)]
pub struct FooTargets(Vec<Entity>);
// MSG: mismatched types expected fn pointer `for<'w> fn(bevy::bevy_ecs::world::DeferredWorld<'w>, bevy::bevy_ecs::component::HookContext)` found struct `Bar`
//
// pub struct Bar;
// #[derive(Component)]
// #[component(
// on_add = Bar,
// )]
// pub struct FooWrongPath;
// MSG: this function takes 1 argument but 2 arguements were supplied
//
// #[derive(Component)]
// #[component(
// on_add = wrong_bazzing("foo"),
// )]
// pub struct FooWrongCall;
//
// fn wrong_bazzing(path: &str) -> impl Fn(bevy::ecs::world::DeferredWorld) {
// |world| {}
// }
// MSG: expected 1 argument, found 2
//
// #[derive(Component)]
// #[component(
// on_add = |w| {},
// )]
// pub struct FooWrongCall;
```
---
## Showcase
I'll try to continue to work on this to have a small section in the
release notes.
## Objective
`insert_or_spawn_batch` is due to be deprecated eventually (#15704), and
removing uses internally will make that easier.
## Solution
Replaced internal uses of `insert_or_spawn_batch` with
`try_insert_batch` (non-panicking variant because
`insert_or_spawn_batch` didn't panic).
All of the internal uses are in rendering code. Since retained rendering
was meant to get rid non-opaque entity IDs, I assume the code was just
using `insert_or_spawn_batch` because `insert_batch` didn't exist and
not because it actually wanted to spawn something. However, I am *not*
confident in my ability to judge rendering code.
# Objective
Component `require()` IDE integration is fully broken, as of #16575.
## Solution
This reverts us back to the previous "put the docs on Component trait"
impl. This _does_ reduce the accessibility of the required components in
rust docs, but the complete erasure of "required component IDE
experience" is not worth the price of slightly increased prominence of
requires in docs.
Additionally, Rust Analyzer has recently started including derive
attributes in suggestions, so we aren't losing that benefit of the
proc_macro attribute impl.
This reverts commit 0b5302d96a.
# Objective
- Fixes#18158
- #17482 introduced rendering changes and was merged a bit too fast
## Solution
- Revert #17482 so that it can be redone and rendering changes discussed
before being merged. This will make it easier to compare changes with
main in the known "valid" state
This is not an issue with the work done in #17482 that is still
interesting
Fixes#17720
## Objective
Spawning RelationshipTargets from scenes currently fails to preserve
RelationshipTarget ordering (ex: `Children` has an arbitrary order).
This is because it uses the normal hook flow to set up the collection,
which means we are pushing onto the collection in _spawn order_ (which
is currently in archetype order, which will often produce mismatched
orderings).
We need to preserve the ordering in the original RelationshipTarget
collection. Ideally without expensive checking / fixups.
## Solution
One solution would be to spawn in hierarchy-order. However this gets
complicated as there can be multiple hierarchies, and it also means we
can't spawn in more cache-friendly orders (ex: the current per-archetype
spawning, or future even-smarter per-table spawning). Additionally,
same-world cloning has _slightly_ more nuanced needs (ex: recursively
clone linked relationships, while maintaining _original_ relationships
outside of the tree via normal hooks).
The preferred approach is to directly spawn the remapped
RelationshipTarget collection, as this trivially preserves the ordering.
Unfortunately we can't _just_ do that, as when we spawn the children
with their Relationships (ex: `ChildOf`), that will insert a duplicate.
We could "fixup" the collection retroactively by just removing the back
half of duplicates, but this requires another pass / more lookups /
allocating twice as much space. Additionally, it becomes complicated
because observers could insert additional children, making it harder
(aka more expensive) to determine which children are dupes and which are
not.
The path I chose is to support "opting out" of the relationship target
hook in the contexts that need that, as this allows us to just cheaply
clone the mapped collection. The relationship hook can look for this
configuration when it runs and skip its logic when that happens. A
"simple" / small-amount-of-code way to do this would be to add a "skip
relationship spawn" flag to World. Sadly, any hook / observer that runs
_as the result of an insert_ would also read this flag. We really need a
way to scope this setting to a _specific_ insert.
Therefore I opted to add a new `RelationshipInsertHookMode` enum and an
`entity.insert_with_relationship_insert_hook_mode` variant. Obviously
this is verbose and ugly. And nobody wants _more_ insert variants. But
sadly this was the best I could come up with from a performance and
capability perspective. If you have alternatives let me know!
There are three variants:
1. `RelationshipInsertHookMode::Run`: always run relationship insert
hooks (this is the default)
2. `RelationshipInsertHookMode::Skip`: do not run any relationship
insert hooks for this insert (this is used by spawner code)
3. `RelationshipInsertHookMode::RunIfNotLinked`: only run hooks for
_unlinked_ relationships (this is used in same-world recursive entity
cloning to preserve relationships outside of the deep-cloned tree)
Note that I have intentionally only added "insert with relationship hook
mode" variants to the cases we absolutely need (everything else uses the
default `Run` mode), just to keep the code size in check. I do not think
we should add more without real _very necessary_ use cases.
I also made some other minor tweaks:
1. I split out `SourceComponent` from `ComponentCloneCtx`. Reading the
source component no longer needlessly blocks mutable access to
`ComponentCloneCtx`.
2. Thanks to (1), I've removed the `RefCell` wrapper over the cloned
component queue.
3. (1) also allowed me to write to the EntityMapper while queuing up
clones, meaning we can reserve entities during the component clone and
write them to the mapper _before_ inserting the component, meaning
cloned collections can be mapped on insert.
4. I've removed the closure from `write_target_component_ptr` to
simplify the API / make it compatible with the split `SourceComponent`
approach.
5. I've renamed `EntityCloner::recursive` to
`EntityCloner::linked_cloning` to connect that feature more directly
with `RelationshipTarget::LINKED_SPAWN`
6. I've removed `EntityCloneBehavior::RelationshipTarget`. This was
always intended to be temporary, and this new behavior removes the need
for it.
---------
Co-authored-by: Viktor Gustavsson <villor94@gmail.com>
# Objective
Fix unsound query transmutes on queries obtained from
`Query::as_readonly()`.
The following compiles, and the call to `transmute_lens()` should panic,
but does not:
```rust
fn bad_system(query: Query<&mut A>) {
let mut readonly = query.as_readonly();
let mut lens: QueryLens<&mut A> = readonly.transmute_lens();
let other_readonly: Query<&A> = query.as_readonly();
// `lens` and `other_readonly` alias, and are both alive here!
}
```
To make `Query::as_readonly()` zero-cost, we pointer-cast
`&QueryState<D, F>` to `&QueryState<D::ReadOnly, F>`. This means that
the `component_access` for a read-only query's state may include
accesses for the original mutable version, but the `Query` does not have
exclusive access to those components! `transmute` and `join` use that
access to ensure that a join is valid, and will incorrectly allow a
transmute that includes mutable access.
As a bonus, allow `Query::join`s that output `FilteredEntityRef` or
`FilteredEntityMut` to receive access from the `other` query. Currently
they only receive access from `self`.
## Solution
When transmuting or joining from a read-only query, remove any writes
before performing checking that the transmute is valid. For joins, be
sure to handle the case where one input query was the result of
`as_readonly()` but the other has valid mutable access.
This requires identifying read-only queries, so add a
`QueryData::IS_READ_ONLY` associated constant. Note that we only call
`QueryState::as_transmuted_state()` with `NewD: ReadOnlyQueryData`, so
checking for read-only queries is sufficient to check for
`as_transmuted_state()`.
Removing writes requires allocating a new `FilteredAccess`, so only do
so if the query is read-only and the state has writes. Otherwise, the
existing access is correct and we can continue using a reference to it.
Use the new read-only state to call `NewD::set_access`, so that
transmuting to a `FilteredAccessMut` results in a read-only
`FilteredAccessMut`. Otherwise, it would take the original write access,
and then the transmute would panic because it had too much access.
Note that `join` was previously passing `self.component_access` to
`NewD::set_access`. Switching it to `joined_component_access` also
allows a join that outputs `FilteredEntity(Ref|Mut)` to receive access
from `other`. The fact that it didn't do that before seems like an
oversight, so I didn't try to prevent that change.
## Testing
Added unit tests with the unsound transmute and join.
# Objective
Many systems like `Schedule` rely on the fact that every structural ECS
changes are deferred until an exclusive system flushes the `World`
itself. This gives us the benefits of being able to run systems in
parallel without worrying about dangling references caused by memory
(re)allocations, which will in turn lead to **Undefined Behavior**.
However, this isn't explicitly documented in `SystemParam`; currently it
only vaguely hints that in `init_state`, based on the fact that
structural ECS changes require mutable access to the _whole_ `World`.
## Solution
Document this behavior explicitly in `SystemParam`'s type-level
documentations.
# Objective
- Fixes#16339
## Solution
- Replaced `component_reads_and_writes` and `component_writes` with
`try_iter_component_access`.
## Testing
- Ran `dynamic` example to confirm behaviour is unchanged.
- CI
---
## Migration Guide
The following methods (some removed in previous PRs) are now replaced by
`Access::try_iter_component_access`:
* `Access::component_reads_and_writes`
* `Access::component_reads`
* `Access::component_writes`
As `try_iter_component_access` returns a `Result`, you'll now need to
handle the failing case (e.g., `unwrap()`). There is currently a single
failure mode, `UnboundedAccess`, which occurs when the `Access` is for
all `Components` _except_ certain exclusions. Since this list is
infinite, there is no meaningful way for `Access` to provide an
iterator. Instead, get a list of components (e.g., from the `Components`
structure) and iterate over that instead, filtering using
`Access::has_component_read`, `Access::has_component_write`, etc.
Additionally, you'll need to `filter_map` the accesses based on which
method you're attempting to replace:
* `Access::component_reads_and_writes` -> `Exclusive(_) | Shared(_)`
* `Access::component_reads` -> `Shared(_)`
* `Access::component_writes` -> `Exclusive(_)`
To ease migration, please consider the below extension trait which you
can include in your project:
```rust
pub trait AccessCompatibilityExt {
/// Returns the indices of the components this has access to.
fn component_reads_and_writes(&self) -> impl Iterator<Item = T> + '_;
/// Returns the indices of the components this has non-exclusive access to.
fn component_reads(&self) -> impl Iterator<Item = T> + '_;
/// Returns the indices of the components this has exclusive access to.
fn component_writes(&self) -> impl Iterator<Item = T> + '_;
}
impl<T: SparseSetIndex> AccessCompatibilityExt for Access<T> {
fn component_reads_and_writes(&self) -> impl Iterator<Item = T> + '_ {
self
.try_iter_component_access()
.expect("Access is unbounded. Please refactor the usage of this method to directly use try_iter_component_access")
.filter_map(|component_access| {
let index = component_access.index().sparse_set_index();
match component_access {
ComponentAccessKind::Archetypal(_) => None,
ComponentAccessKind::Shared(_) => Some(index),
ComponentAccessKind::Exclusive(_) => Some(index),
}
})
}
fn component_reads(&self) -> impl Iterator<Item = T> + '_ {
self
.try_iter_component_access()
.expect("Access is unbounded. Please refactor the usage of this method to directly use try_iter_component_access")
.filter_map(|component_access| {
let index = component_access.index().sparse_set_index();
match component_access {
ComponentAccessKind::Archetypal(_) => None,
ComponentAccessKind::Shared(_) => Some(index),
ComponentAccessKind::Exclusive(_) => None,
}
})
}
fn component_writes(&self) -> impl Iterator<Item = T> + '_ {
self
.try_iter_component_access()
.expect("Access is unbounded. Please refactor the usage of this method to directly use try_iter_component_access")
.filter_map(|component_access| {
let index = component_access.index().sparse_set_index();
match component_access {
ComponentAccessKind::Archetypal(_) => None,
ComponentAccessKind::Shared(_) => None,
ComponentAccessKind::Exclusive(_) => Some(index),
}
})
}
}
```
Please take note of the use of `expect(...)` in these methods. You
should consider using these as a starting point for a more appropriate
migration based on your specific needs.
## Notes
- This new method is fallible based on whether the `Access` is bounded
or unbounded (unbounded occurring with inverted component sets). If
bounded, will return an iterator of every item and its access level. I
believe this makes sense without exposing implementation details around
`Access`.
- The access level is defined by an `enum` `ComponentAccessKind<T>`,
either `Archetypical`, `Shared`, or `Exclusive`. As a convenience, this
`enum` has a method `index` to get the inner `T` value without a match
statement. It does add more code, but the API is clearer.
- Within `QueryBuilder` this new method simplifies several pieces of
logic without changing behaviour.
- Within `QueryState` the logic is simplified and the amount of
iteration is reduced, potentially improving performance.
- Within the `dynamic` example it has identical behaviour, with the
inversion footgun explicitly highlighted by an `unwrap`.
---------
Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
Co-authored-by: Mike <2180432+hymm@users.noreply.github.com>
# Objective
The doc comment for `BorderRadius::resolve_single_corner` returns a
value in physical pixels but the doc comments implies it returns a
logical value.
# Objective
Minimal implementation of directed one-to-one relationships via
implementing `RelationshipSourceCollection` for `Entity`.
Now you can do
```rust
#[derive(Component)]
#[relationship(relationship_target = Below)]
pub struct Above(Entity);
#[derive(Component)]
#[relationship_target(relationship = Above)]
pub struct Below(Entity);
```
## Future Work
It would be nice if the relationships could be fully symmetrical in the
future - in the example above, since `Above` is the source of truth you
can't add `Below` to an entity and have `Above` added automatically.
## Testing
Wrote unit tests for new relationship sources and and verified
adding/removing relationships maintains connection as expected.
# Objective
Work for issue #17682
What's in this PR:
* Removal of some `!Send` resources that Bevy uses internally
* Replaces `!Send` resources with `thread_local!` static
What this PR does not cover:
* The ability to create `!Send` resources still exists
* Tests that test `!Send` resources are present (and should not be
removed until the ability to create `!Send` resources is removed)
* The example `log_layers_ecs` still uses a `!Send` resource. In this
example, removing the `!Send` resource results in the system that uses
it running on a thread other than the main thread, which doesn't work
with lazily initialized `thread_local!` static data. Removing this
`!Send` resource will need to be deferred until the System API is
extended to support configuring which thread the System runs on. Once an
issue for this work is created, it will be mentioned in #17667
Once the System API is extended to allow control of which thread the
System runs on, the rest of the `!Send` resources can be removed in a
different PR.
# Objective
Transparently uses simple `EnvironmentMapLight`s to mimic
`AmbientLight`s. Implements the first part of #17468, but I can
implement hemispherical lights in this PR too if needed.
## Solution
- A function `EnvironmentMapLight::solid_color(&mut Assets<Image>,
Color)` is provided to make an environment light with a solid color.
- A new system is added to `SimulationLightSystems` that maps
`AmbientLight`s on views or the world to a corresponding
`EnvironmentMapLight`.
I have never worked with (or on) Bevy before, so nitpicky comments on
how I did things are appreciated :).
## Testing
Testing was done on a modified version of the `3d/lighting` example,
where I removed all lights except the ambient light. I have not included
the example, but can if required.
## Migration
`bevy_pbr::AmbientLight` has been deprecated, so all usages of it should
be replaced by a `bevy_pbr::EnvironmentMapLight` created with
`EnvironmentMapLight::solid_color` placed on the camera. There is no
alternative to ambient lights as resources.
# Objective
- Fixes the issue described in this comment:
https://github.com/bevyengine/bevy/issues/16680#issuecomment-2522764239.
## Solution
- Cache one-shot systems by `S: IntoSystem` (which is const-asserted to
be a ZST) rather than `S::System`.
## Testing
Added a new unit test named `cached_system_into_same_system_type` to
`system_registry.rs`.
---
## Migration Guide
The `CachedSystemId` resource has been changed:
```rust
// Before:
let cached_id = CachedSystemId::<S::System>(id);
assert!(id == cached_id.0);
// After:
let cached_id = CachedSystemId::<S>::new(id);
assert!(id == SystemId::from_entity(cached_id.entity));
```
This commit makes the
`mark_meshes_as_changed_if_their_materials_changed` system use the new
`AssetChanged<MeshMaterial3d>` query filter in addition to
`Changed<MeshMaterial3d>`. This ensures that we update the
`MeshInputUniform`, which contains the bindless material slot. Updating
the `MeshInputUniform` fixes problems that occurred when the
`MeshBindGroupAllocator` reallocated meshes in such a way as to change
their bindless slot.
Closes#18102.
The test case `query_iter_sorts` was doing lots of comparisons to ensure
that various query arrays were sorted, but the arrays were all empty.
This PR spawns some entities so that the entity lists to compare not
empty, and sorting can actually be tested for correctness.
# Objective
Fixes https://github.com/bevyengine/bevy/issues/17590.
## Solution
`prepare_volumetric_fog_uniforms` adds a uniform for each combination of
fog volume and view. But it only allocated enough uniforms for one fog
volume per view.
## Testing
Ran the `volumetric_fog` example with 1/2/3/4 fog volumes. Also checked
the `fog_volumes` and `scrolling_fog` examples (without multiple
volumes). Win10/Vulkan/Nvidia.
To test multiple views I tried adding fog volumes to the `split_screen`
example. This doesn't quite work - the fog should be centred on the fox,
but instead it's centred on the window. Same result with and without the
PR, so I'm assuming it's a separate bug.

# Objective
As discussed in #14275, Bevy is currently too prone to panic, and makes
the easy / beginner-friendly way to do a large number of operations just
to panic on failure.
This is seriously frustrating in library code, but also slows down
development, as many of the `Query::single` panics can actually safely
be an early return (these panics are often due to a small ordering issue
or a change in game state.
More critically, in most "finished" products, panics are unacceptable:
any unexpected failures should be handled elsewhere. That's where the
new
With the advent of good system error handling, we can now remove this.
Note: I was instrumental in a) introducing this idea in the first place
and b) pushing to make the panicking variant the default. The
introduction of both `let else` statements in Rust and the fancy system
error handling work in 0.16 have changed my mind on the right balance
here.
## Solution
1. Make `Query::single` and `Query::single_mut` (and other random
related methods) return a `Result`.
2. Handle all of Bevy's internal usage of these APIs.
3. Deprecate `Query::get_single` and friends, since we've moved their
functionality to the nice names.
4. Add detailed advice on how to best handle these errors.
Generally I like the diff here, although `get_single().unwrap()` in
tests is a bit of a downgrade.
## Testing
I've done a global search for `.single` to track down any missed
deprecated usages.
As to whether or not all the migrations were successful, that's what CI
is for :)
## Future work
~~Rename `Query::get_single` and friends to `Query::single`!~~
~~I've opted not to do this in this PR, and smear it across two releases
in order to ease the migration. Successive deprecations are much easier
to manage than the semantics and types shifting under your feet.~~
Cart has convinced me to change my mind on this; see
https://github.com/bevyengine/bevy/pull/18082#discussion_r1974536085.
## Migration guide
`Query::single`, `Query::single_mut` and their `QueryState` equivalents
now return a `Result`. Generally, you'll want to:
1. Use Bevy 0.16's system error handling to return a `Result` using the
`?` operator.
2. Use a `let else Ok(data)` block to early return if it's an expected
failure.
3. Use `unwrap()` or `Ok` destructuring inside of tests.
The old `Query::get_single` (etc) methods which did this have been
deprecated.
# Objective
Documentation correction.
# Reasoning
The `GamepadAxis::RightZ` and `LeftZ` do not map to the trigger buttons
on a gamepad. They are in fact for the twisting/yaw of a flight Joystick
and throttle lever respectively. I confirmed this with two gamepads that
has analog triggers (Logitech F710, 8bitdo ultimate BT controller) and a
HOTAS joystick (Saitek X52).
# Objective
Fixes#18022
## Solution
Canonicalize asset paths
## Testing
I ran the examples `sprite`, `desk_toy` and `game_menu` with the feature
`file_watcher` enabled. All correctly updated an asset when the source
file was altered.
Co-authored-by: Threadzless <threadzless@gmail.com>
# Objective
Fixes#18027
## Solution
Run `redraw_requested` logic in `about_to_wait` on Windows during
initial application startup and when in headless mode
## Testing
- Ran `cargo run --example window_settings` to demonstrate invisible
window creation worked again and fixes#18027
- Ran `cargo run --example eased_motion` to demonstrate no regression
with the fix for #17488
Ran all additional `window` examples.
Notes:
- The `transparent_window` was not transparent but this appears to have
been broken prior to #18004. See: #7544
I noticed this while working on #18017 . Some of the `stderr`
compile_fail tests were updated while I generated the output for the new
tests I introduced in the mentioned PR.
I'm on rust 1.85.0
## Objective
`EntityCommands::trigger` internally uses `Commands::trigger_targets`,
which means it gets queued using `Commands::queue` rather
`EntityCommands::queue`. This previously wouldn't have made much
difference, but now entity commands check whether the entity exists, and
that check never happens in this case.
## Solution
- Add `entity_command::trigger`, which calls the same function as before
(`World::trigger_targets_with_caller`) but through the `EntityWorldMut`
passed to entity commands.
- Change `EntityCommands::trigger` to queue the new entity command
normally.
https://github.com/bevyengine/bevy/pull/17905 replaced `ChildOf(entity)`
with `ChildOf { parent: entity }`, but some deprecation advice was
overlooked. Also corrected formatting in documentation.
## Testing
Added a `set_parent` to a random example. Confirmed that the deprecation
warning shows and the advice can be pasted in.
# Objective
Fixes#17988
## Solution
Added two Debug impls to the `impl_ptr` macro - one for Aligned and one
for Unaligned.
## Testing
No tests have been added. Would a test guaranteeing debug layout be
appropriate?
---
## Showcase
The debug representation of a `Ptr<'_, Aligned>` follows. `PtrMut` and
`OwningPtr` are similar.
`Ptr<Aligned>(0x0123456789ab)`
# Objective
There are currently three ways to access the parent stored on a ChildOf
relationship:
1. `child_of.parent` (field accessor)
2. `child_of.get()` (get function)
3. `**child_of` (Deref impl)
I will assert that we should only have one (the field accessor), and
that the existence of the other implementations causes confusion and
legibility issues. The deref approach is heinous, and `child_of.get()`
is significantly less clear than `child_of.parent`.
## Solution
Remove `impl Deref for ChildOf` and `ChildOf::get`.
The one "downside" I'm seeing is that:
```rust
entity.get::<ChildOf>().map(ChildOf::get)
```
Becomes this:
```rust
entity.get::<ChildOf>().map(|c| c.parent)
```
I strongly believe that this is worth the increased clarity and
consistency. I'm also not really a huge fan of the "pass function
pointer to map" syntax. I think most people don't think this way about
maps. They think in terms of a function that takes the item in the
Option and returns the result of some action on it.
## Migration Guide
```rust
// Before
**child_of
// After
child_of.parent
// Before
child_of.get()
// After
child_of.parent
// Before
entity.get::<ChildOf>().map(ChildOf::get)
// After
entity.get::<ChildOf>().map(|c| c.parent)
```
## Objective
Alternative to #18001.
- Now that systems can handle the `?` operator, `get_entity` returning
`Result` would be more useful than `Option`.
- With `get_entity` being more flexible, combined with entity commands
now checking the entity's existence automatically, the panic in `entity`
isn't really necessary.
## Solution
- Changed `Commands::get_entity` to return `Result<EntityCommands,
EntityDoesNotExistError>`.
- Removed panic from `Commands::entity`.
# Objective
fixes#17896
## Solution
Change ChildOf ( Entity ) to ChildOf { parent: Entity }
by doing this we also allow users to use named structs for relationship
derives, When you have more than 1 field in a struct with named fields
the macro will look for a field with the attribute #[relationship] and
all of the other fields should implement the Default trait. Unnamed
fields are still supported.
When u have a unnamed struct with more than one field the macro will
fail.
Do we want to support something like this ?
```rust
#[derive(Component)]
#[relationship_target(relationship = ChildOf)]
pub struct Children (#[relationship] Entity, u8);
```
I could add this, it but doesn't seem nice.
## Testing
crates/bevy_ecs - cargo test
## Showcase
```rust
use bevy_ecs::component::Component;
use bevy_ecs::entity::Entity;
#[derive(Component)]
#[relationship(relationship_target = Children)]
pub struct ChildOf {
#[relationship]
pub parent: Entity,
internal: u8,
};
#[derive(Component)]
#[relationship_target(relationship = ChildOf)]
pub struct Children {
children: Vec<Entity>
};
```
---------
Co-authored-by: Tim Overbeek <oorbecktim@Tims-MacBook-Pro.local>
Co-authored-by: Tim Overbeek <oorbecktim@c-001-001-042.client.nl.eduvpn.org>
Co-authored-by: Tim Overbeek <oorbecktim@c-001-001-059.client.nl.eduvpn.org>
Co-authored-by: Tim Overbeek <oorbecktim@c-001-001-054.client.nl.eduvpn.org>
Co-authored-by: Tim Overbeek <oorbecktim@c-001-001-027.client.nl.eduvpn.org>
## Objective
`insert_by_id` is unsafe, but I forgot to add that to the
manually-queueable version in `entity_command`.
It also can only insert using `InsertMode::Replace`, when it could
easily be configurable by threading an `InsertMode` parameter to the
final `BundleInserter::insert` call.
## Solution
- Add `unsafe` and safety comment.
- Add `InsertMode` parameter to `entity_command::insert_by_id`,
`EntityWorldMut::insert_by_id_with_caller`, and
`EntityWorldMut::insert_dynamic_bundle`.
- Add `InsertMode` parameter to `entity_command::insert` and remove
`entity_command::insert_if_new`, for consistency with the other
manually-queued insertion commands.
# Objective
Fixes#17828
This fixes two bugs:
1. Exclusive systems should see the effect of all commands queued to
that point. That does not happen when the system is configured with
`*_ignore_deferred` which may lead to surprising situations. These
configurations should not behave like that.
2. If `*_ignore_deferred` is used, no sync point may be added at all
**after** the config. Currently this can happen if the last nodes in
that config have no deferred parameters themselves. Instead, sync points
should always be added after such a config, so long systems have
deferred parameters.
## Solution
1. When adding sync points on edges, do not consider
`AutoInsertApplyDeferredPass::no_sync_edges` if the target is an
exclusive system.
2. when going through the nodes in a directed way, store the information
that `AutoInsertApplyDeferredPass::no_sync_edges` suppressed adding a
sync point at the target node. Then, when the target node is evaluated
later by the iteration and that prior suppression was the case, the
target node will behave like it has deferred parameters even if the
system itself does not.
## Testing
I added a test for each bug, please let me know if more are wanted and
if yes, which cases you would want to see.
These tests also can be read as examples how the current code would
fail.
# Objective
- Fixes#17642
## Solution
- Implemented method `new_bezier(points: [P; 4]) -> Self` for
`CubicSegment<P>`
- Old implementation of `new_bezier` is now `new_bezier_easing(p1: impl
Into<Vec2>, p2: impl Into<Vec2>) -> Self` (**breaking change**)
- ~~added method `new_bezier_with_anchor`, which can make a bezier curve
between two points with one control anchor~~
- added methods `iter_positions`, `iter_velocities`,
`iter_accelerations`, the same as in `CubicCurve` (**copied code,
potentially can be reduced)**
- bezier creation logic is moved from `CubicCurve` to `CubicSegment`,
removing the unneeded allocation
## Testing
- Did you test these changes? If so, how?
- Run tests inside `crates/bevy_math/`
- Tested the functionality in my project
- Are there any parts that need more testing?
- Did not run `cargo test` on the whole bevy directory because of OOM
- Performance improvements are expected when creating `CubicCurve` with
`new_bezier` and `new_bezier_easing`, but not tested
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Use in any code that works created `CubicCurve::new_bezier`
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- I don't think relevant
---
## Showcase
```rust
// Imagine a car goes towards a local target
// Create a simple `CubicSegment`, without using heap
let planned_path = CubicSegment::new_bezier([
car_pos,
car_pos + car_dir * turn_radius,
target_point - target_dir * turn_radius,
target_point,
]);
// Check if the planned path itersect other entities
for pos in planned_path.iter_positions(8) {
// do some collision checks
}
```
## Migration Guide
> This section is optional. If there are no breaking changes, you can
delete this section.
- Replace `CubicCurve::new_bezier` with `CubicCurve::new_bezier_easing`
# Objective
`QueryIter::sort_by()` is unsound. It passes the lens items with the
full `'w` lifetime, and a malicious user could smuggle them out of the
closure where they could alias with the query results.
## Solution
Make the sort closures generic in the lifetime parameter of the lens
item. This ensures the lens items cannot outlive the call to the
closure.
## Testing
Added a compile-fail test that demonstrates the unsound pattern.
## Migration Guide
The `sort` family of methods on `QueryIter` unsoundly gave access
`L::Item<'w>` with the full `'w` lifetime. It has been shortened to
`L::Item<'w>` so that items cannot escape the comparer. If you get
lifetime errors using these methods, you will need to make the comparer
generic in the new lifetime. Often this can be done by replacing named
`'w` with `'_`, or by replacing the use of a function item with a
closure.
```rust
// Before: Now fails with "error: implementation of `FnMut` is not general enough"
query.iter().sort_by::<&C>(Ord::cmp);
// After: Wrap in a closure
query.iter().sort_by::<&C>(|l, r| Ord::cmp(l, r));
query.iter().sort_by::<&C>(comparer);
// Before: Uses specific `'w` lifetime from some outer scope
// now fails with "error: implementation of `FnMut` is not general enough"
fn comparer(left: &&'w C, right: &&'w C) -> Ordering { /* ... */ }
// After: Accepts any lifetime using inferred lifetime parameter
fn comparer(left: &&C, right: &&C) -> Ordering { /* ... */ }
# Objective
So far, built-in BRP methods allow users to interact with entities'
components, but global resources have remained beyond its reach. The
goal of this PR is to take the first steps in rectifying this shortfall.
## Solution
Added five new default methods to BRP:
- `bevy/get_resource`: Extracts the value of a given resource from the
world.
- `bevy/insert_resource`: Serializes an input value to a given resource
type and inserts it into the world.
- `bevy/remove_resource`: Removes the given resource from the world.
- `bevy/mutate_resource`: Replaces the value of a field in a given
resource with the result of serializing a given input value.
- `bevy/list_resources`: Lists all resources in the type registry with
an available `ReflectResource`.
## Testing
Added a test resource to the `server` example scene that you can use to
mess around with the new BRP methods.
## Showcase
Resources can now be retrieved and manipulated remotely using a handful
of new BRP methods. For example, a resource that looks like this:
```rust
#[derive(Resource, Reflect, Serialize, Deserialize)]
#[reflect(Resource, Serialize, Deserialize)]
pub struct PlayerSpawnSettings {
pub location: Vec2,
pub lives: u8,
}
```
can be manipulated remotely as follows.
Retrieving the value of the resource:
```json
{
"jsonrpc": "2.0",
"id": 1,
"method": "bevy/get_resource",
"params": {
"resource": "path::to::my::module::PlayerSpawnSettings"
}
}
```
Inserting a resource value into the world:
```json
{
"jsonrpc": "2.0",
"id": 2,
"method": "bevy/insert_resource",
"params": {
"resource": "path::to::my::module::PlayerSpawnSettings",
"value": {
"location": [
2.5,
2.5
],
"lives": 25
}
}
}
```
Removing the resource from the world:
```json
{
"jsonrpc": "2.0",
"id": 3,
"method": "bevy/remove_resource",
"params": {
"resource": "path::to::my::module::PlayerSpawnSettings"
}
}
```
Mutating a field of the resource specified by a path:
```json
{
"jsonrpc": "2.0",
"id": 4,
"method": "bevy/mutate_resource",
"params": {
"resource": "path::to::my::module::PlayerSpawnSettings",
"path": ".location.x",
"value": -3.0
}
}
```
Listing all manipulable resources in the type registry:
```json
{
"jsonrpc": "2.0",
"id": 5,
"method": "bevy/list_resources"
}
```
# Objective
Refactor `bevy_gltf`, the criteria for the split is kind of arbitrary
but at least it is not a 2.6k line file.
## Solution
Move methods and structs found in `bevy_gltf/loader.rs` into multiple
new modules.
## Testing
`cargo run -p ci`
# Objective
- Systems that use the task pool, either explicitly or implicitly using
parallel queries, will often end up executing tasks from different
systems.
- This can cause random tasks to block the main or render schedule at
random, adding frame variance and increasing frame times when CPU bound.
- This profile is a common occurrence on `main`.
`propagate_parent_transforms` takes more than twice as long as it
should, blocking the main schedule for that time, because it uses `task
pool.scope`, which has decided to execute tasks from the render schedule
on the main schedule.

## Solution
- In task pool scope execution, prefer to check if the current task is
complete instead of ticking the executor to find new work.
## Testing
- Ran the scene viewer with tracy to look for images like the one in the
objective section.
- Things look much, much better, and I could not find any occurrences:


# Objective
- Fixes#16416
## Solution
- Add a intermediate temporary mutable `RequiredComponents` to get avoid
of the borrowing issues.
## Testing
- I have run `cargo test --package bevy_ecs -- --exact --show-output`
and past all the tests.
## Objective
The closure argument for
`EntityClonerBuilder::without_required_components` has `Send + Sync +
'static` bounds, but the closure immediately gets called and never needs
to be sent anywhere. (This was my fault :P )
## Solution
Remove the bounds so that users aren't unnecessarily restricted.
I also took the opportunity to expand the tests a little.
# Objective
This prevents overflowing the `last_trigger_id` property that leads to a
panic in debug mode.
```bash
panicked at C:\XXX\.cargo\registry\src\index.crates.io-6f17d22bba15001f\bevy_ecs-0.15.2\src\world\unsafe_world_cell.rs:630:18:
attempt to add with overflow
Encountered a panic when applying buffers for system `bevy_sprite::calculate_bounds_2d`!
Encountered a panic in system `bevy_ecs::schedule::executor::apply_deferred`!
```
## Solution
As this value is only used for detecting a change, we can wrap when it
reaches max value.
## Testing
This can be verified by running `cargo run --example observers`
# Objective
Closes#17572
## Solution
Add the `add_one_related` methods to `EntityCommands` and
`EntityWorldMut`.
## Testing
Clippy
---
## Showcase
The `EntityWorldMut` and `FilteredResourcesMut` now include the
`add_one_related` method if you just want to relate 2 entities.
Currently, we reload a glTF skin each time we encounter a node that
references it. By checking for duplicates, PR #18013 turned this into a
fatal error. But this was always wasteful. This commit fixes the issue
by caching each skin by its index as we load it.
The Maya babylon.js export plugin likes to emit glTFs with multiple
nodes that reference the same skin, so this effectively unbreaks Maya
rigs.
# Objective
* Fixes https://github.com/bevyengine/bevy/issues/14074
* Applies CI fixes for #16326
It is currently not possible to issues a trigger that targets a specific
list of components AND a specific list of entities
## Solution
We can now use `((A, B), (entity_1, entity_2))` as a trigger target, as
well as the reverse
## Testing
Added a unit test.
The triggering rules for observers are quite confusing:
Triggers once per entity target
For each entity target, an observer system triggers if any of its
components matches the trigger target components (but it triggers at
most once, since we use an internal counter to make sure that an
observer can run at most once per entity target)
(copied from #14563)
(copied from #16326)
## Notes
All credit to @BenjaminBrienen and @cBournhonesque! Just applying a
small fix to this PR so it can be merged.
---------
Co-authored-by: Benjamin Brienen <Benjamin.Brienen@outlook.com>
Co-authored-by: Christian Hughes <xdotdash@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- Makes #18010 more easily debuggable. This doesn't solve that issue,
but protects us from it in the future.
## Solution
- Make `LoadContext::add_labeled_asset` and friends return an error if
it finds a duplicate asset.
## Testing
- Added a test - it fails before the fix.
---
## Migration Guide
- `AssetLoader`s must now handle the case of a duplicate subasset label
when using `LoadContext::add_labeled_asset` and its variants. If you
know your subasset labels are unique by construction (e.g., they include
an index number), you can simply unwrap this result.
Even though opaque deferred entities aren't placed into the `Opaque3d`
bin, we still want to cache them as though they were, so that we don't
have to re-queue them every frame. This commit implements that logic,
reducing the time of `queue_material_meshes` to near-zero on Caldera.
Currently, the structure-level `#[uniform]` attribute of `AsBindGroup`
creates a binding array of individual buffers, each of which contains
data for a single material. A more efficient approach would be to
provide a single buffer with an array containing all of the data for all
materials in the bind group. Because `StandardMaterial` uses
`#[uniform]`, this can be notably inefficient with large numbers of
materials.
This patch introduces a new attribute on `AsBindGroup`, `#[data]`, which
works identically to `#[uniform]` except that it concatenates all the
data into a single buffer that the material bind group allocator itself
manages. It also converts `StandardMaterial` to use this new
functionality. This effectively provides the "material data in arrays"
feature.
# Objective
Continuation of #17589 and #16547.
`get_many` is last of the `many` methods with a missing `unique`
counterpart.
It both takes and returns arrays, thus necessitates a matching
`UniqueEntityArray` type!
Plus, some slice methods involve returning arrays, which are currently
missing from `UniqueEntitySlice`.
## Solution
Add the type, the related methods and trait impls.
Note that for this PR, we abstain from some methods/trait impls that
create `&mut UniqueEntityArray`, because it can be successfully
mem-swapped. This can potentially invalidate a larger slice, which is
the same reason we punted on some mutable slice methods in #17589. We
can follow-up on all of these together in a following PR.
The new `unique_array` module is not glob-exported, because the trait
alias `unique_array::IntoIter` would conflict with
`unique_vec::IntoIter`.
The solution for this is to make the various `unique_*` modules public,
which I intend to do in yet another PR.
# Objective
Fixes#17945
## Solution
Check if the view being extracted has OIT enabled and incorporate the
associated bit into the mesh pipeline key.
I basically have no idea what's going on in the renderer, so let me know
if I missed something, which is extraordinarily possible.
## Testing
I modified the `order_independent_transparency` example to put
everything on the default render layer and render a gizmo at the origin.
Previously, this would cause the application to panic.
# Objective
- Fixes#17897.
## Solution
- When removing components, we filter the list of components in the
removed bundle based on whether they are actually in the archetype.
## Testing
- Added a test.
# Objective
Allow prepass to run without ATTRIBUTE_NORMAL.
This is needed for custom materials with non-standard vertex attributes.
For example a voxel material with manually packed vertex data.
Fixes#13054.
This PR covers the first part of the **stale** PR #13569 to only focus
on fixing #13054.
## Solution
- Only push normals `vertex_attributes` when the layout contains
`Mesh::ATTRIBUTE_NORMAL`
## Testing
- Did you test these changes? If so, how?
**Tested the fix on my own project with a mesh without normal
attribute.**
- Are there any parts that need more testing?
**I don't think so.**
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
**Prepass should not be blocked on a mesh without normal attributes
(with or without custom material).**
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
**Probably irrelevant, but Windows/Vulkan.**
# Objective
Implements and closes#17515
## Solution
Add `uv_transform` to `ColorMaterial`
## Testing
Create a example similar to `repeated_texture` but for `Mesh2d` and
`MeshMaterial2d<ColorMaterial>`
## Showcase

## Migration Guide
Add `uv_transform` field to constructors of `ColorMaterial`
# Objective
Fix https://github.com/bevyengine/bevy/issues/17108
See
https://github.com/bevyengine/bevy/issues/17108#issuecomment-2653020889
## Solution
- Make the query match `&Pickable` instead `Option<&Pickable>`
## Testing
- Run the `sprite_picking` example and everything still work
## Migration Guide
- Sprite picking are now opt-in, make sure you insert `Pickable`
component when using sprite picking.
```diff
-commands.spawn(Sprite { .. } );
+commands.spawn((Sprite { .. }, Pickable::default());
```
# Objective
Fixes#17761
## Solution
- Added core error to InvalidDirectionError
## Testing
- Did you test these changes? If so, how?
- An added test that pulls in anyhow as a dev dependency to ensure the
conversion is accounted for in creation via From
- Are there any parts that need more testing?
- I'm unsure but probably not due to being a trivial change
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- I did not try a fully built version of Bevy. Relied purely on tests.
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Only windows
---------
Co-authored-by: Chanceler Shaffer <cshaffer2@lululemon.com>
Co-authored-by: Chanceler Shaffer <chancelershaffer@lululemon.com>
# Objective
A `TransparentUI` phase's items all target the same camera so there is
no need to store the current camera entity in `UiBatch` and ending the
current `UiBatch` on camera changes is pointless as the camera doesn't
change.
## Solution
Remove the `camera` fields from `UiBatch`, `UiShadowsBatch` and
`UiTextureSliceBatch`.
Remove the camera changed check from `prepare_uinodes`.
## Testing
The `multiple_windows` and `split_screen` examples both render UI
elements to multiple cameras and can be used to test these changes.
The UI material plugin already didn't store the camera entity per batch
and worked fine without it.
# Objective
- Contributes to #15460
- Reduce quantity and complexity of feature gates across Bevy
## Solution
- Used `target_has_atomic` configuration variable to automatically
detect impartial atomic support and automatically switch to
`portable-atomic` over the standard library on an as-required basis.
## Testing
- CI
## Notes
To explain the technique employed here, consider getting `Arc` either
from `alloc::sync` _or_ `portable-atomic-util`. First, we can inspect
the `alloc` crate to see that you only have access to `Arc` _if_
`target_has_atomic = "ptr"`. We add a target dependency for this
particular configuration _inverted_:
```toml
[target.'cfg(not(target_has_atomic = "ptr"))'.dependencies]
portable-atomic-util = { version = "0.2.4", default-features = false }
```
This ensures we only have the dependency when it is needed, and it is
entirely excluded from the dependency graph when it is not. Next, we
adjust our configuration flags to instead of checking for `feature =
"portable-atomic"` to instead check for `target_has_atomic = "ptr"`:
```rust
// `alloc` feature flag hidden for brevity
#[cfg(not(target_has_atomic = "ptr"))]
use portable_atomic_util as arc;
#[cfg(target_has_atomic = "ptr")]
use alloc::sync as arc;
pub use arc::{Arc, Weak};
```
The benefits of this technique are three-fold:
1. For platforms without full atomic support, the functionality is
enabled automatically.
2. For platforms with atomic support, the dependency is never included,
even if a feature was enabled using `--all-features` (for example)
3. The `portable-atomic` feature no longer needs to virally spread to
all user-facing crates, it's instead something handled within
`bevy_platform_support` (with some extras where other dependencies also
need their features enabled).
# Objective
- The previous implementation of automatically inserting sync points did
not consider explicitly added sync points. This created additional sync
points. For example:
```
A-B
C-D-E
```
If `A` and `B` needed a sync point, and `D` was an `ApplyDeferred`, an
additional sync point would be generated between `A` and `B`.
```
A-D2-B
C-D -E
```
This can result in the following system ordering:
```
A-D2-(B-C)-D-E
```
Where only `B` and `C` run in parallel. If we could reuse `D` as the
sync point, we would get the following ordering:
```
(A-C)-D-(B-E)
```
Now we have two more opportunities for parallelism!
## Solution
- In the first pass, we:
- Compute the number of sync points before each node
- This was already happening but now we consider `ApplyDeferred` nodes
as creating a sync point.
- Pick an arbitrary explicit `ApplyDeferred` node for each "sync point
index" that we can (some required sync points may be missing!)
- In the second pass, we:
- For each edge, if two nodes have a different number of sync points
before them then there must be a sync point between them.
- Look for an explicit `ApplyDeferred`. If one exists, use it as the
sync point.
- Otherwise, generate a new sync point.
I believe this should also gracefully handle changes to the
`ScheduleGraph`. Since automatically inserted sync points are inserted
as systems, they won't look any different to explicit sync points, so
they are also candidates for "reusing" sync points.
One thing this solution does not handle is "deduping" sync points. If
you add 10 sync points explicitly, there will be at least 10 sync
points. You could keep track of all the sync points at the same
"distance" and then hack apart the graph to dedup those, but that could
be a follow-up step (and it's more complicated since you have to worry
about transferring edges between nodes).
## Testing
- Added a test to test the feature.
- The existing tests from all our crates still pass.
## Showcase
- Automatically inserted sync points can now reuse explicitly inserted
`ApplyDeferred` systems! Previously, Bevy would add new sync points
between systems, ignoring the explicitly added sync points. This would
reduce parallelism of systems in some situations. Now, the parallelism
has been improved!
# Objective
- Closes#12944.
## Solution
- Load `R8G8B8` textures by transcoding to an rgba format since `wgpu`
does not support texture formats with 3 channels.
- Switch to erroring out instead of panicking on an invalid dds file.
---
## Changelog
### Added
- DDS Textures with the `R8G8B8` format are now supported. They require
an additional conversion step, so using `R8G8B8A8` or a similar format
is preferable for texture loading performance.
# Objective
- Fixes#17960
## Solution
- Followed the [edition upgrade
guide](https://doc.rust-lang.org/edition-guide/editions/transitioning-an-existing-project-to-a-new-edition.html)
## Testing
- CI
---
## Summary of Changes
### Documentation Indentation
When using lists in documentation, proper indentation is now linted for.
This means subsequent lines within the same list item must start at the
same indentation level as the item.
```rust
/* Valid */
/// - Item 1
/// Run-on sentence.
/// - Item 2
struct Foo;
/* Invalid */
/// - Item 1
/// Run-on sentence.
/// - Item 2
struct Foo;
```
### Implicit `!` to `()` Conversion
`!` (the never return type, returned by `panic!`, etc.) no longer
implicitly converts to `()`. This is particularly painful for systems
with `todo!` or `panic!` statements, as they will no longer be functions
returning `()` (or `Result<()>`), making them invalid systems for
functions like `add_systems`. The ideal fix would be to accept functions
returning `!` (or rather, _not_ returning), but this is blocked on the
[stabilisation of the `!` type
itself](https://doc.rust-lang.org/std/primitive.never.html), which is
not done.
The "simple" fix would be to add an explicit `-> ()` to system
signatures (e.g., `|| { todo!() }` becomes `|| -> () { todo!() }`).
However, this is _also_ banned, as there is an existing lint which (IMO,
incorrectly) marks this as an unnecessary annotation.
So, the "fix" (read: workaround) is to put these kinds of `|| -> ! { ...
}` closuers into variables and give the variable an explicit type (e.g.,
`fn()`).
```rust
// Valid
let system: fn() = || todo!("Not implemented yet!");
app.add_systems(..., system);
// Invalid
app.add_systems(..., || todo!("Not implemented yet!"));
```
### Temporary Variable Lifetimes
The order in which temporary variables are dropped has changed. The
simple fix here is _usually_ to just assign temporaries to a named
variable before use.
### `gen` is a keyword
We can no longer use the name `gen` as it is reserved for a future
generator syntax. This involved replacing uses of the name `gen` with
`r#gen` (the raw-identifier syntax).
### Formatting has changed
Use statements have had the order of imports changed, causing a
substantial +/-3,000 diff when applied. For now, I have opted-out of
this change by amending `rustfmt.toml`
```toml
style_edition = "2021"
```
This preserves the original formatting for now, reducing the size of
this PR. It would be a simple followup to update this to 2024 and run
`cargo fmt`.
### New `use<>` Opt-Out Syntax
Lifetimes are now implicitly included in RPIT types. There was a handful
of instances where it needed to be added to satisfy the borrow checker,
but there may be more cases where it _should_ be added to avoid
breakages in user code.
### `MyUnitStruct { .. }` is an invalid pattern
Previously, you could match against unit structs (and unit enum
variants) with a `{ .. }` destructuring. This is no longer valid.
### Pretty much every use of `ref` and `mut` are gone
Pattern binding has changed to the point where these terms are largely
unused now. They still serve a purpose, but it is far more niche now.
### `iter::repeat(...).take(...)` is bad
New lint recommends using the more explicit `iter::repeat_n(..., ...)`
instead.
## Migration Guide
The lifetimes of functions using return-position impl-trait (RPIT) are
likely _more_ conservative than they had been previously. If you
encounter lifetime issues with such a function, please create an issue
to investigate the addition of `+ use<...>`.
## Notes
- Check the individual commits for a clearer breakdown for what
_actually_ changed.
---------
Co-authored-by: François Mockers <francois.mockers@vleue.com>
# Objective
`Eq`/`PartialEq` are currently implemented for `MeshMaterial{2|3}d` only
through the derive macro. Since we don't have perfect derive yet, the
impls are only present for `M: Eq` and `M: PartialEq`. On the other
hand, I want to be able to compare material components for my toy
reactivity project.
## Solution
Switch to manual `Eq`/`PartialEq` impl.
## Testing
Boy I hope this didn't break anything!
# Objective
Fixes#17488
## Solution
The world update logic happened in the the `about_to_wait` winit window
callback, but this is is not correct as (1) the winit documentation
states that the callback should not be used for that purpose and (2) the
callback is not fired when the window is resized or being dragged.
However, that callback was used in #11245 to fix an iOS bug (which
caused the regression). The solution presented here is a workaround
until the event loop code can be re-written.
## Testing
I confirmed that the `eased_motion` example continued to be animated
when dragging or resizing the window.
https://github.com/user-attachments/assets/ffaf0abf-4cd7-479b-83e9-e1850aaf3513
- Remove references to the short-lived `CommandError` type.
- Add a sentence to the explanation of error handlers.
- Clean up spacing/linebreaks.
- Use `where` notation for command-related trait `impl`s to make the big
ones easier to parse.
Fixes#17856.
## Migration Guide
- `EventWriter::send` has been renamed to `EventWriter::write`.
- `EventWriter::send_batch` has been renamed to
`EventWriter::write_batch`.
- `EventWriter::send_default` has been renamed to
`EventWriter::write_default`.
---------
Co-authored-by: François Mockers <mockersf@gmail.com>
# Objective
- Make transform propagation faster.
## Solution
- Work sharing worker threads
- Parallel tree traversal excluding leaves
- Second cache friendly wide pass over all leaves
- 3-10x faster than main
## Testing
- Tracy
- Caldera hotel is showing 3-7x faster on my M4 Max. Timing for bevy's
existing transform system shifts wildly run to run, so I don't know that
I would advertise a particular number. But this implementation is faster
in a... statistically significant way.

---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: François Mockers <mockersf@gmail.com>
PR #17898 regressed this, causing much of #17970. This commit fixes the
issue by freeing and reallocating materials in the
`MaterialBindGroupAllocator` on change. Note that more efficiency is
possible, but I opted for the simple approach because (1) we should fix
this bug ASAP; (2) I'd like #17965 to land first, because that unlocks
the biggest potential optimization, which is not recreating the bind
group if it isn't necessary to do so.
We might not be able to prepare a material on the first frame we
encounter a mesh using it for various reasons, including that the
material hasn't been loaded yet or that preparing the material is
exceeding the per-frame cap on number of bytes to load. When this
happens, we currently try to find the material in the
`MaterialBindGroupAllocator`, fail, and then fall back to group 0, slot
0, the default `MaterialBindGroupId`, which is obviously incorrect.
Worse, we then fail to dirty the mesh and reextract it when we *do*
finish preparing the material, so the mesh will continue to be rendered
with an incorrect material.
This patch fixes both problems. In `collect_meshes_for_gpu_building`, if
we fail to find a mesh's material in the `MeshBindGroupAllocator`, then
we detect that case, bail out, and add it to a list,
`MeshesToReextractNextFrame`. On subsequent frames, we process all the
meshes in `MeshesToReextractNextFrame` as though they were changed. This
ensures both that we don't render a mesh if its material hasn't been
loaded and that we start rendering the mesh once its material does load.
This was first noticed in the intermittent Pixel Eagle failures in the
`testbed_3d` patch in #17898, although the problem has actually existed
for some time. I believe it just so happened that the changes to the
allocator in that PR caused the problem to appear more commonly than it
did before.
This patch fixes two bugs in the new non-bindless material allocator
that landed in PR #17898:
1. A debug assertion to prevent double frees had been flipped: we
checked to see whether the slot was empty before freeing, while we
should have checked to see whether the slot was full.
2. The non-bindless allocator returned `None` when querying a slab that
hadn't been prepared yet instead of returning a handle to that slab.
This resulted in a 1-frame delay when modifying materials. In the
`animated_material` example, this resulted in the meshes never showing
up at all, because that example changes every material every frame.
Together with #17979, this patch locally fixes the problems with
`animated_material` on macOS that were reported in #17970.
# Objective
Fixes#8615
## Solution
Bevy currently interprets 1x1 dds textures as 1-dimensional. I think it
might be more common for game engines to assume two dimensions in this
ambiguous case. [citation needed]
I reworked the dimension choosing logic to only use 1d if there's a
dimension > 1, and assume 2d otherwise. I kept the assumption that
compressed textures are probably 2d.
## Testing
Modified `sprite.rs` to use `Tex_0012_0.dds` from the linked issue.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Fix#17924
## Solution
Use fully qualified syntax (`usize::from` rather than `.into()`).
## Testing
Ran a build for the platform specified in the issue.
---------
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
Fixes#17883
# Objective + Solution
When doing normal scene root entity despawns (which are notably now
recursive), do not despawn instanced entities that are no longer in the
hierarchy.
(I would not classify this as a bug, but rather a behavior change)
## Migration Guide
If you previously relied on scene entities no longer in the hierarchy
being despawned when the scene root is despawned , use
`SceneSpawner::despawn_instance()` instead.
# Objective
Calling `define_label!` in a `no_std` 3rd party crate currently requires
the user to import `Box` themselves due to a non-fully-specified
reference to `Box`.
## Solution
Add a fully specified path for `Box` in the one location necessary, to
match all of the other cases.
Two-phase occlusion culling can be helpful for shadow maps just as it
can for a prepass, in order to reduce vertex and alpha mask fragment
shading overhead. This patch implements occlusion culling for shadow
maps from directional lights, when the `OcclusionCulling` component is
present on the entities containing the lights. Shadow maps from point
lights are deferred to a follow-up patch. Much of this patch involves
expanding the hierarchical Z-buffer to cover shadow maps in addition to
standard view depth buffers.
The `scene_viewer` example has been updated to add `OcclusionCulling` to
the directional light that it creates.
This improved the performance of the rend3 sci-fi test scene when
enabling shadows.
Currently, Bevy's implementation of bindless resources is rather
unusual: every binding in an object that implements `AsBindGroup` (most
commonly, a material) becomes its own separate binding array in the
shader. This is inefficient for two reasons:
1. If multiple materials reference the same texture or other resource,
the reference to that resource will be duplicated many times. This
increases `wgpu` validation overhead.
2. It creates many unused binding array slots. This increases `wgpu` and
driver overhead and makes it easier to hit limits on APIs that `wgpu`
currently imposes tight resource limits on, like Metal.
This PR fixes these issues by switching Bevy to use the standard
approach in GPU-driven renderers, in which resources are de-duplicated
and passed as global arrays, one for each type of resource.
Along the way, this patch introduces per-platform resource limits and
bumps them from 16 resources per binding array to 64 resources per bind
group on Metal and 2048 resources per bind group on other platforms.
(Note that the number of resources per *binding array* isn't the same as
the number of resources per *bind group*; as it currently stands, if all
the PBR features are turned on, Bevy could pack as many as 496 resources
into a single slab.) The limits have been increased because `wgpu` now
has universal support for partially-bound binding arrays, which mean
that we no longer need to fill the binding arrays with fallback
resources on Direct3D 12. The `#[bindless(LIMIT)]` declaration when
deriving `AsBindGroup` can now simply be written `#[bindless]` in order
to have Bevy choose a default limit size for the current platform.
Custom limits are still available with the new
`#[bindless(limit(LIMIT))]` syntax: e.g. `#[bindless(limit(8))]`.
The material bind group allocator has been completely rewritten. Now
there are two allocators: one for bindless materials and one for
non-bindless materials. The new non-bindless material allocator simply
maintains a 1:1 mapping from material to bind group. The new bindless
material allocator maintains a list of slabs and allocates materials
into slabs on a first-fit basis. This unfortunately makes its
performance O(number of resources per object * number of slabs), but the
number of slabs is likely to be low, and it's planned to become even
lower in the future with `wgpu` improvements. Resources are
de-duplicated with in a slab and reference counted. So, for instance, if
multiple materials refer to the same texture, that texture will exist
only once in the appropriate binding array.
To support these new features, this patch adds the concept of a
*bindless descriptor* to the `AsBindGroup` trait. The bindless
descriptor allows the material bind group allocator to probe the layout
of the material, now that an array of `BindGroupLayoutEntry` records is
insufficient to describe the group. The `#[derive(AsBindGroup)]` has
been heavily modified to support the new features. The most important
user-facing change to that macro is that the struct-level `uniform`
attribute, `#[uniform(BINDING_NUMBER, StandardMaterial)]`, now reads
`#[uniform(BINDLESS_INDEX, MATERIAL_UNIFORM_TYPE,
binding_array(BINDING_NUMBER)]`, allowing the material to specify the
binding number for the binding array that holds the uniform data.
To make this patch simpler, I removed support for bindless
`ExtendedMaterial`s, as well as field-level bindless uniform and storage
buffers. I intend to add back support for these as a follow-up. Because
they aren't in any released Bevy version yet, I figured this was OK.
Finally, this patch updates `StandardMaterial` for the new bindless
changes. Generally, code throughout the PBR shaders that looked like
`base_color_texture[slot]` now looks like
`bindless_2d_textures[material_indices[slot].base_color_texture]`.
This patch fixes a system hang that I experienced on the [Caldera test]
when running with `caldera --random-materials --texture-count 100`. The
time per frame is around 19.75 ms, down from 154.2 ms in Bevy 0.14: a
7.8× speedup.
[Caldera test]: https://github.com/DGriffin91/bevy_caldera_scene
Deferred rendering currently doesn't support occlusion culling. This PR
implements it in a straightforward way, mirroring what we already do for
the non-deferred pipeline.
On the rend3 sci-fi base test scene, this resulted in roughly a 2×
speedup when applied on top of my other patches. For that scene, it was
useful to add another option, `--add-light`, which forces the addition
of a shadow-casting light, to the scene viewer, which I included in this
patch.
This commit restructures the multidrawable batch set builder for better
performance in various ways:
* The bin traversal is optimized to make the best use of the CPU cache.
* The inner loop that iterates over the bins, which is the hottest part
of `batch_and_prepare_binned_render_phase`, has been shrunk as small as
possible.
* Where possible, multiple elements are added to or reserved from GPU
buffers as a batch instead of one at a time.
* Methods that LLVM wasn't inlining have been marked `#[inline]` where
doing so would unlock optimizations.
This code has also been refactored to avoid duplication between the
logic for indexed and non-indexed meshes via the introduction of a
`MultidrawableBatchSetPreparer` object.
Together, this improved the `batch_and_prepare_binned_render_phase` time
on Caldera by approximately 2×.
Eventually, we should optimize the batchable-but-not-multidrawable and
unbatchable logic as well, but these meshes are much rarer, so in the
interests of keeping this patch relatively small I opted to leave those
to a follow-up.
# Objective
Fix incorrect mesh culling where objects (particularly directional
shadows) were being incorrectly culled during the early preprocessing
phase. The issue manifested specifically on Apple M1 GPUs but not on
newer devices like the M4. The bug was in the
`view_frustum_intersects_obb` function, where including the w component
(plane distance) in the dot product calculations led to false positive
culling results. This caused objects to be incorrectly culled before
shadow casting could begin.
## Issue Details
The problem of missing shadows is reproducible on Apple M1 GPUs as of
this commit (bisected):
```
00722b8d0 Make indirect drawing opt-out instead of opt-in, enabling multidraw by default. (#16757)
```
and as recent as this commit:
```
c818c9214 Add option to animate materials in many_cubes (#17927)
```
- The frustum culling calculation incorrectly included the w component
(plane distance) when transforming basis vectors
- The relative radius calculation should only consider directional
transformation (xyz), not positional information (w)
- This caused false positive culling specifically on M1 devices likely
due to different device-specific floating-point behavior
- When objects were incorrectly culled, `early_instance_count` never
incremented, leading to missing geometry in the shadow pass
## Testing
- Tested on M1 and M4 devices to verify the fix
- Verified shadows and geometry render correctly on both platforms
- Confirmed the solution matches the existing Rust implementation's
behavior for calculating the relative radius:
c818c92143/crates/bevy_render/src/primitives/mod.rs (L77-L87)
- The fix resolves a mathematical error in the frustum culling
calculation while maintaining correct culling behavior across all
platforms.
---
## Showcase
`c818c9214`
<img width="1284" alt="c818c9214"
src="https://github.com/user-attachments/assets/fe1c7ea9-b13d-422e-b12d-f1cd74475213"
/>
`mate-h/frustum-cull-fix`
<img width="1283" alt="frustum-cull-fix"
src="https://github.com/user-attachments/assets/8a9ccb2a-64b6-4d5e-a17d-ac4798da5b51"
/>
# Objective
Make checked vs unchecked shaders configurable
Fixes#17786
## Solution
Added `ValidateShaders` enum to `Shader` and added
`create_and_validate_shader_module` to `RenderDevice`
## Testing
I tested the shader examples locally and they all worked. I'd like to
write a few tests to verify but am unsure how to start.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
The `check_visibility` system currently follows this algorithm:
1. Store all meshes that were visible last frame in the
`PreviousVisibleMeshes` set.
2. Determine which meshes are visible. For each such visible mesh,
remove it from `PreviousVisibleMeshes`.
3. Mark all meshes that remain in `PreviousVisibleMeshes` as invisible.
This algorithm would be correct if the `check_visibility` were the only
system that marked meshes visible. However, it's not: the shadow-related
systems `check_dir_light_mesh_visibility` and
`check_point_light_mesh_visibility` can as well. This results in the
following sequence of events for meshes that are in a shadow map but
*not* visible from a camera:
A. `check_visibility` runs, finds that no camera contains these meshes,
and marks them hidden, which sets the changed flag.
B. `check_dir_light_mesh_visibility` and/or
`check_point_light_mesh_visibility` run, discover that these meshes
are visible in the shadow map, and marks them as visible, again
setting the `ViewVisibility` changed flag.
C. During the extraction phase, the mesh extraction system sees that
`ViewVisibility` is changed and re-extracts the mesh.
This is inefficient and results in needless work during rendering.
This patch fixes the issue in two ways:
* The `check_dir_light_mesh_visibility` and
`check_point_light_mesh_visibility` systems now remove meshes that they
discover from `PreviousVisibleMeshes`.
* Step (3) above has been moved from `check_visibility` to a separate
system, `mark_newly_hidden_entities_invisible`. This system runs after
all visibility-determining systems, ensuring that
`PreviousVisibleMeshes` contains only those meshes that truly became
invisible on this frame.
This fix dramatically improves the performance of [the Caldera
benchmark], when combined with several other patches I've submitted.
[the Caldera benchmark]:
https://github.com/DGriffin91/bevy_caldera_scene
PR #17688 broke motion vector computation, and therefore motion blur,
because it enabled retention of `MeshInputUniform`s, and
`MeshInputUniform`s contain the indices of the previous frame's
transform and the previous frame's skinned mesh joint matrices. On frame
N, if a `MeshInputUniform` is retained on GPU from the previous frame,
the `previous_input_index` and `previous_skin_index` would refer to the
indices for frame N - 2, not the index for frame N - 1.
This patch fixes the problems. It solves these issues in two different
ways, one for transforms and one for skins:
1. To fix transforms, this patch supplies the *frame index* to the
shader as part of the view uniforms, and specifies which frame index
each mesh's previous transform refers to. So, in the situation described
above, the frame index would be N, the previous frame index would be N -
1, and the `previous_input_frame_number` would be N - 2. The shader can
now detect this situation and infer that the mesh has been retained, and
can therefore conclude that the mesh's transform hasn't changed.
2. To fix skins, this patch replaces the explicit `previous_skin_index`
with an invariant that the index of the joints for the current frame and
the index of the joints for the previous frame are the same. This means
that the `MeshInputUniform` never has to be updated even if the skin is
animated. The downside is that we have to copy joint matrices from the
previous frame's buffer to the current frame's buffer in
`extract_skins`.
The rationale behind (2) is that we currently have no mechanism to
detect when joints that affect a skin have been updated, short of
comparing all the transforms and setting a flag for
`extract_meshes_for_gpu_building` to consume, which would regress
performance as we want `extract_skins` and
`extract_meshes_for_gpu_building` to be able to run in parallel.
To test this change, use `cargo run --example motion_blur`.
Currently, the specialized pipeline cache maps a (view entity, mesh
entity) tuple to the retained pipeline for that entity. This causes two
problems:
1. Using the view entity is incorrect, because the view entity isn't
stable from frame to frame.
2. Switching the view entity to a `RetainedViewEntity`, which is
necessary for correctness, significantly regresses performance of
`specialize_material_meshes` and `specialize_shadows` because of the
loss of the fast `EntityHash`.
This patch fixes both problems by switching to a *two-level* hash table.
The outer level of the table maps each `RetainedViewEntity` to an inner
table, which maps each `MainEntity` to its pipeline ID and change tick.
Because we loop over views first and, within that loop, loop over
entities visible from that view, we hoist the slow lookup of the view
entity out of the inner entity loop.
Additionally, this patch fixes a bug whereby pipeline IDs were leaked
when removing the view. We still have a problem with leaking pipeline
IDs for deleted entities, but that won't be fixed until the specialized
pipeline cache is retained.
This patch improves performance of the [Caldera benchmark] from 7.8×
faster than 0.14 to 9.0× faster than 0.14, when applied on top of the
global binding arrays PR, #17898.
[Caldera benchmark]: https://github.com/DGriffin91/bevy_caldera_scene
Currently, Bevy rebuilds the buffer containing all the transforms for
joints every frame, during the extraction phase. This is inefficient in
cases in which many skins are present in the scene and their joints
don't move, such as the Caldera test scene.
To address this problem, this commit switches skin extraction to use a
set of retained GPU buffers with allocations managed by the offset
allocator. I use fine-grained change detection in order to determine
which skins need updating. Note that the granularity is on the level of
an entire skin, not individual joints. Using the change detection at
that level would yield poor performance in common cases in which an
entire skin is animated at once. Also, this patch yields additional
performance from the fact that changing joint transforms no longer
requires the skinned mesh to be re-extracted.
Note that this optimization can be a double-edged sword. In
`many_foxes`, fine-grained change detection regressed the performance of
`extract_skins` by 3.4x. This is because every joint is updated every
frame in that example, so change detection is pointless and is pure
overhead. Because the `many_foxes` workload is actually representative
of animated scenes, this patch includes a heuristic that disables
fine-grained change detection if the number of transformed entities in
the frame exceeds a certain fraction of the total number of joints.
Currently, this threshold is set to 25%. Note that this is a crude
heuristic, because it doesn't distinguish between the number of
transformed *joints* and the number of transformed *entities*; however,
it should be good enough to yield the optimum code path most of the
time.
Finally, this patch fixes a bug whereby skinned meshes are actually
being incorrectly retained if the buffer offsets of the joints of those
skinned meshes changes from frame to frame. To fix this without
retaining skins, we would have to re-extract every skinned mesh every
frame. Doing this was a significant regression on Caldera. With this PR,
by contrast, mesh joints stay at the same buffer offset, so we don't
have to update the `MeshInputUniform` containing the buffer offset every
frame. This also makes PR #17717 easier to implement, because that PR
uses the buffer offset from the previous frame, and the logic for
calculating that is simplified if the previous frame's buffer offset is
guaranteed to be identical to that of the current frame.
On Caldera, this patch reduces the time spent in `extract_skins` from
1.79 ms to near zero. On `many_foxes`, this patch regresses the
performance of `extract_skins` by approximately 10%-25%, depending on
the number of foxes. This has only a small impact on frame rate.
The GPU can fill out many of the fields in `IndirectParametersMetadata`
using information it already has:
* `early_instance_count` and `late_instance_count` are always
initialized to zero.
* `mesh_index` is already present in the work item buffer as the
`input_index` of the first work item in each batch.
This patch moves these fields to a separate buffer, the *GPU indirect
parameters metadata* buffer. That way, it avoids having to write them on
CPU during `batch_and_prepare_binned_render_phase`. This effectively
reduces the number of bits that that function must write per mesh from
160 to 64 (in addition to the 64 bits per mesh *instance*).
Additionally, this PR refactors `UntypedPhaseIndirectParametersBuffers`
to add another layer, `MeshClassIndirectParametersBuffers`, which allows
abstracting over the buffers corresponding indexed and non-indexed
meshes. This patch doesn't make much use of this abstraction, but
forthcoming patches will, and it's overall a cleaner approach.
This didn't seem to have much of an effect by itself on
`batch_and_prepare_binned_render_phase` time, but subsequent PRs
dependent on this PR yield roughly a 2× speedup.
# Objective
- #17787 removed sweeping of binned render phases from 2D by accident
due to them not using the `BinnedRenderPhasePlugin`.
- Fixes#17885
## Solution
- Schedule `sweep_old_entities` in `QueueSweep` like
`BinnedRenderPhasePlugin` does, but for 2D where that plugin is not
used.
## Testing
Tested with the modified `shader_defs` example in #17885 .
Fixes#17290.
<details>
<summary>Compilation errors before fix</summary>
`cargo clippy --tests --all-features --package bevy_image`:
```rust
error[E0061]: this function takes 7 arguments but 6 arguments were supplied
--> crates/bevy_core_pipeline/src/tonemapping/mod.rs:451:5
|
451 | Image::from_buffer(
| ^^^^^^^^^^^^^^^^^^
...
454 | bytes,
| ----- argument #1 of type `std::string::String` is missing
|
note: associated function defined here
--> /Users/josiahnelson/Desktop/Programming/Rust/bevy/crates/bevy_image/src/image.rs:930:12
|
930 | pub fn from_buffer(
| ^^^^^^^^^^^
help: provide the argument
|
451 | Image::from_buffer(/* std::string::String */, bytes, image_type, CompressedImageFormats::NONE, false, image_sampler, RenderAssetUsages::RENDER_WORLD)
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```
`cargo clippy --tests --all-features --package bevy_gltf`:
```rust
error[E0560]: struct `bevy_pbr::StandardMaterial` has no field named `specular_channel`
--> crates/bevy_gltf/src/loader.rs:1343:13
|
1343 | specular_channel: specular.specular_channel,
| ^^^^^^^^^^^^^^^^ `bevy_pbr::StandardMaterial` does not have this field
|
= note: available fields are: `emissive_exposure_weight`, `diffuse_transmission`, `diffuse_transmission_channel`, `diffuse_transmission_texture`, `flip_normal_map_y` ... and 9 others
error[E0560]: struct `bevy_pbr::StandardMaterial` has no field named `specular_texture`
--> crates/bevy_gltf/src/loader.rs:1345:13
|
1345 | specular_texture: specular.specular_texture,
| ^^^^^^^^^^^^^^^^ `bevy_pbr::StandardMaterial` does not have this field
|
= note: available fields are: `emissive_exposure_weight`, `diffuse_transmission`, `diffuse_transmission_channel`, `diffuse_transmission_texture`, `flip_normal_map_y` ... and 9 others
error[E0560]: struct `bevy_pbr::StandardMaterial` has no field named `specular_tint_channel`
--> crates/bevy_gltf/src/loader.rs:1351:13
|
1351 | specular_tint_channel: specular.specular_color_channel,
| ^^^^^^^^^^^^^^^^^^^^^ `bevy_pbr::StandardMaterial` does not have this field
|
= note: available fields are: `emissive_exposure_weight`, `diffuse_transmission`, `diffuse_transmission_channel`, `diffuse_transmission_texture`, `flip_normal_map_y` ... and 9 others
error[E0560]: struct `bevy_pbr::StandardMaterial` has no field named `specular_tint_texture`
--> crates/bevy_gltf/src/loader.rs:1353:13
|
1353 | specular_tint_texture: specular.specular_color_texture,
| ^^^^^^^^^^^^^^^^^^^^^ `bevy_pbr::StandardMaterial` does not have this field
|
= note: available fields are: `emissive_exposure_weight`, `diffuse_transmission`, `diffuse_transmission_channel`, `diffuse_transmission_texture`, `flip_normal_map_y` ... and 9 others
```
</details>
# Objective
Fixes#17022
## Solution
Only enable `bevy_gltf/dds` if `bevy_gltf` is already enabled.
## Testing
Tested with empty project
```toml
[dependencies]
bevy = { version = "0.16.0-dev", path = "../bevy", default-features = false, features = [
"dds",
] }
```
### Before
```
cargo tree --depth 1 -i bevy_gltf
bevy_gltf v0.16.0-dev (/Users/robparrett/src/bevy/crates/bevy_gltf)
└── bevy_internal v0.16.0-dev (/Users/robparrett/src/bevy/crates/bevy_internal)
```
### After
```
cargo tree --depth 1 -i bevy_gltf
warning: nothing to print.
To find dependencies that require specific target platforms, try to use option `--target all` first, and then narrow your search scope accordingly.
```
# Context
Renaming `Parent` to `ChildOf` in #17247 has been contentious. While
those users concerns are valid (especially around legibility of code
IMO!), @cart [has
decided](https://discord.com/channels/691052431525675048/749335865876021248/1340434322833932430)
to stick with the new name.
> In general this conversation is unsurprising to me, as it played out
essentially the same way when I asked for opinions in my PR. There are
strong opinions on both sides. Everyone is right in their own way.
>
> I chose ChildOf for the following reasons:
>
> 1. I think it derives naturally from the system we have built, the
concepts we have chosen, and how we generally name the types that
implement a trait in Rust. This is the name of the type implementing
Relationship. We are adding that Relationship component to a given
entity (whether it "is" the relationship or "has" the relationship is
kind of immaterial ... we are naming the relationship that it "is" or
"has"). What is the name of the relationship that a child has to its
parent? It is a "child" of the parent of course!
> 2. In general the non-parent/child relationships I've seen in the wild
generally benefit from (or need to) use the naming convention in (1)
(aka calling the Relationship the name of the relationship the entity
has). Many relationships don't have an equivalent to the Parent/Child
name concept.
> 3. I do think we could get away with using (1) for pretty much
everything else and special casing Parent/Children. But by embracing the
naming convention, we help establish that this is in fact a pattern, and
we help prime people to think about these things in a consistent way.
Consistency and predictability is a generally desirable property. And
for something as divisive and polarizing as relationship naming, I think
drawing a hard line in the sand is to the benefit of the community as a
whole.
> 4. I believe the fact that we dont see as much of the XOf naming style
elsewhere is to our benefit. When people see things in that style, they
are primed to think of them as relationships (after some exposure to
Bevy and the ecosystem). I consider this a useful hint.
> 5. Most of the practical confusion from using ChildOf seems to be from
calling the value of the target field we read from the relationship
child_of. The name of the target field should be parent (we could even
consider renaming child_of.0 to child_of.parent for clarity). I suspect
that existing Bevy users renaming their existing code will feel the most
friction here, as this requires a reframing. Imo it is natural and
expected to receive pushback from these users hitting this case.
## Objective
The new documentation doesn't do a particularly good job at quickly
explaining the meaning of each component or how to work with them;
making a tricky migration more painful and slowing down new users as
they learn about some of the most fundamental types in Bevy.
## Solution
1. Clearly explain what each component does in the very first line,
assuming no background knowledge. This is the first relationships that
99% of users will encounter, so explaining that they are relationships
is unhelpful as an introduction.
2. Add doc aliases for the rejected `IsParent`/`IsChild`/`Parent` names,
to improve autocomplete and doc searching.
3. Do some assorted docs cleanup while we're here.
---------
Co-authored-by: Eagster <79881080+ElliottjPierce@users.noreply.github.com>
## Objective
There's no general error for when an entity doesn't exist, and some
methods are going to need one when they get Resultified. The closest
thing is `EntityFetchError`, but that error has a slightly more specific
purpose.
## Solution
- Added `EntityDoesNotExistError`.
- Contains `Entity` and `EntityDoesNotExistDetails`.
- Changed `EntityFetchError` and `QueryEntityError`:
- Changed `NoSuchEntity` variant to wrap `EntityDoesNotExistError` and
renamed the variant to `EntityDoesNotExist`.
- Renamed `EntityFetchError` to `EntityMutableFetchError` to make its
purpose clearer.
- Renamed `TryDespawnError` to `EntityDespawnError` to make it more
general.
- Changed `World::inspect_entity` to return `Result<[ok],
EntityDoesNotExistError>` instead of panicking.
- Changed `World::get_entity` and `WorldEntityFetch::fetch_ref` to
return `Result<[ok], EntityDoesNotExistError>` instead of `Result<[ok],
Entity>`.
- Changed `UnsafeWorldCell::get_entity` to return
`Result<UnsafeEntityCell, EntityDoesNotExistError>` instead of
`Option<UnsafeEntityCell>`.
## Migration Guide
- `World::inspect_entity` now returns `Result<impl Iterator<Item =
&ComponentInfo>, EntityDoesNotExistError>` instead of `impl
Iterator<Item = &ComponentInfo>`.
- `World::get_entity` now returns `EntityDoesNotExistError` as an error
instead of `Entity`. You can still access the entity's ID through the
error's `entity` field.
- `UnsafeWorldCell::get_entity` now returns `Result<UnsafeEntityCell,
EntityDoesNotExistError>` instead of `Option<UnsafeEntityCell>`.
Appending to these vectors is performance-critical in
`batch_and_prepare_binned_render_phase`, so `RawBufferVec`, which
doesn't have the overhead of `encase`, is more appropriate.
The `collect_buffers_for_phase` system tries to reuse these buffers, but
its efforts are stymied by the fact that
`clear_batched_gpu_instance_buffers` clears the containing hash table
and therefore frees the buffers. This patch makes
`clear_batched_gpu_instance_buffers` stop doing that so that the
allocations can be reused.
# Objective
Simplify the API surface by removing duplicated functionality between
`Query` and `QueryState`.
Reduce the amount of `unsafe` code required in `QueryState`.
This is a follow-up to #15858.
## Solution
Move implementations of `Query` methods from `QueryState` to `Query`.
Instead of the original methods being on `QueryState`, with `Query`
methods calling them by passing the individual parameters, the original
methods are now on `Query`, with `QueryState` methods calling them by
constructing a `Query`.
This also adds two `_inner` methods that were missed in #15858:
`iter_many_unique_inner` and `single_inner`.
One goal here is to be able to deprecate and eventually remove many of
the methods on `QueryState`, reducing the overall API surface. (I
expected to do that in this PR, but this change was large enough on its
own!) Now that the `QueryState` methods each consist of a simple
expression like `self.query(world).get_inner(entity)`, a future PR can
deprecate some or all of them with simple migration instructions.
The other goal is to reduce the amount of `unsafe` code. The current
implementation of a read-only method like `QueryState::get` directly
calls the `unsafe fn get_unchecked_manual` and needs to repeat the proof
that `&World` has enough access. With this change, `QueryState::get` is
entirely safe code, with the proof that `&World` has enough access done
by the `query()` method and shared across all read-only operations.
## Future Work
The next step will be to mark the `QueryState` methods as
`#[deprecated]` and migrate callers to the methods on `Query`.
# Objective
Support accessing resources using reflection when using
`FilteredResources` in a dynamic system. This is similar to how
components can be queried using reflection when using
`FilteredEntityRef|Mut`.
## Solution
Change `ReflectResource` from taking `&World` and `&mut World` to taking
`impl Into<FilteredResources>` and `impl Into<FilteredResourcesMut>`,
similar to how `ReflectComponent` takes `impl Into<FilteredEntityRef>`
and `impl Into<FilteredEntityMut>`. There are `From` impls that ensure
code passing `&World` and `&mut World` continues to work as before.
## Migration Guide
If you are manually creating a `ReflectComponentFns` struct, the
`reflect` function now takes `FilteredResources` instead `&World`, and
there is a new `reflect_mut` function that takes `FilteredResourcesMut`.
# Objective
Add reference to reported position space in picking backend docs.
Fixes#17844
## Solution
Add explanatory docs to the implementation notes of each picking
backend.
## Testing
`cargo r -p ci -- doc-check` & `cargo r -p ci -- lints`
# Objective
It is impossible to register a type with `TypeRegistry::register` if the
type is unnameable (in the current scope).
## Solution
Add `TypeRegistry::register_by_val` which mirrors std's `size_of_val`
and friends.
## Testing
There's a doc test (unrelated but there seem to be some pre-existing
broken doc links in `bevy_reflect`).
There was nonsense code in `batch_and_prepare_sorted_render_phase` that
created temporary buffers to add objects to instead of using the correct
ones. I think this was debug code. This commit removes that code in
favor of writing to the actual buffers.
Closes#17846.
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
`bevy_assets` has long been unapproachable for contributors and users.
More and better documentation would help that.
We're gradually moving towards globally denying missing docs (#3492)!
However, writing all of the hundreds of missing doc strings in a single
go will be miserable to review.
## Solution
Remove the allow for missing docs temporarily, and then pick some easy
missing doc warnings largely at random to tackle.
Stop when the change set is starting to feel intimidating.
The `output_index` field is only used in direct mode, and the
`indirect_parameters_index` field is only used in indirect mode.
Consequently, we can combine them into a single field, reducing the size
of `PreprocessWorkItem`, which
`batch_and_prepare_{binned,sorted}_render_phase` must construct every
frame for every mesh instance, from 96 bits to 64 bits.
# Objective
Continuation of #16547.
We do not yet have parallel versions of `par_iter_many` and
`par_iter_many_unique`. It is currently very painful to try and use
parallel iteration over entity lists. Even if a list is not long, each
operation might still be very expensive, and worth parallelizing.
Plus, it has been requested several times!
## Solution
Once again, we implement what we lack!
These parallel iterators collect their input entity list into a
`Vec`/`UniqueEntityVec`, then chunk that over the available threads,
inspired by the original `par_iter`.
Since no order guarantee is given to the caller, we could sort the input
list according to `EntityLocation`, but that would likely only be worth
it for very large entity lists.
There is some duplication which could likely be improved, but I'd like
to leave that for a follow-up.
## Testing
The doc tests on `for_each_init` of `QueryParManyIter` and
`QueryParManyUniqueIter`.
# Objective
While surveying the state of documentation for bevy_assets, I noticed a
few minor issues.
## Solution
Revise the docs to focus on clear explanations of core ideas and
cross-linking related objects.
# Objective
Update typos, fix new typos.
1.29.6 was just released to fix an
[issue](https://github.com/crate-ci/typos/issues/1228) where January's
corrections were not included in the binaries for the last release.
Reminder: typos can be tossed in the monthly [non-critical corrections
issue](https://github.com/crate-ci/typos/issues/1221).
## Solution
I chose to allow `implementors`, because a good argument seems to be
being made [here](https://github.com/crate-ci/typos/issues/1226) and
there is now a PR to address that.
## Discussion
Should I exclude `bevy_mikktspace`?
At one point I think we had an informal policy of "don't mess with
mikktspace until https://github.com/bevyengine/bevy/pull/9050 is merged"
but it doesn't seem like that is likely to be merged any time soon.
I think these particular corrections in mikktspace are fine because
- The same typo mistake seems to have been fixed in that PR
- The entire file containing these corrections was deleted in that PR
## Typo of the Month
correspindong -> corresponding
# Objective
Updates the now inaccurate position docs
Fixes#17832
## Solution
From
`The position of the intersection in the world, if the data is available
from the backend.`
To
`The position reported by the backend, if the data is available.
Position data may be in any space (e.g. World space, Screen space, Local
space), specified by the backend providing it.`
## Testing
uhh reading :)
Currently, invocations of `batch_and_prepare_binned_render_phase` and
`batch_and_prepare_sorted_render_phase` can't run in parallel because
they write to scene-global GPU buffers. After PR #17698,
`batch_and_prepare_binned_render_phase` started accounting for the
lion's share of the CPU time, causing us to be strongly CPU bound on
scenes like Caldera when occlusion culling was on (because of the
overhead of batching for the Z-prepass). Although I eventually plan to
optimize `batch_and_prepare_binned_render_phase`, we can obtain
significant wins now by parallelizing that system across phases.
This commit splits all GPU buffers that
`batch_and_prepare_binned_render_phase` and
`batch_and_prepare_sorted_render_phase` touches into separate buffers
for each phase so that the scheduler will run those phases in parallel.
At the end of batch preparation, we gather the render phases up into a
single resource with a new *collection* phase. Because we already run
mesh preprocessing separately for each phase in order to make occlusion
culling work, this is actually a cleaner separation. For example, mesh
output indices (the unique ID that identifies each mesh instance on GPU)
are now guaranteed to be sequential starting from 0, which will simplify
the forthcoming work to remove them in favor of the compute dispatch ID.
On Caldera, this brings the frame time down to approximately 9.1 ms with
occlusion culling on.

# Objective
Fix unsoundness introduced by #15858. `QueryLens::query()` would hand
out a `Query` with the full `'w` lifetime, and the new `_inner` methods
would let the results outlive the `Query`. This could be used to create
aliasing mutable references, like
```rust
fn bad<'w>(mut lens: QueryLens<'w, EntityMut>, entity: Entity) {
let one: EntityMut<'w> = lens.query().get_inner(entity).unwrap();
let two: EntityMut<'w> = lens.query().get_inner(entity).unwrap();
assert!(one.entity() == two.entity());
}
```
Fixes#17693
## Solution
Restrict the `'world` lifetime in the `Query` returned by
`QueryLens::query()` to `'_`, the lifetime of the borrow of the
`QueryLens`.
The model here is that `Query<'w, 's, D, F>` and `QueryLens<'w, D, F>`
have permission to access their components for the lifetime `'w`. So
going from `&'a mut QueryLens<'w>` to `Query<'w, 'a>` would borrow the
permission only for the `'a` lifetime, but incorrectly give it out for
the full `'w` lifetime.
To handle any cases where users were calling `get_inner()` or
`iter_inner()` on the `Query` and expecting the full `'w` lifetime, we
introduce a new `QueryLens::query_inner()` method. This is only valid
for `ReadOnlyQueryData`, so it may safely hand out a copy of the
permission for the full `'w` lifetime. Since `get_inner()` and
`iter_inner()` were only valid on `ReadOnlyQueryData` prior to #15858,
that should cover any uses that relied on the longer lifetime.
## Migration Guide
Users of `QueryLens::query()` who were calling `get_inner()` or
`iter_inner()` will need to replace the call with
`QueryLens::query_inner()`.
Conceptually, bins are ordered hash maps. We currently implement these
as a list of keys with an associated hash map. But we already have a
data type that implements ordered hash maps directly: `IndexMap`. This
patch switches Bevy to use `IndexMap`s for bins. Because we're memory
bound, this doesn't affect performance much, but it is cleaner.
# Objective
Related to #17784. The ticket is actually about just getting rid of
`Entity{Ref,Mut}Except` in favor of `FilteredEntity{Ref,Mut}`, but I got
told the unification of Entity types is a bigger endeavor that has been
going on for a while now (as the "Pointing Fingers" working group) and I
should just add the functions I actually need in the meantime.
## Solution
This PR adds all of the functions necessary to access components by
TypeId or ComponentId instead of static types.
## Testing
> Did you test these changes? If so, how?
Haven't tested it yet, but the changes are mostly copy/paste from other
implementations in the same file, since there is a lot of duplicated
functionality there.
## Not a Migration Guide
There shouldn't be any breaking changes, it's just a few new functions
on existing types.
I had to shuffle around the lifetimes in `From<&EntityMutExcept<'a, B>>
for EntityRefExcept<'a, B>` (originally it was `From<&'a
EntityMutExcept<'_, B>> for EntityRefExcept<'_, B>`) to make the borrow
checker happy, but I don't think that this should have an impact on user
code (correct me if I'm wrong).
* Use texture atomics rather than buffer atomics for the visbuffer
(haven't tested perf on a raster-heavy scene yet)
* Unfortunately to clear the visbuffer we now need a compute pass to
clear it. Using wgpu's clear_texture function internally uses a buffer
-> image copy that's insanely expensive. Ideally it should be using
vkCmdClearColorImage, which I've opened an issue for
https://github.com/gfx-rs/wgpu/issues/7090. For now we'll have to stick
with a custom compute pass and all the extra code that brings.
* Faster resolve depth pass by discarding 0 depth pixels instead of
redundantly writing zero (2x faster for big depth textures like shadow
views)
# Objective
- Wgpu has some expensive code it injects into shaders to avoid the
possibility of things like infinite loops. Generally our shaders are
written by users who won't do this, so it just makes our shaders perform
worse.
## Solution
- Turn off the checks.
- We could try to conditionally keep them, but that complicates the code
and 99.9% of users won't want this.
## Migration Guide
- Bevy no longer turns on wgpu's runtime safety checks
https://docs.rs/wgpu/latest/wgpu/struct.ShaderRuntimeChecks.html. If you
were using Bevy with untrusted shaders, please file an issue.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Continuation of #17589 and #16547.
Slices have several methods that return iterators which themselves yield
slices, which we have not yet implemented.
An example use is `par_iter_many` style logic.
## Solution
Their implementation is rather straightforward, we simply delegate all
impls to `[T]`.
The resulting iterator types need their own wrappers in the form of
`UniqueEntitySliceIter` and `UniqueEntitySliceIterMut`.
We also add three free functions that cast slices of entity slices to
slices of `UniqueEntitySlice`.
These three should be sufficient, though infinite nesting is achievable
with a trait (like `TrustedEntityBorrow` works over infinite reference
nesting), should the need ever arise.
## Objective
Get rid of a redundant Cargo feature flag.
## Solution
Use the built-in `target_abi = "sim"` instead of a custom Cargo feature
flag, which is set for the iOS (and visionOS and tvOS) simulator. This
has been stable since Rust 1.78.
In the future, some of this may become redundant if Wgpu implements
proper supper for the iOS Simulator:
https://github.com/gfx-rs/wgpu/issues/7057
CC @mockersf who implemented [the original
fix](https://github.com/bevyengine/bevy/pull/10178).
## Testing
- Open mobile example in Xcode.
- Launch the simulator.
- See that no errors are emitted.
- Remove the code cfg-guarded behind `target_abi = "sim"`.
- See that an error now happens.
(I haven't actually performed these steps on the latest `main`, because
I'm hitting an unrelated error (EDIT: It was
https://github.com/bevyengine/bevy/pull/17637). But tested it on
0.15.0).
---
## Migration Guide
> If you're using a project that builds upon the mobile example, remove
the `ios_simulator` feature from your `Cargo.toml` (Bevy now handles
this internally).
Currently, we look up each `MeshInputUniform` index in a hash table that
maps the main entity ID to the index every frame. This is inefficient,
cache unfriendly, and unnecessary, as the `MeshInputUniform` index for
an entity remains the same from frame to frame (even if the input
uniform changes). This commit changes the `IndexSet` in the `RenderBin`
to an `IndexMap` that maps the `MainEntity` to `MeshInputUniformIndex`
(a new type that this patch adds for more type safety).
On Caldera with parallel `batch_and_prepare_binned_render_phase`, this
patch improves that function from 3.18 ms to 2.42 ms, a 31% speedup.
Currently, when a mesh slab overflows, we recreate the allocator and
reinsert all the meshes that were in it in an arbitrary order. This can
result in the meshes moving around. Before `MeshInputUniform`s were
retained, this was slow but harmless, because the `MeshInputUniform`
that contained the positions of the vertex and index data in the slab
would be recreated every frame. However, with mesh retention, there's no
guarantee that the `MeshInputUniform`, which could be cached from the
previous frame, will reflect the new position of the mesh data within
the buffer if that buffer happened to grow. This manifested itself as
seeming mesh data corruption when adding many meshes dynamically to the
scene.
There are three possible ways that I could have fixed this that I can
see:
1. Invalidate and rebuild all the `MeshInputUniform`s belonging to all
meshes in a slab when that mesh grows.
2. Introduce a second layer of indirection so that the
`MeshInputUniform` points to a *mesh allocation table* that contains the
current locations of the data of each mesh.
3. Avoid moving meshes when reallocating the buffer.
To be efficient, option (1) would require scanning meshes to see if
their positions changed, a la
`mark_meshes_as_changed_if_their_materials_changed`. Option (2) would
add more runtime indirection and would require additional bookkeeping on
the part of the allocator.
Therefore, this PR chooses option (3), which was remarkably simple to
implement. The key is that the offset allocator happens to allocate
addresses from low addresses to high addresses. So all we have to do is
to *conceptually* allocate the full 512 MiB mesh slab as far as the
offset allocator is concerned, and grow the underlying backing store
from 1 MiB to 512 MiB as needed. In other words, the allocator now
allocates *virtual* GPU memory, and the actual backing slab resizes to
fit the virtual memory. This ensures that the location of mesh data
remains constant for the lifetime of the mesh asset, and we can remove
the code that reinserts meshes one by one when the slab grows in favor
of a single buffer copy.
Closes#17766.