Skip to content

Commit

Permalink
Merge pull request #72 from Paul2708/development
Browse files Browse the repository at this point in the history
Sub commands and fixes
  • Loading branch information
Paul2708 committed Sep 1, 2020
2 parents 9477ab3 + 542a186 commit b84c6ef
Show file tree
Hide file tree
Showing 22 changed files with 1,048 additions and 73 deletions.
7 changes: 7 additions & 0 deletions .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ jobs:
uses: actions/setup-java@v1
with:
java-version: 14
- name: Cache maven dependencies
uses: actions/cache@v1
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Build with Maven
run: mvn clean install
- name: Verify checkstyle rules
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Just add the following repository and dependency to your Maven project.
<dependency>
<groupId>com.github.Paul2708</groupId>
<artifactId>simple-commands</artifactId>
<version>0.3.0</version>
<version>0.4.0</version>
</dependency>
```

Expand All @@ -51,7 +51,7 @@ If you don't use a build tool like Maven or Gradle, you can download the latest
<dependency>
<groupId>de.paul2708</groupId>
<artifactId>simple-commands-core</artifactId>
<version>0.3.0</version>
<version>0.4.0</version>
</dependency>
```

Expand Down
4 changes: 2 additions & 2 deletions arguments/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<artifactId>simple-commands</artifactId>
<groupId>de.paul2708</groupId>
<version>0.3.0</version>
<version>0.4.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand All @@ -16,7 +16,7 @@
<dependency>
<groupId>de.paul2708</groupId>
<artifactId>simple-commands-language</artifactId>
<version>0.3.0</version>
<version>${simple-commands.version}</version>
</dependency>
<!-- Spigot -->
<dependency>
Expand Down
4 changes: 2 additions & 2 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<artifactId>simple-commands</artifactId>
<groupId>de.paul2708</groupId>
<version>0.3.0</version>
<version>0.4.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand All @@ -16,7 +16,7 @@
<dependency>
<groupId>de.paul2708</groupId>
<artifactId>simple-commands-arguments</artifactId>
<version>0.3.0</version>
<version>${simple-commands.version}</version>
</dependency>
<!-- Spigot -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@
import de.paul2708.commands.core.annotation.Command;
import de.paul2708.commands.core.annotation.Inject;
import de.paul2708.commands.core.annotation.Optional;
import de.paul2708.commands.core.command.CommandDelegator;
import de.paul2708.commands.core.command.CommandType;
import de.paul2708.commands.core.command.SimpleCommand;
import de.paul2708.commands.core.command.registry.BukkitCommandRegistry;
import de.paul2708.commands.core.language.DefaultLanguageSelector;
import de.paul2708.commands.core.language.LanguageSelector;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandMap;
import org.bukkit.plugin.java.JavaPlugin;

