Open Jenya705 opened 1 year ago
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.
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)
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)
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
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.
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:
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