bevy icon indicating copy to clipboard operation
bevy copied to clipboard

EntityRef/Mut get_components

Open cart opened this issue 1 year ago • 9 comments

Objective

Implements #13127

EntityRef / EntityMut usage is currently unnecessarily verbose and borrow-checker-constrained. It is currently impossible to use EntityMut to get mutable references to more than one component at the same time:

let mut entity = world.entity_mut(some_entity);
let mut a = entity.get_mut::<A>();
// this fails to compile because `entity` is already borrowed mutably
let mut b = entity.get_mut::<B>();

This makes EntityMut significantly less useful than it could be. Querying necessary components on demand is a pattern many prefer to use over traditional top-level queries.

Solution

Implement new get_components and components methods for EntityRef and EntityMut (and mutable variants for EntityMut) to provide multi-component access:

let (a, b) = world.entity(SOME_ENTITY).components::<(&A, &B)>();
let (a, b) = world.entity(SOME_ENTITY).get_components::<(&A, &B)>().unwrap();
let (mut a, b) = world.entity_mut(SOME_ENTITY).components_mut::<(&mut A, &B)>();
let (mut a, b) = world.entity_mut(SOME_ENTITY).get_components_mut::<(&mut A, &B)>().unwrap();

This is implemented using our existing Query implementation to provide multi-component access. It checks access without actually computing QueryState / access using the very convenient Q::matches_component_set.

Next Steps

  • This doesn't add FilteredEntityRef and FilteredEntityMut variants, as checking that access is actually more challenging (and with the current methods, likely prohibitively expensive because I think we need to compute Access<ComponentId> )
  • This doesn't do the components to get and get_components to try_get renaming / unification I proposed in #13127 as I suspect that will be more controversial, and it also touches a lot of code.

Changelog

Added

  • EntityRef::components, EntityRef::get_components, EntityMut::components, EntityMut::get_components, EntityMut::components_mut, and EntityMut::get_components_mut.

Changed

  • Renamed FilteredEntityRef::components to FilteredEntityRef::accessed_components and FilteredEntityMut::components to FilteredEntityMut::accessed_components to avoid future name clashes

Migration Guide

  • Rename FilteredEntityRef::components to FilteredEntityRef::accessed_components and FilteredEntityMut::components to FilteredEntityMut::accessed_components

cart avatar May 14 '24 23:05 cart

In light of #12660, I would vote against adding more panicking shorthands like components.

msvbg avatar May 14 '24 23:05 msvbg

In light of https://github.com/bevyengine/bevy/issues/12660, I would vote against adding more panicking shorthands like components.

I think discouraging unwrap/panicking variants entirely (as in, not providing impls) would have pretty nasty ergonomics implications for people, especially with the current Option vs Result compatibility problem for ?. I would be very uncomfortable removing those apis right now.

cart avatar May 15 '24 00:05 cart

In light of #12660, I would vote against adding more panicking shorthands like components.

I think discouraging unwrap/panicking variants entirely (as in, not providing impls) would have pretty nasty ergonomics implications for people, especially with the current Option vs Result compatibility problem for ?. I would be very uncomfortable removing those apis right now.

I agree somewhat with this. It's frustrating when something like despawn causes a panic due to an unwrap, but if I want to shoot myself in the foot with something like single or components_mut I should be allowed to.

ramirezmike avatar May 15 '24 00:05 ramirezmike

Left some replies in #12660

cart avatar May 15 '24 00:05 cart

Since this uses QueryData, this would allow doing stuff like this, right?

world.entity(e).get_components::<(Entity, &X, Option<&Y>, Has<Z>)>();

"components" sorta makes sense for Option/Has... Is Entity a component though? What if QueryData gets implemented with more Component-adjacent stuff in the future?

I'm guessing the next steps item 2 would be renaming these to the get functions in the future?

ramirezmike avatar May 15 '24 01:05 ramirezmike

I find this kind of funny. Thinking about this historically, this feels like we've inverted the relationship between Query::get_component and EntityMut/EntityRef with this change.

Haha yeah thats an interesting comparison. Although I think this is significantly more defensible / necessary than Query::get_component.

Since this uses QueryData, this would allow doing stuff like this, right?

Yup!

I'm guessing the next steps item 2 would be renaming these to the get functions in the future?

Yup that is something discussed in the Next Steps section above. Haven't thought of a better interim name. And components is approximately correct.

cart avatar May 15 '24 19:05 cart

Welp this PR is sadly stalled until we sort out this problem: https://github.com/bevyengine/bevy/pull/13375#discussion_r1602135098

Not sure there will be a solution that doesn't involve doing access checks on each call.

cart avatar May 15 '24 19:05 cart

I think the best we can hope for is "allocation free check every entry against every other entry" (similar to query.many_mut), but accomplishing that will require significant changes (or at least, additions) to how we compute access.

cart avatar May 15 '24 19:05 cart

I think we should be able to reuse the access mechanisms from queries to validate soundness here. Would need to sit down with the code to figure out exactly how. I much prefer that over creating another mechanism though, especially since I'd like to be able to add untyped variants to this in the future.

alice-i-cecile avatar May 16 '24 00:05 alice-i-cecile

Would it be possible to merge a version of this PR with just the immutable get_components variants for 0.15? Even just the immutable variants would be very useful for me.

ItsDoot avatar Sep 08 '24 00:09 ItsDoot

I agree the an immutable form would be useful still. Feel free to spin off a PR that does that please.

alice-i-cecile avatar Sep 08 '24 01:09 alice-i-cecile

Closing in favor of #15089; further attempts to implement the mutable form will be easier in a separate PR.

alice-i-cecile avatar Sep 09 '24 16:09 alice-i-cecile