-
-
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
Add a set_parent
method to ChildBuilder
#5845
Conversation
This allows removing a few `unsafe` in child_builder.
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.
I'm not familiar enough with ECS to be sure the change is good, though I like the idea and it's certainly useful. Some remarks though on the documenting comments themselves that could be improved I think. Thanks!
/// This is a safe alternative to [`EntityMut::world_mut`]. | ||
/// | ||
/// If you _know_ that `use_world` doesn't change the current entity's location, | ||
/// then `self.update_location` is extaneous and it might be more efficient to use |
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.
/// then `self.update_location` is extaneous and it might be more efficient to use | |
/// then `self.update_location` is extraneous and it might be more efficient to use |
@@ -508,6 +508,19 @@ impl<'w> EntityMut<'w> { | |||
self.world | |||
} | |||
|
|||
/// Access the inner `&mut World` within `use_world` and run [`Self::update_location`]. |
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.
I've read the entire comment for this method but I have no idea what it means. This sounds like a fairly advanced usage. I don't know what use_world()
does, nor update_location()
. Can we try to give a little bit more detail, and maybe give an example of when this method is useful?
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.
use_world
is the function parameter. update_location
is linked in the doc, because it is surrounded in [], if someone is reading the documentation and doesn't know what update_location
is, they should be able to click on the link and read the update_location
documentation.
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.
/// Access the inner `&mut World` within `use_world` and run [`Self::update_location`]. | |
/// Access the inner `&mut World` within the `use_world` function argument and run [`Self::update_location`]. |
@@ -166,7 +166,8 @@ impl Command for PushChildren { | |||
} | |||
} | |||
|
|||
/// Command that removes children from an entity, and removes that child's parent and inserts it into the previous parent component | |||
/// Command that removes children from an entity, | |||
/// and removes that child's parent and inserts it into the previous parent component |
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.
I don't understand that second part. First, the use of singular on child
is confusing since the first part of the sentence uses the plural children
, though I assume we're talking here about the removed children? Then, we don't "remove the parent", we actually remove the Parent
component from the Entity
, don't we? And then I still don't understand the last bit about inserting into the previous parent component. Sorry I know the original comment was the same before your change, but if you could clean it up while you're touching it that'd be beneficial I think. Thanks!
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.
It's the same comment than before, I only changed the formatting, I feel like this shouldn't be in scope of this PR, but I agree the phrasing can be improved.
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.
Yep, I'm fine to leave this alone for this PR.
/// Spawns an [`Entity`] with no components | ||
/// and inserts it into the children defined by the [`ChildBuilder`] | ||
/// which adds the [`Parent`] component to it. |
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.
Same, that comment is quite confusing to me. How about:
/// Spawns an [`Entity`] without any component, and inserts it into the collection of children
/// of the current [`ChildBuilder`]. A [`Parent`] component is automatically added to that new
/// entity.
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.
I think we can avoid bikeshedding on these doc changes here. I'm fine leaving them how they are or reverting them completely.
|
||
/// Set the parent. | ||
/// | ||
/// This overwrites the existing parent. |
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.
...I assume, for all children of the underlying collection at once?
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 idea is that
child.set_parent(parent)
// is equivalent to
parent.add_child(child)
I don't understand what you mean by "for all children of the underlying collection". Could you precise?
If you mean the Children
component of the parent
, the answer is no. set_parent
just sets the parent of an entity, so it does nothing else than:
- Add a
Parent(parent)
component to thechild
- Push
child
to theChildren
component of theparent
|
||
fn set_parent(&mut self, parent: Entity) -> &mut Self { | ||
let child = self.id(); | ||
self.commands().add(AddChild { child, parent }); |
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.
Does that really work? What if there's already the opposite AddChild
from the above add_child()
call, do we correctly overwrite? I'm a bit surprised that we don't need to do any more book-keeping here.
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.
I might add more test. But logically, if AddChild { parent, child }
works, I don't see why AddChild { child, parent }
wouldn't.
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.
I'd like to see a simple test :)
@@ -345,7 +359,9 @@ impl<'w> WorldChildBuilder<'w> { | |||
self.world.entity_mut(entity) | |||
} | |||
|
|||
/// Spawns an [`Entity`] with no components and inserts it into the children defined by the [`WorldChildBuilder`] which adds the [`Parent`] component to it. | |||
/// Spawns an [`Entity`] with no components and inserts it |
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.
Same remark as previously, comment is fairly confusing to me.
@@ -583,6 +584,7 @@ mod tests { | |||
assert_eq!(*world.get::<Parent>(child1).unwrap(), Parent(parent)); | |||
assert_eq!(*world.get::<Parent>(child2).unwrap(), Parent(parent)); | |||
|
|||
// Why are those assertions repeated? |
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.
Probably a mismerge. Can you please delete instead of adding a comment?
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.
I wasn't willing to remove those asserts before someone reviewed the PR and told me they were not here for a reason I was overlooking (this is called "Chesterton's Fence")
So I added the comment to attract the attention of reviewers and allow them to comment on the asserts.
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.
Yes absolutely, not blaming you here, that was the right call. But I think we both agree that this is useless and unlikely to have any real use? So I was just ACK'ing on the removal. Or do you want to wait for a second reviewer's opinion too? Im fine with that.
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.
We should remove the duplicate assertions.
/// then `self.update_location` is extaneous and it might be more efficient to use | ||
/// the unsafe `world_mut` method instead. | ||
#[inline] | ||
pub fn with_world_mut(&mut self, use_world: impl FnOnce(&mut World)) { |
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.
This needs a doc example to be clear enough for the average user. Cool bit of machinery though!
// Inserting a bundle in the children entities may change the parent entity's location if they were of the same archetype | ||
self.update_location(); | ||
} | ||
self.with_world_mut(|world| update_old_parents(world, parent, children)); |
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.
Really like the elimination of unsafe here.
Superseded by #6189 |
Objective
Depending on the use-case, since #4197, it can be hard
to specify a hierarchy of entities in bevy, especially when
declaring parents.
Solution
Currently, it's possible to use
parent.add_child(child)
,however, there is a few cases where this is highly inconvenient,
and would be better expressed with a
child.set_parent(parent)
operation.Changelog
set_parent
method toChildBuilder
with_world_mut
method toEntityMut
for improved safety.