Commit Graph

87 Commits

Author SHA1 Message Date
andriyDev 4dc8fb4919 Change the ambiguity_detection test to be more strict. (#23846)
# Objective

- Fixes #23843 by preventing these systems from recurring inside Bevy.
- Note this does not fix this for users of Bevy. They would need to
setup their own "strict" checking.

## Solution

- Disable `auto_insert_apply_deferred` in the `ambiguity_detection`
example. Now these stages won't accidentally resolve these ambiguities,
so they will be detected!
- Stop running the app in `ambiguity_detection` and just manually
initialize the schedules.
- We have to do this otherwise the schedules just panic because they
depend on various resource initializations to be executed by commands
(which were previously being applied by the automatically inserted
`apply_deferred`).

### Caveats:

- The ambiguity_detection CI test now won't detect ambiguities in
runtime-added systems.
- This is not a pattern we use today, and I'd encourage us to **delete**
systems instead so that tooling can grab the systems before the app
runs.
- To clarify, this is **not** ambiguity detection in general - just
Bevy's CI test that is affected.

## Testing

- Ran the examples and all the ambiguities have been fixed in previous
PRs.
2026-04-22 16:19:28 +00:00
Carter Anderson 535cf401cc Reframe old "scene" terminology as "world serialization" (#23630)
Part 2 of #23619 

In **Bevy 0.19** we are landing a subset of Bevy's Next Generation Scene
system (often known as BSN), which now lives in the `bevy_scene` /
`bevy::scene` crate. However the old `bevy_scene` system still needs to
stick around for a bit longer, as it provides some features that Bevy's
Next Generation Scene system doesn't (yet!):

1. It is not _yet_ possible to write a World _to_ BSN, so the old system
is still necessary for "round trip World serialization".
2. The GLTF scene loader has not yet been ported to BSN, so the old
system is still necessary to spawn GLTF scenes in Bevy.

For this reason, we have renamed the old `bevy_scene` crate to
`bevy_world_serialization`. If you were referencing `bevy_scene::*` or
`bevy::scene::*` types, rename those paths to
`bevy_world_serialization::*` and `bevy::world_serialization::*`
respectively.

Additionally, to avoid confusion / conflicts with the new scene system,
all "scene" terminology / types have been reframed as "world
serialization":

- `Scene` -> `WorldAsset` (as this was always just a World wrapper)
- `SceneRoot` -> `WorldAssetRoot`
- `DynamicScene` -> `DynamicWorld`
    - `DynamicScene::from_scene` -> `DynamicWorld::from_world_asset`
- `DynamicSceneBuilder` -> `DynamicWorldBuilder`
- `DynamicSceneRoot` -> `DynamicWorldRoot`
- `SceneInstanceReady` -> `WorldInstanceReady`
- `SceneLoader` -> `WorldAssetLoader`
- `ScenePlugin` -> `WorldSerializationPlugin`
- `SceneRootTemplate` -> `WorldAssetRootTemplate`
- `SceneSpawner` -> `WorldInstanceSpawner`
- `SceneFilter` -> `WorldFilter`
- `SceneLoaderError` -> `WorldAssetLoaderError`
- `SceneSpawnError` -> `WorldInstanceSpawnError`

Note that I went with `bevy_world_serialization` over
`bevy_ecs_serialization`, as that is what all of the internal features
described themselves as. I think it is both more specific and does a
better job of making itself decoupled from `bevy_ecs` proper.
2026-04-04 00:31:47 +00:00
atlv 380d2c35f8 Enable RenderApp Ambiguity Detection (#22954)
# Objective

- Fix #7386

## Solution

- #22951 #22952 #22949 #22945 and a handful more changes on this PR.
NOTE: Ci will not pass until all these other prs are merged.
- Fix a bug

## Testing

- examples look fine

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
2026-02-17 16:27:27 +00:00
ickshonpe 6ca4769128 Minimal responsive FontSize support (#22614)
# Objective

Add responsive font sizes supporting rem and viewport units to
`bevy_text` with minimal changes to the APIs and systems.

## Solution

Introduce a new `FontSize` enum:

```rust
pub enum FontSize {
    /// Font Size in logical pixels.
    Px(f32),
    /// Font size as a percentage of the viewport width.
    Vw(f32),
    /// Font size as a percentage of the viewport height.
    Vh(f32),
    /// Font size as a percentage of the smaller of the viewport width and height.
    VMin(f32),
    /// Font size as a percentage of the larger of the viewport width and height.
    VMax(f32),
    /// Font Size relative to the value of the `RemSize` resource.
    Rem(f32),
}
```

This replaces the `f32` value of `TextFont`'s `font_size` field.

The viewport variants work the same way as their respective `Val`
counterparts.

`Rem` values are multiplied by the value of the `RemSize` resource
(which newtypes an `f32`).

`FontSize` provides an `eval` method that takes a logical viewport size
and rem base size and returns an `f32` logical font size. The resolved
logical font size is then written into the `Attributes` passed to Cosmic
Text by `TextPipeline::update_buffer`.

Any text implementation using `bevy_text` must now provide viewport and
rem base values when calling `TextPipeline::update_buffer` or
`create_measure`.

`Text2d` uses the size of the primary window to resolve viewport values
(or `Vec2::splat(1000)` if no primary window is found). This is a
deliberate compromise, a single `Text2d` can be rendered to multiple
viewports using `RenderLayers`, so it's difficult to find a rule for
which viewport size should be chosen.

### Change detection 

`ComputedTextBlock` has two new fields: `uses_viewport_sizes` and
`uses_rem_sizes`, which are set to true in `TextPipeline::update_buffer`
iff any text section in the block uses viewport or rem font sizes,
respectively.

The `ComputedTextBlock::needs_rerender` method has been modified to take
take two bool parameters:
```rust
    pub fn needs_rerender(
        &self,
        is_viewport_size_changed: bool,
        is_rem_size_changed: bool,
    ) -> bool {
        self.needs_rerender
            || (is_viewport_size_changed && self.uses_viewport_sizes)
            || (is_rem_size_changed && self.uses_rem_sizes)
    }
 ```
This ensures that text reupdates will also be scheduled if one of the text section's uses a viewport font size and the local viewport size changed, or if one of the text section's uses a rem font size and the rem size changed.

#### Limitations

There are some limitations because we don't have any sort of font style inheritance yet:

* "rem" units aren't proper rem units, and just based on the value of a resource. 
* "em" units are resolved based on inherited font size, so can't be implemented without inheritance support.

#### Notes

* This PR is quite small and not very technical. Reviewers don't need to be especially familiar with `bevy_text`. Most of the changes are to the examples.

* We could consider using `Val` instead of `FontSize`, then we could use `Val`'s constructor functions which would be much nicer, but some variants might not have sensible interpretations in both UI and Text2d contexts. Also we'd have to make `Val` accessible to `bevy_text`.

## Testing

The changes to the text systems are relatively trivial and easy to understand.  I already added a minor change to the `text` example to use `Vh` font size for the "hello bevy" text in the bottom right corner. If you change the size of the window, you should see the text change size in response. The text initially flickers before it updates because of some unrelated asset/image changes that mean that font textures aren't ready until the frame after the text update that changes the font size.

Most of the example migrations were automated using regular expressions, and there are bound to be mistakes in those changes. It's infeasible to check every single example thoroughly, but it's early enough in the release cycle that I don't think we should be too worried if a few bugs slip in.

---------

Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
2026-02-02 22:52:33 +00:00
Greeble 9d2db8838f Improve frustum culling of skinned meshes through per-joint bounds (#21837)
## Objective

Mostly fix #4971 by adding a new option for updating skinned mesh `Aabb`
components from joint transforms.


https://github.com/user-attachments/assets/c25b31fa-142d-462b-9a1d-012ea928f839

This fixes cases where vertex positions are only modified through
skinning. It doesn't fix other cases like morph targets and vertex
shaders.

The PR kind of upstreams
[`bevy_mod_skinned_aabb`](https://github.com/greeble-dev/bevy_mod_skinned_aabb),
but with some changes to make it simpler and more reliable.

### Dependencies

- (MERGED) #21732 (or something similar) is desirable to make the new
option work with `RenderAssetUsages::RENDER_WORLD`-only meshes.
- This PR is authored as if 21732 has landed. But if that doesn't happen
then I can adjust this PR to note the limitation.
- (Optional) #21845 adds an option related to skinned mesh bounds.
  - Either PR can land first - the second will need to be updated.

## Background

If a main world entity has a `Mesh3d` component then it's automatically
assigned an `Aabb` component. This is done by `bevy_camera` or
`bevy_gltf`. The `Aabb` is used by `bevy_camera` for frustum culling. It
can also be used by `bevy_picking` as an optimization, and by third
party crates.

But there's a problem - the `Aabb` can be wrong if something changes the
mesh's vertex positions after the `Aabb` is calculated. This can be done
by vertex shaders - notably skinning and morph targets - or by mutating
the `Mesh` asset (#4294).

For the skinning case, the most common solution has been to disable
frustum culling via the `NoFrustumCulling` component. This is simple,
and might even be the most efficient approach for apps where meshes tend
to stay on-screen. But it's annoying to implement, bad for apps where
meshes are often off-screen, and it only fixes frustum culling - it
doesn't help other systems that use the `Aabb`.

## Solution

This PR adds a reliable and reasonably efficient method of updating the
`Aabb` of a skinned mesh from its animated joint transforms. See the
"How does it work" section for more detail.

The glTF loader can add skinned bounds automatically if a new
`GltfSkinnedMeshBoundsPolicy` option is enabled in `GltfPlugin` or
`GltfLoaderSettings`:

```rust
app.add_plugins(DefaultPlugins.set(GltfPlugin {
    skinned_mesh_bounds_policy: GltfSkinnedMeshBoundsPolicy::Dynamic,
    ..default()
}))
```

_The new glTF loader option is enabled by default_. I think this is the
right choice for several reasons:

- Bugs caused by skinned mesh culling have been a regular pain for both
new and experienced users. Now the most common case Just Works(tm).
- The CPU cost is modest (see later section), and sophisticated users
can opt-out.
- GPU limited apps might see a performance increase if the user was
previously disabling culling.

Non-glTF cases require some manual steps. The user must ask `Mesh` to
generate the skinned bounds, and then add the `DynamicSkinnedMeshBounds`
marker component to their mesh entity.

```rust
mesh.generate_skinned_mesh_bounds()?;
let mesh_asset = mesh_assets.add(mesh);
entity.insert((Mesh3d(mesh_asset), DynamicSkinnedMeshBounds));
```

See the `custom_skinned_mesh` example for real code.

## Bonus Features

### `GltfSkinnedMeshBoundsPolicy::NoFrustumCulling`

This is a convenience for users who prefer the `NoFrustumCulling`
workaround, but want to avoid the hassle of adding it after a glTF scene
has been spawned.

```rust
app.add_plugins(DefaultPlugins.set(GltfPlugin {
    skinned_mesh_bounds_policy: GltfSkinnedMeshBoundsPolicy::NoFrustumCulling,
    ..default()
}))
```

PR #21845 is also adding an option related to skinned mesh bounds. I'm
fine if that PR lands first - I'll update this PR to include the option.

### Gizmos

`bevy_gizmos::SkinnedMeshBoundsGizmoPlugin` can draw the per-joint
AABBs.

```rust
fn toggle_skinned_mesh_bounds(mut config: ResMut<GizmoConfigStore>) {
    config.config_mut::<SkinnedMeshBoundsGizmoConfigGroup>().1.draw_all ^= true;
}
```

The name is debatable. It's not technically drawing the bounds of the
skinned mesh - it's drawing the per-joint bounds that contribute to the
bounds of the skinned mesh.

## Testing

```sh
cargo run --example test_skinned_mesh_bounds

# Press `B` to show mesh bounds, 'J' to show joint bounds.
cargo run --example scene_viewer --features "free_camera" -- "assets/models/animated/Fox.glb"
cargo run --example scene_viewer --features "free_camera" -- "assets/models/SimpleSkin/SimpleSkin.gltf"

# More complicated mesh downloaded from https://github.com/KhronosGroup/glTF-Sample-Assets/tree/main/Models/RecursiveSkeletons
cargo run --example scene_viewer --features "free_camera" -- "RecursiveSkeletons.glb"

cargo run --example custom_skinned_mesh
```

I also hacked `custom_skinned_mesh` to simulate awkward cases like
rotated and off-screen entities.

## How Does It Work?

<details><summary>Click to expand</summary>

### Summary

`Mesh::generated_skinned_mesh_bounds` calculates an AABB for each joint
in the mesh - the AABB encloses all the vertices skinned to that joint.
Then every frame, `bevy_camera::update_skinned_mesh_bounds` uses the
current joint transforms to calculate an `Aabb` that encloses all the
joint AABBs.

This approach is reliable, in that the final `Aabb` will always enclose
the skinned vertices. But it can be larger than necessary. In practice
it's tight enough to be useful, and rarely more than 50% bigger.

This approach works even with non-rigid transforms and soft skinning. If
there's any doubt then I can add more detail.

### Awkward Bits

The solution is not as simple and efficient as it could be.

#### Problem 1: Joint transforms are world-space, `Aabb` is
entity-space.

- Ideally we'd use the world-space joint transforms to calculate a
world-space `Aabb`, but that's not possible.
- The obvious solution is to transform the joints to entity-space, so
the `Aabb` is directly calculated in entity-space.
  - But that means an extra matrix multiply per joint.
- This PR calculates the `Aabb` in world-space and then transforms it to
entity-space.
- That avoids a matrix multiply per-joint, but can increase the size of
the `Aabb`.

#### Problem 2: Joint AABBs are in a surprising(?) space.

- When creating joint AABBs from a mesh, the intuitive solution would be
to calculate them in joint-space.
- Then the update just has to transform them by the world-space joint
transform.
- But to calculate them in joint-space we need both the bind pose vertex
positions and the bind pose joint transforms.
- These two parts are in separate assets - `Mesh` and
`SkinnedMeshInverseBindposes` - and those assets can be mixed and
matched.
- So we'd need to calculate a `SkinnedMeshBoundsAsset` for each
combination of `Mesh` and `SkinnedMeshInverseBindposes`.
- (`bevy_mod_skinned_aabb` uses this approach - it's slow and fragile.)
- This PR calculates joint AABBs in *mesh-space* (or more strictly
speaking: bind pose space).
  - That can be done with just the `Mesh` asset.
- One downside is that the update needs an extra matrix multiply so we
can go from mesh-space to world-space.
- However, this might become a performance advantage if frustum culling
changes - see the "Future Options" section.
- Another minor downside is that mesh-space AABBs (red in the screenshot
below) tend to be bigger than joint-space AABBs (green), since joints
with one long axis might be at an awkward angle in mesh-space.

<img width="1085" height="759" alt="image"
src="https://github.com/user-attachments/assets/a02a28c3-8882-412c-9be1-64109b767da7"
/>

### Future Options

For frustum culling there's a cheeky way to optimize and simplify
skinned bounds - put frustum culling in the renderer and calculate a
world-space AABB during `extract_skins`. The joint transform will be
already loaded and in the right space, so we can avoid an entity lookup
and matrix multiply. I estimate this would make skinned bounds 3x
faster.

Another option is to change main world frustum culling to use a
world-space AABB. So there would be a new `GlobalAabb` component that
gets updated each frame from `Aabb` and the entity transform (which is
basically the same as transform propagation and the relationship between
`Transform` and `GlobalTransform`). This has some advantages and
disadvantages but I won't get into them here - I think putting frustum
culling into the renderer is a better option.

(Note that putting frustum culling into the renderer doesn't mean
removing the current main world visibility system - it just means the
main world system would be separate opt-in system)

</details>

## Performance

<details><summary>Click to expand</summary>

### Initialization

Creating the skinned bounds asset for `Fox.glb` (576 verts, 22 skinned
joints) takes **0.03ms**. Loading the whole glTF takes 8.7ms, so this is
a **<1% increase**.

### Per-Frame

The `many_foxes` example has 1000 skinned meshes, each with 22 skinned
joints. Updating the skinned bounds takes **0.086ms**. This is a
throughput of roughly 250,000 joints per millisecond, using two threads.

<img width="2404" height="861" alt="image"
src="https://github.com/user-attachments/assets/c27165ae-dc6c-4f6b-bbfb-4e211ab0263c"
/>

The whole animation update takes 3.67ms (where "animation update" =
advancing players + graph evaluation + transform propagation). So we can
kinda sorta claim that this PR increases the cost of skinned animation
by roughly **3%**. But that's very hand-wavey and situation dependent.

This was tested on an AMD Ryzen 7900 but with
`TaskPoolOptions::with_num_threads(6)` to simulate a lower spec CPU.
Comparing against a few other threading options:

- Non-parallel: **0.141ms**.
- 6 threads (2 compute threads): **0.086ms**.
- 24 threads (15 compute threads): **0.051ms**.

So the parallel iterator is better but quickly hits diminishing returns
as the number of threads increases.

### Future Options

The "How Does It Work" section mentions moving skinned mesh bounds into
the renderer's skin extraction. Based on some microbenchmarks, I
estimate this would reduce non-parallel `many_foxes` from 0.141ms to
0.049ms, so roughly 3x faster. Requiring AVX2 (to enable broadcast
loads) or pre-splatting (to fake broadcast loads for SSE) would knock
off another 25%. And fancier SIMD approaches could do better again.

There's also approaches that trade reliability for performance. For
character rigs, an effective optimization is to fold face and finger
joints into a single bound on the head and hand joints. This can reduce
the number of joints required by 50-80%.

</details>

## FAQ

<details><summary>Click to expand</summary>

#### Why can't it be automatically added to any mesh? Then the glTF
importer and custom mesh generators wouldn't need special logic.

`bevy_mod_skinned_aabb` took the automatic approach, and I don't think
the outcome was good. It needs some surprisingly fiddly and fragile
logic to decide when an entity has the right combination of assets in
the right loaded state. And it can never work with
`RenderAssetUsages::RENDER_WORLD`.

So this PR takes a more modest and manual approach. I think there's
plenty of scope to generalise and automate as the asset pipeline
matures. If the glTF importer becomes a purer glTF -> BSN transform,
then adding skinned bounds could be a general scene/asset transform
that's shared with other importers and custom mesh generators.

#### Why is the data in `Mesh`? Shouldn't it go in `SkinnedMesh` or
`SkinnedMeshInverseBindposes`?

That might seem intuitive, but it wouldn't work in practice - the data
is derived from `Mesh` alone. `SkinnedMesh` doesn't work because it's
per mesh instance, so the data would be duplicated.
`SkinnedMeshInverseBindposes` doesn't work because it can be shared
between multiple meshes.

The names are a bit misleading - `Mesh` does contain some skinning data,
while `SkinnedMesh` and `SkinnedMeshInverseBindposes` are more like
joint bindings one step removed from the vertex data.

#### Why not put the bounds on the joint entities?

This is surprisingly tricky in practice because multiple meshes can be
bound to the same joint entity. So there would need to be logic that
tracks the bindings and updates the bounds as meshes are added and
removed.

#### Why is the `DynamicSkinnedMeshBounds` component required?

It's an optimisation for users who want to opt out. It might also be
useful for future expansion, like adding options to approximate the
bounds with an AABB attached to a single joint.

#### Why are the update system and `DynamicSkinnedMeshBounds` component
in `bevy_camera`? Shouldn't they be in `bevy_mesh`?

`bevy_camera` is the owner and main user of `Aabb`, and already has some
mesh related logic (`calculate_bounds` automatically adds an `Aabb` to
mesh entities). So putting it in `bevy_camera` is consistent with the
current structure. I'd agree that it's a little awkward though and could
change in future.

</details>

## What Do Other Engines Do?

<details><summary>Click to expand</summary>

- **Unreal**: Automatically uses [collision
shapes](https://dev.epicgames.com/documentation/en-us/unreal-engine/physics-asset-editor-in-unreal-engine)
attached to joints, which is similar to this PR in practice but fragile
and inefficient. Also supports various fixed bounds options.
- **Unity**: Fixed bounds attached to the root bone. Automatically
calculated from animation poses or specified manually
([documentation](https://docs.unity3d.com/6000.4/Documentation/Manual/troubleshooting-skinned-mesh-renderer-visibility.html)).
- **Godot**: Appears to use roughly the same method as this PR, although
I didn't 100% confirm. See
[`MeshStorage::mesh_get_aabb`](https://github.com/godotengine/godot/blob/fafc07335bdecacd96b548c4119fbe1f47ee5866/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp#L650)
and
[`RendererSceneCull::_update_instance_aabb`](https://github.com/godotengine/godot/blob/235a32ad11f40ecba26d6d9ceea8ab245c13adb0/servers/rendering/renderer_scene_cull.cpp#L1991).
- **O3DE**: Fixed bounds attached to root bone, plus option to
approximate the AABB from joint origins and a fudge factor.
- **Northlight** (Remedy, Alan Wake 2): Specifically for vegetation,
calculates bounds from joint extents on GPU
([source](https://gdcvault.com/play/1034310/Large-Scale-GPU-Based-Skinning),
slide 48)

An approach that's been proposed several times for Bevy is copying
Unity's "fixed AABB from animation poses". I think this is more
complicated and less reliable than many people expect. More complicated
because linking animations to meshes can often be difficult. Less
reliable because it doesn't account for ragdolls and procedural
animation. But it could still be viable for for simple cases like a
single self-contained glTF with basic animation.

</details>

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-01-26 04:25:59 +00:00
Aevyrie a88af65738 Contact Shadows (#22382)
# Objective

- Implement contact shadows to add fine shadow detail where shadow
cascades cannot.

## Solution

- Extend our existing pbr implementation using our existing raymarching
functions.

---

## Showcase

<img width="1824" height="1180" alt="image"
src="https://github.com/user-attachments/assets/e93b79c5-c596-4a9e-b94d-20bdde1d863b"
/>

<img width="1824" height="1180" alt="image"
src="https://github.com/user-attachments/assets/0fd7dffa-60b8-4b92-8fad-7f993d4d89dd"
/>


https://github.com/user-attachments/assets/e74b190d-9ae3-4aaf-97f0-b520930a0667


https://github.com/user-attachments/assets/e80ccb26-bbaa-4d25-a823-8ea12354c5b9


https://github.com/user-attachments/assets/b04f4b00-92bd-4a2f-b7dd-5157d8fbe0ab

<img width="1073" height="685" alt="image"
src="https://github.com/user-attachments/assets/b7629908-dd32-48db-8ee7-a4d2dd8f66c2"
/>

<img width="1073" height="685" alt="image"
src="https://github.com/user-attachments/assets/3de0258e-9191-4180-ac57-41b32e1205bd"
/>

<img width="1073" height="685" alt="image"
src="https://github.com/user-attachments/assets/951477f9-e9a9-426f-ae8d-18ae50cc7b85"
/>

<img width="1073" height="685" alt="image"
src="https://github.com/user-attachments/assets/2291453c-da57-4fcc-a6b0-f60f6eac6cbb"
/>

<img width="1073" height="685" alt="image"
src="https://github.com/user-attachments/assets/5820cdff-ea54-4294-b520-2a8d8dc24996"
/>

<img width="1073" height="685" alt="image"
src="https://github.com/user-attachments/assets/3ea16481-7689-4e99-87e2-1589f1532e4c"
/>

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: charlotte 🌸 <charlotte.c.mcelwain@gmail.com>
2026-01-13 21:51:39 +00:00
Trashtalk217 d431f7e139 Split AmbientLight into two (#21595)
# Objective

For resources-as-components (#19731), structs mustn't doubly derive both
`Component` and `Resource`.

## Solution

Split `AmbientLight` in two: `AmbientLight` (the resource) and
`AmbientLightOverride` (the component).

## Testing

I initially made two structs `AmbientLightComponent` and
`AmbientLightResource`, and replaced every mention with the relevant one
to ensure that I didn't confuse the two.

## Notes

- I don't know if the names are correct. I kept the easiest name for the
resource, as that's the one most often used.
- I haven't provided any conversion methods as there are already plans
to replace the component variant with something else.

---------

Co-authored-by: atlv <email@atlasdostal.com>
2025-10-21 23:04:39 +00:00
Carter Anderson 4d74baf1ae BufferedEvent -> Message Rename (#20953)
This renames the concept of `BufferedEvent` to `Message`, and updates
our APIs, comments, and documentation to refer to these types as
"messages" instead of "events". It also removes/updates anything that
considers messages to be "observable", "listenable", or "triggerable".

This is a followup to https://github.com/bevyengine/bevy/pull/20731,
which omitted the `BufferedEvent -> Message` rename for brevity.

See that post for rationale.
2025-09-10 21:04:15 +00:00
Carter Anderson eda118d033 Event Rearchitecture (#20731)
There is general consensus that our terminology for Events, "entity
events", Observers, and BufferedEvents needs clarity. Additionally, many
of us also agree that the current Observer system would benefit from
additional static-ness: currently it is assumed that you can use events
in pretty much any context, and they all go through the exact same code
path.

Alice put forth a proposal to [Overhaul
Observers](https://hackmd.io/@bevy/rk4S92hmlg), and we have already
partially implemented it for 0.17. I think it does a great job of
outlining many of the issues at play, and it solves them reasonably
well. But I _also_ think the proposed solution isn't yet ideal. Given
that it is already partially implemented for 0.17, it is a breaking
change, _and_ given that we have already broken the Observer API a
number of times, I think we need to sort this out before the next
release.

This is a big changeset, but it is _largely_ just a reframing of what is
already there. I haven't fundamentally changed the behaviors. I've just
refined and constrained in a way that allows us to do what we are
currently doing in a clearer, simpler, and more performant way.

First, I'll give some quick notes on Alice's proposal (which you all
should read if you haven't yet!):
### Notes on Alice's Proposal
- I like the move toward a more static API
- I think we've gone too far down the "separate terminology" path. The
proposal introduces a zoo of apis, terms, and "subterms". I think we
need to simplify our concepts and names to make this all easier to talk
about and use in practice.
- BroadcastEvent feels like the wrong name. EntityEvent is also
"broadcast" in the exact same way
- BufferedEvent is a completely different system than EntityEvent and
BroadcastEvent. This muddles concepts too much. It needs its own
standalone, single-word concept name.
- "Universal observers": I think this should be fully context driven,
rather than needing encoding in the API.
- I agree we can't get rid of buffered events, and that merging them
with "broadcast events" isn't helpful
- I'm not quite sure how we'd make the proposed PropagateEvent subtrait
work transparently. This can't be "layered on top" as a trait. It needs
to be baked in at more fundamental level.
* I don't like `app.add_broadcast_observers()`,
`app.add_universal_observers()`, `Observer::entity_observer`,
`Observer::broadcast`, etc. The `On` event should statically determine
whether an observer is an "entity observer" or a "broadcast" Observer.
This would already be encoded in the type system and is therefore
something we can do on the developer's behalf. Likewise, any observer
being registered at a top level is inherently _not_ a specific entity
observer. All of these variants serve to make users guess and poke
around in a way that is unnecessary. I want simple one word concept
names, single constructors, etc.
### Proposed Principals
- Static-ness:
- Events should only be usable in the context they were defined to be
used.
- When triggered, Observers should *only* have access to fields and
behaviors that are relevant:
- Dont return Option or PLACEHOLDER: the field or function shouldn't
exist
- Entity events that don't support propagation shouldn't expose that
functionality
- Don't do unnecessary work at runtime
- Event triggers shouldn't branch through every potential event code
path
- Don't clone potentially large lists of event context unnecessarily
(Ex: we currently clone the component list for every observer
invocation)
- Minimize codegen
	- Don't recompile things redundantly.
	- Don't compile unnecessary code paths.
- Clear and Simple
- Minimize the number of concept names floating around, and lock each
concept down heavily to a specific context
- I'm convinced at this point that "buffered events" and "observer
events" sharing concept names is wrong. We need two clean and clear
terms, and I'm willing to give "buffered events" a slightly worse name
if it means "observer events" can be nicer.
- Don't throw the concept name "Event" out ... it is a very good name.
Instead, constrain it to one specific thing.
	- Minimize our API surface
- Events contain all context, including what used to be the "target".
This lets people define the "target" name that makes the most sense for
the context, and lets the documentation fully describe the context of
that "target".
### Concepts
- **Event** (the thing you "observe")
- Rationale: "Event" is the clear choice for this concept. An "event"
feels like something that happens in real time. "Event observers" are
things that observe events when they occur (are triggered).
Additionally, this is the concept that "propagates", and "event
propagation" is a term people understand.
- **Trigger**: (the verb that "causes" events to happen for targets).
Events are Triggered. This can include additional context/ data that is
passed to observers / informs the trigger behavior. Events have
_exactly_ one Trigger. If you want a different trigger behavior, define
a new event. This makes the system more static, more predictable, and
easier to understand and document. `world.trigger_ref_with` makes it
possible to pass in mutable reference to your own Trigger data, making
it possible to customize the input trigger data and read out the final
trigger data.
- **Observer** (the thing that "observes" events): An event's `Trigger`
determines which observers will run.
- **Event Types**: You can build any "type" of event. The concept of a
"target" has been removed. Instead, define a `Trigger` that expects a
specific kind of event (ex: `E: EntityEvent`).
- **EntityEvent** We add a new `EntityEvent` trait, which defines an
`event.entity()` accessor. This is used by the `Trigger` impls :
`EntityTrigger`, `PropagateEntityTrigger`, and
`EntityComponentsTrigger`.
- **Message** (the buffered thing you "read" and "write")
- `Message` is a solid metaphor for what this is ... it is data that is
written and then at some later point read by someone / something else. I
expect existing consumers of "buffered events" to lament this name
change, as "event" feels nicer. But having a separate name is within
everyone's best interest.
	- **MessageReader** (the thing that reads messages)
	- **MessageWriter** (the thing that writes messages)
### The Changes
- `Event` trait changes
	- Event is now used exclusively by Observers
- Added `Event::Trigger`, which defines what trigger implementation this
event will use
- Added the `Trigger` trait
- All of the shared / hard-coded observer trigger logic has been broken
out into individual context-specific Trigger traits.
- "Trigger Targets" have been removed.
- Instead, Events, in combination with their Trigger impl, decide how
they will be triggered. In general, this means that Events now include
their "targets" as fields on the event.
- APIs like `trigger_targets` have been replaced by `trigger`, which can
now be used for any `Event`
- `EntityEvent` trait changes
- Propagation config has been removed from the `EntityEvent` trait. It
now lives on the `Trigger` trait (specifically the
`PropagateEntityTrigger` trait).
- `EntityEvent` now provides `entity / entity_mut` accessors for the
Event it is implemented for
- `EntityEvent` defaults to having no propagation (uses the simpler
`EntityTrigger`)
- `#[entity_event(propagate)]` enables the "default" propagation logic
(uses ChildOf). The existing `#[entity_event(traversal = X)]` has been
renamed to `#[entity_event(propagate = X)`
- Deriving `EntityEvent` requires either a single `MyEvent(Entity)`, the
`entity` field name (`MyEvent { entity: Entity}`), or `MyEvent {
#[event_entity] custom: Entity }`
- Animation event changes
- Animation events now have their own `AnimationEvent` trait, which sets
the `AnimationEventTrigger`. This allows developers to pass in events
that _dont_ include the Entity field (as this is set by the system). The
custom trigger also opens the doors to cheaply passing in additional
animation system context, accessible through `On`
- `EntityComponentsTrigger`
- The built in Add/Remove/etc lifecycle events now use the
`EntityComponentsTrigger`, which passes in the components as additional
state. This _significantly_ cuts down on clones, as it does a borrow
rather than cloning the list into _each_ observer execution.
	- Each event now has an `entity` field.
- Style changes
- Prefer the event name for variables: `explode: On<Explode>` not
`event: On<Explode>`
- Prefer using the direct field name for the entity on entity events,
rather than `event.entity()`. This allows us to use more specific names
where appropriate, provides better / more contextual docs, and coaches
developers to think of `On<MyEvent>` _as_ the event itself.

Take a look at the changes to the examples and the built-in events to
see what this looks like in practice.

### Downsides
- Moving the "target" into the event adds some new constraints:
- Triggering the same event for multiple entities requires multiple
trigger calls. For "expensive" events (ex: lots of data attached to the
event), this will be more awkward. Your options become:
		-  Create multiple instances of the event, cloning the expensive data
- Use `trigger_ref`, and mutate the event on each call to change the
target.
- Move the "expensive" shared data into the Trigger, and use
`trigger_ref_with``
- We could build a new EntityEvent method that abstracts over the "event
mutation" behavior and provides something like the old `trigger_target`
behavior.
- Use a different `EntityTargetTrigger` (not currently provided by bevy,
but we could), which brings back the old behavior. This would be used
with `trigger_with` to replicate the old pattern:
`world.trigger_with(MyEvent, [e1, e2].into())` (or we could make the
`into()` implicit)
- Bubbling the event involves mutating the event to set the entity. This
means that `trigger_ref` will result in the event's
`EntityEvent::entity()` being the final bubbled entity instead of the
initial entity.
- Some APIs (trivially) benefit from the "target entity" being separate
from the event. Specifically, this new API requires changes to the
"Animation Event" system in AnimationPlayer. I think this is actually a
good change set, as it allows us to:
- Cheaply expose more animation state as part of a new
AnimationEventTrigger impl
- Move that "implict" entity target provided by the AnimationPlayer into
the AnimationEventTrigger
- Encode the "animation event trigger-ness" of the event into the type
itself (by requiring `#[event(trigger = AnimationEventTrigger)]`)
- By not implementing Default for AnimationEventTrigger, we can block
animation events from being fired manually by the user.

### Draft TODO
- [x] Fill in documentation and update existing docs
- [ ] Benchmark: I expect this impl to be significantly faster. There
might also be tangible binary size improvements, as I've removed a lot
of redundant codegen.
- [x] Update release notes and migration guides

### Next Steps
- The `BufferedEvent -> Message` rename was not included to keep the
size down.

Fixes #19648

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
2025-09-09 23:48:55 +00:00
atlv eed2e0ebe6 Fix missed RedrawRequested and WindowCloseRequested events with UpdateMode::Reactive (part 2) [ADOPTED] (#20624)
# Objective

- Adopt and rebase #18549

## Solution

- merge conflicts were just if let chains

## Testing

- example added by the PR works on mac

---------

Co-authored-by: Matt Thompson <matt@boondocker.io>
Co-authored-by: Aaron Loucks <aloucks@cofront.net>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
2025-09-07 07:51:02 +00:00
atlv f6b77e4e49 bevy_post_process (#20778)
# Objective

Split out post process effects from bevy_core_pipeline because they are
not core pipelines.

## Solution

@IceSentry proposed something like this, not sure if the split is
exactly as he envisioned but this seems reasonable to me.

The goal is to move absolutely everything possible out of
bevy_core_pipelines to unblock bevy_pbr/bevy_sprite_render compilation.

Future PRs may attempt to move more little bits out.

## Testing
2025-09-05 04:26:08 +00:00
TheBlckbird 13877fa84d Add a new trait to accept more types in the Val-helper functions (#20551)
# Objective

- Allow the `Val`-helper functions to accept more types besides just
`f32`

Fixes #20549

## Solution

- Adds a new trait that can be implemented for numbers
- That trait has a method that converts `self` to `f32`

## Testing

- I tested it using Rust's testing framework (although I didn't leave
the tests in, as I don't deem them important enough)

<details>
  <summary>Rust test</summary>

```rust
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_val_helpers_work() {
        let p = px(10_u8);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_u16);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_u32);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_u64);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_u128);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_i8);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_i16);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_i32);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_i64);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_i128);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10.3_f32);
        assert_eq!(p, Val::Px(10.3));

        let p = px(10.6_f64);
        assert_eq!(p, Val::Px(10.6));
    }
}
```
</details>

---

## Showcase

```rust
// Same as Val::Px(10.)
px(10);
px(10_u8);
px(10.0);
```
2025-08-29 20:18:57 +00:00
BigWingBeat 121981b016 Remove redundant number conversion in window resolution (#20582)
# Objective

`WindowResolution` stores the width and height as `u32`, but the
constructors take `f32` and just convert straight to `u32`.
Additionally, everywhere in Bevy where a `WindowResolution` is
constructed specifies whole numbers, making the use of a float entirely
pointless.

## Solution

Replace the `f32` constructors with `u32` constructors.

I also decided to change the generic `I: Into<f32>` tuple and array
constructors to only take u32 instead of `I: Into<u32>` for UX reasons.
It allows formatting those constructors as `(1920, 1080).into()`, as the
compiler can infer that the numbers are u32. Keeping those impls generic
prevents that inference, and because the default number type (i32)
doesn't impl `Into<u32>`, that would require formatting it explicitly as
`(1920u32, 1080u32).into()` to compile.

In practice, these generic constructors were only used with whole-number
f32 values anyway, like everything else, so them being generic wasn't
actually leveraged anywhere.

## Testing

Chased type errors until they were all gone
2025-08-20 18:02:41 +00:00
atlv 68b848217f Yeet RenderAssetUsages re-export (#20498)
# Objective

- Forgor to yeet this

## Solution

- rember and yeet

## Testing

cargo check --examples --all-features
2025-08-11 01:42:08 +00:00
atlv 03dd839b82 Use bevy::camera in examples instead of bevy::render::camera re-export (#20477)
# Objective

- Prepare for removing re-exports

## Solution

- title

## Testing

- cargo check --examples
2025-08-09 21:09:48 +00:00
atlv acc8f6d455 Stop using mesh re-exports in-repo and add bevy_mesh prelude (#20473)
# Objective

- prepare to remove bevy_mesh re-export from bevy_render. This will be
done in 0.18, but we might as well prepare for it now.

## Solution

- Add a prelude and use bevy_mesh directly. After this pr and #20471, we
will be ready.

## Testing

- cargo check --examples
2025-08-09 17:46:27 +00:00
andriyDev 9d4bfdbb53 Use RenderStartup for CopyDeferredLightingIdPipeline. (#20195)
# Objective

- Progress towards #19887.
- This migration actually caught a segfault on Linux + Vulkan + llvmpipe
software rendering driver + (maybe) `xvfb-run`
- It seems the reason for this is that we are concurrently terminating
the program (which trigger's LLVMs `atexit` handlers) while we are also
compiling pipelines in parallel. It seems LLVM code is not quite
multithread safe in this situation.
    - Thanks to @kristoff3r for figuring out this segfault!
    - I still have no idea why this PR triggers it and not others.

## Solution

Most of this is the same as all the other `RenderStartup` migrations.
- Convert FromWorld impls to RenderStartup systems.

In addition, I had to 1) enable synchronous pipeline compilation, 2)
disable pipelined rendering in the `ambiguity_detection` test. This
ensures that 1) the render thread just blocks on pipeline compilation
rather than letting it run in another thread, 2) we don't leave
`App::update` until the render thread finishes. So therefore, there
won't be any pipeline compilation happening by the time the test ends.

## Testing

- I ran the run-examples-linux-vulkan Github action many, many times and
segfaults were consistent until this PR! Now they don't seem to happen
anymore.
2025-07-21 23:03:29 +00:00
Tim 4e9e78c31e Split BufferedEvent from Event (#20101)
# Objective

> I think we should axe the shared `Event` trait entirely
It doesn't serve any functional purpose, and I don't think it's useful
pedagogically
@alice-i-cecile on discord

## Solution

- Remove `Event` as a supertrait of `BufferedEvent`
- Remove any `Event` derives that were made unnecessary
- Update release notes

---------

Co-authored-by: SpecificProtagonist <vincentjunge@posteo.net>
2025-07-14 21:31:48 +00:00
AlephCubed 3aed85a88b Rename send_event and similar methods to write_event (#20017)
Fixes: #18963
Follows up on: #17977
Adopts: #18966

In 0.16, `EventWriter::send` was renamed to `EventWriter::write`, but
many methods were missed (sorry about that). This completes that
refactor by renaming all `send` methods and internals.

| Old | New |

|-------------------------------------|--------------------------------------|
| `World::send_event` | `World::write_event` |
| `World::send_event_default` | `World::write_event_default` |
| `World::send_event_batch` | `World::write_event_batch` |
| `DeferredWorld::send_event` | `DeferredWorld::write_event` |
| `DeferredWorld::send_event_default` |
`DeferredWorld::write_event_default` |
| `DeferredWorld::send_event_batch` | `DeferredWorld::write_event_batch`
|
| `Commands::send_event` | `Commmands::write_event` |
| `Events::send` | `Events::write` |
| `Events::send_default` | `Events::write_default` |
| `Events::send_batch` | `Events::write_batch` |
| `RemovedComponentEvents::send` | `RemovedComponentEvents::write` |
| `command::send_event` | `commmand::write_event` |
| `SendBatchIds` | `WriteBatchIds` |

---------

Co-authored-by: shwwwa <shwwwa.dev@gmail.com>
2025-07-07 22:05:16 +00:00
Greeble 0f75142560 Add test for invalid skinned meshes (#18763)
## Objective

Add a test that would have caught #16929 and #18712.

## Solution

The PR adds a `test_invalid_skinned_mesh` example that creates various
valid and invalid skinned meshes. This is designed to catch panics via
CI, and can be inspected visually. It also tests skinned meshes + motion
blur.


![417958065-37df8799-b068-48b8-87a4-1f144e883c9c](https://github.com/user-attachments/assets/22b2fa42-628b-48a4-9013-76d6524cecf5)

The screenshot shows all the tests, but two are currently disabled as
they cause panics. #18074 will re-enable them.

### Concerns

- The test is not currently suitable for screenshot comparison.
- I didn't add the test to CI. I'm a bit unsure if this should be part
of the PR or a follow up discussion.
- Visual inspection requires understanding why some meshes are
deliberately broken and what that looks like.
- I wasn't sure about naming conventions. I put `test` in the name so
it's not confused with a real example.

## Testing

```
cargo run --example test_invalid_skinned_mesh
```

Tested on Win10/Nvidia, across Vulkan, WebGL/Chrome, WebGPU/Chrome.
2025-07-07 19:28:52 +00:00
Joona Aalto 38c3423693 Event Split: Event, EntityEvent, and BufferedEvent (#19647)
# Objective

Closes #19564.

The current `Event` trait looks like this:

```rust
pub trait Event: Send + Sync + 'static {
    type Traversal: Traversal<Self>;
    const AUTO_PROPAGATE: bool = false;
    
    fn register_component_id(world: &mut World) -> ComponentId { ... }
    fn component_id(world: &World) -> Option<ComponentId> { ... }
}
```

The `Event` trait is used by both buffered events
(`EventReader`/`EventWriter`) and observer events. If they are observer
events, they can optionally be targeted at specific `Entity`s or
`ComponentId`s, and can even be propagated to other entities.

However, there has long been a desire to split the trait semantically
for a variety of reasons, see #14843, #14272, and #16031 for discussion.
Some reasons include:

- It's very uncommon to use a single event type as both a buffered event
and targeted observer event. They are used differently and tend to have
distinct semantics.
- A common footgun is using buffered events with observers or event
readers with observer events, as there is no type-level error that
prevents this kind of misuse.
- #19440 made `Trigger::target` return an `Option<Entity>`. This
*seriously* hurts ergonomics for the general case of entity observers,
as you need to `.unwrap()` each time. If we could statically determine
whether the event is expected to have an entity target, this would be
unnecessary.

There's really two main ways that we can categorize events: push vs.
pull (i.e. "observer event" vs. "buffered event") and global vs.
targeted:

|              | Push            | Pull                        |
| ------------ | --------------- | --------------------------- |
| **Global**   | Global observer | `EventReader`/`EventWriter` |
| **Targeted** | Entity observer | -                           |

There are many ways to approach this, each with their tradeoffs.
Ultimately, we kind of want to split events both ways:

- A type-level distinction between observer events and buffered events,
to prevent people from using the wrong kind of event in APIs
- A statically designated entity target for observer events to avoid
accidentally using untargeted events for targeted APIs

This PR achieves these goals by splitting event traits into `Event`,
`EntityEvent`, and `BufferedEvent`, with `Event` being the shared trait
implemented by all events.

## `Event`, `EntityEvent`, and `BufferedEvent`

`Event` is now a very simple trait shared by all events.

```rust
pub trait Event: Send + Sync + 'static {
    // Required for observer APIs
    fn register_component_id(world: &mut World) -> ComponentId { ... }
    fn component_id(world: &World) -> Option<ComponentId> { ... }
}
```

You can call `trigger` for *any* event, and use a global observer for
listening to the event.

```rust
#[derive(Event)]
struct Speak {
    message: String,
}

// ...

app.add_observer(|trigger: On<Speak>| {
    println!("{}", trigger.message);
});

// ...

commands.trigger(Speak {
    message: "Y'all like these reworked events?".to_string(),
});
```

To allow an event to be targeted at entities and even propagated
further, you can additionally implement the `EntityEvent` trait:

```rust
pub trait EntityEvent: Event {
    type Traversal: Traversal<Self>;
    const AUTO_PROPAGATE: bool = false;
}
```

This lets you call `trigger_targets`, and to use targeted observer APIs
like `EntityCommands::observe`:

```rust
#[derive(Event, EntityEvent)]
#[entity_event(traversal = &'static ChildOf, auto_propagate)]
struct Damage {
    amount: f32,
}

// ...

let enemy = commands.spawn((Enemy, Health(100.0))).id();

// Spawn some armor as a child of the enemy entity.
// When the armor takes damage, it will bubble the event up to the enemy.
let armor_piece = commands
    .spawn((ArmorPiece, Health(25.0), ChildOf(enemy)))
    .observe(|trigger: On<Damage>, mut query: Query<&mut Health>| {
        // Note: `On::target` only exists because this is an `EntityEvent`.
        let mut health = query.get(trigger.target()).unwrap();
        health.0 -= trigger.amount();
    });

commands.trigger_targets(Damage { amount: 10.0 }, armor_piece);
```

> [!NOTE]
> You *can* still also trigger an `EntityEvent` without targets using
`trigger`. We probably *could* make this an either-or thing, but I'm not
sure that's actually desirable.

To allow an event to be used with the buffered API, you can implement
`BufferedEvent`:

```rust
pub trait BufferedEvent: Event {}
```

The event can then be used with `EventReader`/`EventWriter`:

```rust
#[derive(Event, BufferedEvent)]
struct Message(String);

fn write_hello(mut writer: EventWriter<Message>) {
    writer.write(Message("I hope these examples are alright".to_string()));
}

fn read_messages(mut reader: EventReader<Message>) {
    // Process all buffered events of type `Message`.
    for Message(message) in reader.read() {
        println!("{message}");
    }
}
```

In summary:

- Need a basic event you can trigger and observe? Derive `Event`!
- Need the event to be targeted at an entity? Derive `EntityEvent`!
- Need the event to be buffered and support the
`EventReader`/`EventWriter` API? Derive `BufferedEvent`!

## Alternatives

I'll now cover some of the alternative approaches I have considered and
briefly explored. I made this section collapsible since it ended up
being quite long :P

<details>

<summary>Expand this to see alternatives</summary>

### 1. Unified `Event` Trait

One option is not to have *three* separate traits (`Event`,
`EntityEvent`, `BufferedEvent`), and to instead just use associated
constants on `Event` to determine whether an event supports targeting
and buffering or not:

```rust
pub trait Event: Send + Sync + 'static {
    type Traversal: Traversal<Self>;
    const AUTO_PROPAGATE: bool = false;
    const TARGETED: bool = false;
    const BUFFERED: bool = false;
    
    fn register_component_id(world: &mut World) -> ComponentId { ... }
    fn component_id(world: &World) -> Option<ComponentId> { ... }
}
```

Methods can then use bounds like `where E: Event<TARGETED = true>` or
`where E: Event<BUFFERED = true>` to limit APIs to specific kinds of
events.

This would keep everything under one `Event` trait, but I don't think
it's necessarily a good idea. It makes APIs harder to read, and docs
can't easily refer to specific types of events. You can also create
weird invariants: what if you specify `TARGETED = false`, but have
`Traversal` and/or `AUTO_PROPAGATE` enabled?

### 2. `Event` and `Trigger`

Another option is to only split the traits between buffered events and
observer events, since that is the main thing people have been asking
for, and they have the largest API difference.

If we did this, I think we would need to make the terms *clearly*
separate. We can't really use `Event` and `BufferedEvent` as the names,
since it would be strange that `BufferedEvent` doesn't implement
`Event`. Something like `ObserverEvent` and `BufferedEvent` could work,
but it'd be more verbose.

For this approach, I would instead keep `Event` for the current
`EventReader`/`EventWriter` API, and call the observer event a
`Trigger`, since the "trigger" terminology is already used in the
observer context within Bevy (both as a noun and a verb). This is also
what a long [bikeshed on
Discord](https://discord.com/channels/691052431525675048/749335865876021248/1298057661878898791)
seemed to land on at the end of last year.

```rust
// For `EventReader`/`EventWriter`
pub trait Event: Send + Sync + 'static {}

// For observers
pub trait Trigger: Send + Sync + 'static {
    type Traversal: Traversal<Self>;
    const AUTO_PROPAGATE: bool = false;
    const TARGETED: bool = false;
    
    fn register_component_id(world: &mut World) -> ComponentId { ... }
    fn component_id(world: &World) -> Option<ComponentId> { ... }
}
```

The problem is that "event" is just a really good term for something
that "happens". Observers are rapidly becoming the more prominent API,
so it'd be weird to give them the `Trigger` name and leave the good
`Event` name for the less common API.

So, even though a split like this seems neat on the surface, I think it
ultimately wouldn't really work. We want to keep the `Event` name for
observer events, and there is no good alternative for the buffered
variant. (`Message` was suggested, but saying stuff like "sends a
collision message" is weird.)

### 3. `GlobalEvent` + `TargetedEvent`

What if instead of focusing on the buffered vs. observed split, we
*only* make a distinction between global and targeted events?

```rust
// A shared event trait to allow global observers to work
pub trait Event: Send + Sync + 'static {
    fn register_component_id(world: &mut World) -> ComponentId { ... }
    fn component_id(world: &World) -> Option<ComponentId> { ... }
}

// For buffered events and non-targeted observer events
pub trait GlobalEvent: Event {}

// For targeted observer events
pub trait TargetedEvent: Event {
    type Traversal: Traversal<Self>;
    const AUTO_PROPAGATE: bool = false;
}
```

This is actually the first approach I implemented, and it has the neat
characteristic that you can only use non-targeted APIs like `trigger`
with a `GlobalEvent` and targeted APIs like `trigger_targets` with a
`TargetedEvent`. You have full control over whether the entity should or
should not have a target, as they are fully distinct at the type-level.

However, there's a few problems:

- There is no type-level indication of whether a `GlobalEvent` supports
buffered events or just non-targeted observer events
- An `Event` on its own does literally nothing, it's just a shared trait
required to make global observers accept both non-targeted and targeted
events
- If an event is both a `GlobalEvent` and `TargetedEvent`, global
observers again have ambiguity on whether an event has a target or not,
undermining some of the benefits
- The names are not ideal

### 4. `Event` and `EntityEvent`

We can fix some of the problems of Alternative 3 by accepting that
targeted events can also be used in non-targeted contexts, and simply
having the `Event` and `EntityEvent` traits:

```rust
// For buffered events and non-targeted observer events
pub trait Event: Send + Sync + 'static {
    fn register_component_id(world: &mut World) -> ComponentId { ... }
    fn component_id(world: &World) -> Option<ComponentId> { ... }
}

// For targeted observer events
pub trait EntityEvent: Event {
    type Traversal: Traversal<Self>;
    const AUTO_PROPAGATE: bool = false;
}
```

This is essentially identical to this PR, just without a dedicated
`BufferedEvent`. The remaining major "problem" is that there is still
zero type-level indication of whether an `Event` event *actually*
supports the buffered API. This leads us to the solution proposed in
this PR, using `Event`, `EntityEvent`, and `BufferedEvent`.

</details>

## Conclusion

The `Event` + `EntityEvent` + `BufferedEvent` split proposed in this PR
aims to solve all the common problems with Bevy's current event model
while keeping the "weirdness" factor minimal. It splits in terms of both
the push vs. pull *and* global vs. targeted aspects, while maintaining a
shared concept for an "event".

### Why I Like This

- The term "event" remains as a single concept for all the different
kinds of events in Bevy.
- Despite all event types being "events", they use fundamentally
different APIs. Instead of assuming that you can use an event type with
any pattern (when only one is typically supported), you explicitly opt
in to each one with dedicated traits.
- Using separate traits for each type of event helps with documentation
and clearer function signatures.
- I can safely make assumptions on expected usage.
- If I see that an event is an `EntityEvent`, I can assume that I can
use `observe` on it and get targeted events.
- If I see that an event is a `BufferedEvent`, I can assume that I can
use `EventReader` to read events.
- If I see both `EntityEvent` and `BufferedEvent`, I can assume that
both APIs are supported.

In summary: This allows for a unified concept for events, while limiting
the different ways to use them with opt-in traits. No more guess-work
involved when using APIs.

### Problems?

- Because `BufferedEvent` implements `Event` (for more consistent
semantics etc.), you can still use all buffered events for non-targeted
observers. I think this is fine/good. The important part is that if you
see that an event implements `BufferedEvent`, you know that the
`EventReader`/`EventWriter` API should be supported. Whether it *also*
supports other APIs is secondary.
- I currently only support `trigger_targets` for an `EntityEvent`.
However, you can technically target components too, without targeting
any entities. I consider that such a niche and advanced use case that
it's not a huge problem to only support it for `EntityEvent`s, but we
could also split `trigger_targets` into `trigger_entities` and
`trigger_components` if we wanted to (or implement components as
entities :P).
- You can still trigger an `EntityEvent` *without* targets. I consider
this correct, since `Event` implements the non-targeted behavior, and
it'd be weird if implementing another trait *removed* behavior. However,
it does mean that global observers for entity events can technically
return `Entity::PLACEHOLDER` again (since I got rid of the
`Option<Entity>` added in #19440 for ergonomics). I think that's enough
of an edge case that it's not a huge problem, but it is worth keeping in
mind.
- ~~Deriving both `EntityEvent` and `BufferedEvent` for the same type
currently duplicates the `Event` implementation, so you instead need to
manually implement one of them.~~ Changed to always requiring `Event` to
be derived.

## Related Work

There are plans to implement multi-event support for observers,
especially for UI contexts. [Cart's
example](https://github.com/bevyengine/bevy/issues/14649#issuecomment-2960402508)
API looked like this:

```rust
// Truncated for brevity
trigger: Trigger<(
    OnAdd<Pressed>,
    OnRemove<Pressed>,
    OnAdd<InteractionDisabled>,
    OnRemove<InteractionDisabled>,
    OnInsert<Hovered>,
)>,
```

I believe this shouldn't be in conflict with this PR. If anything, this
PR might *help* achieve the multi-event pattern for entity observers
with fewer footguns: by statically enforcing that all of these events
are `EntityEvent`s in the context of `EntityCommands::observe`, we can
avoid misuse or weird cases where *some* events inside the trigger are
targeted while others are not.
2025-06-15 16:46:34 +00:00
Carter Anderson e9a0ef49f9 Rename bevy_platform_support to bevy_platform (#18813)
# Objective

The goal of `bevy_platform_support` is to provide a set of platform
agnostic APIs, alongside platform-specific functionality. This is a high
traffic crate (providing things like HashMap and Instant). Especially in
light of https://github.com/bevyengine/bevy/discussions/18799, it
deserves a friendlier / shorter name.

Given that it hasn't had a full release yet, getting this change in
before Bevy 0.16 makes sense.

## Solution

- Rename `bevy_platform_support` to `bevy_platform`.
2025-04-11 23:13:28 +00:00
Benjamin Brienen c3ff6d4136 Fix non-crate typos (#18219)
# Objective

Correct spelling

## Solution

Fix typos, specifically ones that I found in folders other than /crates

## Testing

CI

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-03-11 06:17:48 +00:00
jf908 bfe932d1f3 Rework WindowMode::Fullscreen API (#17525)
# Objective

- #16883 
- Improve the default behaviour of the exclusive fullscreen API.

## Solution

This PR changes the exclusive fullscreen window mode to require the type
`WindowMode::Fullscreen(MonitorSelection, VideoModeSelection)` and
removes `WindowMode::SizedFullscreen`. This API somewhat intentionally
more closely resembles Winit 0.31's upcoming fullscreen and video mode
API.

The new VideoModeSelection enum is specified as follows:

```rust
pub enum VideoModeSelection {
    /// Uses the video mode that the monitor is already in.
    Current,
    /// Uses a given [`crate::monitor::VideoMode`]. A list of video modes supported by the monitor
    /// is supplied by [`crate::monitor::Monitor::video_modes`].
    Specific(VideoMode),
}
```

### Changing default behaviour

This might be contentious because it removes the previous behaviour of
`WindowMode::Fullscreen` which selected the highest resolution possible.
While the previous behaviour would be quite easy to re-implement as
additional options, or as an impl method on Monitor, I would argue that
this isn't an implementation that should be encouraged.

From the perspective of a Windows user, I prefer what the majority of
modern games do when entering fullscreen which is to preserve the OS's
current resolution settings, which allows exclusive fullscreen to be
entered faster, and to only have it change if I manually select it in
either the options of the game or the OS. The highest resolution
available is not necessarily what the user prefers.

I am open to changing this if I have just missed a good use case for it.

Likewise, the only functionality that `WindowMode::SizedFullscreen`
provided was that it selected the resolution closest to the current size
of the window so it was removed since this behaviour can be replicated
via the new `VideoModeSelection::Specific` if necessary.

## Out of scope

WindowResolution and scale factor act strangely in exclusive fullscreen,
this PR doesn't address it or regress it.

## Testing

- Tested on Windows 11 and macOS 12.7
- Linux untested

## Migration Guide

`WindowMode::SizedFullscreen(MonitorSelection)` and
`WindowMode::Fullscreen(MonitorSelection)` has become
`WindowMode::Fullscreen(MonitorSelection, VideoModeSelection)`.
Previously, the VideoMode was selected based on the closest resolution
to the current window size for SizedFullscreen and the largest
resolution for Fullscreen. It is possible to replicate that behaviour by
searching `Monitor::video_modes` and selecting it with
`VideoModeSelection::Specific(VideoMode)` but it is recommended to use
`VideoModeSelection::Current` as the default video mode when entering
fullscreen.
2025-03-11 01:20:53 +00:00
Alice Cecile 2ad5908e58 Make Query::single (and friends) return a Result (#18082)
# Objective

As discussed in #14275, Bevy is currently too prone to panic, and makes
the easy / beginner-friendly way to do a large number of operations just
to panic on failure.

This is seriously frustrating in library code, but also slows down
development, as many of the `Query::single` panics can actually safely
be an early return (these panics are often due to a small ordering issue
or a change in game state.

More critically, in most "finished" products, panics are unacceptable:
any unexpected failures should be handled elsewhere. That's where the
new

With the advent of good system error handling, we can now remove this.

Note: I was instrumental in a) introducing this idea in the first place
and b) pushing to make the panicking variant the default. The
introduction of both `let else` statements in Rust and the fancy system
error handling work in 0.16 have changed my mind on the right balance
here.

## Solution

1. Make `Query::single` and `Query::single_mut` (and other random
related methods) return a `Result`.
2. Handle all of Bevy's internal usage of these APIs.
3. Deprecate `Query::get_single` and friends, since we've moved their
functionality to the nice names.
4. Add detailed advice on how to best handle these errors.

Generally I like the diff here, although `get_single().unwrap()` in
tests is a bit of a downgrade.

## Testing

I've done a global search for `.single` to track down any missed
deprecated usages.

As to whether or not all the migrations were successful, that's what CI
is for :)

## Future work

~~Rename `Query::get_single` and friends to `Query::single`!~~

~~I've opted not to do this in this PR, and smear it across two releases
in order to ease the migration. Successive deprecations are much easier
to manage than the semantics and types shifting under your feet.~~

Cart has convinced me to change my mind on this; see
https://github.com/bevyengine/bevy/pull/18082#discussion_r1974536085.

## Migration guide

`Query::single`, `Query::single_mut` and their `QueryState` equivalents
now return a `Result`. Generally, you'll want to:

1. Use Bevy 0.16's system error handling to return a `Result` using the
`?` operator.
2. Use a `let else Ok(data)` block to early return if it's an expected
failure.
3. Use `unwrap()` or `Ok` destructuring inside of tests.

The old `Query::get_single` (etc) methods which did this have been
deprecated.
2025-03-02 19:51:56 +00:00
AlephCubed 5f86668bbb Renamed EventWriter::send methods to write. (#17977)
Fixes #17856.

## Migration Guide
- `EventWriter::send` has been renamed to `EventWriter::write`.
- `EventWriter::send_batch` has been renamed to
`EventWriter::write_batch`.
- `EventWriter::send_default` has been renamed to
`EventWriter::write_default`.

---------

Co-authored-by: François Mockers <mockersf@gmail.com>
2025-02-23 21:18:52 +00:00
Zachary Harrold 9bc0ae33c3 Move hashbrown and foldhash out of bevy_utils (#17460)
# Objective

- Contributes to #16877

## Solution

- Moved `hashbrown`, `foldhash`, and related types out of `bevy_utils`
and into `bevy_platform_support`
- Refactored the above to match the layout of these types in `std`.
- Updated crates as required.

## Testing

- CI

---

## Migration Guide

- The following items were moved out of `bevy_utils` and into
`bevy_platform_support::hash`:
  - `FixedState`
  - `DefaultHasher`
  - `RandomState`
  - `FixedHasher`
  - `Hashed`
  - `PassHash`
  - `PassHasher`
  - `NoOpHash`
- The following items were moved out of `bevy_utils` and into
`bevy_platform_support::collections`:
  - `HashMap`
  - `HashSet`
- `bevy_utils::hashbrown` has been removed. Instead, import from
`bevy_platform_support::collections` _or_ take a dependency on
`hashbrown` directly.
- `bevy_utils::Entry` has been removed. Instead, import from
`bevy_platform_support::collections::hash_map` or
`bevy_platform_support::collections::hash_set` as appropriate.
- All of the above equally apply to `bevy::utils` and
`bevy::platform_support`.

## Notes

- I left `PreHashMap`, `PreHashMapExt`, and `TypeIdMap` in `bevy_utils`
as they might be candidates for micro-crating. They can always be moved
into `bevy_platform_support` at a later date if desired.
2025-01-23 16:46:08 +00:00
Carter Anderson 21f1e3045c Relationships (non-fragmenting, one-to-many) (#17398)
This adds support for one-to-many non-fragmenting relationships (with
planned paths for fragmenting and non-fragmenting many-to-many
relationships). "Non-fragmenting" means that entities with the same
relationship type, but different relationship targets, are not forced
into separate tables (which would cause "table fragmentation").

Functionally, this fills a similar niche as the current Parent/Children
system. The biggest differences are:

1. Relationships have simpler internals and significantly improved
performance and UX. Commands and specialized APIs are no longer
necessary to keep everything in sync. Just spawn entities with the
relationship components you want and everything "just works".
2. Relationships are generalized. Bevy can provide additional built in
relationships, and users can define their own.

**REQUEST TO REVIEWERS**: _please don't leave top level comments and
instead comment on specific lines of code. That way we can take
advantage of threaded discussions. Also dont leave comments simply
pointing out CI failures as I can read those just fine._

## Built on top of what we have

Relationships are implemented on top of the Bevy ECS features we already
have: components, immutability, and hooks. This makes them immediately
compatible with all of our existing (and future) APIs for querying,
spawning, removing, scenes, reflection, etc. The fewer specialized APIs
we need to build, maintain, and teach, the better.

## Why focus on one-to-many non-fragmenting first?

1. This allows us to improve Parent/Children relationships immediately,
in a way that is reasonably uncontroversial. Switching our hierarchy to
fragmenting relationships would have significant performance
implications. ~~Flecs is heavily considering a switch to non-fragmenting
relations after careful considerations of the performance tradeoffs.~~
_(Correction from @SanderMertens: Flecs is implementing non-fragmenting
storage specialized for asset hierarchies, where asset hierarchies are
many instances of small trees that have a well defined structure)_
2. Adding generalized one-to-many relationships is currently a priority
for the [Next Generation Scene / UI
effort](https://github.com/bevyengine/bevy/discussions/14437).
Specifically, we're interested in building reactions and observers on
top.

## The changes

This PR does the following:

1. Adds a generic one-to-many Relationship system
3. Ports the existing Parent/Children system to Relationships, which now
lives in `bevy_ecs::hierarchy`. The old `bevy_hierarchy` crate has been
removed.
4. Adds on_despawn component hooks
5. Relationships can opt-in to "despawn descendants" behavior, meaning
that the entire relationship hierarchy is despawned when
`entity.despawn()` is called. The built in Parent/Children hierarchies
enable this behavior, and `entity.despawn_recursive()` has been removed.
6. `world.spawn` now applies commands after spawning. This ensures that
relationship bookkeeping happens immediately and removes the need to
manually flush. This is in line with the equivalent behaviors recently
added to the other APIs (ex: insert).
7. Removes the ValidParentCheckPlugin (system-driven / poll based) in
favor of a `validate_parent_has_component` hook.

## Using Relationships

The `Relationship` trait looks like this:

```rust
pub trait Relationship: Component + Sized {
    type RelationshipSources: RelationshipSources<Relationship = Self>;
    fn get(&self) -> Entity;
    fn from(entity: Entity) -> Self;
}
```

A relationship is a component that:

1. Is a simple wrapper over a "target" Entity.
2. Has a corresponding `RelationshipSources` component, which is a
simple wrapper over a collection of entities. Every "target entity"
targeted by a "source entity" with a `Relationship` has a
`RelationshipSources` component, which contains every "source entity"
that targets it.

For example, the `Parent` component (as it currently exists in Bevy) is
the `Relationship` component and the entity containing the Parent is the
"source entity". The entity _inside_ the `Parent(Entity)` component is
the "target entity". And that target entity has a `Children` component
(which implements `RelationshipSources`).

In practice, the Parent/Children relationship looks like this:

```rust
#[derive(Relationship)]
#[relationship(relationship_sources = Children)]
pub struct Parent(pub Entity);

#[derive(RelationshipSources)]
#[relationship_sources(relationship = Parent)]
pub struct Children(Vec<Entity>);
```

The Relationship and RelationshipSources derives automatically implement
Component with the relevant configuration (namely, the hooks necessary
to keep everything in sync).

The most direct way to add relationships is to spawn entities with
relationship components:

```rust
let a = world.spawn_empty().id();
let b = world.spawn(Parent(a)).id();

assert_eq!(world.entity(a).get::<Children>().unwrap(), &[b]);
```

There are also convenience APIs for spawning more than one entity with
the same relationship:

```rust
world.spawn_empty().with_related::<Children>(|s| {
    s.spawn_empty();
    s.spawn_empty();
})
```

The existing `with_children` API is now a simpler wrapper over
`with_related`. This makes this change largely non-breaking for existing
spawn patterns.

```rust
world.spawn_empty().with_children(|s| {
    s.spawn_empty();
    s.spawn_empty();
})
```

There are also other relationship APIs, such as `add_related` and
`despawn_related`.

## Automatic recursive despawn via the new on_despawn hook

`RelationshipSources` can opt-in to "despawn descendants" behavior,
which will despawn all related entities in the relationship hierarchy:

```rust
#[derive(RelationshipSources)]
#[relationship_sources(relationship = Parent, despawn_descendants)]
pub struct Children(Vec<Entity>);
```

This means that `entity.despawn_recursive()` is no longer required.
Instead, just use `entity.despawn()` and the relevant related entities
will also be despawned.

To despawn an entity _without_ despawning its parent/child descendants,
you should remove the `Children` component first, which will also remove
the related `Parent` components:

```rust
entity
    .remove::<Children>()
    .despawn()
```

This builds on the on_despawn hook introduced in this PR, which is fired
when an entity is despawned (before other hooks).

## Relationships are the source of truth

`Relationship` is the _single_ source of truth component.
`RelationshipSources` is merely a reflection of what all the
`Relationship` components say. By embracing this, we are able to
significantly improve the performance of the system as a whole. We can
rely on component lifecycles to protect us against duplicates, rather
than needing to scan at runtime to ensure entities don't already exist
(which results in quadratic runtime). A single source of truth gives us
constant-time inserts. This does mean that we cannot directly spawn
populated `Children` components (or directly add or remove entities from
those components). I personally think this is a worthwhile tradeoff,
both because it makes the performance much better _and_ because it means
theres exactly one way to do things (which is a philosophy we try to
employ for Bevy APIs).

As an aside: treating both sides of the relationship as "equivalent
source of truth relations" does enable building simple and flexible
many-to-many relationships. But this introduces an _inherent_ need to
scan (or hash) to protect against duplicates.
[`evergreen_relations`](https://github.com/EvergreenNest/evergreen_relations)
has a very nice implementation of the "symmetrical many-to-many"
approach. Unfortunately I think the performance issues inherent to that
approach make it a poor choice for Bevy's default relationship system.

## Followup Work

* Discuss renaming `Parent` to `ChildOf`. I refrained from doing that in
this PR to keep the diff reasonable, but I'm personally biased toward
this change (and using that naming pattern generally for relationships).
* [Improved spawning
ergonomics](https://github.com/bevyengine/bevy/discussions/16920)
* Consider adding relationship observers/triggers for "relationship
targets" whenever a source is added or removed. This would replace the
current "hierarchy events" system, which is unused upstream but may have
existing users downstream. I think triggers are the better fit for this
than a buffered event queue, and would prefer not to add that back.
* Fragmenting relations: My current idea hinges on the introduction of
"value components" (aka: components whose type _and_ value determines
their ComponentId, via something like Hashing / PartialEq). By labeling
a Relationship component such as `ChildOf(Entity)` as a "value
component", `ChildOf(e1)` and `ChildOf(e2)` would be considered
"different components". This makes the transition between fragmenting
and non-fragmenting a single flag, and everything else continues to work
as expected.
* Many-to-many support
* Non-fragmenting: We can expand Relationship to be a list of entities
instead of a single entity. I have largely already written the code for
this.
* Fragmenting: With the "value component" impl mentioned above, we get
many-to-many support "for free", as it would allow inserting multiple
copies of a Relationship component with different target entities.

Fixes #3742 (If this PR is merged, I think we should open more targeted
followup issues for the work above, with a fresh tracking issue free of
the large amount of less-directed historical context)
Fixes #17301
Fixes #12235 
Fixes #15299
Fixes #15308 

## Migration Guide

* Replace `ChildBuilder` with `ChildSpawnerCommands`.
* Replace calls to `.set_parent(parent_id)` with
`.insert(Parent(parent_id))`.
* Replace calls to `.replace_children()` with `.remove::<Children>()`
followed by `.add_children()`. Note that you'll need to manually despawn
any children that are not carried over.
* Replace calls to `.despawn_recursive()` with `.despawn()`.
* Replace calls to `.despawn_descendants()` with
`.despawn_related::<Children>()`.
* If you have any calls to `.despawn()` which depend on the children
being preserved, you'll need to remove the `Children` component first.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-01-18 22:20:30 +00:00
Zachary Harrold 21786632c3 Remove bevy_core (#16897)
# Objective

- Fixes #16892

## Solution

- Removed `TypeRegistryPlugin` (`Name` is now automatically registered
with a default `App`)
- Moved `TaskPoolPlugin` to `bevy_app`
- Moved `FrameCountPlugin` to `bevy_diagnostic`
- Deleted now-empty `bevy_core`

## Testing

- CI

## Migration Guide

- `TypeRegistryPlugin` no longer exists. If you can't use a default
`App` but still need `Name` registered, do so manually with
`app.register_type::<Name>()`.
- References to `TaskPoolPlugin` and associated types will need to
import it from `bevy_app` instead of `bevy_core`
- References to `FrameCountPlugin` and associated types will need to
import it from `bevy_diagnostic` instead of `bevy_core`

## Notes

This strategy was agreed upon by Cart and several other members in
[Discord](https://discord.com/channels/691052431525675048/692572690833473578/1319137218312278077).
2024-12-19 18:36:51 +00:00
Rich Churcher f2719f5470 Rust 1.83, allow -> expect (missing_docs) (#16561)
# Objective

We were waiting for 1.83 to address most of these, due to a bug with
`missing_docs` and `expect`. Relates to, but does not entirely complete,
#15059.

## Solution

- Upgrade to 1.83
- Switch `allow(missing_docs)` to `expect(missing_docs)`
- Remove a few now-unused `allow`s along the way, or convert to `expect`
2024-12-16 23:27:57 +00:00
Clar Fon 711246aa34 Update hashbrown to 0.15 (#15801)
Updating dependencies; adopted version of #15696. (Supercedes #15696.)

Long answer: hashbrown is no longer using ahash by default, meaning that
we can't use the default-hasher methods with ahasher. So, we have to use
the longer-winded versions instead. This takes the opportunity to also
switch our default hasher as well, but without actually enabling the
default-hasher feature for hashbrown, meaning that we'll be able to
change our hasher more easily at the cost of all of these method calls
being obnoxious forever.

One large change from 0.15 is that `insert_unique_unchecked` is now
`unsafe`, and for cases where unsafe code was denied at the crate level,
I replaced it with `insert`.

## Migration Guide

`bevy_utils` has updated its version of `hashbrown` to 0.15 and now
defaults to `foldhash` instead of `ahash`. This means that if you've
hard-coded your hasher to `bevy_utils::AHasher` or separately used the
`ahash` crate in your code, you may need to switch to `foldhash` to
ensure that everything works like it does in Bevy.
2024-12-10 19:45:50 +00:00
Rich Churcher bb81a2cdb3 Simple integration testing (adopted) (#16489)
# Objective

This older PR from `Wcubed` seemed well worth saving, adopted from
#7314. See also tracking issue #2896 for ongoing discussion of Bevy
testability. Thanks `Wcubed`!

## Solution

- Updated for 0.15
- Added the `expected`/`actual` pattern
- Switched to function plugin
- Tweaked a bit of description

## Testing

Green.

---------

Co-authored-by: Wybe Westra <dev@wwestra.nl>
Co-authored-by: Wybe Westra <wybe.westra@protonmail.com>
2024-11-24 20:54:59 +00:00
Rob Parrett 30d84519a2 Use en-us locale for typos (#16037)
# Objective

Bevy seems to want to standardize on "American English" spellings. Not
sure if this is laid out anywhere in writing, but see also #15947.

While perusing the docs for `typos`, I noticed that it has a `locale`
config option and tried it out.

## Solution

Switch to `en-us` locale in the `typos` config and run `typos -w`

## Migration Guide

The following methods or fields have been renamed from `*dependants*` to
`*dependents*`.

- `ProcessorAssetInfo::dependants`
- `ProcessorAssetInfos::add_dependant`
- `ProcessorAssetInfos::non_existent_dependants`
- `AssetInfo::dependants_waiting_on_load`
- `AssetInfo::dependants_waiting_on_recursive_dep_load`
- `AssetInfos::loader_dependants`
- `AssetInfos::remove_dependants_and_labels`
2024-10-20 18:55:17 +00:00
Pablo Reinhardt d96a9d15f6 Migrate from Query::single and friends to Single (#15872)
# Objective

- closes #15866

## Solution

- Simply migrate where possible.

## Testing

- Expect that CI will do most of the work. Examples is another way of
testing this, as most of the work is in that area.
---

## Notes
For now, this PR doesn't migrate `QueryState::single` and friends as for
now, this look like another issue. So for example, QueryBuilders that
used single or `World::query` that used single wasn't migrated. If there
is a easy way to migrate those, please let me know.

Most of the uses of `Query::single` were removed, the only other uses
that I found was related to tests of said methods, so will probably be
removed when we remove `Query::single`.
2024-10-13 20:32:06 +00:00
Rob Parrett 7f24c27645 Fix minimising example minimizing every frame (#15850)
# Objective

The `minimising` example is a bit annoying to run locally, because it
attempts to minimize the window every frame, so un-minimizing it is
difficult.

## Solution

Only minimize once.

The contents of the example can now be inspected, and the window easily
closed after the minimization happens.

## Testing

`cargo run --example minimising`

I tested on macos only.

---------

Co-authored-by: François Mockers <francois.mockers@vleue.com>
2024-10-11 15:36:09 +00:00
Emerson Coskey 7d40e3ec87 Migrate bevy_sprite to required components (#15489)
# Objective

Continue migration of bevy APIs to required components, following
guidance of https://hackmd.io/@bevy/required_components/

## Solution

- Make `Sprite` require `Transform` and `Visibility` and
`SyncToRenderWorld`
- move image and texture atlas handles into `Sprite`
- deprecate `SpriteBundle`
- remove engine uses of `SpriteBundle`

## Testing

ran cargo tests on bevy_sprite and tested several sprite examples.

---

## Migration Guide

Replace all uses of `SpriteBundle` with `Sprite`. There are several new
convenience constructors: `Sprite::from_image`,
`Sprite::from_atlas_image`, `Sprite::from_color`.

WARNING: use of `Handle<Image>` and `TextureAtlas` as components on
sprite entities will NO LONGER WORK. Use the fields on `Sprite` instead.
I would have removed the `Component` impls from `TextureAtlas` and
`Handle<Image>` except it is still used within ui. We should fix this
moving forward with the migration.
2024-10-09 16:17:26 +00:00
Joona Aalto 25bfa80e60 Migrate cameras to required components (#15641)
# Objective

Yet another PR for migrating stuff to required components. This time,
cameras!

## Solution

As per the [selected
proposal](https://hackmd.io/tsYID4CGRiWxzsgawzxG_g#Combined-Proposal-1-Selected),
deprecate `Camera2dBundle` and `Camera3dBundle` in favor of `Camera2d`
and `Camera3d`.

Adding a `Camera` without `Camera2d` or `Camera3d` now logs a warning,
as suggested by Cart [on
Discord](https://discord.com/channels/691052431525675048/1264881140007702558/1291506402832945273).
I would personally like cameras to work a bit differently and be split
into a few more components, to avoid some footguns and confusing
semantics, but that is more controversial, and shouldn't block this core
migration.

## Testing

I ran a few 2D and 3D examples, and tried cameras with and without
render graphs.

---

## Migration Guide

`Camera2dBundle` and `Camera3dBundle` have been deprecated in favor of
`Camera2d` and `Camera3d`. Inserting them will now also insert the other
components required by them automatically.
2024-10-05 01:59:52 +00:00
Joona Aalto 54006b107b Migrate meshes and materials to required components (#15524)
# Objective

A big step in the migration to required components: meshes and
materials!

## Solution

As per the [selected
proposal](https://hackmd.io/@bevy/required_components/%2Fj9-PnF-2QKK0on1KQ29UWQ):

- Deprecate `MaterialMesh2dBundle`, `MaterialMeshBundle`, and
`PbrBundle`.
- Add `Mesh2d` and `Mesh3d` components, which wrap a `Handle<Mesh>`.
- Add `MeshMaterial2d<M: Material2d>` and `MeshMaterial3d<M: Material>`,
which wrap a `Handle<M>`.
- Meshes *without* a mesh material should be rendered with a default
material. The existence of a material is determined by
`HasMaterial2d`/`HasMaterial3d`, which is required by
`MeshMaterial2d`/`MeshMaterial3d`. This gets around problems with the
generics.

Previously:

```rust
commands.spawn(MaterialMesh2dBundle {
    mesh: meshes.add(Circle::new(100.0)).into(),
    material: materials.add(Color::srgb(7.5, 0.0, 7.5)),
    transform: Transform::from_translation(Vec3::new(-200., 0., 0.)),
    ..default()
});
```

Now:

```rust
commands.spawn((
    Mesh2d(meshes.add(Circle::new(100.0))),
    MeshMaterial2d(materials.add(Color::srgb(7.5, 0.0, 7.5))),
    Transform::from_translation(Vec3::new(-200., 0., 0.)),
));
```

If the mesh material is missing, previously nothing was rendered. Now,
it renders a white default `ColorMaterial` in 2D and a
`StandardMaterial` in 3D (this can be overridden). Below, only every
other entity has a material:

![Näyttökuva 2024-09-29
181746](https://github.com/user-attachments/assets/5c8be029-d2fe-4b8c-ae89-17a72ff82c9a)

![Näyttökuva 2024-09-29
181918](https://github.com/user-attachments/assets/58adbc55-5a1e-4c7d-a2c7-ed456227b909)

Why white? This is still open for discussion, but I think white makes
sense for a *default* material, while *invalid* asset handles pointing
to nothing should have something like a pink material to indicate that
something is broken (I don't handle that in this PR yet). This is kind
of a mix of Godot and Unity: Godot just renders a white material for
non-existent materials, while Unity renders nothing when no materials
exist, but renders pink for invalid materials. I can also change the
default material to pink if that is preferable though.

## Testing

I ran some 2D and 3D examples to test if anything changed visually. I
have not tested all examples or features yet however. If anyone wants to
test more extensively, it would be appreciated!

## Implementation Notes

- The relationship between `bevy_render` and `bevy_pbr` is weird here.
`bevy_render` needs `Mesh3d` for its own systems, but `bevy_pbr` has all
of the material logic, and `bevy_render` doesn't depend on it. I feel
like the two crates should be refactored in some way, but I think that's
out of scope for this PR.
- I didn't migrate meshlets to required components yet. That can
probably be done in a follow-up, as this is already a huge PR.
- It is becoming increasingly clear to me that we really, *really* want
to disallow raw asset handles as components. They caused me a *ton* of
headache here already, and it took me a long time to find every place
that queried for them or inserted them directly on entities, since there
were no compiler errors for it. If we don't remove the `Component`
derive, I expect raw asset handles to be a *huge* footgun for users as
we transition to wrapper components, especially as handles as components
have been the norm so far. I personally consider this to be a blocker
for 0.15: we need to migrate to wrapper components for asset handles
everywhere, and remove the `Component` derive. Also see
https://github.com/bevyengine/bevy/issues/14124.

---

## Migration Guide

Asset handles for meshes and mesh materials must now be wrapped in the
`Mesh2d` and `MeshMaterial2d` or `Mesh3d` and `MeshMaterial3d`
components for 2D and 3D respectively. Raw handles as components no
longer render meshes.

Additionally, `MaterialMesh2dBundle`, `MaterialMeshBundle`, and
`PbrBundle` have been deprecated. Instead, use the mesh and material
components directly.

Previously:

```rust
commands.spawn(MaterialMesh2dBundle {
    mesh: meshes.add(Circle::new(100.0)).into(),
    material: materials.add(Color::srgb(7.5, 0.0, 7.5)),
    transform: Transform::from_translation(Vec3::new(-200., 0., 0.)),
    ..default()
});
```

Now:

```rust
commands.spawn((
    Mesh2d(meshes.add(Circle::new(100.0))),
    MeshMaterial2d(materials.add(Color::srgb(7.5, 0.0, 7.5))),
    Transform::from_translation(Vec3::new(-200., 0., 0.)),
));
```

If the mesh material is missing, a white default material is now used.
Previously, nothing was rendered if the material was missing.

The `WithMesh2d` and `WithMesh3d` query filter type aliases have also
been removed. Simply use `With<Mesh2d>` or `With<Mesh3d>`.

---------

Co-authored-by: Tim Blackbird <justthecooldude@gmail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-10-01 21:33:17 +00:00
Joona Aalto de888a373d Migrate lights to required components (#15554)
# Objective

Another step in the migration to required components: lights!

Note that this does not include `EnvironmentMapLight` or reflection
probes yet, because their API hasn't been fully chosen yet.

## Solution

As per the [selected
proposals](https://hackmd.io/@bevy/required_components/%2FLLnzwz9XTxiD7i2jiUXkJg):

- Deprecate `PointLightBundle` in favor of the `PointLight` component
- Deprecate `SpotLightBundle` in favor of the `PointLight` component
- Deprecate `DirectionalLightBundle` in favor of the `DirectionalLight`
component

## Testing

I ran some examples with lights.

---

## Migration Guide

`PointLightBundle`, `SpotLightBundle`, and `DirectionalLightBundle` have
been deprecated. Use the `PointLight`, `SpotLight`, and
`DirectionalLight` components instead. Adding them will now insert the
other components required by them automatically.
2024-10-01 03:20:43 +00:00
Clar Fon efda7f3f9c Simpler lint fixes: makes ci lints work but disables a lint for now (#15376)
Takes the first two commits from #15375 and adds suggestions from this
comment:
https://github.com/bevyengine/bevy/pull/15375#issuecomment-2366968300

See #15375 for more reasoning/motivation.

## Rebasing (rerunning)

```rust
git switch simpler-lint-fixes
git reset --hard main
cargo fmt --all -- --unstable-features --config normalize_comments=true,imports_granularity=Crate
cargo fmt --all
git add --update
git commit --message "rustfmt"
cargo clippy --workspace --all-targets --all-features --fix
cargo fmt --all -- --unstable-features --config normalize_comments=true,imports_granularity=Crate
cargo fmt --all
git add --update
git commit --message "clippy"
git cherry-pick e6c0b94f6795222310fb812fa5c4512661fc7887
```
2024-09-24 11:42:59 +00:00
Zachary Harrold 4742f74fc4 Broaden "Check for bevy_internal imports" CI Task (#15333)
# Objective

- Fixes #15319
- Fixes #15317

## Solution

- Updated CI task to check for _any_ `bevy_*` crates, rather than just
`bevy_internal`

---------

Co-authored-by: François Mockers <francois.mockers@vleue.com>
2024-09-20 17:08:37 +00:00
Hamir Mahal ec728c31c1 style: simplify string formatting for readability (#15033)
# Objective

The goal of this change is to improve code readability and
maintainability.
2024-09-03 23:35:49 +00:00
Alice Cecile 4ac2a63556 Remove all existing system order ambiguities in DefaultPlugins (#15031)
# Objective

As discussed in https://github.com/bevyengine/bevy/issues/7386, system
order ambiguities within `DefaultPlugins` are a source of bugs in the
engine and badly pollute diagnostic output for users.

We should eliminate them!

This PR is an alternative to #15027: with all external ambiguities
silenced, this should be much less prone to merge conflicts and the test
output should be much easier for authors to understand.

Note that system order ambiguities are still permitted in the
`RenderApp`: these need a bit of thought in terms of how to test them,
and will be fairly involved to fix. While these aren't *good*, they'll
generally only cause graphical bugs, not logic ones.

## Solution

All remaining system order ambiguities have been resolved.
Review this PR commit-by-commit to see how each of these problems were
fixed.

## Testing

`cargo run --example ambiguity_detection` passes with no panics or
logging!
2024-09-03 20:24:34 +00:00
ickshonpe 01a3b0e830 UI texture atlas slice shader (#14990)
# Objective

Fixes https://github.com/bevyengine/bevy/issues/14183

## Solution

Reimplement the UI texture atlas slicer using a shader. 

The problems with #14183 could be fixed more simply by hacking around
with the coordinates and scaling but that way is very fragile and might
get broken again the next time we make changes to the layout
calculations. A shader based solution is more robust, it's impossible
for gaps to appear between the image slices with these changes as we're
only drawing a single quad.

I've not tried any benchmarks yet but it should much more efficient as
well, in the worst cases even hundreds or thousands of times faster.

Maybe could have used the UiMaterialPipeline. I wrote the shader first
and used fat vertices and then realised it wouldn't work that way with a
UiMaterial. If it's rewritten it so it puts all the slice geometry in
uniform buffer, then it might work? Adding the uniform buffer would
probably make the shader more complicated though, so don't know if it's
even worth it. Instancing is another alternative.

## Testing
The examples are working and it seems to match the old API correctly but
I've not used the texture atlas slicing API for anything before, I
reviewed the PR but that was back in January.

Needs a review by someone who knows the rendering pipeline and wgsl
really well because I don't really have any idea what I'm doing.
2024-09-02 23:03:58 +00:00
ickshonpe be100b8760 Resolve UI outlines using the correct target's viewport size (#14947)
# Objective
`resolve_outlines_system` wasn't updated when multi-window support was
added and it always uses the size of the primary window when resolving
viewport coords, regardless of the layout's camera target.

Fixes #14945

## Solution

It's awkward to get the viewport size of the target for an individual
node without walking the tree or adding extra fields to `Node`, so I
removed `resolve_outlines_system` and instead the outline values are
updated in `ui_layout_system`.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-09-02 16:56:58 +00:00
Alice Cecile 5243fe6956 Remove manual apply_deferred in bevy_ui (#14768)
# Objective

This `apply_deferred` doesn't seem to have any effect, pointlessly
restricts parallelism and is responsible for a large number of system
order ambiguities. Spotted as part of #7386.

## Solution

Remove it.

This is the *only* manual apply_deferred in the code base currently.

## Testing

I've checked various UI examples and `split_screen`, and couldn't
discern any difference.

This looks like a remnant of a `(a, apply_deferred, b).chain()` pattern
where `b` got removed, leaving us with a weird vestige.
2024-08-15 20:51:25 +00:00
Alice Cecile 0c126ee676 Improve ambiguity detection example / test (#14760)
# Objective

While tackling https://github.com/bevyengine/bevy/issues/7386, I noticed
a few nits / frustrations with the existing testing infrastructure.

Rather than mixing those changes in with much more challenging to review
changes to reduce ambiguities, I've split this work into its own PR.

## Solution

Substantially simplify the `ambiguity_detection` test code, and reduce
the verbosity of logging.

## Testing

When run locally, the test functions as expected, with somewhat cleaner
logging.

---------

Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
2024-08-15 18:30:57 +00:00
Ben Frankel 9b254aab1e Explicitly order CameraUpdateSystem before UiSystem::Prepare (#14609)
# Objective

Fixes https://github.com/bevyengine/bevy/issues/14277.

May also fix https://github.com/bevyengine/bevy/issues/14255, needs
verification.

## Solution

Explicitly order `CameraUpdateSystem` before `UiSystem::Prepare`, so
that when the window resizes, `camera_system` will update the `Camera`'s
viewport size before `ui_layout_system` also reacts to the window resize
and tries to read the new `Camera` viewport size to set UI node sizes
accordingly.

## Testing

I tested that explicitly ordering `CameraUpdateSystem` _after_ triggers
the buggy behavior, and explicitly ordering it _before_ does not trigger
the buggy behavior or crash the app (which also demonstrates that the
system sets are ambiguous).

---

## Migration Guide

`CameraUpdateSystem` is now explicitly ordered before
`UiSystem::Prepare` instead of being ambiguous with it.
2024-08-04 13:34:51 +00:00
Rich Churcher e579622a65 time_system is ambiguous_with event_update_system (#14544)
# Objective

Resolve possible ambiguity detection panic between `time_system` and
`event_update_system`.

Fixes #14524

## Solution

Sets `.ambiguous_with(event_update_system)` on `time_system`. This is
slightly new territory for me, so please treat with scepticism.

## Testing

As described in the issue, added
```
        .configure_schedules(ScheduleBuildSettings {
            ambiguity_detection: LogLevel::Error,
            ..default()
        })
```
to the `time` example and ran it.
2024-07-31 12:13:17 +00:00
Thierry Berger 26fc4c7198 Test for ambiguous system ordering in CI (#13950)
Progress towards https://github.com/bevyengine/bevy/issues/7386.

Following discussion
https://discord.com/channels/691052431525675048/1253260494538539048/1253387942311886960

This Pull Request adds an example to detect system order ambiguities,
and also asserts none exist.

A lot of schedules are ignored in ordered to have the test passing, we
should thrive to make them pass, but in other pull requests.

<details><summary>example output <b>summary</b>, without ignored
schedules</summary>
<p>

```txt
$ cargo run --example ambiguity_detection 2>&1 | grep -C 1 "pairs of syst"
2024-06-21T13:17:55.776585Z  WARN bevy_ecs::schedule::schedule: Schedule First has ambiguities.
1 pairs of systems with conflicting data access have indeterminate execution order. Consider adding `before`, `after`, or `ambiguous_with` relationships between these:
 -- bevy_time::time_system (in set TimeSystem) and bevy_ecs::event::event_update_system (in set EventUpdates)
--
2024-06-21T13:17:55.782265Z  WARN bevy_ecs::schedule::schedule: Schedule PreUpdate has ambiguities.
11 pairs of systems with conflicting data access have indeterminate execution order. Consider adding `before`, `after`, or `ambiguous_with` relationships between these:
 -- bevy_pbr::prepass::update_mesh_previous_global_transforms and bevy_asset::server::handle_internal_asset_events
--
2024-06-21T13:17:55.809516Z  WARN bevy_ecs::schedule::schedule: Schedule PostUpdate has ambiguities.
63 pairs of systems with conflicting data access have indeterminate execution order. Consider adding `before`, `after`, or `ambiguous_with` relationships between these:
 -- bevy_ui::accessibility::image_changed and bevy_ecs::schedule::executor::apply_deferred
--
2024-06-21T13:17:55.816287Z  WARN bevy_ecs::schedule::schedule: Schedule Last has ambiguities.
3 pairs of systems with conflicting data access have indeterminate execution order. Consider adding `before`, `after`, or `ambiguous_with` relationships between these:
 -- bevy_gizmos::update_gizmo_meshes<bevy_gizmos::aabb::AabbGizmoConfigGroup> (in set UpdateGizmoMeshes) and bevy_gizmos::update_gizmo_meshes<bevy_gizmos::light::LightGizmoConfigGroup> (in set UpdateGizmoMeshes)
--
2024-06-21T13:17:55.831074Z  WARN bevy_ecs::schedule::schedule: Schedule ExtractSchedule has ambiguities.
296 pairs of systems with conflicting data access have indeterminate execution order. Consider adding `before`, `after`, or `ambiguous_with` relationships between these:
 -- bevy_render::extract_component::extract_components<bevy_sprite::SpriteSource> and bevy_render::render_asset::extract_render_asset<bevy_sprite::mesh2d::material::PreparedMaterial2d<bevy_sprite::mesh2d::color_material::ColorMaterial>>
```

</p>
</details> 

To try locally: 
```sh
CI_TESTING_CONFIG="./.github/example-run/ambiguity_detection.ron" cargo run --example ambiguity_detection --features "bevy_ci_testing,trace,trace_chrome"
```

---------

Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
2024-07-17 21:05:48 +00:00