From c4801757a2fda147e1cee65f70f80fb215047525 Mon Sep 17 00:00:00 2001
From: Dico Karssiens
Date: Sun, 30 Sep 2018 17:05:42 +0100
Subject: [PATCH] Some changes
---
.../dicore/command/ChildCommandAddress.java | 16 +-
.../java/io/dico/dicore/command/Command.java | 48 +---
.../dico/dicore/command/CommandBuilder.java | 11 +-
.../io/dico/dicore/command/CommandResult.java | 23 --
.../dico/dicore/command/ExecutionContext.java | 243 +++++++++---------
.../dico/dicore/command/ExtendedCommand.java | 3 +-
.../dico/dicore/command/ICommandAddress.java | 33 ++-
.../dico/dicore/command/ICommandReceiver.java | 22 --
.../command/ModifiableCommandAddress.java | 17 +-
.../command/PermissionContextFilter.java | 27 ++
.../dicore/command/RootCommandAddress.java | 37 ++-
.../command/annotation/PreprocessArgs.java | 1 +
.../help/defaults/DefaultPageBuilder.java | 3 +-
.../help/insertion/HelpComponentInserter.java | 2 +-
.../command/parameter/ArgumentBuffer.java | 71 ++---
.../ArgumentMergingPreProcessor.java | 43 +++-
.../command/parameter/ContextParser.java | 32 ++-
.../parameter/IArgumentPreProcessor.java | 20 +-
.../command/parameter/ParameterList.java | 16 +-
.../parameter/type/EnumParameterType.java | 6 +-
.../command/parameter/type/ParameterType.java | 52 ----
.../command/predef/DefaultGroupCommand.java | 4 +-
.../reflect/ICommandInterceptor.java | 36 +++
.../reflect/ICommandReceiver.java | 5 +
.../reflect/ReflectiveCommand.java | 30 ++-
.../reflect/ReflectiveRegistration.java | 42 +--
.../reflect/KotlinReflectiveRegistration.kt | 16 +-
.../example/ParameterInfoObjectExample.java | 73 ++++++
gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54413 bytes
gradle/wrapper/gradle-wrapper.properties | 5 +
gradlew | 172 +++++++++++++
gradlew.bat | 84 ++++++
.../command/AbstractParcelCommands.kt | 16 +-
.../parcels2/command/ParcelCommandBuilder.kt | 5 +-
.../command/ParcelCommandReceivers.kt | 2 +-
.../parcels2/command/ParcelParameterTypes.kt | 4 +-
.../io/dico/parcels2/command/ParcelTarget.kt | 2 +-
.../defaultimpl/DefaultParcelGenerator.kt | 1 -
.../defaultimpl/ParcelProviderImpl.kt | 11 +-
.../dico/parcels2/listener/ParcelListeners.kt | 2 -
.../kotlin/io/dico/parcels2/storage/Hikari.kt | 2 +-
41 files changed, 835 insertions(+), 403 deletions(-)
delete mode 100644 dicore3/command/src/main/java/io/dico/dicore/command/CommandResult.java
delete mode 100644 dicore3/command/src/main/java/io/dico/dicore/command/ICommandReceiver.java
create mode 100644 dicore3/command/src/main/java/io/dico/dicore/command/registration/reflect/ICommandInterceptor.java
create mode 100644 dicore3/command/src/main/java/io/dico/dicore/command/registration/reflect/ICommandReceiver.java
create mode 100644 dicore3/command/src/test/java/io/dico/dicore/command/example/ParameterInfoObjectExample.java
create mode 100644 gradle/wrapper/gradle-wrapper.jar
create mode 100644 gradle/wrapper/gradle-wrapper.properties
create mode 100644 gradlew
create mode 100644 gradlew.bat
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/ChildCommandAddress.java b/dicore3/command/src/main/java/io/dico/dicore/command/ChildCommandAddress.java
index 022904e..9a26f61 100644
--- a/dicore3/command/src/main/java/io/dico/dicore/command/ChildCommandAddress.java
+++ b/dicore3/command/src/main/java/io/dico/dicore/command/ChildCommandAddress.java
@@ -10,6 +10,7 @@ public class ChildCommandAddress extends ModifiableCommandAddress {
final List namesModifiable = new ArrayList<>(4);
List names = namesModifiable;
Command command;
+ boolean isCommandTrailing;
public ChildCommandAddress() {
}
@@ -89,7 +90,7 @@ public class ChildCommandAddress extends ModifiableCommandAddress {
}
public void finalizeNames() {
- if (names instanceof ArrayList) {
+ if (names == namesModifiable) {
names = Collections.unmodifiableList(namesModifiable);
}
}
@@ -103,4 +104,17 @@ public class ChildCommandAddress extends ModifiableCommandAddress {
this.parent = parent;
}
+ @Override
+ public boolean isCommandTrailing() {
+ return isCommandTrailing;
+ }
+
+ @Override
+ public void setCommandTrailing(boolean trailing) {
+ if (hasChildren()) {
+ throw new IllegalStateException("Address already has children, this property can't be modified");
+ }
+ isCommandTrailing = trailing;
+ }
+
}
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/Command.java b/dicore3/command/src/main/java/io/dico/dicore/command/Command.java
index 53e5821..894e74e 100644
--- a/dicore3/command/src/main/java/io/dico/dicore/command/Command.java
+++ b/dicore3/command/src/main/java/io/dico/dicore/command/Command.java
@@ -70,10 +70,11 @@ public abstract class Command {
return this;
}
+ /*
public Command preprocessArguments(IArgumentPreProcessor processor) {
parameterList.setArgumentPreProcessor(processor);
return this;
- }
+ }*/
public final ParameterList getParameterList() {
return parameterList;
@@ -133,56 +134,23 @@ public abstract class Command {
// ---- EXECUTION ----
- public void execute(CommandSender sender, ICommandAddress caller, ArgumentBuffer buffer) {
- ExecutionContext executionContext = new ExecutionContext(sender, caller, this, buffer, false);
-
- try {
- executeWithContext(executionContext);
- } catch (Throwable t) {
- caller.getChatHandler().handleException(sender, executionContext, t);
- }
- }
-
- public void executeWithContext(ExecutionContext context) throws CommandException {
- //System.out.println("In Command.execute(sender, caller, buffer)#try{");
+ public void initializeAndFilterContext(ExecutionContext context) throws CommandException {
int i, n;
for (i = 0, n = contextFilters.size() - postParameterFilterCount; i < n; i++) {
contextFilters.get(i).filterContext(context);
}
- context.parseParameters();
+ context.parse(parameterList);
- for (n = contextFilters.size(); i < n; i++) {
- contextFilters.get(i).filterContext(context);
+ if (!context.isTabComplete()) {
+ for (n = contextFilters.size(); i < n; i++) {
+ contextFilters.get(i).filterContext(context);
+ }
}
-
- //System.out.println("Post-contextfilters");
-
- String message = execute(context.getSender(), context);
- context.sendMessage(EMessageType.RESULT, message);
}
public abstract String execute(CommandSender sender, ExecutionContext context) throws CommandException;
- public List tabComplete(CommandSender sender, ICommandAddress caller, Location location, ArgumentBuffer buffer) {
- ExecutionContext executionContext = new ExecutionContext(sender, caller, this, buffer, true);
- try {
- return tabCompleteWithContext(executionContext, location);
- } catch (CommandException ex) {
- return Collections.emptyList();
- }
- }
-
- public List tabCompleteWithContext(ExecutionContext context, Location location) throws CommandException {
- int i, n;
- for (i = 0, n = contextFilters.size() - postParameterFilterCount; i < n; i++) {
- contextFilters.get(i).filterContext(context);
- }
-
- context.parseParametersQuietly();
- return tabComplete(context.getSender(), context, location);
- }
-
public List tabComplete(CommandSender sender, ExecutionContext context, Location location) {
return context.getSuggestedCompletions(location);
}
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/CommandBuilder.java b/dicore3/command/src/main/java/io/dico/dicore/command/CommandBuilder.java
index 63628d3..e527f27 100644
--- a/dicore3/command/src/main/java/io/dico/dicore/command/CommandBuilder.java
+++ b/dicore3/command/src/main/java/io/dico/dicore/command/CommandBuilder.java
@@ -265,10 +265,19 @@ public final class CommandBuilder {
* @return this
* @throws IllegalStateException if the current group has no command
*/
- public CommandBuilder addRequiredPermission(String permission) {
+ public CommandBuilder addPermission(String permission) {
return addContextFilter(IContextFilter.permission(permission));
}
+ /**
+ * Add a required permission to the command of the current group, which can be inherited
+ * @return this
+ * @throws IllegalStateException if the current group has no command
+ */
+ public CommandBuilder addInheritablePermission(String permission) {
+ return addContextFilter(IContextFilter.inheritablePermission(permission));
+ }
+
/**
* Jump up a level in the address
*
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/CommandResult.java b/dicore3/command/src/main/java/io/dico/dicore/command/CommandResult.java
deleted file mode 100644
index 7c4a891..0000000
--- a/dicore3/command/src/main/java/io/dico/dicore/command/CommandResult.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package io.dico.dicore.command;
-
-/**
- * This enum is intended to provide some constants for default messages.
- * Can be returned by a reflective command.
- * Currently, no constants have an actual message.
- * Prone to removal in the future because of lack of usefullness.
- */
-public enum CommandResult {
- SUCCESS(null),
- QUIET_ERROR(null);
-
- private final String message;
-
- CommandResult(String message) {
- this.message = message;
- }
-
- public String getMessage() {
- return message;
- }
-
-}
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/ExecutionContext.java b/dicore3/command/src/main/java/io/dico/dicore/command/ExecutionContext.java
index 2a074e1..a329f40 100644
--- a/dicore3/command/src/main/java/io/dico/dicore/command/ExecutionContext.java
+++ b/dicore3/command/src/main/java/io/dico/dicore/command/ExecutionContext.java
@@ -17,27 +17,32 @@ import java.util.*;
* It is also responsible for keeping track of the parameter to complete in the case of a tab completion.
*/
public class ExecutionContext {
- private CommandSender sender;
+ // Sender of the command
+ private final CommandSender sender;
+ // Address while parsing parameters with ContextParser
private ICommandAddress address;
+ // Command to execute
private Command command;
- private ArgumentBuffer originalBuffer;
- private ArgumentBuffer processedBuffer;
+ // if this flag is set, this execution is only for completion purposes.
+ private boolean tabComplete;
+
+ private final ArgumentBuffer buffer;
+ // private ArgumentBuffer processedBuffer;
// caches the buffer's cursor before parsing. This is needed to provide the original input of the player.
private int cursorStart;
// when the context starts parsing parameters, this flag is set, and any subsequent calls to #parseParameters() throw an IllegalStateException.
- private boolean attemptedToParse;
+ //private boolean attemptedToParse;
// The parsed parameter values, mapped by parameter name.
// This also includes default values. All parameters from the parameter list are present if parsing was successful.
- private Map parameterValueMap;
+ private Map parameterValueMap = new HashMap<>();
// this set contains the names of the parameters that were present in the command, and not given a default value.
- private Set parsedParameters;
+ private Set parsedParameters = new HashSet<>();
+
- // if this flag is set, this execution is only for completion purposes.
- private boolean tabComplete;
// these fields store information required to provide completions.
// the parameter to complete is the parameter that threw an exception when it was parsing.
// the exception's message was discarded because it is a completion.
@@ -48,37 +53,11 @@ public class ExecutionContext {
// if this flag is set, any messages sent through the sendMessage methods are discarded.
private boolean muted;
- public ExecutionContext(CommandSender sender, boolean tabComplete) {
+ public ExecutionContext(CommandSender sender, ArgumentBuffer buffer, boolean tabComplete) {
this.sender = Objects.requireNonNull(sender);
+ this.buffer = Objects.requireNonNull(buffer);
this.muted = tabComplete;
this.tabComplete = tabComplete;
- }
-
- /**
- * Construct an execution context that is ready to parse the parameter values.
- *
- * @param sender the sender
- * @param address the address
- * @param buffer the arguments
- * @param tabComplete true if this execution is a tab-completion
- */
- public ExecutionContext(CommandSender sender, ICommandAddress address, Command command, ArgumentBuffer buffer, boolean tabComplete) {
- this(sender, tabComplete);
- targetAcquired(address, command, buffer);
- }
-
- void requireAddressPresent(boolean present) {
- //noinspection DoubleNegation
- if ((address != null) != present) {
- throw new IllegalStateException();
- }
- }
-
- void targetAcquired(ICommandAddress address, Command command, ArgumentBuffer buffer) {
- requireAddressPresent(false);
-
- this.address = Objects.requireNonNull(address);
- this.command = Objects.requireNonNull(command);
// If its tab completing, keep the empty element that might be at the end of the buffer
// due to a space at the end of the command.
@@ -86,65 +65,21 @@ public class ExecutionContext {
if (!tabComplete) {
buffer.dropTrailingEmptyElements();
}
-
- this.originalBuffer = buffer;
- this.processedBuffer = buffer.preprocessArguments(getParameterList().getArgumentPreProcessor());
- this.cursorStart = buffer.getCursor();
}
/**
- * Parse the parameters. If no exception is thrown, they were parsed successfully, and the command may continue post-parameter execution.
+ * Construct an execution context that is ready to parse the parameter values.
*
- * @throws CommandException if an error occurs while parsing the parameters.
+ * @param sender the sender
+ * @param address the address
+ * @param command the command
+ * @param buffer the arguments
+ * @param tabComplete true if this execution is a tab-completion
*/
- synchronized void parseParameters() throws CommandException {
- requireAddressPresent(true);
- if (attemptedToParse) {
- throw new IllegalStateException();
- }
-
- attemptedToParse = true;
-
- ContextParser parser = new ContextParser(this);
-
- parameterValueMap = parser.getValueMap();
- parsedParameters = parser.getParsedKeys();
-
- parser.parse();
- }
-
-
- /**
- * Attempts to parse parameters, without throwing an exception or sending any message.
- * This method is typically used by tab completions.
- * After calling this method, the context is ready to provide completions.
- */
- synchronized void parseParametersQuietly() {
- requireAddressPresent(true);
- if (attemptedToParse) {
- throw new IllegalStateException();
- }
-
- attemptedToParse = true;
-
- boolean before = muted;
- muted = true;
- try {
- ContextParser parser = new ContextParser(this);
-
- parameterValueMap = parser.getValueMap();
- parsedParameters = parser.getParsedKeys();
-
- parser.parse();
-
- parameterToComplete = parser.getCompletionTarget();
- parameterToCompleteCursor = parser.getCompletionCursor();
-
- } catch (CommandException ignored) {
-
- } finally {
- muted = before;
- }
+ public ExecutionContext(CommandSender sender, ICommandAddress address, Command command, ArgumentBuffer buffer, boolean tabComplete) {
+ this(sender, buffer, tabComplete);
+ setAddress(address);
+ setCommand(command);
}
/**
@@ -156,6 +91,13 @@ public class ExecutionContext {
return sender;
}
+ /**
+ * @return the buffer of arguments
+ */
+ public ArgumentBuffer getBuffer() {
+ return buffer;
+ }
+
/**
* Command's address
*
@@ -165,6 +107,15 @@ public class ExecutionContext {
return address;
}
+ /**
+ * Set the address
+ *
+ * @param address the new address
+ */
+ public void setAddress(ICommandAddress address) {
+ this.address = address;
+ }
+
/**
* The command
*
@@ -174,13 +125,60 @@ public class ExecutionContext {
return command;
}
+ /**
+ * Set the command
+ *
+ * @param command the new command
+ */
+ public void setCommand(Command command) {
+ this.command = command;
+ }
+
+ /**
+ * @return true if this context is for a tab completion.
+ */
+ public boolean isTabComplete() {
+ return tabComplete;
+ }
+
+ /**
+ * @return true if this context is muted.
+ */
+ public boolean isMuted() {
+ return muted;
+ }
+
+ /**
+ * Parse parameters from the given parameter list,
+ * adding their values to the cache of this context.
+ *
+ * @param parameterList the parameterList
+ * @throws CommandException if the arguments are not valid
+ */
+ public void parse(ParameterList parameterList) throws CommandException {
+ cursorStart = buffer.getCursor();
+
+ ContextParser parser = new ContextParser(this, parameterList, parameterValueMap, parsedParameters);
+
+ try {
+ parser.parse();
+ } finally {
+ if (tabComplete) {
+ parameterToComplete = parser.getCompletionTarget();
+ parameterToCompleteCursor = parser.getCompletionCursor();
+ }
+ }
+
+ }
+
/**
* The command's parameter definition.
*
* @return the parameter list
*/
+ @Deprecated
public ParameterList getParameterList() {
- return command.getParameterList();
+ return null;//command.getParameterList();
}
/**
@@ -188,8 +186,9 @@ public class ExecutionContext {
*
* @return the original buffer
*/
+ @Deprecated
public ArgumentBuffer getOriginalBuffer() {
- return originalBuffer;
+ return buffer;
}
/**
@@ -197,8 +196,9 @@ public class ExecutionContext {
*
* @return the argument buffer
*/
+ @Deprecated
public ArgumentBuffer getProcessedBuffer() {
- return processedBuffer;
+ return buffer;
}
/**
@@ -216,7 +216,7 @@ public class ExecutionContext {
* @return original arguments.
*/
public String[] getOriginal() {
- return originalBuffer.getArrayFromIndex(cursorStart);
+ return buffer.getArrayFromIndex(cursorStart);
}
/**
@@ -225,7 +225,7 @@ public class ExecutionContext {
* @return the path used to access this address.
*/
public String[] getRoute() {
- return Arrays.copyOf(originalBuffer.toArray(), address.getDepth());
+ return Arrays.copyOf(buffer.toArray(), address.getDepth());
}
public Formatting getFormat(EMessageType type) {
@@ -238,9 +238,16 @@ public class ExecutionContext {
* @return the full command
*/
public String getRawInput() {
- return originalBuffer.getRawInput();
+ return buffer.getRawInput();
}
+ /**
+ * Get the value of the parameter with the given name
+ *
+ * @param name the parameter's name
+ * @param expected type
+ * @return the parsed value or the default value
+ */
@SuppressWarnings("unchecked")
public T get(String name) {
if (!parameterValueMap.containsKey(name)) {
@@ -254,15 +261,23 @@ public class ExecutionContext {
}
}
- @SuppressWarnings("unchecked")
- public T get(int index) {
- return get(getParameterList().getIndexedParameterName(index));
- }
-
+ /**
+ * Get the value of the flag with the given name
+ *
+ * @param flag the flag's name, without preceding "-"
+ * @param expected type
+ * @return the parsed value or the default value
+ */
public T getFlag(String flag) {
return get("-" + flag);
}
+ @SuppressWarnings("unchecked")
+ @Deprecated
+ public T get(int index) {
+ return null;//get(getParameterList().getIndexedParameterName(index));
+ }
+
/**
* Checks if the parameter by the name was provided in the command's arguments.
*
@@ -279,8 +294,9 @@ public class ExecutionContext {
* @param index the parameter index
* @return true if it was provided
*/
+ @Deprecated
public boolean isProvided(int index) {
- return isProvided(getParameterList().getIndexedParameterName(index));
+ return false;//isProvided(getParameterList().getIndexedParameterName(index));
}
/**
@@ -293,20 +309,6 @@ public class ExecutionContext {
return parameterToComplete;
}
- /**
- * @return true if this context is muted.
- */
- public boolean isMuted() {
- return muted;
- }
-
- /**
- * @return true if this context is for a tab completion.
- */
- public boolean isTabComplete() {
- return tabComplete;
- }
-
/**
* Get suggested completions.
*
@@ -315,19 +317,22 @@ public class ExecutionContext {
*/
public List getSuggestedCompletions(Location location) {
if (parameterToComplete != null) {
- return parameterToComplete.complete(this, location, processedBuffer.getUnaffectingCopy().setCursor(parameterToCompleteCursor));
+ return parameterToComplete.complete(this, location, buffer.getUnaffectingCopy().setCursor(parameterToCompleteCursor));
}
- ParameterList parameterList = getParameterList();
List result = new ArrayList<>();
for (String name : parameterValueMap.keySet()) {
- if (parameterList.getParameterByName(name).isFlag() && !parsedParameters.contains(name)) {
+ if (name.startsWith("-") && !parsedParameters.contains(name)) {
result.add(name);
}
}
return result;
}
+ /*
+ Chat handling
+ */
+
public void sendMessage(String message) {
sendMessage(true, message);
}
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/ExtendedCommand.java b/dicore3/command/src/main/java/io/dico/dicore/command/ExtendedCommand.java
index a34d30d..47c2aca 100644
--- a/dicore3/command/src/main/java/io/dico/dicore/command/ExtendedCommand.java
+++ b/dicore3/command/src/main/java/io/dico/dicore/command/ExtendedCommand.java
@@ -55,9 +55,10 @@ public abstract class ExtendedCommand> extends Comm
return modifiable ? (T) super.setShortDescription(shortDescription) : newModifiableInstance().setShortDescription(shortDescription);
}
+ /*
@Override
public T preprocessArguments(IArgumentPreProcessor processor) {
return modifiable ? (T) super.preprocessArguments(processor) : newModifiableInstance().preprocessArguments(processor);
- }
+ }*/
}
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/ICommandAddress.java b/dicore3/command/src/main/java/io/dico/dicore/command/ICommandAddress.java
index bef20e4..158b1f0 100644
--- a/dicore3/command/src/main/java/io/dico/dicore/command/ICommandAddress.java
+++ b/dicore3/command/src/main/java/io/dico/dicore/command/ICommandAddress.java
@@ -2,6 +2,7 @@ package io.dico.dicore.command;
import io.dico.dicore.command.chat.IChatHandler;
import io.dico.dicore.command.parameter.ArgumentBuffer;
+import io.dico.dicore.command.parameter.ParameterList;
import io.dico.dicore.command.predef.PredefinedCommand;
import org.bukkit.command.CommandSender;
@@ -131,6 +132,16 @@ public interface ICommandAddress {
* Get an unmodifiable view of the children of this address.
* Values might be duplicated for aliases.
*
+ *
+ * To iterate children without duplicates, you can do something like this:
+ *
{@code
+ * for (String key : address.getChildrenMainKeys()) {
+ * ICommandAddress child = address.getChild(key);
+ * // do stuff with child
+ * }
+ * }
+ *
+ *
* @return the children of this address.
*/
Map getChildren();
@@ -144,14 +155,19 @@ public interface ICommandAddress {
ICommandAddress getChild(String key);
/**
- * Query for a child at the given key, with the given context for reference.
- * Can be used to override behaviour of the tree.
+ * Query for a child using the given buffer, with the given context for reference.
+ * Can be used to override behaviour of the address tree.
+ *
+ * The default implementation is as follows:
+ *
{@code
+ * return buffer.hasNext() ? getChild(buffer.next()) : null;
+ * }
*
- * @param key the key. The name or alias of a command.
* @param context context of a command being executed
+ * @param buffer the buffer. The name or alias of a command.
* @return the child, or null if it's not found, altered freely by the implementation
*/
- ICommandAddress getChild(String key, ExecutionContext context) throws CommandException;
+ ICommandAddress getChild(ExecutionContext context, ArgumentBuffer buffer) throws CommandException;
/**
* Get the command dispatcher for this tree
@@ -165,6 +181,15 @@ public interface ICommandAddress {
*/
IChatHandler getChatHandler();
+ /**
+ * Returns if the command attached to this address should be treated as trailing.
+ * A trailing command is executed whenever the address is scanned for children.
+ * Its parameters are parsed and added to the context.
+ *
+ * @return true if the command attached to this address should be treated as trailing.
+ */
+ boolean isCommandTrailing();
+
static ICommandAddress newChild() {
return new ChildCommandAddress();
}
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/ICommandReceiver.java b/dicore3/command/src/main/java/io/dico/dicore/command/ICommandReceiver.java
deleted file mode 100644
index 6660bf8..0000000
--- a/dicore3/command/src/main/java/io/dico/dicore/command/ICommandReceiver.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package io.dico.dicore.command;
-
-import org.bukkit.plugin.Plugin;
-
-import java.lang.reflect.Method;
-
-public interface ICommandReceiver {
-
- interface Factory {
-
- ICommandReceiver getReceiver(ExecutionContext context, Method target, String cmdName);
-
- Plugin getPlugin();
-
- // type is CoroutineContext, but we avoid referring to Kotlin runtime here
- default Object getCoroutineContext() {
- return null;
- }
-
- }
-
-}
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/ModifiableCommandAddress.java b/dicore3/command/src/main/java/io/dico/dicore/command/ModifiableCommandAddress.java
index 0c4c476..0cfd755 100644
--- a/dicore3/command/src/main/java/io/dico/dicore/command/ModifiableCommandAddress.java
+++ b/dicore3/command/src/main/java/io/dico/dicore/command/ModifiableCommandAddress.java
@@ -2,6 +2,8 @@ package io.dico.dicore.command;
import io.dico.dicore.command.chat.ChatHandlers;
import io.dico.dicore.command.chat.IChatHandler;
+import io.dico.dicore.command.parameter.ArgumentBuffer;
+import io.dico.dicore.command.parameter.ParameterList;
import io.dico.dicore.command.predef.DefaultGroupCommand;
import io.dico.dicore.command.predef.HelpCommand;
import io.dico.dicore.command.predef.PredefinedCommand;
@@ -36,7 +38,7 @@ public abstract class ModifiableCommandAddress implements ICommandAddress {
@Override
public boolean hasUserDeclaredCommand() {
Command command = getCommand();
- return command != null && !(command instanceof PredefinedCommand) && !(command instanceof DefaultGroupCommand);
+ return command != null && !(command instanceof PredefinedCommand);
}
@Override
@@ -139,8 +141,8 @@ public abstract class ModifiableCommandAddress implements ICommandAddress {
}
@Override
- public ChildCommandAddress getChild(String key, ExecutionContext context) throws CommandException {
- return getChild(key);
+ public ChildCommandAddress getChild(ExecutionContext context, ArgumentBuffer buffer) throws CommandException {
+ return buffer.hasNext() ? getChild(buffer.next()) : null;
}
public void addChild(ICommandAddress child) {
@@ -264,6 +266,15 @@ public abstract class ModifiableCommandAddress implements ICommandAddress {
return getRoot();
}
+ @Override
+ public boolean isCommandTrailing() {
+ return false;
+ }
+
+ public void setCommandTrailing(boolean trailing) {
+ throw new UnsupportedOperationException();
+ }
+
void appendDebugInformation(StringBuilder target, String linePrefix, Set seen) {
target.append('\n').append(linePrefix);
if (!seen.add(this)) {
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/PermissionContextFilter.java b/dicore3/command/src/main/java/io/dico/dicore/command/PermissionContextFilter.java
index 3ca1131..75b2035 100644
--- a/dicore3/command/src/main/java/io/dico/dicore/command/PermissionContextFilter.java
+++ b/dicore3/command/src/main/java/io/dico/dicore/command/PermissionContextFilter.java
@@ -1,5 +1,6 @@
package io.dico.dicore.command;
+import java.util.List;
import java.util.Objects;
public class PermissionContextFilter implements IContextFilter {
@@ -106,4 +107,30 @@ public class PermissionContextFilter implements IContextFilter {
return failMessage;
}
+ /*
+ private fun getPermissionsOf(address: ICommandAddress) = getPermissionsOf(address, emptyArray(), mutableListOf())
+
+ private fun getPermissionsOf(address: ICommandAddress, path: Array, result: MutableList): List {
+ val command = address.command ?: return result
+
+ var inherited = false
+ for (filter in command.contextFilters) {
+ when (filter) {
+ is PermissionContextFilter -> {
+ if (path.isEmpty()) result.add(filter.permission)
+ else if (filter.isInheritable) result.add(filter.getInheritedPermission(path))
+ }
+ is InheritingContextFilter -> {
+ if (filter.priority == PERMISSION && address.hasParent() && !inherited) {
+ inherited = true
+ getPermissionsOf(address.parent, arrayOf(address.mainKey, *path), result)
+ }
+ }
+ }
+ }
+
+ return result
+ }
+ */
+
}
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/RootCommandAddress.java b/dicore3/command/src/main/java/io/dico/dicore/command/RootCommandAddress.java
index 10dade5..44f0540 100644
--- a/dicore3/command/src/main/java/io/dico/dicore/command/RootCommandAddress.java
+++ b/dicore3/command/src/main/java/io/dico/dicore/command/RootCommandAddress.java
@@ -85,7 +85,8 @@ public class RootCommandAddress extends ModifiableCommandAddress implements ICom
}
}
- private static void registerMember(Map map, String key, org.bukkit.command.Command value, boolean override) {
+ private static void registerMember(Map map,
+ String key, org.bukkit.command.Command value, boolean override) {
if (override) {
map.put(key, value);
} else {
@@ -147,15 +148,25 @@ public class RootCommandAddress extends ModifiableCommandAddress implements ICom
ModifiableCommandAddress cur = this;
ChildCommandAddress child;
while (buffer.hasNext()) {
- child = cur.getChild(buffer.next(), context);
+ int cursor = buffer.getCursor();
+
+ child = cur.getChild(context, buffer);
+
if (child == null
+ || (context.isTabComplete() && !buffer.hasNext())
|| (child.hasCommand() && !child.getCommand().isVisibleTo(sender))
|| (cur.hasCommand() && cur.getCommand().takePrecedenceOverSubcommand(buffer.peekPrevious(), buffer.getUnaffectingCopy()))) {
- buffer.rewind();
+ buffer.setCursor(cursor);
break;
}
cur = child;
+
+ context.setAddress(child);
+ if (child.hasCommand() && child.isCommandTrailing()) {
+ child.getCommand().initializeAndFilterContext(context);
+ child.getCommand().execute(context.getSender(), context);
+ }
}
return cur;
@@ -173,7 +184,7 @@ public class RootCommandAddress extends ModifiableCommandAddress implements ICom
@Override
public boolean dispatchCommand(CommandSender sender, ArgumentBuffer buffer) {
- ExecutionContext context = new ExecutionContext(sender, false);
+ ExecutionContext context = new ExecutionContext(sender, buffer, false);
ModifiableCommandAddress targetAddress = null;
@@ -189,8 +200,15 @@ public class RootCommandAddress extends ModifiableCommandAddress implements ICom
}
}
- context.targetAcquired(targetAddress, target, buffer);
- target.executeWithContext(context);
+ context.setCommand(target);
+
+ if (!targetAddress.isCommandTrailing()) {
+ target.initializeAndFilterContext(context);
+ String message = target.execute(sender, context);
+ if (message != null && !message.isEmpty()) {
+ context.sendMessage(EMessageType.RESULT, message);
+ }
+ }
} catch (Throwable t) {
if (targetAddress == null) {
@@ -214,15 +232,16 @@ public class RootCommandAddress extends ModifiableCommandAddress implements ICom
@Override
public List getTabCompletions(CommandSender sender, Location location, ArgumentBuffer buffer) {
- ExecutionContext context = new ExecutionContext(sender, true);
+ ExecutionContext context = new ExecutionContext(sender, buffer, true);
try {
ICommandAddress target = getCommandTarget(context, buffer);
List out;
if (target.hasCommand()) {
- context.targetAcquired(target, target.getCommand(), buffer);
- out = target.getCommand().tabCompleteWithContext(context, location);
+ context.setCommand(target.getCommand());
+ target.getCommand().initializeAndFilterContext(context);
+ out = target.getCommand().tabComplete(sender, context, location);
} else {
out = Collections.emptyList();
}
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/annotation/PreprocessArgs.java b/dicore3/command/src/main/java/io/dico/dicore/command/annotation/PreprocessArgs.java
index 40d6d73..57f53bd 100644
--- a/dicore3/command/src/main/java/io/dico/dicore/command/annotation/PreprocessArgs.java
+++ b/dicore3/command/src/main/java/io/dico/dicore/command/annotation/PreprocessArgs.java
@@ -7,6 +7,7 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
+@Deprecated
public @interface PreprocessArgs {
String tokens() default "\"\"";
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/chat/help/defaults/DefaultPageBuilder.java b/dicore3/command/src/main/java/io/dico/dicore/command/chat/help/defaults/DefaultPageBuilder.java
index f5b7cdb..a584e7e 100644
--- a/dicore3/command/src/main/java/io/dico/dicore/command/chat/help/defaults/DefaultPageBuilder.java
+++ b/dicore3/command/src/main/java/io/dico/dicore/command/chat/help/defaults/DefaultPageBuilder.java
@@ -13,7 +13,8 @@ import java.util.ListIterator;
public class DefaultPageBuilder implements IPageBuilder {
@Override
- public String getPage(List helpTopics, IPageLayout pageLayout, ICommandAddress target, Permissible viewer, ExecutionContext context, int pageNum, int pageLen) {
+ public String getPage(List helpTopics, IPageLayout pageLayout, ICommandAddress target,
+ Permissible viewer, ExecutionContext context, int pageNum, int pageLen) {
if (pageLen <= 0 || pageNum < 0) {
throw new IllegalArgumentException();
}
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/chat/help/insertion/HelpComponentInserter.java b/dicore3/command/src/main/java/io/dico/dicore/command/chat/help/insertion/HelpComponentInserter.java
index b043deb..f153165 100644
--- a/dicore3/command/src/main/java/io/dico/dicore/command/chat/help/insertion/HelpComponentInserter.java
+++ b/dicore3/command/src/main/java/io/dico/dicore/command/chat/help/insertion/HelpComponentInserter.java
@@ -19,7 +19,7 @@ public class HelpComponentInserter extends HelpTopicModifier {
@Override
protected List modify(List components, ICommandAddress target, Permissible viewer, ExecutionContext context) {
- int componentCount = components.size();
+ // int componentCount = components.size();
for (int i = insertions.size() - 1; i >= 0; i--) {
IInsertion insertion = insertions.get(i);
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/parameter/ArgumentBuffer.java b/dicore3/command/src/main/java/io/dico/dicore/command/parameter/ArgumentBuffer.java
index e063000..aa69730 100644
--- a/dicore3/command/src/main/java/io/dico/dicore/command/parameter/ArgumentBuffer.java
+++ b/dicore3/command/src/main/java/io/dico/dicore/command/parameter/ArgumentBuffer.java
@@ -1,6 +1,8 @@
package io.dico.dicore.command.parameter;
import io.dico.dicore.command.CommandException;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.*;
@@ -23,7 +25,7 @@ public class ArgumentBuffer extends AbstractList implements Iterator implements Iterator implements Iterator implements Iterator implements Iterator implements Iterator iterator() {
+ public @NotNull Iterator iterator() {
return this;
}
@Override
- public ListIterator listIterator() {
+ public @NotNull ListIterator listIterator() {
return new ListIterator() {
@Override
public boolean hasNext() {
@@ -243,13 +250,14 @@ public class ArgumentBuffer extends AbstractList implements Iterator implements Iterator= 0 && foundSectionCount >= count) return false;
+
while (currentIndex < args.length) {
String arg = args[currentIndex];
if (arg == null) {
@@ -127,9 +132,11 @@ public class ArgumentMergingPreProcessor implements IArgumentPreProcessor {
sectionStart = -1;
sectionEnd = -1;
+
+ ++foundSectionCount;
}
- public String[] doProcess() {
+ String[] doProcess() {
reset();
while (findNextSectionStart()) {
@@ -155,6 +162,14 @@ public class ArgumentMergingPreProcessor implements IArgumentPreProcessor {
return result;
}
+ void updateBuffer(ArgumentBuffer buffer) {
+ if (count < 0) {
+ buffer.setCursor(start);
+ } else {
+ buffer.setCursor(currentIndex);
+ }
+ }
+
}
}
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/parameter/ContextParser.java b/dicore3/command/src/main/java/io/dico/dicore/command/parameter/ContextParser.java
index 3bfcf9b..a5afce5 100644
--- a/dicore3/command/src/main/java/io/dico/dicore/command/parameter/ContextParser.java
+++ b/dicore3/command/src/main/java/io/dico/dicore/command/parameter/ContextParser.java
@@ -13,21 +13,27 @@ public class ContextParser {
private final Parameter, ?> m_repeatedParam;
private final List> m_indexedParams;
private final int m_maxIndex;
- private final int m_requiredIndex;
+ private final int m_maxRequiredIndex;
- private Map m_valueMap = new HashMap<>();
- private Set m_parsedKeys = new HashSet<>();
+ private Map m_valueMap;
+ private Set m_parsedKeys;
private int m_completionCursor = -1;
private Parameter, ?> m_completionTarget = null;
- public ContextParser(ExecutionContext context) {
- this.m_context = context;
- this.m_buffer = context.getProcessedBuffer();
- this.m_paramList = context.getParameterList();
- this.m_repeatedParam = m_paramList.getRepeatedParameter();
- this.m_indexedParams = m_paramList.getIndexedParameters();
- this.m_maxIndex = m_indexedParams.size() - 1;
- this.m_requiredIndex = m_paramList.getRequiredCount() - 1;
+ public ContextParser(ExecutionContext context,
+ ParameterList parameterList,
+ Map valueMap,
+ Set keySet) {
+ m_context = context;
+ m_paramList = parameterList;
+ m_valueMap = valueMap;
+ m_parsedKeys = keySet;
+
+ m_buffer = context.getBuffer();
+ m_repeatedParam = m_paramList.getRepeatedParameter();
+ m_indexedParams = m_paramList.getIndexedParameters();
+ m_maxIndex = m_indexedParams.size() - 1;
+ m_maxRequiredIndex = m_paramList.getRequiredCount() - 1;
}
public ExecutionContext getContext() {
@@ -102,7 +108,7 @@ public class ContextParser {
m_curParamIndex++;
m_curParam = m_indexedParams.get(m_curParamIndex);
prepareRepeatedParameterIfSet();
- requireInput = m_curParamIndex <= m_requiredIndex;
+ requireInput = m_curParamIndex <= m_maxRequiredIndex;
} else if (m_buffer.hasNext()) {
throw new CommandException("Too many arguments for /" + m_context.getAddress().getAddress());
@@ -146,7 +152,7 @@ public class ContextParser {
private void prepareRepeatedParameterIfSet() throws CommandException {
if (m_curParam != null && m_curParam == m_repeatedParam) {
- if (m_curParam.isFlag() && m_curParamIndex < m_requiredIndex) {
+ if (m_curParam.isFlag() && m_curParamIndex < m_maxRequiredIndex) {
Parameter, ?> requiredParam = m_indexedParams.get(m_curParamIndex + 1);
reportParameterRequired(requiredParam);
}
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/parameter/IArgumentPreProcessor.java b/dicore3/command/src/main/java/io/dico/dicore/command/parameter/IArgumentPreProcessor.java
index b112367..0b8198e 100644
--- a/dicore3/command/src/main/java/io/dico/dicore/command/parameter/IArgumentPreProcessor.java
+++ b/dicore3/command/src/main/java/io/dico/dicore/command/parameter/IArgumentPreProcessor.java
@@ -3,19 +3,26 @@ package io.dico.dicore.command.parameter;
/**
* An interface to process tokens such as quotes
*/
+@Deprecated
public interface IArgumentPreProcessor {
/**
- * Preprocess the arguments without modifying the array.
- * Might return the same array (in which case no changes were made).
+ * Preprocess the arguments contained within the given ArgumentBuffer.
+ * If no changes are made, this might return the same buffer.
+ * Any arguments preceding {@code buffer.getCursor()} will not be affected.
*
- * @param argStart the index within the array where the given arguments start (the part before that identifies the command)
- * @param args the arguments
+ *
+ * If {@code count} is non-negative, it declares a limit on the number of arguments after preprocessing.
+ * In that case, the buffer's cursor is set to the index of the first argument following processed arguments.
+ *
+ *
+ * @param buffer the argument buffer
+ * @param count the maximum number of (processed) arguments
* @return the arguments after preprocessing
*/
- String[] process(int argStart, String[] args);
+ ArgumentBuffer process(ArgumentBuffer buffer, int count);
- IArgumentPreProcessor NONE = (argStart, args) -> args;
+ IArgumentPreProcessor NONE = (buffer, count) -> buffer;
/**
* Get an IArgumentPreProcessor that merges arguments between any two tokens
@@ -31,3 +38,4 @@ public interface IArgumentPreProcessor {
}
}
+
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/parameter/ParameterList.java b/dicore3/command/src/main/java/io/dico/dicore/command/parameter/ParameterList.java
index 459ced5..613d057 100644
--- a/dicore3/command/src/main/java/io/dico/dicore/command/parameter/ParameterList.java
+++ b/dicore3/command/src/main/java/io/dico/dicore/command/parameter/ParameterList.java
@@ -5,10 +5,12 @@ import java.util.*;
/**
* IParameter definition for a command
*/
+@SuppressWarnings("UnusedReturnValue")
public class ParameterList {
+ //private ParameterList parent;
private List> indexedParameters;
private Map> byName;
- private IArgumentPreProcessor argumentPreProcessor = IArgumentPreProcessor.NONE;
+ //private IArgumentPreProcessor argumentPreProcessor = IArgumentPreProcessor.NONE;
private int requiredCount = -1;
private boolean repeatFinalParameter;
@@ -18,12 +20,22 @@ public class ParameterList {
// parameter is taken for repeating
private boolean finalParameterMayBeFlag;
+ /*
+ public ParameterList(ParameterList parent) {
+ this();
+ if (parent.repeatFinalParameter) {
+ throw new IllegalArgumentException("Parent may not have repeating parameters");
+ }
+ this.parent = parent;
+ }*/
+
public ParameterList() {
this.indexedParameters = new ArrayList<>();
this.byName = new LinkedHashMap<>();
this.repeatFinalParameter = false;
}
+ /*
public IArgumentPreProcessor getArgumentPreProcessor() {
return argumentPreProcessor;
}
@@ -31,7 +43,7 @@ public class ParameterList {
public ParameterList setArgumentPreProcessor(IArgumentPreProcessor argumentPreProcessor) {
this.argumentPreProcessor = argumentPreProcessor == null ? IArgumentPreProcessor.NONE : argumentPreProcessor;
return this;
- }
+ }*/
public boolean repeatFinalParameter() {
return repeatFinalParameter;
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/parameter/type/EnumParameterType.java b/dicore3/command/src/main/java/io/dico/dicore/command/parameter/type/EnumParameterType.java
index e71c6cc..c23e09b 100644
--- a/dicore3/command/src/main/java/io/dico/dicore/command/parameter/type/EnumParameterType.java
+++ b/dicore3/command/src/main/java/io/dico/dicore/command/parameter/type/EnumParameterType.java
@@ -20,7 +20,8 @@ public class EnumParameterType extends SimpleParameterType parameter, CommandSender sender, String input) throws CommandException {
+ @Override
+ protected E parse(Parameter parameter, CommandSender sender, String input) throws CommandException {
for (E constant : universe) {
if (constant.name().equalsIgnoreCase(input)) {
return constant;
@@ -30,7 +31,8 @@ public class EnumParameterType extends SimpleParameterType complete(Parameter parameter, CommandSender sender, Location location, ArgumentBuffer buffer) {
+ @Override
+ public List complete(Parameter parameter, CommandSender sender, Location location, ArgumentBuffer buffer) {
String input = buffer.next().toUpperCase();
List result = new ArrayList<>();
for (E constant : universe) {
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/parameter/type/ParameterType.java b/dicore3/command/src/main/java/io/dico/dicore/command/parameter/type/ParameterType.java
index d89fd10..e1a62fa 100644
--- a/dicore3/command/src/main/java/io/dico/dicore/command/parameter/type/ParameterType.java
+++ b/dicore3/command/src/main/java/io/dico/dicore/command/parameter/type/ParameterType.java
@@ -146,56 +146,4 @@ public abstract class ParameterType {
}
- public @interface Reference {
-
- /**
- * The path to the static field holding the parameter type referred.
- *
- * @return The path
- */
- String value();
- }
-
- public static class ReferenceUtil {
-
- private ReferenceUtil() {
-
- }
-
-
- /**
- * Get the ParameterType with the associated Reference
- *
- * @param ref the reference
- * @return the parameter type object
- * @throws IllegalArgumentException if the class is found, but the field doesn't exist.
- * @throws IllegalStateException if this method fails to find the object for any other reason
- */
- public static Object getReference(Reference ref) {
- String[] path = ref.value().split("\\.");
- if (path.length < 2) {
- throw new IllegalStateException();
- }
-
- String fieldName = path[path.length - 1];
- String className = String.join(".", Arrays.copyOfRange(path, 0, path.length - 1));
-
- Class> clazz;
- try {
- clazz = Class.forName(className);
- } catch (ClassNotFoundException ex) {
- throw new IllegalArgumentException(ex);
- }
-
- Object result = Reflection.getStaticFieldValue(clazz, fieldName);
-
- if (result == null) {
- throw new IllegalStateException();
- }
-
- return result;
- }
-
- }
-
}
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/predef/DefaultGroupCommand.java b/dicore3/command/src/main/java/io/dico/dicore/command/predef/DefaultGroupCommand.java
index 3988da2..e664cef 100644
--- a/dicore3/command/src/main/java/io/dico/dicore/command/predef/DefaultGroupCommand.java
+++ b/dicore3/command/src/main/java/io/dico/dicore/command/predef/DefaultGroupCommand.java
@@ -38,9 +38,9 @@ public class DefaultGroupCommand extends PredefinedCommand
noArgumentFilter = new IContextFilter() {
@Override
public void filterContext(ExecutionContext context) throws CommandException {
- if (context.getProcessedBuffer().hasNext()) {
+ if (context.getBuffer().hasNext()) {
throw new CommandException("No such command: /" + context.getAddress().getAddress()
- + " " + context.getProcessedBuffer().next());
+ + " " + context.getBuffer().next());
}
}
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/registration/reflect/ICommandInterceptor.java b/dicore3/command/src/main/java/io/dico/dicore/command/registration/reflect/ICommandInterceptor.java
new file mode 100644
index 0000000..67b65e4
--- /dev/null
+++ b/dicore3/command/src/main/java/io/dico/dicore/command/registration/reflect/ICommandInterceptor.java
@@ -0,0 +1,36 @@
+package io.dico.dicore.command.registration.reflect;
+
+import io.dico.dicore.command.ExecutionContext;
+
+import java.lang.reflect.Method;
+
+public interface ICommandInterceptor {
+
+ /**
+ * Get the receiver of the command, if applicable.
+ * A command has a receiver if its first parameter implements {@link ICommandReceiver}
+ * and its instance object implements this interface.
+ *
+ * @param context the context of execution
+ * @param target the method of the command
+ * @param cmdName the name of the command
+ * @return the receiver
+ */
+ default ICommandReceiver getReceiver(ExecutionContext context, Method target, String cmdName) {
+ return null;
+ }
+
+ /**
+ * If applicable, get the coroutine context to use in suspend functions (Kotlin only).
+ * The return type is object to avoid depending on the kotlin runtime.
+ *
+ * @param context the context of execution
+ * @param target the method of the command
+ * @param cmdName the name of the command
+ * @return the coroutine context
+ */
+ default Object getCoroutineContext(ExecutionContext context, Method target, String cmdName) {
+ return null;
+ }
+
+}
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/registration/reflect/ICommandReceiver.java b/dicore3/command/src/main/java/io/dico/dicore/command/registration/reflect/ICommandReceiver.java
new file mode 100644
index 0000000..bdcb568
--- /dev/null
+++ b/dicore3/command/src/main/java/io/dico/dicore/command/registration/reflect/ICommandReceiver.java
@@ -0,0 +1,5 @@
+package io.dico.dicore.command.registration.reflect;
+
+public interface ICommandReceiver {
+
+}
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/registration/reflect/ReflectiveCommand.java b/dicore3/command/src/main/java/io/dico/dicore/command/registration/reflect/ReflectiveCommand.java
index 591d824..ee90efe 100644
--- a/dicore3/command/src/main/java/io/dico/dicore/command/registration/reflect/ReflectiveCommand.java
+++ b/dicore3/command/src/main/java/io/dico/dicore/command/registration/reflect/ReflectiveCommand.java
@@ -15,6 +15,8 @@ public final class ReflectiveCommand extends Command {
private final Method method;
private final Object instance;
private String[] parameterOrder;
+
+ // hasContinuation | hasContext | hasSender | hasReceiver
private final int flags;
ReflectiveCommand(IParameterTypeSelector selector, Method method, Object instance) throws CommandParseException {
@@ -56,6 +58,8 @@ public final class ReflectiveCommand extends Command {
return instance;
}
+ public String getCmdName() { return cmdAnnotation.value(); }
+
void setParameterOrder(String[] parameterOrder) {
this.parameterOrder = parameterOrder;
}
@@ -86,18 +90,24 @@ public final class ReflectiveCommand extends Command {
Object[] args = new Object[parameterOrder.length + start];
int i = 0;
- if ((flags & 1) != 0) {
+
+ int mask = 1;
+ if ((flags & mask) != 0) {
try {
- args[i++] = ((ICommandReceiver.Factory) instance).getReceiver(context, method, cmdAnnotation.value());
+ args[i++] = ((ICommandInterceptor) instance).getReceiver(context, method, getCmdName());
} catch (Exception ex) {
handleException(ex);
return null; // unreachable
}
}
- if ((flags & 2) != 0) {
+
+ mask <<= 1;
+ if ((flags & mask) != 0) {
args[i++] = sender;
}
- if ((flags & 4) != 0) {
+
+ mask <<= 1;
+ if ((flags & mask) != 0) {
args[i++] = context;
}
@@ -105,11 +115,12 @@ public final class ReflectiveCommand extends Command {
args[i] = context.get(parameterOrder[i - start]);
}
- if (!isSuspendFunction()) {
- return callSynchronously(args);
+ mask <<= 1;
+ if ((flags & mask) != 0) {
+ return callAsCoroutine(context, args);
}
- return callAsCoroutine(context, args);
+ return callSynchronously(args);
}
private boolean isSuspendFunction() {
@@ -137,9 +148,6 @@ public final class ReflectiveCommand extends Command {
if (returned instanceof String) {
return (String) returned;
}
- if (returned instanceof CommandResult) {
- return ((CommandResult) returned).getMessage();
- }
return null;
}
@@ -160,7 +168,7 @@ public final class ReflectiveCommand extends Command {
}
private String callAsCoroutine(ExecutionContext context, Object[] args) {
- return KotlinReflectiveRegistrationKt.callAsCoroutine(this, (ICommandReceiver.Factory) instance, context, args);
+ return KotlinReflectiveRegistrationKt.callAsCoroutine(this, (ICommandInterceptor) instance, context, args);
}
}
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/registration/reflect/ReflectiveRegistration.java b/dicore3/command/src/main/java/io/dico/dicore/command/registration/reflect/ReflectiveRegistration.java
index 1279c2b..1405414 100644
--- a/dicore3/command/src/main/java/io/dico/dicore/command/registration/reflect/ReflectiveRegistration.java
+++ b/dicore3/command/src/main/java/io/dico/dicore/command/registration/reflect/ReflectiveRegistration.java
@@ -3,7 +3,6 @@ package io.dico.dicore.command.registration.reflect;
import io.dico.dicore.command.*;
import io.dico.dicore.command.annotation.*;
import io.dico.dicore.command.annotation.GroupMatchedCommands.GroupEntry;
-import io.dico.dicore.command.parameter.IArgumentPreProcessor;
import io.dico.dicore.command.parameter.Parameter;
import io.dico.dicore.command.parameter.ParameterList;
import io.dico.dicore.command.parameter.type.IParameterTypeSelector;
@@ -199,15 +198,20 @@ public class ReflectiveRegistration {
static int parseCommandAttributes(IParameterTypeSelector selector, Method method, ReflectiveCommand command, java.lang.reflect.Parameter[] parameters) throws CommandParseException {
ParameterList list = command.getParameterList();
+
boolean hasReceiverParameter = false;
boolean hasSenderParameter = false;
+ boolean hasContextParameter = false;
+ boolean hasContinuationParameter = false;
+
int start = 0;
- Class> firstParameterType = null;
+ int end = parameters.length;
+
Class> senderParameterType = null;
if (parameters.length > start
- && command.getInstance() instanceof ICommandReceiver.Factory
- && ICommandReceiver.class.isAssignableFrom(firstParameterType = parameters[start].getType())) {
+ && command.getInstance() instanceof ICommandInterceptor
+ && ICommandReceiver.class.isAssignableFrom(parameters[start].getType())) {
hasReceiverParameter = true;
start++;
}
@@ -217,20 +221,18 @@ public class ReflectiveRegistration {
start++;
}
- boolean hasContextParameter = false;
if (parameters.length > start && parameters[start].getType() == ExecutionContext.class) {
hasContextParameter = true;
start++;
}
+ if (parameters.length > start && parameters[end - 1].getType().getName().equals("kotlin.coroutines.Continuation")) {
+ hasContinuationParameter = true;
+ end--;
+ }
+
String[] parameterNames = lookupParameterNames(method, parameters, start);
- for (int i = start, n = parameters.length; i < n; i++) {
- if (parameters[i].getType().getName().equals("kotlin.coroutines.Continuation")) {
- List temp = new ArrayList<>(Arrays.asList(parameterNames));
- temp.remove(i - start);
- parameterNames = temp.toArray(new String[0]);
- continue;
- }
+ for (int i = start, n = end; i < n; i++) {
Parameter, ?> parameter = parseParameter(selector, method, parameters[i], parameterNames[i - start]);
list.addParameter(parameter);
}
@@ -256,11 +258,12 @@ public class ReflectiveRegistration {
list.setRequiredCount(list.getIndexedParameters().size());
}
+ /*
PreprocessArgs preprocessArgs = method.getAnnotation(PreprocessArgs.class);
if (preprocessArgs != null) {
IArgumentPreProcessor preProcessor = IArgumentPreProcessor.mergeOnTokens(preprocessArgs.tokens(), preprocessArgs.escapeChar());
list.setArgumentPreProcessor(preProcessor);
- }
+ }*/
Desc desc = method.getAnnotation(Desc.class);
if (desc != null) {
@@ -286,7 +289,16 @@ public class ReflectiveRegistration {
list.setRepeatFinalParameter(parameters.length > start && parameters[parameters.length - 1].isVarArgs());
list.setFinalParameterMayBeFlag(true);
- return (hasSenderParameter ? 2 : 0) | (hasContextParameter ? 4 : 0) | (hasReceiverParameter ? 1 : 0);
+
+ int flags = 0;
+ if (hasContinuationParameter) flags |= 1;
+ flags <<= 1;
+ if (hasContextParameter) flags |= 1;
+ flags <<= 1;
+ if (hasSenderParameter) flags |= 1;
+ flags <<= 1;
+ if (hasReceiverParameter) flags |= 1;
+ return flags;
}
public static int parseCommandAttributes(IParameterTypeSelector selector, Method method, ReflectiveCommand command) throws CommandParseException {
@@ -373,7 +385,7 @@ public class ReflectiveRegistration {
@Cmd({"tp", "tpto"})
@RequirePermissions("teleport.self")
- public (static) String|void|CommandResult onCommand(Player sender, Player target, @Flag("force", permission = "teleport.self.force") boolean force) {
+ public (static) String|void onCommand(Player sender, Player target, @Flag("force", permission = "teleport.self.force") boolean force) {
Validate.isTrue(force || !hasTpToggledOff(target), "Target has teleportation disabled. Use -force to ignore");
sender.teleport(target);
//return
diff --git a/dicore3/command/src/main/kotlin/io/dico/dicore/command/registration/reflect/KotlinReflectiveRegistration.kt b/dicore3/command/src/main/kotlin/io/dico/dicore/command/registration/reflect/KotlinReflectiveRegistration.kt
index c4aa134..2ef6e39 100644
--- a/dicore3/command/src/main/kotlin/io/dico/dicore/command/registration/reflect/KotlinReflectiveRegistration.kt
+++ b/dicore3/command/src/main/kotlin/io/dico/dicore/command/registration/reflect/KotlinReflectiveRegistration.kt
@@ -1,9 +1,6 @@
package io.dico.dicore.command.registration.reflect
-import io.dico.dicore.command.CommandException
-import io.dico.dicore.command.EMessageType
-import io.dico.dicore.command.ExecutionContext
-import io.dico.dicore.command.ICommandReceiver
+import io.dico.dicore.command.*
import kotlinx.coroutines.CoroutineStart.UNDISPATCHED
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.GlobalScope
@@ -22,15 +19,16 @@ fun isSuspendFunction(method: Method): Boolean {
fun callAsCoroutine(
command: ReflectiveCommand,
- factory: ICommandReceiver.Factory,
+ factory: ICommandInterceptor,
context: ExecutionContext,
args: Array
): String? {
+ val coroutineContext = factory.getCoroutineContext(context, command.method, command.cmdName) as CoroutineContext
// UNDISPATCHED causes the handler to run until the first suspension point on the current thread,
// meaning command handlers that don't have suspension points will run completely synchronously.
// Tasks that take time to compute should suspend the coroutine and resume on another thread.
- val job = GlobalScope.async(context = factory.coroutineContext as CoroutineContext, start = UNDISPATCHED) {
+ val job = GlobalScope.async(context = coroutineContext, start = UNDISPATCHED) {
suspendCoroutineUninterceptedOrReturn { cont ->
command.method.invoke(command.instance, *args, cont.intercepted())
}
@@ -41,12 +39,12 @@ fun callAsCoroutine(
}
job.invokeOnCompletion {
- val cc = context.address.chatHandler
+ val chatHandler = context.address.chatHandler
try {
val result = job.getResult()
- cc.sendMessage(context.sender, EMessageType.RESULT, result)
+ chatHandler.sendMessage(context.sender, EMessageType.RESULT, result)
} catch (ex: Throwable) {
- cc.handleException(context.sender, context, ex)
+ chatHandler.handleException(context.sender, context, ex)
}
}
diff --git a/dicore3/command/src/test/java/io/dico/dicore/command/example/ParameterInfoObjectExample.java b/dicore3/command/src/test/java/io/dico/dicore/command/example/ParameterInfoObjectExample.java
new file mode 100644
index 0000000..1cd4e23
--- /dev/null
+++ b/dicore3/command/src/test/java/io/dico/dicore/command/example/ParameterInfoObjectExample.java
@@ -0,0 +1,73 @@
+package io.dico.dicore.command.example;
+
+import io.dico.dicore.command.CommandBuilder;
+import io.dico.dicore.command.CommandException;
+import io.dico.dicore.command.Validate;
+import io.dico.dicore.command.annotation.Cmd;
+import io.dico.dicore.command.parameter.ArgumentBuffer;
+import io.dico.dicore.command.parameter.Parameter;
+import io.dico.dicore.command.parameter.type.ParameterConfig;
+import io.dico.dicore.command.parameter.type.ParameterType;
+import org.bukkit.command.CommandSender;
+
+public class ParameterInfoObjectExample {
+
+ private @interface ParentPermission {
+ String value();
+ }
+
+ static class MyInfoObject {
+ public static final ParameterConfig config = new ParameterConfig() {
+ @Override
+ protected MyInfoObject toParameterInfo(ParentPermission annotation) {
+ return new MyInfoObject(annotation.value());
+ }
+ };
+
+ private String permissionParent;
+
+ MyInfoObject(String permissionParent) {
+ this.permissionParent = permissionParent;
+ }
+
+ public String getPermissionParent() {
+ return permissionParent;
+ }
+ }
+
+ static class MyParameterType extends ParameterType {
+
+ public MyParameterType() {
+ super(String.class, MyInfoObject.config);
+ }
+
+ @Override
+ public String parse(Parameter parameter, CommandSender sender, ArgumentBuffer buffer) throws CommandException {
+ String value = buffer.next();
+
+ MyInfoObject mio = parameter.getParamInfo();
+ if (mio != null) {
+ String permission = mio.permissionParent + "." + value;
+ Validate.isAuthorized(sender, permission);
+ }
+
+ return value;
+ }
+ }
+
+ static class MyCommands {
+
+ @Cmd("test")
+ Object cmdTest(@ParentPermission("test.permission") String value) {
+ return "You have permission to use the argument '" + value + "'!";
+ }
+
+ }
+
+ static void main(String[] args) {
+ new CommandBuilder()
+ .addParameterType(false, new MyParameterType())
+ .registerCommands(new MyCommands());
+ }
+
+}
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000000000000000000000000000000000..1948b9074f1016d15d505d185bc3f73deb82d8c8
GIT binary patch
literal 54413
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