Commit Graph

86 Commits

Author SHA1 Message Date
Marc 96e198e1e4 Fix Deserialize derive for BrpResponse (#24305)
# Objective

Bevy remote's `BrpResponse` derives `serde::Deserialize`, but the static
lifetime prevents it from actually being so:

```
let response: BrpResponse = serde_json::from_str(&response)?;
                            ---------------------^^^^^^^^^-
                            |                    |
                            |                    borrowed value does not live long enough
                            argument requires that `response` is borrowed for `'static`
```

No migration guide needed, since the interface for `BrpResponse::new`
used by downstream implementers remains unchanged.

## Solution

Remove the `jsonrpc` field by writing a custom `impl` for `Serialize` &
`Deserialize`, which is the same solution as done previously in #23175.

## Testing

This change has a very low impact. Tests pass.

## Alternatives

1. Replace jsonrpc with `String`
2. Replace jsonrpc with `Cow`

---------

Co-authored-by: Mira <specificprotagonist@posteo.org>
2026-06-17 04:13:47 +00:00
Gino Valente d38a00ff8c bevy_reflect: Allow parameters to be passed to type data (#13723)
# Objective

Addresses
[comments](https://github.com/bevyengine/bevy/pull/7317#issuecomment-2143075852)
regarding #7317 (note that this doesn't replace #7317, there are still
some great improvements there besides this syntactical problem).

There currently exist some "special" type data registrations that can be
registered like other type data (e.g. `#[reflect(Hash)]`) or can use a
"special" syntax to allow specifying custom implementations (e.g.
`#[reflect(Hash(custom_hash_fn))]`). And there may be more to follow
(#13432).

What's interesting is that most of these special cased registrations
don't actually come with any type data type. Instead, they simply modify
methods on `Reflect` (e.g. `Reflect::reflect_hash`).

#7317 sought to distinguish between these "special" registrations by
making them lowercase and use a more conventional attribute style:
`#[reflect(hash = "custom_hash_fn")]`.

However, while this did help distinguish these registrations and make
them a bit prettier, they now require the user to actually know which
traits are "special" and which are not (as pointed out
[here](https://github.com/bevyengine/bevy/pull/7317#issuecomment-2143075852)).

Ideally, users shouldn't have to know which traits are "special" until
they need to. For most users, they should just know that they need to
register their trait in order for certain things to work. And the
special-casing may be easier to follow if we open up the configuration
abilities to _all_ type data.

## Solution

This PR introduces `CreateTypeData` which replaces `FromType`. This was
done for two reasons.

Firstly, `FromType` isn't very descriptive as to what it should be used
for. We are creating type data from a type, but it's not immediately
clear this is even for type data. Renaming to `CreateTypeData` should
hopefully make this much clearer.

Secondly, in order to support type data with parameters like the
`custom_hash_fn` in `reflect(Hash(custom_hash_fn))`, an additional
`Input` type parameter had to be added. This makes the new signature
`CreateTypeData<T, Input = ()>`.

We can now create type data that accepts input!

```rust
trait Combine {
  fn combine(a: f32, b: f32) -> f32;
}

#[derive(Clone)]
struct ReflectCombine {
  multiplier: f32,
  additional: f32,
  combine: fn(f32, f32) -> f32,
}

impl ReflectCombine {
  pub fn combine(&self, a: f32, b: f32) -> f32 {
    let combined = (self.combine)(a, b);
    let multiplied = self.multiplier * combined;
    multiplied + self.additional
  }
}

impl<T: Combine + Reflect> CreateTypeData<T, (f32, f32)> for ReflectCombine {
  fn create_type_data(input: (f32, f32)) -> Self {
    Self {
      multiplier: input.0,
      additional: input.1,
      combine: T::combine,
    }
  }
}
```

And then register them with the special function-like syntax:

```rust
#[derive(Reflect)]
#[reflect(Combine(2.0, 4.0))]
struct Foo;
```

The above code will compile into the following registration:

```rust
registration.insert(<ReflectCombine as CreateTypeData<Self, _>>::create_type_data((2.0, 4.0)))
```

Notice how the macro automatically generates the tuple for us, so we
don't have to add an additional layer of parentheses.

### Multiple Input Types

You might be wondering why we're using a type parameter instead of an
associated type to specify the input type.

An associated type would limit us to a single implementation. This means
that if we want to support the type data with optional parameters (e.g.
support both `Hash` and `Hash(custom_hash_fn)`), then all type data must
take in `Option<Self::Input>`, regardless of whether or not a `None`
case is supported.

This is important because the macro has to be pass in _something_,
whether that be `()` or `None`.

By using a type parameter we open the door to type data with required
input:

```rust
// `ReflectMyTrait` must be registered with input
impl<T> CreateTypeData<T, u32> for ReflectMyTrait {
  fn create_type_data(input: u32) -> Self {
    Self {
      value: input,
    }
  }
}

// And we can support all different input types
impl<T> CreateTypeData<T, i32> for ReflectMyTrait {
  fn create_type_data(input: i32) -> Self {
    Self {
      value: input.abs() as u32,
    }
  }
}
```

However, this may be something we don't necessarily care about since
users could also get away with this using custom input enums. And the
required-input case could be deferred until runtime (i.e. maybe a panic
in the `None` case).

### Adding `ReflectPartialEq` and `ReflectHash`

I had originally considered adding `ReflectPartialEq` and `ReflectHash`
type data to further decrease the differences between the "special"
registrations and the regular ones. However, I chose not to do that to
(1) reduce the complexity of this PR and (2) we may end up removing
these entirely due to #8695.

### What else is this good for?

Another question you might have is what else this is good for beyond
just making things a bit more consistent.

I'm not sure exactly how the community will use it, but I can see it
being used for things like feature gating certain functionality:

```rust
#[derive(Reflect)]
#[cfg_attr(feature = "debug", reflect(MyTrait(true)))]
#[cfg_attr(not(feature = "debug"), reflect(MyTrait(false)))]
struct Foo;
```

Or to emulate specialization via reflection:

```rust
impl<T> DoSomething for T {
  fn do_something(&self) {
    println!("Doing the same old stuff.");
  }
}

#[derive(Reflect)]
#[reflect(ReflectDoSomething(|_| {
  println!("Doing something special!");
}))]
struct Foo;
```

Note that all of the above could always be done with manual
registration. However, due to them requiring input, some cases could
_only_ be done with manual registration.

This PR mainly opens the door to doing more of this interesting stuff
with type data via the macro registration. It not only unifies "special"
and regular registrations, but also manual and automatic registrations.

## Testing

The tests for this feature are split into doctests (for the docs on
`CreateTypeData`) and in the compile-fail tests.

These will both be verified automatically by CI.

---

## Changelog

- Replaced `FromType<T>` with `CreateTypeData<T, Input = ()>`
- Type data may now opt-in to accepting input during creation using the
`#[reflect(MyTrait(...))]` syntax
- Added `TypeRegistry::register_type_data_with` method

## Migration Guide

`FromType<T>` has been replaced by `CreateTypeData<T, Input = ()>`.
Implementors of `FromType<T>` will need to update their implementation:

```rust
// BEFORE
impl<T> FromType<T> for ReflectMyTrait {
  fn from_type() -> Self {
    // ...
  }
}

// AFTER
impl<T> CreateTypeData<T> for ReflectMyTrait {
  fn create_type_data(input: ()) -> Self {
    // ...
  }
}
```

Additionally, any calls made to `FromType::from_type` will need to be
updated as well:

```rust
// BEFORE
<ReflectMyTrait as FromType<Foo>>::from_type()

// AFTER
<ReflectMyTrait as CreateTypeData<Foo>>::create_type_data(())
```
2026-05-21 09:49:51 +00:00
François Mockers ec2b9dba62 can have observers through BRP (#23800)
# Objective

- Observe events through BRP

## Solution

- Add a observe + watch method to observe events
- remote observer systems are limited to only the event as a parameter,
processing it will have to happen on the client side
- depends on #23797

## Testing

- CI with new test

---------

Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
2026-04-19 08:21:18 +00:00
andriyDev dc9fad28c4 Allow BRP schedule.graph to initialize the schedules it is collecting. (#23743)
# Objective

- In #23733, we started using the `ScheduleData` API for the BRP
`schedule.graph` endpoint.
- This had a consequence that only schedules that were initialized
(i.e., previously ran) could be returned.
- In addition, the schedule data was missing edges for automatically
inserted `apply_deferred` systems.

## Solution

- Cache the `ScheduleBuildMetadata` whenever a schedule is built (the
`ScheduleBuilt` event).
- Lookup this metadata when BRP `schedule.graph` runs, and use it to
extract the schedule data.
- This metadata includes the edges for automatically inserted systems,
making the resulting ScheduleData more accurate to the running schedule.
- If the schedule needs to be built (has changed/hasn't run before),
build the schedule which automatically caches its metadata.

## Testing

- Added a test for this.
2026-04-12 21:59:18 +00:00
andriyDev 9129cb1004 Replace the bespoke BRP schedule.graph implementation with ScheduleData. (#23733)
# Objective

- A possible step towards #10981.
- Followup to #22520.
- We accidentally have two implementations of the same thing! We created
a way to collect schedule data in `bevy_dev_tools` and in `bevy_remote`.
`ScheduleData` is a more complete implementation of collecting schedule
data, and is less tied to the internals of BRP (e.g., it supports
serializing to disk instead of only through the BRP API), so we switch
to that.

## Solution

- Replace the implementation of `schedule.graph` with the `ScheduleData`
API.

A disadvantage is that we now need to wait for the schedules to be
initialized before we can read them. Since users have to connect with
BRP though, it is almost certain that the schedules will be initialized
by the time they request the schedules. This may not be true of
schedules like state transitions though - since these only run rarely.
In a future PR, we can build the schedules on-demand instead.

## Testing

- Updated the test for this.
- Ran the same test as #23452
    - Terminal 1: `cargo r --example server --features=bevy_remote`
- Terminal 2: `curl
-d'{"jsonrpc":"2.0","method":"schedule.graph","id":1,"params":{"schedule_label":"First"}}'
-X POST -H "Accept: applcation/json" -H "Content-Type: application/json"
http://127.0.0.1:15702`
    - It dumped out a whole load of JSON that looked expected!
- I don't have a visualization of the schedule data yet, so I can't
validate that it's correct, but there's no reason to believe its wrong
given the existing `ScheduleData` tests.
2026-04-09 23:29:11 +00:00
Chris Russell 6a5ef7388f Change ResourceEntities from SparseSet to SparseArray to speed up resource lookups (#23616)
# Objective

Reduce memory usage for resources, and maybe improve performance of
resource lookups.

Related to #23039, but not a solution.

## Solution

Change `ResourceEntities` from a `SparseSet` to a `SparseArray`.  

`SparseArray` is `pub (crate)`, so simply exposing it through `Deref`
would cause privacy errors. Instead, remove the `Deref` impl and add
wrapper methods for `iter`, `get`, and `remove`. Change the return types
from `&Entity` to `Entity` now that they aren't generic.

As background: A `SparseArray` is a simple `Vec<Option<V>>`, while a
`SparseSet` is a `SparseArray` that maps keys to dense indexes, combined
with dense arrays of keys and values. That requires a second array
operation to find the actual value, but can be much better for memory
usage when the values are large, since missing items only take up space
for a single index instead of an entire value.

But the values in `ResourceEntities` are `Entity`, which are already
small! A `SparseArray` will always be smaller on 64-bit systems, since
an `Entity` is the same size as a `usize`, and we don't need to store
the additional `dense` and `indices` arrays. So switching to
`SparseArray` will save a lookup *and* save memory.

One drawback is that we can no longer use the dense lists to iterate all
resources, so methods like `iter_resources` now need to scan all
component ids. I don't expect this to be a problem in practice, though.
`iter_resources` is rarely used, and O(components) isn't all that much
worse than O(resources). If it turns out to be an issue, it's also
possible to recover this data by querying the `IsResource` component.

## Testing

Inconclusive.  

I attempted to run benchmarks, both `bevymark` as in the linked issue
and `cargo bench -p benches --bench ecs`, but the results were too noisy
on my machine to reach any conclusions. And now that I look more
closely, we don't have many benches that even use resources!

---------

Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
2026-04-08 15:40:20 +00:00
Kevin Chen 9f90ff38b9 fix(brp): allow params and id to be undefined when deserializing (#23661)
# Objective

- Fixes #23643 
- Some methods for BRP have `params` as an `Option`. `id` itself also
seems to be an `Option`. If these are not provided in the request
object, it should not panic on the deserialization level. Individual
methods should handle it, and they do already when its necesssary.

## Solution

- during deserialization, `params` and `id` should just flatten the
nested `Option` instead of `unwrap` and assuming something is there

## Testing

- Wrote a regression test
- Tested executing a curl while the `server` example without params, and
it works
`curl -d'{"jsonrpc":"2.0","method":"world.list_components","id":1}' -X
POST -H "Accept: applcation/json" -H "Content-Type: application/json"
http://127.0.0.1:15702`
- Tested `schedule.graph` to ensure that it panics without params
provided on its own (it does) and that params are still read correctly
when provided (it does)
2026-04-06 23:17:11 +00:00
Daniel Skates 3c98d531d8 Add BRP to render app (#23446)
# Objective

- BRP on the `RenderApp`

## Solution

- Add type registry to `RenderApp`
- Add BRP systems to render app
- Add HTTP listener to extra port

I suggest hiding whitespace for reviewing:

<img width="422" height="360" alt="image"
src="https://github.com/user-attachments/assets/3d76eafb-40f5-42f6-8752-c9d94f81d378"
/>

## Related:

- https://github.com/bevyengine/bevy/pull/23513
- https://github.com/bevyengine/bevy/pull/23447
- https://github.com/bevyengine/bevy/pull/23452

## Testing

- CI
- in terminal 1 run `cargo run --example client
--features="bevy_remote"`
- in terminal 2 run `curl
-d'{"jsonrpc":"2.0","method":"world.list_resources","id":1,"params":{}}'
-X POST -H "Accept: applcation/json" -H "Content-Type: application/json"
http://127.0.0.1:15702`
- in terminal 2 run `curl
-d'{"jsonrpc":"2.0","method":"world.list_resources","id":1,"params":{}}'
-X POST -H "Accept: applcation/json" -H "Content-Type: application/json"
http://127.0.0.1:15703`

---------

Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
2026-03-30 05:52:08 +00:00
Daniel Skates 56f3ef608b BRP Add schedule.graph endpoint (#23452)
# Objective

- Describe the graph for a given schedule

## Solution

- Add endpoint `schedule.graph`

## Related:

- https://github.com/bevyengine/bevy/pull/23447
- https://github.com/bevyengine/bevy/pull/23446

## Testing

- in terminal 1 run `cargo run --example server
--features="bevy_remote"`
- in terminal 2 run `curl
-d'{"jsonrpc":"2.0","method":"schedule.graph","id":1,"params":{"schedule_name":"First"}}'
-X POST -H "Accept: applcation/json" -H "Content-Type: application/json"
http://127.0.0.1:15702 `

<details><summary>Response</summary>
<p>

```json
{
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
        "systemsets": [
            {
                "key": "SystemSetKey(1v1)",
                "method": "SystemTypeSet:bevy_ecs::message::update::message_update_system"
            },
            {
                "key": "SystemSetKey(2v1)",
                "method": "MessageUpdateSystems"
            },
            {
                "key": "SystemSetKey(3v1)",
                "method": "SystemTypeSet:bevy_time::time_system"
            },
            {
                "key": "SystemSetKey(4v1)",
                "method": "TimeSystems"
            },
            {
                "key": "SystemSetKey(5v1)",
                "method": "SystemTypeSet:bevy_render::view::window::screenshot::clear_screenshots"
            },
            {
                "key": "SystemSetKey(6v1)",
                "method": "SystemTypeSet:bevy_ecs::schedule::executor::ApplyDeferred"
            },
            {
                "key": "SystemSetKey(7v1)",
                "method": "SystemTypeSet:bevy_ui::widget::viewport::viewport_picking"
            },
            {
                "key": "SystemSetKey(8v1)",
                "method": "PostInput"
            },
            {
                "key": "SystemSetKey(9v1)",
                "method": "SystemTypeSet:bevy_picking::input::mouse_pick_events"
            },
            {
                "key": "SystemSetKey(10v1)",
                "method": "Input"
            },
            {
                "key": "SystemSetKey(11v1)",
                "method": "SystemTypeSet:bevy_picking::input::touch_pick_events"
            }
        ],
        "hierarchy_nodes": [
            "Set(SystemSetKey(11v1))",
            "Set(SystemSetKey(10v1))",
            "System(SystemKey(6v1))",
            "Set(SystemSetKey(9v1))",
            "System(SystemKey(5v1))",
            "Set(SystemSetKey(8v1))",
            "Set(SystemSetKey(7v1))",
            "System(SystemKey(4v1))",
            "Set(SystemSetKey(6v1))",
            "Set(SystemSetKey(5v1))",
            "System(SystemKey(3v1))",
            "Set(SystemSetKey(4v1))",
            "Set(SystemSetKey(3v1))",
            "System(SystemKey(2v1))",
            "Set(SystemSetKey(2v1))",
            "Set(SystemSetKey(1v1))",
            "System(SystemKey(1v1))"
        ],
        "hierarchy_edges": [
            [
                "Set(SystemSetKey(1v1))",
                "System(SystemKey(1v1))"
            ],
            [
                "Set(SystemSetKey(3v1))",
                "System(SystemKey(2v1))"
            ],
            [
                "Set(SystemSetKey(8v1))",
                "System(SystemKey(4v1))"
            ],
            [
                "Set(SystemSetKey(2v1))",
                "System(SystemKey(1v1))"
            ],
            [
                "Set(SystemSetKey(7v1))",
                "System(SystemKey(4v1))"
            ],
            [
                "Set(SystemSetKey(4v1))",
                "System(SystemKey(2v1))"
            ],
            [
                "Set(SystemSetKey(9v1))",
                "System(SystemKey(5v1))"
            ],
            [
                "Set(SystemSetKey(10v1))",
                "System(SystemKey(6v1))"
            ],
            [
                "Set(SystemSetKey(5v1))",
                "System(SystemKey(3v1))"
            ],
            [
                "Set(SystemSetKey(10v1))",
                "System(SystemKey(5v1))"
            ],
            [
                "Set(SystemSetKey(11v1))",
                "System(SystemKey(6v1))"
            ]
        ],
        "dependency_nodes": [
            "System(SystemKey(1v1))",
            "Set(SystemSetKey(1v1))",
            "Set(SystemSetKey(2v1))",
            "System(SystemKey(2v1))",
            "Set(SystemSetKey(3v1))",
            "Set(SystemSetKey(4v1))",
            "System(SystemKey(3v1))",
            "Set(SystemSetKey(5v1))",
            "Set(SystemSetKey(6v1))",
            "System(SystemKey(4v1))",
            "Set(SystemSetKey(7v1))",
            "Set(SystemSetKey(8v1))",
            "System(SystemKey(5v1))",
            "Set(SystemSetKey(9v1))",
            "Set(SystemSetKey(10v1))",
            "System(SystemKey(6v1))",
            "Set(SystemSetKey(11v1))"
        ],
        "dependency_edges": [
            [
                "Set(SystemSetKey(2v1))",
                "Set(SystemSetKey(10v1))"
            ],
            [
                "Set(SystemSetKey(10v1))",
                "Set(SystemSetKey(8v1))"
            ],
            [
                "System(SystemKey(3v1))",
                "Set(SystemSetKey(6v1))"
            ],
            [
                "System(SystemKey(5v1))",
                "System(SystemKey(6v1))"
            ],
            [
                "Set(SystemSetKey(4v1))",
                "Set(SystemSetKey(8v1))"
            ],
            [
                "Set(SystemSetKey(4v1))",
                "Set(SystemSetKey(10v1))"
            ],
            [
                "Set(SystemSetKey(2v1))",
                "Set(SystemSetKey(8v1))"
            ],
            [
                "Set(SystemSetKey(1v1))",
                "System(SystemKey(3v1))"
            ]
        ]
    }
}
```

</p>
</details> 

From the above response, the below graph can be generated. Hierarchy
edges are blue, dependency edges are red. System nodes are implied by
hierarchy from Set to System.

<img width="1543" height="347" alt="first"
src="https://github.com/user-attachments/assets/80ac7e80-2a28-4246-80cc-29337bad4383"
/>

<details><summary>GraphViz Source</summary>
<p>

```
digraph {
    "Set(SystemSetKey(1v1))" [label="message_update_system"]
    "Set(SystemSetKey(2v1))" [label="MessageUpdateSystems"]
    "Set(SystemSetKey(3v1))" [label="time_system"]
    "Set(SystemSetKey(4v1))" [label="TimeSystems"]
    "Set(SystemSetKey(5v1))" [label="clear_screenshots"]
    "Set(SystemSetKey(6v1))" [label="ApplyDeferred"]
    "Set(SystemSetKey(7v1))" [label="viewport_picking"]
    "Set(SystemSetKey(8v1))" [label="PostInput"]
    "Set(SystemSetKey(9v1))" [label="mouse_pick_events"]
    "Set(SystemSetKey(10v1))" [label="Input"]
    "Set(SystemSetKey(11v1))" [label="touch_pick_events"]

    // implied nodes
    "System(SystemKey(1v1))" [label="implied message_update_system", shape=rectangle]
    "System(SystemKey(2v1))" [label="implied time_system", shape=rectangle]
    "System(SystemKey(3v1))" [label="implied clear_screenshots", shape=rectangle]
    "System(SystemKey(4v1))" [label="implied viewport_picking", shape=rectangle]
    "System(SystemKey(5v1))" [label="implied mouse_pick_events", shape=rectangle]
    "System(SystemKey(6v1))" [label="implied touch_pick_events", shape=rectangle]

    // hierarchy
    "Set(SystemSetKey(1v1))" -> "System(SystemKey(1v1))" [color=blue]
    "Set(SystemSetKey(3v1))" -> "System(SystemKey(2v1))" [color=blue]
    "Set(SystemSetKey(8v1))" -> "System(SystemKey(4v1))" [color=blue]
    "Set(SystemSetKey(2v1))" -> "System(SystemKey(1v1))" [color=blue]
    "Set(SystemSetKey(7v1))" -> "System(SystemKey(4v1))" [color=blue]
    "Set(SystemSetKey(4v1))" -> "System(SystemKey(2v1))" [color=blue]
    "Set(SystemSetKey(9v1))" -> "System(SystemKey(5v1))" [color=blue]
    "Set(SystemSetKey(10v1))" -> "System(SystemKey(6v1))" [color=blue]
    "Set(SystemSetKey(5v1))" -> "System(SystemKey(3v1))" [color=blue]
    "Set(SystemSetKey(10v1))" -> "System(SystemKey(5v1))" [color=blue]
    "Set(SystemSetKey(11v1))" -> "System(SystemKey(6v1))" [color=blue]

    // dependencies
    "Set(SystemSetKey(2v1))" -> "Set(SystemSetKey(10v1))" [color=red]
    "Set(SystemSetKey(10v1))" -> "Set(SystemSetKey(8v1))" [color=red]
    "System(SystemKey(3v1))" -> "Set(SystemSetKey(6v1))" [color=red]
    "System(SystemKey(5v1))" -> "System(SystemKey(6v1))" [color=red]
    "Set(SystemSetKey(4v1))" -> "Set(SystemSetKey(8v1))" [color=red]
    "Set(SystemSetKey(4v1))" -> "Set(SystemSetKey(10v1))" [color=red]
    "Set(SystemSetKey(2v1))" -> "Set(SystemSetKey(8v1))" [color=red]
    "Set(SystemSetKey(1v1))" -> "System(SystemKey(3v1))" [color=red]
}
```

</p>
</details>

---------

Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-03-26 22:23:56 +00:00
Daniel Skates 1a5fdf96db BRP Add schedule.list endpoint (#23447)
# Objective

- List schedules in BRP

## Solution

- Add the endpoint
- Add to `Schedules` some tracking of `temporarily_removed` (schedule
removed to execute) and `empty_labels` (no `Schedule` for that label)

## Related:

- https://github.com/bevyengine/bevy/pull/23452
- https://github.com/bevyengine/bevy/pull/23446

## Testing

- in terminal 1 run `cargo run --example server
--features="bevy_remote"`
- in terminal 2 run `curl
-d'{"jsonrpc":"2.0","method":"schedule.list","id":1,"params":{}}' -X
POST -H "Accept: applcation/json" -H "Content-Type: application/json"
http://127.0.0.1:15702`

<details><summary>Response</summary>
<p>

```json
{
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
        "empty_schedule_labels": [
            "FixedPreUpdate",
            "FixedUpdate"
        ],
        "schedule_labels": [
            "Startup",
            "First",
            "RunFixedMainLoop",
            "PostStartup",
            "FixedFirst",
            "StateTransition",
            "PreUpdate",
            "PostUpdate",
            "Update",
            "PreStartup",
            "SpawnScene",
            "Last",
            "FixedLast",
            "FixedPostUpdate",
            "FixedMain"
        ],
        "unavailable_schedule_labels": [
            "Main",
            "RemoteLast"
        ]
    }
}
```

</p>
</details>

---------

Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
2026-03-25 16:56:06 +00:00
François Mockers 27fe7af0c7 Write Messages by Bevy Remote Protocol (#23391)
# Objective

- Be able to write a message through BRP

## Solution

- Add an endpoint to bevy_remote that creates a message from a payload
and writes it to the world
- Make `BrpTriggerEventParams` pub like all the other params for easier
use

## Testing

- New test in CI

---------

Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
2026-03-18 18:38:17 +00:00
Olle Lukowski 0b0f65377b Address some nightly clippy lints (#23314)
# Objective

Just some code cleanup opportunities that clippy detected.

## Solution

- Apply the suggestions from clippy

## Testing

Don't think I need to test this (other than compiling which I did)
2026-03-11 19:47:35 +00:00
Mira 5f8435b89d BrpRequest: remove jsonrpc field (#23175)
# Objective

`BrpRequest` includes a useless `jsonrpc` field that must always be set
to "2.0". Remove it.

This change could also be made to `BrpResponse`, but that would be much
more involved due to the `serde(flatten)` while also offering less
benefit (as users need to create this struct less often).

I've not added a migration guide because no advice is needed to migrate.

## Testing

Run the `server` + `client` example.

---------

Co-authored-by: Mira Morgana <mira-morgana@posteo.net>
Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
2026-03-10 04:48:58 +00:00
Sébastien Job 55c4e977d0 Add component info to BRP registry schema (#23102)
# Objective

Add component metadata to the BRP `registry.schema` method.

The following data related to components is missing and this PR adds it:

- Whether the component is mutable or not.
- Type paths of required components.
- Whether the component is a relationship or relationship target.

Other metadata could easily be added, basically everything in the
[`ComponentInfo`](https://docs.rs/bevy/latest/bevy/ecs/component/struct.ComponentInfo.html)
type.

## Solution

- Once per type, use `World::components` to obtain a potential
`ComponentId` and `ComponentInfo`.
- Use it to fill the new `component_info` field.
- It doesn't introduce a breaking change, as the new field is optional
and hidden for non-component types.

## Testing

- I added a unit test. It verifies mutability, required components, and
relationship kind for a few test components.
- I also called BRP to retrieve a schema and verify the returned data is
correct.

---

## Showcase

Here are a few examples of the returned JSON schema when calling the BRP
`registry.schema` method, with other fields omitted for brevity (they
are unchanged):

```json
{
  "bevy_ecs::hierarchy::ChildOf": {
    "componentInfo": {
      "isSendAndSync": true,
      "mutable": false,
      "relationshipKind": "Relationship",
      "storageType": "Table"
    }
  },
  "bevy_ecs::hierarchy::Children": {
    "componentInfo": {
      "isSendAndSync": true,
      "mutable": true,
      "relationshipKind": "RelationshipTarget",
      "storageType": "Table"
    }
  },
  "bevy_transform::components::transform::Transform": {
    "componentInfo": {
      "isSendAndSync": true,
      "mutable": true,
      "requiredComponentTypes": [
        "bevy_transform::components::global_transform::GlobalTransform",
        "bevy_transform::components::transform::TransformTreeChanged"
      ],
      "storageType": "Table"
    }
  },
  "bevy_render::sync_world::SyncToRenderWorld": {
    "componentInfo": {
      "isSendAndSync": true,
      "mutable": true,
      "storageType": "SparseSet"
    }
  }
}
```
2026-03-01 20:35:39 +00:00
Mira b9eb475f8e Tiny bevy_remote doc format fix (#23176)
Co-authored-by: Mira Morgana <mira-morgana@posteo.net>
2026-03-01 04:08:53 +00:00
Carter Anderson f4bb750f34 Remove component/resource redundancies (#22930)
Part of #19731 
Follow-up to #22919 and #20934

This consolidates some of our component registration internals and
removes some resource / component redundancies there.
2026-02-13 01:53:41 +00:00
Trashtalk217 59e9ee3a1a Store Resources as components on singleton entities (#20934)
This is part of #19731.

# Resources as Components

## Motivation

More things should be entities. This simplifies the API, the lower-level
implementation and the tools we have for entities and components can be
used for other things in the engine. In particular, for resources, it is
really handy to have observers, which we currently don't have. See
#20821 under 1A, for a more specific use.

## Current Work

This removes the `resources` field from the world storage and instead
store the resources on singleton entities. For easy lookup, we add a
`HashMap<ComponentId, Entity>` to `World`, in order to quickly find the
singleton entity where the resource is stored.

Because we store resources on entities, we derive `Component` alongside
`Resource`, this means that

```rust
#[derive(Resource)]
struct Foo;
```
turns into
```rust
#[derive(Resource, Component)]
struct Foo;
```

This was also done for reflections, meaning that

```rust
#[derive(Resource, Reflect)]
#[refect(Resource)]
struct Bar;
```
becomes
```rust
#[derive(Resource, Component, Reflect)]
#[refect(Resource, Component)]
struct Bar;
```

In order to distinguish resource entities, they are tagged with the
`IsResource` component. Additionally, to ensure that they aren't queried
by accident, they are also tagged as being internal entities, which
means that they don't show up in queries by default.

## Drawbacks

- Currently you can't have a struct that is both a `Resource` and a
`Component`, because `Resource` expands to also implement `Component`,
this means that this throws a compiler error as it's implemented twice.
- Because every reflected Resource must also implement
`ReflectComponent` you need to import
`bevy_ecs::reflect::ReflectComponent` every time you use
`#[reflect(Resource)]`. This is kind of unintuitive.

## Future Work

- Simplify `Access` in the ECS, to only deal with components (and not
components *and* resources).
- Newtype `Res<Resource>` to `Single<Ref<Resource>>` (or something
similair).
- Eliminate `ReflectResource`.
- Take stabs at simplifying the public facing API.

---------

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Dimitrios Loukadakis <dloukadakis@users.noreply.github.com>
2026-02-10 18:53:12 +00:00
atlv 3ae32d500b move transmission stuff to bevy_pbr (#22687)
# Objective

- It makes no sense for bevy_camera::Camera3d to talk about transmission
quality settings
- transmission is not a core thing its a purely pbr thing, why is in
bevy_core_pipelines
- the implementation is generally scattered all over the place
- ScreenSpaceTransmissionQuality is a resource for no reason at all

## Solution

- split out a struct for transmission stuff
- consolidate stuff in bevy_pbr
- make ScreenSpaceTransmissionQuality not a resource

## Testing

transmission example looks good
2026-01-25 20:36:42 +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
Federico Rinaldi 53791c227c Update BRP method names in code examples (#22387)
Fixes #22385

I searched for all the old methods listed in commit
3517af235a. The `bevy/query` method was
still being used in two JSON example blocks, while it was updated to
`world.query`. This PR fixes that. I found no instances of the other old
methods being used.
2026-01-05 22:55:30 +00:00
Federico Rinaldi 6ee5067857 Make BRP builtins utilities parse and parse_some public (#22005)
# Objective

Builtin BRP methods make constant use of `parse` and `parse_some` in
parsing utilities. Making them public allows users to use them in their
own code.

## Solution

Make both functions `pub`.

## Testing

I think testing is not necessary, especially since doc strings do not
link anywhere.
2025-12-15 02:14:04 +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
Christophe Bronner 0af6fc1c74 Implement world.trigger_event remote method (#21798)
# Objective

Tools using `bevy_remote` will be able to identify (via the schema) and
trigger events.

- [x] Document `bevy_ecs/src/reflect/event.rs`

## Solution

I've added a method `world.trigger_event`, added `Event` to the schema's
reflection metadata and `ReflectEvent` to allow this.

## Testing

I have copied the (tested) code from my game but have NOT tested this
branch yet.
I am new to Rust/Cargo and need to go to sleep now, I'll figure this out
and test it tomorrow.

---

## Showcase

Here's what I needed to add to my game in order to allow my editor to
access and trigger an event:

```rust
#[derive(Event, Reflect)]
#[reflect(Event)]
pub struct AssignToRoute {
    pub vehicle: Entity,
    pub route: Entity,
    pub origin: Entity,
}
```

Here's a screenshot of my editor using this feature:

<img width="1463" height="967" alt="Screenshot 2025-11-10 at 1 40 42 AM"
src="https://github.com/user-attachments/assets/7696ddb8-3552-4e0d-a78f-6178c0c66cbb"
/>
2025-12-08 21:37:20 +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
re0312 2219069c72 remove deprecated APIs in 0.17 (#21723)
# Objective

- removes all APIs that were marked as deprecated in 0.17,
2025-11-03 18:51:23 +00:00
MevLyshkin 5f9b085cbb BRP allow spawning/inserting Components with only Reflect (#20981)
# Objective

Fixes #20952

## Solution

Improve flow for getting type path. Add new test to make sure it will
work later on.

## Testing

New test is added to confirm that the solution works, I wrote the test
first to check if I have the same issue as described in report. It was
that and the fix was provided by @natepiano so my work here is mostly
test.
2025-09-21 15:33:09 +00:00
Marc Guiselin 8a2d9c1231 Document missing brp methods (#21007)
# Objective

Document missing brp methods:
- `registry.schema`
- `rpc.discover`

## Solution

- Update crate-level documentation

## Testing

- `cargo doc -p bevy_remote`
2025-09-17 20:59:23 +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
Tom 94bb6e1585 Fix broken json documentation (#20789)
It's pretty self-explanatory. There was simply a missing ' " '
2025-08-29 22:34:06 +00:00
atlv 90c5c123c6 Fix doc paths to not use deprecated re-exports (#20496)
# Objective

- Prepare for removing re-exports

## Solution

- title

## Testing

- cargo check --examples --all-features
2025-08-10 20:48:01 +00:00
James Liu 8e52194d70 CI fixes for Rust 1.89 (#20462)
Adopted from #20456

Notes:

* The origin of the `dead_code` lints were coming from the `ShaderType `
derive macro. This has been reported as
https://github.com/teoxoy/encase/issues/102, and a temporary
workspace-wide `allow` added to the top level Cargo.toml.
* One of the lints pointed out that `PartialEq` and `Eq` may not work as
expected for function pointers, so `CloneBehavior` no longer implements
either trait, and pattern matching is used in instead.

Original PR Description:
># Objective
>
>Unbreak CI.
>
> ## Solution
>
> Fix the lints.
>
>I've opted for anonymous lifetimes in every revealed case so far;
please let me know if you think I should used named lifetimes in
specific cases and why.
>
>## Testing
>
>Is CI green?
>
>## Context
>
> This lint originally had a much larger splash damage, with fairly
negative effects on Bevy. See
https://github.com/rust-lang/rust/issues/131725.
>
> The more restricted former is much more helpful, despite the large
diff in this PR. Bevy is a large code base!
>
>## TODO
>
>- [x] discuss proposed lifetime lint fixes
>,- [x] use cargo clippy --fix to fix newly uncovered docs misformatting
>- [x] fix newly revealed dead code issues
>- [x] ensure CI is green

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Mike <mike.hsu@gmail.com>
2025-08-08 21:14:36 +00:00
AlephCubed 3517af235a Renamed BRP methods to be more explicit. (#19377)
Fixed #18055.

Based on the discussion in the related issue, the following BRP methods
have been renamed:

| Old                    | New                           |
|------------------------|-------------------------------|
| `bevy/query`           | `world.query`                 |
| `bevy/spawn`           | `world.spawn_entity`          |
| `bevy/destroy`         | `world.despawn_entity`        |
| `bevy/reparent`        | `world.reparent_entities`       |
| `bevy/get`             | `world.get_components`        |
| `bevy/insert`          | `world.insert_components`     |
| `bevy/remove`          | `world.remove_components`     |
| `bevy/list`            | `world.list_components`       |
| `bevy/mutate`          | `world.mutate_components`     |
| `bevy/get+watch`       | `world.get_components+watch`  |
| `bevy/list+watch`      | `world.list_components+watch` |
| `bevy/get_resource`    | `world.get_resources`         |
| `bevy/insert_resource` | `world.insert_resources`      |
| `bevy/remove_resource` | `world.remove_resources`      |
| `bevy/list_resources`  | `world.list_resources`        |
| `bevy/mutate_resource` | `world.mutate_resources`      |
| `registry/schema`      | `registry.schema`             |

I also replaced the word `destroy` with `despawn` to match
`EntityCommands::despawn` and other related methods.
2025-07-29 20:22:37 +00:00
Chris Russell 0dce905613 Faster FilteredEntity(Ref|Mut) and Entity(Ref|Mut)Except by borrowing Access (#20111)
# Objective

Improve the performance of queries using `FilteredEntityRef`,
`FilteredEntityMut`, `EntityRefExcept`, and `EntityMutExcept`. In
particular, this appears to speed up `bevy_animation::animate_targets`
by 10% in many-foxes.

`FilteredEntity(Ref|Mut)` needs to store an `Access` to determine which
components may be accessed. Prior to #15396, this required cloning the
`Access` for each instance. Now, we can borrow the `Access` from the
query state and make cheap pointer copies.

`Entity(Ref|Mut)Except` avoided needing to clone an `Access` by calling
functions on the `Bundle` trait. Unfortunately, that meant we needed to
convert from a type to a `ComponentId` for every component in the bundle
on every check. Now, we can do those conversions up front and pass
references to an `Access`.

Finally, fix a bug where `Entity(Ref|Mut)Except` would not initialize
their components during `init_state`. I noticed this while updating
`init_state` and fixed it while I was there. That was normally harmless
because the components would be registered elsewhere, but a system like
`fn system(_q1: Query<EntityMutExcept<C>>, _q2: Query<&mut C>) {}` would
fail to find the `ComponentId` for `C` and not exclude it from the
access for `q1`, and then panic with conflicting access from `q2`.

## Solution

Change `FilteredEntityRef` and `FilteredEntityMut` to store `&'s Access`
instead of `Access`, and change `EntityRefExcept` and `EntityMutExcept`
to store an extra `&'s Access`.

This adds the `'s` lifetime to those four types, and most changes are
adding lifetimes as appropriate.

Change the `WorldQuery::State` for `Entity(Ref|Mut)Except` to store an
`Access` that can be borrowed from, replacing the
`SmallVec<[ComponentId; 4]>` that was used only to set the query access.

To support the conversions from `EntityRef` and `EntityMut`, we need to
be able to create a `&'static Access` for read-all or write-all. I could
not change `fn read_all_components()` to be `const` because it called
the non-`const` `FixedBitSet::clear()`, so I created separate
constructor functions.

## Testing

Ran `cargo run --example many_foxes --features bevy/trace_tracy
--release` before and after, and compared the results of
`animate_targets`, since that is the only in-engine use of
`EntityMutExcept` and was the motivation for creating it.

Yellow is this PR, red is main: 

<img width="695" height="690" alt="image"
src="https://github.com/user-attachments/assets/24531a3f-65bf-46d0-baa5-29ea9e56b16a"
/>
2025-07-21 22:41:59 +00:00
Joe Buehler d16d216083 Add support for returning all Component and values to query method in the Bevy Remote Protocol (#19857)
# Objective

We should have an API with filtering to allow BRP clients to retrieve
all relevant data from the world state. Currently working on adding
examples - but reviews are appreciated! Still semi-WIP while I get my
head around bevy’s reflection and implementation :)

## Solution

This change adds support to query all entities in the world, and returns
all of their Reflected Components with corresponding values. For custom
`Components` it's important to still implement `Reflect` so that this
endpoint returns these. This will be useful for the
`bevy_entity_inspector` so that we can easily get the current world
state. We have modified the existing query API
so that clients can now pass in an empty `components[]` on the JSON
request.

## Testing

Updated example to showcase how to use the new endpoint to get all data:
```rust
/// Create a query_all request to send to the remote Bevy app.
/// This request will return all entities in the app, their components, and their
/// component values.
fn run_query_all_components_and_entities(url: String) -> Result<(), anyhow::Error> {
    let query_all_req = BrpRequest {
        jsonrpc: String::from("2.0"),
        method: String::from(BRP_QUERY_METHOD),
        id: Some(serde_json::to_value(1)?),
        params: None,
    };
    println!("query_all req: {:#?}", query_all_req);
    let query_all_res = ureq::post(&url)
        .send_json(query_all_req)?
        .body_mut()
        .read_json::<serde_json::Value>()?;
    println!("{query_all_res:#}");
    Ok(())
}
```

---

## Showcase
In the `client.rs` example, we can clearly see (assuming the `server.rs`
is running) a query hit for all entities and components:
```text
query_all req: BrpRequest {
    jsonrpc: "2.0",
    method: "bevy/query",
    id: Some(
        Number(1),
    ),
    params: Some(
        Object {
            "data": Object {
                "components": Array [],
                "has": Array [],
                "option": Array [],
            },
            "filter": Object {
                "with": Array [],
                "without": Array [],
            },
            "strict": Bool(false),
        },
    ),
}
```

And in the massive response:
```text
.....
{
      "components": {
        "bevy_window::monitor::Monitor": {
          "name": "\\\\.\\DISPLAY1",
          "physical_height": 1080,
          "physical_position": [
            -1920,
            0
          ],
          "physical_width": 1920,
          "refresh_rate_millihertz": 240000,
          "scale_factor": 1.25,
          "video_modes": [
            {
              "bit_depth": 32,
              "physical_size": [
                1920,
                1080
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1680,
                1050
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1600,
                900
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1440,
                900
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1400,
                1050
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1366,
                768
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1360,
                768
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1280,
                1024
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1280,
                960
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1280,
                800
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1280,
                768
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1280,
                720
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1280,
                600
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1152,
                864
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1024,
                768
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                800,
                600
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                640,
                480
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                640,
                400
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                512,
                384
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                400,
                300
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                320,
                240
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                320,
                200
              ],
              "refresh_rate_millihertz": 240000
            }
          ]
        }
      },
      "entity": 4294967267
    },
....
```

What's also really cool about this and `bevy_reflect` is that we also
get custom components returned as well (see below for `"server::Cube":
1.0` as the custom reflected struct specified in `server.rs`:

```text
{
      "components": {
        "bevy_render::primitives::Aabb": {
          "center": [
            0.0,
            0.0,
            0.0
          ],
          "half_extents": [
            0.5,
            0.5,
            0.5
          ]
        },
        "bevy_render::view::visibility::InheritedVisibility": true,
        "bevy_render::view::visibility::ViewVisibility": true,
        "bevy_render::view::visibility::Visibility": "Inherited",
        "bevy_transform::components::global_transform::GlobalTransform": [
          1.0,
          0.0,
          0.0,
          0.0,
          1.0,
          0.0,
          0.0,
          0.0,
          1.0,
          0.0,
          2.4572744369506836,
          0.0
        ],
        "bevy_transform::components::transform::Transform": {
          "rotation": [
            0.0,
            0.0,
            0.0,
            1.0
          ],
          "scale": [
            1.0,
            1.0,
            1.0
          ],
          "translation": [
            0.0,
            2.4572744369506836,
            0.0
          ]
        },
        "bevy_transform::components::transform::TransformTreeChanged": null,
        "server::Cube": 1.0
      },
```

---------

Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
2025-07-03 18:51:32 +00:00
charlotte 🌸 92e65d5eb1 Upgrade to Rust 1.88 (#19825) 2025-06-26 19:38:19 +00:00
MevLyshkin 84f21f7c8a Schema types metadata (#19524)
# Objective

- Currently there is predefinied list of supported DataTypes that can be
detected on Bevy JSON Schema generation and mapped as reflect_types
array elements.
- Make it possible to register custom `reflectTypes` mappings for Bevy
JSON Schema.

## Solution

- Create a `SchemaTypesMetadata` Resource that will hold mappings for
`TypeId` of `TypeData`. List is bigger from beggining and it is possible
to expand it without forking package.

## Testing

- I use it for quite a while in my game, I have a fork of bevy_remote
with more changes that later I want to merge to main as well.

---------

Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
2025-06-20 17:07:16 +00:00
François Mockers 4e694aea53 ECS: put strings only used for debug behind a feature (#19558)
# Objective

- Many strings in bevy_ecs are created but only used for debug: system
name, component name, ...
- Those strings make a significant part of the final binary and are no
use in a released game

## Solution

- Use [`strings`](https://linux.die.net/man/1/strings) to find ...
strings in a binary
- Try to find where they come from
- Many are made from `type_name::<T>()` and only used in error / debug
messages
- Add a new structure `DebugName` that holds no value if `debug` feature
is disabled
- Replace `core::any::type_name::<T>()` by `DebugName::type_name::<T>()`

## Testing

Measurements were taken without the new feature being enabled by
default, to help with commands

### File Size

I tried building the `breakout` example with `cargo run --release
--example breakout`

|`debug` enabled|`debug` disabled|
|-|-|
|81621776 B|77735728B|
|77.84MB|74.13MB|

### Compilation time

`hyperfine --min-runs 15 --prepare "cargo clean && sleep 5"
'RUSTC_WRAPPER="" cargo build --release --example breakout'
'RUSTC_WRAPPER="" cargo build --release --example breakout --features
debug'`

```
breakout' 'RUSTC_WRAPPER="" cargo build --release --example breakout --features debug'
Benchmark 1: RUSTC_WRAPPER="" cargo build --release --example breakout
  Time (mean ± σ):     84.856 s ±  3.565 s    [User: 1093.817 s, System: 32.547 s]
  Range (min … max):   78.038 s … 89.214 s    15 runs

Benchmark 2: RUSTC_WRAPPER="" cargo build --release --example breakout --features debug
  Time (mean ± σ):     92.303 s ±  2.466 s    [User: 1193.443 s, System: 33.803 s]
  Range (min … max):   90.619 s … 99.684 s    15 runs

Summary
  RUSTC_WRAPPER="" cargo build --release --example breakout ran
    1.09 ± 0.05 times faster than RUSTC_WRAPPER="" cargo build --release --example breakout --features debug
```
2025-06-18 20:15:25 +00:00
Alice Cecile 6ddd0f16a8 Component lifecycle reorganization and documentation (#19543)
# Objective

I set out with one simple goal: clearly document the differences between
each of the component lifecycle events via module docs.

Unfortunately, no such module existed: the various lifecycle code was
scattered to the wind.
Without a unified module, it's very hard to discover the related types,
and there's nowhere good to put my shiny new documentation.

## Solution

1. Unify the assorted types into a single
`bevy_ecs::component_lifecycle` module.
2. Write docs.
3. Write a migration guide.

## Testing

Thanks CI!

## Follow-up

1. The lifecycle event names are pretty confusing, especially
`OnReplace`. We should consider renaming those. No bikeshedding in my PR
though!
2. Observers need real module docs too :(
3. Any additional functional changes should be done elsewhere; this is a
simple docs and re-org PR.

---------

Co-authored-by: theotherphil <phil.j.ellison@gmail.com>
2025-06-10 00:59:16 +00:00
Eagster 8ad7118443 Only get valid component ids (#19510)
# Objective

- #19504 showed a 11x regression in getting component values for
unregistered components. This pr should fix that and improve others a
little too.
- This is some cleanup work from #18173 .

## Solution

- Whenever we expect a component value to exist, we only care about
fully registered components, not queued to be registered components
since, for the value to exist, it must be registered.
- So we can use the faster `get_valid_*` instead of `get_*` in a lot of
places.
- Also found a bug where `valid_*` did not forward to `get_valid_*`
properly. That's fixed.

## Testing

CI
2025-06-06 20:59:57 +00:00
Sébastien Job 2b8bf45f0d Fix BRP query failing when specifying missing/invalid components (#18871)
# Objective

- Fixes #18869.

## Solution

The issue was the `?` after a `Result` raising the error, instead of
treating it.
Instead it is handled with `ok`, `and_then`, `map` ...

_Edit: I added the following logic._
On `bevy/query` remote requests, when `strict` is false:
- Unregistered components in `option` and `without` are ignored.
- Unregistered components in `has` are considered absent from the
entity.
- Unregistered components in `components` and `with` result in an empty
response since they specify hard requirements.

I made the `get_component_ids` function return a
`AnyhowResult<(Vec<(TypeId, ComponentId)>, Vec<String>)>` instead of the
previous `AnyhowResult<Vec<(TypeId, ComponentId)>>`; that is I added the
list of unregistered components.

## Testing

I tested changes using the same procedure as in the linked issue:
```sh
cargo run --example server --features="bevy_remote"
```
In another terminal:
```sh
# Not strict:
$ curl -X POST http://localhost:15702 -H "Content-Type: application/json" -d '{ "jsonrpc": "2.0", "method": "bevy/query", "id": 0, "params": { "data": { "components": [ "foo::bar::MyComponent" ] } } }'
{"jsonrpc":"2.0","id":0,"result":[]}

# Strict:
$ curl -X POST http://localhost:15702 -H "Content-Type: application/json" -d '{ "jsonrpc": "2.0", "method": "bevy/query", "id": 0, "params": { "data": { "components": [ "foo::bar::MyComponent" ] }, "strict": true } }'
{"jsonrpc":"2.0","id":0,"error":{"code":-23402,"message":"Component `foo::bar::MyComponent` isn't registered or used in the world"}}
```
2025-05-26 15:26:46 +00:00
Eagster 0b4858726c Make entity::index non max (#18704)
# Objective

There are two problems this aims to solve. 

First, `Entity::index` is currently a `u32`. That means there are
`u32::MAX + 1` possible entities. Not only is that awkward, but it also
make `Entity` allocation more difficult. I discovered this while working
on remote entity reservation, but even on main, `Entities` doesn't
handle the `u32::MAX + 1` entity very well. It can not be batch reserved
because that iterator uses exclusive ranges, which has a maximum upper
bound of `u32::MAX - 1`. In other words, having `u32::MAX` as a valid
index can be thought of as a bug right now. We either need to make that
invalid (this PR), which makes Entity allocation cleaner and makes
remote reservation easier (because the length only needs to be u32
instead of u64, which, in atomics is a big deal), or we need to take
another pass at `Entities` to make it handle the `u32::MAX` index
properly.

Second, `TableRow`, `ArchetypeRow` and `EntityIndex` (a type alias for
u32) all have `u32` as the underlying type. That means using these as
the index type in a `SparseSet` uses 64 bits for the sparse list because
it stores `Option<IndexType>`. By using `NonMaxU32` here, we cut the
memory of that list in half. To my knowledge, `EntityIndex` is the only
thing that would really benefit from this niche. `TableRow` and
`ArchetypeRow` I think are not stored in an `Option` in bulk. But if
they ever are, this would help. Additionally this ensures
`TableRow::INVALID` and `ArchetypeRow::INVALID` never conflict with an
actual row, which in a nice bonus.

As a related note, if we do components as entities where `ComponentId`
becomes `Entity`, the the `SparseSet<ComponentId>` will see a similar
memory improvement too.

## Solution

Create a new type `EntityRow` that wraps `NonMaxU32`, similar to
`TableRow` and `ArchetypeRow`.
Change `Entity::index` to this type.

## Downsides

`NonMax` is implemented as a `NonZero` with a binary inversion. That
means accessing and storing the value takes one more instruction. I
don't think that's a big deal, but it's worth mentioning.

As a consequence, `to_bits` uses `transmute` to skip the inversion which
keeps it a nop. But that also means that ordering has now flipped. In
other words, higher indices are considered less than lower indices. I
don't think that's a problem, but it's also worth mentioning.

## Alternatives

We could keep the index as a u32 type and just document that `u32::MAX`
is invalid, modifying `Entities` to ensure it never gets handed out.
(But that's not enforced by the type system.) We could still take
advantage of the niche here in `ComponentSparseSet`. We'd just need some
unsafe manual conversions, which is probably fine, but opens up the
possibility for correctness problems later.

We could change `Entities` to fully support the `u32::MAX` index. (But
that makes `Entities` more complex and potentially slightly slower.)

## Testing

- CI
- A few tests were changed because they depend on different ordering and
`to_bits` values.

## Future Work

- It might be worth removing the niche on `Entity::generation` since
there is now a different niche.
- We could move `Entity::generation` into it's own type too for clarity.
- We should change `ComponentSparseSet` to take advantage of the new
niche. (This PR doesn't change that yet.)
- Consider removing or updating `Identifier`. This is only used for
`Entity`, so it might be worth combining since `Entity` is now more
unique.

---------

Co-authored-by: atlv <email@atlasdostal.com>
Co-authored-by: Zachary Harrold <zac@harrold.com.au>
2025-05-07 18:20:30 +00:00
Joona Aalto 7b1c9f192e Adopt consistent FooSystems naming convention for system sets (#18900)
# Objective

Fixes a part of #14274.

Bevy has an incredibly inconsistent naming convention for its system
sets, both internally and across the ecosystem.

<img alt="System sets in Bevy"
src="https://github.com/user-attachments/assets/d16e2027-793f-4ba4-9cc9-e780b14a5a1b"
width="450" />

*Names of public system set types in Bevy*

Most Bevy types use a naming of `FooSystem` or just `Foo`, but there are
also a few `FooSystems` and `FooSet` types. In ecosystem crates on the
other hand, `FooSet` is perhaps the most commonly used name in general.
Conventions being so wildly inconsistent can make it harder for users to
pick names for their own types, to search for system sets on docs.rs, or
to even discern which types *are* system sets.

To reign in the inconsistency a bit and help unify the ecosystem, it
would be good to establish a common recommended naming convention for
system sets in Bevy itself, similar to how plugins are commonly suffixed
with `Plugin` (ex: `TimePlugin`). By adopting a consistent naming
convention in first-party Bevy, we can softly nudge ecosystem crates to
follow suit (for types where it makes sense to do so).

Choosing a naming convention is also relevant now, as the [`bevy_cli`
recently adopted
lints](https://github.com/TheBevyFlock/bevy_cli/pull/345) to enforce
naming for plugins and system sets, and the recommended naming used for
system sets is still a bit open.

## Which Name To Use?

Now the contentious part: what naming convention should we actually
adopt?

This was discussed on the Bevy Discord at the end of last year, starting
[here](<https://discord.com/channels/691052431525675048/692572690833473578/1310659954683936789>).
`FooSet` and `FooSystems` were the clear favorites, with `FooSet` very
narrowly winning an unofficial poll. However, it seems to me like the
consensus was broadly moving towards `FooSystems` at the end and after
the poll, with Cart
([source](https://discord.com/channels/691052431525675048/692572690833473578/1311140204974706708))
and later Alice
([source](https://discord.com/channels/691052431525675048/692572690833473578/1311092530732859533))
and also me being in favor of it.

Let's do a quick pros and cons list! Of course these are just what I
thought of, so take it with a grain of salt.

`FooSet`:

- Pro: Nice and short!
- Pro: Used by many ecosystem crates.
- Pro: The `Set` suffix comes directly from the trait name `SystemSet`.
- Pro: Pairs nicely with existing APIs like `in_set` and
`configure_sets`.
- Con: `Set` by itself doesn't actually indicate that it's related to
systems *at all*, apart from the implemented trait. A set of what?
- Con: Is `FooSet` a set of `Foo`s or a system set related to `Foo`? Ex:
`ContactSet`, `MeshSet`, `EnemySet`...

`FooSystems`:

- Pro: Very clearly indicates that the type represents a collection of
systems. The actual core concept, system(s), is in the name.
- Pro: Parallels nicely with `FooPlugins` for plugin groups.
- Pro: Low risk of conflicts with other names or misunderstandings about
what the type is.
- Pro: In most cases, reads *very* nicely and clearly. Ex:
`PhysicsSystems` and `AnimationSystems` as opposed to `PhysicsSet` and
`AnimationSet`.
- Pro: Easy to search for on docs.rs.
- Con: Usually results in longer names.
- Con: Not yet as widely used.

Really the big problem with `FooSet` is that it doesn't actually
describe what it is. It describes what *kind of thing* it is (a set of
something), but not *what it is a set of*, unless you know the type or
check its docs or implemented traits. `FooSystems` on the other hand is
much more self-descriptive in this regard, at the cost of being a bit
longer to type.

Ultimately, in some ways it comes down to preference and how you think
of system sets. Personally, I was originally in favor of `FooSet`, but
have been increasingly on the side of `FooSystems`, especially after
seeing what the new names would actually look like in Avian and now
Bevy. I prefer it because it usually reads better, is much more clearly
related to groups of systems than `FooSet`, and overall *feels* more
correct and natural to me in the long term.

For these reasons, and because Alice and Cart also seemed to share a
preference for it when it was previously being discussed, I propose that
we adopt a `FooSystems` naming convention where applicable.

## Solution

Rename Bevy's system set types to use a consistent `FooSet` naming where
applicable.

- `AccessibilitySystem` → `AccessibilitySystems`
- `GizmoRenderSystem` → `GizmoRenderSystems`
- `PickSet` → `PickingSystems`
- `RunFixedMainLoopSystem` → `RunFixedMainLoopSystems`
- `TransformSystem` → `TransformSystems`
- `RemoteSet` → `RemoteSystems`
- `RenderSet` → `RenderSystems`
- `SpriteSystem` → `SpriteSystems`
- `StateTransitionSteps` → `StateTransitionSystems`
- `RenderUiSystem` → `RenderUiSystems`
- `UiSystem` → `UiSystems`
- `Animation` → `AnimationSystems`
- `AssetEvents` → `AssetEventSystems`
- `TrackAssets` → `AssetTrackingSystems`
- `UpdateGizmoMeshes` → `GizmoMeshSystems`
- `InputSystem` → `InputSystems`
- `InputFocusSet` → `InputFocusSystems`
- `ExtractMaterialsSet` → `MaterialExtractionSystems`
- `ExtractMeshesSet` → `MeshExtractionSystems`
- `RumbleSystem` → `RumbleSystems`
- `CameraUpdateSystem` → `CameraUpdateSystems`
- `ExtractAssetsSet` → `AssetExtractionSystems`
- `Update2dText` → `Text2dUpdateSystems`
- `TimeSystem` → `TimeSystems`
- `AudioPlaySet` → `AudioPlaybackSystems`
- `SendEvents` → `EventSenderSystems`
- `EventUpdates` → `EventUpdateSystems`

A lot of the names got slightly longer, but they are also a lot more
consistent, and in my opinion the majority of them read much better. For
a few of the names I took the liberty of rewording things a bit;
definitely open to any further naming improvements.

There are still also cases where the `FooSystems` naming doesn't really
make sense, and those I left alone. This primarily includes system sets
like `Interned<dyn SystemSet>`, `EnterSchedules<S>`, `ExitSchedules<S>`,
or `TransitionSchedules<S>`, where the type has some special purpose and
semantics.

## Todo

- [x] Should I keep all the old names as deprecated type aliases? I can
do this, but to avoid wasting work I'd prefer to first reach consensus
on whether these renames are even desired.
- [x] Migration guide
- [x] Release notes
2025-05-06 15:18:03 +00:00
Carter Anderson e9a0ef49f9 Rename bevy_platform_support to bevy_platform (#18813)
# Objective

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

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

## Solution

- Rename `bevy_platform_support` to `bevy_platform`.
2025-04-11 23:13:28 +00:00
Hennadii Chernyshchyk d82c359a5a Add Default for all schedule labels (#18731)
# Objective

In `bevy_enhanced_input`, I'm trying to associate `Actions` with a
schedule. I can do this via an associated type on a trait, but there's
no way to construct the associated label except by requiring a `Default`
implementation. However, Bevy labels don't implement `Default`.

## Solution

Add `Default` to all built-in labels. I think it should be useful in
general.
2025-04-06 16:44:33 +00:00
BD103 746b593833 Fix indentation of bevy/query strict parameter in docs (#18681)
# Objective

- The `strict` field of
[`BrpQueryParams`](https://dev-docs.bevyengine.org/bevy/remote/builtin_methods/struct.BrpQueryParams.html)
was newly added as part of 0.16.
- Its documentation in `lib.rs` improperly indents `strict`, making look
like its part of
[`BrpQueryFilter`](https://dev-docs.bevyengine.org/bevy/remote/builtin_methods/struct.BrpQueryFilter.html):


![image](https://github.com/user-attachments/assets/f49521da-36d3-4d5d-a7ea-f7a44ddaf195)

## Solution

- Fix `strict`'s indentation so its clear that it is a field of
`BrpQueryParams`, not `BrpQueryFilter`.

I would like this to be included in 0.16, since it's a trivial
documentation change that fixes an error, but if it needs to be removed
from the milestone that's fine.

## Testing

Run `cargo doc -p bevy_remote --no-deps` and verify the indentation is
fixed. :)
2025-04-02 17:33:02 +00:00
François Mockers 031f67ebb6 fix error and lints when building for wasm32 (#18500)
# Objective

- Some crates don't compile or have clippy warnings when building for
wasm32

## Solution

- bevy_asset: unused lifetime
- bevy_gltf: the error is not too large in wasm32
- bevy_remote: fails to compile as feature http is also gated on wasm32
- bevy_winit: unused import `error`
2025-03-23 22:06:28 +00:00
Zachary Harrold 4127ac1662 Properly gate functionality on http in bevy_remote (#18478)
# Objective

Noticed that `bevy_remote` fails to compile without default features.

## Solution

Adjusted offending method to avoid reliance on `http` module when it is
disabled.

## Testing

- CI
- `cargo clippy -p bevy_remote --no-default-features`
2025-03-22 11:26:36 +00:00
andristarr 2b21b6cc13 FilteredResource returns a Result instead of a simple Option (#18265)
# Objective
FilteredResource::get should return a Result instead of Option

Fixes #17480 

---

## Migration Guide

Users will need to handle the different return type on
FilteredResource::get, FilteredResource::get_id,
FilteredResource::get_mut as it is now a Result not an Option.
2025-03-17 18:54:13 +00:00
MevLyshkin 8f38ea352e RPC Discover endpoint with basic informations (#18068)
# Objective

It does not resolves issue for full support for OpenRPC for
`bevy_remote`, but it is a first step in that direction. Connected to
the #16744 issue.

## Solution

- Adds `rpc.discover` endpoint to the bevy_remote which follows
https://spec.open-rpc.org/#openrpc-document For now in methods array
only the name, which is the endpoint address is populated.
- Moves json_schema structs into new module inside `bevy_remote`. 

## Testing

Tested the commands by running the BRP sample( cargo run --example
server --features="bevy_remote") and with these curl command:

```sh
curl -X POST -d '{ "jsonrpc": "2.0", "id": 1, "method": "rpc.discover"}' 127.0.0.1:15702 | jq .
```
The output is: 
```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "info": {
      "title": "Bevy Remote Protocol",
      "version": "0.16.0-dev"
    },
    "methods": [
      {
        "name": "bevy/mutate_component",
        "params": []
      },
      {
        "name": "bevy/insert",
        "params": []
      },
      {
        "name": "bevy/get",
        "params": []
      },
      {
        "name": "bevy/spawn",
        "params": []
      },
      {
        "name": "bevy/get+watch",
        "params": []
      },
      {
        "name": "bevy/destroy",
        "params": []
      },
      {
        "name": "bevy/list",
        "params": []
      },
      {
        "name": "bevy/mutate_resource",
        "params": []
      },
      {
        "name": "bevy/reparent",
        "params": []
      },
      {
        "name": "bevy/registry/schema",
        "params": []
      },
      {
        "name": "bevy/get_resource",
        "params": []
      },
      {
        "name": "bevy/query",
        "params": []
      },
      {
        "name": "bevy/remove_resource",
        "params": []
      },
      {
        "name": "rpc.discover",
        "params": []
      },
      {
        "name": "bevy/insert_resource",
        "params": []
      },
      {
        "name": "bevy/list_resources",
        "params": []
      },
      {
        "name": "bevy/remove",
        "params": []
      },
      {
        "name": "bevy/list+watch",
        "params": []
      }
    ],
    "openrpc": "1.3.2",
    "servers": [
      {
        "name": "Server",
        "url": "127.0.0.1:15702"
      }
    ]
  }
}
```

---------

Co-authored-by: Viktor Gustavsson <villor94@gmail.com>
2025-03-12 23:32:06 +00:00