-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
Replaced EntityCommand
Implementation for FnOnce
#9604
Replaced EntityCommand
Implementation for FnOnce
#9604
Conversation
Round three! I definitely like this as a final solution best of all :) |
Fingers crossed! 😂 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The unsafe method world_mut can be used to gain access to the World from an EntityMut if a more reasonable refactor is not possible:
We should encourage people to use into_world_mut
or world_scope
instead. Otherwise, LGTM.
Didn't know about that method! I've updated the Migration Guide for this PR to reflect the better alternative. |
# Objective Fix #4278 Fix #5504 Fix #9422 Provide safe ways to borrow an entire entity, while allowing disjoint mutable access. `EntityRef` and `EntityMut` are not suitable for this, since they provide access to the entire world -- they are just helper types for working with `&World`/`&mut World`. This has potential uses for reflection and serialization ## Solution Remove `EntityRef::world`, which allows it to soundly be used within queries. `EntityMut` no longer supports structural world mutations, which allows multiple instances of it to exist for different entities at once. Structural world mutations are performed using the new type `EntityWorldMut`. ```rust fn disjoint_system( q2: Query<&mut A>, q1: Query<EntityMut, Without<A>>, ) { ... } let [entity1, entity2] = world.many_entities_mut([id1, id2]); *entity1.get_mut::<T>().unwrap() = *entity2.get().unwrap(); for entity in world.iter_entities_mut() { ... } ``` --- ## Changelog - Removed `EntityRef::world`, to fix a soundness issue with queries. + Removed the ability to structurally mutate the world using `EntityMut`, which allows it to be used in queries. + Added `EntityWorldMut`, which is used to perform structural mutations that are no longer allowed using `EntityMut`. ## Migration Guide **Note for maintainers: ensure that the guide for #9604 is updated accordingly.** Removed the method `EntityRef::world`, to fix a soundness issue with queries. If you need access to `&World` while using an `EntityRef`, consider passing the world as a separate parameter. `EntityMut` can no longer perform 'structural' world mutations, such as adding or removing components, or despawning the entity. Additionally, `EntityMut::world`, `EntityMut::world_mut` , and `EntityMut::world_scope` have been removed. Instead, use the newly-added type `EntityWorldMut`, which is a helper type for working with `&mut World`. --------- Co-authored-by: Alice Cecile <[email protected]>
# Objective - Fixes bevyengine#4917 - Replaces bevyengine#9602 ## Solution - Replaced `EntityCommand` implementation for `FnOnce` to apply to `FnOnce(EntityMut)` instead of `FnOnce(Entity, &mut World)` --- ## Changelog - `FnOnce(Entity, &mut World)` no longer implements `EntityCommand`. This is a breaking change. ## Migration Guide ### 1. New-Type `FnOnce` Create an `EntityCommand` type which implements the method you previously wrote: ```rust pub struct ClassicEntityCommand<F>(pub F); impl<F> EntityCommand for ClassicEntityCommand<F> where F: FnOnce(Entity, &mut World) + Send + 'static, { fn apply(self, id: Entity, world: &mut World) { (self.0)(id, world); } } commands.add(ClassicEntityCommand(|id: Entity, world: &mut World| { /* ... */ })); ``` ### 2. Extract `(Entity, &mut World)` from `EntityMut` The method `into_world_mut` can be used to gain access to the `World` from an `EntityMut`. ```rust let old = |id: Entity, world: &mut World| { /* ... */ }; let new = |mut entity: EntityMut| { let id = entity.id(); let world = entity.into_world_mut(); /* ... */ }; ```
…ght be despawned (#11107) # Objective In #9604 we removed the ability to define an `EntityCommand` as `fn(Entity, &mut World)`. However I have since realized that `fn(Entity, &mut World)` is an incredibly expressive and powerful way to define a command for an entity that may or may not exist (`fn(EntityWorldMut)` only works on entities that are alive). ## Solution Support `EntityCommand`s in the style of `fn(Entity, &mut World)`, as well as `fn(EntityWorldMut)`. Use a marker generic on the `EntityCommand` trait to allow multiple impls. The second commit in this PR replaces all of the internal command definitions with ones using `fn` definitions. This is mostly just to show off how expressive this style of command is -- we can revert this commit if we'd rather avoid breaking changes. --- ## Changelog Re-added support for expressively defining an `EntityCommand` as a function that takes `Entity, &mut World`. ## Migration Guide All `Command` types in `bevy_ecs`, such as `Spawn`, `SpawnBatch`, `Insert`, etc., have been made private. Use the equivalent methods on `Commands` or `EntityCommands` instead.
# Objective - Fixes bevyengine#4917 - Replaces bevyengine#9602 ## Solution - Replaced `EntityCommand` implementation for `FnOnce` to apply to `FnOnce(EntityMut)` instead of `FnOnce(Entity, &mut World)` --- ## Changelog - `FnOnce(Entity, &mut World)` no longer implements `EntityCommand`. This is a breaking change. ## Migration Guide ### 1. New-Type `FnOnce` Create an `EntityCommand` type which implements the method you previously wrote: ```rust pub struct ClassicEntityCommand<F>(pub F); impl<F> EntityCommand for ClassicEntityCommand<F> where F: FnOnce(Entity, &mut World) + Send + 'static, { fn apply(self, id: Entity, world: &mut World) { (self.0)(id, world); } } commands.add(ClassicEntityCommand(|id: Entity, world: &mut World| { /* ... */ })); ``` ### 2. Extract `(Entity, &mut World)` from `EntityMut` The method `into_world_mut` can be used to gain access to the `World` from an `EntityMut`. ```rust let old = |id: Entity, world: &mut World| { /* ... */ }; let new = |mut entity: EntityMut| { let id = entity.id(); let world = entity.into_world_mut(); /* ... */ }; ```
# Objective Fix bevyengine#4278 Fix bevyengine#5504 Fix bevyengine#9422 Provide safe ways to borrow an entire entity, while allowing disjoint mutable access. `EntityRef` and `EntityMut` are not suitable for this, since they provide access to the entire world -- they are just helper types for working with `&World`/`&mut World`. This has potential uses for reflection and serialization ## Solution Remove `EntityRef::world`, which allows it to soundly be used within queries. `EntityMut` no longer supports structural world mutations, which allows multiple instances of it to exist for different entities at once. Structural world mutations are performed using the new type `EntityWorldMut`. ```rust fn disjoint_system( q2: Query<&mut A>, q1: Query<EntityMut, Without<A>>, ) { ... } let [entity1, entity2] = world.many_entities_mut([id1, id2]); *entity1.get_mut::<T>().unwrap() = *entity2.get().unwrap(); for entity in world.iter_entities_mut() { ... } ``` --- ## Changelog - Removed `EntityRef::world`, to fix a soundness issue with queries. + Removed the ability to structurally mutate the world using `EntityMut`, which allows it to be used in queries. + Added `EntityWorldMut`, which is used to perform structural mutations that are no longer allowed using `EntityMut`. ## Migration Guide **Note for maintainers: ensure that the guide for bevyengine#9604 is updated accordingly.** Removed the method `EntityRef::world`, to fix a soundness issue with queries. If you need access to `&World` while using an `EntityRef`, consider passing the world as a separate parameter. `EntityMut` can no longer perform 'structural' world mutations, such as adding or removing components, or despawning the entity. Additionally, `EntityMut::world`, `EntityMut::world_mut` , and `EntityMut::world_scope` have been removed. Instead, use the newly-added type `EntityWorldMut`, which is a helper type for working with `&mut World`. --------- Co-authored-by: Alice Cecile <[email protected]>
Objective
Solution
EntityCommand
implementation forFnOnce
to apply toFnOnce(EntityMut)
instead ofFnOnce(Entity, &mut World)
Changelog
FnOnce(Entity, &mut World)
no longer implementsEntityCommand
. This is a breaking change.Migration Guide
1. New-Type
FnOnce
Create an
EntityCommand
type which implements the method you previously wrote:2. Extract
(Entity, &mut World)
fromEntityMut
The method
into_world_mut
can be used to gain access to theWorld
from anEntityMut
.