| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
|
Also, just wanted to mention that this currently is untested which will be done until noon on Saturday. |
Sorry, something went wrong.
|
As requested on discord, I will now add some code examples and explain my changes a little more. 1. Internal changesTo be able to implement this without having to use if-statements (in fact, I didn't use a single one), I changed the executeWith method in the IExecutorTyped interface to now also take in a Map<String, Object>. This map is filled with content in CommandAPIHandler#generateCommand. 1.1 Interfaces and executes...Before I made this PR, each executor had two interfaces: ...CommandExecutor and ...ResultingCommandExecutor.
The ...ExecutionInfo and ...ResultingExecutionInfo interfaces both have one method:
void run(BlockCommandSender sender, Object[] args, Map<String, Object> argsMap) throws WrapperCommandSyntaxException;
int run(BlockCommandSender sender, Object[] args, Map<String, Object> argsMap) throws WrapperCommandSyntaxException;Those two interfaces are now also available through the use of the .executes... methods. public T executesPlayer(PlayerExecutionInfo info) {
this.executor.addNormalExecutor(info);
return (T) this;
}
public T executesPlayer(PlayerResultingExecutionInfo info) {
this.executor.addResultingExecutor(info);
return (T) this;
}Use the new methods in your codeFor this section, I will just add some examples I wrote: new CommandAPICommand("nomap")
.withArguments(new ItemStackArgument("item"))
.executesPlayer((player, args) -> {
// This command does not have access to the map with stores the arguments mapped to their node names
// We have to get the ItemStack as normal
ItemStack itemStack = (ItemStack) args[0];
player.getInventory().addItem(itemStack);
})
.register();
new CommandAPICommand("withmap")
.withArguments(new ItemStackArgument("item"))
.executesPlayer((player, args, argsMap) -> {
// This command has access to the map which stores the arguments mapped to their node names
// Here we can get the ItemStack with two ways:
// The known way:
ItemStack possibilityOne = (ItemStack) args[0];
// Or:
ItemStack possibilityTwo = (ItemStack) argsMap.get("item");
player.getInventory().addItem(possibilityOne, possibilityTwo);
})
.register();2. TestsAs written previously, I did not test this yet but I am confident that it should work. |
Sorry, something went wrong.
|
Not scheduling for 8.6.0 - too close to the expected release date. I'm more than happy to have this for 9.0.0. My problem with this implementation is the limited scope for future extensibility. The CommandAPI has been around for just over four years and we're only now adding more accessibly functionality to the .executes() methods - it's quite possible that another four years down the line we may want to add more functionality to our .executes() method. The choice to use another functional interface with three parameters is limiting and leads into questionable design decisions, such as:
I think going with a record would be better. It would allow us (CommandAPI development team) to be able to expand the list of accessible functions easily without causing backwards-incompatible changes and without CommandAPI users needing to change their executor implementation. Perhaps something like this would be better? new CommandAPICommand("withmap")
.withArguments(new ItemStackArgument("item"))
.executesPlayer(info -> {
ItemStack possibilityOne = info.args()[0]; // Access using args()
ItemStack possibilityTwo = info.argsMap().get("item"); // Access using argsMap()
Player player = info.sender(); // Access command sender. Using generics, we can make this a Player instead of a CommandSender object.
})
.register(); |
Sorry, something went wrong.
|
Yes, I read that record suggestion in #360 and also tried to implement it like that. |
Sorry, something went wrong.
I envision something along the lines of creating a generalized record like this: public record ExecutionInfo<Sender extends CommandSender> (
Sender sender,
Object[] args,
Map<String, Object> argsMap
) {}I think in the long run it would be safer to create a generic functional interface for our two types rather than using Function<ExecutionInfo, Integer> and Consumer<ExecutionInfo> (especially for Kotlin purposes). Say we add an INormalExecution and an IResultingExecution which follows something like this: public interface INormalExecution<Sender extends CommandSender> extends IExecutorTyped {
@Override
default int executeWith(CommandSender sender, Object[] args) throws WrapperCommandSyntaxException {
// Some implementation here... either changing the parameters to this function
// to using ExecutionInfo or something? I didn't think this far ahead
return 1;
}
void run(ExecutionInfo<Sender> info) throws WrapperCommandSyntaxException;
}Then I think it's safe to say we can add our implementations for each execution type and then link them into Executable. For example, for a normal player execution: @FunctionalInterface
public interface PlayerCommandExecution extends INormalExecution<Player> {
void run(ExecutionInfo<Player> player) throws WrapperCommandSyntaxException;
@Override
default ExecutorType getType() {
return ExecutorType.PLAYER;
}
}And then linking: // class dev.jorel.commandapi.Executable {
public T executesPlayer(PlayerCommandExecution executor) {
this.executor.addNormalExecutor(executor); // Something to this effect
return (T) this;
}
// }If all of the names of "executor" and "execution" and "executable" start getting too complicated, feel free to choose alternatives for the new classes! In short, the main idea is that we have one centralized record which is easy to update with new changes, and then each new executor implements that. |
Sorry, something went wrong.
|
This is now tested and should work! Also, I decided to not include the CommandArgs class which Lucas suggested on discord as I decided to include the Object[] and Map<String, Object> anyway. |
Sorry, something went wrong.
|
@DerEchtePilz Please update this branch with the latest changes from JorelAli:dev/dev which includes the multi-platform refactor so this can be merged cleanly. For all intents and purposes:
|
Sorry, something went wrong.
|
So, what I've decided to do is that I will first resolve those issues right here (because honestly, I kinda do not want to mess anything up) and then I will update this branch. Can someone please tell me how to update this branch? I've merged conflicting files before but it is important (for me, you and this pull request) that everything goes well. |
Sorry, something went wrong.
… argsToObjectArr to argsToCommandArgs
There was a problem hiding this comment.
A few minor tid-bits that I noticed during manual testing, but nothing severe enough to prevent merging it over. These minor points should be addressed before 9.0.0 goes out though.
Sorry, something went wrong.
| /** | ||
| * @return The wrapper type of this command | ||
| */ | ||
| WrapperType senderWrapper(); |
There was a problem hiding this comment.
This is exposed to the end user. A comment stating that this is only used internally, and you should be using sender() instead would be nice.
Sorry, something went wrong.
| * @param nodeName The node name of this argument. This was set when initializing an argument | ||
| * @return an argument which has the given node name | ||
| */ | ||
| public Object get(String nodeName) { |
There was a problem hiding this comment.
This method can return null (if nodeName is not found). This should be made known to the end user (by using the javax.annotation.Nullable annotation) and it should be stated in the JavaDocs that this can return null if nodeName is not found.
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Hello!
It's me again.
I opened this PR so you can decide if you want to have it in 8.6.0 or later (or if you want me to change/add anything).