Skip to content

Improved Spawn APIs and Bundle Effects #17521

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Feb 9, 2025
Merged

Improved Spawn APIs and Bundle Effects #17521

merged 12 commits into from
Feb 9, 2025

Conversation

cart
Copy link
Member

@cart cart commented Jan 24, 2025

Objective

A major critique of Bevy at the moment is how boilerplatey it is to compose (and read) entity hierarchies:

commands
    .spawn(Foo)
    .with_children(|p| {
        p.spawn(Bar).with_children(|p| {
            p.spawn(Baz);
        });
        p.spawn(Bar).with_children(|p| {
            p.spawn(Baz);
        });
    });

There is also currently no good way to statically define and return an entity hierarchy from a function. Instead, people often do this "internally" with a Commands function that returns nothing, making it impossible to spawn the hierarchy in other cases (direct World spawns, ChildSpawner, etc).

Additionally, because this style of API results in creating the hierarchy bits after the initial spawn of a bundle, it causes ECS archetype changes (and often expensive table moves).

Because children are initialized after the fact, we also can't count them to pre-allocate space. This means each time a child inserts itself, it has a high chance of overflowing the currently allocated capacity in the RelationshipTarget collection, causing literal worst-case reallocations.

We can do better!

Solution

The Bundle trait has been extended to support an optional BundleEffect. This is applied directly to World immediately after the Bundle has fully inserted. Note that this is intentionally not done via a deferred Command, which would require repeatedly copying each remaining subtree of the hierarchy to a new command as we walk down the tree (not good performance).

This allows us to implement the new SpawnRelated trait for all RelationshipTarget impls, which looks like this in practice:

world.spawn((
    Foo,
    Children::spawn((
        Spawn((
            Bar,
            Children::spawn(Spawn(Baz)),
        )),
        Spawn((
            Bar,
            Children::spawn(Spawn(Baz)),
        )),
    ))
))

Children::spawn returns SpawnRelatedBundle<Children, L: SpawnableList>, which is a Bundle that inserts Children (preallocated to the size of the SpawnableList::size_hint()). Spawn<B: Bundle>(pub B) implements SpawnableList with a size of 1. SpawnableList is also implemented for tuples of SpawnableList (same general pattern as the Bundle impl).

There are currently three built-in SpawnableList implementations:

world.spawn((
    Foo,
    Children::spawn((
        Spawn(Name::new("Child1")),   
        SpawnIter(["Child2", "Child3"].into_iter().map(Name::new),
        SpawnWith(|parent: &mut ChildSpawner| {
            parent.spawn(Name::new("Child4"));
            parent.spawn(Name::new("Child5"));
        })
    )),
))

We get the benefits of "structured init", but we have nice flexibility where it is required!

Some readers' first instinct might be to try to remove the need for the Spawn wrapper. This is impossible in the Rust type system, as a tuple of "child Bundles to be spawned" and a "tuple of Components to be added via a single Bundle" is ambiguous in the Rust type system. There are two ways to resolve that ambiguity:

  1. By adding support for variadics to the Rust type system (removing the need for nested bundles). This is out of scope for this PR :)
  2. Using wrapper types to resolve the ambiguity (this is what I did in this PR).

For the single-entity spawn cases, Children::spawn_one does also exist, which removes the need for the wrapper:

world.spawn((
    Foo,
    Children::spawn_one(Bar),
))

This works for all Relationships

This API isn't just for Children / ChildOf relationships. It works for any relationship type, and they can be mixed and matched!

world.spawn((
    Foo,
    Observers::spawn((
        Spawn(Observer::new(|trigger: Trigger<FuseLit>| {})),
        Spawn(Observer::new(|trigger: Trigger<Exploded>| {})),
    )),
    OwnerOf::spawn(Spawn(Bar))
    Children::spawn(Spawn(Baz))
))

Macros

While Spawn is necessary to satisfy the type system, we can remove the need to express it via macros. The example above can be expressed more succinctly using the new children![X] macro, which internally produces Children::spawn(Spawn(X)):

