diff --git a/build.gradle b/build.gradle
index b3f35803..2809708c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,14 +3,13 @@ plugins {
id 'maven-publish'
}
-apply plugin: 'maven-publish'
-
allprojects {
- group = 'com.wizardlybump17.wlib'
- version = '1.6.7'
-
apply plugin: 'com.github.johnrengelman.shadow'
apply plugin: 'java'
+ apply plugin: 'maven-publish'
+
+ group = 'com.wizardlybump17.wlib'
+ version = '1.6.7-ncs-2'
repositories {
mavenLocal()
@@ -24,6 +23,10 @@ allprojects {
compileJava {
options.encoding = 'UTF-8'
}
+
+ assemble {
+ dependsOn(shadowJar)
+ }
}
java {
@@ -32,8 +35,6 @@ allprojects {
}
subprojects {
- apply plugin: 'maven-publish'
-
if (project.name == 'versions' || project.name.matches('v\\d_\\d+_R\\d+')) {
tasks.withType(PublishToMavenRepository).configureEach {
it.enabled = false
@@ -79,8 +80,4 @@ subprojects {
events "passed", "skipped", "failed", "standardOut", "standardError"
}
}
-
- build {
- dependsOn(test, shadowJar)
- }
}
\ No newline at end of file
diff --git a/bukkit-utils/build.gradle b/bukkit-utils/build.gradle
index 00e702b8..970dd5b2 100644
--- a/bukkit-utils/build.gradle
+++ b/bukkit-utils/build.gradle
@@ -4,6 +4,9 @@ dependencies {
'org.spigotmc:spigot:1.17.1-R0.1-SNAPSHOT',
'org.jetbrains:annotations:23.0.0',
)
+ compileOnly("net.kyori:adventure-api:4.18.0")
+ compileOnly("net.kyori:adventure-text-minimessage:4.18.0")
+ compileOnly("net.kyori:adventure-platform-bukkit:4.3.4")
implementation(
project(':utils')
)
diff --git a/bukkit-utils/src/main/java/com/wizardlybump17/wlib/util/bukkit/MiniMessageUtil.java b/bukkit-utils/src/main/java/com/wizardlybump17/wlib/util/bukkit/MiniMessageUtil.java
new file mode 100644
index 00000000..6cbc701a
--- /dev/null
+++ b/bukkit-utils/src/main/java/com/wizardlybump17/wlib/util/bukkit/MiniMessageUtil.java
@@ -0,0 +1,39 @@
+package com.wizardlybump17.wlib.util.bukkit;
+
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.minimessage.MiniMessage;
+import net.kyori.adventure.text.minimessage.tag.Tag;
+import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+
+public final class MiniMessageUtil {
+
+ private MiniMessageUtil() {
+ }
+
+ public static @NotNull Component getMessage(@NotNull String message, @NotNull Map placeholders) {
+ MiniMessage miniMessage = MiniMessage.miniMessage();
+ if (placeholders.isEmpty())
+ return miniMessage.deserialize(message);
+
+ TagResolver[] resolvers = new TagResolver[placeholders.size()];
+ int resolverIndex = 0;
+ for (Map.Entry entry : placeholders.entrySet()) {
+ String key = entry.getKey();
+ Object value = entry.getValue();
+ resolvers[resolverIndex++] = TagResolver.builder()
+ .tag(
+ key,
+ Tag.inserting(value instanceof Component component ? component : Component.text(String.valueOf(value)))
+ )
+ .build();
+ }
+ return miniMessage.deserialize(message, resolvers);
+ }
+
+ public static @NotNull Component getMessage(@NotNull String message) {
+ return getMessage(message, Map.of());
+ }
+}
diff --git a/bungee/src/main/java/com/wizardlybump17/wlib/bungee/command/BungeeCommandExecutor.java b/bungee/src/main/java/com/wizardlybump17/wlib/bungee/command/BungeeCommandExecutor.java
index 57ed1875..cca749bd 100644
--- a/bungee/src/main/java/com/wizardlybump17/wlib/bungee/command/BungeeCommandExecutor.java
+++ b/bungee/src/main/java/com/wizardlybump17/wlib/bungee/command/BungeeCommandExecutor.java
@@ -1,13 +1,13 @@
package com.wizardlybump17.wlib.bungee.command;
-import com.wizardlybump17.wlib.bungee.command.sender.GenericSender;
-import com.wizardlybump17.wlib.bungee.command.sender.ProxiedPlayerSender;
+import com.wizardlybump17.wlib.bungee.command.sender.BungeeCommandSender;
import com.wizardlybump17.wlib.command.CommandManager;
-import com.wizardlybump17.wlib.command.CommandSender;
+import com.wizardlybump17.wlib.command.exception.CommandException;
import com.wizardlybump17.wlib.command.holder.CommandExecutor;
-import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Command;
+import java.util.logging.Level;
+
public class BungeeCommandExecutor extends Command implements CommandExecutor {
private final CommandManager manager;
@@ -18,17 +18,16 @@ public BungeeCommandExecutor(CommandManager manager, String name) {
}
@Override
- public void execute(CommandSender> sender, String commandName, String[] args) {
+ public void execute(com.wizardlybump17.wlib.command.sender.CommandSender> sender, String commandName, String[] args) throws CommandException {
manager.execute(sender, commandName + " " + String.join(" ", args));
}
@Override
public void execute(net.md_5.bungee.api.CommandSender sender, String[] args) {
- CommandSender> realSender;
- if (sender instanceof ProxiedPlayer)
- realSender = new ProxiedPlayerSender((ProxiedPlayer) sender);
- else
- realSender = new GenericSender(sender);
- execute(realSender, getName(), args);
+ try {
+ execute(new BungeeCommandSender(sender), getName(), args);
+ } catch (CommandException e) {
+ manager.getHolder().getLogger().log(Level.SEVERE, "Error while executing a command", e);
+ }
}
}
diff --git a/bungee/src/main/java/com/wizardlybump17/wlib/bungee/command/BungeeCommandManager.java b/bungee/src/main/java/com/wizardlybump17/wlib/bungee/command/BungeeCommandManager.java
index 48c0b047..bfd1bafa 100644
--- a/bungee/src/main/java/com/wizardlybump17/wlib/bungee/command/BungeeCommandManager.java
+++ b/bungee/src/main/java/com/wizardlybump17/wlib/bungee/command/BungeeCommandManager.java
@@ -1,9 +1,10 @@
package com.wizardlybump17.wlib.bungee.command;
import com.wizardlybump17.wlib.command.CommandManager;
-import com.wizardlybump17.wlib.command.RegisteredCommand;
+import com.wizardlybump17.wlib.command.registered.RegisteredCommand;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.Plugin;
+import org.jetbrains.annotations.NotNull;
public class BungeeCommandManager extends CommandManager {
@@ -12,7 +13,7 @@ public BungeeCommandManager(BungeeCommandHolder holder) {
}
@Override
- public void registerCommands(Object... objects) {
+ public void registerCommands(@NotNull Object @NotNull ... objects) {
super.registerCommands(objects);
for (Object object : objects) {
for (RegisteredCommand command : getCommands(object)) {
diff --git a/bungee/src/main/java/com/wizardlybump17/wlib/bungee/command/sender/GenericSender.java b/bungee/src/main/java/com/wizardlybump17/wlib/bungee/command/sender/BungeeCommandSender.java
similarity index 57%
rename from bungee/src/main/java/com/wizardlybump17/wlib/bungee/command/sender/GenericSender.java
rename to bungee/src/main/java/com/wizardlybump17/wlib/bungee/command/sender/BungeeCommandSender.java
index 86698b06..702f31eb 100644
--- a/bungee/src/main/java/com/wizardlybump17/wlib/bungee/command/sender/GenericSender.java
+++ b/bungee/src/main/java/com/wizardlybump17/wlib/bungee/command/sender/BungeeCommandSender.java
@@ -1,11 +1,15 @@
package com.wizardlybump17.wlib.bungee.command.sender;
-import com.wizardlybump17.wlib.command.CommandSender;
import lombok.RequiredArgsConstructor;
import net.md_5.bungee.api.chat.TextComponent;
+import net.md_5.bungee.api.connection.ConnectedPlayer;
+import net.md_5.bungee.api.connection.ProxiedPlayer;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.UUID;
@RequiredArgsConstructor
-public class GenericSender implements CommandSender {
+public class BungeeCommandSender implements com.wizardlybump17.wlib.command.sender.CommandSender {
private final net.md_5.bungee.api.CommandSender handle;
@@ -34,12 +38,16 @@ public boolean hasPermission(String permission) {
return handle.hasPermission(permission);
}
- @Override
- public GenericSender toGeneric() {
- return this;
+ public @NotNull ProxiedPlayer asProxiedPlayer() {
+ return (ProxiedPlayer) handle;
}
- public static boolean isGeneric() {
- return true;
+ public @NotNull ConnectedPlayer asConnectedPlayer() {
+ return (ConnectedPlayer) handle;
+ }
+
+ @Override
+ public boolean hasId(@NotNull UUID id) {
+ return handle instanceof ProxiedPlayer player && player.getUniqueId().equals(id);
}
}
diff --git a/bungee/src/main/java/com/wizardlybump17/wlib/bungee/command/sender/ProxiedPlayerSender.java b/bungee/src/main/java/com/wizardlybump17/wlib/bungee/command/sender/ProxiedPlayerSender.java
deleted file mode 100644
index d2fca3f7..00000000
--- a/bungee/src/main/java/com/wizardlybump17/wlib/bungee/command/sender/ProxiedPlayerSender.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.wizardlybump17.wlib.bungee.command.sender;
-
-import com.wizardlybump17.wlib.command.CommandSender;
-import lombok.RequiredArgsConstructor;
-import net.md_5.bungee.api.chat.TextComponent;
-import net.md_5.bungee.api.connection.ProxiedPlayer;
-
-@RequiredArgsConstructor
-public class ProxiedPlayerSender implements CommandSender {
-
- private final ProxiedPlayer handle;
-
- @Override
- public ProxiedPlayer getHandle() {
- return handle;
- }
-
- @Override
- public void sendMessage(String message) {
- handle.sendMessage(TextComponent.fromLegacyText(message));
- }
-
- @Override
- public void sendMessage(String... messages) {
- handle.sendMessage(TextComponent.fromLegacyText(String.join("\n", messages)));
- }
-
- @Override
- public String getName() {
- return handle.getName();
- }
-
- @Override
- public boolean hasPermission(String permission) {
- return handle.hasPermission(permission);
- }
-
- @Override
- public GenericSender toGeneric() {
- return new GenericSender(handle);
- }
-}
diff --git a/commands/build.gradle b/commands/build.gradle
index f57b9327..2497418c 100644
--- a/commands/build.gradle
+++ b/commands/build.gradle
@@ -11,6 +11,7 @@ dependencies {
implementation("com.github.sisyphsu:dateparser:1.0.11") {
exclude(group: "org.projectlombok", module: "lombok")
}
+ testCompileOnly("org.jetbrains:annotations:26.0.1")
}
shadowJar {
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/CommandManager.java b/commands/src/main/java/com/wizardlybump17/wlib/command/CommandManager.java
index 371354f6..08bff110 100644
--- a/commands/src/main/java/com/wizardlybump17/wlib/command/CommandManager.java
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/CommandManager.java
@@ -1,82 +1,81 @@
package com.wizardlybump17.wlib.command;
+import com.wizardlybump17.wlib.command.data.CommandData;
+import com.wizardlybump17.wlib.command.exception.CommandException;
+import com.wizardlybump17.wlib.command.extractor.CommandExtractor;
+import com.wizardlybump17.wlib.command.extractor.DirectCommandExtractor;
+import com.wizardlybump17.wlib.command.extractor.MethodCommandExtractor;
import com.wizardlybump17.wlib.command.holder.CommandHolder;
-import com.wizardlybump17.wlib.util.ReflectionUtil;
-import lombok.Getter;
-import lombok.NonNull;
-import lombok.RequiredArgsConstructor;
-import org.jetbrains.annotations.Nullable;
-
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.logging.Level;
-
-@Getter
-@RequiredArgsConstructor
+import com.wizardlybump17.wlib.command.registered.RegisteredCommand;
+import com.wizardlybump17.wlib.command.sender.CommandSender;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.*;
+
public class CommandManager {
- private final List commands = new ArrayList<>();
- protected final CommandHolder> holder;
- private final @NonNull Map, Map> fieldCache = new HashMap<>();
-
- public void registerCommands(Object... objects) {
- for (Object object : objects) {
- for (Method method : object.getClass().getDeclaredMethods()) {
- if (!method.isAnnotationPresent(Command.class) || method.getParameterCount() == 0 || !CommandSender.class.isAssignableFrom(method.getParameterTypes()[0]))
- continue;
-
- MethodHandle handle;
- try {
- handle = MethodHandles.publicLookup().findVirtual(object.getClass(), method.getName(), MethodType.methodType(method.getReturnType(), method.getParameterTypes()));
- } catch (NoSuchMethodException | IllegalAccessException e) {
- holder.getLogger().log(Level.SEVERE, "Error while trying to get the MethodHandle for " + method.getName() + " at " + object.getClass().getName(), e);
- continue;
- }
+ private final @NotNull Map> commands = new HashMap<>();
+ protected final @NotNull CommandHolder> holder;
+ private final @NotNull Set commandExtractors = new HashSet<>();
- RegisteredCommand command = new RegisteredCommand(
- method.getAnnotation(Command.class),
- object,
- method,
- handle
- );
-
- commands.add(command);
- com.wizardlybump17.wlib.command.holder.Command holderCommand = holder.getCommand(command.getName());
- if (holderCommand != null)
- holderCommand.setExecutor(holderCommand.getDefaultExecutor(this, command.getName()));
- }
- }
+ public CommandManager(@NotNull CommandHolder> holder) {
+ this.holder = holder;
+ commandExtractors.add(new MethodCommandExtractor());
+ commandExtractors.add(new DirectCommandExtractor());
+ }
+ public void registerCommands(@NotNull Object @NotNull ... objects) {
+ for (Object object : objects)
+ for (CommandExtractor extractor : commandExtractors)
+ registerCommands(extractor.extract(this, holder, object));
+ }
+
+ public void registerCommands(@NotNull Collection commands) {
+ commands.forEach(this::registerCommand);
+ }
+
+ public void registerCommand(@NotNull RegisteredCommand command) {
+ command.onRegister(this);
+ List commands = this.commands.computeIfAbsent(command.getName().toLowerCase(), $ -> new ArrayList<>());
+ commands.add(command);
commands.sort(null);
}
public void unregisterCommands() {
+ commands.forEach((name, commands) -> {
+ commands.forEach(command -> command.onUnregister(this));
+ commands.clear();
+ });
commands.clear();
}
- public void execute(CommandSender> sender, String string) {
+ public void execute(@NotNull CommandSender> sender, @NotNull String string) throws CommandException {
if (commands.isEmpty())
return;
- for (RegisteredCommand registeredCommand : commands) {
- Command command = registeredCommand.getCommand();
+ int spaceIndex = string.indexOf(' ');
+ String name;
+ if (spaceIndex == -1)
+ name = string;
+ else
+ name = string.substring(0, spaceIndex);
+
+ for (RegisteredCommand registeredCommand : commands.getOrDefault(name, List.of())) {
+ CommandData command = registeredCommand.getCommand();
CommandResult result = registeredCommand.execute(sender, string);
switch (result) {
case PERMISSION_FAIL -> {
- handleMessage(registeredCommand, sender, command.permissionMessage(), command.permissionMessageIsField());
+ String message = command.getPermissionMessage();
+ if (message != null)
+ sender.sendMessage(message);
return;
}
case INVALID_SENDER -> {
- handleMessage(registeredCommand, sender, command.invalidSenderMessage(), command.invalidSenderMessageIsField());
+ String message = command.getInvalidSenderMessage();
+ if (message != null)
+ sender.sendMessage(message);
return;
}
@@ -87,55 +86,45 @@ public void execute(CommandSender> sender, String string) {
}
}
- protected void handleMessage(@NonNull RegisteredCommand registeredCommand, @NonNull CommandSender> sender, @NonNull String message, boolean isField) {
- if (!isField) {
- if (!message.isEmpty())
- sender.sendMessage(message);
- return;
- }
+ public @NotNull List<@NotNull String> autoComplete(@NotNull CommandSender> sender, @NotNull String string) {
+ return List.of();
+ }
- String fieldMessage = getFieldMessage(registeredCommand, message);
- if (fieldMessage != null)
- sender.sendMessage(fieldMessage);
+ public @NotNull List getCommands(@NotNull String name) {
+ List commands = this.commands.get(name);
+ return commands == null ? List.of() : List.copyOf(commands);
}
- protected @Nullable String getFieldMessage(@NonNull RegisteredCommand registeredCommand, @NonNull String fieldName) {
- Map fields = fieldCache.computeIfAbsent(registeredCommand.getObject().getClass(), clazz -> {
- Map map = new HashMap<>();
- for (Field field : clazz.getDeclaredFields())
- map.put(field.getName(), field);
- return map;
- });
+ public @NotNull List getCommands(@NotNull Object object) {
+ List result = new ArrayList<>(commands.size());
+ for (List commands : this.commands.values())
+ for (RegisteredCommand command : commands)
+ if (command.isOwnedBy(object))
+ result.add(command);
+ return result;
+ }
- Field field = fields.get(fieldName);
- if (field == null)
- return null;
+ public @NotNull CommandHolder> getHolder() {
+ return holder;
+ }
- Object fieldValue = ReflectionUtil.getFieldValue(field, registeredCommand.getObject());
- return fieldValue == null ? null : fieldValue.toString();
+ public @NotNull Map> getCommands() {
+ return Map.copyOf(commands);
}
- @NonNull
- public List<@NonNull String> autoComplete(@NonNull CommandSender> sender, @NonNull String string) {
- List result = new ArrayList<>();
- for (RegisteredCommand command : commands)
- result.addAll(command.autoComplete(sender, string));
- return result;
+ public @NotNull Set getCommandExtractors() {
+ return Set.copyOf(commandExtractors);
+ }
+
+ public void addCommandExtractor(@NotNull CommandExtractor extractor) {
+ commandExtractors.add(extractor);
}
- public List getCommand(String name) {
- List commands = new ArrayList<>(this.commands.size());
- for (RegisteredCommand command : this.commands)
- if (command.getName().equalsIgnoreCase(name))
- commands.add(command);
- return commands;
+ public void removeCommandExtractor(@NotNull CommandExtractor extractor) {
+ commandExtractors.remove(extractor);
}
- public List getCommands(Object object) {
- List commands = new ArrayList<>(this.commands.size());
- for (RegisteredCommand command : this.commands)
- if (command.getObject() == object)
- commands.add(command);
- return commands;
+ public boolean hasCommandExtractor(@NotNull CommandExtractor extractor) {
+ return commandExtractors.contains(extractor);
}
}
\ No newline at end of file
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/RegisteredCommand.java b/commands/src/main/java/com/wizardlybump17/wlib/command/RegisteredCommand.java
deleted file mode 100644
index 5ae2885e..00000000
--- a/commands/src/main/java/com/wizardlybump17/wlib/command/RegisteredCommand.java
+++ /dev/null
@@ -1,275 +0,0 @@
-package com.wizardlybump17.wlib.command;
-
-import com.wizardlybump17.wlib.command.args.ArgsNode;
-import com.wizardlybump17.wlib.command.args.ArgsReaderRegistry;
-import com.wizardlybump17.wlib.command.args.ArgsReaderType;
-import com.wizardlybump17.wlib.command.args.reader.ArgsReader;
-import com.wizardlybump17.wlib.command.args.reader.ArgsReaderException;
-import com.wizardlybump17.wlib.object.Pair;
-import lombok.Getter;
-import lombok.NonNull;
-import org.jetbrains.annotations.NotNull;
-
-import java.lang.invoke.MethodHandle;
-import java.lang.reflect.Method;
-import java.lang.reflect.Parameter;
-import java.util.*;
-
-@Getter
-public class RegisteredCommand implements Comparable {
-
- private final Command command;
- private final Object object;
- private final Method method;
- private final List nodes = new ArrayList<>();
- private final @NonNull MethodHandle methodHandle;
-
- public RegisteredCommand(Command command, Object object, Method method, @NonNull MethodHandle methodHandle) {
- this.command = command;
- this.object = object;
- this.method = method;
- this.methodHandle = methodHandle;
- prepareNodes();
- }
-
- private void prepareNodes() {
- String[] commandArgs = command.execution().split(" ");
-
- Class>[] types = method.getParameterTypes();
- Parameter[] parameters = method.getParameters();
- int index = 1; //skipping the first type because of the CommandSender
- for (String commandArg : commandArgs) {
- if (!requiredArgs(commandArg)) {
- nodes.add(new ArgsNode(
- commandArg,
- false,
- null,
- null,
- false
- ));
- continue;
- }
-
- Description description = parameters[index].getAnnotation(Description.class);
-
- ArgsReaderType argsReaderType = parameters[index].getAnnotation(ArgsReaderType.class);
- if (argsReaderType == null && Argument.class.isAssignableFrom(types[index]))
- throw new IllegalArgumentException("the \"" + commandArg + "\" argument requires the " + ArgsReaderType.class.getName() + " annotation");
-
- ArgsReader> reader;
- if (argsReaderType == null)
- reader = ArgsReaderRegistry.INSTANCE.getReader(types[index]);
- else
- reader = ArgsReaderRegistry.INSTANCE.get(argsReaderType.value());
- if (reader == null)
- throw new IllegalArgumentException("no reader found for " + types[index].getName());
-
- nodes.add(new ArgsNode(
- trim(commandArg),
- true,
- reader,
- description == null ? null : description.value(),
- Argument.class.isAssignableFrom(types[index])
- ));
-
- index++;
- }
- }
-
- public String getName() {
- return command.execution().split(" ")[0];
- }
-
- @Override
- public int compareTo(@NotNull RegisteredCommand o) {
- if (o.command.priority() == -1 && command.priority() == -1) {
- int args = compareArgs(o);
-
- if (args == 0)
- return compareSize(o);
-
- return args;
- }
-
- return Integer.compare(o.command.priority(), command.priority());
- }
-
- private int compareArgs(RegisteredCommand other) {
- return Integer.compare(other.command.execution().split(" ").length, command.execution().split(" ").length);
- }
-
- private int compareSize(RegisteredCommand other) {
- return Integer.compare(other.command.execution().length(), command.execution().length());
- }
-
- public Optional>> parse(String input, boolean autoComplete) throws ArgsReaderException {
- List toParse = new ArrayList<>();
- checkArrays(input, toParse, autoComplete);
-
- List> result = new ArrayList<>(nodes.size());
-
- if (parseRequiredOnly(result, toParse, autoComplete))
- return Optional.of(result);
-
- return Optional.empty();
- }
-
- private boolean parseRequiredOnly(List> target, List strings, boolean autoComplete) throws ArgsReaderException {
- if (autoComplete && nodes.size() > strings.size())
- return false;
-
- for (int i = 0; i < nodes.size() && i < strings.size(); i++) {
- ArgsNode node = nodes.get(i);
- if (!node.isUserInput()) {
- if (!node.getName().equalsIgnoreCase(strings.get(i)))
- return false;
-
- continue;
- }
-
- Object parse = node.parse(strings.get(i));
- if (parse == ArgsNode.EMPTY)
- continue;
-
- target.add(new Pair<>(node, parse));
- }
-
- return true;
- }
-
- private void checkArrays(String input, List target, boolean autoComplete) throws ArgsReaderException {
- StringBuilder builder = new StringBuilder();
- boolean inArray = false;
- for (String s : input.split(" ")) {
- if (s.startsWith("\"") && s.endsWith("\"") && !s.endsWith("\\\"") && s.length() != 1) { //"string" | single word
- target.add(s.substring(1, s.length() - 1));
- continue;
- }
-
- if (s.startsWith("\"")) { //"string | it is starting the array
- builder.append(s.substring(1).replace("\\\"", "\"")).append(" ");
- inArray = true;
- continue;
- }
-
- if (s.endsWith("\"") && !s.endsWith("\\\"")) { //string" | it is ending the array
- builder.append(s.replace("\\\"", "\""), 0, s.length() - 1);
- target.add(builder.toString());
- builder = new StringBuilder();
- inArray = false;
- continue;
- }
-
- if (!builder.isEmpty()) { //string | it is in the array
- builder.append(s.replace("\\\"", "\"")).append(" ");
- continue;
- }
-
- target.add(s.replace("\\\"", "\"")); //string | it is not in the array
- }
-
- if (inArray && !autoComplete)
- throw new ArgsReaderException("Invalid array");
- }
-
- public CommandResult execute(CommandSender> sender, String string) {
- try {
- Optional>> parse = parse(string, true);
- if (parse.isEmpty())
- return CommandResult.ARGS_FAIL;
-
- if (!getSenderType().isInstance(sender) && !isSenderGeneric())
- return CommandResult.INVALID_SENDER;
-
- Object[] objects = parse.get().stream().map(Pair::getSecond).toArray();
- return executeInternal(sender, objects);
- } catch (ArgsReaderException e) {
- return CommandResult.EXCEPTION;
- }
- }
-
- private CommandResult executeInternal(CommandSender> sender, Object[] objects) {
- try {
- if (!command.permission().isEmpty() && !sender.hasPermission(command.permission()))
- return CommandResult.PERMISSION_FAIL;
-
- List list = new ArrayList<>(Arrays.asList(objects));
- list.add(0, isSenderGeneric() ? sender.toGeneric() : sender);
-
- if (list.size() != method.getParameterCount())
- return CommandResult.ARGS_FAIL;
-
- list.add(0, object);
- methodHandle.invokeWithArguments(list);
- return CommandResult.SUCCESS;
- } catch (Throwable e) {
- e.printStackTrace();
- return CommandResult.METHOD_FAIL;
- }
- }
-
- @NonNull
- public List<@NonNull String> autoComplete(@NonNull CommandSender> sender, @NonNull String string) {
- if (nodes.size() == 1)
- return Collections.emptyList();
-
- if (!getSenderType().isInstance(sender) && !isSenderGeneric())
- return Collections.emptyList();
-
- try {
- Optional>> parse = parse(string, false);
- if (parse.isEmpty())
- return Collections.emptyList();
-
- String[] split = string.split(" ");
- String lastString = split[split.length - 1];
-
- List> pairs = parse.get();
-
- if (pairs.isEmpty()) {
- ArgsNode secondNode = nodes.get(1);
- ArgsReader> secondNodeReader = secondNode.getReader();
- return secondNodeReader == null ? List.of(secondNode.getName()) : secondNodeReader.autoComplete(sender, lastString);
- }
-
- Pair lastPair = pairs.get(pairs.size() - 1);
-
- ArgsNode node = lastPair.getFirst();
- ArgsReader> reader = node.getReader();
-
- return reader == null ? List.of(node.getName()) : reader.autoComplete(sender, lastString);
- } catch (ArgsReaderException e) {
- e.printStackTrace();
- return Collections.emptyList();
- }
- }
-
- @Override
- public String toString() {
- return "RegisteredCommand{" + command.execution() + "}";
- }
-
- @SuppressWarnings("unchecked")
- public Class extends CommandSender>> getSenderType() {
- return (Class extends CommandSender>>) method.getParameterTypes()[0];
- }
-
- public boolean isSenderGeneric() {
- boolean result = false;
- try {
- result = (Boolean) getSenderType().getDeclaredMethod("isGeneric").invoke(null);
- } catch (NoSuchMethodException ignored) {
- } catch (Exception e) {
- e.printStackTrace();
- }
- return result;
- }
-
- private static String trim(String string) {
- return string.substring(1, string.length() - 1);
- }
-
- private static boolean requiredArgs(String string) {
- return string.startsWith("<") && string.endsWith(">");
- }
-}
\ No newline at end of file
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/Command.java b/commands/src/main/java/com/wizardlybump17/wlib/command/annotation/Command.java
similarity index 90%
rename from commands/src/main/java/com/wizardlybump17/wlib/command/Command.java
rename to commands/src/main/java/com/wizardlybump17/wlib/command/annotation/Command.java
index ca53cf22..b941b23b 100644
--- a/commands/src/main/java/com/wizardlybump17/wlib/command/Command.java
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/annotation/Command.java
@@ -1,4 +1,7 @@
-package com.wizardlybump17.wlib.command;
+package com.wizardlybump17.wlib.command.annotation;
+
+import com.wizardlybump17.wlib.command.sender.CommandSender;
+import org.jetbrains.annotations.NotNull;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -81,4 +84,9 @@
* @return if the {@link #invalidSenderMessage()} is a field in the class that have this annotation
*/
boolean invalidSenderMessageIsField() default false;
+
+ /**
+ * @return the type of the {@link CommandSender#getHandle()} that can execute this command
+ */
+ @NotNull Class> senderType() default Object.class;
}
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/args/ArgsNode.java b/commands/src/main/java/com/wizardlybump17/wlib/command/args/ArgsNode.java
index afb04352..23d07d47 100644
--- a/commands/src/main/java/com/wizardlybump17/wlib/command/args/ArgsNode.java
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/args/ArgsNode.java
@@ -42,4 +42,16 @@ public Object parse(String input) throws ArgsReaderException {
return object;
}
+
+ public static @NotNull ArgsNode literal(@NotNull String string) {
+ return new ArgsNode(string, false, null, null, false);
+ }
+
+ public static @NotNull ArgsNode userInput(@NotNull String name, @NotNull ArgsReader> reader) {
+ return new ArgsNode(name, true, reader, null, false);
+ }
+
+ public static @NotNull ArgsNode userInput(@NotNull String name, @NotNull Class> type) {
+ return userInput(name, ArgsReaderRegistry.INSTANCE.getReader(type));
+ }
}
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/ArgsReader.java b/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/ArgsReader.java
index 3ca7ecee..d8a6fa5a 100644
--- a/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/ArgsReader.java
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/ArgsReader.java
@@ -1,6 +1,6 @@
package com.wizardlybump17.wlib.command.args.reader;
-import com.wizardlybump17.wlib.command.CommandSender;
+import com.wizardlybump17.wlib.command.sender.CommandSender;
import lombok.NonNull;
import org.jetbrains.annotations.Nullable;
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/BooleanReader.java b/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/BooleanReader.java
index ef854c6a..539558be 100644
--- a/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/BooleanReader.java
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/BooleanReader.java
@@ -1,6 +1,6 @@
package com.wizardlybump17.wlib.command.args.reader;
-import com.wizardlybump17.wlib.command.CommandSender;
+import com.wizardlybump17.wlib.command.sender.CommandSender;
import lombok.NonNull;
import java.util.List;
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/ByteReader.java b/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/ByteReader.java
index 6b7e920d..00c9056c 100644
--- a/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/ByteReader.java
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/ByteReader.java
@@ -1,6 +1,6 @@
package com.wizardlybump17.wlib.command.args.reader;
-import com.wizardlybump17.wlib.command.CommandSender;
+import com.wizardlybump17.wlib.command.sender.CommandSender;
import lombok.NonNull;
import java.util.List;
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/DoubleReader.java b/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/DoubleReader.java
index 9dd12592..b7c4f356 100644
--- a/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/DoubleReader.java
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/DoubleReader.java
@@ -1,6 +1,6 @@
package com.wizardlybump17.wlib.command.args.reader;
-import com.wizardlybump17.wlib.command.CommandSender;
+import com.wizardlybump17.wlib.command.sender.CommandSender;
import lombok.NonNull;
import java.util.List;
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/FloatReader.java b/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/FloatReader.java
index 1541cf68..f90a346a 100644
--- a/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/FloatReader.java
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/FloatReader.java
@@ -1,6 +1,6 @@
package com.wizardlybump17.wlib.command.args.reader;
-import com.wizardlybump17.wlib.command.CommandSender;
+import com.wizardlybump17.wlib.command.sender.CommandSender;
import lombok.NonNull;
import java.util.List;
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/IntegerReader.java b/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/IntegerReader.java
index 111c3c09..5123f358 100644
--- a/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/IntegerReader.java
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/IntegerReader.java
@@ -1,6 +1,6 @@
package com.wizardlybump17.wlib.command.args.reader;
-import com.wizardlybump17.wlib.command.CommandSender;
+import com.wizardlybump17.wlib.command.sender.CommandSender;
import lombok.NonNull;
import java.util.List;
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/ShortReader.java b/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/ShortReader.java
index af95f3ff..14e84005 100644
--- a/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/ShortReader.java
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/ShortReader.java
@@ -1,6 +1,6 @@
package com.wizardlybump17.wlib.command.args.reader;
-import com.wizardlybump17.wlib.command.CommandSender;
+import com.wizardlybump17.wlib.command.sender.CommandSender;
import lombok.NonNull;
import java.util.List;
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/StringReader.java b/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/StringReader.java
index e6719a67..93f2c9c4 100644
--- a/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/StringReader.java
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/StringReader.java
@@ -1,6 +1,6 @@
package com.wizardlybump17.wlib.command.args.reader;
-import com.wizardlybump17.wlib.command.CommandSender;
+import com.wizardlybump17.wlib.command.sender.CommandSender;
import lombok.NonNull;
import java.util.List;
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/UUIDReader.java b/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/UUIDReader.java
index d061710b..d9f4c7db 100644
--- a/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/UUIDReader.java
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/args/reader/UUIDReader.java
@@ -1,6 +1,6 @@
package com.wizardlybump17.wlib.command.args.reader;
-import com.wizardlybump17.wlib.command.CommandSender;
+import com.wizardlybump17.wlib.command.sender.CommandSender;
import lombok.NonNull;
import java.util.List;
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/completer/ArgumentCompleter.java b/commands/src/main/java/com/wizardlybump17/wlib/command/completer/ArgumentCompleter.java
index 187191c0..f0145c0d 100644
--- a/commands/src/main/java/com/wizardlybump17/wlib/command/completer/ArgumentCompleter.java
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/completer/ArgumentCompleter.java
@@ -1,6 +1,6 @@
package com.wizardlybump17.wlib.command.completer;
-import com.wizardlybump17.wlib.command.CommandSender;
+import com.wizardlybump17.wlib.command.sender.CommandSender;
import lombok.NonNull;
import java.util.List;
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/data/AnnotationCommandData.java b/commands/src/main/java/com/wizardlybump17/wlib/command/data/AnnotationCommandData.java
new file mode 100644
index 00000000..e45d26f0
--- /dev/null
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/data/AnnotationCommandData.java
@@ -0,0 +1,100 @@
+package com.wizardlybump17.wlib.command.data;
+
+import com.wizardlybump17.wlib.command.annotation.Command;
+import com.wizardlybump17.wlib.util.ReflectionUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+public class AnnotationCommandData extends CommandData {
+
+ private final @NotNull Command annotation;
+ private final @NotNull Object object;
+ private final @NotNull Map fieldCache = new HashMap<>();
+
+ public AnnotationCommandData(@NotNull Command annotation, @NotNull Object object) {
+ this.annotation = annotation;
+ this.object = object;
+ }
+
+ @Override
+ public @NotNull String getExecution() {
+ return annotation.execution();
+ }
+
+ @Override
+ public @Nullable String getPermission() {
+ String permission = annotation.permission();
+ return permission.isBlank() ? super.getPermission() : permission;
+ }
+
+ @Override
+ public @Nullable String getPermissionMessage() {
+ return getMessage(annotation.permissionMessage(), annotation.permissionMessageIsField(), super.getPermissionMessage());
+ }
+
+ @Override
+ public int getPriority() {
+ int priority = annotation.priority();
+ return priority == -1 ? super.getPriority() : priority;
+ }
+
+ @Override
+ public @Nullable String getDescription() {
+ String description = annotation.description();
+ return description.isBlank() ? super.getDescription() : description;
+ }
+
+ @Override
+ public @Nullable String getInvalidSenderMessage() {
+ return getMessage(annotation.invalidSenderMessage(), annotation.invalidSenderMessageIsField(), super.getInvalidSenderMessage());
+ }
+
+ protected @Nullable String getMessage(@NotNull String message, boolean isField, @Nullable String defaultMessage) {
+ if (isField) {
+ return ReflectionUtil.getFieldValue(
+ fieldCache.computeIfAbsent(
+ message,
+ $ -> ReflectionUtil.getField(message, object.getClass())
+ ),
+ object
+ );
+ }
+ return message.isBlank() ? defaultMessage : message;
+ }
+
+ public @NotNull Command getAnnotation() {
+ return annotation;
+ }
+
+ @Override
+ public @NotNull Class> getSenderType() {
+ return annotation.senderType();
+ }
+
+ @Override
+ public boolean equals(Object object1) {
+ if (object1 == null || getClass() != object1.getClass())
+ return false;
+ AnnotationCommandData that = (AnnotationCommandData) object1;
+ return Objects.equals(annotation, that.annotation) && Objects.equals(object, that.object) && Objects.equals(fieldCache, that.fieldCache);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(annotation, object, fieldCache);
+ }
+
+ @Override
+ public String toString() {
+ return "AnnotationCommandData{" +
+ "annotation=" + annotation +
+ ", object=" + object +
+ ", fieldCache=" + fieldCache +
+ '}';
+ }
+}
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/data/CommandData.java b/commands/src/main/java/com/wizardlybump17/wlib/command/data/CommandData.java
new file mode 100644
index 00000000..9dd74ef5
--- /dev/null
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/data/CommandData.java
@@ -0,0 +1,81 @@
+package com.wizardlybump17.wlib.command.data;
+
+import com.wizardlybump17.wlib.command.sender.CommandSender;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public abstract class CommandData {
+
+ /**
+ * How the sender must type the command in order for it to be triggered.
+ * Example:
command hello world
+ * In the example above, the sender must type /command hello world, so it can be triggered.
+ * To add parameters that depends on the sender input, just put the parameter between <>.
+ *
+ * Example: command <hello> world
+ * The type of each parameter is defined in the method that have this annotation.
+ * An example for the command above:
+ *
+ * @Command(execution = "command <hello> world")
+ * public void commandHelloWorld(GenericSender sender, String hello) {
+ * System.out.println(sender.getName() + " executed the hello world command with the argument " + hello);
+ * }
+ *
+ *
+ * @return how the command must be sent to be triggered
+ * @see com.wizardlybump17.wlib.command.args.reader.ArgsReader
+ */
+ public abstract @NotNull String getExecution();
+
+ /**
+ * @return which permission the sender must have to trigger this command
+ */
+ public @Nullable String getPermission() {
+ return null;
+ }
+
+ /**
+ * Used when the {@link CommandSender} does not have the required {@link #getPermission()}.
+ * @return the message to be sent when the {@link CommandSender} does not have the required {@link #getPermission()}
+ */
+ public @Nullable String getPermissionMessage() {
+ return null;
+ }
+
+ /**
+ * @return the priority of this command
+ */
+ public int getPriority() {
+ return getExecution().split(" ").length;
+ }
+
+ /**
+ * @return the description of this command
+ */
+ public @Nullable String getDescription() {
+ return null;
+ }
+
+ /**
+ * Used when the {@link CommandSender} is not valid for this command.
+ * @return the message to be sent when the {@link CommandSender} is not valid for this command
+ */
+ public @Nullable String getInvalidSenderMessage() {
+ return null;
+ }
+
+ public final @NotNull String getName() {
+ return getExecution().split(" ")[0];
+ }
+
+ /**
+ * @return the {@link CommandSender#getHandle()} that can execute this command
+ */
+ public @NotNull Class> getSenderType() {
+ return Object.class;
+ }
+
+ public static @NotNull SimpleCommandData.Builder builder() {
+ return new SimpleCommandData.Builder();
+ }
+}
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/data/SimpleCommandData.java b/commands/src/main/java/com/wizardlybump17/wlib/command/data/SimpleCommandData.java
new file mode 100644
index 00000000..66905c05
--- /dev/null
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/data/SimpleCommandData.java
@@ -0,0 +1,216 @@
+package com.wizardlybump17.wlib.command.data;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.function.Supplier;
+
+public class SimpleCommandData extends CommandData {
+
+ private final @NotNull Supplier execution;
+ private final @NotNull Supplier permission;
+ private final @NotNull Supplier permissionMessage;
+ private final @NotNull Supplier priority;
+ private final @NotNull Supplier description;
+ private final @NotNull Supplier invalidSenderMessage;
+ private final @NotNull Supplier> senderType;
+
+ public SimpleCommandData(@NotNull Supplier execution, @NotNull Supplier permission, @NotNull Supplier permissionMessage, @NotNull Supplier priority, @NotNull Supplier description, @NotNull Supplier invalidSenderMessage, @NotNull Supplier> senderType) {
+ this.execution = execution;
+ this.permission = permission;
+ this.permissionMessage = permissionMessage;
+ this.priority = priority;
+ this.description = description;
+ this.invalidSenderMessage = invalidSenderMessage;
+ this.senderType = senderType;
+ }
+
+ public SimpleCommandData(@NotNull String execution, @Nullable String permission, @Nullable String permissionMessage, int priority, @Nullable String description, @Nullable String invalidSenderMessage, @NotNull Class> senderType) {
+ this(
+ () -> execution,
+ () -> permission,
+ () -> permissionMessage,
+ () -> priority,
+ () -> description,
+ () -> invalidSenderMessage,
+ () -> senderType
+ );
+ }
+
+ @Override
+ public @NotNull String getExecution() {
+ return execution.get();
+ }
+
+ @Override
+ public @Nullable String getPermission() {
+ return permission.get();
+ }
+
+ @Override
+ public @Nullable String getPermissionMessage() {
+ return permissionMessage.get();
+ }
+
+ @Override
+ public int getPriority() {
+ return priority.get();
+ }
+
+ @Override
+ public @Nullable String getDescription() {
+ return description.get();
+ }
+
+ @Override
+ public @Nullable String getInvalidSenderMessage() {
+ return invalidSenderMessage.get();
+ }
+
+ @Override
+ public @NotNull Class> getSenderType() {
+ return senderType.get();
+ }
+
+ public static class Builder {
+
+ Builder() {
+ }
+
+ private @Nullable Supplier execution;
+ private @Nullable Supplier permission;
+ private @Nullable Supplier permissionMessage;
+ private @Nullable Supplier priority;
+ private @Nullable Supplier description;
+ private @Nullable Supplier invalidSenderMessage;
+ private @Nullable Supplier> senderType;
+
+ public @Nullable String execution() {
+ return execution == null ? null : execution.get();
+ }
+
+ public @NotNull Builder execution(@Nullable String execution) {
+ this.execution = () -> execution;
+ return this;
+ }
+
+ public @NotNull Builder execution(@Nullable Supplier execution) {
+ this.execution = execution;
+ return this;
+ }
+
+ public @Nullable String permission() {
+ return permission == null ? null : permission.get();
+ }
+
+ public @NotNull Builder permission(@Nullable String permission) {
+ this.permission = () -> permission;
+ return this;
+ }
+
+ public @NotNull Builder permission(@Nullable Supplier permission) {
+ this.permission = permission;
+ return this;
+ }
+
+ public @Nullable String permissionMessage() {
+ return permissionMessage == null ? null : permissionMessage.get();
+ }
+
+ public @NotNull Builder permissionMessage(@Nullable String permissionMessage) {
+ this.permissionMessage = () -> permissionMessage;
+ return this;
+ }
+
+ public @NotNull Builder permissionMessage(@Nullable Supplier permissionMessage) {
+ this.permissionMessage = permissionMessage;
+ return this;
+ }
+
+ public @Nullable Integer priority() {
+ return priority == null ? null : priority.get();
+ }
+
+ public @NotNull Builder priority(@Nullable Integer priority) {
+ this.priority = () -> priority;
+ return this;
+ }
+
+ public @NotNull Builder priority(@Nullable Supplier priority) {
+ this.priority = priority;
+ return this;
+ }
+
+ public @Nullable String description() {
+ return description == null ? null : description.get();
+ }
+
+ public @NotNull Builder description(@Nullable String description) {
+ this.description = () -> description;
+ return this;
+ }
+
+ public @NotNull Builder description(@Nullable Supplier description) {
+ this.description = description;
+ return this;
+ }
+
+ public @Nullable String invalidSenderMessage() {
+ return invalidSenderMessage == null ? null : invalidSenderMessage.get();
+ }
+
+ public @NotNull Builder invalidSenderMessage(@Nullable String invalidSenderMessage) {
+ this.invalidSenderMessage = () -> invalidSenderMessage;
+ return this;
+ }
+
+ public @NotNull Builder invalidSenderMessage(@Nullable Supplier invalidSenderMessage) {
+ this.invalidSenderMessage = invalidSenderMessage;
+ return this;
+ }
+
+ public @Nullable Class> senderType() {
+ return senderType == null ? null : senderType.get();
+ }
+
+ public @NotNull Builder senderType(@Nullable Class> senderType) {
+ this.senderType = () -> senderType;
+ return this;
+ }
+
+ public @NotNull Builder senderType(@Nullable Supplier> senderType) {
+ this.senderType = senderType;
+ return this;
+ }
+
+ public @NotNull CommandData build() {
+ String execution = execution();
+ if (execution == null)
+ throw new NullPointerException("The execution can not be null");
+
+ String permission = permission();
+ String permissionMessage = permissionMessage();
+
+ Integer priority = priority();
+ if (priority == null)
+ priority = execution.split(" ").length;
+
+ String description = description();
+ String invalidSenderMessage = invalidSenderMessage();
+
+ Class> senderType = senderType();
+ if (senderType == null)
+ senderType = Object.class;
+
+ return new SimpleCommandData(
+ execution,
+ permission,
+ permissionMessage,
+ priority,
+ description,
+ invalidSenderMessage,
+ senderType
+ );
+ }
+ }
+}
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/exception/CommandException.java b/commands/src/main/java/com/wizardlybump17/wlib/command/exception/CommandException.java
new file mode 100644
index 00000000..7c99b73f
--- /dev/null
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/exception/CommandException.java
@@ -0,0 +1,21 @@
+package com.wizardlybump17.wlib.command.exception;
+
+import org.jetbrains.annotations.NotNull;
+
+public class CommandException extends Exception {
+
+ public CommandException() {
+ }
+
+ public CommandException(@NotNull String message) {
+ super(message);
+ }
+
+ public CommandException(@NotNull String message, @NotNull Throwable cause) {
+ super(message, cause);
+ }
+
+ public CommandException(@NotNull Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/executor/CommandExecutor.java b/commands/src/main/java/com/wizardlybump17/wlib/command/executor/CommandExecutor.java
new file mode 100644
index 00000000..a0c3720a
--- /dev/null
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/executor/CommandExecutor.java
@@ -0,0 +1,12 @@
+package com.wizardlybump17.wlib.command.executor;
+
+import com.wizardlybump17.wlib.command.exception.CommandException;
+import com.wizardlybump17.wlib.command.sender.CommandSender;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+
+public interface CommandExecutor {
+
+ void execute(@NotNull CommandSender> sender, @NotNull Map args) throws CommandException;
+}
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/extractor/CommandExtractor.java b/commands/src/main/java/com/wizardlybump17/wlib/command/extractor/CommandExtractor.java
new file mode 100644
index 00000000..8f1d4373
--- /dev/null
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/extractor/CommandExtractor.java
@@ -0,0 +1,13 @@
+package com.wizardlybump17.wlib.command.extractor;
+
+import com.wizardlybump17.wlib.command.CommandManager;
+import com.wizardlybump17.wlib.command.holder.CommandHolder;
+import com.wizardlybump17.wlib.command.registered.RegisteredCommand;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+public interface CommandExtractor {
+
+ @NotNull List extract(@NotNull CommandManager manager, @NotNull CommandHolder> holder, @NotNull Object object);
+}
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/extractor/DirectCommandExtractor.java b/commands/src/main/java/com/wizardlybump17/wlib/command/extractor/DirectCommandExtractor.java
new file mode 100644
index 00000000..bb21f6c5
--- /dev/null
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/extractor/DirectCommandExtractor.java
@@ -0,0 +1,16 @@
+package com.wizardlybump17.wlib.command.extractor;
+
+import com.wizardlybump17.wlib.command.CommandManager;
+import com.wizardlybump17.wlib.command.holder.CommandHolder;
+import com.wizardlybump17.wlib.command.registered.RegisteredCommand;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+public class DirectCommandExtractor implements CommandExtractor {
+
+ @Override
+ public @NotNull List extract(@NotNull CommandManager manager, @NotNull CommandHolder> holder, @NotNull Object object) {
+ return object instanceof RegisteredCommand command ? List.of(command) : List.of();
+ }
+}
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/extractor/MethodCommandExtractor.java b/commands/src/main/java/com/wizardlybump17/wlib/command/extractor/MethodCommandExtractor.java
new file mode 100644
index 00000000..354da31d
--- /dev/null
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/extractor/MethodCommandExtractor.java
@@ -0,0 +1,44 @@
+package com.wizardlybump17.wlib.command.extractor;
+
+import com.wizardlybump17.wlib.command.CommandManager;
+import com.wizardlybump17.wlib.command.annotation.Command;
+import com.wizardlybump17.wlib.command.holder.CommandHolder;
+import com.wizardlybump17.wlib.command.registered.RegisteredCommand;
+import com.wizardlybump17.wlib.command.registered.RegisteredMethodCommand;
+import com.wizardlybump17.wlib.command.sender.CommandSender;
+import org.jetbrains.annotations.NotNull;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+
+public class MethodCommandExtractor implements CommandExtractor {
+
+ @Override
+ public @NotNull List extract(@NotNull CommandManager manager, @NotNull CommandHolder> holder, @NotNull Object object) {
+ List commands = new ArrayList<>();
+ for (Method method : object.getClass().getDeclaredMethods()) {
+ if (!method.isAnnotationPresent(Command.class) || method.getParameterCount() == 0 || !CommandSender.class.isAssignableFrom(method.getParameterTypes()[0]))
+ continue;
+
+ RegisteredMethodCommand command;
+ try {
+ command = new RegisteredMethodCommand(
+ method.getAnnotation(Command.class),
+ object,
+ method
+ );
+ } catch (Exception e) {
+ holder.getLogger().log(Level.SEVERE, "Error while creating a command", e);
+ continue;
+ }
+
+ commands.add(command);
+ com.wizardlybump17.wlib.command.holder.Command holderCommand = holder.getCommand(command.getName());
+ if (holderCommand != null)
+ holderCommand.setExecutor(holderCommand.getDefaultExecutor(manager, command.getName()));
+ }
+ return commands;
+ }
+}
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/holder/CommandExecutor.java b/commands/src/main/java/com/wizardlybump17/wlib/command/holder/CommandExecutor.java
index de8e1475..05321945 100644
--- a/commands/src/main/java/com/wizardlybump17/wlib/command/holder/CommandExecutor.java
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/holder/CommandExecutor.java
@@ -1,12 +1,13 @@
package com.wizardlybump17.wlib.command.holder;
-import com.wizardlybump17.wlib.command.CommandSender;
import com.wizardlybump17.wlib.command.args.reader.ArgsReaderException;
+import com.wizardlybump17.wlib.command.exception.CommandException;
+import com.wizardlybump17.wlib.command.sender.CommandSender;
/**
* Interface for intercepting commands when they are called
*/
public interface CommandExecutor {
- void execute(CommandSender> sender, String commandName, String[] args) throws ArgsReaderException;
+ void execute(CommandSender> sender, String commandName, String[] args) throws ArgsReaderException, CommandException;
}
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/registered/RegisteredCommand.java b/commands/src/main/java/com/wizardlybump17/wlib/command/registered/RegisteredCommand.java
new file mode 100644
index 00000000..aa31aea1
--- /dev/null
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/registered/RegisteredCommand.java
@@ -0,0 +1,138 @@
+package com.wizardlybump17.wlib.command.registered;
+
+import com.wizardlybump17.wlib.command.CommandManager;
+import com.wizardlybump17.wlib.command.CommandResult;
+import com.wizardlybump17.wlib.command.args.ArgsNode;
+import com.wizardlybump17.wlib.command.args.reader.ArgsReaderException;
+import com.wizardlybump17.wlib.command.data.CommandData;
+import com.wizardlybump17.wlib.command.exception.CommandException;
+import com.wizardlybump17.wlib.command.executor.CommandExecutor;
+import com.wizardlybump17.wlib.command.sender.CommandSender;
+import com.wizardlybump17.wlib.util.StringUtil;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Optional;
+
+public class RegisteredCommand implements Comparable {
+
+ private final @NotNull CommandData command;
+ private final @NotNull List nodes;
+ private final @NotNull CommandExecutor executor;
+
+ public RegisteredCommand(@NotNull CommandData command, @NotNull List nodes, @NotNull CommandExecutor executor) {
+ this.command = command;
+ this.nodes = nodes;
+ this.executor = executor;
+ }
+
+ protected RegisteredCommand(@NotNull CommandData command, @NotNull List nodes) {
+ this.command = command;
+ this.nodes = nodes;
+ executor = createExecutor();
+ }
+
+ protected CommandExecutor createExecutor() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getName() {
+ return command.getExecution().split(" ")[0];
+ }
+
+ @Override
+ public int compareTo(@NotNull RegisteredCommand o) {
+ return Integer.compare(o.command.getPriority(), command.getPriority());
+ }
+
+ public Optional> parse(String input) throws ArgsReaderException {
+ List toParse = StringUtil.parseQuotedStrings(input);
+
+ LinkedHashMap result = new LinkedHashMap<>();
+
+ if (checkNodes(result, toParse))
+ return Optional.of(result);
+
+ return Optional.empty();
+ }
+
+ protected boolean checkNodes(LinkedHashMap target, List strings) throws ArgsReaderException {
+ if (nodes.size() > strings.size())
+ return false;
+
+ for (int i = 0; i < nodes.size() && i < strings.size(); i++) {
+ ArgsNode node = nodes.get(i);
+ if (!node.isUserInput()) {
+ if (node.getName().equalsIgnoreCase(strings.get(i)))
+ continue;
+ return false;
+ }
+
+ Object parse = node.parse(strings.get(i));
+ if (parse != ArgsNode.EMPTY)
+ target.put(node.getName(), parse);
+ }
+
+ return true;
+ }
+
+ public @NotNull CommandResult execute(@NotNull CommandSender> sender, @NotNull String string) throws CommandException {
+ if (!canExecute(sender))
+ return CommandResult.INVALID_SENDER;
+
+ String permission = command.getPermission();
+ if (permission != null && !sender.hasPermission(permission))
+ return CommandResult.PERMISSION_FAIL;
+
+ try {
+ Optional> parse = parse(string);
+ if (parse.isEmpty())
+ return CommandResult.ARGS_FAIL;
+
+ LinkedHashMap args = parse.get();
+ if (!isValidArgs(args))
+ return CommandResult.ARGS_FAIL;
+
+ executor.execute(sender, args);
+ return CommandResult.SUCCESS;
+ } catch (ArgsReaderException e) {
+ return CommandResult.EXCEPTION;
+ }
+ }
+
+ protected boolean isValidArgs(@NotNull LinkedHashMap args) {
+ return true;
+ }
+
+ public boolean canExecute(@NotNull CommandSender> sender) {
+ return command.getSenderType().isInstance(sender.getHandle());
+ }
+
+ @Override
+ public String toString() {
+ return "RegisteredCommand{" + command.getExecution() + "}";
+ }
+
+ public @NotNull CommandData getCommand() {
+ return command;
+ }
+
+ public @NotNull CommandExecutor getExecutor() {
+ return executor;
+ }
+
+ public @NotNull List getNodes() {
+ return nodes;
+ }
+
+ public boolean isOwnedBy(@NotNull Object object) {
+ return false;
+ }
+
+ public void onRegister(@NotNull CommandManager manager) {
+ }
+
+ public void onUnregister(@NotNull CommandManager manager) {
+ }
+}
\ No newline at end of file
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/registered/RegisteredMethodCommand.java b/commands/src/main/java/com/wizardlybump17/wlib/command/registered/RegisteredMethodCommand.java
new file mode 100644
index 00000000..721860f0
--- /dev/null
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/registered/RegisteredMethodCommand.java
@@ -0,0 +1,123 @@
+package com.wizardlybump17.wlib.command.registered;
+
+import com.wizardlybump17.wlib.command.Argument;
+import com.wizardlybump17.wlib.command.Description;
+import com.wizardlybump17.wlib.command.annotation.Command;
+import com.wizardlybump17.wlib.command.args.ArgsNode;
+import com.wizardlybump17.wlib.command.args.ArgsReaderRegistry;
+import com.wizardlybump17.wlib.command.args.ArgsReaderType;
+import com.wizardlybump17.wlib.command.args.reader.ArgsReader;
+import com.wizardlybump17.wlib.command.data.AnnotationCommandData;
+import com.wizardlybump17.wlib.command.exception.CommandException;
+import com.wizardlybump17.wlib.command.executor.CommandExecutor;
+import lombok.Getter;
+import org.jetbrains.annotations.NotNull;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+@Getter
+public class RegisteredMethodCommand extends RegisteredCommand {
+
+ private final @NotNull Command annotation;
+ private final @NotNull Object object;
+ private final @NotNull Method method;
+ private final @NotNull MethodHandle methodHandle;
+
+ public RegisteredMethodCommand(@NotNull Command annotation, @NotNull Object object, @NotNull Method method) throws NoSuchMethodException, IllegalAccessException {
+ super(
+ new AnnotationCommandData(
+ annotation,
+ object
+ ),
+ new ArrayList<>()
+ );
+ this.annotation = annotation;
+ this.object = object;
+ this.method = method;
+ methodHandle = MethodHandles.publicLookup().findVirtual(object.getClass(), method.getName(), MethodType.methodType(method.getReturnType(), method.getParameterTypes()));
+ prepareNodes();
+ }
+
+ @Override
+ protected CommandExecutor createExecutor() {
+ return (sender, args) -> {
+ List objects = new ArrayList<>(args.values());
+ objects.add(0, object);
+ objects.add(1, sender);
+ try {
+ methodHandle.invokeWithArguments(objects);
+ } catch (Throwable e) {
+ throw new CommandException("Error while executing the command " + getCommand().getExecution() + " with the arguments " + args, e);
+ }
+ };
+ }
+
+ protected void prepareNodes() {
+ String[] commandArgs = getCommand().getExecution().split(" ");
+
+ Class>[] types = method.getParameterTypes();
+ Parameter[] parameters = method.getParameters();
+ int index = 1; //skipping the first type because of the CommandSender
+ for (String commandArg : commandArgs) {
+ if (!isRequiredArgs(commandArg)) {
+ getNodes().add(new ArgsNode(
+ commandArg,
+ false,
+ null,
+ null,
+ false
+ ));
+ continue;
+ }
+
+ Description description = parameters[index].getAnnotation(Description.class);
+
+ ArgsReaderType argsReaderType = parameters[index].getAnnotation(ArgsReaderType.class);
+ if (argsReaderType == null && Argument.class.isAssignableFrom(types[index]))
+ throw new IllegalArgumentException("the \"" + commandArg + "\" argument requires the " + ArgsReaderType.class.getName() + " annotation");
+
+ ArgsReader> reader;
+ if (argsReaderType == null)
+ reader = ArgsReaderRegistry.INSTANCE.getReader(types[index]);
+ else
+ reader = ArgsReaderRegistry.INSTANCE.get(argsReaderType.value());
+ if (reader == null)
+ throw new IllegalArgumentException("no reader found for " + types[index].getName());
+
+ getNodes().add(new ArgsNode(
+ trim(commandArg),
+ true,
+ reader,
+ description == null ? null : description.value(),
+ Argument.class.isAssignableFrom(types[index])
+ ));
+
+ index++;
+ }
+ }
+
+ @Override
+ protected boolean isValidArgs(@NotNull LinkedHashMap args) {
+ return args.size() + 1 == method.getParameterCount();
+ }
+
+ @Override
+ public boolean isOwnedBy(@NotNull Object object) {
+ return this.object == object;
+ }
+
+ private static String trim(String string) {
+ return string.substring(1, string.length() - 1);
+ }
+
+ private static boolean isRequiredArgs(String string) {
+ return string.startsWith("<") && string.endsWith(">");
+ }
+}
\ No newline at end of file
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/sender/BasicCommandSender.java b/commands/src/main/java/com/wizardlybump17/wlib/command/sender/BasicCommandSender.java
new file mode 100644
index 00000000..8f2d8f86
--- /dev/null
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/sender/BasicCommandSender.java
@@ -0,0 +1,164 @@
+package com.wizardlybump17.wlib.command.sender;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Objects;
+import java.util.UUID;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+public class BasicCommandSender implements CommandSender {
+
+ private final @NotNull S handle;
+ private final @NotNull String name;
+ private final @NotNull UUID id;
+ private final @NotNull Consumer messageConsumer;
+ private final @NotNull Predicate permissionTest;
+
+ public BasicCommandSender(@NotNull S handle, @NotNull String name, @NotNull UUID id, @NotNull Consumer messageConsumer, @NotNull Predicate permissionTest) {
+ this.handle = handle;
+ this.name = name;
+ this.id = id;
+ this.messageConsumer = messageConsumer;
+ this.permissionTest = permissionTest;
+ }
+
+ @Override
+ public @NotNull S getHandle() {
+ return handle;
+ }
+
+ @Override
+ public void sendMessage(String message) {
+ messageConsumer.accept(message);
+ }
+
+ @Override
+ public void sendMessage(String... messages) {
+ sendMessage(String.join("\n", messages));
+ }
+
+ @Override
+ public @NotNull String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean hasPermission(String permission) {
+ return permissionTest.test(permission);
+ }
+
+ @Override
+ public boolean hasId(@NotNull UUID id) {
+ return id.equals(this.id);
+ }
+
+ public @NotNull UUID getId() {
+ return id;
+ }
+
+ public @NotNull Consumer getMessageConsumer() {
+ return messageConsumer;
+ }
+
+ public @NotNull Predicate getPermissionTest() {
+ return permissionTest;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || getClass() != o.getClass())
+ return false;
+ BasicCommandSender> that = (BasicCommandSender>) o;
+ return Objects.equals(handle, that.handle) && Objects.equals(name, that.name) && Objects.equals(id, that.id)
+ && Objects.equals(messageConsumer, that.messageConsumer) && Objects.equals(permissionTest, that.permissionTest);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(handle, name, id, messageConsumer, permissionTest);
+ }
+
+ @Override
+ public String toString() {
+ return "BasicCommandSender{" +
+ "handle=" + handle +
+ ", name='" + name + '\'' +
+ ", id=" + id +
+ ", messageConsumer=" + messageConsumer +
+ ", permissionTest=" + permissionTest +
+ '}';
+ }
+
+ public static Builder builder() {
+ return new Builder<>();
+ }
+
+ public static class Builder {
+
+ private @Nullable S handle;
+ private @Nullable String name;
+ private @Nullable UUID id;
+ private @Nullable Consumer messageConsumer;
+ private @Nullable Predicate permissionTest;
+
+ protected Builder() {
+ }
+
+ public @Nullable S handle() {
+ return handle;
+ }
+
+ public @NotNull Builder handle(@Nullable S handle) {
+ this.handle = handle;
+ return this;
+ }
+
+ public @Nullable String name() {
+ return name;
+ }
+
+ public @NotNull Builder name(@Nullable String name) {
+ this.name = name;
+ return this;
+ }
+
+ public @Nullable UUID id() {
+ return id;
+ }
+
+ public @NotNull Builder id(@Nullable UUID id) {
+ this.id = id;
+ return this;
+ }
+
+ public @Nullable Consumer messageConsumer() {
+ return messageConsumer;
+ }
+
+ public @NotNull Builder messageConsumer(@Nullable Consumer messageConsumer) {
+ this.messageConsumer = messageConsumer;
+ return this;
+ }
+
+ public @Nullable Predicate permissionTest() {
+ return permissionTest;
+ }
+
+ public @NotNull Builder permissionTest(@Nullable Predicate permissionTest) {
+ this.permissionTest = permissionTest;
+ return this;
+ }
+
+ public @NotNull BasicCommandSender build() {
+ return new BasicCommandSender<>(
+ Objects.requireNonNull(handle, "the 'handler' can not be null"),
+ Objects.requireNonNull(name, "the 'name' can not be null"),
+ Objects.requireNonNull(id, "the 'id' can not be null"),
+ messageConsumer == null ? System.out::println : messageConsumer,
+ permissionTest == null ? permission -> true : permissionTest
+ );
+ }
+ }
+}
diff --git a/commands/src/main/java/com/wizardlybump17/wlib/command/CommandSender.java b/commands/src/main/java/com/wizardlybump17/wlib/command/sender/CommandSender.java
similarity index 54%
rename from commands/src/main/java/com/wizardlybump17/wlib/command/CommandSender.java
rename to commands/src/main/java/com/wizardlybump17/wlib/command/sender/CommandSender.java
index c4b89aa3..0786ac74 100644
--- a/commands/src/main/java/com/wizardlybump17/wlib/command/CommandSender.java
+++ b/commands/src/main/java/com/wizardlybump17/wlib/command/sender/CommandSender.java
@@ -1,6 +1,8 @@
-package com.wizardlybump17.wlib.command;
+package com.wizardlybump17.wlib.command.sender;
-import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.UUID;
/**
* Represents a command sender, someone that can trigger commands.
@@ -22,13 +24,5 @@ public interface CommandSender {
boolean hasPermission(String permission);
- /**
- * Used to convert this CommandSender to a generic sender, a command sender that can be anything
- *
- * @return the generic sender
- */
- @Nullable
- default CommandSender> toGeneric() {
- return null;
- }
+ boolean hasId(@NotNull UUID id);
}
diff --git a/commands/src/test/java/com/wizardlybump17/wlib/command/test/sender/BasicCommandSenderTests.java b/commands/src/test/java/com/wizardlybump17/wlib/command/test/sender/BasicCommandSenderTests.java
new file mode 100644
index 00000000..6c66a360
--- /dev/null
+++ b/commands/src/test/java/com/wizardlybump17/wlib/command/test/sender/BasicCommandSenderTests.java
@@ -0,0 +1,64 @@
+package com.wizardlybump17.wlib.command.test.sender;
+
+import com.wizardlybump17.wlib.command.sender.BasicCommandSender;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.UUID;
+
+class BasicCommandSenderTests {
+
+ @Test
+ void testPermissionsAllTrue() {
+ String name = "Test Sender";
+ BasicCommandSender sender = BasicCommandSender.builder()
+ .handle(new Object())
+ .name(name)
+ .id(UUID.nameUUIDFromBytes(name.getBytes()))
+ .permissionTest(permission -> true)
+ .build();
+ Assertions.assertTrue(sender.hasPermission("test0.permission0"));
+ Assertions.assertTrue(sender.hasPermission("test0.permission1"));
+ Assertions.assertTrue(sender.hasPermission("test0.permission2"));
+ Assertions.assertTrue(sender.hasPermission("test1.permission0"));
+ Assertions.assertTrue(sender.hasPermission("test1.permission1"));
+ Assertions.assertTrue(sender.hasPermission("test1.permission2"));
+ }
+
+ @Test
+ void testPermissionsAllFalse() {
+ String name = "Test Sender";
+ BasicCommandSender sender = BasicCommandSender.builder()
+ .handle(new Object())
+ .name(name)
+ .id(UUID.nameUUIDFromBytes(name.getBytes()))
+ .permissionTest(permission -> false)
+ .build();
+ Assertions.assertFalse(sender.hasPermission("test0.permission0"));
+ Assertions.assertFalse(sender.hasPermission("test0.permission1"));
+ Assertions.assertFalse(sender.hasPermission("test0.permission2"));
+ Assertions.assertFalse(sender.hasPermission("test1.permission0"));
+ Assertions.assertFalse(sender.hasPermission("test1.permission1"));
+ Assertions.assertFalse(sender.hasPermission("test1.permission2"));
+ }
+
+ @Test
+ void testSpecificPermissions() {
+ String name = "Test Sender";
+ BasicCommandSender sender = BasicCommandSender.builder()
+ .handle(new Object())
+ .name(name)
+ .id(UUID.nameUUIDFromBytes(name.getBytes()))
+ .permissionTest(permission -> permission.startsWith("test0."))
+ .build();
+ Assertions.assertTrue(sender.hasPermission("test0.permission0"));
+ Assertions.assertTrue(sender.hasPermission("test0.permission1"));
+ Assertions.assertTrue(sender.hasPermission("test0.permission2"));
+ Assertions.assertFalse(sender.hasPermission("test1.permission0"));
+ Assertions.assertFalse(sender.hasPermission("test1.permission1"));
+ Assertions.assertFalse(sender.hasPermission("test1.permission2"));
+ Assertions.assertFalse(sender.hasPermission("test2.permission0"));
+ Assertions.assertFalse(sender.hasPermission("test2.permission1"));
+ Assertions.assertFalse(sender.hasPermission("test2.permission2"));
+ }
+}
diff --git a/core/build.gradle b/core/build.gradle
index 776fb140..b31666b8 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -4,6 +4,9 @@ dependencies {
'org.jetbrains:annotations:23.1.0',
'org.spigotmc:spigot:1.17.1-R0.1-SNAPSHOT',
)
+ compileOnly("net.kyori:adventure-api:4.18.0")
+ compileOnly("net.kyori:adventure-text-minimessage:4.18.0")
+ compileOnly("net.kyori:adventure-platform-bukkit:4.3.4")
annotationProcessor('org.projectlombok:lombok:1.18.24')
implementation(
diff --git a/core/src/main/java/com/wizardlybump17/wlib/WLib.java b/core/src/main/java/com/wizardlybump17/wlib/WLib.java
index 5360dca2..bf90d6db 100644
--- a/core/src/main/java/com/wizardlybump17/wlib/WLib.java
+++ b/core/src/main/java/com/wizardlybump17/wlib/WLib.java
@@ -3,6 +3,7 @@
import com.wizardlybump17.wlib.adapter.EnchantmentAdapter;
import com.wizardlybump17.wlib.adapter.ItemAdapter;
import com.wizardlybump17.wlib.adapter.PotionEffectTypeAdapter;
+import com.wizardlybump17.wlib.adapter.command.CommandMapAdapter;
import com.wizardlybump17.wlib.adapter.v1_19_R2.player.PlayerAdapter;
import com.wizardlybump17.wlib.command.args.ArgsReaderRegistry;
import com.wizardlybump17.wlib.command.reader.*;
@@ -28,15 +29,18 @@
import com.wizardlybump17.wlib.util.bukkit.particle.*;
import lombok.Getter;
import lombok.NonNull;
+import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bukkit.Bukkit;
import org.bukkit.configuration.serialization.ConfigurationSerialization;
import org.bukkit.event.HandlerList;
import org.bukkit.plugin.java.JavaPlugin;
+import org.jetbrains.annotations.NotNull;
@Getter
public class WLib extends JavaPlugin {
private final SaveControllersTask saveControllersTask = new SaveControllersTask(getLogger());
+ private BukkitAudiences audiences;
@Override
public void onLoad() {
@@ -63,6 +67,8 @@ protected void initConfigs() {
@Override
public void onEnable() {
+ audiences = BukkitAudiences.create(this);
+
Bukkit.getPluginManager().registerEvents(new EntityListener(), this);
Bukkit.getPluginManager().registerEvents(new PlayerListener(this), this);
@@ -75,6 +81,11 @@ public void onEnable() {
public void onDisable() {
HandlerList.unregisterAll(this);
saveControllersTask.cancel();
+
+ if (audiences != null) {
+ audiences.close();
+ audiences = null;
+ }
}
private void initCommandSystem() {
@@ -121,60 +132,70 @@ private void setupAdapters() {
PlayerAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_16_R3.player.PlayerAdapter());
PotionEffectTypeAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_16_R3.PotionEffectTypeAdapter());
EnchantmentAdapter.setInstance(new EnchantmentAdapter());
+ CommandMapAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_16_R3.command.CommandMapAdapter());
}
case V1_17_1 -> {
ItemAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_17_R1.ItemAdapter());
PlayerAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_17_R1.player.PlayerAdapter());
PotionEffectTypeAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_17_R1.PotionEffectTypeAdapter());
EnchantmentAdapter.setInstance(new EnchantmentAdapter());
+ CommandMapAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_17_R1.command.CommandMapAdapter());
}
case V1_18 -> {
ItemAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_18_R1.ItemAdapter());
PlayerAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_18_R1.player.PlayerAdapter());
PotionEffectTypeAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_18_R1.PotionEffectTypeAdapter());
EnchantmentAdapter.setInstance(new EnchantmentAdapter());
+ CommandMapAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_18_R1.command.CommandMapAdapter());
}
case V1_18_2 -> {
ItemAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_18_R2.ItemAdapter());
PlayerAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_18_R2.player.PlayerAdapter());
PotionEffectTypeAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_18_R2.PotionEffectTypeAdapter());
EnchantmentAdapter.setInstance(new EnchantmentAdapter());
+ CommandMapAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_18_R2.command.CommandMapAdapter());
}
case V1_19 -> {
ItemAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_19_R1.ItemAdapter());
PlayerAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_19_R1.player.PlayerAdapter());
PotionEffectTypeAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_19_R1.PotionEffectTypeAdapter());
EnchantmentAdapter.setInstance(new EnchantmentAdapter());
+ CommandMapAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_19_R1.command.CommandMapAdapter());
}
case V1_19_3 -> {
ItemAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_19_R2.ItemAdapter());
PlayerAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_19_R2.player.PlayerAdapter());
PotionEffectTypeAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_19_R2.PotionEffectTypeAdapter());
EnchantmentAdapter.setInstance(new EnchantmentAdapter());
+ CommandMapAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_19_R2.command.CommandMapAdapter());
}
case V1_19_4 -> {
ItemAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_19_R3.ItemAdapter());
PlayerAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_19_R3.player.PlayerAdapter());
PotionEffectTypeAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_19_R3.PotionEffectTypeAdapter());
EnchantmentAdapter.setInstance(new EnchantmentAdapter());
+ CommandMapAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_19_R3.command.CommandMapAdapter());
}
case V1_20_1 -> {
ItemAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_20_R1.ItemAdapter());
PlayerAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_20_R1.player.PlayerAdapter());
PotionEffectTypeAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_20_R1.PotionEffectTypeAdapter());
EnchantmentAdapter.setInstance(new EnchantmentAdapter());
+ CommandMapAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_20_R1.command.CommandMapAdapter());
}
case V1_20_2 -> {
ItemAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_20_R2.ItemAdapter());
PlayerAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_20_R2.player.PlayerAdapter());
PotionEffectTypeAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_20_R2.PotionEffectTypeAdapter());
EnchantmentAdapter.setInstance(new EnchantmentAdapter());
+ CommandMapAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_20_R2.command.CommandMapAdapter());
}
case V1_20_4 -> {
ItemAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_20_R3.ItemAdapter());
PlayerAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_20_R3.player.PlayerAdapter());
PotionEffectTypeAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_20_R3.PotionEffectTypeAdapter());
EnchantmentAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_20_R3.EnchantmentAdapter());
+ CommandMapAdapter.setInstance(new com.wizardlybump17.wlib.adapter.v1_20_R3.command.CommandMapAdapter());
}
}
@@ -194,4 +215,8 @@ public static WLib getInstance() {
public static @NonNull String getServerVersion() {
return Bukkit.getServer().getClass().getName().split("\\.")[3];
}
+
+ public @NotNull BukkitAudiences getAudiences() {
+ return audiences;
+ }
}
diff --git a/core/src/main/java/com/wizardlybump17/wlib/command/BukkitCommandExecutor.java b/core/src/main/java/com/wizardlybump17/wlib/command/BukkitCommandExecutor.java
index c5577b03..c878081f 100644
--- a/core/src/main/java/com/wizardlybump17/wlib/command/BukkitCommandExecutor.java
+++ b/core/src/main/java/com/wizardlybump17/wlib/command/BukkitCommandExecutor.java
@@ -1,54 +1,41 @@
package com.wizardlybump17.wlib.command;
-import com.wizardlybump17.wlib.command.sender.ConsoleSender;
-import com.wizardlybump17.wlib.command.sender.GenericSender;
-import com.wizardlybump17.wlib.command.sender.PlayerSender;
+import com.wizardlybump17.wlib.command.exception.CommandException;
+import com.wizardlybump17.wlib.command.sender.BukkitCommandSender;
+import com.wizardlybump17.wlib.command.sender.CommandSender;
import lombok.RequiredArgsConstructor;
-import lombok.SneakyThrows;
import org.bukkit.command.Command;
-import org.bukkit.command.CommandSender;
-import org.bukkit.command.*;
-import org.bukkit.entity.Player;
+import org.bukkit.command.TabExecutor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
+import java.util.logging.Level;
@RequiredArgsConstructor
public class BukkitCommandExecutor implements TabExecutor, com.wizardlybump17.wlib.command.holder.CommandExecutor {
private final CommandManager manager;
- @SneakyThrows
@Override
- public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
- execute(getSender(sender), command.getName(), args);
+ public boolean onCommand(@NotNull org.bukkit.command.CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
+ try {
+ execute(new BukkitCommandSender(sender), command.getName(), args);
+ } catch (CommandException e) {
+ manager.getHolder().getLogger().log(Level.SEVERE, "Error while executing a command", e);
+ }
return false;
}
@Override
- public void execute(com.wizardlybump17.wlib.command.CommandSender> sender, String commandName, String[] args) {
+ public void execute(CommandSender> sender, String commandName, String[] args) throws CommandException {
String commandExecution = commandName + " " + String.join(" ", args);
manager.execute(sender, commandExecution);
}
@Nullable
@Override
- public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
-// String fullCommand = command.getName() + " " + String.join(" ", args);
-// List suggestions = manager.autoComplete(getSender(sender), fullCommand);
-// ArrayList strings = StringUtil.copyPartialMatches(args[args.length - 1], suggestions, new ArrayList<>(suggestions.size()));
-// return strings;
+ public List onTabComplete(@NotNull org.bukkit.command.CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
return null;
}
-
- private com.wizardlybump17.wlib.command.CommandSender> getSender(CommandSender original) {
- if (original instanceof Player player)
- return new PlayerSender(player);
- if (original instanceof ConsoleCommandSender consoleSender)
- return new ConsoleSender(consoleSender);
- if (original instanceof BlockCommandSender blockSender)
- return new com.wizardlybump17.wlib.command.sender.BlockCommandSender(blockSender);
- return new GenericSender(original);
- }
}
diff --git a/core/src/main/java/com/wizardlybump17/wlib/command/completer/EntityTypeArgumentCompleter.java b/core/src/main/java/com/wizardlybump17/wlib/command/completer/EntityTypeArgumentCompleter.java
index de7bf8f4..2068365d 100644
--- a/core/src/main/java/com/wizardlybump17/wlib/command/completer/EntityTypeArgumentCompleter.java
+++ b/core/src/main/java/com/wizardlybump17/wlib/command/completer/EntityTypeArgumentCompleter.java
@@ -1,6 +1,6 @@
package com.wizardlybump17.wlib.command.completer;
-import com.wizardlybump17.wlib.command.CommandSender;
+import com.wizardlybump17.wlib.command.sender.CommandSender;
import lombok.NonNull;
import org.bukkit.entity.EntityType;
diff --git a/core/src/main/java/com/wizardlybump17/wlib/command/completer/MaterialArgumentCompleter.java b/core/src/main/java/com/wizardlybump17/wlib/command/completer/MaterialArgumentCompleter.java
index 6ded4874..8c72508f 100644
--- a/core/src/main/java/com/wizardlybump17/wlib/command/completer/MaterialArgumentCompleter.java
+++ b/core/src/main/java/com/wizardlybump17/wlib/command/completer/MaterialArgumentCompleter.java
@@ -1,6 +1,6 @@
package com.wizardlybump17.wlib.command.completer;
-import com.wizardlybump17.wlib.command.CommandSender;
+import com.wizardlybump17.wlib.command.sender.CommandSender;
import lombok.NonNull;
import org.bukkit.Material;
diff --git a/core/src/main/java/com/wizardlybump17/wlib/command/completer/PlayerArgumentCompleter.java b/core/src/main/java/com/wizardlybump17/wlib/command/completer/PlayerArgumentCompleter.java
index 2d963104..29145e42 100644
--- a/core/src/main/java/com/wizardlybump17/wlib/command/completer/PlayerArgumentCompleter.java
+++ b/core/src/main/java/com/wizardlybump17/wlib/command/completer/PlayerArgumentCompleter.java
@@ -1,6 +1,6 @@
package com.wizardlybump17.wlib.command.completer;
-import com.wizardlybump17.wlib.command.CommandSender;
+import com.wizardlybump17.wlib.command.sender.CommandSender;
import lombok.NonNull;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
diff --git a/core/src/main/java/com/wizardlybump17/wlib/command/reader/BlockDataArgsReader.java b/core/src/main/java/com/wizardlybump17/wlib/command/reader/BlockDataArgsReader.java
index dca102c3..8b9ca548 100644
--- a/core/src/main/java/com/wizardlybump17/wlib/command/reader/BlockDataArgsReader.java
+++ b/core/src/main/java/com/wizardlybump17/wlib/command/reader/BlockDataArgsReader.java
@@ -1,8 +1,8 @@
package com.wizardlybump17.wlib.command.reader;
-import com.wizardlybump17.wlib.command.CommandSender;
import com.wizardlybump17.wlib.command.args.reader.ArgsReader;
import com.wizardlybump17.wlib.command.args.reader.ArgsReaderException;
+import com.wizardlybump17.wlib.command.sender.CommandSender;
import lombok.NonNull;
import org.bukkit.Bukkit;
import org.bukkit.Material;
diff --git a/core/src/main/java/com/wizardlybump17/wlib/command/reader/EntityTypeArgsReader.java b/core/src/main/java/com/wizardlybump17/wlib/command/reader/EntityTypeArgsReader.java
index 4ca9a7ce..c6986ffb 100644
--- a/core/src/main/java/com/wizardlybump17/wlib/command/reader/EntityTypeArgsReader.java
+++ b/core/src/main/java/com/wizardlybump17/wlib/command/reader/EntityTypeArgsReader.java
@@ -1,7 +1,7 @@
package com.wizardlybump17.wlib.command.reader;
-import com.wizardlybump17.wlib.command.CommandSender;
import com.wizardlybump17.wlib.command.args.reader.ArgsReader;
+import com.wizardlybump17.wlib.command.sender.CommandSender;
import lombok.NonNull;
import org.bukkit.entity.EntityType;
diff --git a/core/src/main/java/com/wizardlybump17/wlib/command/reader/MapJsonArgsReader.java b/core/src/main/java/com/wizardlybump17/wlib/command/reader/MapJsonArgsReader.java
index a456c1c8..d7c82251 100644
--- a/core/src/main/java/com/wizardlybump17/wlib/command/reader/MapJsonArgsReader.java
+++ b/core/src/main/java/com/wizardlybump17/wlib/command/reader/MapJsonArgsReader.java
@@ -2,9 +2,9 @@
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
-import com.wizardlybump17.wlib.command.CommandSender;
import com.wizardlybump17.wlib.command.args.reader.ArgsReader;
import com.wizardlybump17.wlib.command.args.reader.ArgsReaderException;
+import com.wizardlybump17.wlib.command.sender.CommandSender;
import lombok.NonNull;
import java.util.List;
diff --git a/core/src/main/java/com/wizardlybump17/wlib/command/reader/MaterialReader.java b/core/src/main/java/com/wizardlybump17/wlib/command/reader/MaterialReader.java
index 8251dd9c..2daf7f90 100644
--- a/core/src/main/java/com/wizardlybump17/wlib/command/reader/MaterialReader.java
+++ b/core/src/main/java/com/wizardlybump17/wlib/command/reader/MaterialReader.java
@@ -1,7 +1,7 @@
package com.wizardlybump17.wlib.command.reader;
-import com.wizardlybump17.wlib.command.CommandSender;
import com.wizardlybump17.wlib.command.args.reader.ArgsReader;
+import com.wizardlybump17.wlib.command.sender.CommandSender;
import lombok.NonNull;
import org.bukkit.Material;
diff --git a/core/src/main/java/com/wizardlybump17/wlib/command/reader/OfflinePlayerReader.java b/core/src/main/java/com/wizardlybump17/wlib/command/reader/OfflinePlayerReader.java
index 5da69881..46c29ea4 100644
--- a/core/src/main/java/com/wizardlybump17/wlib/command/reader/OfflinePlayerReader.java
+++ b/core/src/main/java/com/wizardlybump17/wlib/command/reader/OfflinePlayerReader.java
@@ -1,7 +1,7 @@
package com.wizardlybump17.wlib.command.reader;
-import com.wizardlybump17.wlib.command.CommandSender;
import com.wizardlybump17.wlib.command.args.reader.ArgsReader;
+import com.wizardlybump17.wlib.command.sender.CommandSender;
import lombok.NonNull;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
diff --git a/core/src/main/java/com/wizardlybump17/wlib/command/reader/PlayerReader.java b/core/src/main/java/com/wizardlybump17/wlib/command/reader/PlayerReader.java
index ddb38aa7..1521ff37 100644
--- a/core/src/main/java/com/wizardlybump17/wlib/command/reader/PlayerReader.java
+++ b/core/src/main/java/com/wizardlybump17/wlib/command/reader/PlayerReader.java
@@ -1,7 +1,7 @@
package com.wizardlybump17.wlib.command.reader;
-import com.wizardlybump17.wlib.command.CommandSender;
import com.wizardlybump17.wlib.command.args.reader.ArgsReader;
+import com.wizardlybump17.wlib.command.sender.CommandSender;
import lombok.NonNull;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
diff --git a/core/src/main/java/com/wizardlybump17/wlib/command/registered/RegisteredBukkitCommand.java b/core/src/main/java/com/wizardlybump17/wlib/command/registered/RegisteredBukkitCommand.java
new file mode 100644
index 00000000..46ea8992
--- /dev/null
+++ b/core/src/main/java/com/wizardlybump17/wlib/command/registered/RegisteredBukkitCommand.java
@@ -0,0 +1,59 @@
+package com.wizardlybump17.wlib.command.registered;
+
+import com.wizardlybump17.wlib.adapter.command.CommandMapAdapter;
+import com.wizardlybump17.wlib.command.CommandManager;
+import com.wizardlybump17.wlib.command.args.ArgsNode;
+import com.wizardlybump17.wlib.command.data.CommandData;
+import com.wizardlybump17.wlib.command.exception.CommandException;
+import com.wizardlybump17.wlib.command.executor.CommandExecutor;
+import com.wizardlybump17.wlib.command.sender.BukkitCommandSender;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandMap;
+import org.bukkit.command.CommandSender;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class RegisteredBukkitCommand extends RegisteredCommand {
+
+ private final @NotNull String fallback;
+
+ public RegisteredBukkitCommand(@NotNull CommandData command, @NotNull List nodes, @NotNull CommandExecutor executor, @NotNull String fallback) {
+ super(command, nodes, executor);
+ this.fallback = fallback;
+ }
+
+ public @NotNull String getFallback() {
+ return fallback;
+ }
+
+ @Override
+ public void onRegister(@NotNull CommandManager manager) {
+ CommandMap commandMap = CommandMapAdapter.getInstance().getCommandMap();
+ String name = getCommand().getName();
+ Logger logger = manager.getHolder().getLogger();
+
+ commandMap.register(name, fallback, new Command(name) {
+ @Override
+ public boolean execute(@NotNull CommandSender sender, @NotNull String label, @NotNull String[] args) {
+ try {
+ manager.execute(new BukkitCommandSender(sender), name + " " + String.join(" ", args));
+ } catch (CommandException e) {
+ logger.log(Level.SEVERE, "Error while executing a command.", e);
+ }
+ return false;
+ }
+ });
+ }
+
+ @Override
+ public void onUnregister(@NotNull CommandManager manager) {
+ CommandMapAdapter adapter = CommandMapAdapter.getInstance();
+
+ String name = getCommand().getName();
+ adapter.unregisterCommand(name);
+ adapter.unregisterCommand(fallback + ":" + name);
+ }
+}
diff --git a/core/src/main/java/com/wizardlybump17/wlib/command/sender/AbstractSender.java b/core/src/main/java/com/wizardlybump17/wlib/command/sender/AbstractSender.java
deleted file mode 100644
index 98af7103..00000000
--- a/core/src/main/java/com/wizardlybump17/wlib/command/sender/AbstractSender.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.wizardlybump17.wlib.command.sender;
-
-import com.wizardlybump17.wlib.command.CommandSender;
-import lombok.Getter;
-import lombok.NonNull;
-import lombok.RequiredArgsConstructor;
-
-@RequiredArgsConstructor
-@Getter
-public abstract class AbstractSender implements CommandSender {
-
- private final S handle;
-
- @Override
- public void sendMessage(String message) {
- handle.sendMessage(message);
- }
-
- @Override
- public void sendMessage(String... message) {
- handle.sendMessage(String.join("\n", message));
- }
-
- @Override
- public String getName() {
- return handle.getName();
- }
-
- @Override
- public boolean hasPermission(String permission) {
- return handle.hasPermission(permission);
- }
-
- @Override
- @NonNull
- public GenericSender toGeneric() {
- return new GenericSender(handle);
- }
-}
diff --git a/core/src/main/java/com/wizardlybump17/wlib/command/sender/BlockCommandSender.java b/core/src/main/java/com/wizardlybump17/wlib/command/sender/BlockCommandSender.java
deleted file mode 100644
index 2f3b8455..00000000
--- a/core/src/main/java/com/wizardlybump17/wlib/command/sender/BlockCommandSender.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.wizardlybump17.wlib.command.sender;
-
-public class BlockCommandSender extends AbstractSender {
-
- public BlockCommandSender(org.bukkit.command.BlockCommandSender handle) {
- super(handle);
- }
-}
diff --git a/core/src/main/java/com/wizardlybump17/wlib/command/sender/BukkitCommandSender.java b/core/src/main/java/com/wizardlybump17/wlib/command/sender/BukkitCommandSender.java
new file mode 100644
index 00000000..d13d6355
--- /dev/null
+++ b/core/src/main/java/com/wizardlybump17/wlib/command/sender/BukkitCommandSender.java
@@ -0,0 +1,90 @@
+package com.wizardlybump17.wlib.command.sender;
+
+import com.wizardlybump17.wlib.WLib;
+import com.wizardlybump17.wlib.util.bukkit.MiniMessageUtil;
+import net.kyori.adventure.chat.ChatType;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.ComponentLike;
+import org.bukkit.command.BlockCommandSender;
+import org.bukkit.command.ConsoleCommandSender;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+import java.util.UUID;
+
+public class BukkitCommandSender implements CommandSender {
+
+ private final @NotNull org.bukkit.command.CommandSender handle;
+
+ public BukkitCommandSender(@NotNull org.bukkit.command.CommandSender handle) {
+ this.handle = handle;
+ }
+
+ @Override
+ public org.bukkit.command.CommandSender getHandle() {
+ return handle;
+ }
+
+ @Override
+ public void sendMessage(String message) {
+ handle.sendMessage(message);
+ }
+
+ @Override
+ public void sendMessage(String... message) {
+ handle.sendMessage(String.join("\n", message));
+ }
+
+ public void sendMiniMessage(@NotNull String message, @NotNull Map placeholders) {
+ WLib.getInstance().getAudiences().sender(handle).sendMessage(MiniMessageUtil.getMessage(message, placeholders));
+ }
+
+ public void sendMiniMessage(@NotNull String message) {
+ sendMiniMessage(message, Map.of());
+ }
+
+ public void sendMessage(@NotNull Component message) {
+ WLib.getInstance().getAudiences().sender(handle).sendMessage(message);
+ }
+
+ public void sendMessage(@NotNull Component message, @NotNull ChatType.Bound type) {
+ WLib.getInstance().getAudiences().sender(handle).sendMessage(message, type);
+ }
+
+ public void sendMessage(@NotNull ComponentLike message) {
+ WLib.getInstance().getAudiences().sender(handle).sendMessage(message);
+ }
+
+ public void sendMessage(@NotNull ComponentLike message, @NotNull ChatType.Bound type) {
+ WLib.getInstance().getAudiences().sender(handle).sendMessage(message, type);
+ }
+
+ @Override
+ public String getName() {
+ return handle.getName();
+ }
+
+ @Override
+ public boolean hasPermission(String permission) {
+ return handle.hasPermission(permission);
+ }
+
+ public @NotNull BlockCommandSender asBlockCommand() {
+ return (BlockCommandSender) handle;
+ }
+
+ public @NotNull ConsoleCommandSender asConsole() {
+ return (ConsoleCommandSender) handle;
+ }
+
+ public @NotNull Player asPlayer() {
+ return (Player) handle;
+ }
+
+ @Override
+ public boolean hasId(@NotNull UUID id) {
+ return handle instanceof Entity entity && entity.getUniqueId().equals(id);
+ }
+}
diff --git a/core/src/main/java/com/wizardlybump17/wlib/command/sender/ConsoleSender.java b/core/src/main/java/com/wizardlybump17/wlib/command/sender/ConsoleSender.java
deleted file mode 100644
index 46e55e01..00000000
--- a/core/src/main/java/com/wizardlybump17/wlib/command/sender/ConsoleSender.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.wizardlybump17.wlib.command.sender;
-
-import org.bukkit.command.ConsoleCommandSender;
-
-public class ConsoleSender extends AbstractSender {
-
- public ConsoleSender(ConsoleCommandSender handle) {
- super(handle);
- }
-}
diff --git a/core/src/main/java/com/wizardlybump17/wlib/command/sender/GenericSender.java b/core/src/main/java/com/wizardlybump17/wlib/command/sender/GenericSender.java
deleted file mode 100644
index d223526d..00000000
--- a/core/src/main/java/com/wizardlybump17/wlib/command/sender/GenericSender.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.wizardlybump17.wlib.command.sender;
-
-import lombok.NonNull;
-import org.bukkit.command.CommandSender;
-
-public class GenericSender extends AbstractSender {
-
- public GenericSender(CommandSender handle) {
- super(handle);
- }
-
- @Override
- @NonNull
- public GenericSender toGeneric() {
- return this;
- }
-
- public static boolean isGeneric() {
- return true;
- }
-}
diff --git a/core/src/main/java/com/wizardlybump17/wlib/command/sender/PlayerSender.java b/core/src/main/java/com/wizardlybump17/wlib/command/sender/PlayerSender.java
deleted file mode 100644
index ac2f08eb..00000000
--- a/core/src/main/java/com/wizardlybump17/wlib/command/sender/PlayerSender.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.wizardlybump17.wlib.command.sender;
-
-import org.bukkit.entity.Player;
-
-public class PlayerSender extends AbstractSender {
-
- public PlayerSender(Player handle) {
- super(handle);
- }
-}
diff --git a/core/src/main/resources/plugin.yml b/core/src/main/resources/plugin.yml
index dee76513..35676d43 100644
--- a/core/src/main/resources/plugin.yml
+++ b/core/src/main/resources/plugin.yml
@@ -3,4 +3,8 @@ main: com.wizardlybump17.wlib.WLib
version: '${version}'
author: WizardlyBump17
api-version: '1.13'
-load: STARTUP
\ No newline at end of file
+load: STARTUP
+libraries:
+ - net.kyori:adventure-api:4.18.0
+ - net.kyori:adventure-text-minimessage:4.18.0
+ - net.kyori:adventure-platform-bukkit:4.3.4
diff --git a/versions/adapter/src/main/java/com/wizardlybump17/wlib/adapter/command/CommandMapAdapter.java b/versions/adapter/src/main/java/com/wizardlybump17/wlib/adapter/command/CommandMapAdapter.java
new file mode 100644
index 00000000..14a001ae
--- /dev/null
+++ b/versions/adapter/src/main/java/com/wizardlybump17/wlib/adapter/command/CommandMapAdapter.java
@@ -0,0 +1,28 @@
+package com.wizardlybump17.wlib.adapter.command;
+
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandMap;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+
+public abstract class CommandMapAdapter {
+
+ private static CommandMapAdapter instance;
+
+ public abstract @NotNull CommandMap getCommandMap();
+
+ public abstract void unregisterCommand(@NotNull String command);
+
+ public abstract @NotNull Map getCommands();
+
+ public static CommandMapAdapter getInstance() {
+ return instance;
+ }
+
+ public static void setInstance(@NotNull CommandMapAdapter instance) {
+ if (CommandMapAdapter.instance != null)
+ throw new IllegalStateException("The CommandAdapter instance is already set.");
+ CommandMapAdapter.instance = instance;
+ }
+}
diff --git a/versions/v1_16_R3/src/main/java/com/wizardlybump17/wlib/adapter/v1_16_R3/command/CommandMapAdapter.java b/versions/v1_16_R3/src/main/java/com/wizardlybump17/wlib/adapter/v1_16_R3/command/CommandMapAdapter.java
new file mode 100644
index 00000000..f2461fd8
--- /dev/null
+++ b/versions/v1_16_R3/src/main/java/com/wizardlybump17/wlib/adapter/v1_16_R3/command/CommandMapAdapter.java
@@ -0,0 +1,37 @@
+package com.wizardlybump17.wlib.adapter.v1_16_R3.command;
+
+import com.wizardlybump17.wlib.util.ReflectionUtil;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandMap;
+import org.bukkit.command.SimpleCommandMap;
+import org.jetbrains.annotations.NotNull;
+
+import java.lang.reflect.Field;
+import java.util.Map;
+
+public class CommandMapAdapter extends com.wizardlybump17.wlib.adapter.command.CommandMapAdapter {
+
+ public static final @NotNull Field COMMAND_MAP = ReflectionUtil.getField("commandMap", Bukkit.getServer().getClass());
+ public static final @NotNull Field COMMANDS = ReflectionUtil.getField("knownCommands", SimpleCommandMap.class);
+
+ @Override
+ public @NotNull CommandMap getCommandMap() {
+ return ReflectionUtil.getFieldValue(COMMAND_MAP, Bukkit.getServer());
+ }
+
+ @Override
+ public void unregisterCommand(@NotNull String command) {
+ Map commands = getCommands();
+ CommandMap commandMap = getCommandMap();
+
+ Command removed = commands.remove(command);
+ if (removed != null)
+ removed.unregister(commandMap);
+ }
+
+ @Override
+ public @NotNull Map getCommands() {
+ return ReflectionUtil.getFieldValue(COMMANDS, getCommandMap());
+ }
+}
diff --git a/versions/v1_17_R1/src/main/java/com/wizardlybump17/wlib/adapter/v1_17_R1/command/CommandMapAdapter.java b/versions/v1_17_R1/src/main/java/com/wizardlybump17/wlib/adapter/v1_17_R1/command/CommandMapAdapter.java
new file mode 100644
index 00000000..3e6d948d
--- /dev/null
+++ b/versions/v1_17_R1/src/main/java/com/wizardlybump17/wlib/adapter/v1_17_R1/command/CommandMapAdapter.java
@@ -0,0 +1,37 @@
+package com.wizardlybump17.wlib.adapter.v1_17_R1.command;
+
+import com.wizardlybump17.wlib.util.ReflectionUtil;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandMap;
+import org.bukkit.command.SimpleCommandMap;
+import org.jetbrains.annotations.NotNull;
+
+import java.lang.reflect.Field;
+import java.util.Map;
+
+public class CommandMapAdapter extends com.wizardlybump17.wlib.adapter.command.CommandMapAdapter {
+
+ public static final @NotNull Field COMMAND_MAP = ReflectionUtil.getField("commandMap", Bukkit.getServer().getClass());
+ public static final @NotNull Field COMMANDS = ReflectionUtil.getField("knownCommands", SimpleCommandMap.class);
+
+ @Override
+ public @NotNull CommandMap getCommandMap() {
+ return ReflectionUtil.getFieldValue(COMMAND_MAP, Bukkit.getServer());
+ }
+
+ @Override
+ public void unregisterCommand(@NotNull String command) {
+ Map commands = getCommands();
+ CommandMap commandMap = getCommandMap();
+
+ Command removed = commands.remove(command);
+ if (removed != null)
+ removed.unregister(commandMap);
+ }
+
+ @Override
+ public @NotNull Map getCommands() {
+ return ReflectionUtil.getFieldValue(COMMANDS, getCommandMap());
+ }
+}
diff --git a/versions/v1_18_R1/src/main/java/com/wizardlybump17/wlib/adapter/v1_18_R1/command/CommandMapAdapter.java b/versions/v1_18_R1/src/main/java/com/wizardlybump17/wlib/adapter/v1_18_R1/command/CommandMapAdapter.java
new file mode 100644
index 00000000..aa747170
--- /dev/null
+++ b/versions/v1_18_R1/src/main/java/com/wizardlybump17/wlib/adapter/v1_18_R1/command/CommandMapAdapter.java
@@ -0,0 +1,37 @@
+package com.wizardlybump17.wlib.adapter.v1_18_R1.command;
+
+import com.wizardlybump17.wlib.util.ReflectionUtil;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandMap;
+import org.bukkit.command.SimpleCommandMap;
+import org.jetbrains.annotations.NotNull;
+
+import java.lang.reflect.Field;
+import java.util.Map;
+
+public class CommandMapAdapter extends com.wizardlybump17.wlib.adapter.command.CommandMapAdapter {
+
+ public static final @NotNull Field COMMAND_MAP = ReflectionUtil.getField("commandMap", Bukkit.getServer().getClass());
+ public static final @NotNull Field COMMANDS = ReflectionUtil.getField("knownCommands", SimpleCommandMap.class);
+
+ @Override
+ public @NotNull CommandMap getCommandMap() {
+ return ReflectionUtil.getFieldValue(COMMAND_MAP, Bukkit.getServer());
+ }
+
+ @Override
+ public void unregisterCommand(@NotNull String command) {
+ Map commands = getCommands();
+ CommandMap commandMap = getCommandMap();
+
+ Command removed = commands.remove(command);
+ if (removed != null)
+ removed.unregister(commandMap);
+ }
+
+ @Override
+ public @NotNull Map getCommands() {
+ return ReflectionUtil.getFieldValue(COMMANDS, getCommandMap());
+ }
+}
diff --git a/versions/v1_18_R2/src/main/java/com/wizardlybump17/wlib/adapter/v1_18_R2/command/CommandMapAdapter.java b/versions/v1_18_R2/src/main/java/com/wizardlybump17/wlib/adapter/v1_18_R2/command/CommandMapAdapter.java
new file mode 100644
index 00000000..cdb45016
--- /dev/null
+++ b/versions/v1_18_R2/src/main/java/com/wizardlybump17/wlib/adapter/v1_18_R2/command/CommandMapAdapter.java
@@ -0,0 +1,37 @@
+package com.wizardlybump17.wlib.adapter.v1_18_R2.command;
+
+import com.wizardlybump17.wlib.util.ReflectionUtil;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandMap;
+import org.bukkit.command.SimpleCommandMap;
+import org.jetbrains.annotations.NotNull;
+
+import java.lang.reflect.Field;
+import java.util.Map;
+
+public class CommandMapAdapter extends com.wizardlybump17.wlib.adapter.command.CommandMapAdapter {
+
+ public static final @NotNull Field COMMAND_MAP = ReflectionUtil.getField("commandMap", Bukkit.getServer().getClass());
+ public static final @NotNull Field COMMANDS = ReflectionUtil.getField("knownCommands", SimpleCommandMap.class);
+
+ @Override
+ public @NotNull CommandMap getCommandMap() {
+ return ReflectionUtil.getFieldValue(COMMAND_MAP, Bukkit.getServer());
+ }
+
+ @Override
+ public void unregisterCommand(@NotNull String command) {
+ Map commands = getCommands();
+ CommandMap commandMap = getCommandMap();
+
+ Command removed = commands.remove(command);
+ if (removed != null)
+ removed.unregister(commandMap);
+ }
+
+ @Override
+ public @NotNull Map getCommands() {
+ return ReflectionUtil.getFieldValue(COMMANDS, getCommandMap());
+ }
+}
diff --git a/versions/v1_19_R1/src/main/java/com/wizardlybump17/wlib/adapter/v1_19_R1/command/CommandMapAdapter.java b/versions/v1_19_R1/src/main/java/com/wizardlybump17/wlib/adapter/v1_19_R1/command/CommandMapAdapter.java
new file mode 100644
index 00000000..a5ce6522
--- /dev/null
+++ b/versions/v1_19_R1/src/main/java/com/wizardlybump17/wlib/adapter/v1_19_R1/command/CommandMapAdapter.java
@@ -0,0 +1,37 @@
+package com.wizardlybump17.wlib.adapter.v1_19_R1.command;
+
+import com.wizardlybump17.wlib.util.ReflectionUtil;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandMap;
+import org.bukkit.command.SimpleCommandMap;
+import org.jetbrains.annotations.NotNull;
+
+import java.lang.reflect.Field;
+import java.util.Map;
+
+public class CommandMapAdapter extends com.wizardlybump17.wlib.adapter.command.CommandMapAdapter {
+
+ public static final @NotNull Field COMMAND_MAP = ReflectionUtil.getField("commandMap", Bukkit.getServer().getClass());
+ public static final @NotNull Field COMMANDS = ReflectionUtil.getField("knownCommands", SimpleCommandMap.class);
+
+ @Override
+ public @NotNull CommandMap getCommandMap() {
+ return ReflectionUtil.getFieldValue(COMMAND_MAP, Bukkit.getServer());
+ }
+
+ @Override
+ public void unregisterCommand(@NotNull String command) {
+ Map commands = getCommands();
+ CommandMap commandMap = getCommandMap();
+
+ Command removed = commands.remove(command);
+ if (removed != null)
+ removed.unregister(commandMap);
+ }
+
+ @Override
+ public @NotNull Map getCommands() {
+ return ReflectionUtil.getFieldValue(COMMANDS, getCommandMap());
+ }
+}
diff --git a/versions/v1_19_R2/src/main/java/com/wizardlybump17/wlib/adapter/v1_19_R2/command/CommandMapAdapter.java b/versions/v1_19_R2/src/main/java/com/wizardlybump17/wlib/adapter/v1_19_R2/command/CommandMapAdapter.java
new file mode 100644
index 00000000..4b7b0639
--- /dev/null
+++ b/versions/v1_19_R2/src/main/java/com/wizardlybump17/wlib/adapter/v1_19_R2/command/CommandMapAdapter.java
@@ -0,0 +1,37 @@
+package com.wizardlybump17.wlib.adapter.v1_19_R2.command;
+
+import com.wizardlybump17.wlib.util.ReflectionUtil;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandMap;
+import org.bukkit.command.SimpleCommandMap;
+import org.jetbrains.annotations.NotNull;
+
+import java.lang.reflect.Field;
+import java.util.Map;
+
+public class CommandMapAdapter extends com.wizardlybump17.wlib.adapter.command.CommandMapAdapter {
+
+ public static final @NotNull Field COMMAND_MAP = ReflectionUtil.getField("commandMap", Bukkit.getServer().getClass());
+ public static final @NotNull Field COMMANDS = ReflectionUtil.getField("knownCommands", SimpleCommandMap.class);
+
+ @Override
+ public @NotNull CommandMap getCommandMap() {
+ return ReflectionUtil.getFieldValue(COMMAND_MAP, Bukkit.getServer());
+ }
+
+ @Override
+ public void unregisterCommand(@NotNull String command) {
+ Map commands = getCommands();
+ CommandMap commandMap = getCommandMap();
+
+ Command removed = commands.remove(command);
+ if (removed != null)
+ removed.unregister(commandMap);
+ }
+
+ @Override
+ public @NotNull Map getCommands() {
+ return ReflectionUtil.getFieldValue(COMMANDS, getCommandMap());
+ }
+}
diff --git a/versions/v1_19_R3/src/main/java/com/wizardlybump17/wlib/adapter/v1_19_R3/command/CommandMapAdapter.java b/versions/v1_19_R3/src/main/java/com/wizardlybump17/wlib/adapter/v1_19_R3/command/CommandMapAdapter.java
new file mode 100644
index 00000000..e0b6df28
--- /dev/null
+++ b/versions/v1_19_R3/src/main/java/com/wizardlybump17/wlib/adapter/v1_19_R3/command/CommandMapAdapter.java
@@ -0,0 +1,37 @@
+package com.wizardlybump17.wlib.adapter.v1_19_R3.command;
+
+import com.wizardlybump17.wlib.util.ReflectionUtil;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandMap;
+import org.bukkit.command.SimpleCommandMap;
+import org.jetbrains.annotations.NotNull;
+
+import java.lang.reflect.Field;
+import java.util.Map;
+
+public class CommandMapAdapter extends com.wizardlybump17.wlib.adapter.command.CommandMapAdapter {
+
+ public static final @NotNull Field COMMAND_MAP = ReflectionUtil.getField("commandMap", Bukkit.getServer().getClass());
+ public static final @NotNull Field COMMANDS = ReflectionUtil.getField("knownCommands", SimpleCommandMap.class);
+
+ @Override
+ public @NotNull CommandMap getCommandMap() {
+ return ReflectionUtil.getFieldValue(COMMAND_MAP, Bukkit.getServer());
+ }
+
+ @Override
+ public void unregisterCommand(@NotNull String command) {
+ Map commands = getCommands();
+ CommandMap commandMap = getCommandMap();
+
+ Command removed = commands.remove(command);
+ if (removed != null)
+ removed.unregister(commandMap);
+ }
+
+ @Override
+ public @NotNull Map getCommands() {
+ return ReflectionUtil.getFieldValue(COMMANDS, getCommandMap());
+ }
+}
diff --git a/versions/v1_20_R1/src/main/java/com/wizardlybump17/wlib/adapter/v1_20_R1/command/CommandMapAdapter.java b/versions/v1_20_R1/src/main/java/com/wizardlybump17/wlib/adapter/v1_20_R1/command/CommandMapAdapter.java
new file mode 100644
index 00000000..98a07dd8
--- /dev/null
+++ b/versions/v1_20_R1/src/main/java/com/wizardlybump17/wlib/adapter/v1_20_R1/command/CommandMapAdapter.java
@@ -0,0 +1,37 @@
+package com.wizardlybump17.wlib.adapter.v1_20_R1.command;
+
+import com.wizardlybump17.wlib.util.ReflectionUtil;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandMap;
+import org.bukkit.command.SimpleCommandMap;
+import org.jetbrains.annotations.NotNull;
+
+import java.lang.reflect.Field;
+import java.util.Map;
+
+public class CommandMapAdapter extends com.wizardlybump17.wlib.adapter.command.CommandMapAdapter {
+
+ public static final @NotNull Field COMMAND_MAP = ReflectionUtil.getField("commandMap", Bukkit.getServer().getClass());
+ public static final @NotNull Field COMMANDS = ReflectionUtil.getField("knownCommands", SimpleCommandMap.class);
+
+ @Override
+ public @NotNull CommandMap getCommandMap() {
+ return ReflectionUtil.getFieldValue(COMMAND_MAP, Bukkit.getServer());
+ }
+
+ @Override
+ public void unregisterCommand(@NotNull String command) {
+ Map commands = getCommands();
+ CommandMap commandMap = getCommandMap();
+
+ Command removed = commands.remove(command);
+ if (removed != null)
+ removed.unregister(commandMap);
+ }
+
+ @Override
+ public @NotNull Map getCommands() {
+ return ReflectionUtil.getFieldValue(COMMANDS, getCommandMap());
+ }
+}
diff --git a/versions/v1_20_R2/src/main/java/com/wizardlybump17/wlib/adapter/v1_20_R2/command/CommandMapAdapter.java b/versions/v1_20_R2/src/main/java/com/wizardlybump17/wlib/adapter/v1_20_R2/command/CommandMapAdapter.java
new file mode 100644
index 00000000..b14f309f
--- /dev/null
+++ b/versions/v1_20_R2/src/main/java/com/wizardlybump17/wlib/adapter/v1_20_R2/command/CommandMapAdapter.java
@@ -0,0 +1,37 @@
+package com.wizardlybump17.wlib.adapter.v1_20_R2.command;
+
+import com.wizardlybump17.wlib.util.ReflectionUtil;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandMap;
+import org.bukkit.command.SimpleCommandMap;
+import org.jetbrains.annotations.NotNull;
+
+import java.lang.reflect.Field;
+import java.util.Map;
+
+public class CommandMapAdapter extends com.wizardlybump17.wlib.adapter.command.CommandMapAdapter {
+
+ public static final @NotNull Field COMMAND_MAP = ReflectionUtil.getField("commandMap", Bukkit.getServer().getClass());
+ public static final @NotNull Field COMMANDS = ReflectionUtil.getField("knownCommands", SimpleCommandMap.class);
+
+ @Override
+ public @NotNull CommandMap getCommandMap() {
+ return ReflectionUtil.getFieldValue(COMMAND_MAP, Bukkit.getServer());
+ }
+
+ @Override
+ public void unregisterCommand(@NotNull String command) {
+ Map commands = getCommands();
+ CommandMap commandMap = getCommandMap();
+
+ Command removed = commands.remove(command);
+ if (removed != null)
+ removed.unregister(commandMap);
+ }
+
+ @Override
+ public @NotNull Map getCommands() {
+ return ReflectionUtil.getFieldValue(COMMANDS, getCommandMap());
+ }
+}
diff --git a/versions/v1_20_R3/src/main/java/com/wizardlybump17/wlib/adapter/v1_20_R3/command/CommandMapAdapter.java b/versions/v1_20_R3/src/main/java/com/wizardlybump17/wlib/adapter/v1_20_R3/command/CommandMapAdapter.java
new file mode 100644
index 00000000..2c867d02
--- /dev/null
+++ b/versions/v1_20_R3/src/main/java/com/wizardlybump17/wlib/adapter/v1_20_R3/command/CommandMapAdapter.java
@@ -0,0 +1,37 @@
+package com.wizardlybump17.wlib.adapter.v1_20_R3.command;
+
+import com.wizardlybump17.wlib.util.ReflectionUtil;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandMap;
+import org.bukkit.command.SimpleCommandMap;
+import org.jetbrains.annotations.NotNull;
+
+import java.lang.reflect.Field;
+import java.util.Map;
+
+public class CommandMapAdapter extends com.wizardlybump17.wlib.adapter.command.CommandMapAdapter {
+
+ public static final @NotNull Field COMMAND_MAP = ReflectionUtil.getField("commandMap", Bukkit.getServer().getClass());
+ public static final @NotNull Field COMMANDS = ReflectionUtil.getField("knownCommands", SimpleCommandMap.class);
+
+ @Override
+ public @NotNull CommandMap getCommandMap() {
+ return ReflectionUtil.getFieldValue(COMMAND_MAP, Bukkit.getServer());
+ }
+
+ @Override
+ public void unregisterCommand(@NotNull String command) {
+ Map commands = getCommands();
+ CommandMap commandMap = getCommandMap();
+
+ Command removed = commands.remove(command);
+ if (removed != null)
+ removed.unregister(commandMap);
+ }
+
+ @Override
+ public @NotNull Map getCommands() {
+ return ReflectionUtil.getFieldValue(COMMANDS, getCommandMap());
+ }
+}