diff options
Diffstat (limited to 'dicore3/command/src/main/java/io/dico/dicore')
26 files changed, 472 insertions, 371 deletions
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<String> namesModifiable = new ArrayList<>(4); List<String> 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<String> 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<String> 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<String> 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,11 +265,20 @@ 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 * * @return this 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<String, Object> parameterValueMap; + private Map<String, Object> 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<String> parsedParameters; + private Set<String> 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. - */ - 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. + * @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 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); } /** @@ -157,6 +92,13 @@ public class ExecutionContext { } /** + * @return the buffer of arguments + */ + public ArgumentBuffer getBuffer() { + return buffer; + } + + /** * Command's address * * @return the command's address @@ -166,6 +108,15 @@ public class ExecutionContext { } /** + * Set the address + * + * @param address the new address + */ + public void setAddress(ICommandAddress address) { + this.address = address; + } + + /** * The command * * @return the command @@ -175,12 +126,59 @@ public class ExecutionContext { } /** + * 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 <T> expected type + * @return the parsed value or the default value + */ @SuppressWarnings("unchecked") public <T> T get(String name) { if (!parameterValueMap.containsKey(name)) { @@ -254,15 +261,23 @@ public class ExecutionContext { } } - @SuppressWarnings("unchecked") - public <T> 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 <T> expected type + * @return the parsed value or the default value + */ public <T> T getFlag(String flag) { return get("-" + flag); } + @SuppressWarnings("unchecked") + @Deprecated + public <T> 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)); } /** @@ -294,20 +310,6 @@ public class ExecutionContext { } /** - * @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. * * @param location The location as passed to {link org.bukkit.command.Command#tabComplete(CommandSender, String, String[], Location)}, or null if requested in another way. @@ -315,19 +317,22 @@ public class ExecutionContext { */ public List<String> 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<String> 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<T extends ExtendedCommand<T>> 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. * + * <p> + * To iterate children without duplicates, you can do something like this: + * <pre>{@code + * for (String key : address.getChildrenMainKeys()) { + * ICommandAddress child = address.getChild(key); + * // do stuff with child + * } + * }</pre> + * </p> + * * @return the children of this address. */ Map<String, ? extends ICommandAddress> 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. + * <p> + * The default implementation is as follows: + * <pre>{@code + * return buffer.hasNext() ? getChild(buffer.next()) : null; + * }</pre> * - * @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<ICommandAddress> 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<String>, result: MutableList<String>): List<String> { + 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<String, org.bukkit.command.Command> map, String key, org.bukkit.command.Command value, boolean override) { + private static void registerMember(Map<String, org.bukkit.command.Command> 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<String> 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<String> 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<IHelpTopic> helpTopics, IPageLayout pageLayout, ICommandAddress target, Permissible viewer, ExecutionContext context, int pageNum, int pageLen) { + public String getPage(List<IHelpTopic> 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<IHelpComponent> modify(List<IHelpComponent> 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<String> implements Iterator<Str // // drop the last element of args if it is empty // result = args; //} else { - result = new String[args.length + 1]; + result = new String[args.length + 1]; //} System.arraycopy(args, 0, result, 1, result.length - 1); result[0] = Objects.requireNonNull(label); @@ -35,16 +37,21 @@ public class ArgumentBuffer extends AbstractList<String> implements Iterator<Str * None of the array its elements should be empty. * * @param array the array + * @throws NullPointerException if the array or any of its elements are null */ public ArgumentBuffer(String[] array) { - this.array = Objects.requireNonNull(array); + for (String elem : array) { + if (elem == null) throw new NullPointerException("ArgumentBuffer array element"); + } + this.array = array; + } public int getCursor() { return cursor; } - public ArgumentBuffer setCursor(int cursor) { + public @NotNull ArgumentBuffer setCursor(int cursor) { if (cursor <= 0) { cursor = 0; } else if (size() <= cursor) { @@ -60,7 +67,7 @@ public class ArgumentBuffer extends AbstractList<String> implements Iterator<Str } @Override - public String get(int index) { + public @NotNull String get(int index) { return array[index]; } @@ -91,11 +98,11 @@ public class ArgumentBuffer extends AbstractList<String> implements Iterator<Str * @return the next value, or null */ @Override - public String next() { + public @Nullable String next() { return hasNext() ? get(cursor++) : null; } - public String requireNext(String parameterName) throws CommandException { + public @NotNull String requireNext(String parameterName) throws CommandException { String next = next(); if (next == null) { throw CommandException.missingArgument(parameterName); @@ -104,7 +111,7 @@ public class ArgumentBuffer extends AbstractList<String> implements Iterator<Str } // useful for completion code - public String nextOrEmpty() { + public @NotNull String nextOrEmpty() { return hasNext() ? get(cursor++) : ""; } @@ -113,62 +120,62 @@ public class ArgumentBuffer extends AbstractList<String> implements Iterator<Str * * @return the previous value, or null */ - public String previous() { + public @Nullable String previous() { return hasPrevious() ? get(--cursor) : null; } - public String peekNext() { + public @Nullable String peekNext() { return hasNext() ? get(cursor) : null; } - public String peekPrevious() { + public @Nullable String peekPrevious() { return hasPrevious() ? get(cursor - 1) : null; } - public ArgumentBuffer advance() { + public @NotNull ArgumentBuffer advance() { return advance(1); } - public ArgumentBuffer advance(int amount) { + public @NotNull ArgumentBuffer advance(int amount) { cursor = Math.min(Math.max(0, cursor + amount), size()); return this; } - public ArgumentBuffer rewind() { + public @NotNull ArgumentBuffer rewind() { return rewind(1); } - public ArgumentBuffer rewind(int amount) { + public @NotNull ArgumentBuffer rewind(int amount) { return advance(-amount); } - String[] getArray() { + @NotNull String[] getArray() { return array; } - public String[] getArrayFromCursor() { + public @NotNull String[] getArrayFromCursor() { return getArrayFromIndex(cursor); } - public String[] getArrayFromIndex(int index) { + public @NotNull String[] getArrayFromIndex(int index) { return Arrays.copyOfRange(array, index, array.length); } - public String getRawInput() { + public @NotNull String getRawInput() { return String.join(" ", array); } - public String[] toArray() { + public @NotNull String[] toArray() { return array.clone(); } @Override - public Iterator<String> iterator() { + public @NotNull Iterator<String> iterator() { return this; } @Override - public ListIterator<String> listIterator() { + public @NotNull ListIterator<String> listIterator() { return new ListIterator<String>() { @Override public boolean hasNext() { @@ -243,13 +250,14 @@ public class ArgumentBuffer extends AbstractList<String> implements Iterator<Str } } - public ArgumentBuffer preprocessArguments(IArgumentPreProcessor preProcessor) { - String[] array = this.array; - // processor shouldn't touch any items prior to the cursor - if (array != (array = preProcessor.process(cursor, array))) { - return new ArgumentBuffer(array).setCursor(cursor); - } - return this; + /** + * Preprocess this argument buffer with the given preprocessor + * + * @param preProcessor preprocessor + * @return a new ArgumentBuffer with processed contents. Might be this buffer if nothing changed. + */ + public @NotNull ArgumentBuffer preprocessArguments(IArgumentPreProcessor preProcessor) { + return preProcessor.process(this, -1); } /** @@ -273,10 +281,15 @@ public class ArgumentBuffer extends AbstractList<String> implements Iterator<Str } @SuppressWarnings("MethodDoesntCallSuperMethod") - public ArgumentBuffer clone() { + public @NotNull ArgumentBuffer clone() { ArgumentBuffer result = getUnaffectingCopy(); this.unaffectingCopy = null; return result; } + @Override + public String toString() { + return String.format("ArgumentBuffer(size = %d, cursor = %d)", size(), getCursor()); + } + } diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/parameter/ArgumentMergingPreProcessor.java b/dicore3/command/src/main/java/io/dico/dicore/command/parameter/ArgumentMergingPreProcessor.java index 5f7b81d..ce818b7 100644 --- a/dicore3/command/src/main/java/io/dico/dicore/command/parameter/ArgumentMergingPreProcessor.java +++ b/dicore3/command/src/main/java/io/dico/dicore/command/parameter/ArgumentMergingPreProcessor.java @@ -11,39 +11,44 @@ public class ArgumentMergingPreProcessor implements IArgumentPreProcessor { } @Override - public String[] process(int argStart, String[] args) { - if (!(0 <= argStart && argStart <= args.length)) { - throw new IndexOutOfBoundsException(); - } - - Parser parser = new Parser(argStart, args.clone()); - return parser.doProcess(); + public ArgumentBuffer process(ArgumentBuffer buffer, int count) { + Parser parser = new Parser(buffer.getArray().clone(), buffer.getCursor(), count); + String[] array = parser.doProcess(); + ArgumentBuffer result = new ArgumentBuffer(array); + parser.updateBuffer(result); + return result; } private class Parser { - private final int argStart; private final String[] args; + private final int start; + private final int count; + private int foundSectionCount; private int currentIndex; private int sectionStart; private char closingToken; private int sectionEnd; private int removeCount; - Parser(int argStart, String[] args) { - this.argStart = argStart; + Parser(String[] args, int start, int count) { + this.start = start; this.args = args; + this.count = count; } private void reset() { - removeCount = 0; - closingToken = 0; + foundSectionCount = 0; + currentIndex = start; sectionStart = -1; + closingToken = 0; sectionEnd = -1; - currentIndex = argStart; + removeCount = 0; } private boolean findNextSectionStart() { + if (count >= 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<Parameter<?, ?>> m_indexedParams; private final int m_maxIndex; - private final int m_requiredIndex; + private final int m_maxRequiredIndex; - private Map<String, Object> m_valueMap = new HashMap<>(); - private Set<String> m_parsedKeys = new HashSet<>(); + private Map<String, Object> m_valueMap; + private Set<String> 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<String, Object> valueMap, + Set<String> 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 + * <p> + * 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. + * </p> + * + * @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<Parameter<?, ?>> indexedParameters; private Map<String, Parameter<?, ?>> 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<E extends Enum> extends SimpleParameterType<E, Vo } } - @Override protected E parse(Parameter<E, Void> parameter, CommandSender sender, String input) throws CommandException { + @Override + protected E parse(Parameter<E, Void> 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<E extends Enum> extends SimpleParameterType<E, Vo throw CommandException.invalidArgument(parameter.getName(), "the enum value does not exist"); } - @Override public List<String> complete(Parameter<E, Void> parameter, CommandSender sender, Location location, ArgumentBuffer buffer) { + @Override + public List<String> complete(Parameter<E, Void> parameter, CommandSender sender, Location location, ArgumentBuffer buffer) { String input = buffer.next().toUpperCase(); List<String> 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<TReturn, TParamInfo> { } - 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<DefaultGroupCommand> 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<String> 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 |