Skip to content

Commit

Permalink
adding #360 (#369)
Browse files Browse the repository at this point in the history
* adding #360

* provide ExecutionInfo with a record

* fixing JavaDocs

* fixing some things

* adding a CommandArguments class to hold provided arguments

* remove method parameters, fix documentation code to match new syntax

* fix Kotlin DSL to match new syntax

* fixing Converter

* fix some more documentation issues

* fixing some annotation examples to match new syntax

* fix annotation generation to match new syntax

* handle String[] for converted commands correctly

* parse arguments only once

* Make argsToObjectArr return a CommandArguments object. Change name of argsToObjectArr to argsToCommandArgs

* fixing generateCommand method

* fix Brigadier#parseArguments method

* add Javadocs to ExecutionInfo

* Remove test command thingy from CommandAPIMain. Add Javadocs to CommandArguments

* clean up after merge

* fixing a method call in Brigadier#parseArguments

* fixing CommandTree DSL

* optimizing some imports

* fixing some formatting issues

* fixing documentation example code

* fix commands not being executable

* fixing build error
  • Loading branch information
DerEchtePilz authored Dec 17, 2022
1 parent 6c715cb commit 340902c
Show file tree
Hide file tree
Showing 47 changed files with 1,260 additions and 396 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -353,9 +353,9 @@ private int emitExecutes(PrintWriter out, Map<Integer, String> argumentMapping,
} else {
out.print(simpleFromQualified(fromArgumentMap));
}
out.print(") args[");
out.print(") args.get(");
out.print(i);
out.print("]");
out.print(")");
}
//populate stuff here

Expand Down
4 changes: 2 additions & 2 deletions commandapi-annotations/src/test/java/WarpCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ class Examples {
warps.keySet().toArray(new String[0])
)))
.executesPlayer((player, args) -> {
player.teleport(warps.get((String) args[0]));
player.teleport(warps.get((String) args.get(0)));
})
.register();

