# 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
petgraph 0.7 has been released a while ago, but bevy still pulls in
petgraph 0.6
## Solution
- Update the version in bevy_reflect's `Cargo.toml`.
## Testing
- I ran `cargo test --all-features`.
# 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
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
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();
```
Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.30.0 to
1.30.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/crate-ci/typos/releases">crate-ci/typos's
releases</a>.</em></p>
<blockquote>
<h2>v1.30.1</h2>
<h2>[1.30.1] - 2025-03-04</h2>
<h3>Features</h3>
<ul>
<li><em>(action)</em> Create <code>v1</code> tag</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/crate-ci/typos/blob/master/CHANGELOG.md">crate-ci/typos's
changelog</a>.</em></p>
<blockquote>
<h2>[1.30.1] - 2025-03-04</h2>
<h3>Features</h3>
<ul>
<li><em>(action)</em> Create <code>v1</code> tag</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="72f3776b6e"><code>72f3776</code></a>
chore: Release</li>
<li><a
href="36c9d7068c"><code>36c9d70</code></a>
docs: Update changelog</li>
<li><a
href="67a0344016"><code>67a0344</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/1250">#1250</a>
from muzimuzhi/ci/major-tag</li>
<li><a
href="6b1c68673a"><code>6b1c686</code></a>
chore(ci): maintain major tags for GitHub Actions</li>
<li><a
href="ff2ab643f4"><code>ff2ab64</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/1247">#1247</a>
from crate-ci/renovate/derive_more-2.x</li>
<li><a
href="561caedbaf"><code>561caed</code></a>
chore(deps): Update Rust crate derive_more to v2</li>
<li>See full diff in <a
href="https://github.com/crate-ci/typos/compare/v1.30.0...v1.30.1">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
# 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
- While a PR is in work, if several commits fail and trigger a comment
from the action, this can create a lot of comments from actions with low
value
- Noticed on https://github.com/bevyengine/bevy/pull/18139
## Solution
- If last comment on a PR is from an action, don't add a new comment
---------
Co-authored-by: Martín Maita <47983254+mnmaita@users.noreply.github.com>
# 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>
# Objective
The `paste` crate is giving us [warnings in
CI](https://github.com/bevyengine/bevy/actions/runs/13751490200/job/38452998990?pr=18099)
via `cargo-deny` about being unmaintained.
This warning is quite noisy: making unrelated PRs seem like they have a
problem due to a job failing.
## Solution
Ignore the warning for now. There are multiple crates (accesskit, metal,
macro_rules_attribute, rmp) which are using this, and there's no clear
migration advice, even if we want to poke upstream to swap off.
Strategy for ignoring was taken from
https://github.com/EmbarkStudios/cargo-deny/blob/main/deny.template.toml
## Testing
Let's see if CI works!
---------
Co-authored-by: andriyDev <andriydzikh@gmail.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
- When a PR gets merged that modifies the rendering screenshots, the
main reference will be updated
- Every in-flight PR will then "fail" rendering change detection as they
come from an outdated main branch
## Solution
- Suggest updating the PR to the latest main branch
# 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>