import java.lang.reflect.Field;
Expand All @@ -39,6 +37,8 @@ public final class DefaultCommandRegistry implements CommandRegistry {

private final LanguageSelector languageSelector;

private final BukkitCommandRegistry bukkitCommandRegistry;

/**
* Create a new command registry.
*
Expand All @@ -53,6 +53,8 @@ public final class DefaultCommandRegistry implements CommandRegistry {
this.injectedObjects = new ArrayList<>();

this.languageSelector = new DefaultLanguageSelector();

this.bukkitCommandRegistry = new BukkitCommandRegistry(plugin, languageSelector);
}

/**
Expand Down Expand Up @@ -158,9 +160,9 @@ public void register(Object... objects) {
// Register command
SimpleCommand simpleCommand = new SimpleCommand(method.getAnnotation(Command.class), commandType,
object, method, list);
commands.add(simpleCommand);

registerBukkitCommand(simpleCommand, new CommandDelegator(languageSelector, simpleCommand));
commands.add(simpleCommand);
bukkitCommandRegistry.register(simpleCommand);
}
}
}
Expand Down Expand Up @@ -213,27 +215,4 @@ private Object getInjectedValue(String key, Class<?> objectClass) {

return null;
}

/**
* Register a simple command as a bukkit command by using the command map.
* The plugin name will be used as command prefix.
*
* @param simpleCommand simple command
* @param bukkitCommand to simple command related bukkit command
*/
private void registerBukkitCommand(SimpleCommand simpleCommand, org.bukkit.command.Command bukkitCommand) {
try {
Field commandMapField = Bukkit.getServer().getClass().getDeclaredField("commandMap");
commandMapField.setAccessible(true);

CommandMap commandMap = (CommandMap) commandMapField.get(Bukkit.getServer());
commandMap.register(plugin.getName(), bukkitCommand);

for (String alias : simpleCommand.getInformation().aliases()) {
commandMap.register(alias, plugin.getName(), bukkitCommand);
}
} catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException exception) {
exception.printStackTrace();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,23 @@
@Target(ElementType.METHOD)
public @interface Command {

/**
* This permission indicates that the sender needs operation rights (OP).
*/
String OP_PERMISSION = "*";

/**
* This permission indicates that none permission is needed.
*/
String NONE_PERMISSION = "";

/**
* Array of parents.
*
* @return array of parents or an empty array if no parent is present
*/
String[] parent() default {};

/**
* Command name.
*
Expand All @@ -29,12 +46,14 @@
String desc() default "";

/**
* Permission, a player needs, to execute the command. '*' means that the player requires op rights.
* Default value is '*'.
* Permission, a player needs, to execute the command.
* '*' means that the player requires op rights.
* An empty string means that no permission is needed at all.
* Default value is ''.
*
* @return command permission
*/
String permission() default "*";
String permission() default Command.NONE_PERMISSION;

/**
* Command aliases. Default value is an empty array.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;

import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
Expand All @@ -27,19 +28,35 @@
public final class CommandDelegator extends Command {

private final LanguageSelector languageSelector;
private final SimpleCommand simpleCommand;
private final List<SimpleCommand> commands;

private CommandMatcher matcher;

private boolean initiated;

/**
* Create a new basic command based on the simple command.
*
* @param languageSelector language selector to translate messages
* @param simpleCommand simple command
* @param commands list of commands including root and all sub commands
*/
public CommandDelegator(LanguageSelector languageSelector, SimpleCommand simpleCommand) {
super(simpleCommand.getInformation().name());
public CommandDelegator(LanguageSelector languageSelector, List<SimpleCommand> commands) {
super(commands.get(0).getBukkitLabel());

this.languageSelector = languageSelector;
this.simpleCommand = simpleCommand;
this.commands = commands;
}

/**
* Called if the first command relating to this command group got exectued.
* This means that every command got registered.
*/
private void firstExecution() {
// TODO: Ugly af
if (!initiated) {
this.matcher = new CommandMatcher(commands);
initiated = true;
}
}

/**
Expand All @@ -52,8 +69,11 @@ public CommandDelegator(LanguageSelector languageSelector, SimpleCommand simpleC
*/
@SuppressWarnings("checkstyle:illegalcatch")
@Override
public boolean execute(CommandSender sender, String commandLabel, String[] args) {
public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, String[] args) {
// TODO: Add custom listener
firstExecution();

SimpleCommand simpleCommand = matcher.findBestMatch(args);

// Check executor
switch (simpleCommand.getType()) {
Expand Down Expand Up @@ -82,9 +102,13 @@ public boolean execute(CommandSender sender, String commandLabel, String[] args)
return true;
}

// Move arguments
String[] movedArgs = new String[args.length - simpleCommand.getInformation().parent().length];
System.arraycopy(args, simpleCommand.getInformation().parent().length, movedArgs, 0, movedArgs.length);

// Test arguments
ArgumentGenerator generator = new ArgumentGenerator(simpleCommand.getArguments());
ArgumentTester tester = new ArgumentTester(args);
ArgumentTester tester = new ArgumentTester(movedArgs);

List<TestResult> results = new LinkedList<>();

Expand All @@ -101,16 +125,23 @@ public boolean execute(CommandSender sender, String commandLabel, String[] args)
List<Object> test = ((SuccessResult) result).getMappedArguments().stream()
.map(parameter -> parameter.isEmpty() ? null : parameter.get())
.collect(Collectors.toList());
execute(sender, test);
execute(simpleCommand, sender, test);
}, () -> {
// TODO: How to check which error message should be printed?
sendUsage(sender, simpleCommand.getArguments());
sendUsage(sender, simpleCommand, simpleCommand.getArguments());
});
return true;
}

/**
* Execute the command method with a list of passed parameters.
*
* @param simpleCommand executed (sub) command
* @param sender command sender
* @param mappedParameters mapped parameters, excluding the first sender object
*/
@SuppressWarnings("checkstyle:IllegalCatch")
private void execute(CommandSender sender, List<Object> mappedParameters) {
public void execute(SimpleCommand simpleCommand, CommandSender sender, List<Object> mappedParameters) {
mappedParameters.add(0, sender);

try {
Expand All @@ -134,10 +165,11 @@ private void execute(CommandSender sender, List<Object> mappedParameters) {
* private helper to send usage to a CommandSender
*
* @param sender the sender to send the usage to
* @param command (sub) command
* @param arguments the required arguments of the command
*/
private void sendUsage(CommandSender sender, List<CommandArgument<?>> arguments) {
StringBuilder usage = new StringBuilder("/" + simpleCommand.getInformation().name() + " ");
private void sendUsage(CommandSender sender, SimpleCommand command, List<CommandArgument<?>> arguments) {
StringBuilder usage = new StringBuilder("/" + String.join(" ", command.getPath()) + " ");

for (CommandArgument<?> argument : arguments) {
if (argument.isOptional()) {
Expand Down Expand Up @@ -168,28 +200,52 @@ private void sendUsage(CommandSender sender, List<CommandArgument<?>> arguments)
* @throws IllegalArgumentException if sender, alias, or args is null
*/
@Override
public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
// TODO: Check if tab completion works with optional arguments
@NotNull
public List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias, String[] args)
throws IllegalArgumentException {
firstExecution();

if (sender == null || alias == null || args == null) {
throw new IllegalArgumentException();
}
// TODO: Check if tab completion works with optional arguments

if (args.length == 0 || args.length > simpleCommand.getArguments().size()) {
return Collections.emptyList();
SimpleCommand command = matcher.findBestMatch(args);
List<String> subCommands = matcher.findDirectSubCommands(command).stream()
.filter(cmd -> cmd.getPathWithoutParent().length == args.length)
.map(c -> c.getInformation().name())
.filter(s -> s.startsWith(args[args.length - 1]))
.collect(Collectors.toList());

List<String> arguments = new ArrayList<>();
if (!command.getArguments().isEmpty()) {
String singleArgument = args[args.length - 1];
int argIndex = args.length - command.getPathWithoutParent().length - 1;

if (argIndex >= 0 && argIndex < command.getArguments().size()) {
CommandArgument<?> argument = command.getArguments().get(argIndex);
arguments.addAll(argument.autoComplete(singleArgument));
}
}

return simpleCommand.getArguments().get(args.length - 1).autoComplete(args[args.length - 1]);
List<String> result = new ArrayList<>(subCommands);
result.addAll(arguments);
return result;
}

/**
* Check if a command sender has the given permission.
*
* @param sender command sender
* @param permission permission
* @return true if the sender is the console or if the player has the permission, otherwise false
* @return true if the sender is the console, has operator rights or has the permission
* or no permission is needed at all
*/
private boolean hasPermission(CommandSender sender, String permission) {
return sender instanceof ConsoleCommandSender || (sender instanceof Player && sender.hasPermission(permission));
if (permission.equals(de.paul2708.commands.core.annotation.Command.NONE_PERMISSION)) {
return true;
}

return sender instanceof ConsoleCommandSender
|| sender.isOp()
|| (sender.hasPermission(permission)
&& !permission.equals(de.paul2708.commands.core.annotation.Command.OP_PERMISSION));
}
}

0 comments on commit b84c6ef

Please sign in to comment.