# Objective
An attempt to start building a base for first-party tilemaps (#13782).
The objective is to create a very simple tilemap chunk rendering plugin
that can be used as a building block for 3rd-party tilemap crates, and
eventually a first-party tilemap implementation.
## Solution
- Introduces two user-facing components, `TilemapChunk` and
`TilemapChunkIndices`, and a new material `TilemapChunkMaterial`.
- `TilemapChunk` holds the chunk and tile sizes, and the tileset image
- The tileset image is expected to be a layered image for use with
`texture_2d_array`, with the assumption that atlases or multiple images
would go through an asset loader/processor. Not sure if that should be
part of this PR or not..
- `TilemapChunkIndices` holds a 1d representation of all of the tile's
Option<u32> index into the tileset image.
- Indices are fixed to the size of tiles in a chunk (though maybe this
should just be an assertion instead?)
- Indices are cloned and sent to the shader through a u32 texture.
## Testing
- Initial testing done with the `tilemap_chunk` example, though I need
to include some way to update indices as part of it.
- Tested wasm with webgl2 and webgpu
- I'm thinking it would probably be good to do some basic perf testing.
---
## Showcase
```rust
let chunk_size = UVec2::splat(64);
let tile_size = UVec2::splat(16);
let indices: Vec<Option<u32>> = (0..chunk_size.x * chunk_size.y)
.map(|_| rng.gen_range(0..5))
.map(|i| if i == 0 { None } else { Some(i - 1) })
.collect();
commands.spawn((
TilemapChunk {
chunk_size,
tile_size,
tileset,
},
TilemapChunkIndices(indices),
));
```

# Objective
- Notice a word duplication typo
- Small quest to fix similar or nearby typos with my faithful companion
`\b(\w+)\s+\1\b`
## Solution
Fix em
# Objective
The objective of this PR is to enable Components to use their
`MapEntities` implementation for `Component::map_entities`.
With the improvements to the entity mapping system, there is definitely
a huge reduction in boilerplate. However, especially since
`(Entity)HashMap<..>` doesn't implement `MapEntities` (I presume because
the lack of specialization in rust makes `HashMap<Entity|X, Entity|X>`
complicated), when somebody has types that contain these hashmaps they
can't use this approach.
More so, we can't even depend on the previous implementation, since
`Component::map_entities` is used instead of
`MapEntities::map_entities`. Outside of implementing `Component `and
`Component::map_entities` on these types directly, the only path forward
is to create a custom type to wrap the hashmaps and implement map
entities on that, or split these components into a wrapper type that
implement `Component`, and an inner type that implements `MapEntities`.
## Current Solution
The solution was to allow adding `#[component(map_entities)]` on the
component. By default this will defer to the `MapEntities`
implementation.
```rust
#[derive(Component)]
#[component(map_entities)]
struct Inventory {
items: HashMap<Entity, usize>
}
impl MapEntities for Inventory {
fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
self.items = self.items
.drain()
.map(|(id, count)|(entity_mapper.get_mapped(id), count))
.collect();
}
}
```
You can use `#[component(map_entities = <function path>)]` instead to
substitute other code in for components. This function can also include
generics, but sso far I haven't been able to find a case where they are
needed.
```rust
#[derive(Component)]
#[component(map_entities = map_the_map)]
// Also works #[component(map_entities = map_the_map::<T,_>)]
struct Inventory<T> {
items: HashMap<Entity, T>
}
fn map_the_map<T, M: EntityMapper>(inv: &mut Inventory<T>, entity_mapper: &mut M) {
inv.items = inv.items
.drain()
.map(|(id, count)|(entity_mapper.get_mapped(id), count))
.collect();
}
```
The idea is that with the previous changes to MapEntities, MapEntities
is implemented more for entity collections than for Components. If you
have a component that makes sense as both, `#[component(map_entities)]`
would work great, while otherwise a component can use
`#[component(map_entities = <function>)]` to change the behavior of
`Component::map_entities` without opening up the component type to be
included in other components.
## (Original Solution if you want to follow the PR)
The solution was to allow adding `#[component(entities)]` on the
component itself to defer to the `MapEntities` implementation
```rust
#[derive(Component)]
#[component(entities)]
struct Inventory {
items: HashMap<Entity, usize>
}
impl MapEntities for Inventory {
fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
self.items = self.items
.drain()
.map(|(id, count)|(entity_mapper.get_mapped(id), count))
.collect();
}
}
```
## Testing
I tested this by patching my local changes into my own bevy project. I
had a system that loads a scene file and executes some logic with a
Component that contains a `HashMap<Entity, UVec2>`, and it panics when
Entity is not found from another query. Since the 0.16 update this
system has reliably panicked upon attempting to the load the scene.
After patching my code in, I added `#[component(entities)]` to this
component, and I was able to successfully load the scene.
Additionally, I wrote a doc test.
## Call-outs
### Relationships
This overrules the default mapping of relationship fields. Anything else
seemed more problematic, as you'd have inconsistent behavior between
`MapEntities` and `Component`.
This is a bit of a test case in writing the
[explanation](https://bevyengine.org/learn/contribute/helping-out/explaining-examples/)
for an example whose subject (`DistanceFog` as a component on cameras)
is the focus, but isn't that complicated either. Not certain if this
could be an exception or something more common.
Putting the controls below the explanation, as they're more of a
fall-back for the on-screen info (also that's where they were before).
# Objective
- Start the realtime direct lighting work for bevy solari
## Solution
- Setup all the CPU-side code for the realtime lighting path (minus some
parts for the temporal reuse I haven't written yet)
- Implement RIS with 32 samples to choose a good random light
- Don't sample a disk for the directional light, just treat it as a
single point. This is faster and not much worse quality.
## Future
- Spatiotemporal reuse (ReSTIR DI)
- Denoiser (DLSS-RR)
- Light tile optimization for faster light selection
- Indirect lighting (ReSTIR GI)
## Testing
- Run the solari example to see realtime
- Run the solari example with `-- --pathtracer` to see the existing
pathtracer
---
## Showcase
1 frame direct lighting:

Accumulated pathtracer output:

---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
While working on #17607, I found myself confused and frustrated by the
tangled web woven by the various modules inside of our observers code.
Rather than tackle that as part of a big rewrite PR, I've decided to do
the mature (if frustrating) thing where you split out your trivial but
noisy refactoring first.
There are a large number of moving parts, especially in terms of
storage, and these are strewn willy-nilly across the module with no
apparent ordering. To make matters worse, this was almost all just
dumped into a multi-thousand LOC mod.rs at the root.
## Solution
I've reshuffled the modules, attempting to:
- reduce the size of the mod.rs file
- organize structs so that smaller structs are found after the larger
structs that contain them
- group related functionality together
- document why modules exist, and their broad organization
No functional changes have been made here, although I've had to increase
the visibility of a few fields from private to pub(crate) or pub(super)
to keep things compiling.
During these changes, I've opted for the lazy private module, public
re-export strategy, to avoid causing any breakages, both within and
outside of `bevy` itself. I think we can do better, but I want to leave
that for a proper cleanup pass at the end. There's no sense maintaining
migration guides and forcing multiple breaking changes throughout the
cycle.
## Testing
No functional changes; relying on existing test suite and the Rust
compiler.
# Objective
Fix https://github.com/bevyengine/bevy/issues/19617
# Solution
Add newlines before all impl blocks.
I suspect that at least some of these will be objectionable! If there's
a desired Bevy style for this then I'll update the PR. If not then we
can just close it - it's the work of a single find and replace.
Bump version after release
This PR has been auto-generated
Fixes#19766
---------
Co-authored-by: Bevy Auto Releaser <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
Co-authored-by: François Mockers <mockersf@gmail.com>
# Objective
There is a lot of `world.entities().len()`, especially in tests. In
tests, usually, the assumption is made that empty worlds do not contain
any entities. This is about to change (#19711), and as such all of these
tests are failing for that PR.
## Solution
`num_entities` is a convenience method that returns the number of
entities inside a world. It can later be adapted to exclude 'unexpected'
entities, associated with internal data structures such as Resources,
Queries, Systems. In general I argue for a separation of concepts where
`World` ignores internal entities in methods such as `iter_entities()`
and `clear_entities()`, that discussion is, however, separate from this
PR.
## Testing
I replaced most occurrences of `world.entities().len()` with
`world.num_entities()` and the tests passed.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Some methods and commands carelessly overwrite `Relationship`
components. This may overwrite additional data stored at them which is
undesired.
Part of #19589
## Solution
A new private method will be used instead of insert:
`modify_or_insert_relation_with_relationship_hook_mode`.
This method behaves different to `insert` if `Relationship` is a larger
type than `Entity` and already contains this component. It will then use
the `modify_component` API and a new `Relationship::set_risky` method to
set the related entity, keeping all other data untouched.
For the `replace_related`(`_with_difference`) methods this also required
a `InsertHookMode` parameter for efficient modifications of multiple
children. The changes here are limited to the non-public methods.
I would appreciate feedback if this is all good.
# Testing
Added tests of all methods that previously could reset `Relationship`
data.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
I've noticed that some methods with `MaybeLocation::caller` don't have
`#[track_caller]` which resulted in wrong locations reported when
`track_location` is enabled.
## Solution
add `#[track_caller]` to them.
Click to focus is now a global observer.
# Objective
Previously, the "click to focus" behavior was implemented in each
individual headless widget, producing redundant logic.
## Solution
The new scheme is to have a global observer which looks for pointer down
events and triggers an `AcquireFocus` event on the target. This event
bubbles until it finds an entity with `TabIndex`, and then focuses it.
## Testing
Tested the changes using the various examples that have focusable
widgets. (This will become easier to test when I add focus ring support
to the examples, but that's for another day. For now you just have to
know which keys to press.)
## Migration
This change is backwards-compatible. People who want the new behavior
will need to install the new plugin.
# Objective
- Fix#19759
- The bigger permutation table only comes into play for higher
dimensions than 1, when you start doing
`PERMUTATION_TABLE[PERMUTATION_TABLE[index] + some_number]`
- The bigger permutation table has no mathematical meaning, it's just
there to avoid having to write more `& 0xFF` when doing multiple nested
lookups in higher dimensions
- But we only use 1D Perlin noise for the camera shake because we want
the dimensions to be uncorrelated
## Solution
- So, we can trim the permutation table down :)
- This should be mathematically identical, as a wrapped value will still
access the same element as an unwrapped value would in the bigger table
- The comment was a bit misleading anyways. "mirror" did not refer to
"mirrored values" but to "repeated values".
## Testing
- Ran the example. Still behaves like before.
# Objective
Add support for interpolation in OKLab and OKLCH color spaces for UI
gradients.
## Solution
* New `InterpolationColorSpace` enum with `OkLab`, `OkLch`, `OkLchLong`,
`Srgb` and `LinearRgb` variants.
* Added a color space specialization to the gradients pipeline.
* Added support for interpolation in OkLCH and OkLAB color spaces to the
gradients shader. OKLCH interpolation supports both short and long hue
paths. This is mostly based on the conversion functions from
`bevy_color` except that interpolation in polar space uses radians.
* Added `color_space` fields to each gradient type.
## Testing
The `gradients` example has been updated to demonstrate the different
color interpolation methods.
Press space to cycle through the different options.
---
## Showcase

Without this dependency, the bevy_ecs tests fail with missing as_string
methods.
# Objective
- Fixes#19734
## Solution
- add bevy_utils with feature = "Debug" to dev-dependencies
## Testing
- Ran `cargo test -p bevy_ecs`
- Ran `taplo fmt --check`
---
# Objective
There were 2 folders inside of `examples`, each with 1 example, and with
similar folder names.
## Solution
Move the example in the `usages` folder to `usage`.
## Testing
`cargo run -p ci`
# Objective
- A nightly only lint is allowed in cargo.toml, making all stable builds
issue warning
- Fixes#19528
## Solution
- Don't allow nightly lints
# Objective
- Currently there is predefinied list of supported DataTypes that can be
detected on Bevy JSON Schema generation and mapped as reflect_types
array elements.
- Make it possible to register custom `reflectTypes` mappings for Bevy
JSON Schema.
## Solution
- Create a `SchemaTypesMetadata` Resource that will hold mappings for
`TypeId` of `TypeData`. List is bigger from beggining and it is possible
to expand it without forking package.
## Testing
- I use it for quite a while in my game, I have a fork of bevy_remote
with more changes that later I want to merge to main as well.
---------
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
# Objective
- Alternative to #19721
- The old implementation had several issues:
- underexplained
- bit complicated in places
- did not follow the source as described
- camera moves away
- camera does not use noise
- camera nudges back after shake ends, which looks cinematic, but not
what you want in practice
All in all: the old implementation did not really show a typical
implementation IMO
## Solution
- Rewrite it :D
- I believe the current implementation is a robust thing you can learn
from or just copy-paste into your project
## Testing
https://github.com/user-attachments/assets/bfe74fb6-c428-4d5a-9c9c-cd4a034ba176
---------
Co-authored-by: Rob Parrett <robparrett@gmail.com>
# Objective
This is part of the "core widgets" effort:
https://github.com/bevyengine/bevy/issues/19236.
## Solution
This adds the "core checkbox" widget type.
## Testing
Tested using examples core_widgets and core_widgets_observers.
Note to reviewers: I reorganized the code in the examples, so the diffs
are large because of code moves.
# Objective
- Splitted off from #19491
- Make adding generated code to the `Bundle` derive macro easier
- Fix a bug when multiple fields are `#[bundle(ignore)]`
## Solution
- Instead of accumulating the code for each method in a different `Vec`,
accumulate only the names of non-ignored fields and their types, then
use `quote` to generate the code for each of them in the method body.
- To fix the bug, change the code populating the `BundleFieldKind` to
push only one of them per-field (previously each `#[bundle(ignore)]`
resulted in pushing twice, once for the correct
`BundleFieldKind::Ignore` and then again unconditionally for
`BundleFieldKind::Component`)
## Testing
- Added a regression test for the bug that was fixed
Custom derived `QueryData` impls currently generate `Item` structs with
the lifetimes swapped, which blows up the borrow checker sometimes.
See:
https://discord.com/channels/691052431525675048/749335865876021248/1385509416086011914
could add a regression test, TBH I don't know the error well enough to
do that minimally. Seems like it's that both lifetimes on
`QueryData::Item` need to be covariant, but I'm not sure.
# Objective
Unblock #18162.
#15396 added the `'s` lifetime to `QueryData::Item` to make it possible
for query items to borrow from the state. The state isn't passed
directly to `QueryData::fetch()`, so it also added the `'s` lifetime to
`WorldQuery::Fetch` so that we can pass the borrows through there.
Unfortunately, having `WorldQuery::Fetch` borrow from the state makes it
impossible to have owned state, because we store the state and the
`Fetch` in the same `struct` during iteration.
## Solution
Undo the change to add the `'s` lifetime to `WorldQuery::Fetch`.
Instead, add a `&'s Self::State` parameter to `QueryData::fetch()` and
`QueryFilter::filter_fetch()` so that borrows from the state can be
passed directly to query items.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Emerson Coskey <emerson@coskey.dev>
# Objective
- Many strings in bevy_ecs are created but only used for debug: system
name, component name, ...
- Those strings make a significant part of the final binary and are no
use in a released game
## Solution
- Use [`strings`](https://linux.die.net/man/1/strings) to find ...
strings in a binary
- Try to find where they come from
- Many are made from `type_name::<T>()` and only used in error / debug
messages
- Add a new structure `DebugName` that holds no value if `debug` feature
is disabled
- Replace `core::any::type_name::<T>()` by `DebugName::type_name::<T>()`
## Testing
Measurements were taken without the new feature being enabled by
default, to help with commands
### File Size
I tried building the `breakout` example with `cargo run --release
--example breakout`
|`debug` enabled|`debug` disabled|
|-|-|
|81621776 B|77735728B|
|77.84MB|74.13MB|
### Compilation time
`hyperfine --min-runs 15 --prepare "cargo clean && sleep 5"
'RUSTC_WRAPPER="" cargo build --release --example breakout'
'RUSTC_WRAPPER="" cargo build --release --example breakout --features
debug'`
```
breakout' 'RUSTC_WRAPPER="" cargo build --release --example breakout --features debug'
Benchmark 1: RUSTC_WRAPPER="" cargo build --release --example breakout
Time (mean ± σ): 84.856 s ± 3.565 s [User: 1093.817 s, System: 32.547 s]
Range (min … max): 78.038 s … 89.214 s 15 runs
Benchmark 2: RUSTC_WRAPPER="" cargo build --release --example breakout --features debug
Time (mean ± σ): 92.303 s ± 2.466 s [User: 1193.443 s, System: 33.803 s]
Range (min … max): 90.619 s … 99.684 s 15 runs
Summary
RUSTC_WRAPPER="" cargo build --release --example breakout ran
1.09 ± 0.05 times faster than RUSTC_WRAPPER="" cargo build --release --example breakout --features debug
```
# Objective
While `KeyCode` is very often the correct way to interact with keyboard
input there are a bunch of cases where it isn't, notably most of the
symbols (e.g. plus, minus, different parentheses). Currently the only
way to get these is to read from `EventReader<KeyboardInput>`, but then
you'd have to redo the `ButtonInput` logic for pressed/released to e.g.
make zoom functionality that depends on plus/minus keys.
This has led to confusion previously, like
https://github.com/bevyengine/bevy/issues/3278
## Solution
Add a `ButtonInput<Key>` resource.
## Testing
Modified the `keyboard_input` example to test it.
## Open questions
I'm not 100% sure this is the right way forward, since it duplicates the
key processing logic and might make people use the shorter
`ButtonInput<Key>` even when it's not appropriate.
Another option is to add a new struct with both `Key` and `KeyCode`, and
use `ButtonInput` with that instead. That would make it more
explanatory, but that is a lot of churn.
The third alternative is to not do this because it's too niche.
I'll add more documentation and take it out of draft if we want to move
forward with it.
# Objective
Fixes#18726
Alternative to and closes#18797
## Solution
Create a method `Observer::system_name` to expose the name of the
`Observer`'s system
## Showcase
```rust
// Returns `my_crate::my_observer`
let observer = Observer::new(my_observer);
println!(observer.system_name());
// Returns `my_crate::method::{{closure}}`
let observer = Observer::new(|_trigger: Trigger<...>|);
println!(observer.system_name());
// Returns `custom_name`
let observer = Observer::new(IntoSystem::into_system(my_observer).with_name("custom_name"));
println!(observer.system_name());
```
## TODO
- [ ] Achieve cart's approval
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Fix https://github.com/bevyengine/bevy/issues/19642 by enabling e.g.
```
map.get_type::<MyType>();
```
in place of
```
map.get(&TypeId::of::<MyType>());
```
## Solution
Add an extension trait `TypeIdMapExt` with `insert_type`, `get_type`,
`get_type_mut` and `remove_type` counterparts for `insert`, `get`,
`get_mut` and `remove`.
## Testing
Doc test.
# Objective
- Fixes#19627
- Tackles part of #19644
- Supersedes #19629
- `Window` has become a very very very big component
- As such, our change detection does not *really* work on it, as e.g.
moving the mouse will cause a change for the entire window
- We circumvented this with a cache
- But, some things *shouldn't* be cached as they can be changed from
outside the user's control, notably the cursor grab mode on web
- So, we need to disable the cache for that
- But because change detection is broken, that would result in the
cursor grab mode being set every frame the mouse is moved
- That is usually *not* what a dev wants, as it forces the cursor to be
locked even when the end-user is trying to free the cursor on the
browser
- the cache in this situation is invalid due to #8949
## Solution
- Split `Window` into multiple components, each with working change
detection
- Disable caching of the cursor grab mode
- This will only attempt to force the grab mode when the `CursorOptions`
were touched by the user, which is *much* rarer than simply moving the
mouse.
- If this PR is merged, I'll do the exact same for the other
constituents of `Window` as a follow-up
## Testing
- Ran all the changed examples
Closes#19677.
I don't think that the output type needs to be `Send`. I've done some
test at it seems to work fine without it, which in IMO makes sense, but
please correct me if that is not the case.
# Objective
- compute_matrix doesn't compute anything, it just puts an Affine3A into
a Mat4. the name is inaccurate
## Solution
- rename it to conform with to_isometry (which, ironically, does compute
a decomposition which is rather expensive)
## Testing
- Its a rename. If it compiles, its good to go
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- When trying to serialize an structure that contains `&'static str`
using only Reflection, I get the following error:
```
"type `&str` did not register the `ReflectSerialize` or `ReflectSerializeWithRegistry` type data.
For certain types, this may need to be registered manually using `register_type_data` (stack: ... -> `core::option::Option<&str>` -> `&str`)")
```
## Solution
- Register `ReflectSerialize` for `&str`
## Testing
- `cargo run -p ci`: OK
# Objective
The position for track clicks in `core_slider` is calculated incorrectly
when using `UiScale`.
## Solution
`trigger.event().pointer_location.position` uses logical window
coordinates, that is:
`position = physical_position / window_scale_factor`
while `ComputedNodeTarget::scale_factor` returns the window scale factor
multiplied by Ui Scale:
`target_scale_factor = window_scale_factor * ui_scale`
So to get the physical position need to divide by the `UiScale`:
```
position * target_scale_factor / ui_scale
= (physical_postion / window_scale_factor) * (window_scale_factor * ui_scale) / ui_scale
= physical_position
```
I thought this was fixed during the slider PR review, but must have got
missed somewhere or lost in a merge.
## Testing
Can test using the `core_widgets` example` with
`.insert_resource(UiScale(2.))` added to the bevy app.
# Objective
When the `CoreSlider`s `on_change` is set to None, Keyboard input, like
ArrowKeys, does not update the `SliderValue`.
## Solution
Handle the missing case, like it is done for Pointer.
## Testing
- Did you test these changes?
Yes: core_widgets & core_widgets_observers
in both examples one has to remove / comment out the setting of
`CoreSlider::on_change` to test the case of `on_change` being none.
- Are there any parts that need more testing?
No not that I am aware of.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
Yes: core_widgets & core_widgets_observers
in both examples one has to remove / comment out the setting of
`CoreSlider::on_change` to test the case of `on_change` being none.
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
I tested on linux + wayland. But it is unlikely that it would effect
outcomes.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- to_isometry is not a direct conversion, it involves computation. the
docs could be clearer
## Solution
- Improve docs
## Testing
- its docs
# Objective
Our strategy for storing observers is made up of several moving parts,
which are ultimately fairly simple nested HashMaps.
These types are currently `pub`, but lack any meaningful way to access
this data.
We have three options here:
1. Make these internals not `pub` at all.
2. Make the data read-only accessible.
3. Make the data mutably accessible.
## Solution
I've opted for option 2, exposing read-only values. This is consistent
with our existing approach to the ECS internals, allowing for easier
debugging without risking wanton data corruption. If one day you would
like to mutably access this data, please open an issue clearly
explaining what you're trying to do.
This was a pretty mechanical change, exposing fields via getters. I've
also opted to do my best to clarify some field names and documentation:
please double-check those for correctness. It was hard to be fully
confident, as the field names and documentation was not very clear ;)
## Testing
I spent some time going through the code paths, making sure that users
can trace all the way from `World` to the leaf nodes. Reviewers, please
ensure the same!
## Notes for reviewers
This is part of a broader observer overhaul: I fully expect us to change
up these internals and break these shiny new APIs. Probably even within
the same cycle!
But clean up your work area first: this sort of read-only getter and
improved docs will be important to replace as we work.
# Objective
*Fixes #5670 as an opt-in for now*
glTF uses the following coordinate system:
- forward: Z
- up: Y
- right: -X
and Bevy uses:
- forward: -Z
- up: Y
- right: X
For the longest time, Bevy has simply ignored this distinction. That
caused issues when working across programs, as most software respects
the
glTF coordinate system when importing and exporting glTFs. Your scene
might have looked correct in Blender, Maya, TrenchBroom, etc. but
everything would be flipped when importing it into Bevy!
## Solution
Add an option to the glTF loader to perform coordinate conversion. Note
that this makes a distinction in the camera nodes, as glTF uses a
different coordinate system for them.
## Follow Ups
- Add global glTF loader settings, similar to the image loader, so that
users can make third-party crates also load their glTFs with corrected
coordinates
- Decide on a migration strategy to make this the future default
- Create an issue
- Get feedback from Patrick Walton and Cart (not pinging them here to
not spam them)
- Include this pic for reference of how Blender assumes -Y as forward:

## Testing
I ran all glTF animation examples with the new setting enabled to
validate that they look the same, just flipped.
Also got a nice test scene from Chris that includes a camera inside the
glTF. Thanks @ChristopherBiscardi!
Blender (-Y forward):

Bevy (-Z forward, but the model looks the wrong way):

Bevy with `convert_coordinates` enabled (-Z forward):

Validation that the axes are correct with F3D's glTF viewer (+Z
forward):

# Objective
- Fix issue where `SubStates` depending on multiple source states would
only react when _all_ source states changed simultaneously.
- SubStates should be created/destroyed whenever _any_ of their source
states transitions, not only when all change together.
# Solution
- Changed the "did parent change" detection logic from AND to OR. We
need to check if _any_ of the event readers changed, not if _all_ of
them changed.
- See
https://github.com/bevyengine/bevy/actions/runs/15610159742/job/43968937544?pr=19595
for failing test proof before I pushed the fix.
- The generated code we want needs `||`s not `&&`s like this:
```rust
fn register_sub_state_systems_in_schedule<T: SubStates<SourceStates = Self>>(schedule: &mut Schedule) {
let apply_state_transition = |(mut ereader0, mut ereader1, mut ereader2): (
EventReader<StateTransitionEvent<S0::RawState>>,
EventReader<StateTransitionEvent<S1::RawState>>,
EventReader<StateTransitionEvent<S2::RawState>>,
),
event: EventWriter<StateTransitionEvent<T>>,
commands: Commands,
current_state_res: Option<ResMut<State<T>>>,
next_state_res: Option<ResMut<NextState<T>>>,
(s0, s1, s2): (
Option<Res<State<S0::RawState>>>,
Option<Res<State<S1::RawState>>>,
Option<Res<State<S2::RawState>>>,
)| {
// With `||` we can correctly count parent changed if any of the sources changed.
let parent_changed = (ereader0.read().last().is_some()
|| ereader1.read().last().is_some()
|| ereader2.read().last().is_some());
let next_state = take_next_state(next_state_res);
if !parent_changed && next_state.is_none() {
return;
}
// ...
}
}
```
# Testing
- Add new test.
- Check the fix worked in my game.
# Objective
Current way to wire `Layer`s together using `layer.with(new_layer)` in
the `bevy_log` plugin is brittle and not flexible. As #17722
demonstrated, the current solution makes it very hard to do any kind of
advanced wiring, as the type system of `tracing::Subscriber` gets in the
way very quickly (the type of each new layer depends on the type of the
previous ones). We want to make it easier to have more complex wiring of
`Layers`. It would be hard to solve #19085 without it
## Solution
It aims to be functionally equivalent.
- Replace of using `layer.with(new_layer)` . We now add `layer.boxed()`
to a `Vec<BoxedLayer>`. It is a solution recommended by
`tracing_subscriber::Layer` for complex wiring cases (See
https://docs.rs/tracing-subscriber/latest/tracing_subscriber/layer/index.html#runtime-configuration-with-layers)
- Do some refactoring and clean up that is now enabled by the new
solution
## Testing
- Ran CI locally on Linux
- Ran the logs examples
- Need people familiar with the features `trace`, `tracing-chrome`,
`tracing-tracy` to check that it still works as expected
- Need people with access to `ios`, `android` and `wasm` to check it as
well.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Kristoffer Søholm <k.soeholm@gmail.com>
# Objective
I have a custom asset loader, and need access to the error it reports
when failing to load (e.g. through `AssetLoadFailedEvent { error:
AssetLoadError::AssetLoaderError(loader_error), .. }`). However
`AssetLoaderError` doesn't expose its `<core::error::Error>::source()`
(i.e. its `error` field. It only formats it when `Display`ed.
*I haven't searched for issues about it.*
## Solution
- Annotate `AssetLoaderError`'s `error` field with `#[source]`.
- Don't include the error when `AssetLoaderError` is `Display`ed (when
one prints an error's source stack like a backtrace, it would now be
dupplicated).
- (optional, included as a separated commit) Add a getter for the `&dyn
Error` stored in the `error` field (whithin an `Arc`). This is more
ergonomic than using `Error::source()` because it casts an `&Arc<dyn
Error>` into an `&dyn Error`, meaning one has to downcast it twice to
get the original error from the loader, including once where you have to
specify the correct type of the *private* `error` field. So downcasting
from `Error::source()` effectively rely on the internal implementation
of `AssetLoaderError`. The getter instead return the trait object
directly, which mean it will directly downcast to the expected loader
error type.
I didn't included a test that checks that double-downcasting
`<AssetLoaderError as Error>::source()` doesn't break user code that
would rely on the private field's type.
## Testing
- Downcasting the trait objects for both `source()` and the `error()`
getter work as described above.
- `cargo test -p bevy_asset --all-features` pass without errors.
---------
Co-authored-by: austreelis <git@swhaele.net>
# Objective
Fixes#16051Closes#16145
## Solution
Allow passing `--build-jobs` and `--test-threads` to `ci`
i.e.
```
cargo run -p ci -- --build-jobs 4 --test-threads 4
```
## Testing
running ci locally
---------
Co-authored-by: Benjamin Brienen <Benjamin.Brienen@outlook.com>