Commit Graph

245 Commits

Author SHA1 Message Date
laund 9ed66d7a06 bsn: throw error when using caching syntax on unsupported scene entries (#24473)
# Objective

Implement changes discussed with cart around erroring when using caching
syntax where its not implemented.


## Solution

Throw a compile error, in a way which is easy to remove once caching
exists/works for more cases.

Also contains a commit to alleviate trait errors which will (from my
experience writing this PR and fixing them in bevy) arise from fixing
this for existing bsn code. This commit can be dropped if not desired.
This would ideally be fixed upstream so this workaround can be removed:
https://github.com/rust-lang/rust/issues/141258#issuecomment-4565897810

Note: The error caused by this workaround is far from ideal. It
initially looks like a method call is missing, but ultimately the
hint/advice *is* correct
<img width="1982" height="477" alt="image"
src="https://github.com/user-attachments/assets/879f7630-ada8-4e63-9c59-80be466f37cf"
/>


## Testing

- `cargo test -p bevy_scene --lib`
- `cargo check`

---------

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2026-05-29 23:07:39 +00:00
DavidCrossman 9dfc7a6d33 Use absolute paths in declarative macros (#24261)
# Objective

- Improve declarative macro hygiene.
- Fix declarative macros using non-imported items.
  - `AnimatedField` is unqualified in the `animated_field` macro.
  - `offset_of` is unqualified in the `impl_atomic_pod` macro.
- `format` is unqualified in `hash_error` macro (requires import in
`no_std`).

## Solution

- Qualify unqualified items and use absolute paths in every public
(`#[macro_export]`) `macro_rules`.
- Re-export `format` in `bevy_reflect::__macro_exports::alloc_utils`.

## Testing

- Ran `cargo run -p ci -- compile`
2026-05-21 09:47:16 +00:00
Mira 281062d418 Remove leftover add_remove.rs benchmark file (#24340)
Delete unused duplicate benchmark.

Cart's fork of ecs_bench_suite split `add_remove` into table and sparse
set versions, but forgot to delete the unused old file.
2026-05-21 09:05:12 +00:00
laund 81520a73c8 bsn: Allow passing EntityTemplate into scene functions and Scene Component @props (#24174)
# Objective
Prior PR, see for somewhat outdated description regarding global entity
indices:
- #24173

Currently, its not possible to pass an entity name reference to a scene
function (`-> impl Scene`) or a Scene Component `@props`

This PR enables this, based on #24173 by allowing easy passing on
EntityTemplate:
```rs
 #[derive(Component, FromTemplate)]
struct Reference(Entity);
fn widget(entity: EntityTemplate) -> impl Scene {
    bsn! {
        Reference(entity)
    }
}
bsn! {
    #Name
    Children [
        :widget(#Name)
    ]
};
```

## Solution

I tried this before in
https://github.com/bevyengine/bevy/compare/main...laundmo:bevy:bsn-hacky-name-passing
but had to compromise so it was obvious it wasn't going to ever be
merged. After talking with @cart on discord about this [around
here](https://discord.com/channels/691052431525675048/1264881140007702558/1501663053551239209)
i went with attempting the global entitiy indices, which resulted in
#24173 (all of those changes also being part of this PR)

## Testing

- [x] `cargo test -p bevy_scene --lib` with new tests for this feature
- [x] `cargo run --example feathers_gallery --features=bevy_feathers`
still works the same
- [x] new basic benchmark for name resolution doesn't show any major
regression

---

## Showcase

In a `bsn!` macro, its now possible to pass a `#Name` entity reference
into another Scene as an `EntityTemplate`.

To use this, write a scene function (or scene component prop) which
takes `EntityTemplate`. Components which contain an `Entity` and
implement `FromTemplate` can directly take in `EntityTemplate`

```rust
#[derive(Component, FromTemplate)]
struct FooBar(Entity);
        
fn foo(entity: EntityTemplate) -> impl Scene {
    bsn! {
        Reference(entity)
    }
}
```
Now, theres multiple ways to pass in an `EntityTemplate` like this,
heres some examples:
```rust
bsn! {
	#SomeName
    Children [
        :foo(#SomeName),
		foo(#SomeName)
		foo(#{some_entity_value}) // some_entity_value: any expression evaluating to Entity, most likely a variable
		:Bar {
		  @myprop: #SomeName
		}
    ]
}
```

---------

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2026-05-17 13:24:59 +00:00
Trashtalk217 a50b65dfa5 Store resources on sparse sets (#24077)
# Objective

Part of the #23988 and #24058 saga. We attempt to speed up resource
access.

## Solution

When messing around with #23988 I noticed that changing the storage type
mattered a lot for the benchmarks.

## Testing

Added benchmarks from #24058 and got the following micro benchmarks
compared to main:

```
ecs::resources::get     time:   [6.3584 ns 6.3840 ns 6.4097 ns]
                        change: [−10.625% −10.075% −9.6652%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 9 outliers among 100 measurements (9.00%)
  1 (1.00%) low mild
  8 (8.00%) high mild

ecs::resources::get_mut time:   [7.4181 ns 7.4343 ns 7.4515 ns]
                        change: [−39.895% −39.304% −38.809%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 7 outliers among 100 measurements (7.00%)
  5 (5.00%) high mild
  2 (2.00%) high severe

ecs::resources::insert_remove
                        time:   [89.515 ns 89.654 ns 89.815 ns]
                        change: [−20.163% −16.527% −11.930%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 10 outliers among 100 measurements (10.00%)
  2 (2.00%) low severe
  1 (1.00%) low mild
  3 (3.00%) high mild
  4 (4.00%) high severe
```

If someone wants to double-check these numbers, I encourage you to do
so.
2026-05-04 16:15:20 -07:00
Rostyslav Toch aaec9e8d5b Add camera primitives benchmark (#23863)
# Objective

- Add performance benchmarks for camera primitives to track the
efficiency of intersection tests.

## Solution

- Created a new benchmark suite `bevy_camera`.

## Testing

- Ran the benchmarks locally using `cargo bench -p benches --bench
camera -- --save-baseline main intersects_obb`.

```
intersects_obb/sphere_intersects_obb
                        time:   [6.5819 ns 6.6022 ns 6.6255 ns]
intersects_obb/frustum_intersects_obb
                        time:   [14.919 ns 14.954 ns 14.991 ns]
intersects_obb/frustum_intersects_obb_fallback_identity
                        time:   [14.940 ns 14.965 ns 14.993 ns]
intersects_obb/frustum_intersects_obb_identity
                        time:   [6.8076 ns 6.8173 ns 6.8276 ns]

```

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-04-27 02:30:15 +00:00
Sieluna 738b147b53 Add bevy_transform benchmarks (#23906)
# Objective

- Add dedicated benchmarks for `bevy_transform`'s propagation systems to
catch performance regressions.

## Solution

**Benchmarks** (`benches/benches/bevy_transform/propagate.rs`):

Added small benchmarks targeting each stage of the propagation pipeline
individually.

- `mark_dirty_trees` — localized vs. distributed leaf update patterns
- `propagate_parent_transforms` — full recompute with roots changed vs.
leaves changed (static optimization disabled to isolate traversal cost)
- `transform_pipeline` — end-to-end pipeline with static optimization
on/off, plus `ChildOf` reparent churn

The hierarchy setup uses 48 roots × 6 depth layers with mixed fanout
(4-4-3-3-2-2) and extra archetype padding (`MarkerA/B/C`) to reflect
realistic gameplay scenes.

## Testing

```sh
cargo bench -p benches --bench transform
```

---------

Co-authored-by: ickshonpe <27962798+ickshonpe@users.noreply.github.com>
2026-04-21 17:01:39 +00:00
Carter Anderson 6e9522c5af Asset Value Templates via asset_value() and HandleTemplate::Value (#23839)
# Objective

Temporary simple / suboptimal solution to #23822

It would be very nice to be able to define assets inline in BSN.

## Solution

- Add a new `HandleTemplate::Value` variant, which contains an
`Arc<Mutex<AssetOrHandle<T>>>`
- This template, when first applied, will lock the mutex, insert the
asset value as a new asset, cache the handle in the
`Arc<Mutex<HandleOrTemplate>` and return the handle. Future calls will
lock the mutex and return the cached handle.
- Add `asset_value(SOME_ASSET)` function to improve ergonomics.
- Port `3d_scene` to illustrate

Doing a lock on every spawn is obviously suboptimal. The long term plan
for "inline assets in BSN" is defined in #23822 and will not use this
locking approach.
2026-04-20 00:52:10 +00:00
Carter Anderson dc70b2e0fd Insert ResolvedScenes as dynamic bundles (#23808)
# Objective

Currently BSN inserts each component one-by-one. This is incredibly
expensive, as it forces an archetype move after every insert.

## Solution

Scene templates now write their outputs to reusable bundle scratch space
(which uses a bump allocator). The final bundle is written after all
components (including inherited components) are written to the bundle.

- Introduce a `BundleWriter`, which enables defining a dynamic bundle
using scratch space in a bump allocator. Currently this only supports
writing individual components to the `BundleWriter`, because supporting
arbitrary bundles is much harder (ex: dynamic bundle effects). This
sadly means that we are temporarily constraining both `bsn! { Node }`
and `bsn! { @SomeTemplate }` "template patches" to _require_ a component
output. Custom scene impls can still push arbitrary bundles, which are
inserted before the final dynamic bundle write. In practice I believe
this will cover the relevant use cases in the short term.
- We now skip duplicate insertions of components when spawning inherited
scenes.
- We now write empty RelationshipTarget collections, pre-allocated to
the correct size to the dynamic bundle, which both avoids another
archetype move and ensures we only allocate the inner relationship
target collection once.
- We now write the Relationship component to the dynamic bundle,
avoiding an archetype move
- I added a new "loaded scene inheritance" test variant, just to make
sure that case still works
- `ErasedTemplate` has been moved to `bevy_scene`, as it is now
"opinionated", more specific to `bevy_scene`, and less safe to use in a
general context

<img width="795" height="274" alt="image"
src="https://github.com/user-attachments/assets/68ea02c7-6b7e-4f7c-9474-603188fe6d0b"
/>

These are benchmarks that produce the same UI scene hierarchy through
different means (the benchmarks have been updated to have a few "matrix
wrapper" components to show the cost of archetype moves):
- `immediate_function_scene`: a test of going through the whole "scene
building" process, then spawning. this is the cost of ad-hoc scenes that
don't reuse work from inherited scenes
- `immediate_loaded_scene`: a test where we instantiate a bunch of
inherited scene instances, where the inherited scene has already been
computed / cached.
- `raw_bundle_no_scene`: just spawning the raw bundle directly
2026-04-16 22:34:28 +00:00
Alice Cecile 85212f763e Fix CI errors for Rust 1.95 (#23829)
# Objective

CI is
[broken](https://github.com/bevyengine/bevy/actions/runs/24511176705/job/71642514168?pr=23785)

## Solution

Look at the CI errors. Fix them.

## Testing

Let's see if CI is green!
2026-04-16 17:46:57 +00:00
Rostyslav Toch a8a6002064 Optimize render asset extraction by reusing heap allocations (#23758)
# Objective

- Address CPU overhead in the render asset extraction phase.
- Prior to this change, `extract_render_asset` and
`extract_erased_render_asset` created several fresh `HashSet` and `Vec`
collections every frame.
- Furthermore, these collections were being sent to the render world via
`Commands::insert_resource`, which causes the previous frame's resource
(and its allocated capacity) to be dropped and deallocated.
- This results in unnecessary pressure on the global allocator and lower
CPU cache efficiency due to constant memory re-initialization.

## Solution

- Converted the temporary `needs_extracting` `HashSet` into a `Local`
system parameter. This allows the collection to retain its capacity
between system runs.
- Switched from using `Commands::insert_resource` to using
`ResMut<ExtractedAssets<A>>`. By calling `.clear()` on the existing
resource instead of replacing it, we reuse the heap-allocated buffers
for the `extracted` Vec and the `removed`, `modified`, and `added`
HashSets.

## Testing

- Introduced a micro-benchmark simulating N unique asset modifications
per frame to trigger the extraction logic.

```
cargo bench -p benches --bench render -- extract_render_asset
```

---

## Showcase

### Criterion Table
```
extract_render_asset/allocations/10
                        time:   [8.6633 µs 8.7004 µs 8.7432 µs]
                        thrpt:  [1.1437 Melem/s 1.1494 Melem/s 1.1543 Melem/s]
                 change:
                        time:   [−0.3467% +0.2334% +0.8050%] (p = 0.42 > 0.05)
                        thrpt:  [−0.7986% −0.2329% +0.3479%]
                        No change in performance detected.
extract_render_asset/allocations/100
                        time:   [11.256 µs 11.297 µs 11.340 µs]
                        thrpt:  [8.8183 Melem/s 8.8519 Melem/s 8.8838 Melem/s]
                 change:
                        time:   [−13.487% −12.672% −11.536%] (p = 0.00 < 0.05)
                        thrpt:  [+13.041% +14.511% +15.590%]
                        Performance has improved.
extract_render_asset/allocations/1000
                        time:   [34.867 µs 35.037 µs 35.222 µs]
                        thrpt:  [28.392 Melem/s 28.541 Melem/s 28.681 Melem/s]
                 change:
                        time:   [−42.567% −41.359% −40.454%] (p = 0.00 < 0.05)
                        thrpt:  [+67.938% +70.530% +74.116%]
                        Performance has improved.
extract_render_asset/allocations/10000
                        time:   [302.54 µs 305.30 µs 308.22 µs]
                        thrpt:  [32.445 Melem/s 32.755 Melem/s 33.053 Melem/s]
                 change:
                        time:   [−39.411% −37.491% −35.597%] (p = 0.00 < 0.05)
                        thrpt:  [+55.272% +59.976% +65.047%]
                        Performance has improved.
extract_render_asset/allocations/100000
                        time:   [4.7822 ms 4.9347 ms 5.1028 ms]
                        thrpt:  [19.597 Melem/s 20.265 Melem/s 20.911 Melem/s]
                 change:
                        time:   [−9.8539% −6.8588% −3.4015%] (p = 0.00 < 0.05)
                        thrpt:  [+3.5212% +7.3639% +10.931%]
                        Performance has improved.

```
2026-04-13 21:22:31 +00:00
Willem 9c5508c1ae Remove SystemState from more benches (#23705)
# Objective

Fixes #23238
I thought there would be more instances to fix :-)

## Solution

Same as #23687

## Testing

Ran affected benches and the regression results are a bit flaky -- but
seeing that only the ~regression~ bench logic has been changed, this
should be OK.

```sh
cargo bench -p benches --bench ecs -- iter_fragmented
```
2026-04-12 20:44:25 +00:00
Willem 0d0fa6ad12 Use run_system instead of SystemState for ECS benches (#23687)
# Objective

We want to use `World::run_system` where possible - especially in older
code that did not have the benefit of using it when it was written.

This is a small step towards #23238. More work is needed on the unit
tests and possibly elsewhere if this approach has been verified.

## Solution
- Instead of `SystemState` I used a closure system and registered it.
- I called the registered system with `World::run_system` inside the
bench.

## Testing
I ran the benches effected and found that they did not regress on my
machine.

Quick check:
```sh
cargo bench -p benches --bench ecs -- 50000_entities_table
```
2026-04-06 23:52:54 +00:00
Carter Anderson 6b0fb37e2c Rename bevy_scene2 to bevy_scene (#23668)
# Objective

Part 3 of #23619 

## Solution

Renames `bevy_scene2` to `bevy_scene` and adds it to the prelude.
2026-04-05 02:19:43 +00:00
Carter Anderson f4d17d9eb2 Next Generation Scenes: Core scene system, bsn! macro, Templates (#23413)
After much [iteration](https://github.com/bevyengine/bevy/pull/20158),
[designing](https://github.com/bevyengine/bevy/discussions/14437) and
[collaborating](https://discord.com/channels/691052431525675048/1264881140007702558),
it is finally time to land a baseline featureset of Bevy's Next
Generation Scene system, often known by its new scene format name ...
BSN (Bevy Scene Notation).

This PR adds the following:
- **The new scene system**: The core in-memory traits, asset types, and
functionality for Bevy's new scene system. Spawn `Scene`s and
`SceneList`s. Inherit from other scenes. Patch component fields. Depend
on assets before loading as scene. Resolve Entity references throughout
your scene.
- **The `bsn!` and `bsn_list!` macro**s: Define Bevy scenes in your code
using a new ergonomic Rust-ey syntax, which plays nicely with Rust
Analyzer and supports autocomplete, go-to definition, semantic
highlighting, and doc hover.
- **`Template` / `GetTemplate`**: construct types (ex: Components) from
a "template context", which includes access to the current entity _and_
access to the `World`. This is a foundational piece of the scene system.

Note that this _does not_ include a loader for the BSN asset format,
which will be added in a future PR. See the "Whats Next?" section for a
roadmap of the future.

Part of #23030 

## Review Etiquette

This is a big PR. _Please use threaded comments everywhere, not top
level comments_. Even if what you have to say is not anchored in code,
find a line to leave your comment on.

## Overview

This is a reasonably comprehensive conceptual overview / feature list.
This uses a "bottom up" approach to illustrate concepts, as they build
on each other. If you just want to see what BSN looks like, scroll down
a bit!
### Templates

`Template` is a simple trait implemented for "template types", which
when passed an entity/world context, can produce an output type such as
a `Component` or `Bundle`:

```rust
pub trait Template {
    type Output;
    fn build_template(&mut self, context: &mut TemplateContext) -> Result<Self::Output>;
}
```

Template is the cornerstone of the new scene system. It allows us to
define types (and hierarchies) that require no `World` context to
define, but can _use_ the `World` to produce the final runtime state.
Templates are notably:

* **Repeatable**: Building a Template does not consume it. This allows
us to reuse "baked" scenes / avoid rebuilding scenes each time we want
to spawn one. If a Template produces a value this often means some form
of cloning is required.
* **Clone-able**: Templates can be duplicated via
`Template::clone_template`, enabling scenes to be duplicated, supporting
copy-on-write behaviors, etc.
* **Serializable**: Templates are intended to be easily serialized and
deserialized, as they are typically composed of raw data.

The poster-child for templates is the asset `Handle<T>`. We now have a
`HandleTemplate<T>`, which wraps an `AssetPath`. This can be used to
load the requested asset and produce a strong `Handle` for it.

```rust
impl<T: Asset> Template for HandleTemplate<T> {
    type Output = Handle<T>;
    fn build_template(&mut self, context: &mut TemplateContext) -> Result<Handle<T>> {
        Ok(context.resource::<AssetServer>().load(&self.path))
    }
}
```

Types that have a "canonical" `Template` can implement the `GetTemplate`
trait, allowing us to correlate to something's `Template` in the type
system.

```rust
impl<T: Asset> GetTemplate for Handle<T> {
    type Template = HandleTemplate<T>;
}
```

This is where things start to get interesting. `GetTemplate` can be
derived for types whose fields also implement `GetTemplate`:

```rust
#[derive(Component, GetTemplate)]
struct Sprite {
  image: Handle<Image>,
}
```

Internally this produces the following:

```rust
#[derive(Template)]
struct SpriteTemplate {
  image: HandleTemplate<Image>,
}

impl GetTemplate for Sprite {
    type Template = SpriteTemplate;
}
```

Another common use case for templates is `Entity`. With templates we can
resolve an identifier of an entity in a scene to the final `Entity` it
points to (for example: an entity path or an "entity reference" ... this
will be described in detail later).

Both `Template` and `GetTemplate` are blanket-implemented for any type
that implements both Clone and Default. This means that _most_ types are
automatically usable as templates. Neat!

```rust
impl<T: Clone + Default> Template for T {
    type Output = T;

    fn build_template(&mut self, context: &mut TemplateContext) -> Result<Self::Output> {
        Ok(self.clone())
    }
}

impl<T: Clone + Default> GetTemplate for T {
    type Template = T;
}
```

It is best to think of `GetTemplate` as an alternative to `Default` for
types that require world/spawn context to instantiate. Note that because
of the blanket impl, you _cannot_ implement `GetTemplate`, `Default`,
and `Clone` together on the same type, as it would result in two
conflicting GetTemplate impls. This is also why `Template` has its own
`Template::clone_template` method (to avoid using the Clone impl, which
would pull in the auto-impl).
### Scenes

Templates on their own already check many of the boxes we need for a
scene system, but they aren't enough on their own. We want to define
scenes as _patches_ of Templates. This allows scenes to inherit from /
write on top of other scenes without overwriting fields set in the
inherited scene. We want to be able to "resolve" scenes to a final group
of templates.

 This is where the `Scene` trait comes in:

```rust
pub trait Scene: Send + Sync + 'static {
    fn resolve(&self, context: &mut ResolveContext, scene: &mut ResolvedScene) -> Result<(), ResolveSceneError>;
    fn register_dependencies(&self, _dependencies: &mut Vec<AssetPath<'static>>);
}
```

The `ResolvedScene` is a collection of "final" `Template` instances
which can be applied to an entity. `Scene::resolve` applies the `Scene`
as a "patch" on top of the final `ResolvedScene`. It stores a flat list
of templates to be applied to the top-level entity _and_ typed lists of
related entities (ex: Children, Observers, etc), which each have their
own ResolvedScene. `Scene`s are free to modify these lists, but in most
cases they should probably just be pushing to the back of them.
`ResolvedScene` can handle both repeated and unique instances of a
template of a given type, depending on the context.

`Scene::register_dependencies` allows the Scene to register whatever
asset dependencies it needs to perform `Scene::resolve`. The scene
system will ensure `Scene::resolve` is not called until all of the
dependencies have loaded.

`Scene` is always _one_ top level / root entity. For "lists of scenes"
(such as a list of related entities), we have the `SceneList` trait,
which can be used in any place where zero to many scenes are expected.
These are separate traits for logical reasons: world.spawn() is a
"single entity" action, scene inheritance only makes sense when both
scenes are single roots, etc.
### Template Patches

The `TemplatePatch` type implements `Scene`, and stores a function that
mutates a template. Functionally, a `TemplatePatch` scene will
initialize a `Default` value of the patched `Template` if it does not
already exist in the `ResolvedScene`, then apply the patch on top of the
current Template in the `ResolvedScene`. Types that implement `Template`
can generate a `TemplatePatch` like this:

```rust
#[derive(Template)]
struct MyTemplate {
    value: usize,
}

MyTemplate::patch_template(|my_template, context| {
    my_template.value = 10;
});
```

Likewise, types that implement `GetTemplate` can generate a patch _for
their template type_ like this:

```rust
#[derive(GetTemplate)]
struct Sprite {
    image: Handle<Image>,
}

Sprite::patch(|sprite_template| {
    // note that this is HandleTemplate<Image>
    sprite.image = "player.png".into();
})
```

We can now start composing scenes by writing functions that return `impl
Scene`!

```rust
fn player() -> impl Scene {
    (
        Sprite::patch(|sprite| {
            sprite.image = "player.png".into();
        ),
        Transform::patch(|transform| {
            transform.translation.y = 4.0;
        }),
    )
}
```

### The `on()` Observer / event handler Scene

`on` is a function that returns a scene that creates an Observer
template:

```rust
fn player() -> impl Scene {
    (
        Sprite::patch(|sprite| {
            sprite.image = "player.png".into();
        ),
        on(|jump: On<Jump>| {
            info!("player jumped!");
        })
    )
}
```

### The BSN Format

`BSN` is a new specification for defining Bevy Scenes. It is designed to
be as Rust-ey as possible, while also eliminating unnecessary syntax and
context. The goal is to make defining arbitrary scenes and UIs as easy,
delightful, and legible as possible.

It is intended to be usable as both an asset format (ex: `level.bsn`
files) _and_ defined in code via a `bsn!` macro. These are notably
_compatible with each other_. You can define a BSN asset file (ex: in a
visual scene editor, such as the upcoming Bevy Editor), then inherit
from that and use it in `bsn!` defined in code.

```rust
:"player.bsn"
Player
Sprite { image: "player.png" }
Health(10)
Transform {
	translation: Vec3 { y: 4.0 }
}
on(|jump: On<Jump>| {
	info!("player jumped!");
})
Children [
	(
		Hat
		Sprite { image: "cute_hat.png" }
		Transform { translation: Vec3 { y: 3.0 } } )
	),
	(:sword Transform { translation: Vec3 { x: 10. } } 
]
```

Note that this PR includes the `bsn!` macro, but it does not include the
BSN asset format. It _does_ include all of the in-memory / in-code
support for the asset format. All that remains is defining a BSN asset
loader, which will be done in a followup.
### The `bsn!` Macro

`bsn!` is an _optional_ ergonomic syntax for defining `Scene`
expressions. It was built in such a way that Rust Analyzer autocomplete,
go-to definition, doc hover, and semantic token syntax highlighting
works as expected pretty much everywhere (but there are _some_ gaps and
idiosyncrasies at the moment, which I believe we can iron out).

It looks like this:

```rust
fn player() -> impl Scene {
    bsn! {
        Player
        Sprite { image: "player.png" }
        Health(10)
        Transform {
            translation: Vec3 { y: 4.0 }
        }
        on(|jump: On<Jump>| {
            info!("player jumped!");
        })
        Children [
            (
                Hat
                Sprite { image: "cute_hat.png" }
                Transform { translation: Vec3 { y: 3.0 } } )
            ),
            (:sword Transform { translation: Vec3 { x: 10. } } 
        ]
    }
}

fn sword() -> impl Scene {
    bsn! {
       Sword
       Sprite { image: "sword.png" } 
    }
}

fn blue_player() -> impl Scene {
    bsn! {
        :player
        Team::Blue
        Children [
            Sprite { image: "blue_shirt.png" } 
        ]
    }
}
```

I'll do a brief overview of each implemented `bsn!` feature now.

### `bsn!`: Patch Syntax

When you see a normal "type expression", that resolves to a
`TemplatePatch` as defined above.

```rust
bsn! {
    Player {
        image: "player.png"
    }
}
```

This resolve to the following:

```rust
<Player as GetTemplatePatch>::patch(|template| {
    template.image = "player.png".into();
})
```

This means you only need to define the fields you actually want to set!

Notice the implicit `.into()`. Wherever possible, `bsn!` provides
implicit `into()` behavior, which allows developers to skip defining
wrapper types, such as the `HandleTemplate<Image>` expected in the
example above.

This also works for nested struct-style types:

```rust
bsn! {
    Transform {
        translation: Vec3 { x: 1.0 }
    }
}
```

Note that you can just define the type name if you don't care about
setting specific field values / just want to add the component:

```rust
bsn! {
    Transform
}
```

To add multiple patches to the entity, just separate them with spaces or
newlines:

```rust
bsn! {
    Player
    Transform
}
```

Enum patching is also supported:

```rust
#[derive(Component, GetTemplate)]
enum Emotion {
    Happy { amount: usize, quality: HappinessQuality },
    Sad(usize),
}

bsn! {
    Emotion::Happy { amount: 10. }
}
```

Notably, when you derive GetTemplate for an enum, you get default
template values for _every_ variant:

```rust
// We can skip fields for this variant because they have default values
bsn! { Emotion::Happy }

// We can also skip fields for this variant
bsn! { Emotion::Sad }
```

This means that unlike the `Default` trait, enums that derive
`GetTemplate` are "fully patchable". If a patched variant matches the
current template variant, it will just write fields on top. If it
corresponds to a different variant, it initializes that variant with
default values and applies the patch on top.

For practical reasons, enums only use this "fully patchable" approach
when in "top-level scene entry patch position". _Nested_ enums (aka
fields on patches) require specifying _every_ value. This is because the
majority of types in the Rust and Bevy ecosystem will not derive
`GetTemplate` and therefore will break if we try to create default
variants values for them. I think this is the right constraint solve in
terms of default behaviors, but we can discuss how to support both
nested scenarios effectively.

Constructors also work (note that constructor args are _not_ patched.
you must specify every argument). A constructor patch will fully
overwrite the current value of the Template.

```rust
bsn! {
    Transform::from_xyz(1., 2., 3.)
}
```

You can also use type-associated constants, which will also overwrite
the current value of the template:

```rust
bsn! {
    Transform::IDENTITY
}
```

If you have a type that does not currently implement
Template/GetTemplate, you have two options:

```rust
bsn! {
    // This will return a Template that produces the returned type.
    // `context` has World access!
	template(|context| {
	    Ok(TextFont {
	        font: context
	            .resource::<AssetServer>()
	            .load("fonts/FiraSans-Bold.ttf").into(),
	        ..default()
	    })
	})
	
	// This will return the value as a Template
	template_value(Foo::Bar)
}
```
### `bsn!` Template patch syntax

Types that are expressed using the syntax we learned above are expected
to implement `GetTemplate`. If you want to patch a `Template` _directly_
by type name (ex: your Template is not paired with a GetTemplate type),
you can do so using `@` syntax:

```rust
struct MyTemplate {
    value: usize,
}

impl Template for MyTemplate {
    /* impl here */
}

bsn! {
    @MyTemplate {
        value: 10.
    }
}
```

In most cases, BSN encourages you to work with the _final_ type names
(ex: you type `Sprite`, not `SpriteTemplate`).

However in cases where you really want to work with the template type
directly (such as custom / manually defined templates), "Template patch
syntax" lets you do that!
### `bsn!`: Inline function syntax

You can call functions that return `Scene` impls inline. The `on()`
function that adds an Observer (described above) is a particularly
common use case

```rust
bsn! {
    Player
    on(|jump: On<Jump>| {
        info!("Player jumped");
    })
}
```

### `bsn!`: Relationship Syntax

`bsn!` provides native support for spawning related entities, in the
format `RelationshipTarget [ SCENE_0, ..., SCENE_X ]`:

```rust
bsn! {
    Node { width: Px(10.) } 
    Children [
        Node { width: Px(4.0) },
        (Node { width: Px(4.0) } BackgroundColor(srgb(1.0, 0.0, 0.0)),
    ]
}
```

Note that related entity scenes are comma separated. Currently they can
either be flat _or_ use `()` to group them:

```rust
bsn! {
    Children [
        // Child 1
        Node BorderRadius::MAX,
        // Child 2
        (Node BorderRadius::MAX),
    ]
}
```

It is generally considered best practice to wrap related entities with
more than one entry in `()` to improve legibility.

### `bsn!`: Expression Syntax

`bsn!` supports expressions in a number of locations using `{}`:

```rust
let x: u32 = 1;
let world = "world";
bsn! {
    // Field position expressions
    Health({ x + 2 })
    Message {
        text: {format!("hello {world}")}
    }
}
```

Expressions in field position have implicit `into()`.

Expressions are also supported in "scene entry" position, enabling
nesting `bsn!` inside `bsn!`:

```rust
let position = bsn! {
    Transform { translation: Vec3 { x: 10. } }
};

bsn! {
    Player
    {position}
}
```

### `bsn!`: Inline variables

You can specify variables inline:

```rust
let black = Color::BLACK;
bsn! {
    BackgroundColor(black)
}
```

This also works in "scene entry" position:

```rust
let position = bsn! {
    Transform { translation: Vec3 { x: 10. } }
};

bsn! {
    Player
    position
}
```

### Inheritance

`bsn!` uses `:` to designate "inheritance". Unlike defining scenes
inline (as mentioned above), this will _pre-resolve_ the inherited
scene, making your current scene cheaper to spawn. This is great when
you inherit from large scene (ex: an asset defined by a visual editor).
Scenes can only inherit from one scene at a time, and it must be defined
first.

You can inherit from scene assets like this:

```rust
fn red_button() -> impl Scene {
    bsn! {
        :"button.bsn"
        BackgroundColor(RED)
    }
}
```

Note that while there is currently no implemented `.bsn` asset format,
you can still test this using `AssetServer::load_with_path`.

You can also inherit from functions that return a `Scene`:

```rust
fn button() -> impl Scene {
    bsn! {
        Button
        Children [
            Text("Button")
        ]
    }
}

fn red_button() -> impl Scene {
    bsn! {
        :button
        BackgroundColor(RED)
    }
}
```

Note that because inheritance is cached / pre-resolved, function
inheritance does not support function parameters. You can still use
parameterized scene functions by defining them directly in the scene
(rather than using inheritance):

```rust
fn button(text: &str) -> impl Scene {
    bsn! {
        Button
        Children [
            Text(text)
        ]
    }
}

fn red_button() -> impl Scene {
    bsn! {
        button("Click Me")
        BackgroundColor(RED)
    }
}
```

Related entities can also inherit:

```rust
bsn! {
    Node
    Children [
        (:button BackgroundColor(RED)),
        (:button BackgroundColor(BLUE)),
    ]
}
```

Inheritance concatenates related entities:

```rust
fn a() -> impl Scene {
    bsn! {
        Children [
            Name("1"),
            Name("2"),
        ]
    }
}

fn b() -> impl Scene {
    /// this results in Children [ Name("1"), Name("2"), Name("3") ]
    bsn! {
        :a
        Children [
            Name("3"),
        ]
    }
}
```

### `bsn_list!` / SceneList

Relationship expression syntax `{}` expects a SceneList. Many things,
such as `Vec<S: Scene>` implement `SceneList` allowing for some cool
patterns:

```rust
fn inventory() -> impl Scene {
    let items = (0..10usize)
        .map(|i| bsn! {Item { size: {i} }})
        .collect::<Vec<_>>();
    bsn! {
        Inventory [
            {items}
        ]
    } 
}
```

The `bsn_list!` macro allows defining a list of BSN entries (using the
same syntax as relationships). This returns a type that implements
`SceneList`, making it useable in relationship expressions!

```rust
fn container() -> impl Scene {
    let children = bsn_list! [
        Name("Child1"),
        Name("Child2"),
        (Name("Child3") FavoriteChild),
    ]
    bsn! {
        Container [
            {children}
        ]
    } 
}
```

This, when combined with inheritance, means you can build abstractions
like this:

```rust
fn list_widget(children: impl SceneList) -> impl Scene {
    bsn! {
        Node {
            width: Val::Px(1.0)
        }
        Children [
            Text("My List:")
            {children}
        ]
    }
}

fn ui() -> impl Scene {
    bsn! {
        Node
        Children [
            list_widget({bsn_list! [
                Node { width: Px(4.) },
                Node { width: Px(5.) },
            ]})
        ]
    }
}
```

### `bsn!`: Name Syntax

You can quickly define `Name` components using `#Name` shorthand.

```rust
bsn! {
    #Root
    Node
    Children [
        (#Child1, Node),
        (#Child2, Node),
    ]
}
```

`#MyName` produces the `Name("MyName")` component output.

Within a given `bsn!` or `bsn_list!` scope, `#Name` can _also_ be used
in _value position_ as an `Entity` Template:

```rust
#[derive(Component, GetTemplate)]
struct UiRoot(Entity);

#[derive(Component, GetTemplate)]
struct CurrentButton(Entity);

bsn! {
	#Root
	CurrentButton(#MyButton)
	Children [
		(
		  #MyButton,
		  UiRoot(#Root)
		)
	]
}
```

These behave a bit like variable names. In the context of inheritance
and embedded scenes, `#Name` is only valid within the current "scene
scope":

```rust
fn button() -> impl Scene {
	bsn! {
		#Button
		Node
		Children [
			ButtonRef(#Button)
		]
	}
}

fn red_button() -> impl Scene {
	bsn! {
		:button
		// #Button is not valid here, but #MyButton
		// will refer to the same final entity as #Button
		#MyButton
		Children [
			AnotherReference(#MyButton)
		]
	}
}
```

In the example above, because `#MyButton` is defined "last" / is the
most "specific" `Name`, the spawned entity will have `Name("MyButton")`

Name references are allowed to conflict across inheritance scopes and
they will not interfere with each other.

`#Name` can also be used in the context of `bsn_list!`, which enables
defining graph structures:

```rust
bsn_list! [
	(#Node1, Sibling(#Node2)),
	(#Node2, Sibling(#Node1)),
]
```
### Name Restructure

The core name component has also been restructured to play nicer with
`bsn!`. The impl on `main` requires `Name::new("MyName")`. By making the
name string field public and internalizing the prehash logic on that
field, and utilizing implicit `.into()`, we can now define names like
this:

```rust
bsn! {
    Name("Root")
    Children [
        Name("Child1"),
        Name("Child2"),
    ]
}
```

### BSN Spawning

You can spawn scenes using `World::spawn_scene` and
`Commands::spawn_scene`:

```rust
world.spawn_scene(bsn! {
    Node
    Children [
        (Node BackgroundColor(RED))
    ]
})?;

commands.spawn_scene(widget());
```

The `spawn_scene` operation happens _immediately_, and therefore assumes
that all of the `Scene`'s dependencies have been loaded (or
alternatively, that there are no dependencies). If the scene has a
dependency that hasn't been loaded yet, `World::spawn_scene` will return
an error (or log an error in the context of `Commands::spawn_scene`).

If your scene has dependencies, you can use `World::queue_spawn_scene`
and `Commands::queue_spawn_scene`. This will spawn the entity as soon as
all of the `Scene`'s dependencies have been loaded.

```rust
// This will spawn the entity once the "player.bsn" asset is loaded
world.queue_spawn_scene(bsn! {
  :"player.bsn"
  Transform { position: Vec3 { x: 10. } }
});
```

There are also `spawn_scene_list` variants for everything above:

```rust
world.spawn_scene_list(bsn_list! [
	button("Ok"),
	button("Cancel"),
])
```

`EntityWorldMut` and `EntityCommands` also have some new functionality:

```rust
entity.queue_spawn_related_scene::<Children>(bsn_list! [
	(:"player.bsn", #Player1),
	(:"player.bsn", #Player2),
]);
```

```rust
entity.apply_scene(bsn! {
	Transform { position: Vec3 { x: 10. } }
})?;
```

For scene assets, you can also just add the `ScenePatchInstance(handle)`
component, just like the old Bevy scene system.
### VariantDefaults derive

`GetTemplate` automatically generates default values for enum Template
variants. But for types that don't use `GetTemplate`, I've also
implemented a `VariantDefaults` derive that also generates these
methods.

## What's Next?

### Must happen before 0.19
- [ ] **Sort out `bevy_scene` vs `bevy_scene2`**: The current plan is to
rename `bevy_scene` to `bevy_ecs_serialization`, and remove "scene"
terminology from it. That then frees up `bevy_scene2` to be renamed to
`bevy_scene`. The current `bevy_scene` will need to exist for awhile in
parallel to BSN, as BSN is not yet ready for "full world serialization"
scenarios.
- [x] ~~**Resolve the Default Handle situation**: Currently, to provide
Template support for `Handle`, it implements `GetTemplate`. This of
course conflicts with `impl Default for Handle`. This is pretty
disruptive to non-BSN users (which is currently everyone). We'll want to
sort out a middleground solution in the short term that ideally allows
us to keep `impl Default for Handle` during the transition.~~
- Resolved this by using a [specialization
trick](https://github.com/bevyengine/bevy/pull/23413#discussion_r2961341173)
- [ ] Nested `bsn!` `Scene` tuples to surpass tuple impl limits


### Ideally before 0.19

We likely won't land all of these. The plan is to (ideally) land this PR
before Bevy 0.19 RC1, then _maybe_ land a couple more of these before

- [ ] **Feathers BSN Port**: Largely already done. Just need to
reconcile with current state of main. This will help BSN land well, so
landing it alongside BSN is a high priority.
- [ ] **ResolvedScene-as-dynamic-bundle**: ResolvedScene should insert
all of the components at once as a single bundle, rather than
one-by-one, which is really bad from an archetype move perspective.
Without this, using `world.spawn_scene(scene)` as a
`world.spawn(bundle)` replacement will result in a pretty significant
performance reduction.
- [ ] **`#Name` references in more places**: The UI eventing scenario
_really_ wants `#Name` to be usable in closures. This would functionally
be expressed as a template that returns a closure that accesses a
specific entity. This unlocks a lot of value for UI devs, so ideally it
lands alongside BSN.
- [ ] **Top-down vs bottom-up spawn order**: Currently BSN follows the
normal bevy top-down spawn order. I think we should heavily consider
spawning bottom-up, in the interest of making scene contents available
to "higher level" components in their lifecycle events (ex: a `Player`
component accessing nested entities like "equipment" when inserted). If
we decide to keep things as they are, we probably want to introduce
additional "scene ready" entity events that trigger "bottom up".
- [ ] **Inline field value expressions**: Support cases such as
`px(10).all()
- [ ] **Add EntityPath to EntityTemplate**: Support resolving entity
paths (ex: `"Root/Child1/GrandChild1"`). This is relatively low hanging
fruit, especially if we switch to bottom-up spawning order.
- [ ] **Function Inheritance Caching**: Currently only scene asset
inheritance is pre-computed / cached. For consistency / predictability /
optimizations, function inheritance (ex `:button`) should also be
cached.
- [ ] **`derive(GetTemplate)` generics ergonomics**: Currently this
requires casting spells: `T: GetTemplate<Template: Default +
Template<Output = T>>`

### Near Future
- [ ] **BSN Asset Format**: Add a `.bsn` parser / AssetLoader that can
produce the current `ScenePatch` assets.
- [ ] **Struct-style inheritance**: It would be nice to be able to do
something like `:Button { prop } ` instead of `:button(prop)`. I'd
really like us to explore this being component-tied (ex: associate a
scene with a Button component).
- [ ] **Descendant Patching**: It should be possible to "reach in" to an
inherited scene and patch one of its descendants / children.
- [ ] **Optimize Related Entity Spawning**: This currently inserts the
relationship component first, then spawns the related scene. This
results in an unnecessary archetype move.
- [ ] Observers as relationships
- [ ] **Scene-owned-entities**: Currently when spawning a `Scene`, every
entity defined in the scene is instantiated. Some scenarios would
benefit from Scene instances _sharing_ some unique entity. For example:
defining assets _inside_ of scenes (this would pair nicely with Assets
as Entities) , sharing Observer entities, etc.
- [ ] The `touch_type::<Nested>()` approach could be replaced with `let
x: &mut Nested` for actual type safety (and probably better
autocomplete).
- [ ] Fix Rust Analyzer autocomplete bug that fails to resolve functions
and enums for `<Transform as GetTemplate>::Template::from_transform()`
- [ ] Fix Rust Analyzer autocomplete bug that also suggests function
names when type struct field names. This _should_ be fixed by using
irrefutable `if let` statements. And it would probably allow us to reuse
macro code across enums / structs (and avoid needing to use PathType
inference in this case, which has gnarly corner cases).
### Longer Term
- [ ] **`bsn!` hot patching via subsecond**: [Proof of concept
here](https://github.com/cart/bevy/pull/36)
- [ ] **Reactivity**: This has been proven out
[here](https://github.com/viridia/bevy_reactor/)
- [ ] **BSN Sets**: See the [old design
doc](https://github.com/bevyengine/bevy/discussions/14437) for the
design space I'm talking about here
* This would also allow expressing "flattened" forms of BSN, which makes
diffs easier to read in some case
- [ ] **World to BSN**: If we can support this, BSN can be used for
things like saving Worlds to disk. This might also be useful for
building scene editors.

---------

Co-authored-by: andriyDev <andriydzikh@gmail.com>
Co-authored-by: Nico Zweifel <34443492+NicoZweifel@users.noreply.github.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: copygirl <copygirl@mcft.net>
2026-03-27 03:18:26 +00:00
Christian Hughes 4b09a461e9 Simplify Command error handling traits (#23432)
# Objective

I have working `Command` reflection for my game:

```rust
#[derive(Clone)]
pub struct ReflectCommand {
    pub apply: fn(&mut World, &dyn PartialReflect, &TypeRegistry),
}

impl ReflectCommand {
    pub fn apply(&self, world: &mut World, command: &dyn PartialReflect, registry: &TypeRegistry) {
        (self.apply)(world, command, registry);
    }
}

impl<C: Command<Result> + Reflect + TypePath> FromType<C> for ReflectCommand {
    fn from_type() -> Self {
        ReflectCommand {
            apply: |world, command, registry| {
                let command = from_reflect_with_fallback::<C>(command, world, registry);
                command.apply(world);
            },
        }
    }
}
```

However, I am currently only allowed to support a single output type
across *all* command types (which I've chosen to be `Result` for the
time being). This is because, by virtue of `Out` being a generic
parameter, `Command` *can* be implemented multiple times for the same
type, but with different output types. In order for my command
reflection logic to support command types with *any* output type, I need
the ability to guarantee that `Command` will only be implemented once
for some `FooCommand`.

That's why `Out` should be changed into an associated type.

## Solution

- Turned the `Out` generic parameter into an associated type on both
`Command` and `EntityCommand`.
- Bounded `Command::Out` associated type with a new `CommandOutput`
trait.
- This replaces the functionality of the now removed `HandleError`
trait, and allows us to add its functions directly on the `Command`
trait.
- Also bounded `EntityCommand::Out` associated type with the new
`CommandOutput` trait.
- This replaces the functionality of the now removed `CommandWithEntity`
trait, and allows us to add its functions directly on the
`EntityCommand` trait.

Additionally, the new `CommandOutput` trait gives a place for bevy users
to hook into error handling logic with their own types! It also comes
with `diagnostic::on_unimplemented` diagnostics!

## Testing

Maybe TODO: Current tests appear green but should we add tests for the
new `CommandOutput` trait?
2026-03-22 20:09:31 +00:00
atlv 1aea391609 Support Custom SystemExecutors (#23414)
# Objective

- Audio wants a realtime-safe executor with minimal checking. This means
no command application or multithreading etc.

## Solution

- Make it possible to supply our own executor.

## Testing

- Tests are updated
- New custom executor example

Note: reviewing commits individually is probably easier.
2026-03-19 20:23:33 +00:00
Alice Cecile b265dc042a Merge SystemParam::validate_param into SystemParam::get_param (#23225)
# Objective

As raised in
[#23174](https://github.com/bevyengine/bevy/pull/23174#discussion_r2868030355_),
we currently duplicate working when looking up our system parameters:
once during validation, and then again when actually fetching the data.

This is (maybe) slow, and would worsen the performance regression
incurred by resources-as-components (#19731).

This strategy also imposes some non-trivial complexity and
maintainability costs. Because "validate" is a distinct step from "use",
it's possible to skip validation! As far as I could tell, this is the
case in a number of places before this PR: particularly in the
unconventional "please just run my system" path. While in most cases
this will simply result in a crash in a different place, it causes these
paths to not handle

Fixes #23179. Fixes #15505.

## Solution

Fundamentally, what we're doing is rolling the
`SystemParam::validate_param` behavior into `SystemParam::get_param`, by
making the latter return a `Result`.

However, there is a tremendous amount of splash damage required to get
that to actually compile and expose the correct semantics. The most
important of these are:

- `SystemState::get` and friends now returns a `Result`
- this leads to a fair bit of assorted unwrap spam in our tests and
weird internal usages
- these tests can probably be refactored to not use `SystemState`
directly in the future now that we have better tools like
`run_system_once`, but eh, not this PR's job
- this is semantically correct, as these params could fail validation
- `System::validate_param_unsafe` has been removed, and validation now
occurs inside of `System::run_unsafe`
- very much a net positive for both abstract robustness and current
correctness
- this impacts the strategy that various executors use: see the next
section

There are a *lot* of moving parts here: I'm sorry that I couldn't get
this into a smaller, more incremental refactor. When reviewing this PR,
you should begin with the migration guide to help get you oriented on
the details: `validation_merging.md`.

From there, the most important files to review are:

1. `system_param.rs`: trait changes and implementers
2. `function_system.rs`: primary implementer of `System`
3. `multithreaded.rs`: the parallel executor

**NOTE TO REVIEWERS:** Please make comments to generate threads; this PR
review might get fairly hairy.

### Performance discussion

For the parallel `MultithreadedExecutor`, validation was previously done
as a cheap pre-validation step,
while checking run conditions.
Now, tasks will be spawned for systems which would fail or are skipped
during validation.

In most cases, avoiding the extra overhead of looking up the required
data twice should dominate.
However, this change may negatively affect systems which are frequently
skipped (e.g. due to `Single`).

### Paths not taken

In this PR, I've decided not to:

- Add another variant
[RunSystemError](https://docs.rs/bevy/latest/bevy/ecs/system/enum.RunSystemError.html),
distinguishing "validation failed" from "system ran but returned an
error".
- While reusing
[RunSystemError::Failed](https://docs.rs/bevy/latest/bevy/ecs/system/enum.RunSystemError.html#variant.Failed)
for both cases is messy, this PR is already a bit of a nightmare to
review.
- Return a result from `ParamSet::get_mut`.
   - Instead, we just `unwrap`.
- Bubbling up the `Result` is technically more correct, but these were
already panicking before if e.g. a resource is missing, and `ParamSet`
is already an ergonomic abomination.

## Testing

I've added a number of new tests to exercise the system param validation
paths, ensuring that validation is done when systems are run.

However, I would appreciate some help benchmarking the net impact on
realistic-ish scenes. `breakout`, `bevy_city` and `many_animated_foxes`
are probably a decent scattering, but I'd be very open to other
suggestions.

Having done this refactor, I think that it's a net improvement for
robustness and clarity even without the perf benefits however, and that
we should proceed unless this is a clear regression.

---------

Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
2026-03-11 19:03:10 +00:00
Gonçalo Rica Pais da Silva f255b8e57a Upgrade glam, hexasphere, rand & uuid to latest versions (#22928)
# Objective

- `glam`, `hexasphere` & `rand` have released their latest versions,
update Bevy to support them.

## Solution

- The above have been updated to their compatible versions. `rand_distr`
updated as well to match `rand` v0.10 support.
- `rand_chacha` is soft deprecated and no longer used by `rand`, so its
usage has been changed to `chacha20` to match `rand` dep tree.
- `uuid` is in the process of updating to `getrandom` v0.4, which `rand`
v0.10 supports. This PR remains in draft until a new `uuid` release hits
crates.io.
- `RngCore` is now `Rng`, and `Rng` is now `RngExt`, so this required
updating across many files.
- `choose_multiple` method is deprecated, changed to `sample`.

## Testing

- Chase all compiler errors, since this should not regress any already
existing behaviour.
- This must pass CI without regressions.

## Additional Notes

`getrandom` v0.4 doesn't add anything new for Web WASM support, so the
same `wasm_js` feature is used.
2026-02-19 22:17:25 +00:00
Eagster 4cc92a00e7 Amortize the cost of freeing entities (#22658)
# Objective

The biggest drawback of #18670 was that it made freeing `Entity`'s back
to the allocator 4x slower. That meant a 20% regression in despawn
performance. This PR vastly improves the performance of the entity
allocator for freeing entities.

## Solution

Add a local free list in pace in the main entity allocator. This is an
`ArrayVec` called `quick_free`. When an entity is freed, add it to the
`quick_free`. If it is full, flush the array to the full shared
allocator.

Currently the array has length 64, taking 512 bytes. Since this is
directly included in the already massive `World` type, I don't think
this is an issue, and I would guess boxing it would hurt performance
here. It also means that there will be at most 64 freed entities that
simply can't be allocated. This reduces the worst case maximum entity
count from 4,294,967,296 to 4,294,967,232 (big deal).

This also adds a new `free_many` function that is very fast compared to
doing them one by one.

## Testing

- CI and benches.

---

## Showcase

Here are some rough benchmarks on my M2 MAX:

```txt
group                                        post_quick_free_list                   pre_quick_free_list                    pre_remote_reservation
-----                                        --------------------                   -------------------                    ----------------------
entity_allocator_free/10000_entities         1.00     29.7±0.48µs        ? ?/sec    1.31     38.9±0.97µs        ? ?/sec    1.00     29.8±0.85µs        ? ?/sec
entity_allocator_free/100_entities           1.00   393.3±26.21ns        ? ?/sec    1.35   531.8±26.34ns        ? ?/sec    1.14   446.7±11.32ns        ? ?/sec
entity_allocator_free/1_entities             1.00      4.6±2.17ns        ? ?/sec    42.27  195.3±32.49ns        ? ?/sec    4.25     19.6±8.67ns        ? ?/sec
entity_allocator_free_bulk/10000_entities    1.00      8.7±0.36µs        ? ?/sec
entity_allocator_free_bulk/100_entities      1.00   240.9±31.01ns        ? ?/sec
entity_allocator_free_bulk/1_entities        1.00   206.8±39.95ns        ? ?/sec
```

Looking at the cost of freeing 1,000 entities, this makes the new
allocator exactly as fast as the pre-#18670 one, 30% faster than main.
The new `free_many` takes 8.7µs to free 1,000 entities where the
optimized `free` takes `29.7`, so another big win there.

This should make up the 20% regression to despawning. It might be even
faster than pre-#18670 if we increase 64 to 128 or something, but I
think that's unnecessary. This could also much improve performance for
despawning scenes if we can find a way to make use of `free_many`, but
that's a different task.
2026-02-03 02:14:11 +00:00
Jenya705 b842bcb923 Contiguous access (#21984)
# Objective

Enables accessing slices from tables directly via Queries.

Fixes: #21861 

## Solution

One new trait:
- `ContiguousQueryData` allows to fetch all values from tables all at
once (an implementation for `&T` returns a slice of components in the
set table, for `&mut T` returns a mutable slice of components in the set
table as well as a struct with methods to set update ticks (to match the
`fetch` implementation))

Methods `contiguous_iter`, `contiguous_iter_mut` and similar in `Query`
and `QueryState` making possible to iterate using these traits.

Macro `QueryData` was updated to support contiguous items when
`contiguous(target)` attribute is added (a target can be `all`,
`mutable` and `immutable`, refer to the `custom_query_param` example)

## Testing

- `sparse_set_contiguous_query` test verifies that you can't use
`next_contiguous` with sparse set components
- `test_contiguous_query_data` test verifies that returned values are
valid
- `base_contiguous` benchmark (file is named
`iter_simple_contiguous.rs`)
- `base_no_detection` benchmark (file is named
`iter_simple_no_detection.rs`)
- `base_no_detection_contiguous` benchmark (file is named
`iter_simple_no_detection_contiguous.rs`)
- `base_contiguous_avx2` benchmark (file is named
`iter_simple_contiguous_avx2.rs`)

---

## Showcase

Examples `contiguous_query`, `custom_query_param`

### Example
```rust
// - self.0 is a World
// - self.1 is a QueryState
// - velocity is a slice of components with Vec3 inside.
// - position is a data structure which implements Deref/DerefMut and IntoIterator methods to access the slice
// as well as mechanism to update update ticks (which it does automatically on dereference), 
// which may be bypassed via `bypass_change_detection` methods.
for (velocity, mut position) in self.1.contiguous_iter_mut(&mut self.0).unwrap() {
    assert!(velocity.len() == position.len());
    for (v, p) in velocity.iter().zip(position.iter_mut()) {
        p.0 += v.0;
    }
}
```

### Benchmarks
Code for `base` benchmark:
```rust
#[derive(Component, Copy, Clone)]
struct Transform(Mat4);

#[derive(Component, Copy, Clone)]
struct Position(Vec3);

#[derive(Component, Copy, Clone)]
struct Rotation(Vec3);

#[derive(Component, Copy, Clone)]
struct Velocity(Vec3);

pub struct Benchmark<'w>(World, QueryState<(&'w Velocity, &'w mut Position)>);

impl<'w> Benchmark<'w> {
    pub fn new() -> Self {
        let mut world = World::new();

        world.spawn_batch(core::iter::repeat_n(
            (
                Transform(Mat4::from_scale(Vec3::ONE)),
                Position(Vec3::X),
                Rotation(Vec3::X),
                Velocity(Vec3::X),
            ),
            10_000,
        ));

        let query = world.query::<(&Velocity, &mut Position)>();
        Self(world, query)
    }

    #[inline(never)]
    pub fn run(&mut self) {
        for (velocity, mut position) in self.1.iter_mut(&mut self.0) {
            position.0 += velocity.0;
        }
    }
}
```
Iterating over 10000 entities from **a single** table and increasing a
3-dimensional vector from component `Position` by a 3-dimensional vector
from component `Velocity`

| Name | Time | Time (AVX2) | Description |

|------------------------------|-----------|-------------|--------------------------------------------------------------------|
| base | 5.5828 µs | 5.5122 µs | Iteration over components |
| base_contiguous | 4.8825 µs | 1.8665 µs | Iteration over contiguous
chunks |
| base_contiguous_avx2 | 2.0740 µs | 1.8665 µs | Iteration over
contiguous chunks with enforced avx2 optimizations |
| base_no_detection | 4.8065 µs | 4.7723 µs | Iteration over components
while bypassing change detection through `bypass_change_detection()`
method |
| base_no_detection_contiguous | 4.3979 µs | 1.5797 µs | Iteration over
components without registering update ticks |

Using contiguous 'iterator' makes the program a little bit faster and it
can be further vectorized to make it even faster
2026-02-03 00:02:26 +00:00
Eagster 8c8e77158c Benchmark remote allocation (#22659)
# Objective

After #18670, we have a `RemoteAllocator`, but we don't have benchmarks
for it compared to the non-remote allocator. This PR just adds those
benchmarks.

I don't know if we actually want these benchmarks, but it seems
reasonable to have, and it took no time to make, so I figured I'd put it
out there.

## Solution

Add `entity_allocator_allocate_fresh_remote` and
`entity_allocator_allocate_reused_remote` benchmark groups.

## Testing

- CI, benchmarks

---

## Showcase

```txt
entity_allocator_allocate_fresh/10000_entities            1.00     22.8±0.29µs        ? ?/sec
entity_allocator_allocate_fresh/100_entities              1.00    227.9±6.37ns        ? ?/sec
entity_allocator_allocate_fresh/1_entities                1.00      6.2±3.83ns        ? ?/sec
entity_allocator_allocate_fresh_bulk/10000_entities       1.00     19.9±0.25µs        ? ?/sec
entity_allocator_allocate_fresh_bulk/100_entities         1.00    227.5±6.95ns        ? ?/sec
entity_allocator_allocate_fresh_bulk/1_entities           1.00     11.5±4.69ns        ? ?/sec
entity_allocator_allocate_fresh_remote/10000_entities     1.00     19.4±0.32µs        ? ?/sec
entity_allocator_allocate_fresh_remote/100_entities       1.00    174.2±3.63ns        ? ?/sec
entity_allocator_allocate_fresh_remote/1_entities         1.00      3.5±3.02ns        ? ?/sec
entity_allocator_allocate_reused/10000_entities           1.00     21.5±0.37µs        ? ?/sec
entity_allocator_allocate_reused/100_entities             1.00   233.3±11.77ns        ? ?/sec
entity_allocator_allocate_reused/1_entities               1.00      8.3±3.70ns        ? ?/sec
entity_allocator_allocate_reused_bulk/10000_entities      1.00     20.4±0.64µs        ? ?/sec
entity_allocator_allocate_reused_bulk/100_entities        1.00   261.5±45.59ns        ? ?/sec
entity_allocator_allocate_reused_bulk/1_entities          1.00    19.7±10.77ns        ? ?/sec
entity_allocator_allocate_reused_remote/10000_entities    1.00     77.9±1.53µs        ? ?/sec
entity_allocator_allocate_reused_remote/100_entities      1.00   774.9±16.28ns        ? ?/sec
entity_allocator_allocate_reused_remote/1_entities        1.00      7.3±3.60ns        ? ?/sec
```

Long story short, remote allocation is a little over 3 times slower than
non-remote. All things considered, I think that's pretty good.
2026-02-02 22:57:00 +00:00
Lucas Franca abbaa47aac Glam 0.31 (#22681)
# Objective

Adopt and closes #22665

## Solution

Delete bevy's `Affine3`, create an extension trait for methods create
for old bevy's `Affine3` to be used by glam's `Affine3`, and register
glam's `Affine3` for reflection

## Testing

`cargo run -p ci`

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-01-25 22:14:28 +00:00
Eagster bb78bbf3bd Add benchmarks for raw entity allocation (#22640)
# Objective

As per
[this](https://github.com/bevyengine/bevy/pull/18670#issuecomment-3781624261)
comment on #18670, this adds benchmarks for direct access to the entity
allocator.

## Solution

Add 5 groups of benchmarks:

- allocating fresh entities
- allocating fresh entities in bulk
- freeing entities
- allocating reused entities
- allocating reused entities in bulk

## Testing

- CI and benches
2026-01-23 01:57:25 +00:00
Eagster cf8f9beea7 Improve realism of entity benches by warming up the entity allocator (#22639)
# Objective

As per
[this](https://github.com/bevyengine/bevy/pull/18670#issuecomment-3776301267)
comment on #18670, this PR attempts to make entity related benchmarks
more realistic by warming up the entity allocator. This helps test the
freelist in the entity allocator.

## Solution

This PR introduces a new `WorldBuilder` type that starts with
`World::new`, allows configuration options for warming up the world via
the builder pattern, and then builds the warmed up, realistic world. For
now, the only available "warm up" is for entities, but we could also add
functionality in the future to cache bundle info, pre-create tables, etc
to make our benchmarks more realistic. That is, more closely match the
performance of a running app, rather than an app at startup.

The current implementation for entity warmups allocates some entities
and frees them in a random order. It also spawns the highest allocated
entity index to prepare `Entities`'s location storage, etc. This
involves using `rng` (deterministically), but without this, the entities
are allocated in a linear index order (0, 1, 2, ...), which is
unrealistic and extremely cache friendly (so it probably makes an impact
in performance not desirable for a benchmark).

The major downsides here are that the benches take a little longer to
run now and that startup/caching time is no longer benchmarked. That is
for example, that benchmarking despawning only one entity used to tell
us some information about performance of allocating the free list
(amongst other one time actions). Now, that information is lost since
the world is already warmed up. In practice, for N values of entities,
it used to be the case that a higher N showed the performance of the
operation, and a lower N showed the performance of the operation + any
registration/caching costs. Now, the different N values only tell us
more about how well the CPU accommodates a batch of the operation.

Currently in Bevy, making a change might make the `...1_entity` benches
much worse but the `...1000_entities` much much better because the
change added some new caching. The inverse is also common. With this PR,
that will no longer be the case, at least for entities and whatever else
we add to the `WorldBuilder` in the future. And that change may or may
not be desirable.

## Testing

Ran a sampling of the benchmarks.
2026-01-23 01:56:51 +00:00
Yash Kumar 41f3ee7e47 Improve time complexity of get_component_mut (#22572)
# Objective

- Addresses #22483.

## Solution

Add a bloom filter to `has_conflicts` as a pre-check to see if we need
to check a given access against every other access or not. If the access
doesn't hit any component or resource a previous access does, we know we
don't need to check it element-by-element. Well-formed calls to
get_components_mut should then be linear in time taken to check for
conflicts, as they would always pass the pre-check.

The filter used is exported in the `bevy_utils` API as it is not
specific to components or resources.

## Testing

Tested via `cargo test`, where the get_component_mut tests pass or panic
as expected.

The get_component_mut benchmarks show >=20% improvements at as little as
5 components compared to the existing fallback for smaller sets. The
larger, 32 component benchmark added shows massive improvements. In
general, the new pre-check filter means we're only about 4-5x slower
than not checking at all.

```
ecs::world::world_get::world_query_get_components_mut/10_components_50000_entities
                        time:   [6.5252 ms 6.5314 ms 6.5388 ms]
                        change: [−34.225% −33.954% −33.747%] (p = 0.00 < 0.05)
                        Performance has improved.
[...]
ecs::world::world_get::world_query_get_components_mut/32_components
                        time:   [21.608 ms 21.696 ms 21.828 ms]
                        change: [−92.284% −92.236% −92.186%] (p = 0.00 < 0.05)
                        Performance has improved.
```
| bench | mean (prev, with fallback threshold) | mean (post, always
complex) | delta |
|-|-|-|-|
| 2_components | 770.73 us | 925.90 us | +19.62% |
| unchecked_2_components | 288.66 us | 288.71 us | -0.84% |
| 5_components | 2.960 ms | 2.286 ms | -22.77% |
| unchecked_5_components | 505.45 us | 521.56 us | +2.14% |
| 10_components | 9.889 ms | 6.531 ms | -33.95% |
| unchecked_10_components | 1.452 ms | 1.538 ms | +5.48% |
| 32_components | 279.44 ms | 21.696 ms | -92.24% |
| unchecked_32_components | 4.460 ms | 4.458 ms | -0.05%
2026-01-22 19:18:17 +00:00
Carter Anderson fb5a669925 Add critcmp to benches README (#22616)
This is useful and we use it regularly. Worth documenting!
2026-01-21 02:24:11 +00:00
MichiRecRoom 7b03032783 Reorganize some of bevy_reflect's exports into their respective modules (#22342)
# Objective
- #22321 

## Solution
Do it

## Testing
`cargo clippy` and CI.

---------

Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
2026-01-13 18:51:51 +00:00
Chris Biscardi 238e1ea665 Add a benchmark for spawn_batch (#22439)
# Objective

There was no benchmark for spawn_batch that I could find.

## Solution

Add one.

The intent here is to make it comparable to the `spawn_world` benchmark,
so I kept the construction of the vec of component data in the
benchmark.

The benchmark uses the iter to use batch sizes from 1 to 10,000, which
also explains the addition of the 1000 level.

## Testing

```
cargo bench -p benches -- world_spawn
```

## Showcase

```
spawn_world/1_entities  time:   [47.966 ns 48.690 ns 49.464 ns]
                        change: [+2.1054% +4.5065% +6.9285%] (p = 0.00 < 0.05)
                        Performance has regressed.
spawn_world/100_entities
                        time:   [4.8244 µs 4.8961 µs 4.9715 µs]
                        change: [−2.9086% −0.5143% +1.9117%] (p = 0.68 > 0.05)
                        No change in performance detected.
spawn_world/10000_entities
                        time:   [473.97 µs 481.61 µs 490.26 µs]
                        change: [−0.5065% +1.7613% +4.2000%] (p = 0.14 > 0.05)
                        No change in performance detected.
Found 1 outliers among 100 measurements (1.00%)
  1 (1.00%) high mild

spawn_world_batch/1_entities
                        time:   [663.32 µs 669.68 µs 677.00 µs]
Found 1 outliers among 100 measurements (1.00%)
  1 (1.00%) high mild
spawn_world_batch/100_entities
                        time:   [379.35 µs 386.57 µs 394.14 µs]
Found 1 outliers among 100 measurements (1.00%)
  1 (1.00%) low mild
spawn_world_batch/1000_entities
                        time:   [354.48 µs 361.06 µs 367.44 µs]
Found 1 outliers among 100 measurements (1.00%)
  1 (1.00%) low mild
spawn_world_batch/10000_entities
                        time:   [382.73 µs 392.63 µs 402.06 µs]
Found 1 outliers among 100 measurements (1.00%)
  1 (1.00%) high mild
```

---------

Co-authored-by: François Mockers <francois.mockers@vleue.com>
2026-01-11 08:22:23 +00:00
Kristoffer Søholm 16409b8a02 Fix lints after Rust 1.92 (#22092)
# Objective

CI is currently failing

## Solution

Fix the lints (and work around all the rustc lint bugs that are
apparently included)

---------

Co-authored-by: MichiRecRoom <1008889+LikeLakers2@users.noreply.github.com>
2025-12-12 09:10:29 +00:00
Mike d76c3aab95 get_components_mut (#21780)
# Objective

- Add a checked version of `EntityMut::get_components_mut` and
`EntityWorldMut::get_components_mut` that does not allocate

## Solution

- Add a iterator over the access type to `QueryData`. This is then used
to iterate over the pairs of access to check if they are compatible or
not.

## Testing

- Added a unit test

### Bench checked vs unchecked (50000 entities)

| #components | unchecked | checked  | times slower |
|-------------|-----------|----------|----------|
| 2           | 509 us    | 1123 us  | 2.2x     |
| 5           | 903 us    | 2902us  | 3.2x     |
| 10          | 1700 us   | 11424 us | 6.72x    |

so at 10 components each call was taking about 0.22us vs 0.03 us

---

## ToDo

* [x] add release note
* [x] add migration guide
* [x] add macro for more benches
* [x] add bench results to pr description
* [ ] look into if this will help with uncached queries
* [x] see if we can optimize it a bit

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-12-08 22:43:07 +00:00
dependabot[bot] c378b7aa7e Update criterion requirement from 0.7.0 to 0.8.0 (#21994)
Updates the requirements on
[criterion](https://github.com/criterion-rs/criterion.rs) to permit the
latest version.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/criterion-rs/criterion.rs/blob/master/CHANGELOG.md">criterion's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/criterion-rs/criterion.rs/compare/criterion-v0.7.0...criterion-v0.8.0">0.8.0</a>
- 2025-11-29</h2>
<h3>BREAKING</h3>
<ul>
<li>Drop async-std support</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Bump MSRV to 1.86, stable to 1.91.1</li>
</ul>
<h3>Added</h3>
<ul>
<li>Add ability to plot throughput on summary page.</li>
<li>Add support for reporting throughput in elements and bytes -
<code>Throughput::ElementsAndBytes</code> allows the text summary to
report throughput in both units simultaneously.</li>
<li>Add alloca-based memory layout randomisation to mitigate memory
effects on measurements.</li>
<li>Add doc comment to benchmark runner in criterion_group macro
(removes linter warnings)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Fix plotting NaN bug</li>
</ul>
<h3>Other</h3>
<ul>
<li>Remove Master API Docs links temporarily while we restore the docs
publishing.</li>
</ul>
<h2>[0.7.0] - 2025-07-25</h2>
<ul>
<li>Bump version of criterion-plot to align dependencies.</li>
</ul>
<h2>[0.6.0] - 2025-05-17</h2>
<h3>Changed</h3>
<ul>
<li>MSRV bumped to 1.80</li>
<li>The <code>real_blackbox</code> feature no longer has any impact.
Criterion always uses <code>std::hint::black_box()</code> now.
Users of <code>criterion::black_box()</code> should switch to
<code>std::hint::black_box()</code>.</li>
<li><code>clap</code> dependency unpinned.</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>gnuplot version is now correctly detected when using certain Windows
binaries/configurations that used to fail</li>
</ul>
<h3>Added</h3>
<ul>
<li>Async benchmarking with Tokio may be done via a
<code>tokio::runtime::Handle</code>, not only a
<code>tokio::runtime::Runtime</code></li>
</ul>
<h2>[0.5.1] - 2023-05-26</h2>
<h3>Fixed</h3>
<ul>
<li>Quick mode (--quick) no longer crashes with measured times over 5
seconds when --noplot is not active</li>
</ul>
<h2>[0.5.0] - 2023-05-23</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/criterion-rs/criterion.rs/commit/b49ade728c064f49cb2a70b0368658a15cf21833"><code>b49ade7</code></a>
chore: release v0.8.0</li>
<li>See full diff in <a
href="https://github.com/criterion-rs/criterion.rs/compare/criterion-plot-v0.7.0...criterion-v0.8.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-01 07:01:32 +00:00
dependabot[bot] 6c29824a15 Update criterion requirement from 0.6.0 to 0.7.0 (#21726)
Updates the requirements on
[criterion](https://github.com/bheisler/criterion.rs) to permit the
latest version.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/bheisler/criterion.rs/blob/master/CHANGELOG.md">criterion's
changelog</a>.</em></p>
<blockquote>
<h2>[0.7.0] - 2025-07-25</h2>
<ul>
<li>Bump version of criterion-plot to align dependencies.</li>
</ul>
<h2>[0.6.0] - 2025-05-17</h2>
<h3>Changed</h3>
<ul>
<li>MSRV bumped to 1.80</li>
<li>The <code>real_blackbox</code> feature no longer has any impact.
Criterion always uses <code>std::hint::black_box()</code> now.
Users of <code>criterion::black_box()</code> should switch to
<code>std::hint::black_box()</code>.</li>
<li><code>clap</code> dependency unpinned.</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>gnuplot version is now correctly detected when using certain Windows
binaries/configurations that used to fail</li>
</ul>
<h3>Added</h3>
<ul>
<li>Async benchmarking with Tokio may be done via a
<code>tokio::runtime::Handle</code>, not only a
<code>tokio::runtime::Runtime</code></li>
</ul>
<h2>[0.5.1] - 2023-05-26</h2>
<h3>Fixed</h3>
<ul>
<li>Quick mode (--quick) no longer crashes with measured times over 5
seconds when --noplot is not active</li>
</ul>
<h2>[0.5.0] - 2023-05-23</h2>
<h3>Changed</h3>
<ul>
<li>Replaced lazy_static dependency with once_cell</li>
<li>Improved documentation of the <code>html_reports</code> feature</li>
<li>Replaced atty dependency with is-terminal</li>
<li>MSRV bumped to 1.64</li>
<li>Upgraded clap dependency to v4</li>
<li>Upgraded tempfile dependency to v3.5.0</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Quick mode (<code>--quick</code>) no longer outputs 1ms for measured
times over 5 seconds</li>
<li>Documentation updates</li>
</ul>
<h2>[0.4.0] - 2022-09-10</h2>
<h3>Removed</h3>
<ul>
<li>The <code>Criterion::can_plot</code> function has been removed.</li>
<li>The <code>Criterion::bench_function_over_inputs</code> function has
been removed.</li>
<li>The <code>Criterion::bench_functions</code> function has been
removed.</li>
<li>The <code>Criterion::bench</code> function has been removed.</li>
</ul>
<h3>Changed</h3>
<ul>
<li>HTML report hidden behind non-default feature flag:
'html_reports'</li>
<li>Standalone support (ie without cargo-criterion) feature flag:
'cargo_bench_support'</li>
<li>MSRV bumped to 1.57</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/bheisler/criterion.rs/commit/567405d25363804dd1e6d440a0c9d6612c4cecd8"><code>567405d</code></a>
release: bump criterion and criterion-plot versions (<a
href="https://redirect.github.com/bheisler/criterion.rs/issues/878">#878</a>)</li>
<li><a
href="https://github.com/bheisler/criterion.rs/commit/ccccbcc15237233af22af4c76751a7aa184609b3"><code>ccccbcc</code></a>
fix: deal with throughput in bits (<a
href="https://redirect.github.com/bheisler/criterion.rs/issues/861">#861</a>)</li>
<li><a
href="https://github.com/bheisler/criterion.rs/commit/deb0eb021dbaa58678222725a455662f780751d0"><code>deb0eb0</code></a>
feat: support throughput reports in bits (<a
href="https://redirect.github.com/bheisler/criterion.rs/issues/833">#833</a>)</li>
<li><a
href="https://github.com/bheisler/criterion.rs/commit/d4fd7cc478dfb15e82ea9726c8e4c5a3afc4bc49"><code>d4fd7cc</code></a>
Add CI job checking library builds with oldest allowed dependencies (<a
href="https://redirect.github.com/bheisler/criterion.rs/issues/854">#854</a>)</li>
<li>See full diff in <a
href="https://github.com/bheisler/criterion.rs/compare/0.6.0...0.7.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-04 07:54:02 +00:00
Eagster 279a8678d4 Improved Entity Lifecycle: remove flushing, support manual spawning and despawning (#19451)
# Objective

This is the next step for #19430 and is also convinient for #18670.

For context, the way entities work on main is as a "allocate and use"
system. Entity ids are allocated, and given a location. The location can
then be changed, etc. Entities that are free have an invalid location.
To allocate an entity, one must also set its location. This introduced
the need for pending entities, where an entity would be reserved,
pending, and at some point flushed. Pending and free entities have an
invalid location, and others are assumed to have a valid one.

This paradigm has a number of downsides: First, the entities metadata
table is inseparable from the allocator, which makes remote reservation
challenging. Second, the `World` must be flushed, even to do simple
things, like allocate a temporary entity id. Third, users have little
control over entity ids, only interacting with conceptual entities. This
made things like `Entities::alloc_at` clunky and slow, leading to its
removal, despite some users still having valid need of it.

So the goal of this PR is to:
- Decouple `Entities` from entity allocation to make room for other
allocators and resolve `alloc_at` issues.
- Decouple entity allocation from spawning to make reservation a moot
point.
- Introduce constructing and destructing entities, in addition to
spawn/despawn.
- Change `reserve` and `flush` patterns to `alloc` and `construct`
patterns.

It is possible to break this up into multiple prs, as I originally
intended, but doing so would require lots of temporary scaffolding that
would both hurt performance and make things harder to review.

## Solution

This solution builds on #19433, which changed the representation of
invalid entity locations from a constant to `None`.

There's quite a few steps to this, each somewhat controversial:

### Entities with no location

This pr introduces the idea of entity rows both with and without
locations. This corresponds to entities that are constructed (the row
has a location) and not constructed (the row has no location). When a
row is free or pending, it is not constructed. When a row is outside the
range of the meta list, it still exists; it's just not constructed.

This extends to conceptual entities; conceptual entities may now be in
one of 3 states: empty (constructed; no components), normal
(constructed; 1 or more components), or null (not constructed). This
extends to entity pointers (`EntityWorldMut`, etc): These now can point
to "null"/not constructed entities. Depending on the privilege of the
pointer, these can also construct or destruct the entity.

This also changes how `Entity` ids relate to conceptual entities. An
`Entity` now exists if its generation matches that of its row. An
`Entity` that has the right generation for its row will claim to exist,
even if it is not constructed. This means, for example, an `Entity`
manually constructed with a large index and generation of 0 *will* exist
if it has not been allocated yet.

### `Entities` is separate from the allocator

This pr separates entity allocation from `Entities`. `Entities` is now
only focused on tracking entity metadata, etc. The new
`EntitiesAllocator` on `World` manages all allocations. This forces
`Entities` to not rely on allocator state to determine if entities
exist, etc, which is convinient for remote reservation and needed for
custom allocators. It also paves the way for allocators not housed
within the `World`, makes some unsafe code easier since the allocator
and metadata live under different pointers, etc.

This separation requires thinking about interactions with `Entities` in
a new way. Previously, the `Entities` set the rules for what entities
are valid and what entities are not. Now, it has no way of knowing.
Instead, interaction with `Entities` are more like declaring some
information for it to track than changing some information it was
already tracking. To reflect this, `set` has been split up into
`declare` and `update`.

### Constructing and destructing

As mentioned, entities that have no location (not constructed) can be
constructed at any time. This takes on exactly the same meaning as the
previous `spawn_non_existent`. It creates/declares a location instead of
updating an old one. As an example, this makes spawning an entity now
literately just allocate a new id and construct it immediately.

Conversely, entities that are constructed may be destructed. This
removes all components and despawns related entities, just like
`despawn`. The only difference is that destructing does not free the
entity id for reuse. Between constructing and destructing, all needs for
`alloc_at` are resolved. If you want to keep the id for custom reuse,
just destruct instead of despawn! Despawn, now just destructs the entity
and frees it.

Destructing a not constructed entity will do nothing. Constructing an
already constructed entity will panic. This is to guard against users
constructing a manually formed `Entity` that the allocator could later
hand out. However, public construction methods have proper error
handling for this. Despawning a not constructed entity just frees its
id.

### No more flushing

All places that once needed to reserve and flush entity ids now allocate
and construct them instead. This improves performance and simplifies
things.

### Flow chart

![entity row
lifecycle](https://github.com/user-attachments/assets/3e5397ab-4ec6-4477-91de-3d002d0cf92e)

(Thanks @ItsDoot)

## Testing

- CI
- Some new tests
- A few deleted (no longer applicable) tests
- If you see something you think should have a test case, I'll gladly
add it.

## Showcase

Here's an example of constructing and destructing

```rust
let e4 = world.spawn_null();
world
    .entity_mut(e4)
    .construct((TableStored("junk"), A(0)))
    .unwrap()
    .destruct()
    .construct((TableStored("def"), A(456)))
    .unwrap();
```

## Future Work

- [x] More expansive docs. This should definitely should be done, but
I'd rather do that in a future pr to separate writing review from code
review. If you have more ideas for how to introduce users to these
concepts, I'd like to see them. As it is, we don't do a very good job of
explaining entities to users. Ex: `Entity` doesn't always correspond to
a conceptual entity.
- [ ] Try to remove panics from `EntityWorldMut`. There is (and was) a
lot of assuming the entity is constructed there (was assuming it was not
despawned).
- [ ] A lot of names are still centered around spawn/despawn, which is
more user-friendly than construct/destruct but less precise. Might be
worth changing these over.
- [ ] Making a centralized bundle despawner would make sense now.
- [ ] Of course, build on this for remote reservation and, potentially,
for paged entities.

## Performance

<details>

<summary>Benchmarks</summary>

```txt
critcmp main pr19451 -t 1
group                                                                                                     main                                     pr19451
-----                                                                                                     ----                                     -------
add_remove/sparse_set                                                                                     1.13    594.7±6.80µs        ? ?/sec      1.00    527.4±8.01µs        ? ?/sec
add_remove/table                                                                                          1.08   799.6±15.53µs        ? ?/sec      1.00   739.7±15.10µs        ? ?/sec
add_remove_big/sparse_set                                                                                 1.10    614.6±6.50µs        ? ?/sec      1.00   557.0±19.04µs        ? ?/sec
add_remove_big/table                                                                                      1.03      2.8±0.01ms        ? ?/sec      1.00      2.7±0.02ms        ? ?/sec
added_archetypes/archetype_count/100                                                                      1.01     30.9±0.50µs        ? ?/sec      1.00     30.5±0.44µs        ? ?/sec
added_archetypes/archetype_count/1000                                                                     1.00   638.0±19.77µs        ? ?/sec      1.03   657.0±73.61µs        ? ?/sec
added_archetypes/archetype_count/10000                                                                    1.02      5.5±0.14ms        ? ?/sec      1.00      5.4±0.09ms        ? ?/sec
all_added_detection/50000_entities_ecs::change_detection::Sparse                                          1.02     47.9±1.22µs        ? ?/sec      1.00     46.8±0.40µs        ? ?/sec
all_added_detection/50000_entities_ecs::change_detection::Table                                           1.02     45.4±1.89µs        ? ?/sec      1.00     44.6±0.78µs        ? ?/sec
build_schedule/1000_schedule                                                                              1.02   942.6±11.53ms        ? ?/sec      1.00   925.2±10.35ms        ? ?/sec
build_schedule/100_schedule                                                                               1.01      5.8±0.12ms        ? ?/sec      1.00      5.7±0.12ms        ? ?/sec
build_schedule/100_schedule_no_constraints                                                                1.03   803.1±28.93µs        ? ?/sec      1.00   781.1±50.11µs        ? ?/sec
build_schedule/500_schedule_no_constraints                                                                1.00      5.6±0.31ms        ? ?/sec      1.08      6.0±0.27ms        ? ?/sec
busy_systems/01x_entities_03_systems                                                                      1.00     24.4±1.35µs        ? ?/sec      1.01     24.7±1.35µs        ? ?/sec
busy_systems/03x_entities_03_systems                                                                      1.00     38.1±1.70µs        ? ?/sec      1.04     39.7±1.49µs        ? ?/sec
busy_systems/03x_entities_09_systems                                                                      1.01    111.4±2.27µs        ? ?/sec      1.00    109.9±2.46µs        ? ?/sec
busy_systems/03x_entities_15_systems                                                                      1.00    174.8±2.56µs        ? ?/sec      1.01    176.6±4.22µs        ? ?/sec
contrived/03x_entities_09_systems                                                                         1.00     59.0±2.92µs        ? ?/sec      1.01     59.8±3.03µs        ? ?/sec
contrived/03x_entities_15_systems                                                                         1.00     97.5±4.87µs        ? ?/sec      1.01     98.8±4.69µs        ? ?/sec
contrived/05x_entities_09_systems                                                                         1.00     75.3±3.76µs        ? ?/sec      1.01     76.4±4.11µs        ? ?/sec
despawn_world/10000_entities                                                                              1.32    344.8±4.47µs        ? ?/sec      1.00    261.4±4.91µs        ? ?/sec
despawn_world/100_entities                                                                                1.22      4.3±0.04µs        ? ?/sec      1.00      3.5±0.54µs        ? ?/sec
despawn_world/1_entities                                                                                  1.01    169.6±7.88ns        ? ?/sec      1.00   167.8±11.45ns        ? ?/sec
despawn_world_recursive/10000_entities                                                                    1.20  1723.0±53.82µs        ? ?/sec      1.00  1437.0±26.11µs        ? ?/sec
despawn_world_recursive/100_entities                                                                      1.16     17.9±0.10µs        ? ?/sec      1.00     15.5±0.16µs        ? ?/sec
despawn_world_recursive/1_entities                                                                        1.01   372.8±15.68ns        ? ?/sec      1.00   367.7±16.90ns        ? ?/sec
ecs::entity_cloning::hierarchy_many/clone                                                                 1.03   227.9±24.67µs 1559.9 KElem/sec    1.00   221.1±29.74µs 1607.8 KElem/sec
ecs::entity_cloning::hierarchy_many/reflect                                                               1.00   406.2±23.46µs 875.2 KElem/sec     1.02   413.9±22.45µs 858.9 KElem/sec
ecs::entity_cloning::hierarchy_tall/clone                                                                 1.01     12.2±0.34µs  4.0 MElem/sec      1.00     12.0±1.41µs  4.1 MElem/sec
ecs::entity_cloning::hierarchy_tall/reflect                                                               1.02     15.3±0.39µs  3.2 MElem/sec      1.00     15.0±2.14µs  3.2 MElem/sec
ecs::entity_cloning::single/clone                                                                         1.02  659.0±100.01ns 1481.8 KElem/sec    1.00  643.3±101.49ns 1517.9 KElem/sec
ecs::entity_cloning::single/reflect                                                                       1.03  1135.2±72.17ns 860.2 KElem/sec     1.00  1098.3±65.99ns 889.1 KElem/sec
empty_archetypes/for_each/10                                                                              1.02      8.1±0.57µs        ? ?/sec      1.00      8.0±0.37µs        ? ?/sec
empty_archetypes/for_each/100                                                                             1.01      8.1±0.34µs        ? ?/sec      1.00      8.1±0.28µs        ? ?/sec
empty_archetypes/for_each/1000                                                                            1.03      8.4±0.25µs        ? ?/sec      1.00      8.2±0.29µs        ? ?/sec
empty_archetypes/iter/100                                                                                 1.01      8.1±0.29µs        ? ?/sec      1.00      8.0±0.34µs        ? ?/sec
empty_archetypes/iter/1000                                                                                1.02      8.5±0.31µs        ? ?/sec      1.00      8.4±0.62µs        ? ?/sec
empty_archetypes/iter/10000                                                                               1.01     10.6±1.22µs        ? ?/sec      1.00     10.5±0.49µs        ? ?/sec
empty_archetypes/par_for_each/10                                                                          1.01      8.8±0.49µs        ? ?/sec      1.00      8.7±0.31µs        ? ?/sec
empty_archetypes/par_for_each/100                                                                         1.00      8.7±0.48µs        ? ?/sec      1.04      9.0±0.34µs        ? ?/sec
empty_archetypes/par_for_each/10000                                                                       1.01     21.2±0.41µs        ? ?/sec      1.00     20.9±0.44µs        ? ?/sec
empty_commands/0_entities                                                                                 1.72      3.7±0.01ns        ? ?/sec      1.00      2.1±0.02ns        ? ?/sec
empty_systems/100_systems                                                                                 1.00     82.9±3.29µs        ? ?/sec      1.07     88.3±3.77µs        ? ?/sec
empty_systems/2_systems                                                                                   1.01      8.2±0.71µs        ? ?/sec      1.00      8.2±0.38µs        ? ?/sec
empty_systems/4_systems                                                                                   1.00      8.2±0.72µs        ? ?/sec      1.03      8.4±0.71µs        ? ?/sec
entity_hash/entity_set_build/10000                                                                        1.10     45.9±1.60µs 207.7 MElem/sec     1.00     41.6±0.39µs 229.0 MElem/sec
entity_hash/entity_set_build/3162                                                                         1.06     12.7±0.77µs 236.7 MElem/sec     1.00     12.0±0.75µs 250.6 MElem/sec
entity_hash/entity_set_lookup_hit/10000                                                                   1.02     14.5±0.30µs 658.3 MElem/sec     1.00     14.2±0.07µs 672.6 MElem/sec
entity_hash/entity_set_lookup_hit/3162                                                                    1.01      4.4±0.03µs 682.7 MElem/sec     1.00      4.4±0.01µs 691.3 MElem/sec
entity_hash/entity_set_lookup_miss_gen/10000                                                              1.01     61.3±4.12µs 155.6 MElem/sec     1.00     60.6±1.47µs 157.3 MElem/sec
entity_hash/entity_set_lookup_miss_gen/3162                                                               1.00      9.5±0.02µs 316.3 MElem/sec     1.01      9.7±0.88µs 311.7 MElem/sec
entity_hash/entity_set_lookup_miss_id/100                                                                 1.00    145.5±1.49ns 655.4 MElem/sec     1.03    149.8±1.59ns 636.7 MElem/sec
entity_hash/entity_set_lookup_miss_id/10000                                                               1.85     63.9±3.57µs 149.3 MElem/sec     1.00     34.6±3.81µs 275.8 MElem/sec
entity_hash/entity_set_lookup_miss_id/316                                                                 1.00    562.0±9.58ns 536.2 MElem/sec     1.02    573.9±1.27ns 525.1 MElem/sec
entity_hash/entity_set_lookup_miss_id/3162                                                                1.03      9.1±0.10µs 330.7 MElem/sec     1.00      8.9±0.24µs 339.0 MElem/sec
event_propagation/four_event_types                                                                        1.12    541.5±3.84µs        ? ?/sec      1.00    482.7±4.64µs        ? ?/sec
event_propagation/single_event_type                                                                       1.07   769.5±10.21µs        ? ?/sec      1.00   715.9±15.16µs        ? ?/sec
event_propagation/single_event_type_no_listeners                                                          1.56    393.4±2.89µs        ? ?/sec      1.00    251.4±3.68µs        ? ?/sec
events_iter/size_16_events_100                                                                            1.01     64.0±0.18ns        ? ?/sec      1.00     63.4±0.23ns        ? ?/sec
events_iter/size_4_events_100                                                                             1.02     64.8±0.90ns        ? ?/sec      1.00     63.4±0.24ns        ? ?/sec
events_iter/size_4_events_1000                                                                            1.01    586.5±8.00ns        ? ?/sec      1.00    579.1±4.93ns        ? ?/sec
events_send/size_16_events_100                                                                            1.00   142.7±24.34ns        ? ?/sec      1.03   147.1±28.36ns        ? ?/sec
events_send/size_16_events_10000                                                                          1.01     12.2±0.13µs        ? ?/sec      1.00     12.1±0.12µs        ? ?/sec
fake_commands/10000_commands                                                                              1.43     63.3±8.21µs        ? ?/sec      1.00     44.1±0.16µs        ? ?/sec
fake_commands/1000_commands                                                                               1.40      6.2±0.01µs        ? ?/sec      1.00      4.4±0.02µs        ? ?/sec
fake_commands/100_commands                                                                                1.38    629.4±1.69ns        ? ?/sec      1.00    457.1±0.84ns        ? ?/sec
few_changed_detection/50000_entities_ecs::change_detection::Table                                         1.00     57.7±0.86µs        ? ?/sec      1.07     61.6±1.19µs        ? ?/sec
few_changed_detection/5000_entities_ecs::change_detection::Sparse                                         1.05      5.4±0.53µs        ? ?/sec      1.00      5.1±0.56µs        ? ?/sec
few_changed_detection/5000_entities_ecs::change_detection::Table                                          1.00      4.3±0.30µs        ? ?/sec      1.18      5.1±0.35µs        ? ?/sec
insert_commands/insert                                                                                    1.11   402.5±10.75µs        ? ?/sec      1.00    363.6±8.07µs        ? ?/sec
insert_commands/insert_batch                                                                              1.00    174.9±3.03µs        ? ?/sec      1.02    177.9±5.74µs        ? ?/sec
insert_simple/base                                                                                        1.04   564.1±23.01µs        ? ?/sec      1.00   544.3±60.70µs        ? ?/sec
insert_simple/unbatched                                                                                   1.32  929.3±180.10µs        ? ?/sec      1.00  704.1±132.88µs        ? ?/sec
iter_fragmented/base                                                                                      1.02    280.0±2.86ns        ? ?/sec      1.00    274.0±4.85ns        ? ?/sec
iter_fragmented/foreach                                                                                   1.00     97.3±0.42ns        ? ?/sec      1.03    100.6±3.44ns        ? ?/sec
iter_fragmented/foreach_wide                                                                              1.04      2.7±0.04µs        ? ?/sec      1.00      2.6±0.03µs        ? ?/sec
iter_fragmented_sparse/base                                                                               1.00      5.6±0.05ns        ? ?/sec      1.04      5.8±0.06ns        ? ?/sec
multiple_archetypes_none_changed_detection/100_archetypes_10000_entities_ecs::change_detection::Sparse    1.00   737.7±27.38µs        ? ?/sec      1.01   747.5±30.01µs        ? ?/sec
multiple_archetypes_none_changed_detection/100_archetypes_10000_entities_ecs::change_detection::Table     1.02   678.3±25.13µs        ? ?/sec      1.00   662.1±19.63µs        ? ?/sec
multiple_archetypes_none_changed_detection/100_archetypes_1000_entities_ecs::change_detection::Sparse     1.09     76.0±9.35µs        ? ?/sec      1.00     70.0±3.29µs        ? ?/sec
multiple_archetypes_none_changed_detection/100_archetypes_1000_entities_ecs::change_detection::Table      1.03     64.7±3.40µs        ? ?/sec      1.00     62.8±1.80µs        ? ?/sec
multiple_archetypes_none_changed_detection/100_archetypes_100_entities_ecs::change_detection::Table       1.02      7.6±0.12µs        ? ?/sec      1.00      7.5±0.16µs        ? ?/sec
multiple_archetypes_none_changed_detection/100_archetypes_10_entities_ecs::change_detection::Sparse       1.00  1003.5±12.38ns        ? ?/sec      1.01  1013.7±32.64ns        ? ?/sec
multiple_archetypes_none_changed_detection/20_archetypes_10_entities_ecs::change_detection::Sparse        1.03   187.1±21.18ns        ? ?/sec      1.00   181.9±22.86ns        ? ?/sec
multiple_archetypes_none_changed_detection/5_archetypes_10_entities_ecs::change_detection::Sparse         1.00     52.8±8.19ns        ? ?/sec      1.03     54.3±8.06ns        ? ?/sec
multiple_archetypes_none_changed_detection/5_archetypes_10_entities_ecs::change_detection::Table          1.00     46.8±2.23ns        ? ?/sec      1.03     48.0±2.48ns        ? ?/sec
no_archetypes/system_count/0                                                                              1.00     16.3±0.17ns        ? ?/sec      1.02     16.6±0.16ns        ? ?/sec
no_archetypes/system_count/100                                                                            1.02    851.5±9.32ns        ? ?/sec      1.00    832.9±7.93ns        ? ?/sec
none_changed_detection/5000_entities_ecs::change_detection::Sparse                                        1.00      3.4±0.04µs        ? ?/sec      1.02      3.5±0.05µs        ? ?/sec
nonempty_spawn_commands/10000_entities                                                                    1.89    261.1±6.99µs        ? ?/sec      1.00    137.8±8.47µs        ? ?/sec
nonempty_spawn_commands/1000_entities                                                                     1.90     26.4±3.18µs        ? ?/sec      1.00     13.9±2.38µs        ? ?/sec
nonempty_spawn_commands/100_entities                                                                      1.87      2.6±0.07µs        ? ?/sec      1.00  1388.8±97.31ns        ? ?/sec
observe/trigger_simple                                                                                    1.09    347.5±1.51µs        ? ?/sec      1.00    317.7±2.62µs        ? ?/sec
observe/trigger_targets_simple/10000_entity                                                               1.04   696.5±15.50µs        ? ?/sec      1.00   672.0±13.88µs        ? ?/sec
par_iter_simple/with_0_fragment                                                                           1.01     34.4±0.51µs        ? ?/sec      1.00     33.9±0.53µs        ? ?/sec
par_iter_simple/with_1000_fragment                                                                        1.04     45.5±0.93µs        ? ?/sec      1.00     43.9±1.85µs        ? ?/sec
par_iter_simple/with_100_fragment                                                                         1.03     36.2±0.50µs        ? ?/sec      1.00     35.1±0.44µs        ? ?/sec
par_iter_simple/with_10_fragment                                                                          1.03     37.5±0.97µs        ? ?/sec      1.00     36.5±0.74µs        ? ?/sec
param/combinator_system/8_dyn_params_system                                                               1.00     10.4±0.73µs        ? ?/sec      1.01     10.5±0.79µs        ? ?/sec
param/combinator_system/8_piped_systems                                                                   1.05      8.0±0.65µs        ? ?/sec      1.00      7.6±0.57µs        ? ?/sec
query_get/50000_entities_sparse                                                                           1.06    136.7±0.35µs        ? ?/sec      1.00    128.6±0.44µs        ? ?/sec
query_get_many_10/50000_calls_sparse                                                                      1.02  1649.4±77.80µs        ? ?/sec      1.00  1614.4±78.91µs        ? ?/sec
query_get_many_2/50000_calls_sparse                                                                       1.00    191.3±3.66µs        ? ?/sec      1.01    193.3±0.75µs        ? ?/sec
query_get_many_2/50000_calls_table                                                                        1.00    243.9±0.55µs        ? ?/sec      1.05    257.2±8.62µs        ? ?/sec
query_get_many_5/50000_calls_sparse                                                                       1.00    585.9±7.70µs        ? ?/sec      1.03    600.6±5.99µs        ? ?/sec
query_get_many_5/50000_calls_table                                                                        1.00    673.7±7.44µs        ? ?/sec      1.07   722.3±10.77µs        ? ?/sec
run_condition/no/1000_systems                                                                             1.00     23.7±0.06µs        ? ?/sec      1.06     25.1±0.07µs        ? ?/sec
run_condition/no/100_systems                                                                              1.00   1460.5±4.28ns        ? ?/sec      1.03   1510.1±3.69ns        ? ?/sec
run_condition/no/10_systems                                                                               1.00    201.5±0.53ns        ? ?/sec      1.04    209.1±2.37ns        ? ?/sec
run_condition/yes/1000_systems                                                                            1.00  1225.7±22.58µs        ? ?/sec      1.02  1253.7±24.90µs        ? ?/sec
run_condition/yes/100_systems                                                                             1.02     89.4±3.43µs        ? ?/sec      1.00     88.0±3.96µs        ? ?/sec
run_condition/yes_using_query/1000_systems                                                                1.00  1288.3±26.57µs        ? ?/sec      1.03  1323.0±24.73µs        ? ?/sec
run_condition/yes_using_query/100_systems                                                                 1.00    108.8±2.51µs        ? ?/sec      1.03    112.3±3.09µs        ? ?/sec
run_condition/yes_using_resource/100_systems                                                              1.03     99.0±3.37µs        ? ?/sec      1.00     96.2±4.80µs        ? ?/sec
run_empty_schedule/MultiThreaded                                                                          1.03     15.3±0.10ns        ? ?/sec      1.00     14.9±0.03ns        ? ?/sec
run_empty_schedule/Simple                                                                                 1.01     15.2±0.15ns        ? ?/sec      1.00     15.0±0.25ns        ? ?/sec
sized_commands_0_bytes/10000_commands                                                                     1.57     52.6±0.41µs        ? ?/sec      1.00     33.5±0.10µs        ? ?/sec
sized_commands_0_bytes/1000_commands                                                                      1.57      5.3±0.01µs        ? ?/sec      1.00      3.4±0.00µs        ? ?/sec
sized_commands_0_bytes/100_commands                                                                       1.56    536.5±4.83ns        ? ?/sec      1.00    343.6±1.12ns        ? ?/sec
sized_commands_12_bytes/10000_commands                                                                    1.22     63.0±0.53µs        ? ?/sec      1.00     51.5±6.06µs        ? ?/sec
sized_commands_12_bytes/1000_commands                                                                     1.25      5.7±0.01µs        ? ?/sec      1.00      4.6±0.05µs        ? ?/sec
sized_commands_12_bytes/100_commands                                                                      1.27    579.3±1.28ns        ? ?/sec      1.00    455.4±0.85ns        ? ?/sec
sized_commands_512_bytes/10000_commands                                                                   1.11   248.4±85.81µs        ? ?/sec      1.00   224.3±52.11µs        ? ?/sec
sized_commands_512_bytes/1000_commands                                                                    1.09     22.8±0.18µs        ? ?/sec      1.00     21.0±0.17µs        ? ?/sec
sized_commands_512_bytes/100_commands                                                                     1.13  1852.2±11.21ns        ? ?/sec      1.00   1635.3±4.91ns        ? ?/sec
spawn_commands/10000_entities                                                                             1.04   844.2±11.96µs        ? ?/sec      1.00   811.5±13.25µs        ? ?/sec
spawn_commands/1000_entities                                                                              1.05     84.9±3.66µs        ? ?/sec      1.00     80.5±4.13µs        ? ?/sec
spawn_commands/100_entities                                                                               1.06      8.6±0.12µs        ? ?/sec      1.00      8.1±0.12µs        ? ?/sec
spawn_world/10000_entities                                                                                1.03   413.2±25.20µs        ? ?/sec      1.00   400.9±49.97µs        ? ?/sec
spawn_world/100_entities                                                                                  1.02      4.1±0.62µs        ? ?/sec      1.00      4.1±0.69µs        ? ?/sec
spawn_world/1_entities                                                                                    1.04     42.2±3.23ns        ? ?/sec      1.00     40.6±6.81ns        ? ?/sec
world_entity/50000_entities                                                                               1.18     88.3±0.42µs        ? ?/sec      1.00     74.7±0.16µs        ? ?/sec
world_get/50000_entities_sparse                                                                           1.02    182.2±0.32µs        ? ?/sec      1.00    179.5±0.84µs        ? ?/sec
world_get/50000_entities_table                                                                            1.01    198.3±0.46µs        ? ?/sec      1.00    196.2±0.63µs        ? ?/sec
world_query_for_each/50000_entities_sparse                                                                1.00     32.7±0.12µs        ? ?/sec      1.01     33.1±0.46µs        ? ?/sec
```
</details>

This roughly doubles command spawning speed! Despawning also sees a
20-30% improvement. Dummy commands improve by 10-50% (due to not needing
an entity flush). Other benchmarks seem to be noise and are negligible.
It looks to me like a massive performance win!

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Christian Hughes <9044780+ItsDoot@users.noreply.github.com>
Co-authored-by: urben1680 <55257931+urben1680@users.noreply.github.com>
Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
Co-authored-by: Trashtalk217 <24552941+Trashtalk217@users.noreply.github.com>
Co-authored-by: James Liu <contact@jamessliu.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2025-11-03 23:06:02 +00:00
Trashtalk217 17ba0fd733 Remove #[derive(Resource, Component)] from tests (#21589)
# Objective

Multiple tests derive both `Resource` and `Component` on a single
struct. In the current resources-for-components plan (#19731), this
leads to a conflict.

## Solution

```rust
#[derive(Resource, Component)]
struct A;
```

Becomes

```rust
#[derive(Component)]
struct A;

#[derive(Resource)]
struct ResA;
```

and the tests are changed accordingly.

There was one test that had to be removed as it specifically tested that
a query could both query a resource and a component with the same name.
That test doesn't make any sense anymore, so I removed it.

## Testing

I tested the changes by adding code into `Resource` derive macro, that
also derives `Component`, so any conflicts showed up by running `cargo
build`.

## Future work

`AmbientLight` in `bevy_light` still derives both, but since that
requires a little more work, I'm saving it for later.
2025-10-19 19:42:12 +00:00
Rob Parrett af1ff013e1 Fix a few "repeated word" typos (#21547)
# Objective

Fix some typos

## Solution

Have a lovely stroll through the codebase with my friend
`\b(\w+)\s+\1\b` and

```diff
- word word
+ word
```
2025-10-14 23:01:54 +00:00
atlv 44b904ed05 Rename bevy_mesh_picking_backend to mesh_picking (#21436)
# Objective

- Only prefix features bevy_ if they correspond to a crate
- Another step towards #20867

## Solution

- rename it

## Testing

- ci
2025-10-07 23:49:49 +00:00
Greeble e713c7b606 Change bevy_math to use inline instead of inline(always) (#20887)
## Objective

Move `bevy_math` closer to recommended inlining practices, and avoid
problems with debuggers and optimising for size.

## Background

Some `bevy_math` modules apply `#[inline(always)]` to almost every
function. This has downsides for some users - it can prevent optimising
for size, and can stop the debugger from stepping into functions.

I can't find any source that advises `inline(always)` by default - the
most common advice is "use rarely and only after profiling" (example:
[std lib
guide](https://std-dev-guide.rust-lang.org/policy/inline.html)). I've
poked around the `bevy_math` history but couldn't find anything that
explains why `inline(always)` was chosen.

## Solution

This PR changes all instances of `#[inline(always)]` to `#[inline]`.

The change is very unlikely to make any difference in optimised builds -
almost all the functions are tiny so they're going to be inlined either
way. Benchmarks showed no difference.

The change can sometimes decrease performance in `opt-level = 0` builds
- one math heavy microbenchmark took a -10% hit. But this is arguably
the right trade-off if it lets the user step into functions in the
debugger.

Overall, I think this is the safer default for most users.
`inline(always)` has several concrete downsides, while `inline` has some
trade-offs but no clear downsides.

The change also adds a new `bevy_math` benchmark which includes some of
the affected functions.

## Alternatives

The change could have been taken further.

- Remove `#[inline]` from heftier functions like
`BoundingSphere::from_point_cloud`.
- Could help optimising for size. I left this out to keep things simple.
- Remove `#[inline]` entirely.
- I think this is likely to be a good thing, but it needs more testing
and would probably be controversial.

## Testing

```sh
cargo bench -p benches --bench math
```

Also:

- Checked benchmark disassembly to confirm what was inlined.
- Compiled `alien_cake_addict` with various optimisation levels to check
there weren't major differences in size.

EDIT: More details in [comment
1](https://github.com/bevyengine/bevy/pull/20887#issuecomment-3261735671),
[comment
2](https://github.com/bevyengine/bevy/pull/20887#issuecomment-3263596184).
2025-09-29 22:55:36 +00:00
Fangdun Tsai a0e9aabcb5 chore: update encase to 0.12 (#21078)
Objective
----

Change log for the upgrade:
https://github.com/teoxoy/encase/blob/main/CHANGELOG.md#v0120-2025-09-12
2025-09-23 07:37:30 +00:00
Eagster 12f802b1f0 Revived #18741, Remove SimpleExecutor. (#21176)
# Objective

Revive #18741 :

Reduce complexity and code duplication of schedule executors. This is an
alternative to fix #18453.

It sounds like `SimpleExecutor` was a temporary solution to "sync
points" in schedules, but now those can be inferred, so `SimpleExecutor`
is unnecessary now.

Further, `SimpleExecutor` and `SingleThreadedExecutor` were *very*
similar, which was becoming a consistency and code quality headache.

## Solution

Remove `SimpleExecutor`.

## Testing

CI
2025-09-22 23:26:36 +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 90ae57d8ac use affine inverse in picking (#20713)
# Objective

- affine inverse not mat4 inverse

## Solution

- do it yet again

## Testing

- debug_picking example
2025-08-22 21:12:57 +00:00
Carter Anderson 5058f8a9e6 Improve On Terminology (#20648)
# Objective

Fixes #19263 (and expands on it)

Within `Observers`, we have started to distance ourselves from the
"trigger" terminology. Specifically, we have renamed `Trigger` to `On`.
I think this was a very good move, but we're currently in an awkward
middle ground state. Users interact with `On` as if it were an event:
`On<E>` exposes the event and derefs directly to it. I think we should
embrace this mindset fully, in the interest of clarity.

## Solution

- Rename all `trigger: On<SomeEvent>` cases to `event: On<SomeEvent>`.
- Rename `On::target` to `On::entity`. This reads _much_ better when
writing `query.get(event.entity())` and pairs more effectively with the
`EntityEvent` terminology.
- Rename `On::original_target` to `On::original_entity`, for the same
reasons.
- Take advantage of the `Deref` behavior where appropriate

```rust
// Before
entity.observe(|trigger: On<Explode>| {
  println!("{} exploded!", trigger.target());
})

// After
entity.observe(|event: On<Explode>| {
  println!("{} exploded!", event.entity());
})
```
2025-08-21 08:54:28 +00:00
atlv 7b98b7b9da Use bevy_shader in pbr, core pipelines, sprite, aa, gizmos, feathers, solari, dev_tools instead of bevy_render::shader re-export (#20493)
# Objective

- Prepare for removing re-exports
- Probably depends on #20491 merging first

## Solution

- title

## Testing

- cargo check --examples --all-features

---------

Co-authored-by: Tim Blackbird <JustTheCoolDude@gmail.com>
2025-08-10 17:08:54 +00:00
atlv 67b4ecdb01 Use bevy_light in pbr instead of bevy_pbr::light re-export + add bevy_light prelude (#20488)
# Objective

- Prepare for removing re-exports

## Solution

- title

## Testing

- cargo check --examples
2025-08-10 06:29:09 +00:00
Gonçalo Rica Pais da Silva ef845e0cea Update rand, glam and encase to latest versions (#18047)
# Objective

New `rand` version, which means updating `glam` and `encase` to support
the newer ecosystem update. Does mean that this changes how WASM builds
need to be done in order to configure `getrandom` correctly, but this
can be remedied with updated docs.

## Solution

Updating all needed dependencies to their compatible versions. ~~This PR
is currently blocked by `encase`, which is waiting on [this
PR](https://github.com/teoxoy/encase/pull/88) to be merged and then a
new version published.~~ ~~This PR is no longer blocked~~,
~~`hexasphere` is blocking this PR now due to not yet having a new
release with the latest `glam` version support~~, The PR is all good to
go now, everything in order across glam/rand deps.

## Testing

- Must pass CI for all checks, tests, not introduce breaking changes.

---

## Migration Guide

With newer versions of `glam` & `encase`, the updated versions don't
seem to have introduced breakages, though as always, best to consult
their docs [1](https://docs.rs/glam/latest/glam/)
[2](https://docs.rs/encase/0.11.0/encase/) for any changes.

`rand` changes are more extensive, with changes such as `thread_rng()`
-> `rng()`, `from_entropy()` -> `from_os_rng()`, and so forth. `RngCore`
is now split into infallible `RngCore` and fallible `TryRngCore`, and
the `distributions` module has been renamed to `distr`. Most of this
affects only internals, and doesn't directly affect Bevy's APIs. For the
full set of changes, see `rand` [migration
notes](https://rust-random.github.io/book/update-0.9.html).

`getrandom` is also updated, and will require additional configuration
when building Bevy for WASM/Web (if also using `rand`). The full details
of how to do this is in the `getrandom` docs
[1](https://github.com/rust-random/getrandom?tab=readme-ov-file#opt-in-backends)
[2](https://github.com/rust-random/getrandom?tab=readme-ov-file#webassembly-support).

---------

Co-authored-by: François Mockers <francois.mockers@vleue.com>
2025-08-09 02:09:10 +00:00
Nicholas Nethercote 0fc17e9bc1 Trim dependencies. (#20426)
# Objective

Remove unneeded dependencies.

## Solution

Found using `cargo-shear`, `cargo-machete`, and `cargo-udeps`. They all
do the same thing (identify unused dependencies), they are all so-so at
it (with lots of false negatives and positives) but the combination of
all three is enough to get a useful outcome.

## Testing

- I double-checked all the removals by grepping for each removed
dependency's name within the affected crate, to make sure there weren't
any uses remaining. I think they're all ok.
- `cargo run -p ci`

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: James Liu <contact@jamessliu.com>
2025-08-06 08:44:47 +00:00
Trashtalk217 4b1b70d501 Deprecate iter_entities and iter_entities_mut (#20260)
# Objective

Both `iter_entities()` and `iter_entities_mut` are awkward functions as
they both return _all_ entities, which is something you (should) rarely
want.

## Solution

Deprecate both functions and substitute them where they are used.

## Testing

Not necessary.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Carter Weinberg <weinbergcarter@gmail.com>
2025-07-23 20:10:07 +00:00
Trashtalk217 6354a950ee Adjust benches to be more robust (#20207)
# Objective

Currently, benchmarks access the world's entities in a very unsafe way,
which doesn't hold up if we add more internal entities.

Part of #19711.

## Solution

Have the setups return a `Vec<Entity>` we can iterate over.

## Testing

Not needed.
2025-07-20 16:08:08 +00:00