Commit Graph

9079 Commits

Author SHA1 Message Date
jf908
9f376e2537
Update doc about Windows CursorGrabMode support (#19192)
# Objective

- Windows now supports `CursorGrabMode::Locked` in [Winit
0.30.10](https://github.com/rust-windowing/winit/releases/tag/v0.30.10)
which is automatically pulled in by cargo.

## Solution

- Remove the doc that says its unsupported.
2025-06-24 00:00:30 +00:00
Conner Petzold
3f187cf752
Add TilemapChunk rendering (#18866)
# 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),
));
```

![Screenshot 2025-04-17 at 11 54
56 PM](https://github.com/user-attachments/assets/850a53c1-16fc-405d-aad2-8ef5a0060fea)
2025-06-23 23:55:10 +00:00
Rob Parrett
d3ad66f033
Fix some typos (#19788)
# 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
2025-06-23 22:32:46 +00:00
Testare
da83232fa8
Let Component::map_entities defer to MapEntities (#19414)
# 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`.
2025-06-23 21:05:04 +00:00
Fallible Things
d7594a4f3c
Explanation for the 'classic' fog example (#19196)
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).
2025-06-23 20:55:38 +00:00
mgi388
efd17f133d
Rename num_entities to entity_count (#19781)
As discussed in
https://github.com/bevyengine/bevy/pull/19780#issuecomment-2994554024.
2025-06-23 05:08:02 +00:00
JMS55
0518eda2ad
bevy_solari: RIS for Direct Lighting (#19620)
# 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:

![image](https://github.com/user-attachments/assets/b70b968d-9c73-4983-9b6b-b60cace9b47a)

Accumulated pathtracer output:

![image](https://github.com/user-attachments/assets/d681bded-ef53-4dbe-bcca-96997c58c3be)

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-06-23 00:47:10 +00:00
Alice Cecile
61a5a37584
Improve module structure of observers code (#19779)
# 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.
2025-06-22 23:25:25 +00:00
theotherphil
7645ce91ed
Add newlines before impl blocks (#19746)
# 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.
2025-06-22 23:07:02 +00:00
github-actions[bot]
a466084167
Bump Version after Release (#19774)
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>
2025-06-22 23:06:43 +00:00
Trashtalk217
6dbe3600ed
Add num_entities() to World (#19780)
# 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>
2025-06-22 22:48:35 +00:00
urben1680
c6ae964709
EntityWorldMut methods do not automatically overwrite Relationship components (#19601)
# 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>
2025-06-22 00:22:05 +00:00
eugineerd
2d897380a0
add missing #[track_caller] (#19769)
# 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.
2025-06-21 18:05:58 +00:00
Talin
4ff595a4bc
New simplified "click to focus" logic for core widgets. (#19736)
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.
2025-06-21 18:05:26 +00:00
Jan Hohenheim
d770648c2f
Remove unused code in Perlin noise 1D impl (#19765)
# 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.
2025-06-21 15:07:43 +00:00
ickshonpe
45a3f3d138
Color interpolation in OKLab, OKLCH spaces for UI gradients (#19330)
# 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


![color_spaces](https://github.com/user-attachments/assets/e10f8342-c3c8-487e-b386-7acdf38d638f)
2025-06-21 15:06:35 +00:00
Lailatova
5d5a95fa6e
Fix issue 19734: add dependency on bevy_utils for the bevy_ecs test. (#19738)
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`

---
2025-06-21 15:05:04 +00:00
Lucas Franca
8f08d6bc86
Move usages folder to usage (#19757)
# 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`
2025-06-21 00:06:44 +00:00
François Mockers
9ed928b071
don't allow nightly lints (#19756)
# Objective

- A nightly only lint is allowed in cargo.toml, making all stable builds
issue warning
- Fixes #19528 

## Solution

- Don't allow nightly lints
2025-06-20 23:44:31 +00:00
MevLyshkin
84f21f7c8a
Schema types metadata (#19524)
# 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>
2025-06-20 17:07:16 +00:00
Jan Hohenheim
ffd6c9e1c9
Rewrite camera shake example (#19724)
# 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>
2025-06-20 16:43:14 +00:00
Talin
9fdddf7089
Core Checkbox (#19665)
# 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.
2025-06-20 16:37:18 +00:00
Giacomo Stevanato
35166d9029
Refactor bundle derive (#19749)
# 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
2025-06-20 16:36:08 +00:00
Emerson Coskey
8e1d0051d2
Fix QueryData derive codegen (#19750)
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.
2025-06-20 15:48:16 +00:00
theotherphil
b6bd205e8a
Gate Reflect derive behind feature flag (#19745)
# Objective

Fix https://github.com/bevyengine/bevy/issues/19733

## Solution

Gate reflect features behind `feature(bevy_reflect)`

## Tests

None
2025-06-19 21:58:17 +00:00
theotherphil
d2e1f725db
deny(missing_docs) for bevy_window (#19655)
# Objective

Write some more boilerplate-y docs, to get one crate closer to closing
https://github.com/bevyengine/bevy/issues/3492.
2025-06-19 19:33:49 +00:00
theotherphil
b129764924
deny(missing_docs) for bevy_asset_macros (#19719)
# Objective

More boilerplate docs, towards
https://github.com/bevyengine/bevy/issues/3492.

Another place where https://github.com/bevyengine/bevy/issues/19537
might be worth doing as a follow up - I've added a comment on that
issue.
2025-06-19 02:02:39 +00:00
Chris Russell
d0550f58ae
Remove 's lifetime from WorldQuery::Fetch (#19720)
# 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>
2025-06-19 00:58:21 +00:00
François Mockers
4e694aea53
ECS: put strings only used for debug behind a feature (#19558)
# 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
```
2025-06-18 20:15:25 +00:00
Kristoffer Søholm
2119838e27
Add support for ButtonInput<Key> (#19684)
# 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.
2025-06-18 20:15:03 +00:00
atlv
a1d3c6197f
rename Transform::compute_matrix to to_matrix (#19646)
# Objective

- Parity with #19643

## Solution

- Rename

## Testing

- None

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-06-18 05:37:25 +00:00
Lucas Franca
6f08bb84d2
Exposes Observer's system's name (#19611)
# 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>
2025-06-17 22:38:31 +00:00
Malek
f3e7a4b048
Added clone bounds to EntityEvents that were missing them. (#19708)
# Objective

Lack of clone on certain builtin events

## Solution

Added clone to those events

## Testing

## Showcase
2025-06-17 21:22:32 +00:00
theotherphil
66086a2616
Add TypeIdMapExt trait to make TypeIdMap operations more ergonomic (#19683)
# 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.
2025-06-17 21:06:27 +00:00
Alice Cecile
1079b83af9
Revert "bevy_log: refactor how log layers are wired together (#19248)" (#19705)
This reverts commit 8661e914a5, aka
#19248.

Fixes #19689.
2025-06-17 20:41:30 +00:00
Jan Hohenheim
a750cfe4a1
Split CursorOptions off of Window (#19668)
# 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
2025-06-17 20:20:13 +00:00
Alejandro Pascual
d1c6fbea57
Support fallible one-shot systems (#19678)
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.
2025-06-17 19:48:37 +00:00
atlv
2915a3b903
rename GlobalTransform::compute_matrix to to_matrix (#19643)
# 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>
2025-06-17 18:37:26 +00:00
Erick Z
20781371e8
Register ReflectSerialize for &'static str (#19680)
# 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
2025-06-16 22:09:15 +00:00
ickshonpe
c0fa10b0c3
slider widget track click position UiScale fix (#19676)
# 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.
2025-06-16 22:07:54 +00:00
HippoGamus
209866cc27
Fix Keyboard observer not updating SliderValue (#19661)
# 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>
2025-06-16 22:05:19 +00:00
atlv
7c2289c96e
Clarify GlobalTransform::to_isometry doc (#19645)
# Objective

- to_isometry is not a direct conversion, it involves computation. the
docs could be clearer

## Solution

- Improve docs

## Testing

- its docs
2025-06-16 22:02:30 +00:00
Alice Cecile
7237c2173b
Make observers metadata / storage publicly visible (#19608)
# 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.
2025-06-16 22:00:33 +00:00
ickshonpe
0c63aa2405
Document TextShadow not supported by Text2d (#19533)
# Objective

Document `TextShadow` not supported by `Text2d`

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-06-16 21:55:32 +00:00
Jan Hohenheim
9b743d2a43
Allow users to fix glTF coordinate system imports (#19633)
# 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:

![image](https://github.com/user-attachments/assets/8f5ae364-48f0-46e4-922b-50bccb8d58b3)

## 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): 

![image](https://github.com/user-attachments/assets/129013f1-a025-488a-8764-c7ee5e7019a1)

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

![image](https://github.com/user-attachments/assets/842e00e0-48ce-4ca7-a88e-ea458ecbf852)

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

![image](https://github.com/user-attachments/assets/e97f3797-75a0-4d2b-ac54-130ba69f0a3c)

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

![image](https://github.com/user-attachments/assets/b9f02adf-a7b0-4a18-821f-fdd04426d3bd)
2025-06-16 21:47:34 +00:00
mgi388
1f2fd3d29d
Fix SubStates with multiple source states not reacting to all source changes (#19595)
# 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.
2025-06-16 21:34:22 +00:00
SilentSpaceTraveller
8661e914a5
bevy_log: refactor how log layers are wired together (#19248)
# 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>
2025-06-16 21:30:55 +00:00
theotherphil
3b25b38bdc
deny(missing_docs) for bevy_reflect (#19481)
## Objective

Deny missing docs in bevy_reflect, towards
https://github.com/bevyengine/bevy/issues/3492.

## Solution

Add the missing docs!

## Testing

N/A
2025-06-16 21:26:24 +00:00
Austreelis
6db71367d4
allow access to the source error of AssetLoaderError and downcasting (#19471)
# 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>
2025-06-16 21:24:01 +00:00
Lucas Franca
c8cb7bdf57
Allow passing number of thread for building and testing to CI (#19359)
# Objective

Fixes #16051
Closes #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>
2025-06-16 21:19:47 +00:00