world.spawn((
    Foo,
    children![
        (
            Bar,
            children![Baz],
        ),
        (
            Bar,
            children![Baz],
        ),
    ]
))

There is also a related! macro, which is a generic version of the children! macro that supports any relationship type:

world.spawn((
    Foo,
    related!(Children[
        (
            Bar,
            related!(Children[Baz]),
        ),
        (
            Bar,
            related!(Children[Baz]),
        ),
    ])
))

Returning Hierarchies from Functions

Thanks to these changes, the following pattern is now possible:

fn button(text: &str, color: Color) -> impl Bundle {
    (
        Node {
            width: Val::Px(300.),
            height: Val::Px(100.),
            ..default()
        },
        BackgroundColor(color),
        children![
            Text::new(text),
        ]
    )
}

fn ui() -> impl Bundle {
    (
        Node {
            width: Val::Percent(100.0),
            height: Val::Percent(100.0),
            ..default(),
        },
        children![
            button("hello", BLUE),
            button("world", RED),
        ]
    )
}

// spawn from a system
fn system(mut commands: Commands) {
    commands.spawn(ui());
}

// spawn directly on World
world.spawn(ui());

Additional Changes and Notes

  • Bundle::from_components has been split out into BundleFromComponents::from_components, enabling us to implement Bundle for types that cannot be "taken" from the ECS (such as the new SpawnRelatedBundle).
  • The NoBundleEffect trait (which implements BundleEffect) is implemented for empty tuples (and tuples of empty tuples), which allows us to constrain APIs to only accept bundles that do not have effects. This is critical because the current batch spawn APIs cannot efficiently apply BundleEffects in their current form (as doing so in-place could invalidate the cached raw pointers). We could consider allocating a buffer of the effects to be applied later, but that does have performance implications that could offset the balance and value of the batched APIs (and would likely require some refactors to the underlying code). I've decided to be conservative here. We can consider relaxing that requirement on those APIs later, but that should be done in a followup imo.
  • I've ported a few examples to illustrate real-world usage. I think in a followup we should port all examples to the children! form whenever possible (and for cases that require things like SpawnIter, use the raw APIs).
  • Some may ask "why not use the Relationship to spawn (ex: ChildOf::spawn(Foo)) instead of the RelationshipTarget (ex: Children::spawn(Spawn(Foo)))?". That would allow us to remove the Spawn wrapper. I've explicitly chosen to disallow this pattern. Bundle::Effect has the ability to create significant weirdness. Things in Bundle position look like components. For example world.spawn((Foo, ChildOf::spawn(Bar))) looks and reads like Foo is a child of Bar. ChildOf is in Foo's "component position" but it is not a component on Foo. This is a huge problem. Now that Bundle::Effect exists, we should be very principled about keeping the "weird and unintuitive behavior" to a minimum. Things that read like components _should be the components they appear to be".

Remaining Work

  • The macros are currently trivially implemented using macro_rules and are currently limited to the max tuple length. They will require a proc_macro implementation to work around the tuple length limit.

Next Steps

  • Port the remaining examples to use children! where possible and raw Spawn / SpawnIter / SpawnWith where the flexibility of the raw API is required.

Migration Guide

Existing spawn patterns will continue to work as expected.

Manual Bundle implementations now require a BundleEffect associated type. Exisiting bundles would have no bundle effect, so use (). Additionally Bundle::from_components has been moved to the new BundleFromComponents trait.

// Before
unsafe impl Bundle for X {
    unsafe fn from_components<T, F>(ctx: &mut T, func: &mut F) -> Self {
    }
    /* remaining bundle impl here */
}

// After
unsafe impl Bundle for X {
    type Effect = ();
    /* remaining bundle impl here */
}

unsafe impl BundleFromComponents for X {
    unsafe fn from_components<T, F>(ctx: &mut T, func: &mut F) -> Self {
    }
}

