-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
Proof of Concept for Required Components: Require<T>
#8557
Conversation
I prefer #5121: I don't think that these should be defined at compile time (and there's quite a few critical relationships that can't be expressed here). If these are compile time only it becomes very dangerous for library authors to set them. |
I'd love some counter examples for why having this check be at compile time is bad. Is it possible that we need both dynamic and compile time invariants...? |
Hmm, because this is tied to bundles specifically I think that moving it to compile time is basically okay. The concerns around compile time archetype invariants are:
More concerns though:
Overall I still feel that we should review and finalize the old PR (which is effectively complete) rather than having two very similar features, one of which is substantially more limited. |
Regarding your concerns:
Agreed. I don't see a way around this unless we keep something in memory to keep track of removed components, and then that just gets messy. Personally, I'm ok with ignoring this on the basis of "we're all (mostly) adults here" 😉 , but I get why others may disagree.
Again, to me, this is a feature, not a downside. 😁 I want to say "All entities with this bundle must have component X.", period. This gives me a full guarantee that no entity can spawn without my required component. An example of this which motivated me to make this is I have several systems which all require their entities to have This is why I think we may benefit from having "Required Components" be a separate feature for more low level control, and reserve archetype invariants for higher level entity composition. i.e. Dynamic vs. Static requirements. Regardless, if the other CL is near completion, I'll hold off working on this to see how that pans out. I'd like to keep this PR open for the time being though, if that's ok. |
Yep, feel free to keep this open and let's see what others think! |
#[bundle(require)]
ImplementationRequire<T>
Closing in favor of #14791 🎉 |
Objective
An attempt to fix #7272
This is a proposal for a way to express bundle requirements using a bit of macro help.
Solution
My solution is to leverage the existing
derive_bundle
macro to provide a set of required component IDs for everyBundle
.Currently, the syntax looks like this:
Require<T>
is simply aPhantomData<T>
which has a custom implementation ofBundle
.It is not inserted as a component. Instead, it is used to populate a list of
ComponentId
which is checked duringBundleInfo
construction:This allows us to enforce
Bundle
dependencies by panicking.There is currently a few issues I'm trying to resolve:
#[bundle(require)]
. If we can parse the type name containingRequire<*>
, I think we can make it less verbose.#[allow(unused)]
.Require
is likePhantomData
, but not. It should be unused, but rust doesn't know that, which causes warnings in user code. I'm open to ideas here.I've included two tests with the initial implementation which demonstrates complete usage.
Please note, Currently this PR is just a draft. I'm still new to internals of Bevy, and I'm interested in dialogue with more experienced developers. If there is any way to simplify things further, or if there are any edge cases I'm missing, I'm open to any and all feedback.
Personally, I think this is a major feature missing from Bevy, since it's impossible for bundles to overlap. This means if two bundles depend on a component existing on an entity, there is simply no way to enforce or express that prior to runtime. This is what motivated me to open this PR.
Changelog
Added
Require<T>
type to specify a required component within a bundleBundleFieldKind::Require
to support#[bundle(require)]
Bundle::requires()
which does nothing on all internalBundle
implementations except forRequire<T>
.bundle_with_missing_require
andbundle_with_require
Changed
derive_bundle
to implementrequires()
for deriving BundlesBundleInfo::new
to check for missing required components