Expand All @@ -135,7 +135,7 @@ class Examples {
.withPermission("warps.create")
.withArguments(new StringArgument("warpname"))
.executesPlayer((player, args) -> {
warps.put((String) args[0], player.getLocation());
warps.put((String) args.get(0), player.getLocation());
})
)
.register();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ Command fromCommand(AbstractCommandAPICommand<?, Argument, CommandSender> comman
*/
public static <Argument extends AbstractArgument<?, ?, Argument, ?>> Object[] parseArguments(CommandContext cmdCtx, List<Argument> args) throws CommandSyntaxException {
CommandAPIHandler<Argument, ?, ?> handler = (CommandAPIHandler<Argument, ?, ?>) CommandAPIHandler.getInstance();
return handler.argsToObjectArr(cmdCtx, (Argument[]) args.toArray(AbstractArgument[]::new));
return handler.argsToCommandArgs(cmdCtx, (Argument[]) args.toArray(AbstractArgument[]::new)).args();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,7 @@
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import dev.jorel.commandapi.commandsenders.*;
import dev.jorel.commandapi.exceptions.WrapperCommandSyntaxException;
import dev.jorel.commandapi.executors.ExecutorType;
import dev.jorel.commandapi.executors.IExecutorNormal;
import dev.jorel.commandapi.executors.IExecutorResulting;
import dev.jorel.commandapi.executors.IExecutorTyped;
import dev.jorel.commandapi.executors.*;

import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -63,13 +60,13 @@ public void addResultingExecutor(IExecutorResulting<?, ?> executor) {
this.resultingExecutors.add((IExecutorResulting<CommandSender, WrapperType>) executor);
}

public int execute(WrapperType sender, Object[] arguments) throws CommandSyntaxException {
public int execute(AbstractExecutionInfo<CommandSender, WrapperType> info) throws CommandSyntaxException {

// Parse executor type
if (!resultingExecutors.isEmpty()) {
// Run resulting executor
try {
return execute(resultingExecutors, sender, arguments);
return execute(resultingExecutors, info);
} catch (WrapperCommandSyntaxException e) {
throw e.getException();
} catch (Exception e) {
Expand All @@ -79,7 +76,7 @@ public int execute(WrapperType sender, Object[] arguments) throws CommandSyntaxE
} else {
// Run normal executor
try {
return execute(normalExecutors, sender, arguments);
return execute(normalExecutors, info);
} catch (WrapperCommandSyntaxException e) {
throw e.getException();
} catch (Exception e) {
Expand All @@ -89,35 +86,35 @@ public int execute(WrapperType sender, Object[] arguments) throws CommandSyntaxE
}
}

private int execute(List<? extends IExecutorTyped<WrapperType>> executors, WrapperType sender, Object[] args)
private int execute(List<? extends IExecutorTyped<CommandSender, WrapperType>> executors, AbstractExecutionInfo<CommandSender, WrapperType> info)
throws WrapperCommandSyntaxException {
if (isForceNative()) {
return execute(executors, sender, args, ExecutorType.NATIVE);
} else if (sender instanceof AbstractPlayer && matches(executors, ExecutorType.PLAYER)) {
return execute(executors, sender, args, ExecutorType.PLAYER);
} else if (sender instanceof AbstractEntity && matches(executors, ExecutorType.ENTITY)) {
return execute(executors, sender, args, ExecutorType.ENTITY);
} else if (sender instanceof AbstractConsoleCommandSender && matches(executors, ExecutorType.CONSOLE)) {
return execute(executors, sender, args, ExecutorType.CONSOLE);
} else if (sender instanceof AbstractBlockCommandSender && matches(executors, ExecutorType.BLOCK)) {
return execute(executors, sender, args, ExecutorType.BLOCK);
} else if (sender instanceof AbstractProxiedCommandSender && matches(executors, ExecutorType.PROXY)) {
return execute(executors, sender, args, ExecutorType.PROXY);
return execute(executors, info, ExecutorType.NATIVE);
} else if (info.senderWrapper() instanceof AbstractPlayer && matches(executors, ExecutorType.PLAYER)) {
return execute(executors, info, ExecutorType.PLAYER);
} else if (info.senderWrapper() instanceof AbstractEntity && matches(executors, ExecutorType.ENTITY)) {
return execute(executors, info, ExecutorType.ENTITY);
} else if (info.senderWrapper() instanceof AbstractConsoleCommandSender && matches(executors, ExecutorType.CONSOLE)) {
return execute(executors, info, ExecutorType.CONSOLE);
} else if (info.senderWrapper() instanceof AbstractBlockCommandSender && matches(executors, ExecutorType.BLOCK)) {
return execute(executors, info, ExecutorType.BLOCK);
} else if (info.senderWrapper() instanceof AbstractProxiedCommandSender && matches(executors, ExecutorType.PROXY)) {
return execute(executors, info, ExecutorType.PROXY);
} else if (matches(executors, ExecutorType.ALL)) {
return execute(executors, sender, args, ExecutorType.ALL);
return execute(executors, info, ExecutorType.ALL);
} else {
throw new WrapperCommandSyntaxException(new SimpleCommandExceptionType(
new LiteralMessage(CommandAPI.getConfiguration().getMissingImplementationMessage()
.replace("%s", sender.getClass().getSimpleName().toLowerCase())
.replace("%S", sender.getClass().getSimpleName()))).create());
.replace("%s", info.sender().getClass().getSimpleName().toLowerCase())
.replace("%S", info.sender().getClass().getSimpleName()))).create());
}
}

private int execute(List<? extends IExecutorTyped<WrapperType>> executors, WrapperType sender, Object[] args,
ExecutorType type) throws WrapperCommandSyntaxException {
for (IExecutorTyped<WrapperType> executor : executors) {
private int execute(List<? extends IExecutorTyped<CommandSender, WrapperType>> executors,
AbstractExecutionInfo<CommandSender, WrapperType> info, ExecutorType type) throws WrapperCommandSyntaxException {
for (IExecutorTyped<CommandSender, WrapperType> executor : executors) {
if (executor.getType() == type) {
return executor.executeWith(sender, args);
return executor.executeWith(info);
}
}
throw new NoSuchElementException("Executor had no valid executors for type " + type.toString());
Expand All @@ -139,8 +136,8 @@ public boolean isForceNative() {
return matches(normalExecutors, ExecutorType.NATIVE) || matches(resultingExecutors, ExecutorType.NATIVE);
}

private boolean matches(List<? extends IExecutorTyped<?>> executors, ExecutorType type) {
for (IExecutorTyped<?> executor : executors) {
private boolean matches(List<? extends IExecutorTyped<?, ?>> executors, ExecutorType type) {
for (IExecutorTyped<?, ?> executor : executors) {
if (executor.getType() == type) {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
import com.mojang.brigadier.tree.LiteralCommandNode;
import dev.jorel.commandapi.arguments.*;
import dev.jorel.commandapi.commandsenders.AbstractCommandSender;
import dev.jorel.commandapi.executors.AbstractExecutionInfo;
import dev.jorel.commandapi.executors.CommandArguments;
import dev.jorel.commandapi.preprocessor.RequireField;
import dev.jorel.commandapi.wrappers.PreviewableFunction;

Expand All @@ -42,8 +44,8 @@
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Field;
import java.util.List;
import java.util.*;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;

Expand Down Expand Up @@ -161,21 +163,54 @@ Command<Source> generateCommand(Argument[] args, CommandAPIExecutor<CommandSende
// Generate our command from executor
return (cmdCtx) -> {
AbstractCommandSender<? extends CommandSender> sender = platform.getSenderForCommand(cmdCtx, executor.isForceNative());
CommandArguments commandArguments = argsToCommandArgs(cmdCtx, args);
AbstractExecutionInfo<CommandSender, AbstractCommandSender<? extends CommandSender>> executionInfo = new AbstractExecutionInfo<>() {
@Override
public CommandSender sender() {
return sender.getSource();
}

@Override
public AbstractCommandSender<? extends CommandSender> senderWrapper() {
return sender;
}

@Override
public CommandArguments args() {
return commandArguments;
}
};
if (converted) {
Object[] argObjs = argsToObjectArr(cmdCtx, args);
int resultValue = 0;

// Return a String[] of arguments for converted commands
String[] argsAndCmd = cmdCtx.getRange().get(cmdCtx.getInput()).split(" ");
String[] result = new String[argsAndCmd.length - 1];
AbstractExecutionInfo<CommandSender, AbstractCommandSender<? extends CommandSender>> convertedExecutionInfo = new AbstractExecutionInfo<>() {
@Override
public CommandSender sender() {
return sender.getSource();
}

@Override
public AbstractCommandSender<? extends CommandSender> senderWrapper() {
return sender;
}

@Override
public CommandArguments args() {
return new CommandArguments(result, new LinkedHashMap<>());
}
};

System.arraycopy(argsAndCmd, 1, result, 0, argsAndCmd.length - 1);

// As stupid as it sounds, it's more performant and safer to use
// a List<?>[] instead of a List<List<?>>, due to NPEs and AIOOBEs.
@SuppressWarnings("unchecked")
List<String>[] entityNamesForArgs = new List[args.length];
for (int i = 0; i < args.length; i++) {
entityNamesForArgs[i] = args[i].getEntityNames(argObjs[i]);
entityNamesForArgs[i] = args[i].getEntityNames(commandArguments.get(i));
}
List<List<String>> product = CartesianProduct.getDescartes(Arrays.asList(entityNamesForArgs));

Expand All @@ -189,12 +224,12 @@ Command<Source> generateCommand(Argument[] args, CommandAPIExecutor<CommandSende
}
}
}
resultValue += executor.execute(sender, result);
resultValue += executor.execute(convertedExecutionInfo);
}

return resultValue;
} else {
return executor.execute(sender, argsToObjectArr(cmdCtx, args));
return executor.execute(executionInfo);
}
};
}
Expand All @@ -204,22 +239,27 @@ Command<Source> generateCommand(Argument[] args, CommandAPIExecutor<CommandSende
*
* @param cmdCtx the command context that will execute this command
* @param args the map of strings to arguments
* @return an Object[] which can be used in (sender, args) ->
* @throws CommandSyntaxException when an argument isn't formatted correctly
* @return an CommandArguments object which can be used in (sender, args) ->
* @throws CommandSyntaxException
*/
Object[] argsToObjectArr(CommandContext<Source> cmdCtx, Argument[] args)
CommandArguments argsToCommandArgs(CommandContext<Source> cmdCtx, Argument[] args)
throws CommandSyntaxException {
// Array for arguments for executor
List<Object> argList = new ArrayList<>();

// LinkedHashMap for arguments for executor
Map<String, Object> argsMap = new LinkedHashMap<>();

// Populate array
for (Argument argument : args) {
if (argument.isListed()) {
argList.add(parseArgument(cmdCtx, argument.getNodeName(), argument, argList.toArray()));
Object parsedArgument = parseArgument(cmdCtx, argument.getNodeName(), argument, argList.toArray());
argList.add(parsedArgument);
argsMap.put(argument.getNodeName(), parsedArgument);
}
}

return argList.toArray();
return new CommandArguments(argList.toArray(), argsMap);
}

/**
Expand Down Expand Up @@ -633,8 +673,7 @@ LiteralArgumentBuilder<Source> getLiteralArgumentBuilder(String commandName) {
* @param permission the permission required to use this literal
* @return a brigadier LiteralArgumentBuilder representing a literal
*/
LiteralArgumentBuilder<Source> getLiteralArgumentBuilderArgument(String commandName,
CommandPermission permission, Predicate<CommandSender> requirements) {
LiteralArgumentBuilder<Source> getLiteralArgumentBuilderArgument(String commandName, CommandPermission permission, Predicate<CommandSender> requirements) {
LiteralArgumentBuilder<Source> builder = LiteralArgumentBuilder.literal(commandName);
return builder.requires((Source css) -> permissionCheck(platform.getCommandSenderFromCommandSource(css),
permission, requirements));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package dev.jorel.commandapi.executors;

import dev.jorel.commandapi.commandsenders.AbstractCommandSender;

/**
* This interface represents an AbstractExecutionInfo for a command. It provides the sender of a command, as well as it's arguments
*
* @param <Sender> The type of the sender of a command this AbstractExecutionInfo belongs to
*/
public interface AbstractExecutionInfo<Sender, WrapperType extends AbstractCommandSender<? extends Sender>> {

/**
* @return The sender of this command
*/
Sender sender();

/**
* @return The wrapper type of this command
*/
WrapperType senderWrapper();

/**
* @return The arguments of this command
*/
CommandArguments args();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package dev.jorel.commandapi.executors;

import java.util.Map;

/**
* This class stores the arguments for this command
*/
public class CommandArguments {

private final Object[] args;
private final Map<String, Object> argsMap;

/**
* Constructs a new CommandArguments instance
*
* @param args The arguments for this command
* @param argsMap The arguments for this command mapped to the node names. This is an ordered map
*/
public CommandArguments(Object[] args, Map<String, Object> argsMap) {
this.args = args;
this.argsMap = argsMap;
}

/**
* @return The complete argument array of this command
*/
public Object[] args() {
return args;
}

/**
* Returns an argument by its position
*
* @param index The position of this argument
* @return an argument which is placed at the given index
*/
public Object get(int index) {
return args[index];
}

/**
* Returns an argument by its node name
*
* @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) {
return argsMap.get(nodeName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,27 +28,24 @@
* @param <CommandSender> The CommandSender for this executor
* @param <WrapperType> The AbstractCommandSender that wraps the CommandSender
*/
public interface IExecutorNormal<CommandSender, WrapperType extends AbstractCommandSender<? extends CommandSender>> extends IExecutorTyped<WrapperType> {

public interface IExecutorNormal<CommandSender, WrapperType extends AbstractCommandSender<? extends CommandSender>> extends IExecutorTyped<CommandSender, WrapperType> {
/**
* Executes the command executor with the provided command sender and the provided arguments.
* @param sender the command sender for this command
* @param args the arguments provided to this command
* @param info The AbstractExecutionInfo for this command
* @return 1 if the command succeeds, 0 if the command fails
* @throws WrapperCommandSyntaxException if an error occurs during the execution of this command
*/
@Override
default int executeWith(WrapperType sender, Object[] args) throws WrapperCommandSyntaxException {
this.run(sender.getSource(), args);
default int executeWith(AbstractExecutionInfo<CommandSender, WrapperType> info) throws WrapperCommandSyntaxException {
this.run(info);
return 1;
}

/**
* Executes the command.
* @param sender the command sender for this command
* @param args the arguments provided to this command
* @param info The AbstractExecutionInfo for this command
* @throws WrapperCommandSyntaxException if an error occurs during the execution of this command
*/
void run(CommandSender sender, Object[] args) throws WrapperCommandSyntaxException;
void run(AbstractExecutionInfo<CommandSender, WrapperType> info) throws WrapperCommandSyntaxException;

}
Loading

0 comments on commit 340902c

Please sign in to comment.