Skip to content
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

Brigadier (Command API) #332

Open
Tracked by #288
Jenya705 opened this issue May 6, 2023 · 6 comments
Open
Tracked by #288

Brigadier (Command API) #332

Jenya705 opened this issue May 6, 2023 · 6 comments
Labels
enhancement New feature or request

Comments

@Jenya705
Copy link
Contributor

Jenya705 commented May 6, 2023

Describe the problem related to your feature request.

There is no command api for valence. I would start with porting brigadier (library that mojang uses to handle commands)

What solution would you like?

A command object which will contain nodes.
Command object will handle:

  • command executions
  • command suggestions

What alternative(s) have you considered?

Just do like in bukkit. All arguments passed into an array of strings.

Additional context

Brigadier: https://github.com/Mojang/brigadier

@Jenya705 Jenya705 added the enhancement New feature or request label May 6, 2023
@dyc3
Copy link
Collaborator

dyc3 commented May 6, 2023

We've already discussed this in discord quite a bit, but I can't seem to find the thread right now.

Edit: Here's the thread (thanks @AviiNL): https://discord.com/channels/998132822239870997/1072277129183625256 I'd recommend reading through it to get caught up.

@rj00a
Copy link
Member

rj00a commented May 7, 2023

We discussed this a bit on discord in the past, but the way Brigadier relies on mutable callback functions and dynamic typing for the executes context doesn't seem like a great fit for Rust or ECS (or any language really). For example:

CommandDispatcher<CommandSourceStack> dispatcher = new CommandDispatcher<>();

dispatcher.register(
    literal("foo")
        .then(
            argument("bar", integer())
                .executes(c -> {
                    System.out.println("Bar is " + getInteger(c, "bar"));
                    return 1;
                })
        )
        .executes(c -> {
            System.out.println("Called foo with no arguments");
            return 1;
        })
);

Instead of the above, I would rather see something roughly like this:

#[derive(Command)]
struct MyFooCommand {
    bar: Option<i32>,
}

fn handle_foo_commands(foos: EventReader<CommandEvent<MyFooCommand>>) {
    for event in foos.iter_mut() {
        match event.command.bar {
            Some(n) => println!("Bar is {n}"),
            None => println!("Called foo with no arguments"),
        }
    }
}

In other words, you describe the structure of the command graph as a Rust data type and pattern match on it to do the execution.

You'd register MyFooCommand as "foo" somewhere (CommandContext resource or something) and off you go.

You could also represent cyclic commands this way:

#[derive(Command)]
struct MyCyclicCommand {
    blah: i32,
    recursion: Option<Box<MyCyclicCommand>>,
}

(Disclaimer: I have not actually used Brigadier)

@Jenya705
Copy link
Contributor Author

Jenya705 commented May 7, 2023

We discussed this a bit on discord in the past, but the way Brigadier relies on mutable callback functions and dynamic typing for the executes context doesn't seem like a great fit for Rust or ECS (or any language really). For example:

CommandDispatcher<CommandSourceStack> dispatcher = new CommandDispatcher<>();

dispatcher.register(
    literal("foo")
        .then(
            argument("bar", integer())
                .executes(c -> {
                    System.out.println("Bar is " + getInteger(c, "bar"));
                    return 1;
                })
        )
        .executes(c -> {
            System.out.println("Called foo with no arguments");
            return 1;
        })
);

Instead of the above, I would rather see something roughly like this:

#[derive(Command)]
struct MyFooCommand {
    bar: Option<i32>,
}

fn handle_foo_commands(foos: EventReader<CommandEvent<MyFooCommand>>) {
    for event in foos.iter_mut() {
        match event.command.bar {
            Some(n) => println!("Bar is {n}"),
            None => println!("Called foo with no arguments"),
        }
    }
}

In other words, you describe the structure of the command graph as a Rust data type and pattern match on it to do the execution.

You'd register MyFooCommand as "foo" somewhere (CommandContext resource or something) and off you go.

You could also represent cyclic commands this way:

#[derive(Command)]
struct MyCyclicCommand {
    blah: i32,
    recursion: Option<Box<MyCyclicCommand>>,
}

(Disclaimer: I have not actually used Brigadier)

I've thought we could use a Execute Id, which is just a number. So execute function returns this id and fill the vector with arguments, which were calculated during finding this id.

match command_dispatcher.execute("gamemode @s creative", &mut arguments) {
    Ok(0) => {
        let (entity_selector, game_mode_enum) = parse_arguments!(arguments);
        
        for entity in entity_selector.iter() {
             let mut gamemode = gamemode_query.get(entity) else { continue; };
             gamemode.0 = game_mode_enum; 
        }
    } // set creative gamemode to @s player
    // possibly others execute ids
    Err(err) => {} // some error
}

This ids are set when the user is 'building' nodes. (Like in brigadier but instead of callbacks a number)

@rj00a rj00a changed the title Brigadier Brigadier (Command API) May 23, 2023
This was referenced May 23, 2023
@Jenya705 Jenya705 mentioned this issue Jun 2, 2023
@dyc3
Copy link
Collaborator

dyc3 commented Oct 9, 2024

To speed up development, I think we should try to avoid reinventing the wheel.
Azalea seems to have a workable crate already, we should evaluate it if we could use it in Valence.
https://github.com/azalea-rs/azalea/tree/main/azalea-brigadier

@JackCrumpLeys
Copy link
Contributor

JackCrumpLeys commented Oct 10, 2024

To speed up development, I think we should try to avoid reinventing the wheel.
Azalea seems to have a workable crate already, we should evaluate it if we could use it in Valence.
https://github.com/azalea-rs/azalea/tree/main/azalea-brigadier

I already did this. See merged pr #446. We haven't done server side completion yet tho.

@andrewgazelka
Copy link

does brigadier support generating the command completion packets?

if you are curious I have auto completion and am doing something like this

https://github.com/andrewgazelka/hyperion/blob/7540e89e92b4ce38ff4249f7fe4b9ea5d87e1319/crates/hyperion-permission/src/lib.rs#L101-L121

although yea probably better to combine and not have nom + brigadier like syntax

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants