-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Let Component::map_entities defer to MapEntities #19414
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
base: main
Are you sure you want to change the base?
Conversation
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 like the idea, but I found that users are quite confusing by having separate mapping method inside Component
and MapEntities
in general.
Maybe we could just require MapEntities
for Component
? I remember that the mentioned downside was more complicated manual Component
implementation, but maybe this change worth it in the end? 🤔
I don't think that would work because I don't think Perhaps the simplification could be that you add #[derive(Component)]
struct NeedsNoEntity(usize);
#[derive(Component, MapEntities)]
#[component(map_entities)]
struct AutomaticMapping(#[entities] Vec<Entity>);
// Above would work for relationships too
#[derive(Component)]
#[component(map_entities)]
struct ManualMapping(HashMap<Entity, Entity>);
impl MapEntities for ManualMapping {
// ...
} It is a little more work for the common case, but it might be less confusing than the separate implementations. Then again, it adds more boilerplate, and we're getting close to returning to |
Ah, I see the problem! I think |
I also much prefer the version with |
To be clear, by the I'm going to assume so and I'll try to update the PR tomorrow |
Doubts about
|
Makes sense! |
Objective
The objective of this PR is to enable Components to use their
MapEntities
implementation forComponent::map_entities
.With the improvements to the entity mapping system, there is definitely a huge reduction in boilerplate. However, especially since
(Entity)HashMap<..>
doesn't implementMapEntities
(I presume because the lack of specialization in rust makesHashMap<Entity|X, Entity|X>
complicated), when somebody has types that contain these hashmaps they can't use this approach.More so, we can't even depend on the previous implementation, since
Component::map_entities
is used instead ofMapEntities::map_entities
. Outside of implementingComponent
andComponent::map_entities
on these types directly, the only path forward is to create a custom type to wrap the hashmaps and implement map entities on that, or split these components into a wrapper type that implementComponent
, and an inner type that implementsMapEntities
.Solution
The solution was to allow adding
#[component(entities)]
on the component itself to defer to theMapEntities
implementationTesting
I tested this by patching my local changes into my own bevy project. I had a system that loads a scene file and executes some logic with a Component that contains a
HashMap<Entity, UVec2>
, and it panics when Entity is not found from another query. Since the 0.16 update this system has reliably panicked upon attempting to the load the scene.After patching my code in, I added
#[component(entities)]
to this component, and I was able to successfully load the scene.Additionally, I wrote a doc test.
Call-outs
Relationships
This overrules the default mapping of relationship fields. Anything else seemed more problematic, as you'd have inconsistent behavior between
MapEntities
andComponent
.API bikeshedding
I initially set out to make it so you could just add
#[entities]
to the type directly, which seemed to the most logical way to express this. However, all component derive attributes are nested in#[component(..)]
, I assume to prevent collisions, so I followed this for this attribute as well. I'm open to other ideas for attribute name though, or just using#[entities]
instead.