Implement WorldQuery for EntityRef#6960
Conversation
joseph-gio
left a comment
There was a problem hiding this comment.
The WorldQuery impl looks right to me, and I don't see any real issues. Just a few things that could be added.
I imagine this will be very useful in niche situations.
| !access.access().has_any_write(), | ||
| "EntityRef conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.", | ||
| ); | ||
| access.read_all(); |
There was a problem hiding this comment.
Does a Query<EntityRef> conflict with Res<Foo> with a read_all?
There was a problem hiding this comment.
No, but a ResMut<T> would conflict under this access model. We could split this between "read all components" and "reads all resources" but I'm not sure how that would interact with the bitsets. Happy to try to do this in this PR, or defer it until later.
There was a problem hiding this comment.
I'd prefer to split that out (and I do think that should be done): that sort of work needs careful review.
There was a problem hiding this comment.
Should I address this as a part of this PR or should I leave this for later?
There was a problem hiding this comment.
Leave it until later please.
| access: &mut Access<ArchetypeComponentId>, | ||
| ) { | ||
| for component_id in archetype.components() { | ||
| access.add_read(archetype.get_archetype_component_id(component_id).unwrap()); |
There was a problem hiding this comment.
This means that you can have a system with Query<(EntityRef, &A)> that is fine, until you do commands.entity(entity).insert(A), right? Can we have a test for that?
There was a problem hiding this comment.
That's probably still fine since it only mutates the command queue and not the entity directly.
There was a problem hiding this comment.
Yeah I didn't expect it to be unsound, just something to keep in mind where a system may panic depending on the entities and components in the world.
Like how (a: Query<(&mut A, &C)>, b: Query<(&mut A, &B)>) used to only conflict as soon as a (A, B, C) entity is spawned. https://bevyengine.org/news/bevy-0-5/#query-conflicts-use-componentid-instead-of-archetypecomponentid
Co-authored-by: Jakob Hellermann <jakob.hellermann@protonmail.com>
|
@james7132 I'm happy with this work and glad to see more steps towards runtime component access coming together! Once you've resolved conflicts feel free to merge <3 |
cart
left a comment
There was a problem hiding this comment.
This looks good to me!
I've resolved conflicts (and adjusted to the UnsafeWorldCell changes)
Objective
Partially address #5504. Fix #4278. Provide "whole entity" access in queries. This can be useful when you don't know at compile time what you're accessing (i.e. reflection via
ReflectComponent).Solution
Implement
WorldQueryforEntityRef.EntityRefcan normally do.EntityRefto the ECS prelude.To make this safe,
EntityRef::worldwas removed as it gave potentialUnsafeCell-like access to other parts of theWorldincluding aliased mutable access to the components it would otherwise read safely.Performance
Not great beyond the additional parallelization opportunity over exclusive systems. The
EntityRefis fetched fromEntitieslike any other call toWorld::entity, which can be very random access heavy. This could be simplified ifArchetypeRowis available inWorldQuery::fetch's arguments, but that's likely not something we should optimize for.Future work
An equivalent API where it gives mutable access to all components on a entity can be done with a scoped version of
EntityMutwhere it does not provide&mut Worldaccess nor allow for structural changes to the entity is feasible as well. This could be done as a safe alternative to exclusive system when structural mutation isn't required or the target set of entities is scoped.Changelog
Added:
Access::has_any_writeAdded:
EntityRefnow implementsWorldQuery. Allows read-only access to the entire entity, incompatible with any other mutable access, can be mixed withWith/Withoutfilters for more targeted use.Added:
EntityReftobevy::ecs::prelude.Removed:
EntityRef::worldMigration Guide
EntityRef::worldhas been removed to makeEntityRefsound to use as a query result. If you were retrievingEntityRefviaWorld::entityorWorld::get_entity. Save a copy of the reference to theWorldbefore callingWorld::entity.