-
-
Notifications
You must be signed in to change notification settings - Fork 4k
EntityCloner
allow/deny by BundleId
and allow_if_new
#19632
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
EntityCloner
allow/deny by BundleId
and allow_if_new
#19632
Conversation
Would appreciate a review from you @eugineerd :) |
fn filter_allow_if_new(&mut self, id: ComponentId) { | ||
if self.entity_cloner.filter_allows_components { | ||
self.entity_cloner.filter_if_new.insert(id); | ||
} else { | ||
self.entity_cloner.filter_if_new.remove(&id); | ||
} | ||
if self.attach_required_components { | ||
if let Some(info) = self.world.components().get_info(id) { | ||
for required_id in info.required_components().iter_ids() { | ||
if self.entity_cloner.filter_allows_components { | ||
self.entity_cloner.filter_if_new.insert(required_id); | ||
} else { | ||
self.entity_cloner.filter_if_new.remove(&required_id); | ||
} | ||
} | ||
} |
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 am wondering though, when id
is already contained in the target, should that also skip required_id
of this id
even if the target does not contain these? Then this solution here is not enough.
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, this should probably skip required component ids in that case. I believe that's how insert_if_new
works at least. I'm not really sure how to add this behavior correctly without introducing more performance regressions (yet another set to check in if implemented naively). Maybe it would make sense to do this using a sorted vec set that would store (ComponentId, FilterType)
or something similar, but I don't know if that will actually be more performant.
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 have a few ideas, for now this PR here is blocked on the fix I decided to do extra so it be shipped in a point release.
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.
Hm seems like this issue also arises for #19635 when considering the source archetype.
When I deny_all
and allow::<A>
where A
requires B
, then B
gets cloned even when the source entity lacks A
.
I think #19326 did not do the correct implementation for the For example see this method: fn filter_deny(&mut self, id: ComponentId) {
if self.entity_cloner.filter_allows_components {
self.entity_cloner.filter.remove(&id);
} else {
self.entity_cloner.filter.insert(id);
}
if self.attach_required_components {
if let Some(info) = self.world.components().get_info(id) {
for required_id in info.required_components().iter_ids() {
if self.entity_cloner.filter_allows_components {
self.entity_cloner.filter_required.remove(&required_id);
} else {
self.entity_cloner.filter_required.insert(required_id);
}
}
}
}
} The context is an Now let's assume the source entity has the components This test therefore fails: #[test]
fn deny_with_non_unique_required() {
#[derive(Component, Clone, PartialEq, Debug, Default)]
#[require(C(5))]
struct A;
#[derive(Component, Clone, PartialEq, Debug, Default)]
#[require(C(5))]
struct B;
#[derive(Component, Clone, PartialEq, Debug)]
struct C(u32);
let mut world = World::default();
let e = world.spawn((A, B, C(10))).id();
let e_clone = world.spawn_empty().id();
EntityCloner::build(&mut world)
.deny::<A>()
.clone_entity(e, e_clone);
assert_eq!(world.entity(e_clone).get::<A>(), None);
assert_eq!(world.entity(e_clone).get::<B>(), Some(&B));
assert_eq!(world.entity(e_clone).get::<C>(), Some(&C(10))); // fails, is C(5)
} I will fix this issue in this PR too. |
Blocked by #19635 |
Objective
I use the
EntityCloner
for my reversible crate and cache operations by storing the relevantBundleId
. If I want to generate anEntityCloner
from that I need to fetch the component ids first. (1)Also, to only clone components the target does not know yet requires me to create a new bundle from ids and the target archetype. (2)
Solution
BundleId
to the cloner directly so I added methods for that.EntityCloner
replacing required components. #19326EntityCloner
becomes aware of the target archetype and withallow_if_new
methods can itself determine which components to clone.I renamed the internal field
filter_required
tofilter_if_new
because functionally this describes the behavior of handling required components as well.It made no sense to me to also add
deny_if_new
. Who would want a component to not be cloned if it the target does not contain it?Testing
Added a new test
Showcase