Related: Cargo Feature Collections
https://github.com/bevyengine/bevy/pull/21472
## Context:
> If `default_app` is meant to be
> > The core pieces that most apps need. This serves as a baseline
feature set for other higher level feature collections (such as "2d" and
"3d"). It is also useful as a baseline feature set for scenarios like
headless apps that require no rendering (ex: command line tools,
servers, etc).
>
> why should `bevy_window` / `custom_cursor` be there? I would expect
these to be in `common_api`.
\- Me,
https://discord.com/channels/691052431525675048/692572690833473578/1460424003486224517
> Imo this is a mistake. Can you open a PR with a migration guide
please?
\- Alice,
https://discord.com/channels/691052431525675048/692572690833473578/1460429142376845404
## Solution
- <strike>Move `bevy_window`, `bevy_input_focus`, `custom_cursor`
features from `default_app` collection to `common_api`</strike>
- From `default_app` collection move: `bevy_window` to `common_api`,
`bevy_input_focus` to `ui_api`, and `custom_cursor` to
`default_platform`.
## Testing
- Did you test these changes? If so, how?
Confirmed that `default_app` collection no longer introduces the crates
to the dependency tree:
```sh
$ git checkout bevy/main -q
$ cargo tree --no-default-features -Fdefault_app -e normal | grep -e bevy_window -e bevy_input_focus -e custom_cursor
├── bevy_input_focus v0.18.0-dev
│ ├── bevy_window v0.18.0-dev
├── bevy_window v0.18.0-dev (*)
├── bevy_input_focus v0.18.0-dev (*)
├── bevy_window v0.18.0-dev (*)
$ git checkout reduced-feature-group
Previous HEAD position was f8ea30965 Add support for reflected math operations ➕➖✖️➗ (#22478)
Switched to branch 'reduced-feature-group'
$ cargo tree --no-default-features -Fdefault_app -e normal | grep -e bevy_window -e bevy_input_focus -e custom_cursor
$
```
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
I'm not sure how cross-cutting changes to features have to be since I
haven't worked with such a complicated feature set before, so it's
possible I've omitted a change to some place that needs to be updated.
Please point it out to me, thank you.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
# Objective
The current PanCamera only supports keyboard panning, when a common use
case is mouse panning.
## Solution
Add optional mouse panning with some settings
## Testing
I ran the Pan Camera example with the new settings
## Additional notes
I added settings for setting the exact mouse button that triggers the
panning, and whether or not to grab the cursor when panning.
I am unsure about the cursor grab part of this design as it may mess
with the app's existing cursor options and the window part may not work
for some setups.
It may be wiser to just omit grabbing for now, or maybe keep grabbing
but don't change visibility idk
As always I am open to any and all feedback.
---------
Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- @NthTensor suggested using their `web-task` crate so tasks can use the
normal cancel semantics on the web.
- Fixes#4304, closes#4286.
## Solution
- Remove bevy's Task wrapper, since it's now redundant.
- Use `web_task::spawn_local(future)` in `single_threaded_task_pool.rs`.
## Testing
I ran all of the async tasks examples locally and via wasm and they
behaved identically.
# Objective
Fixes#23170.
## Solution
> Swapping the UI framework for your Bevy project is a common form of
customization.
> We think that users should be able to do this easily, without having
to give up the ease of use (and updates!)
> that come with our top-level feature collections.
>
> To achieve this, the `ui` feature collection is now no longer implied
by the `3d` or `2d` feature collection.
>
> To migrate:
>
> - If you used all default features before, nothing changes for you.
> - If you want to opt out of using `bevy_ui`, it is now as simple as
disabling default features, and manually opting into `3d` or `2d` (and
optionally `audio`).
> - If you already opted into non-default features and want to continue
using `bevy_ui`, you will now have to add the `ui` feature.
# Objective
Depends on #22187. Fixes#17794. ~For platform consistency I think it’s
reasonable to enable primitive restart by default.~ wgpu will force
primitive restart after https://github.com/gfx-rs/wgpu/pull/8850.
## Solution
Add index format to MeshPipelineKey, replace
`MeshPipelineKey::from_primitive_topology` with
`MeshPipelineKey::from_primitive_topology_and_index`, and enable
`strip_index_format` in render pipeline.
## Testing
I modified the `lines` example to demonstrate primitive restart.
## Showcase
<details>
<summary>Click to view showcase</summary>
<img width="1550" height="852" alt="屏幕截图_20251218_210849"
src="https://github.com/user-attachments/assets/a7c41943-f22b-415a-8132-98455f21735d"
/>
</details>
# Objective
Make release notes and migration guides show up first when viewing PRs
in github.
## Solution
Prefix the release-content directory with `_` so it sorts first.
## Testing
See for yourself.
# Objective
I have working `Command` reflection for my game:
```rust
#[derive(Clone)]
pub struct ReflectCommand {
pub apply: fn(&mut World, &dyn PartialReflect, &TypeRegistry),
}
impl ReflectCommand {
pub fn apply(&self, world: &mut World, command: &dyn PartialReflect, registry: &TypeRegistry) {
(self.apply)(world, command, registry);
}
}
impl<C: Command<Result> + Reflect + TypePath> FromType<C> for ReflectCommand {
fn from_type() -> Self {
ReflectCommand {
apply: |world, command, registry| {
let command = from_reflect_with_fallback::<C>(command, world, registry);
command.apply(world);
},
}
}
}
```
However, I am currently only allowed to support a single output type
across *all* command types (which I've chosen to be `Result` for the
time being). This is because, by virtue of `Out` being a generic
parameter, `Command` *can* be implemented multiple times for the same
type, but with different output types. In order for my command
reflection logic to support command types with *any* output type, I need
the ability to guarantee that `Command` will only be implemented once
for some `FooCommand`.
That's why `Out` should be changed into an associated type.
## Solution
- Turned the `Out` generic parameter into an associated type on both
`Command` and `EntityCommand`.
- Bounded `Command::Out` associated type with a new `CommandOutput`
trait.
- This replaces the functionality of the now removed `HandleError`
trait, and allows us to add its functions directly on the `Command`
trait.
- Also bounded `EntityCommand::Out` associated type with the new
`CommandOutput` trait.
- This replaces the functionality of the now removed `CommandWithEntity`
trait, and allows us to add its functions directly on the
`EntityCommand` trait.
Additionally, the new `CommandOutput` trait gives a place for bevy users
to hook into error handling logic with their own types! It also comes
with `diagnostic::on_unimplemented` diagnostics!
## Testing
Maybe TODO: Current tests appear green but should we add tests for the
new `CommandOutput` trait?
# Objective
- Continue Render Recovery efforts #23350#22761#23433#23458
- Part of goal #23029
- make indirect parameter buffers and batched instance buffers
reinitalize on recovery
## Solution
- split out the stuff that shouldnt be reinitialized from them
- use init_gpu_resource
## Testing
- examples run
- in combination with the rest of the fixes and a couple other local
changes i havent PRd yet, render_recovery example works.
# Objective
There are three separate traits for primary text components: `TextRoot`,
`TextSpanAccess` and `TextSpanComponent`.
They all provide the same functionality and can be consolidated into a
single trait.
The method names on `TextSpanAccess`'s (`read_span` and `write_span`)
aren't ideal either. The names imply performing an action, not just the
return of a reference, and should be changed to something more
idiomatic.
## Solution
* Renamed `TextSpanAccess` to `TextSection` and added a `From<String>`
trait bound.
* Renamed `read_span` to `get_text`.
* Renamed `write_span` to `get_text_mut`.
* Removed the `TextRoot` and `TextSpanComponent`.
* Replaced all usages of `TextRoot` and `TextSpanComponent` with
`TextSection`.
* Renamed the private `TextSection` struct in the `pipeline` module to
`TextSectionView`.
# Objective
- Fix startup crash on 3d_shapes example and anything that uses
wireframes
- Make sure extra_buffer_usages set arent lost on recovery
## Solution
- Move extra_buffer_usages to MeshAllocatorSettings
## Testing
- 3d_example doesnt crash
# Objective
Expose more data from `FilteredAccess` to allow third-party crates to
inspect queries. In particular, expose `required` and `filter_sets`,
which will allow third-party implementations of query observers (#20817)
to determine what component observers they will need.
## Solution
Add `pub` methods to expose `required` and `filter_sets`, make
`AccessFilters` `pub`, and add methods to expose `with` and `without`.
Add a `ComponentIdSet` type that wraps `FixedBitSet`. This allows us to
expose the efficient set operations like `union_with` that would not be
available if we returned a simple `Iterator<Item = ComponentId>`. And
not exposing the `FixedBitSet` directly avoids forcing users to manually
convert between `usize` and `ComponentId`, and will let us change the
implementation of the set (as in #18955) or representation of
`ComponentId` without changing the public API. It also simplifies the
internals a bit!
## Showcase
Here is how to calculate the component observers required for a query
observer in an implementation of #20817 using these APIs:
```rust
fn components_for_observers(
access: &FilteredAccess,
) -> (&ComponentIdSet, ComponentIdSet, ComponentIdSet) {
// We need `insert` observers for any component we read,
// since the value has changed.
// Unbounded access (`EntityRef`) is not supported,
// since we cannot add observers to all possible components.
let insert = access
.access()
.try_reads_and_writes()
.expect("Query observers do not support unbounded access");
// We need `add` observers for any component with archetypal access,
// since `Has` may have changed,
let mut add = access.access().archetypal().clone();
// and any component with `With` filters,
// since the query may start matching,
for filter_set in access.filter_sets() {
add.union_with(&filter_set.with());
}
// but not for any component already covered by `insert` observers
add.difference_with(insert);
// We need `remove` observers for any component we read or write,
// since `Option<&T>` may have changed,
let mut remove = insert.clone();
// and for any component with archetypal access,
// since `Has` may have changed,
remove.union_with(access.access().archetypal());
// and any component with `Without` filters,
// since the query may start matching,
for filter_set in access.filter_sets() {
add.union_with(&filter_set.without());
}
// but not for any required component,
// since it is guaranteed not to match after they are removed
// (otherwise every `&T` would add a `remove` observer!)
remove.difference_with(access.required());
(insert, add, remove)
}
```
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- Audio wants a realtime-safe executor with minimal checking. This means
no command application or multithreading etc.
## Solution
- Make it possible to supply our own executor.
## Testing
- Tests are updated
- New custom executor example
Note: reviewing commits individually is probably easier.
# Objective
- Previously, you needed to insert the type registry into the scene
you're serializing, which results in weird behavior since some users are
extracting the resources out of the scene (which would include the type
registry).
## Solution
- Make the scene APIs explicitly take a type registry so that users are
less likely to get it wrong, and no longer need to insert the registry
into the world/scene being serialized.
## Testing
- Updated tests. Tests pass
- The scene example still works.
# Objective
- Fixes#23071
- Also allow state scoped messages to clear on same state transitions if
desired.
## Solution
- Add a `&& !transition.allow_same_state_transitions` check whenever the
`entered` state and `exited` state are compared. The
`allow_same_state_transitions` property is available from
`StateTransitionEvent`. This extra comparison is already being used for
`OnEnter` and `OnExit`.
## Testing
- Added a unit test to see that DespawnOnExit runs during same state
transitions if desired, since the logic is basically the same for all
three Despawn* Components.
- Ran the `state_scoped` example and everything looks ok
# Objective
- Fixes#22641
## Solution
- Changes `ViewportNode.camera` to an `Option<Entity>`. Update this
field to None if the camera is not found in `viewport_picking` and, more
importantly, `update_viewport_render_target_size`. I did not put this
same logic in `extract_viewport_nodes` because I wasn’t sure whether to
add a `mut` to the query / if that affects performance or something (but
if I should, let me know)
## Testing
- `cargo run --example viewport_node` still works
# Objective
Improve the legibility of the text internals by replacing the `(u32,
FontSmoothing)` tuple with a struct with named fields.
## Solution
New struct `TextBrush` with named fields `section_index` and
`font_smoothing`.
---------
Co-authored-by: François Mockers <francois.mockers@vleue.com>
# Objective
`RelationshipAccessor` was previously missing the value of
`Relationship::ALLOW_SELF_REFERENTIAL` and `ComponentId`s of the
counterpart components.
## Solution
- Add `allow_self_referential` fields to both
`RelationshipAccessor::Relationship` and
`RelationshipAccessor::RelationshipTarget`.
- Add `relationship_target` to `RelationshipAccessor::Relationship` and
`relationship` to `RelationshipAccessor::RelationshipTarget` which store
`ComponentId`s of the counterpart.
- Replace `RelationshipAccessor` with `RelationshipAcessorInitializer`
in `ComponentDescriptior::new_with_layout` to ~add more
`AbstractBuilderFactoryBuilder` vibes~ allow dynamic components to set
`ComponentId` of the counterpart component.
Note that this PR requires components to be actually initialized inside
`Components` and makes `ComponentInfo::relationship_accessor` return
`None` if relationship components are only queued for registration.
## Testing
Added a new test for all the fields
# Objective
- Fixes#19372
- `System::type_id` is confusingly named because it shadows the standard
`Any::type_id` method and returns a different value (the wrapped
system's type, not the wrapper's type). This has caused confusion and
bugs.
## Solution
- Renamed `System::type_id` to `System::system_type` to clearly
distinguish it from `Any::type_id` and align with the existing
`SystemSet::system_type` naming convention.
- Added a deprecated `type_id` shim that forwards to `system_type`, so
existing call sites get a compiler warning instead of silently resolving
to `Any::type_id`.
- Updated all internal call sites and tests to use `system_type`.
## Migration Guide
See `release-content/migration-guides/rename_system_type_id.md`.
## Testing
- All existing tests pass with the rename, including the `type_id`
consistency tests in `exclusive_function_system` and `function_system`
(updated to use `system_type`).
# Objective
- Fixes#22947
- Prep for impending RC (soon)
## Solution
- Removed remaining mentions to the best of my ability, replacing it
with Parley where it felt appropriate.
- I figured the migration guides should be updated too, since users
would be migrating to a version where Cosmic has already been replaced,
so no need to give them outdated information.
---------
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
# Objective
As raised in
[#23174](https://github.com/bevyengine/bevy/pull/23174#discussion_r2868030355_),
we currently duplicate working when looking up our system parameters:
once during validation, and then again when actually fetching the data.
This is (maybe) slow, and would worsen the performance regression
incurred by resources-as-components (#19731).
This strategy also imposes some non-trivial complexity and
maintainability costs. Because "validate" is a distinct step from "use",
it's possible to skip validation! As far as I could tell, this is the
case in a number of places before this PR: particularly in the
unconventional "please just run my system" path. While in most cases
this will simply result in a crash in a different place, it causes these
paths to not handle
Fixes#23179. Fixes#15505.
## Solution
Fundamentally, what we're doing is rolling the
`SystemParam::validate_param` behavior into `SystemParam::get_param`, by
making the latter return a `Result`.
However, there is a tremendous amount of splash damage required to get
that to actually compile and expose the correct semantics. The most
important of these are:
- `SystemState::get` and friends now returns a `Result`
- this leads to a fair bit of assorted unwrap spam in our tests and
weird internal usages
- these tests can probably be refactored to not use `SystemState`
directly in the future now that we have better tools like
`run_system_once`, but eh, not this PR's job
- this is semantically correct, as these params could fail validation
- `System::validate_param_unsafe` has been removed, and validation now
occurs inside of `System::run_unsafe`
- very much a net positive for both abstract robustness and current
correctness
- this impacts the strategy that various executors use: see the next
section
There are a *lot* of moving parts here: I'm sorry that I couldn't get
this into a smaller, more incremental refactor. When reviewing this PR,
you should begin with the migration guide to help get you oriented on
the details: `validation_merging.md`.
From there, the most important files to review are:
1. `system_param.rs`: trait changes and implementers
2. `function_system.rs`: primary implementer of `System`
3. `multithreaded.rs`: the parallel executor
**NOTE TO REVIEWERS:** Please make comments to generate threads; this PR
review might get fairly hairy.
### Performance discussion
For the parallel `MultithreadedExecutor`, validation was previously done
as a cheap pre-validation step,
while checking run conditions.
Now, tasks will be spawned for systems which would fail or are skipped
during validation.
In most cases, avoiding the extra overhead of looking up the required
data twice should dominate.
However, this change may negatively affect systems which are frequently
skipped (e.g. due to `Single`).
### Paths not taken
In this PR, I've decided not to:
- Add another variant
[RunSystemError](https://docs.rs/bevy/latest/bevy/ecs/system/enum.RunSystemError.html),
distinguishing "validation failed" from "system ran but returned an
error".
- While reusing
[RunSystemError::Failed](https://docs.rs/bevy/latest/bevy/ecs/system/enum.RunSystemError.html#variant.Failed)
for both cases is messy, this PR is already a bit of a nightmare to
review.
- Return a result from `ParamSet::get_mut`.
- Instead, we just `unwrap`.
- Bubbling up the `Result` is technically more correct, but these were
already panicking before if e.g. a resource is missing, and `ParamSet`
is already an ergonomic abomination.
## Testing
I've added a number of new tests to exercise the system param validation
paths, ensuring that validation is done when systems are run.
However, I would appreciate some help benchmarking the net impact on
realistic-ish scenes. `breakout`, `bevy_city` and `many_animated_foxes`
are probably a decent scattering, but I'd be very open to other
suggestions.
Having done this refactor, I think that it's a net improvement for
robustness and clarity even without the perf benefits however, and that
we should proceed unless this is a clear regression.
---------
Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
# Objective
Follow-up to #21557
Support streaming iteration (a.k.a. lending iteration) for `QueryIter`
and `QuerySortedIter` so that it's possible to iterate
`Query<Parent<&mut T>>`.
Double-check that all the `IterQueryData` bounds are correct and that
the safety comments are correct. A few were not!
## Solution
Offer a `fetch_next` method on `QueryIter` and `QuerySortedIter` that
borrows the entire iterator to prevent aliasing, similar to
`QueryManyIter::QueryManyIter`.
Offer a `Query::iter_inner` method to produce `QueryIter` even when it
is not an `Iterator`. We cannot rely on `IntoIterator` in that case, and
Clippy objects to an inherent method called `into_iter()` that is not
the standard trait method. This supersedes the existing `iter_inner`
method that only worked on `ReadOnlyQueryData`.
Add a missing `IterQueryData` bound to `iter_combinations_mut`. It
yields multiple entities concurrently, so is never sound to use with
non-`IterQueryData`. I think the reason I missed this originally is that
it already has a `fetch_next` method and conditional `Iterator` impl.
But even `fetch_next` yields multiple entities at once for
`QueryCombinationIter`!
Add a `ContiguousQueryData: IterQueryData` supertrait bound.
`QueryContiguousIter` also yields multiple entities concurrently, so it
does not make sense on non-iterable data. This was not actually unsound,
though, as `QueryContiguousIter` does not call `fetch`.
Finally, update some missing or incorrect safety comments.
### Verify bounds on the other iterator types
To verify I didn't miss any bounds on iterator types, here is a list of
every `Query*Iter` type, and whether they support non-`IterQueryData`:
| Type | Supports non-`Iter`? |
| --- | --- |
|`CombinationIter`|No, added missing bound|
|`ContiguousIter`|No, added missing bound|
|`Iter`|Yes, added support|
|`ManyIter`|Yes, existing support|
|`ManyUniqueIter`|No, and existing bound*|
|`ParIter`|No, and existing bound|
|`ParManyIter`|No, and existing bound|
|`ParManyUniqueIter`|No, and existing bound|
|`SortedIter`|Yes, added support|
|`SortedManyIter`|Yes, existing support|
`Iter` and `SortedIter` were changed in this PR to support streaming
iteration for all `QueryData`, while only implementing `Iterator` for
`IterQueryData`.
`ManyIter` and `SortedManyIter` already had streaming iteration, and
only implement `Iterator` with a stricter `ReadOnlyQueryData` bound,
since they may yield the same entity multiple times.
`ManyUniqueIter` could theoretically be used with non-`IterQueryData`...
but if you need to do streaming iteration anyway then you can call
`iter_many_mut()` instead of `iter_many_unique_mut()`.
`CombinationIter`, `ContiguousIter`, and the `Par*Iter` types are all
fundamentally about accessing multiple entities concurrently, and should
always require `IterQueryData`. `CombinationIter` and `ContiguousIter`
did not have `IterQueryData` bounds, so fix that!
## Showcase
This is cheating a bit because we don't yet have `Parent<&mut T>`, but
once we do it would look like:
```rust
fn system(query: Query<Parent<&mut Component>>) {
let mut iter = query.iter_mut();
while let Some(mut parent_component) = iter.fetch_next() {
// Use `parent_component` here
}
}
```
# Objective
- Allow users to save images.
- Make a "simple" example of asset saving (as opposed to the existing
complex example).
## Solution
- Pass in the asset path to `AssetSaver`s.
- Make `get_full_extension` return a `&str` instead of an owned
`String`.
- Created a new `ImageSaver` that currently only supports PNG.
- We can extend this in the future if we want more support. It's not
super straightforward since e.g., JPEG doesn't support alpha and wgpu
TextureFormat doesn't have a regular RGB8 format.
- Renamed the old `asset_saving` example to
`asset_saving_with_subassets`.
- Created a new `asset_saving` example which allows drawing an image and
then saving it.
## Testing
- The new example works!
# Objective
- Fixes#23192 by removing the threshold from the associated functions
## Solution
- We are removing the threshold all together, so the optimization is
either enabled or disabled now.
## Migration guide
- Don't rely on from_threshold calls, either have the optimizations
enabled or disabled.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
# Objective
There's a lot of code duplication in `access.rs`. The same logic is
duplicated between components and resources. This also takes up
unnecessary memory in `Access`, as it relies on bitsets spanning the
entire `ComponentId` range.
## Solution
Since resources are now a special kind of component, this can be
removed.
## Limitations
Since `!Send` data queries used `Access` resources, `!Send` data queries
now conflict with broad queries.
```rust
// 0.18
fn system(q1_: Query<EntityMut>, q2_: NonSend<R>) {} // valid, does not conflict
// 0.19
fn system(q1_: Query<EntityMut>, q2_: NonSend<R>) {} // invalid, does conflict
```
Given how rarely non-send data is used, I recommend using
```
// 0.19
fn system(q1_: Query<EntityMut, Without<R>>, q2_: NonSend<R>) {} // works again
```
If this is also unacceptable, this PR is blocked on the `!Send` data
removal from the ECS (or some hacky workaround).
## Extra Attention
@chescock brought `AssetChanged` to my attention. It has a weird access
pattern. See the following example:
```rust
fn system(c: Query<&mut AssetChanges<Mesh>>, r: Query<(), AssetChanged<Mesh>>) {}
```
System `c` registers access with `add_write` for `AssetChanges<Mesh>`,
while `r` registers access with `add_read` for both `Mesh` and
`AssetChanges<Mesh>`. This system is invalid, and I've added a test to
reflect that. However, since this stuff is tricky, I would like some
extra eyes on it. Currently, it looks *fine*.
# Objective
- bevy_seedling is incompatible with `bevy_audio`
- all our profile features (`3d`, `2d`, `ui`) enable the `audio`
collection feature
- That means that a seedling user needs to do this to land at the
current `default`:
```toml
[dependencies]
bevy = { version = "0.18.0", default-features = false, features = [
# 2d
"2d_bevy_render",
"default_app",
"picking",
"scene",
# 3d
"3d_bevy_render",
# ui
"ui_api",
"ui_bevy_render",
# default_platform
"android-game-activity",
"bevy_gilrs",
"bevy_winit",
"default_font",
"multi_threaded",
"std",
"sysinfo_plugin",
"wayland",
"webgl2",
"x11",
] }
```
## Solution
- Disable the `audio` collection features for all profile features and
instead enable it by default
- The new seedling config now looks like this:
```toml
[dependencies]
bevy = { version = "0.18.0", default-features = false, features = [
"2d",
"3d",
"ui",
] }
```
## Testing
- None, CI should take care of this
# Objective
- #22443 broke wireframe and some examples
## Solution
- Fix them by having the systems run after `MeshPipelineSet`
- Also add a migration guide
## Testing
- run the examples modified or anything using wireframe
# Objective
- Allow users to specify a custom output directory for screen recordings
in `EasyScreenRecordPlugin`.
- Currently, recordings are always saved to the current working
directory with no way to configure the path.
## Solution
- Add an `output_dir: Option<PathBuf>` field to
`EasyScreenRecordPlugin`.
- When `None` (the default), recordings are saved in the current working
directory, preserving existing behavior.
- When `Some(path)`, recordings are saved in the specified directory.
The directory is created automatically if it does not exist.
- Update `RecordCommand::Start` to use `PathBuf` instead of `String`.
## Testing
- Verified compilation with `cargo check -p bevy_dev_tools --features
screenrecording`.
---
## Showcase
```rust
// Default: records to current working directory
app.add_plugins(EasyScreenRecordPlugin::default());
// Custom output directory
app.add_plugins(EasyScreenRecordPlugin {
output_dir: Some("recordings".into()),
..default()
});
```
Fixes#16437
it was as simple as @ulmer-a suggested
I also adapted the documentation
i havent manually tested if these axis arent switched, but from reading
the code it should be fine
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Extracting meshes to the render world is done in two phases: first, Bevy
does *extraction*, which pulls information from the main world ECS to
thread-local buffers in the render world; second, Bevy does
*collection*, which processes those buffers in parallel to update the
GPU buffers and other information. Unfortunately, the
`RenderMeshInstances` buffer that contains information that the CPU and
GPU need to know to draw the meshes properly currently isn't
thread-safe. Therefore, the parallel worker threads send completed data
through a channel to a single consumer thread, which updates the
`RenderMeshInstances` tables. This is a sequential bottleneck on large
scenes (especially since `RenderMeshInstance` is bigger than it ought to
be).
This PR tackles the problem directly by making `RenderMeshInstances`
partially thread-safe and allowing the worker threads to update mesh
instance data directly, via shared memory. Note the use of "partially":
the `RenderMeshInstances` buffer can still only grow to accommodate
*new* meshes on a single thread with this patch. However, *existing*
meshes can, with one exception (changing render layers), can be updated
directly.
The thread safety is accomplished via a new trait, `AtomicPod`, and a
new buffer type, `AtomicBufferVec`. `AtomicPod` is a trait that
describes a type that can be bitcast onto an array of `AtomicU32`s,
known as the *blob* type. With only a single exception, this is
implemented entirely in safe code, via `bytemuck`. This patch introduces
a new helper macro, `impl_atomic_pod!`, that automates the
implementation of `AtomicPod` types and provides accessors and mutators
so that the blob type feels like the original POD type as much as
possible. The single use of unsafe code is to upload the blob of
`AtomicU32`s to the GPU, as no safe method can currently cast an
`AtomicU32` array to a `u8` array to pass to `write_buffer`. The actual
*conversion* between the POD type and the blob type is entirely safe
code that's automatically generated.
Note that on x86-64 and AArch64, a relaxed load and store to an
`AtomicU32` location produces the exact same machine code as a regular
load and store to a memory location.
The downside of this PR, besides the minor inconvenience of accessing
`RenderMeshInstances` through helper methods, is that *new* mesh
instances can't be added to the `RenderMeshInstances` table while the
workers are running anymore, only afterward. This could regress the
performance in cases in which many new objects are queued. I believe
this is an easily worthwhile tradeoff. However, we could improve the
situation via heuristics (e.g. detecting the number of meshes that
became visible all at once) in the future if we wanted to.
On `bevy_city`, this PR increases the performance of
`collect_meshes_for_gpu_building` from 7.74 ms to 4.03 ms, a 1.92x
speedup. Most importantly, the sequential part of
`collect_meshes_for_gpu_building` is entirely eliminated.
Performance of a `bevy_city` frame with #22966 applied:
<img width="2756" height="1800" alt="Screenshot 2026-02-16 202420"
src="https://github.com/user-attachments/assets/a61b19c8-df98-4d8d-8cfc-4647ccf9990f"
/>
Notice the sequential mesh collection bottleneck.
Before this PR and after:
<img width="2756" height="1800" alt="Screenshot 2026-02-16 195459"
src="https://github.com/user-attachments/assets/91595254-3506-4e6e-9fb8-af1827b3c970"
/>
---------
Co-authored-by: charlotte <charlotte.c.mcelwain@gmail.com>
# Objective
Support queries that soundly access multiple entities.
This can be used to create queries that follow relations, as in #17647.
This can also be used to create queries that perform resource access.
This has been supported since #16843, although that approach may become
unsound if we do resources-as-components #19731, such as #21346.
Fixes#20315
## Solution
Allow a `QueryData` that wants to access other entities to store a
`QueryState<D, F>` in its `WorldQuery::State`, so that it can create a
nested `Query<D, F>` during the outer `fetch`.
### `NestedQuery` type
Introduce a `NestedQuery` type that implements `QueryData` by yielding a
`Query`. It is intended to be used inside other implementations of
`QueryData`, either for manual implementations or
`#[derive(QueryData)]`. It is not normally useful to query directly,
since it's equivalent to adding another `Query` parameter to a system.
In theory, we could directly `impl QueryData for Query`, but this would
be too easy to do accidentally. Having to explicitly import and write
`NestedQuery` will make it clear that it's something unusual, and also
allows us to remove the need for passing `'static` for the `'w` and `'s`
lifetimes.
### New `WorldQuery` methods
For it to be sound to create the `Query` during `fetch`, we need to
register the `FilteredAccess` of the nested query and check for
conflicts with other parameters. Create a
`WorldQuery::update_external_component_access` method for that purpose.
For `Query as SystemParam`, call this during `init_access` so the access
can be combined with the rest of the system access. For loose
`QueryState`s, call it during `QueryState::new`.
In order to keep the query cache up-to-date, create a
`WorldQuery::update_archetypes` method where it can call
`QueryState::update_archetypes_unsafe_world_cell`, and call it *from*
there.
### New `QueryData` subtraits
Some operations would not be sound with nested queries! In particular,
we want a `Parent<D>` query that reads data from the parent entity by
following the `ChildOf` relation. But many entities may share a parent,
so it's not sound to iterate a `Query<Parent<&mut C>>`.
It *is* sound to `get_mut`, though, so we want the query type to
*exist*, just not be iterable. And following the relation in the other
direction for a `Query<Children<&mut C>>` is sound to iterate, since
children are unique to a given parent.
So, introduce two new `QueryData` subtraits:
* `IterQueryData` - For anything it's sound to iterate. This is used to
bound `iter_mut` and related methods.
* `SingleEntityQueryData` - For anything that only accesses data from
one entity. This is used to bound `EntityRef::get_components` (see
#20315). It's also used to bound `transmute` at the moment, although we
may be able to relax that later (see below, under Future Work).
Note that `SingleEntityQueryData: IterQueryData`, since single-entity
queries never alias data across entities, and `ReadOnlyQueryData:
IterQueryData`, since it's always sound to alias read-only data.
Here is a summary of the traits implemented by some representative
`QueryData`:
| Data | Iter | ReadOnly | SingleEntity |
| -- | -- | -- | -- |
| `&T` | ✓ | ✓ | ✓ |
| `&mut T` | ✓ | x | ✓ |
| `Parent<&T>` | ✓ | ✓ | x |
| `Parent<&mut T>` | x | x | x |
| `(&mut T, Parent<&U>)` | ✓ | x | x |
| `Children<&mut T>` | ✓ | x | x |
## Alternatives
We could avoid the need for the `IterQueryData` trait by making it a
requirement for *all* `QueryData`. That would reduce the number of
traits required, at the cost of making it impossible to support
`Query<Parent<&mut C>>`.
## Showcase
Here is an implementation of a `Related<R, D, F>` query using this PR:
<details>
```rust
pub struct Related<R: Relationship, D: QueryData + 'static, F: QueryFilter + 'static = ()>(
RelatedInner<R, D, F>,
);
type RelatedInner<R, D, F> = (
&'static R,
NestedQuery<D, (F, With<<R as Relationship>::RelationshipTarget>)>,
);
unsafe impl<R: Relationship, D: QueryData + 'static, F: QueryFilter + 'static> WorldQuery
for Related<R, D, F>
{
type Fetch<'w> = <RelatedInner<R, D, F> as WorldQuery>::Fetch<'w>;
type State = <RelatedInner<R, D, F> as WorldQuery>::State;
fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
<RelatedInner<R, D, F> as WorldQuery>::shrink_fetch(fetch)
}
unsafe fn init_fetch<'w, 's>(
world: UnsafeWorldCell<'w>,
state: &'s Self::State,
last_run: Tick,
this_run: Tick,
) -> Self::Fetch<'w> {
unsafe {
<RelatedInner<R, D, F> as WorldQuery>::init_fetch(world, state, last_run, this_run)
}
}
const IS_DENSE: bool = <RelatedInner<R, D, F> as WorldQuery>::IS_DENSE;
unsafe fn set_archetype<'w, 's>(
fetch: &mut Self::Fetch<'w>,
state: &'s Self::State,
archetype: &'w Archetype,
table: &'w Table,
) {
unsafe {
<RelatedInner<R, D, F> as WorldQuery>::set_archetype(fetch, state, archetype, table)
};
}
unsafe fn set_table<'w, 's>(
fetch: &mut Self::Fetch<'w>,
state: &'s Self::State,
table: &'w Table,
) {
unsafe { <RelatedInner<R, D, F> as WorldQuery>::set_table(fetch, state, table) };
}
fn update_component_access(state: &Self::State, access: &mut FilteredAccess) {
<RelatedInner<R, D, F> as WorldQuery>::update_component_access(state, access);
}
fn init_nested_access(
state: &Self::State,
system_name: Option<&str>,
component_access_set: &mut FilteredAccessSet,
world: UnsafeWorldCell,
) {
<RelatedInner<R, D, F> as WorldQuery>::init_nested_access(state, system_name, component_access_set, world);
}
fn init_state(world: &mut World) -> Self::State {
<RelatedInner<R, D, F> as WorldQuery>::init_state(world)
}
fn get_state(components: &Components) -> Option<Self::State> {
<RelatedInner<R, D, F> as WorldQuery>::get_state(components)
}
fn matches_component_set(
state: &Self::State,
set_contains_id: &impl Fn(ComponentId) -> bool,
) -> bool {
<RelatedInner<R, D, F> as WorldQuery>::matches_component_set(state, set_contains_id)
}
fn update_archetypes(state: &mut Self::State, world: UnsafeWorldCell) {
<RelatedInner<R, D, F> as WorldQuery>::update_archetypes(state, world);
}
}
unsafe impl<R: Relationship, D: QueryData + 'static, F: QueryFilter + 'static> QueryData
for Related<R, D, F>
{
const IS_READ_ONLY: bool = D::IS_READ_ONLY;
type ReadOnly = Related<R, D::ReadOnly, F>;
type Item<'w, 's> = Option<D::Item<'w, 's>>;
fn shrink<'wlong: 'wshort, 'wshort, 's>(
item: Self::Item<'wlong, 's>,
) -> Self::Item<'wshort, 's> {
item.map(D::shrink)
}
unsafe fn fetch<'w, 's>(
state: &'s Self::State,
fetch: &mut Self::Fetch<'w>,
entity: Entity,
table_row: TableRow,
) -> Self::Item<'w, 's> {
let (relationship, query) =
unsafe { <RelatedInner<R, D, F> as QueryData>::fetch(state, fetch, entity, table_row) };
query.get_inner(relationship.get()).ok()
}
}
unsafe impl<R: Relationship, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> ReadOnlyQueryData for Related<R, D, F> { }
// Note that we require `D: ReadOnlyQueryData` for `Related: IterQueryData`
unsafe impl<R: Relationship, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> IterQueryData for Related<R, D, F> { }
```
</details>
I'd like to leave that to a follow-up PR to allow bikeshedding the API,
and to take advantage of #21581 to remove the `Option`, but I think it
works!
## Future Work
There is more to do here, but this PR is already pretty big. Future work
includes:
* #17647
* Following #21346, update `AssetChanged` to use nested queries for
resource access, and stop tracking resource access separately in
`Access`
* Implement `get_state` for `NestedQuery`. This is difficult because
constructing a `QueryState` requires reading the `DefaultQueryFilters`
resource, but `get_state` can be called from `transmute` with no access.
* Relax the `SingleEntityQueryData` bound on transmutes and joins. This
will require checking that the nested query access is also a subset of
the original access. Although unless we also solve the problem of
implementing `get_state`, transmuting to a query with nested queries
won't work anyway.
* Support streaming iteration for `QueryIter` by offering a `fn
fetch_next(&self) -> D::Item<'_>` method and relaxing the
`IterQueryData` bound on `Query::into_iter` and `Query::iter_mut`. This
would work similar to `iter_many_mut` and `iter_many_inner`.
* Relax the `IterQueryData` bound on `Query::single_inner`,
`Query::single_mut`, and `Single<D, F>`. This seems like it should be
straightforward, because the method only returns a single item. But the
way it checks that there is only one item is by fetching the second one!
# Objective
- #22949 had breaking changes but no migration guide
## Solution
- add a migration guide
## Testing
- gee i sure hope this doesnt break anything
# Objective
- `bevy_pbr` no longer strictly requires `bevy_gltf`
## Solution
- Make `bevy_gltf` an optional dependency, and feature gate the usage
## Testing
- `cargo run --example animated_mesh` compiles `bevy_gltf` and displays
the fox and grass
- `cargo run --example 3d_shapes --no-default-features --features
default_app,default_platform,3d_api,bevy_pbr,bevy_ui` compiles without
`bevy_gltf` or `gltf`
Right now, every frame, all specialization and queuing systems iterate
over all entities visible from a view and check to see whether they need
to be updated by consulting a set of change ticks and comparing them to
the current change ticks. To handle cases in which a mesh needs to be
removed from the bins, a separate final *sweep* pass then finds entities
that no longer exist and removes them manually from the bins. This
process is complex, error-prone, and slow, as it involves visiting all
visible entities multiple times every frame.
This PR changes the setup so that, instead of examining change ticks,
the visibility logic pushes the set of added and removed entities to
each view explicitly. The visibility system determines which meshes need
to be added and removed by first sorting the list of visible entities,
then performing an O(n) diff process on the last frame's visible
entities and this frame's visible entity list. The end result is that
the specialization and queuing systems only process the entities that
they need to every frame. If a mesh was visible last frame, remained
visible this frame, and didn't change its mesh or material, then it's
generally not examined at all. Not only is this significantly faster for
virtually all realistic scenes, but it's also much simpler.
In order to achieve the benefits of not examining every visible mesh
every frame, I made sorted render passes retained via an `IndexMap`.
This allows entities to be removed and added via random access while
still allowing the list to be sorted by distance. Note that I had to
remove the radix sort because `IndexMap` doesn't currently support that;
I believe the enormous speed benefits of this patch outweigh any minor
sorting regressions from this.
I tested this PR by running `scene_viewer` on a test scene with many
meshes and materials and implementing a material shuffler that randomly
switches the materials around. I tested the following cases:
* Moving the camera so that meshes become visible and invisible.
* Switching opaque materials on meshes.
* Moving meshes from opaque to alpha masked and vice versa.
* Moving meshes from binned render passes to sorted render passes (i.e.
transparent).
* All of the above while the meshes were off screen, then moving them on
screen to ensure that the changes took effect.
This PR brings the `specialize_shadows` time on the `bevy_city` demo
from 12.87 ms per frame to 0.1261 ms per frame, a 102x speedup. It
brings the `queue_shadows` time on the same demo from 12.34 ms per frame
to 0.1102 ms, a 111x speedup. Mean frame time goes from 50.16 ms to
23.26 ms, a 2.16x speedup.
`specialize_shadows` in `bevy_city` before and after:
<img width="2756" height="1800" alt="Screenshot 2026-02-14 180313"
src="https://github.com/user-attachments/assets/dbc3c68b-e0ec-424f-8085-87c0f5f41d3f"
/>
`queue_shadows` in `bevy_city` before and after:
<img width="2756" height="1800" alt="Screenshot 2026-02-14 180500"
src="https://github.com/user-attachments/assets/08f8e1bb-6ab4-47da-ae68-a80156d59caa"
/>
Frame graph of `bevy_city` before:
<img width="2756" height="1800" alt="Screenshot 2026-02-12 203324"
src="https://github.com/user-attachments/assets/d0807cee-23a2-4e14-be1a-7466b795ebfa"
/>
Frame graph of `bevy_city` after:
<img width="2756" height="1800" alt="Screenshot 2026-02-14 180506"
src="https://github.com/user-attachments/assets/b22acf0f-a6f9-432b-93d7-f8057c815b05"
/>
# Objective
- `glam`, `hexasphere` & `rand` have released their latest versions,
update Bevy to support them.
## Solution
- The above have been updated to their compatible versions. `rand_distr`
updated as well to match `rand` v0.10 support.
- `rand_chacha` is soft deprecated and no longer used by `rand`, so its
usage has been changed to `chacha20` to match `rand` dep tree.
- `uuid` is in the process of updating to `getrandom` v0.4, which `rand`
v0.10 supports. This PR remains in draft until a new `uuid` release hits
crates.io.
- `RngCore` is now `Rng`, and `Rng` is now `RngExt`, so this required
updating across many files.
- `choose_multiple` method is deprecated, changed to `sample`.
## Testing
- Chase all compiler errors, since this should not regress any already
existing behaviour.
- This must pass CI without regressions.
## Additional Notes
`getrandom` v0.4 doesn't add anything new for Web WASM support, so the
same `wasm_js` feature is used.
# Objective
`bevy_ui_widgets is still incomplete and unstable, but the utility of
the `experimental` designation is questionable:
1. Running examples with required non-default features suck. This is
frustrating for UI examples, and hampers adoption in our other examples
even when real UI-based controls would be more elegant.
2. These widgets have proven useful to end users in practice, even in
0.19.
3. These widgets have seen a number of small bug fixes and improvements
since their initial release.
4. It's not clear that this label is effective for slowing adoption, or
if slowing adoption is currently desirable. Users don't have a ton of
other great options: writing their own widgets will waste work *and*
still need to be rewritten with BSN.
5. Bevy as a whole is still quite experimental. Unlike e.g. ghost nodes,
there's no indication that we are considering wholly reverting these
features.
## Solution
Amended based on review feedback:
> The `experimental_ui_widgets` feature have been renamed to
`ui_widgets`.
>
> The `ui_widgets` feature has been added to the `ui` feature collection
(and thus `bevy`'s default features) for ease of use.
Previous solution, from the original migration guide:
> The `experimental_ui_widgets` and `experimental_bevy_feathers`
features have been renamed to `ui_widgets` and `bevy_feathers`
respectively.
>
> The `ui_widgets` feature has been added to the `ui` feature collection
(and thus `bevy`'s default features) for ease of use.
> The `bevy_feathers` feature remains off by default: it is primarily
intended for use in dev tools, and should typically not be included in
shipped end-user applications. As a result, it needs to be easy to
enable and disable conditionally. This would be very challenging if it
were a default feature or in a popular feature collection.
>
> These crates remain immature, and subject to heavy breaking changes,
even relative to Bevy's pre-1.0 standards.
> However, they are useful enough to see wider adoption, and this
changes substantially improves the user experience when setting up new
projects and running Bevy examples.
---------
Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
# Objective
Improve the `FontAtlas` implementation. Should help simplify the assets
as entities (#22939) text changes, as well mitigate some of the
performance regressions due to the parley migration (#22879).
* `FontAtlas` has a handle to a `TextureAtlasLayout` asset, but it would
be less complicated and more efficient for it to just hold the layout
itself directly.
* `PositionedGlyph`'s `size` field isn't used for anything. The size can
be gotten from the atlas rect. The doc comment is wrong as well: it's in
physical pixels, not logical.
* `GlyphAtlasInfo` can just store the atlas rect directly, replacing the
atlas layout handle and index.
* The offset and rect values should use f32s not i32s, they aren't ever
used except after conversion.
* `GlyphAtlasInfo::offset` should be stored with the correct
orientation, instead of negating its y axis each time.
## Solution
* Font atlas layouts are now stored in `FontAtlas` directly, not as
assets.
* Removed `PositionedGlyph`'s `size` field.
* `GlyphAtlasInfo`'s `texture_atlas` and `location` fields have been
removed, replaced with `rect` and `offset` fields.
* `get_outlined_glyph_texture` returns a `Vec2` instead of an `IVec2`
with the y value negated.
---------
Co-authored-by: Rob Parrett <robparrett@gmail.com>
Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
# Objective
We currently describe the new `gltf_render_enabled` flag as "disabling
PBR rendering", which is much broader than what it does in practice. In
its current form it controls the construction and insertion of
`StandardMaterial`s on entities, but does not affect the PBR rendering
functionality of the application, or of glTF assets. (A user could still
create their own `StandardMaterial`s or `StandardMaterial` extensions
and insert them on the required meshes).
## Solution
Rename the flag to more accurately depict what it does in practice,
which is enable/disable the automatic construction and insertion of
`StandardMaterial`s when a glTF file is loading.
## Testing
There's only one example that turns this off, `gltf_extension_mesh_2d`,
which continues to run as expected.
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- #22933 removed the `bevy_picking` feature because it had the same
description as `picking` yet a different purpose. I believe this
different purpose is worth preserving and the fix is to document them
more adequately instead. The rest of the PR was good, i agree with
making it not enable `bevy_input_focus` when its enabled. Furthermore, I
would be in favor of a `picking_input_focus` feature.
## Solution
- Restore `bevy_picking` feature
- Adjust docs
## Testing
- ci
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
The asset server doesn't handle paths with multiple `#` in them well,
which leads to users trying to load the new-style standard material
(post `GltfMaterial`/pbr inversion) like this:
```rust
let handle: Handle<StandardMaterial> =
asset_server.load("models/animated/Fox.glb#Material0#std");
```
and failing with
> 2026-02-13T18:39:46.765922Z ERROR bevy_asset::server: Could not find
an asset loader matching: Loader Name: None; Asset Type:
Some(TypeId(0x84f48d0a22ca9da8cd205decd68dcefa)); Extension: None; Path:
Some("models/animated/Fox.glb#Material0#std");
## Solution
On recommendation from @andriyDev , switching to use slashes fixes the
pathing issue.
```rust
let handle: Handle<StandardMaterial> =
asset_server.load("models/animated/Fox.glb#Material0/std");
```
## Testing
Used the gltf animated fox example to load a material as indicated
above, and apply it to a 100x100x100 cube:
<img width="2650" height="2096" alt="screenshot-2026-02-13-at-10 42
22@2x"
src="https://github.com/user-attachments/assets/cd977e4a-6f4d-4c6a-aeb7-561a7443bcf4"
/>
---
The migration guide uses paths since so are the source of truth for the
asset server, and there is currently no `GltfAssetLabel` for the new
standard material handling. (This should be fixed also in a different
PR).
# Objective
The feature flags "bevy_picking" and "picking" have the same description
despite fulfilling different goals. This is very confusing!
Fixes#22931.
The status quo before this PR.
> - picking is a feature collection in bevy, which enables
["bevy_picking", "mesh_picking", "sprite_picking", "ui_picking"].
> - the ui feature collection enables picking itself
> - bevy_picking is defined in bevy, which defers to
["bevy_internal/bevy_picking"]
> - in bevy_internal, this toggles bevy_picking = ["dep:bevy_picking",
"bevy_input_focus?/bevy_picking"]
> - this then toggles the bevy_picking dependency (apparently that works
as if it were a feature?) in bevy_input_focus
> - which is ultimately used to enable mouse / virtual cursor based
input focus selection
> - @viridia is concerned about making this mandatory because of worries
about observer overhead
## Solution
Condense bevy_picking at the bevy_internal level into bevy_ui_picking.
There's no way someone wants general UI picking but not input focus
picking. This fixes the redundancy, and groups functionality more
reasonably, while still making it possible to avoid UI picking as a
whole off if you're concerned for whatever reason.
Users who want even more granularity than that can of course compose the
various Bevy crates however they please.
## Alternative
1. Keep this feature around, renaming it to `input_focus_picking`.
2. Enable that feature inside of `ui_picking`.
This adds another niche feature flag at the top level, but makes it
easier for users who want to use `bevy_input_focus` without `bevy_ui`. I
have never met such a user, but maybe they exist!
# Objective
Since #20934, `World::clear_all` and `World::clear_all_entities` behave
identically. `World::clear_all` used to clear all resources and
entities, but since resources are now components,
`World::clear_all_entities` also does this.
## Solution
Since `World::clear_all_non_send()` was not included in
`World::clear_all`, I've decided to include it.
## Objective
Change the morph target pipeline to:
- Avoid a system ordering dependency between multiple crates.
- Optimise main world CPU and memory.
- Add flexibility.
## Summary
The morph target pipeline currently relies on copying morph target
weights between components. This has several issues.
First, the copy requires a system ordering dependency between
`bevy_animation`, `bevy_mesh` and `bevy_render`:
```rust
// bevy_mesh
pub struct InheritWeightSystems;
// bevy_animation
animate_targets.before(bevy_mesh::InheritWeightSystems)
// bevy_render
inherit_weights.in_set(InheritWeightSystems)
```
Second, the copy is arguably redundant - the weights will be copied
again into render buffers.
Third, the copy requires certain entities to be children of other
entities. This inflexibility is not a problem right now, but might be in
future.
This PR avoids the redundant copy and removes the need for system
ordering.
## Current Pipeline
In scenes created from glTFs, the morph weights are in three places:
- A `MorphWeights` component (basically a `Vec<f32>`).
- This is animated by `bevy_animation` or the user - see
`bevy_animation::animate_targets`.
- It must be on the _parent_ entity of one or more entities with a
`Mesh3d` component.
- A `MeshMorphWeights` component (also a `Vec<f32>`).
- This must be on an entity with a `Mesh3d` component.
- In the main world update, `bevy_render::inherit_weights` copies
weights from `MorphWeights` to any `MeshMorphWeights` components in
child entities.
- Render buffers.
- In the render world extraction, `bevy_render::extract_morphs` copies
weights from `MeshMorphWeights` to render buffers.
So the flow is `MorphWeights` -> `MeshMorphWeights` -> render buffers.
The separation between `MorphWeights` and `MeshMorphWeights` allows a
single `MorphWeights` component to drive multiple `MeshMorphWeights`
components.
A user who's setting up their own pipeline can choose to avoid
`MorphWeights` and use only `MeshMorphWeights`.
## Solution
In the new pipeline, `MeshMorphWeights` is not a copy of `MorphWeights`.
Instead it's either a standalone value or a reference to the entity
containing `MorphWeights`.
```diff
-struct MeshMorphWeights { weights: Vec<f32> }
+enum MeshMorphWeights {
+ Value { weights: Vec<f32> },
+ Reference(Entity),
+}
```
The `inherit_weights` copy is no longer needed. If `MeshMorphWeights` is
a reference then render extraction copies `MorphWeights` straight into
render buffers.
This is also more flexible - the child entity requirement of
`inherit_weights` is gone, so a `MeshMorphWeights` can point to any
entity.
## Performance
Tested on `many_morph_targets` (#18536), which uses `MorphWeights` and
`MeshMorphWeights`:
- `inherit_weights` goes from 30.3us to zero.
- `extract_morphs` goes from 42.5us to 48.9us (+6.4us).
- Overall, that means throughput goes from 14 to 21 meshes per us
(+50%).
There's room for further optimisation. The render buffers have a copy of
the weights for each mesh, but multiple meshes could be sharing the same
weights.
## Testing
```sh
cargo run --example morph_targets
cargo run --example scene_viewer --features "free_camera" -- assets/models/animated/MorphStressTest.gltf
# Requires #18536.
cargo run --example many_morph_targets
```
Also tested a few other glTFs, and hacked the glTF importer to simulate
some valid and invalid combinations (missing weights, mismatched
arrays).
Part of #19731
Follow-up to #22919 and #20934
This consolidates some of our component registration internals and
removes some resource / component redundancies there.
# Objective
- Rename lifecycle “Replace” hooks/events to “Discard” to reflect actual
semantics (fires on overwrite, remove, and despawn), and free up
“Replace” for a future true replacement event. Addresses #20729.
## Solution
- Renamed Replace/on_replace to Discard/on_discard across hooks,
observers, events, derive macros, docs, examples, and tests.
- Updated UI compile‑fail expectations and added OnDiscard doc alias on
Discard for discoverability.
## Testing
- `cargo run -p ci -- compile-fail`
- `cargo test -p bevy_ecs --lib --tests --features
bevy_ecs/track_location` (fails locally due to missing bevy_ecs/debug
feature in two tests that assert full system names)
follow up to #22414
in my comment
<https://github.com/bevyengine/bevy/pull/22414#issuecomment-2645849258>
i realized the warn added in #22414 would never actually trigger because
`pixel_bytes` and `pixel_bytes_mut` were returning `Option` instead of
`Result`, which caused the `UnsupportedTextureFormat` error to be lost
and converted to `OutOfBounds`.
this changes:
- `pixel_data_offset` now returns `Result` instead of `Option`
- `pixel_bytes` and `pixel_bytes_mut` now return `Result` instead of
`Option`
- errors are properly propagated so the warn in sprite picking actually
triggers for compressed textures
- added a regression test
`compressed_texture_format_is_reported_correctly`
- updated `examples/2d/cpu_draw.rs` for the new signature
should i remove the regression test if it's useless ?
thanks
This is part of #19731.
# Resources as Components
## Motivation
More things should be entities. This simplifies the API, the lower-level
implementation and the tools we have for entities and components can be
used for other things in the engine. In particular, for resources, it is
really handy to have observers, which we currently don't have. See
#20821 under 1A, for a more specific use.
## Current Work
This removes the `resources` field from the world storage and instead
store the resources on singleton entities. For easy lookup, we add a
`HashMap<ComponentId, Entity>` to `World`, in order to quickly find the
singleton entity where the resource is stored.
Because we store resources on entities, we derive `Component` alongside
`Resource`, this means that
```rust
#[derive(Resource)]
struct Foo;
```
turns into
```rust
#[derive(Resource, Component)]
struct Foo;
```
This was also done for reflections, meaning that
```rust
#[derive(Resource, Reflect)]
#[refect(Resource)]
struct Bar;
```
becomes
```rust
#[derive(Resource, Component, Reflect)]
#[refect(Resource, Component)]
struct Bar;
```
In order to distinguish resource entities, they are tagged with the
`IsResource` component. Additionally, to ensure that they aren't queried
by accident, they are also tagged as being internal entities, which
means that they don't show up in queries by default.
## Drawbacks
- Currently you can't have a struct that is both a `Resource` and a
`Component`, because `Resource` expands to also implement `Component`,
this means that this throws a compiler error as it's implemented twice.
- Because every reflected Resource must also implement
`ReflectComponent` you need to import
`bevy_ecs::reflect::ReflectComponent` every time you use
`#[reflect(Resource)]`. This is kind of unintuitive.
## Future Work
- Simplify `Access` in the ECS, to only deal with components (and not
components *and* resources).
- Newtype `Res<Resource>` to `Single<Ref<Resource>>` (or something
similair).
- Eliminate `ReflectResource`.
- Take stabs at simplifying the public facing API.
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Dimitrios Loukadakis <dloukadakis@users.noreply.github.com>