-
-
Save sum-catnip/dcaf3f1fd09015336d95b2c040fa1f39 to your computer and use it in GitHub Desktop.
use bevy::{ | |
ecs::{ | |
bundle::{BundleEffect, DynamicBundle}, | |
component::{ | |
ComponentId, Components, ComponentsRegistrator, RequiredComponents, StorageType, | |
}, | |
}, | |
prelude::*, | |
ptr::OwningPtr, | |
}; | |
pub struct EffectBundleFn(Box<dyn FnOnce(&mut EntityWorldMut) + Sync + Send + 'static>); | |
impl EffectBundleFn { | |
pub fn new<F: FnOnce(&mut EntityWorldMut) + Sync + Send + 'static>(f: F) -> Self { | |
Self(Box::new(f)) | |
} | |
} | |
unsafe impl Bundle for EffectBundleFn { | |
fn get_component_ids(components: &Components, ids: &mut impl FnMut(Option<ComponentId>)) { | |
<() as Bundle>::get_component_ids(components, ids); | |
} | |
fn register_required_components( | |
components: &mut ComponentsRegistrator, | |
required_components: &mut RequiredComponents, | |
) { | |
<() as Bundle>::register_required_components(components, required_components); | |
} | |
fn component_ids(components: &mut ComponentsRegistrator, ids: &mut impl FnMut(ComponentId)) { | |
<() as Bundle>::component_ids(components, ids); | |
} | |
} | |
impl DynamicBundle for EffectBundleFn { | |
type Effect = Self; | |
fn get_components(self, func: &mut impl FnMut(StorageType, OwningPtr<'_>)) -> Self::Effect { | |
<() as DynamicBundle>::get_components((), func); | |
self | |
} | |
} | |
impl BundleEffect for EffectBundleFn { | |
fn apply(self, entity: &mut EntityWorldMut) { | |
(self.0)(entity) | |
} | |
} |
This feels incredibly nice to use. Thanks for sharing!
Out of curiosity, do we know if anything even remotely shaped like this is part of the "grand BSN plan"?
Thank you :). For everyone seeing this here i should mention that ole from the bevy discord made something like this but specific to observers and its much nicer for when you want to attach an observer. I like using both for different use cases.
This effectbundlefn is also special in that it erases the type of the fn you pass in which is good and bad:
- good: it erases the type so you can use it to return different
impl bundle
s from one function - bad: you cant add multiple of theese to one bundle because
I will probably make a generic non type erased version too for when you don't need the type erasure.
For the second question i have no idea but there is an open github discussion about bsn so maybe ask there or in the ui channel on discord
@sum-catnip I think you need to be careful with this because you report to the ECS system that the bundle contains no components
fn get_component_ids(components: &Components, ids: &mut impl FnMut(Option<ComponentId>)) {
<() as Bundle>::get_component_ids(components, ids);
}
but then in your type erased example demonstrate how EffectBundleFn
can be used to insert components, does this lead to undefined behavior? Or is the insertion of components in the BundleEffect completely separate from the logic of Bundle?
can be used for this:
or this: