Skip to content

Simpler custom commands #2899

Closed
Closed

Description

@alice-i-cecile

What problem does this solve or what need does it fill?

Custom commands are cumbersome and bulky to work with. See book draft for current design.

What solution would you like?

impl Command for <impl FnOnce(&mut World)>

This could be used for simple one-off use-cases where the whole struct + trait extension pattern is too heavy.

What alternative(s) have you considered?

Running systems as commands has similar effects, see #2234. However, it has higher overhead and is not well-suited to reusing custom entity spawning / other archetype modifying logic (unless we use it to insert new exclusive systems).

Additional context

Idea credit @TheRawMeatball.

Activity

  1. added
    A-ECSEntities, components, systems, and events
    C-UsabilityA targeted quality-of-life change that makes Bevy easier to use
    S-Ready-For-ImplementationThis issue is ready for an implementation PR. Go for it!
    on Oct 1, 2021
  2. added
    D-TrivialNice and easy! A great choice to get started with Bevy
    on Oct 1, 2021
  3. cart commented on Oct 1, 2021

    @cart
    Member

    I see no harm in implementing Command for functions / supporting this. But I wouldn't recommend it for any "structured / reusable" command, especially those with inputs. Extension methods are 100% optional, so in practice this is the difference:

    // Struct with no inputs
    struct Foo;
    impl Command for Foo {
        fn write(self, world: &mut World) {
            /* do thing */
        }
    } 
    commands.add(Foo);
    
    // Struct with inputs
    struct Bar {
        baz: usize,
    }
    
    impl Command for Bar {
        fn write(self, world: &mut World) {
            /* do thing */
        }
    } 
    commands.add(Bar { baz: 42 };
    // Floating functions with no inputs
    fn foo(world: &mut World) {
        /* do thing */
    }
    
    commands.add(foo);
    
    // Floating function with inputs
    fn bar(baz: usize) -> impl FnOnce(&mut World) {
        move |world: &mut World| {
            /* do thing with baz */
        }
    }
    
    commands.add(bar(42));

    I think functions will be most useful for one-off system-specific capture closure commands. Traits seems way clearer for reusable commands (both on the definition and consumption side).

  4. Supermath101 commented on Oct 2, 2021

    @Supermath101
    // Floating function with inputs
    fn bar(baz: usize) -> impl FnOnce(&mut World) {
        move |world: &mut World| {
            /* do thing with baz */
        }
    }
    
    commands.add(bar(42));

    Why don't we just make a macro to convert a standard function into that special format?

  5. alice-i-cecile commented on Oct 2, 2021

    @alice-i-cecile
    MemberAuthor

    You could go one further, and even make the extension trait with a macro 🤔

    // Creates a param-storage struct and extends the Command trait.
    #[command]
    fn do_stuff(world: &mut World, param1: Param1) {
       // Does things
    }
    
    // Usage
    commands.do_stuff(param1);
  6. TheRawMeatball commented on Oct 2, 2021

    @TheRawMeatball
    Member

    Sure, but a macro doesn't seem very practical here, or very bevy-ish. But, I'd say floating fn with inputs personally looks pretty clean, though that's more so a style thing.

  7. alice-i-cecile commented on Oct 2, 2021

    @alice-i-cecile
    MemberAuthor

    Yeah, my preference is for the floating fn personally; I think it's nice for simple one-off uses.

    That plus proper docs on how to do custom commands the Proper Way should be plenty.

  8. mockersf commented on Oct 4, 2021

    @mockersf
    Member

    Wouldn't a floating fn with input be a system? So #2234 would fix this?

  9. TheRawMeatball commented on Oct 5, 2021

    @TheRawMeatball
    Member

    Chances are if you're writing a custom command it's because you need direct world access, so, probably not.

  10. alice-i-cecile commented on Oct 5, 2021

    @alice-i-cecile
    MemberAuthor

    Does #2234 work with exclusive systems @mockersf?

  11. TheRawMeatball commented on Oct 5, 2021

    @TheRawMeatball
    Member

    Even if it did, getting all the system stuff feels like unnecessary complexity.

  12. added a commit that references this issue on Oct 21, 2021
    4d26bd7
  13. added a commit that references this issue on Feb 3, 2022
    21ac4bc
  14. added a commit that references this issue on Feb 11, 2022
    ff45350
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-ECSEntities, components, systems, and eventsC-UsabilityA targeted quality-of-life change that makes Bevy easier to useD-TrivialNice and easy! A great choice to get started with BevyS-Ready-For-ImplementationThis issue is ready for an implementation PR. Go for it!

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions