diff --git a/core-bukkit-api/build.gradle.kts b/core-bukkit-api/build.gradle.kts index 66b64df..3fbeb64 100644 --- a/core-bukkit-api/build.gradle.kts +++ b/core-bukkit-api/build.gradle.kts @@ -20,6 +20,7 @@ dependencies { api("me.lucko:commodore:2.2") api("org.spigotmc:spigot-api:1.21.11-R0.1-SNAPSHOT") + api("net.kyori:adventure-platform-bukkit:4.4.1") } tasks.findByName("shadowJar")?.let { diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/ScrowAPI.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/ScrowAPI.java index 236e65d..81d26a5 100644 --- a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/ScrowAPI.java +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/ScrowAPI.java @@ -2,6 +2,7 @@ package de.kentoj.scrow.bukkit; import com.mongodb.reactivestreams.client.MongoDatabase; import de.kentoj.scrow.bukkit.services.EconomyService; +import de.kentoj.scrow.bukkit.services.command.CommandManager; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @@ -15,6 +16,8 @@ public class ScrowAPI { private static @Nullable MongoDatabase database; @Getter private static EconomyService economyService; + @Getter + private static CommandManager commandManager; @ApiStatus.Internal public static void setDatabase(@Nullable MongoDatabase database) { @@ -25,5 +28,10 @@ public class ScrowAPI { public static void setEconomyService(EconomyService economyService) { ScrowAPI.economyService = economyService; } + + @ApiStatus.Internal + public static void setCommandManager(CommandManager commandManager) { + ScrowAPI.commandManager = commandManager; + } } diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/command/CommandArgument.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/command/CommandArgument.java new file mode 100644 index 0000000..903e370 --- /dev/null +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/command/CommandArgument.java @@ -0,0 +1,14 @@ +package de.kentoj.scrow.bukkit.services.command; + +import de.kentoj.scrow.bukkit.services.command.arg.ArgumentType; +import lombok.Value; + +import java.util.function.Function; + +@Value +public class CommandArgument { + int index; + String name; + ArgumentType type; + Function defaultValue; +} diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/old/CmdContext.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/command/CommandContext.java similarity index 65% rename from core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/old/CmdContext.java rename to core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/command/CommandContext.java index f3994bc..8394a2d 100644 --- a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/old/CmdContext.java +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/command/CommandContext.java @@ -1,16 +1,14 @@ -package de.kentoj.scrow.bukkit.services.old; +package de.kentoj.scrow.bukkit.services.command; import org.bukkit.command.CommandSender; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; -public interface CmdContext { +public interface CommandContext { CommandSender getSender(); Player getSenderPlayer(); Entity getSenderEntity(); - - T getArg(String key); } diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/command/CommandExecutionContext.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/command/CommandExecutionContext.java new file mode 100644 index 0000000..d750801 --- /dev/null +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/command/CommandExecutionContext.java @@ -0,0 +1,6 @@ +package de.kentoj.scrow.bukkit.services.command; + +public interface CommandExecutionContext extends CommandContext { + + T getArg(String key); +} diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/old/CommandExecutor.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/command/CommandExecutor.java similarity index 51% rename from core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/old/CommandExecutor.java rename to core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/command/CommandExecutor.java index bd44ff6..abadfbf 100644 --- a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/old/CommandExecutor.java +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/command/CommandExecutor.java @@ -1,9 +1,9 @@ -package de.kentoj.scrow.bukkit.services.old; +package de.kentoj.scrow.bukkit.services.command; public interface CommandExecutor { /** * @return true on success, 1 on failure */ - boolean execute(CmdContext ctx); + void execute(CommandExecutionContext ctx); } diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/command/CommandManager.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/command/CommandManager.java new file mode 100644 index 0000000..1fe5944 --- /dev/null +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/command/CommandManager.java @@ -0,0 +1,8 @@ +package de.kentoj.scrow.bukkit.services.command; + +import org.bukkit.plugin.Plugin; + +public interface CommandManager { + + void register(CommandNode rootCommandNode, Plugin plugin); +} diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/command/CommandNode.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/command/CommandNode.java new file mode 100644 index 0000000..325ad20 --- /dev/null +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/command/CommandNode.java @@ -0,0 +1,40 @@ +package de.kentoj.scrow.bukkit.services.command; + +import de.kentoj.scrow.bukkit.services.command.arg.ArgumentType; +import org.bukkit.permissions.Permission; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.function.Function; + +// TODO javadoc +public interface CommandNode { + + void addArg(String name, ArgumentType type, @Nullable Function defaultValue); + + default void addArg(String name, ArgumentType type) { + addArg(name, type, null); + } + + void addSubCommand(CommandNode subCommand); + + void setPermission(@Nullable Permission permission); + + default void setPermission(String permission) { + setPermission(new Permission(permission)); + } + + @Nullable Permission getPermission(); + + @Nullable CommandArgument getArg(int index); + + List getSubCommands(); + + String getName(); + + String[] getAliases(); + + String getDescription(); + + @Nullable CommandExecutor getExecutor(); +} diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/command/arg/ArgumentType.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/command/arg/ArgumentType.java new file mode 100644 index 0000000..d21a1d6 --- /dev/null +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/command/arg/ArgumentType.java @@ -0,0 +1,6 @@ +package de.kentoj.scrow.bukkit.services.command.arg; + +public interface ArgumentType { + + S parseInput(String str); +} diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/old/arg/PlayerArgType.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/command/arg/PlayerArgumentType.java similarity index 70% rename from core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/old/arg/PlayerArgType.java rename to core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/command/arg/PlayerArgumentType.java index 605f9f2..17b9909 100644 --- a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/old/arg/PlayerArgType.java +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/command/arg/PlayerArgumentType.java @@ -1,4 +1,4 @@ -package de.kentoj.scrow.bukkit.services.old.arg; +package de.kentoj.scrow.bukkit.services.command.arg; import lombok.AccessLevel; import lombok.NoArgsConstructor; @@ -10,9 +10,9 @@ import java.util.UUID; // FIXME module stuff @NoArgsConstructor(access = AccessLevel.PRIVATE) -public class PlayerArgType { +public class PlayerArgumentType { - public static final CmdArg player = str -> { + public static final ArgumentType player = str -> { if (str.length() == 36) { var uuid = UUID.fromString(str); return Bukkit.getPlayer(uuid); @@ -21,7 +21,7 @@ public class PlayerArgType { } }; - public static final CmdArg offlinePlayer = str -> { + public static final ArgumentType offlinePlayer = str -> { var uuid = UUID.fromString(str); return Bukkit.getOfflinePlayer(uuid); }; diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/old/CommandsService.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/old/CommandsService.java deleted file mode 100644 index 6a53a98..0000000 --- a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/old/CommandsService.java +++ /dev/null @@ -1,9 +0,0 @@ -package de.kentoj.scrow.bukkit.services.old; - -import org.bukkit.command.Command; -import org.bukkit.plugin.Plugin; - -public interface CommandsService { - - void register(Plugin plugin, Command command); -} diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/old/RegisteredCmdArg.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/old/RegisteredCmdArg.java deleted file mode 100644 index 24dd626..0000000 --- a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/old/RegisteredCmdArg.java +++ /dev/null @@ -1,11 +0,0 @@ -package de.kentoj.scrow.bukkit.services.old; - -import de.kentoj.scrow.bukkit.services.old.arg.CmdArg; -import lombok.Value; - -@Value -public class RegisteredCmdArg { - int index; - String key; - CmdArg arg; -} diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/old/SCommand.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/old/SCommand.java deleted file mode 100644 index 0e17f41..0000000 --- a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/old/SCommand.java +++ /dev/null @@ -1,21 +0,0 @@ -package de.kentoj.scrow.bukkit.services.old; - -import org.bukkit.permissions.Permission; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -public interface SCommand { - - @Nullable Permission getPermission(); - - RegisteredCmdArg getArg(int index); - - List getSubCommands(); - - String[] getLabels(); - - String getDescription(); - - @Nullable CommandExecutor getExecutor(); -} diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/old/arg/CmdArg.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/old/arg/CmdArg.java deleted file mode 100644 index fef832a..0000000 --- a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/services/old/arg/CmdArg.java +++ /dev/null @@ -1,6 +0,0 @@ -package de.kentoj.scrow.bukkit.services.old.arg; - -public interface CmdArg { - - S parseInput(String str); -} diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/util/chat/ErrorMessage.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/util/chat/ErrorMessage.java new file mode 100644 index 0000000..88377fd --- /dev/null +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/util/chat/ErrorMessage.java @@ -0,0 +1,15 @@ +package de.kentoj.scrow.bukkit.util.chat; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.audience.Audiences; +import net.kyori.adventure.platform.bukkit.BukkitAudiences; +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ErrorMessage { + +} diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/util/command/PlayerArgument.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/util/command/PlayerArgument.java new file mode 100644 index 0000000..9c090ca --- /dev/null +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/util/command/PlayerArgument.java @@ -0,0 +1,30 @@ +package de.kentoj.scrow.bukkit.util.command; + +import com.mojang.brigadier.LiteralMessage; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import java.util.UUID; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class PlayerArgument { + + public static Player resolve(CommandContext ctx, String argumentName) throws CommandSyntaxException { + var str = ctx.getArgument(argumentName, String.class); + boolean isUUID = str.length() == 36; + return isUUID ? Bukkit.getPlayer(parseUUID(str)) : Bukkit.getPlayerExact(str); + } + + private static UUID parseUUID(String string) throws CommandSyntaxException { + try { + return UUID.fromString(string); + } catch (IllegalArgumentException ex) { + throw new SimpleCommandExceptionType(new LiteralMessage("Invalid UUID")).create(); + } + } +} diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/CoreImplPlugin.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/CoreImplPlugin.java index 4ebbc94..44d2b86 100644 --- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/CoreImplPlugin.java +++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/CoreImplPlugin.java @@ -1,5 +1,9 @@ package de.kentoj.scrow.bukkit; +import de.kentoj.scrow.bukkit.friends.casd.FriendCommand; +import de.kentoj.scrow.bukkit.friends.command.LaunchCommand; +import me.lucko.commodore.CommodoreProvider; +import org.bukkit.command.PluginCommand; import org.bukkit.plugin.java.JavaPlugin; import reactor.core.publisher.Mono; @@ -10,6 +14,11 @@ public class CoreImplPlugin extends JavaPlugin { @Override public void onEnable() { ScrowAPISurface.initScrowAPI(false); + + { + ScrowAPI.getCommandManager().register(new LaunchCommand(), this); + } + { var playerId = UUID.randomUUID(); var economyService = ScrowAPI.getEconomyService(); diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/ScrowAPISurface.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/ScrowAPISurface.java index 6a4d76c..0d9e68f 100644 --- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/ScrowAPISurface.java +++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/ScrowAPISurface.java @@ -4,6 +4,7 @@ import com.mongodb.ConnectionString; import com.mongodb.MongoClientSettings; import com.mongodb.reactivestreams.client.MongoClient; import com.mongodb.reactivestreams.client.MongoClients; +import de.kentoj.scrow.bukkit.command.bukkit.CommandManagerImpl; import de.kentoj.scrow.bukkit.economy.InMemoryEconomyService; import de.kentoj.scrow.bukkit.economy.MongoEconomyService; import lombok.AccessLevel; @@ -37,6 +38,8 @@ public class ScrowAPISurface { ScrowAPI.getDatabase() != null ? new MongoEconomyService(ScrowAPI.getDatabase()) : new InMemoryEconomyService() ); + + ScrowAPI.setCommandManager(new CommandManagerImpl()); } public static void destroyScrowAPI() { diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/AbstractCommandNode.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/AbstractCommandNode.java new file mode 100644 index 0000000..cd27119 --- /dev/null +++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/AbstractCommandNode.java @@ -0,0 +1,79 @@ +package de.kentoj.scrow.bukkit.command; + +import com.google.common.collect.ImmutableList; +import de.kentoj.scrow.bukkit.services.command.CommandContext; +import de.kentoj.scrow.bukkit.services.command.CommandExecutor; +import de.kentoj.scrow.bukkit.services.command.CommandArgument; +import de.kentoj.scrow.bukkit.services.command.CommandNode; +import de.kentoj.scrow.bukkit.services.command.arg.ArgumentType; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; +import org.bukkit.permissions.Permission; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +public abstract class AbstractCommandNode implements CommandNode { + + private final List subCommands = new ArrayList<>(); + private final List> args = new ArrayList<>(); + + @Getter + private final String name; + @Getter + private final String[] aliases; + @Getter + private @Nullable Permission permission = null; + @Getter + @Setter(value = AccessLevel.PROTECTED) + private @Nullable String description; + @Getter + @Setter(value = AccessLevel.PROTECTED) + private @Nullable CommandExecutor executor = null; + + public AbstractCommandNode(String name, String... aliases) { + this.name = name; + this.aliases = aliases; + } + + @Override + public void addArg(String name, ArgumentType type, Function defaultValue) { + var index = args.size(); + if (index > 0) { + boolean isPreviousArgumentOptional = args.get(index - 1).getDefaultValue() != null; + boolean isNewArgumentOptional = defaultValue != null; + if (isPreviousArgumentOptional && !isNewArgumentOptional) { + // TODO document in javadoc + throw new IllegalStateException("an optional argument(an argument with a defaultValue set) may not be followed by a required argument"); + } + } + args.add(new CommandArgument<>(index, name, type, defaultValue)); + // TODO + } + + @Override + public void addSubCommand(CommandNode subCommand) { + subCommands.add(subCommand); + } + + @Override + public void setPermission(@Nullable Permission permission) { + this.permission = permission; + } + + @Override + public @Nullable CommandArgument getArg(int index) { + return args.stream() + .filter(ra -> ra.getIndex() == index) + .findFirst() + .orElse(null); + } + + @Override + public List getSubCommands() { + return ImmutableList.copyOf(subCommands); + } +} \ No newline at end of file diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/AbstractSCommand.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/AbstractSCommand.java deleted file mode 100644 index c2e3be6..0000000 --- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/AbstractSCommand.java +++ /dev/null @@ -1,69 +0,0 @@ -package de.kentoj.scrow.bukkit.command; - -import com.google.common.collect.ImmutableList; -import de.kentoj.scrow.bukkit.services.old.CommandExecutor; -import de.kentoj.scrow.bukkit.services.old.RegisteredCmdArg; -import de.kentoj.scrow.bukkit.services.old.SCommand; -import de.kentoj.scrow.bukkit.services.old.arg.CmdArg; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.Setter; -import org.bukkit.permissions.Permission; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; - -public abstract class AbstractSCommand implements SCommand { - - private final List subCommands = new ArrayList<>(); - private final List> args = new ArrayList<>(); - - @Getter - private final String[] labels; - @Getter - private @Nullable Permission permission = null; - @Getter - @Setter(value = AccessLevel.PROTECTED) - private @Nullable String description; - @Getter - @Setter(value = AccessLevel.PROTECTED) - private @Nullable CommandExecutor executor = null; - - public AbstractSCommand(String... labels) { - this.labels = labels; - } - - protected void addArg(String key, CmdArg arg) { - - } - protected void addArg(String key, CmdArg arg, T defaultValue) { - var index = args.size(); - args.add(new RegisteredCmdArg<>(index, key, arg)); - } - - @Override - public RegisteredCmdArg getArg(int index) { - //noinspection OptionalGetWithoutIsPresent - return args.stream() - .filter(ra -> ra.getIndex() == index) - .findFirst() - .get(); - } - - public void addSubCommand(SCommand subCommand) { - subCommands.add(subCommand); - } - - protected void setPermission(@Nullable Permission permission) { - this.permission = permission; - } - - protected void setPermission(String permission) { - setPermission(new Permission(permission)); - } - - public List getSubCommands() { - return ImmutableList.copyOf(subCommands); - } -} \ No newline at end of file diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/CmdContextImpl.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/CommandContextImpl.java similarity index 62% rename from core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/CmdContextImpl.java rename to core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/CommandContextImpl.java index bc71cca..f326835 100644 --- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/CmdContextImpl.java +++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/CommandContextImpl.java @@ -1,18 +1,15 @@ package de.kentoj.scrow.bukkit.command; -import de.kentoj.scrow.bukkit.services.old.CmdContext; +import de.kentoj.scrow.bukkit.services.command.CommandContext; import lombok.Getter; import lombok.RequiredArgsConstructor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; -import java.util.Map; - @RequiredArgsConstructor -public class CmdContextImpl implements CmdContext { +public class CommandContextImpl implements CommandContext { - private final Map args; @Getter private final CommandSender sender; @@ -25,9 +22,4 @@ public class CmdContextImpl implements CmdContext { public Entity getSenderEntity() { return (Entity) sender; } - - @SuppressWarnings("unchecked") - public T getArg(String key) { - return (T) args.get(key); - } } diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/CommandExecutionContextImpl.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/CommandExecutionContextImpl.java new file mode 100644 index 0000000..96f238e --- /dev/null +++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/CommandExecutionContextImpl.java @@ -0,0 +1,21 @@ +package de.kentoj.scrow.bukkit.command; + +import de.kentoj.scrow.bukkit.services.command.CommandExecutionContext; +import org.bukkit.command.CommandSender; + +import java.util.Map; + +public class CommandExecutionContextImpl extends CommandContextImpl implements CommandExecutionContext { + + private final Map args; + + public CommandExecutionContextImpl(CommandSender sender, Map args) { + super(sender); + this.args = args; + } + + @SuppressWarnings("unchecked") + public T getArg(String key) { + return (T) args.get(key); + } +} diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/CommandProcessor.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/CommandProcessor.java deleted file mode 100644 index 1aed98f..0000000 --- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/CommandProcessor.java +++ /dev/null @@ -1,29 +0,0 @@ -package de.kentoj.scrow.bukkit.command; - -import de.kentoj.scrow.bukkit.services.old.CmdContext; -import de.kentoj.scrow.bukkit.services.old.SCommand; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; -import org.jetbrains.annotations.NotNull; - -import java.util.HashMap; -import java.util.Map; - -public class CommandProcessor implements CommandExecutor { - - public CmdContext process(SCommand scommand, String[] strArgs, CommandSender sender) { - Map args = new HashMap<>(); - for (int i = 0; i < strArgs.length; i++) { - var arg = scommand.getArg(i); - var value = arg.getArg().parseInput(strArgs[i]); - args.put(arg.getKey(), value); - } - return new CmdContextImpl(args, sender); - } - - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - return false; - } -} diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/LaunchCommand.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/LaunchCommand.java deleted file mode 100644 index 3c110bd..0000000 --- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/LaunchCommand.java +++ /dev/null @@ -1,26 +0,0 @@ -package de.kentoj.scrow.bukkit.command; - -import de.kentoj.scrow.bukkit.services.old.CommandExecutor; -import de.kentoj.scrow.bukkit.services.old.arg.PlayerArgType; -import de.kentoj.scrow.bukkit.services.old.CmdContext; -import org.bukkit.entity.Player; -import org.bukkit.permissions.Permission; -import org.bukkit.util.Vector; - -public class LaunchCommand extends AbstractSCommand implements CommandExecutor { - - public LaunchCommand() { - super("launch"); - setPermission(new Permission("corebukkit.cmd.launch")); - setExecutor(this); - addArg("player", PlayerArgType.player); - addArg("factor", IntRangeType.range(1, 5), 1); - } - - @Override - public boolean execute(CmdContext ctx) { - final Player player = ctx.getArg("player"); - player.setVelocity(new Vector(0, 1, 0)); - return true; - } -} diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/bukkit/BukkitCommand.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/bukkit/BukkitCommand.java new file mode 100644 index 0000000..aa3427f --- /dev/null +++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/bukkit/BukkitCommand.java @@ -0,0 +1,36 @@ +package de.kentoj.scrow.bukkit.command.bukkit; + +import de.kentoj.scrow.bukkit.services.command.CommandNode; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class BukkitCommand extends Command { + + private static final CommandProcessor commandProcessor = new CommandProcessor(); + + private final CommandNode rootCommandNode; + + protected BukkitCommand(CommandNode rootCommandNode, @NotNull String name, @NotNull String description, @NotNull String usageMessage, @NotNull List aliases) { + super(name, description, usageMessage, aliases); + this.rootCommandNode = rootCommandNode; + } + + @Override + public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { + final Runnable runnable; + try { + runnable = commandProcessor.toRunnable(rootCommandNode, sender, args); + } catch (CommandProcessException e) { + sender.sendMessage(e.getMessage()); + return true; + } catch (IllegalStateException e) { + throw new RuntimeException("failed processing command " + rootCommandNode.getName(), e); + } + + runnable.run(); + return true; + } +} diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/bukkit/CommandManagerImpl.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/bukkit/CommandManagerImpl.java new file mode 100644 index 0000000..52d9cf2 --- /dev/null +++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/bukkit/CommandManagerImpl.java @@ -0,0 +1,41 @@ +package de.kentoj.scrow.bukkit.command.bukkit; + +import de.kentoj.scrow.bukkit.services.command.CommandManager; +import de.kentoj.scrow.bukkit.services.command.CommandNode; +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandMap; +import org.bukkit.plugin.Plugin; + +import java.util.Arrays; + +public class CommandManagerImpl implements CommandManager { + + private final CommandMap commandMap; + + public CommandManagerImpl() { + try { + var field = Bukkit.getPluginManager().getClass().getDeclaredField("commandMap"); + field.setAccessible(true); + commandMap = (CommandMap) field.get(Bukkit.getPluginManager()); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + @Override + public void register(CommandNode rootCommandNode, Plugin plugin) { + var bukkitCmd = toBukkitCommand(rootCommandNode); + commandMap.register(plugin.getName(), bukkitCmd); + } + + private Command toBukkitCommand(CommandNode commandNode) { + return new BukkitCommand( + commandNode, + commandNode.getName(), + commandNode.getDescription(), + "", + Arrays.stream(commandNode.getAliases()).toList() + ); + } +} diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/bukkit/CommandProcessException.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/bukkit/CommandProcessException.java new file mode 100644 index 0000000..2feb26b --- /dev/null +++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/bukkit/CommandProcessException.java @@ -0,0 +1,10 @@ +package de.kentoj.scrow.bukkit.command.bukkit; + +public class CommandProcessException extends RuntimeException { + public CommandProcessException(String message) { + super(message); + } + public CommandProcessException(String message, Throwable throwable) { + super(message + ": " + throwable.getMessage()); + } +} diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/bukkit/CommandProcessor.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/bukkit/CommandProcessor.java new file mode 100644 index 0000000..cff9d9a --- /dev/null +++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/command/bukkit/CommandProcessor.java @@ -0,0 +1,78 @@ +package de.kentoj.scrow.bukkit.command.bukkit; + +import com.google.common.base.Strings; +import de.kentoj.scrow.bukkit.command.CommandContextImpl; +import de.kentoj.scrow.bukkit.command.CommandExecutionContextImpl; +import de.kentoj.scrow.bukkit.services.command.CommandArgument; +import de.kentoj.scrow.bukkit.services.command.CommandContext; +import de.kentoj.scrow.bukkit.services.command.CommandNode; +import lombok.RequiredArgsConstructor; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +public class CommandProcessor { + + public Runnable toRunnable(final CommandNode rootCommandNode, final CommandSender sender, final String[] args) throws CommandProcessException { + final var argToValueFunMap = new HashMap>(); + CommandNode lastNode = rootCommandNode; + + for (int cursor = 0; true; cursor++) { + final var arg = lastNode.getArg(cursor); + if (arg != null) { + final var valueFun = getArgValueFun(cursor, arg); + argToValueFunMap.put(arg.getName(), valueFun); + } else { + if (lastNode.getSubCommands().isEmpty()) break; + final var subcommand = getSubCommand(lastNode, args[cursor]); + if (subcommand == null) { + final var subcommands = lastNode.getSubCommands().stream().map(CommandNode::getName).toList(); + throw new CommandProcessException("Illegal argument -- " + args[cursor] + "\nExpected arguments: " + String.join(", ", subcommands)); + } + + lastNode = subcommand; + } + } + if (lastNode.getExecutor() == null) throw new IllegalStateException("Last CommandNode must have an executor"); + + final CommandNode finalLastNode = lastNode; + return () -> { + var ctx = new CommandExecutionContextImpl(sender, remap(argToValueFunMap, sender)); + finalLastNode.getExecutor().execute(ctx); + }; + } + + private Map remap(Map> argToValueFunMap, CommandSender sender) { + var ctx = new CommandContextImpl(sender); + return argToValueFunMap.entrySet() + .stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + ent -> ent.getValue().apply(ctx) + )); + } + + private Function getArgValueFun(int argIndex, CommandArgument arg) throws CommandProcessException { + if (args.length - 1 < argIndex) { + if (arg.getDefaultValue() == null) + throw new CommandProcessException("usage: missing arg value for " + arg.getName()); + return arg.getDefaultValue(); + } else { + return __ -> arg.getType().parseInput(args[argIndex]); + } + } + + private @Nullable CommandNode getSubCommand(CommandNode commandNode, String label) { + return commandNode.getSubCommands() + .stream() + .filter(c -> Arrays.stream(c.getAliases()).toList().contains(label)) + .findFirst() + .orElse(null); + } +} diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/casd/FriendAddCommand.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/casd/FriendAddCommand.java new file mode 100644 index 0000000..20b7120 --- /dev/null +++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/casd/FriendAddCommand.java @@ -0,0 +1,28 @@ +package de.kentoj.scrow.bukkit.friends.casd; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.LiteralMessage; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import com.mojang.brigadier.tree.ArgumentCommandNode; +import de.kentoj.scrow.bukkit.util.command.PlayerArgument; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class FriendAddCommand implements Command { + + @Override + public int run(CommandContext ctx) throws CommandSyntaxException { + final Player player = PlayerArgument.resolve(ctx, "player"); + if (player == null) { + throw new SimpleCommandExceptionType(new LiteralMessage("Player is not online")).create(); + } + + player.setVelocity(new Vector(0, 2, 0)); + return 0; + } +} diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/FriendsCommand.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/casd/FriendCommand.java similarity index 57% rename from core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/FriendsCommand.java rename to core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/casd/FriendCommand.java index 236ebfd..a6ebaed 100644 --- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/FriendsCommand.java +++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/casd/FriendCommand.java @@ -1,22 +1,19 @@ -package de.kentoj.scrow.bukkit.friends; +package de.kentoj.scrow.bukkit.friends.casd; -import com.mojang.brigadier.Command; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.builder.RequiredArgumentBuilder; -public class FriendsCommand { +public class FriendCommand { - public static Command createCommand() { + public static LiteralArgumentBuilder create() { return LiteralArgumentBuilder.literal("friends") - .then(LiteralArgumentBuilder.literal("add") - .then(RequiredArgumentBuilder.argument("player", StringArgumentType.word()))) + .then(LiteralArgumentBuilder.literal("add")) .then(LiteralArgumentBuilder.literal("list")) .then(LiteralArgumentBuilder.literal("requests")) .then(LiteralArgumentBuilder.literal("remove")) .then(LiteralArgumentBuilder.literal("jump")) .then(LiteralArgumentBuilder.literal("accept")) - .then(LiteralArgumentBuilder.literal("deny")) - .build().getCommand(); + .then(LiteralArgumentBuilder.literal("deny")); } } diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/casd/FriendCommandExecutor.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/casd/FriendCommandExecutor.java new file mode 100644 index 0000000..b8cc074 --- /dev/null +++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/casd/FriendCommandExecutor.java @@ -0,0 +1,13 @@ +package de.kentoj.scrow.bukkit.friends.casd; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; + +public class FriendCommandExecutor implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + return false; + } +} diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/LaunchCommand.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/LaunchCommand.java new file mode 100644 index 0000000..4128f08 --- /dev/null +++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/LaunchCommand.java @@ -0,0 +1,31 @@ +package de.kentoj.scrow.bukkit.friends.command; + +import de.kentoj.scrow.bukkit.command.AbstractCommandNode; +import de.kentoj.scrow.bukkit.services.command.CommandContext; +import de.kentoj.scrow.bukkit.services.command.CommandExecutionContext; +import de.kentoj.scrow.bukkit.services.command.CommandExecutor; +import de.kentoj.scrow.bukkit.services.command.arg.PlayerArgumentType; +import net.md_5.bungee.api.chat.TranslatableComponent; +import org.bukkit.entity.Player; +import org.bukkit.permissions.Permission; +import org.bukkit.util.Vector; + +public class LaunchCommand extends AbstractCommandNode implements CommandExecutor { + + public LaunchCommand() { + super("launch", "lunch"); + this.setDescription("launches a player in the air"); + this.setPermission(new Permission("bukkitcore.cmd.launch")); + + this.addArg("player", PlayerArgumentType.player, CommandContext::getSenderPlayer); + this.setExecutor(this); + } + + @Override + public void execute(CommandExecutionContext ctx) { + final Player player = ctx.getArg("player"); + player.spigot().sendMessage(new TranslatableComponent("")); + player.setVelocity(new Vector(0, 2, 0)); + player.sendMessage("Launched " + player.getName() + "."); + } +}