@cart cart added A-ECS Entities, components, systems, and events C-Usability A targeted quality-of-life change that makes Bevy easier to use labels Jan 24, 2025
@cart cart added this to the 0.16 milestone Jan 24, 2025
@BenjaminBrienen BenjaminBrienen added D-Complex Quite challenging from either a design or technical perspective. Ask for help! S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Jan 24, 2025
@alice-i-cecile alice-i-cecile added the M-Needs-Release-Note Work that should be called out in the blog due to impact label Jan 24, 2025
@alice-i-cecile
Copy link
Member

We probably want to roll this up into / right after the relations release note, but I want to make sure this doesn't get missed when writing them. It's also notable enough that folks skimming the milestone + "Needs-Release-Notes" will be interested.

@alice-i-cecile alice-i-cecile self-requested a review January 24, 2025 03:13
@benfrankel
Copy link
Contributor

benfrankel commented Jan 24, 2025

IMO this is a step in the right direction, making entity spawning constructs more reusable / composable (having only read the PR description). One thing I feel will still be missing after this PR is argument passing ergonomics, since fn ui and fn button aren't systems. But I imagine that can be iterated on independent of the new API.

@alice-i-cecile
Copy link
Member

One thing I feel will still be missing after this PR is argument passing ergonomics, since fn ui and fn button aren't systems. But I imagine that can be iterated on independent of the new API.

Agreed: the key thing there is "dependency injection-flavored access to asset collections". The Construct trait (which I think is Cart's next step after this PR!) should go a long way.

}

/// The parts from [`Bundle`] that don't require statically knowing the components of the bundle.
pub trait DynamicBundle {
/// An operation on the entity that happens _after_ inserting this bundle.
type Effect: BundleEffect;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will partially break Box<dyn DynamicBundle>, since you'll need to specify an Effect associated type.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are the existing and intended use cases for this?

Copy link
Member

@alice-i-cecile alice-i-cecile left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like this. The end result is great: like a generic, flexible version of the WithChild component I hacked together, but without the terrible performance and no bizarre type-system gotchas. I prefer the non-macro API, but I don't mind the macro form, and I'm happy to standardize that in the learning material.

Implementation is solid: lots of moving parts, but I don't see any immediate way to simplify them, and the docs are exceptionally clear. Updating the rest of the example should go in follow-up.

This makes impl Bundle the blessed API for spawning entity collections, which is super exciting because it unblocks widgets over in bevy_ui. I'm a little nervous about the lack of boxed trait objects hampering our the flexibility of designs there, but the recently added default query filters + entity cloning should make an entity zoo (prefabs?) approach extremely comfortable.

@vultix
Copy link

vultix commented Jan 24, 2025

Some readers' first instinct might be to try to remove the need for the Spawn wrapper. This is impossible in the Rust type system, as a tuple of "child Bundles to be spawned" and a "tuple of Components to be added via a single Bundle" is ambiguous in the Rust type system. There are two ways to resolve that ambiguity:

  1. By adding support for variadics to the Rust type system (removing the need for nested bundles). This is out of scope for this PR :)
  2. Using wrapper types to resolve the ambiguity (this is what I did in this PR).

I think there's a third option here - breaking the concept of nested bundles into a set of new traits.

The ambiguity arises because we have the following impl:

impl<B: Bundle> Bundle for (B1, B2, ..., Bn) {}

I believe we could remove this impl, and introduce a new trait:

trait BundleList {}
impl<B: Bundle> BundleList for (B1, B2, ..., Bn) {}
impl<B: Bundle> BundleList for B {}

This allows us to use the bundles in BundleList differently depending on the context:

  • World::spawn(impl BundleList) would merge all of the bundles in the list and spawn a single entity
  • Children::spawn(impl BundleList) would spawn a separate child entity for each bundle in the list

We'll also need to adjust the definition of Bundle to be a "list of things that can be spawned on an entity"

/// An `Effect` or a `Component`, something that can be "spawned" on a given entity
///
/// Currently this will either be:
/// - a `Component`
/// - The `SpawnRelated<T>` struct, returned by `RelationshipTarget::spawn`. 
///   `SpawnRelated<T>` has an Effect that spawns the related entities
trait Spawn {}

