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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 literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..d2c45a4 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..cccdd3d --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..f955316 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/src/main/kotlin/io/dico/parcels2/command/AbstractParcelCommands.kt b/src/main/kotlin/io/dico/parcels2/command/AbstractParcelCommands.kt index bcc7997..eaa9f57 100644 --- a/src/main/kotlin/io/dico/parcels2/command/AbstractParcelCommands.kt +++ b/src/main/kotlin/io/dico/parcels2/command/AbstractParcelCommands.kt @@ -1,9 +1,8 @@ package io.dico.parcels2.command -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 io.dico.dicore.command.registration.reflect.ICommandInterceptor +import io.dico.dicore.command.registration.reflect.ICommandReceiver import io.dico.parcels2.* import io.dico.parcels2.PlayerProfile.Real import io.dico.parcels2.PlayerProfile.Unresolved @@ -13,13 +12,16 @@ import org.bukkit.entity.Player import org.bukkit.plugin.Plugin import java.lang.reflect.Method -abstract class AbstractParcelCommands(val plugin: ParcelsPlugin) : ICommandReceiver.Factory { - override fun getPlugin(): Plugin = plugin +abstract class AbstractParcelCommands(val plugin: ParcelsPlugin) : ICommandInterceptor { override fun getReceiver(context: ExecutionContext, target: Method, cmdName: String): ICommandReceiver { return getParcelCommandReceiver(plugin.parcelProvider, context, target, cmdName) } + override fun getCoroutineContext(context: ExecutionContext?, target: Method?, cmdName: String?): Any { + return plugin.coroutineContext + } + protected fun checkConnected(action: String) { if (!plugin.storage.isConnected) err("Parcels cannot $action right now because of a database error") } @@ -57,8 +59,6 @@ abstract class AbstractParcelCommands(val plugin: ParcelsPlugin) : ICommandRecei .format(progress * 100, elapsedTime / 1000.0) ) } - - override fun getCoroutineContext() = plugin.coroutineContext } fun err(message: String): Nothing = throw CommandException(message) \ No newline at end of file diff --git a/src/main/kotlin/io/dico/parcels2/command/ParcelCommandBuilder.kt b/src/main/kotlin/io/dico/parcels2/command/ParcelCommandBuilder.kt index 2777b7f..721ce2d 100644 --- a/src/main/kotlin/io/dico/parcels2/command/ParcelCommandBuilder.kt +++ b/src/main/kotlin/io/dico/parcels2/command/ParcelCommandBuilder.kt @@ -1,6 +1,7 @@ package io.dico.parcels2.command import io.dico.dicore.command.* +import io.dico.dicore.command.parameter.ArgumentBuffer import io.dico.dicore.command.predef.DefaultGroupCommand import io.dico.dicore.command.registration.reflect.ReflectiveRegistration import io.dico.parcels2.Interactables @@ -107,10 +108,12 @@ class SpecialCommandAddress : ChildCommandAddress() { } } + // h:1 @Throws(CommandException::class) - override fun getChild(key: String, context: ExecutionContext): ChildCommandAddress? { + override fun getChild(context: ExecutionContext, buffer: ArgumentBuffer): ChildCommandAddress? { speciallyParsedIndex = null + val key = buffer.next() ?: return null for (specialKey in speciallyTreatedKeys) { if (key.startsWith(specialKey)) { val result = getChild(specialKey.substring(0, specialKey.length - 1)) diff --git a/src/main/kotlin/io/dico/parcels2/command/ParcelCommandReceivers.kt b/src/main/kotlin/io/dico/parcels2/command/ParcelCommandReceivers.kt index 8f6dabc..15548b4 100644 --- a/src/main/kotlin/io/dico/parcels2/command/ParcelCommandReceivers.kt +++ b/src/main/kotlin/io/dico/parcels2/command/ParcelCommandReceivers.kt @@ -2,7 +2,7 @@ package io.dico.parcels2.command import io.dico.dicore.command.CommandException import io.dico.dicore.command.ExecutionContext -import io.dico.dicore.command.ICommandReceiver +import io.dico.dicore.command.registration.reflect.ICommandReceiver import io.dico.dicore.command.Validate import io.dico.parcels2.* import io.dico.parcels2.Privilege.* diff --git a/src/main/kotlin/io/dico/parcels2/command/ParcelParameterTypes.kt b/src/main/kotlin/io/dico/parcels2/command/ParcelParameterTypes.kt index 736e568..a9f5498 100644 --- a/src/main/kotlin/io/dico/parcels2/command/ParcelParameterTypes.kt +++ b/src/main/kotlin/io/dico/parcels2/command/ParcelParameterTypes.kt @@ -30,7 +30,7 @@ class ParcelParameterType(val parcelProvider: ParcelProvider) : ParameterType)?([0-9]+):([0-9]+)") override fun parse(parameter: Parameter, sender: CommandSender, buffer: ArgumentBuffer): Parcel { - val matchResult = regex.matchEntire(buffer.next()) + val matchResult = regex.matchEntire(buffer.next()!!) ?: invalidInput(parameter, "must match (w->)?a:b (/${regex.pattern}/)") val world = parcelProvider.getTargetWorld(matchResult.groupValues[2], sender, parameter) @@ -66,7 +66,7 @@ class ProfileParameterType : ParameterType(PlayerProfile::cl val allowReal = (info and REAL) != 0 val allowFake = (info and FAKE) != 0 - val input = buffer.next() + val input = buffer.next()!! return PlayerProfile.byName(input, allowReal, allowFake) } diff --git a/src/main/kotlin/io/dico/parcels2/command/ParcelTarget.kt b/src/main/kotlin/io/dico/parcels2/command/ParcelTarget.kt index 70a8dda..8891912 100644 --- a/src/main/kotlin/io/dico/parcels2/command/ParcelTarget.kt +++ b/src/main/kotlin/io/dico/parcels2/command/ParcelTarget.kt @@ -91,7 +91,7 @@ sealed class ParcelTarget(val world: ParcelWorld, val parsedKind: Int, val isDef ParameterType(ParcelTarget::class.java, TargetKind) { override fun parse(parameter: Parameter, sender: CommandSender, buffer: ArgumentBuffer): ParcelTarget { - var input = buffer.next() + var input = buffer.next()!! val worldString = input.substringBefore("/", missingDelimiterValue = "") input = input.substringAfter("/") diff --git a/src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt b/src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt index e9ec148..9e43c05 100644 --- a/src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt +++ b/src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt @@ -279,7 +279,6 @@ class DefaultParcelGenerator( val region = getRegion(parcel) val blocks = parcelTraverser.traverseRegion(region) val blockCount = region.blockCount.toDouble() - val world = world val floorHeight = o.floorHeight val airType = airType diff --git a/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelProviderImpl.kt b/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelProviderImpl.kt index 74545d6..48a7fee 100644 --- a/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelProviderImpl.kt +++ b/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelProviderImpl.kt @@ -50,7 +50,7 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider { return } - //val newlyCreatedWorlds = mutableListOf() + val newlyCreatedWorlds = mutableListOf() for ((worldName, worldOptions) in options.worlds.entries) { var parcelWorld = _worlds[worldName] if (parcelWorld != null) continue @@ -70,7 +70,7 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider { val time = DateTime.now() plugin.storage.setWorldCreationTime(parcelWorld.id, time) parcelWorld.creationTime = time - //newlyCreatedWorlds.add(parcelWorld) + newlyCreatedWorlds.add(parcelWorld) } else { GlobalScope.launch(context = Dispatchers.Unconfined) { parcelWorld.creationTime = plugin.storage.getWorldCreationTime(parcelWorld.id).await() ?: DateTime.now() @@ -80,10 +80,10 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider { _worlds[worldName] = parcelWorld } - loadStoredData() + loadStoredData(newlyCreatedWorlds.toSet()) } - private fun loadStoredData() { + private fun loadStoredData(newlyCreatedWorlds: Collection = emptyList()) { plugin.launch(Dispatchers.Default) { val migration = plugin.options.migration if (migration.enabled) { @@ -105,9 +105,8 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider { val channel = plugin.storage.transmitAllParcelData() while (true) { val (id, data) = channel.receiveOrNull() ?: break - if (data == null) continue val parcel = getParcelById(id) ?: continue - parcel.copyData(data, callerIsDatabase = true) + data?.let { parcel.copyData(it, callerIsDatabase = true) } } } diff --git a/src/main/kotlin/io/dico/parcels2/listener/ParcelListeners.kt b/src/main/kotlin/io/dico/parcels2/listener/ParcelListeners.kt index 04941b4..59d10e7 100644 --- a/src/main/kotlin/io/dico/parcels2/listener/ParcelListeners.kt +++ b/src/main/kotlin/io/dico/parcels2/listener/ParcelListeners.kt @@ -85,8 +85,6 @@ class ParcelListeners( newTo = newTo.add(it, delta * 100 * if (it == Dimension.Y) 0.5 else speed) } - - event.to = Location( toLoc.world, newTo.x, newTo.y.clampMin(0.0).clampMax(255.0), newTo.z, diff --git a/src/main/kotlin/io/dico/parcels2/storage/Hikari.kt b/src/main/kotlin/io/dico/parcels2/storage/Hikari.kt index d1500d5..480d533 100644 --- a/src/main/kotlin/io/dico/parcels2/storage/Hikari.kt +++ b/src/main/kotlin/io/dico/parcels2/storage/Hikari.kt @@ -32,7 +32,7 @@ fun getHikariConfig(dialectName: String, username = dco.username password = dco.password connectionTimeout = 15000 - leakDetectionThreshold = 30000 + leakDetectionThreshold = 10000 connectionTestQuery = "SELECT 1"