pmmp / PocketMine-MP

A server software for Minecraft: Bedrock Edition in PHP
https://pmmp.io
GNU Lesser General Public License v3.0
3.28k stars 1.56k forks source link

Command overloading, & automatic command argument parsing & validation system #6518

Open dktapps opened 1 week ago

dktapps commented 1 week ago

Description

This has been discussed many times over the years, but it's never been done in a satisfying way.

Currently, all commands receive their arguments as string[] and have to do boilerplate validation themselves, including argument count checking, conversion to appropriate types (e.g. targets), checking if the targets exist/are valid/etc, checking if the parameters are part of an accepted set of values, etc.

You need only look at this nasty code to see why we need this. I remember spending hours and hours to get to those few lines of code.

Before I get into this, I'll mention that it's possible there are general-purpose libraries for supporting this kind of feature. Processing commands is not unique to Minecraft, as it's also a common need of applications to parse CLI arguments, which would have pretty much the same requirements.

It should be possible to implement this system without breaking BC, even just within a custom Command::execute(), as this is essentially a subcommands system combined with automatic argument validation & parsing. However, it may be desirable to introduce an OverloadedCommand to allow overload information to be exported for use in features like #6517.

This issue proposes the following:

Justification

The current command system is annoying to work with for anything but the simplest of use-cases, due to the writer of the command needing to know how to parse the given arguments.

This also leads to many inconsistencies in the way arguments are parsed and handled. For example, some people will just use (int) $args[0] to convert to an int instead of using getInteger() which has bounds checks. It's also easy to forget to check permissions for subcommands.

Implementing this would also make it trivial to support client-side command hints as per #6517, with no extra work by the developer. I'm of the opinion that if we're going to break BC to support command hints, we should do so in a way that maximizes the benefit gained for the extra work the developer has to do.

Alternative methods

ShockedPlot7560 commented 3 days ago

What about using attribute in function signature to define custom validator, dynamic/hard enums to validate string or values ? In some case we probably want to have only a set of Player or whatever from a default validator/parser based on an enum. I think we need to include it to provide a better API

dktapps commented 3 days ago

I'm thinking a brigadier style API would allow more flexibility. Attributes wouldn't be able to include context info, so it would be difficult to do stuff like dynamic integer bounds. Might be OK for the simple cases to infer the arg types from the function though. Similar to how we have registerEvents() (uses magic & attributes) and registerEvent() (everything explicit & can do weird stuff not possible with magic & attributes, but harder to work with).

dktapps commented 3 days ago

Make no mistake though, this will probably be very hard to implement. As I rambled on about on #team the other day, the process of parsing args and selecting overloads would be non-trivial.