/// A bundle is a list of `Spawn`, things that can be spawned on an entity
trait Bundle {}
impl<S: Spawn> Bundle for (S1, S2, ..., Sn) {}
impl<S: Spawn> Bundle for S {}

Finally, in cases where we want to support nested bundles, we make use of the BundleList trait:

/// World::spawn creates a new entity with all of the bundles in the BundleList
impl World {
    fn spawn(bundle: impl BundleList);
}

/// `Children::spawn` returns a type that implements `Spawn` that isn't a component, but an Effect
/// The returned `impl Spawn` has an Effect that spawns a new child entity for each Bundle in the BundleList
impl Children {
    fn spawn(entities: impl BundleList) -> impl Spawn {}
}

This set of traits should allow the following to work:

world.spawn((
    Foo,
    (Bar, Baz),
    Children::spawn((
        (Bar, Children::spawn(Baz)), 
        (Bar, Children::spawn(Baz))
    )),
    Observers::spawn((Observer1, Observer2)),
));

cart and others added 5 commits January 24, 2025 13:13
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
Co-authored-by: Emerson Coskey <emerson@coskey.dev>
github-merge-queue bot pushed a commit that referenced this pull request Mar 11, 2025
# Objective

Contributes to #18238 
Updates the `state/states` example to use the `children!` macro. Note
that this example also requires `--features bevy_dev_tools`

## Solution

Updates examples to use the Improved Spawning API merged in
#17521

## Testing

- Did you test these changes? If so, how?
- Opened the examples before and after and verified the same behavior
was observed. I did this on Ubuntu 24.04.2 LTS using `--features
wayland`.
- Are there any parts that need more testing?
- Other OS's and features can't hurt, but this is such a small change it
shouldn't be a problem.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
  - Run the examples yourself with and without these changes.
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
  - see above

---

## Showcase

n/a

## Migration Guide

