Conversation
Jondolf
left a comment
There was a problem hiding this comment.
This doesn't seem too much better than just writing out the hook manually:
#[derive(Component)]
#[component(on_add)]
pub struct MyComponent;
impl MyComponent {
fn on_add(world: DeferredWorld, ctx: HookContext) {
todo!(); // you could also run a one-shot system here if you wanted to
}
}I also don't like that setup implicitly adds the on_add implementation, without clearly implying it in the name. I can picture someone trying to add both and getting errors.
Another potential footgun here is that the setup method runs a one-shot system with a command, so it's deferred, and doesn't run immediately when the component is added the way on_add does.
Having something like setup also makes me wonder, where's the equivalent for on_remove? Having sugar for just a single hook seems a bit inconsistent to me
I think it's a lot better than writing out the hook manually, as that doesn't get you systemparams, complicates resource access due to aliasing rules (like having Compare: #[derive(Component)]
#[component(on_add)]
pub struct Test;
impl Test {
fn on_add(mut world: DeferredWorld, ctx: HookContext) {
// these must be ordered like this to avoid mutably borrowing world twice!
let asset_server = world.resource::<AssetServer>();
let mesh = asset_server.load("mesh.glb");
let mut materials = world.resource_mut::<Assets<StandardMaterial>>();
let material = materials.add(Color::WHITE);
world
.commands()
.entity(ctx.entity)
.insert((Mesh3d(mesh), MeshMaterial3d(material)))
.observe(my_observer);
}
}#[derive(Component)]
#[setup(setup_test)]
pub struct Test;
fn setup_test(
entity: In<Entity>,
mut commands: Commands,
asset_server: Res<AssetServer>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// freedom!
commands
.entity(*entity)
.insert((
Mesh3d(asset_server.load("mesh.glb")),
MeshMaterial3d(materials.add(Color::WHITE)),
))
.observe(my_observer);
}
As implemented in this PR you can have both and they get combined without errors (see the macro expansion)
Yup that seems like a potential issue, fair enough.
Destructor patterns seem to be way less common but I could add sugar for that too for consistency! |
Objective
On<Add, Component>observer is used to "set up" an entity prototype based on a marker struct:Solution
Add a
setupderive helper to theComponentderive helper so that devs can statically declare setup systems without needing to add any plugin machinery.Testing
Tested in a sample project and it works as expected.
Helper expands to a hook like this:
where the
on_add(world, ctx)is the custom on_add hook set via#[component(on_add = ...)]or omitted if none is set.Showcase
Note
A-OK if this isn't a direction that's wanted, just figured I'd throw the PR out there because if it goes through I'd use it to remove 42 plugins from my code!