# Objective
- Fixes#17506
- Fixes#16258
## Solution
- Added a new folder of examples, `no_std`, similar to the `mobile`
folder.
- Added a single example, `no_std_library`, which demonstrates how to
make a `no_std` compatible Bevy library.
- Added a new CI task, `check-compiles-no-std-examples`, which checks
that `no_std` examples compile on `no_std` targets.
- Added `bevy_platform_support::prelude` to `bevy::prelude`.
## Testing
- CI
---
## Notes
- I've structured the folders here to permit further `no_std` examples
(e.g., GameBoy Games, ESP32 firmware, etc.), but I am starting with the
simplest and least controversial example.
- I've tried to be as clear as possible with the documentation for this
example, catering to an audience who may not have even heard of `no_std`
before.
---------
Co-authored-by: Greeble <166992735+greeble-dev@users.noreply.github.com>
# Objective
WESL was broken on windows.
## Solution
- Upgrade to `wesl_rs` 1.2.
- Fix path handling on windows.
- Improve example for khronos demo this week.
# Objective
- #17581 broke gizmos
- Fixes#18325
## Solution
- Revert #17581
- Add gizmos to testbed
## Testing
- Run any example with gizmos, it renders correctly
# Objective
On iOS:
- Allow `std` to do its runtime initialization.
- Avoid requiring the user to specify linked libraries and framework in
Xcode.
- Reduce the amount of work that `#[bevy_main]` does
- In the future we may also be able to eliminate the need for it on
Android, cc @daxpedda.
## Solution
We previously:
- Exposed an `extern "C" fn main_rs` entry point.
- Ran Cargo in a separate Xcode target as an external build system.
- Imported that as a dependency of `bevy_mobile_example.app`.
- Compiled a trampoline C file with Xcode that called `main_rs`.
- Linked that via. Xcode.
All of this is unnecessary; `rustc` is well capable of creating iOS
executables, the trick is just to place it at the correct location for
Xcode to understand it, namely `$TARGET_BUILD_DIR/$EXECUTABLE_PATH`
(places it in `bevy_mobile_example.app/bevy_mobile_example`).
Note: We might want to wait with the changes to `#[bevy_main]` until the
problem is resolved on Android too, to make the migration easier.
## Testing
Open the Xcode project, and build for an iOS target.
---
## Migration Guide
**If you have been building your application for iOS:**
Previously, the `#[bevy_main]` attribute created a `main_rs` entry point
that most Xcode templates were using to run your Rust code from C. This
was found to be unnecessary, as you can simply let Rust build your
application as a binary, and run that directly.
You have two options for dealing with this:
If you've added further C code and Xcode customizations, or it makes
sense for your use-case to continue link with Xcode, you can revert to
the old behaviour by adding `#[no_mangle] extern "C" main_rs() { main()
}` to your `main.rs`. Note that the old approach of linking a static
library prevents the Rust standard library from doing runtime
initialization, so certain functionality provided by `std` might be
unavailable (stack overflow handlers, stdout/stderr flushing and other
such functionality provided by the initialization routines).
The other, preferred option is to remove your "compile" and "link" build
phases, and instead replace it with a "run script" phase that invokes
`cargo build --bin ...`, and moves the built binary to the Xcode path
`$TARGET_BUILD_DIR/$EXECUTABLE_PATH`. An example of how to do this can
be viewed at [INSERT LINK TO UPDATED EXAMPLE PROJECT].
To make the debugging experience in Xcode nicer after this, you might
also want to consider either enabling `panic = "abort"` or to set a
breakpoint on the `rust_panic` symbol.
---------
Co-authored-by: François Mockers <mockersf@gmail.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
# 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
#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
Contributes to #18238
Updates the `computed_states`, example to use the `children!` macro.
Note that this example requires `--features bevy_dev_tools` to run
## Solution
Updates examples to use the Improved Spawning API merged in
https://github.com/bevyengine/bevy/pull/17521
## 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
n/a
# Objective
Some of Bevy's examples contain boilerplate which is split out into the
`helpers` folder. This allows examples to have access to common
functionality without building into Bevy directly. However, these
helpers are themselves quite high-quality code, and we do intend for
users to read them and even use them. But, we don't list them in the
examples document, and they aren't explicitly checked in CI, only
transitively through examples which import them.
## Solution
- Added `camera_controller` and `widgets` as library examples.
## Testing
- CI
---
## Notes
- Library examples are identical to any other example, just with
`crate-type = ["lib"]` in the `Cargo.toml`. Since they are marked as
libraries, they don't require a `main` function but do require public
items to be documented.
- Library examples opens the possibility of creating examples which
don't need to be actual runnable applications. This may be more
appropriate for certain ECS examples, and allows for adding helpers
which (currently) don't have an example that needs them without them
going stale.
- I learned about this as a concept during research for `no_std`
examples, but believe it has value for Bevy outside that specific niche.
---------
Co-authored-by: mgi388 <135186256+mgi388@users.noreply.github.com>
Co-authored-by: Carter Weinberg <weinbergcarter@gmail.com>
# Objective
Contributes to #18238
Updates the `custom_transitions` and `sub_states` examples to use the
`children!` macro.
## Solution
Updates examples to use the Improved Spawning API merged in
https://github.com/bevyengine/bevy/pull/17521
## 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
n/a
# Objective
Contributes to #18238
Updates the `gamepad_viewer`, example to use the `children!` macro.
## Solution
Updates examples to use the Improved Spawning API merged in
https://github.com/bevyengine/bevy/pull/17521
## 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
n/a
# Objective
Contributes to #18238
Updates the `SteppingPlugin` of the `breakout` example to use the
`children!` macro. Note that in order to test this usage you must use
`--features bevy_debug_stepping` and hit the back-tick key to enable
stepping mode to see the proper text spans rendered.
## Solution
Updates examples to use the Improved Spawning API merged in
https://github.com/bevyengine/bevy/pull/17521
## 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
n/a
# Objective
Contributes to #18238
Updates the `render_primitives` example to use the `children!` macro.
## Solution
Updates examples to use the Improved Spawning API merged in
https://github.com/bevyengine/bevy/pull/17521
## 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
n/a
# 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
Correct spelling
## Solution
Fix typos, specifically ones that I found in folders other than /crates
## Testing
CI
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Contributes to #18238
Updates the `text_input` and `virtual_time` examples to use the
`children!` macro. I wanted to keep the PR small but chose to do two
examples since they both included only a single `with_children` call.
## Solution
Updates examples to use the Improved Spawning API merged in
https://github.com/bevyengine/bevy/pull/17521
## 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
n/a
# Objective
Contributes to #18238
Updates the `state/states` example to use the `children!` macro. Note
that this example also requires `--features bevy_dev_tools`
## Solution
Updates examples to use the Improved Spawning API merged in
https://github.com/bevyengine/bevy/pull/17521
## 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
n/a
# 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
`Text2d` testing hasn't been as thorough as text in the UI, and it
suffered a bunch of bugs / perf issues in recent cycles.
## Solution
Add some more `Text2d` scenarios to the 2d testbed to catch bugs,
testing bounded and unbounded text with various justification.
## Testing
`cargo run --example testbed_2d` (press space a few times)
<img width="1280" alt="Screenshot 2025-03-10 at 1 02 03 PM"
src="https://github.com/user-attachments/assets/1e4ee39c-809b-4cc6-81bd-68e67b9625b5"
/>
---------
Co-authored-by: Ben Frankel <ben.frankel7@gmail.com>
Update the documentation comment to correctly state that the function
responds to spacebar presses rather than mouse clicks. This aligns the
documentation with the actual implementation, which was already using
keyboard input.
# Objective
- Fix incorrect documentation comment for the cycle_modes function that
inaccurately described using mouse input when the implementation
actually uses spacebar.
- This ensures documentation accuracy and prevents confusion for new
learners.
## Solution
- Updated the documentation comment to correctly state that the function
responds to spacebar presses rather than mouse clicks.
- The code functionality remains unchanged.
# Objective
Add an option to `many_buttons` that spawns a grid of buttons where each
button is rendered through its own camera.
## Testing
Run with:
```
cargo run --example many_buttons --release -- --many-cameras --buttons 20
```
The default buttons count of `110` is too much for my computer.
# 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
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
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
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
- 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
`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.
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
- have a testbed for UI
## Solution
- move previous `ui` example to `full_ui`
- add a testbed ui with several scenes
- `ui_layout_rounding` is one of those scenes, so remove it as a
standalone example
the previous `ui` / new `full_ui` is I think still useful as it has some
things like scroll, debug ui that are not shown anywhere else
# 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
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#18095
## Solution
Update the feature gates so that `Taa`, etc are added if
- Not on wasm
- OR using webgpu
## Testing
Check that `Taa` is disabled with appropriate messaging on webgl2
```
cargo run -p build-wasm-example -- --api webgl2 transmission && basic-http-server examples/wasm/
```
Check that `Taa` works on webgpu in chrome
```
cargo run -p build-wasm-example -- --api webgpu transmission && basic-http-server examples/wasm/
```
Check that `Taa` still works in a native build
```
cargo run -example transmission
```
# 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
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
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
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
I noticed when I was looking at the embedded assets example that there
wasn't any comments on it to indicate what an embedded asset is and why
anyone would want to make one.
## Solution
I added some more comments to the example that gives more detail about
embedded assets and how they work. Feel free to be aggressive with
rewriting these comments however, I just think the example could use
something haha.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# 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#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>
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>
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.