-
Notifications
You must be signed in to change notification settings - Fork 66
Dynamic Queries #37
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
Dynamic Queries #37
Conversation
|
||
A static query returns the various components it has retrieved in a tuple. This isn't an option for a Dynamic Query | ||
however, since the number of components being returned isn't known at compile time. Instead, a Dynamic Query returns | ||
a `DynamicQueryEntity` struct, which is both indexable and iterable to access the individual `DynamicItem`s 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.
Allowing indexing and iteration over query items to static queries might be a nice bit of API consistency. I've seen users ask for an alternative to tuple unpacking before in favor of a more "named" API.
Using static typing, you would perform a query like this: | ||
|
||
```rust | ||
let query_state = world.query::<(Entity, &Velocity, &mut Position, Option<&Layer>), Without<Frozen>>(); |
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 would really like to see this used in a standard system context as well; I think the ergonomics of it matter too. If it's not possible, explain why in this section.
} | ||
``` | ||
The two inner types, `DynamicComponentReference` and `DynamicMutComponentReference` provide safe access to | ||
`&`/`&mut` and change tracking functionality while also enabling users to have access to the underlying pointer for |
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.
Presumably the underlying pointer API will have to be extremely unsafe?
result[2].unwrap_mut_component().downcast_mut::<Position>().unwrap() += result[1].unwrap_component().downcast_mut::<Velocity>.unwrap(); | ||
} | ||
``` | ||
|
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.
IMO this really needs to show a more representative use case after the existing "basic usage" example.
Right now, all of the functionality demonstrated is simply less safe and slower than the existing tools :p
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 agree. I'd like to see something like a function that lists all the values of an arbitrary component given a String component name, (which could actually be useful for debugging.)
Could DynamicQuery
be serializable? This would make it possible to send queries from another process or machine.`
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.
@HackerFoo I feel that a built in serialization method may be overly prescriptive. It would be convenient, but for use cases such as scripting interfaces it makes more sense for the plugin implementation to determine the best method of communicating the query across the interop boundary.
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 doesn't need to be implemented, but it would be useful if it was designed to make that possible. Just using #[derive(Serialize, Deserialize)]
from serde
should be enough, though, which can then be serialized in any way that works with serde
.
is inferior to the static interface in all but a very specific subset of cases. While this is a concern, it isn't | ||
one which will have much of an impact as long as documentation guides users towards the standard static queries, and | ||
makes it clear that the primary audience of dynamic queries is plugin authors. The interface has been designed with | ||
ergonomic builders, but it's unlikely that the intended consumers of the dynamic query API will ever user it in this |
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.
ergonomic builders, but it's unlikely that the intended consumers of the dynamic query API will ever user it in this | |
ergonomic builders, but it's unlikely that the intended consumers of the dynamic query API will ever use it in this |
- Should dynamic queries be hidden behind a feature? | ||
- Which traits should the `DynamicItem`/`DynamicItemSet` types implemented for maximum convenience? | ||
- Do we even want maximum convenience? | ||
|
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.
How do modding / scripting use cases access resources?
These questions remain unresolved: | ||
- How much of the type's information should the `DynamicComponentReference` types carry with them (Layout?)? | ||
- How can change tracking information be captured in dynamic queries? | ||
- Should dynamic queries be hidden behind a feature? |
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.
Given that many of the other bits of special-case functionality (e.g. audio), I think it should be reasonable to do so.
If it is, this should not be a default feature. Ideally it's named in such a way that we can easily add other related bits of functionality to the same feature flag.
This would help reduce compile times slightly (I think), but more importantly, make it much more challenging for beginners to accidentally stumble across.
Dynamic queries lay the groundwork for future expansion of the ECS to fully support runtime behaviour changes. | ||
Plugins could dynamically define systems at runtime based on configuration files or scripts, since they now have the | ||
tools to interact with the Entity Component System freely. This addition of this single RFC would still leave Bevy a | ||
long way from full dynamic support though. Future RFCs should set up implementations for inserting new systems and |
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.
Link to bevyengine/bevy#2507
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.
Hey there! Thanks for pinging me on this @alice-i-cecile. :)
Unfortunately I don't have time to do a great review of this, but it looks like the right direction as far as I can tell roughly.
Also, as far as implementation goes, the bevy internals have changed so much I don't know anything much about them anymore. :)
Anyway, that's what I've got for what it's worth, but thanks for working on scripting support @GarettCooper!
I thought of a potential use for dynamic queries. I model relations as entities having a component that implements a Relation trait. The entities referred to in each Relation component have an index to all Relation entities to which they belong. When despawning an entity belonging to a Relation, it would be nice to remove it from the relation, but that's difficult, because it can belong to multiple different component types, so I'd need to query every type that implements Relation. Ideally, I could store the list of types in each index, and automatically query each type. There may be better ways to implement relations, but this is one potential use case for dynamic queries - implementing general cleanup systems. |
What's happened? |
I haven't had the time to pursue this and it seems like there community has been happy to move on without it with a lot of great work being done in the dynamic/reflection space. I figured this was just adding noise to the open RFCs list and was better off closed. |
If anybody is looking for dynamic query support, there is now the work-in-progress, but very promising, It's all a little work-in-progress and under development, but so far it looks like it's going to turn out great. |
RENDERED
Expands the query interface of
World
to support queries with parameters which are determined at runtime, not compile time, to enable future scripting and hot reloading.I wrote this RFC as a way of learning how Bevy's ECS worked, so I had to implement most of it to make sure what I was proposing was possible. You can find my branch here.