n/a
github-merge-queue bot pushed a commit that referenced this pull request Mar 11, 2025
…API (#18249)

# Objective

Contributes to #18238 
Updates the `text_input` and `virtual_time` examples to use the
`children!` macro. I wanted to keep the PR small but chose to do two
examples since they both included only a single `with_children` call.

## Solution

Updates examples to use the Improved Spawning API merged in
#17521

## Testing

- Did you test these changes? If so, how?
- Opened the examples before and after and verified the same behavior
was observed. I did this on Ubuntu 24.04.2 LTS using `--features
wayland`.
- Are there any parts that need more testing?
- Other OS's and features can't hurt, but this is such a small change it
shouldn't be a problem.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
  - Run the examples yourself with and without these changes.
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
  - see above

---

## Showcase

n/a

## Migration Guide

n/a
github-merge-queue bot pushed a commit that referenced this pull request Mar 12, 2025
# Objective

Contributes to #18238 
Updates the `render_primitives` example to use the `children!` macro.  

## Solution

Updates examples to use the Improved Spawning API merged in
#17521

## Testing

- Did you test these changes? If so, how?
- Opened the examples before and after and verified the same behavior
was observed. I did this on Ubuntu 24.04.2 LTS using `--features
wayland`.
- Are there any parts that need more testing?
- Other OS's and features can't hurt, but this is such a small change it
shouldn't be a problem.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
  - Run the examples yourself with and without these changes.
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
  - see above

---

## Showcase

n/a

## Migration Guide

n/a
github-merge-queue bot pushed a commit that referenced this pull request Mar 12, 2025
# Objective

Contributes to #18238 
Updates the `SteppingPlugin` of the `breakout` example to use the
`children!` macro. Note that in order to test this usage you must use
`--features bevy_debug_stepping` and hit the back-tick key to enable
stepping mode to see the proper text spans rendered.

## Solution

Updates examples to use the Improved Spawning API merged in
#17521

## Testing

- Did you test these changes? If so, how?
- Opened the examples before and after and verified the same behavior
was observed. I did this on Ubuntu 24.04.2 LTS using `--features
wayland`.
- Are there any parts that need more testing?
- Other OS's and features can't hurt, but this is such a small change it
shouldn't be a problem.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
  - Run the examples yourself with and without these changes.
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
  - see above

---

## Showcase

n/a

## Migration Guide

n/a
github-merge-queue bot pushed a commit that referenced this pull request Mar 13, 2025
# Objective

Contributes to #18238 
Updates the `gamepad_viewer`, example to use the `children!` macro.  

## Solution

Updates examples to use the Improved Spawning API merged in
#17521

## Testing

- Did you test these changes? If so, how?
- Opened the examples before and after and verified the same behavior
was observed. I did this on Ubuntu 24.04.2 LTS using `--features
wayland`.
- Are there any parts that need more testing?
- Other OS's and features can't hurt, but this is such a small change it
shouldn't be a problem.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
  - Run the examples yourself with and without these changes.
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
  - see above

---

## Showcase

n/a

## Migration Guide

n/a
github-merge-queue bot pushed a commit that referenced this pull request Mar 13, 2025
…ro (#18292)

# Objective

Contributes to #18238 
Updates the `custom_transitions` and `sub_states` examples to use the
`children!` macro.

## Solution

Updates examples to use the Improved Spawning API merged in
#17521

## Testing

- Did you test these changes? If so, how?
- Opened the examples before and after and verified the same behavior
was observed. I did this on Ubuntu 24.04.2 LTS using `--features
wayland`.
- Are there any parts that need more testing?
- Other OS's and features can't hurt, but this is such a small change it
shouldn't be a problem.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
  - Run the examples yourself with and without these changes.
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
  - see above

---

## Showcase

n/a

## Migration Guide

n/a
github-merge-queue bot pushed a commit that referenced this pull request Mar 13, 2025
# Objective

Contributes to #18238 
Updates the `computed_states`, example to use the `children!` macro.
Note that this example requires `--features bevy_dev_tools` to run

## Solution

Updates examples to use the Improved Spawning API merged in
#17521

## Testing

- Did you test these changes? If so, how?
- Opened the examples before and after and verified the same behavior
was observed. I did this on Ubuntu 24.04.2 LTS using `--features
wayland`.
- Are there any parts that need more testing?
- Other OS's and features can't hurt, but this is such a small change it
shouldn't be a problem.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
  - Run the examples yourself with and without these changes.
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
  - see above

---

## Showcase

n/a

## Migration Guide

n/a
@aloucks
Copy link
Contributor

aloucks commented Mar 14, 2025

Please reconsider having macros in the prelude.

Bevy users are encouraged to to use the prelude for imports, which essentially makes children! global . This is a very generic name. Rust added the ability to give context to macros to avoid name collisions. Having that context creates an added bonus of making them easier to read and understand where a they come from when it's used with a crate/mod prefix. Using bevy::children! isn't that much more to type, illuminates context, and also aids in discoverability via auto complete.

As a compromise, the macros could be exported both at the bevy level as well as a separate prelude just for macros.

github-merge-queue bot pushed a commit that referenced this pull request Mar 20, 2025
…se children macro (#18318)

# Objective

Contributes to #18238 
Updates the `sprite_slice`, `spatial_audio_3d` and `spatial_audio_2d`
examples to use the `children!` macro.

## Solution

Updates examples to use the Improved Spawning API merged in
#17521

## Testing

- Did you test these changes? If so, how?
- Opened the examples before and after and verified the same behavior
was observed. I did this on Ubuntu 24.04.2 LTS using `--features
wayland`.
- Are there any parts that need more testing?
- Other OS's and features can't hurt, but this is such a small change it
shouldn't be a problem.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
  - Run the examples yourself with and without these changes.
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
  - see above

---

## Showcase

n/a

## Migration Guide

n/a
github-merge-queue bot pushed a commit that referenced this pull request Mar 21, 2025
# Objective

Contributes to #18238 
Updates the `text2d`, example to use the `children!` macro.

~~The SpawnIter usage in this example is maybe not the best. Very open
to opinions. I even left one `with_children` that I thought was just
much better than any alternative.~~

## Solution

Updates examples to use the Improved Spawning API merged in
#17521

## Testing

- Did you test these changes? If so, how?
- Opened the examples before and after and verified the same behavior
was observed. I did this on Ubuntu 24.04.2 LTS using `--features
wayland`.
- Are there any parts that need more testing?
- Other OS's and features can't hurt, but this is such a small change it
shouldn't be a problem.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
  - Run the examples yourself with and without these changes.
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
  - see above

---

## Showcase

n/a

## Migration Guide

n/a
github-merge-queue bot pushed a commit that referenced this pull request Mar 22, 2025
# Objective

Contributes to #18238 
Updates the `text2d`, example to use the `children!` macro.

I'm not sure I love the SpawnIter usage here, as I feel the `move`
keyword in this case is subtle and error prone for those who lose fights
with the borrow checker frequently (like me). Feedback very much
welcome.

## Solution

Updates examples to use the Improved Spawning API merged in
#17521

## Testing

- Did you test these changes? If so, how?
- Opened the examples before and after and verified the same behavior
was observed. I did this on Ubuntu 24.04.2 LTS using `--features
wayland`.
- Are there any parts that need more testing?
- Other OS's and features can't hurt, but this is such a small change it
shouldn't be a problem.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
  - Run the examples yourself with and without these changes.
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
  - see above

---

## Showcase

n/a

## Migration Guide

n/a
github-merge-queue bot pushed a commit that referenced this pull request Mar 22, 2025
…es to use children! macro (#18270)

# Objective

Contributes to #18238 
Updates the `shader_prepass`, `testbed_2d` and `first_person_view_model`
examples to use the `children!` macro. I wanted to keep the PR small but
chose to do 3 examples since they were all limited in scope

## Solution

Updates examples to use the Improved Spawning API merged in
#17521

## Testing

- Did you test these changes? If so, how?
- Opened the examples before and after and verified the same behavior
was observed. I did this on Ubuntu 24.04.2 LTS using `--features
wayland`.
- Are there any parts that need more testing?
- Other OS's and features can't hurt, but this is such a small change it
shouldn't be a problem.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
  - Run the examples yourself with and without these changes.
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
  - see above

---

## Showcase

n/a

## Migration Guide

n/a
mockersf pushed a commit that referenced this pull request Mar 23, 2025
…se children macro (#18318)

# Objective

Contributes to #18238 
Updates the `sprite_slice`, `spatial_audio_3d` and `spatial_audio_2d`
examples to use the `children!` macro.

## Solution

Updates examples to use the Improved Spawning API merged in
#17521

## Testing

- Did you test these changes? If so, how?
- Opened the examples before and after and verified the same behavior
was observed. I did this on Ubuntu 24.04.2 LTS using `--features
wayland`.
- Are there any parts that need more testing?
- Other OS's and features can't hurt, but this is such a small change it
shouldn't be a problem.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
  - Run the examples yourself with and without these changes.
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
  - see above

---

## Showcase

n/a

## Migration Guide

n/a
@alice-i-cecile
Copy link
Member

Thank you to everyone involved with the authoring or reviewing of this PR! This work is relatively important and needs release notes! Head over to bevyengine/bevy-website#1992 if you'd like to help out.

Shatur added a commit to projectharmonia/bevy_replicon that referenced this pull request Apr 15, 2025
Shatur added a commit to projectharmonia/bevy_replicon that referenced this pull request Apr 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ECS Entities, components, systems, and events C-Usability A targeted quality-of-life change that makes Bevy easier to use D-Complex Quite challenging from either a design or technical perspective. Ask for help! M-Needs-Release-Note Work that should be called out in the blog due to impact S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it X-Blessed Has a large architectural impact or tradeoffs, but the design has been endorsed by decision makers
Projects
None yet
Development

Successfully merging this pull request may close these issues.