Rework commands

This commit is contained in:
Len 2022-11-13 00:59:53 +01:00
parent 72fd7efc86
commit c04142cf2a
9 changed files with 306 additions and 83 deletions

View File

@ -106,14 +106,6 @@ bukkit {
authors = listOf("destro174") authors = listOf("destro174")
depend = listOf("Vault") depend = listOf("Vault")
commands {
register("playershop") {
description = "This is a test command!"
aliases = listOf("shop")
permission = "playershops.command.playershop"
}
}
permissions { permissions {
register("playershops.admin") { register("playershops.admin") {
description = "Admin permission for the ${rootProject.name} plugin." description = "Admin permission for the ${rootProject.name} plugin."

View File

@ -1,6 +1,6 @@
package com.alttd.playershops; package com.alttd.playershops;
import com.alttd.playershops.commands.ShopCommand; import com.alttd.playershops.commands.PlayerShopCommands;
import com.alttd.playershops.config.Config; import com.alttd.playershops.config.Config;
import com.alttd.playershops.config.DatabaseConfig; import com.alttd.playershops.config.DatabaseConfig;
import com.alttd.playershops.config.MessageConfig; import com.alttd.playershops.config.MessageConfig;
@ -102,7 +102,7 @@ public class PlayerShops extends JavaPlugin {
} }
private void registerCommands() { private void registerCommands() {
getCommand("playershop").setExecutor(new ShopCommand()); PlayerShopCommands.registerCommands();
} }
public void reloadConfigs() { public void reloadConfigs() {

View File

@ -0,0 +1,141 @@
package com.alttd.playershops.commands;
import com.alttd.playershops.commands.subcommands.CheckStockCommand;
import com.alttd.playershops.commands.subcommands.OpenCommand;
import com.alttd.playershops.commands.subcommands.ReloadCommand;
import com.google.common.base.Functions;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import it.unimi.dsi.fastutil.Pair;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionDefault;
import org.bukkit.plugin.PluginManager;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.stream.Collectors;
import static net.kyori.adventure.text.Component.text;
import static net.kyori.adventure.text.format.NamedTextColor.RED;
public class PlayerShopCommand extends Command {
public static final String BASE_PERM = "playershops.command"; // TODO load from config
// subcommand label -> subcommand
private static final Map<String, Subcommand> SUBCOMMANDS = PlayerShopCommands.make(() -> {
final Map<Set<String>, Subcommand> commands = new HashMap<>();
commands.put(Set.of("reload"), new ReloadCommand());
commands.put(Set.of("checkstock"), new CheckStockCommand());
commands.put(Set.of("open"), new OpenCommand());
return commands.entrySet().stream()
.flatMap(entry -> entry.getKey().stream().map(s -> Map.entry(s, entry.getValue())))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
});
// alias -> subcommand label
private static final Map<String, String> ALIASES = PlayerShopCommands.make(() -> {
final Map<String, Set<String>> aliases = new HashMap<>();
aliases.put("reload", Set.of("reloadconfig"));
return aliases.entrySet().stream()
.flatMap(entry -> entry.getValue().stream().map(s -> Map.entry(s, entry.getKey())))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
});
public PlayerShopCommand() {
super("playershop");
this.description = "PlayerShop related commands";
this.usageMessage = "/playershop [" + String.join(" | ", SUBCOMMANDS.keySet()) + "]";
final List<String> permissions = new ArrayList<>();
permissions.add(BASE_PERM);
permissions.addAll(SUBCOMMANDS.keySet().stream().map(s -> BASE_PERM + "." + s).toList());
this.setPermission(String.join(";", permissions));
final PluginManager pluginManager = Bukkit.getServer().getPluginManager();
for (final String perm : permissions) {
pluginManager.addPermission(new Permission(perm, PermissionDefault.OP));
}
}
private static boolean testPermission(final CommandSender sender, final String permission) {
if (sender.hasPermission(BASE_PERM + "." + permission)) {
return true;
}
sender.sendMessage(Bukkit.permissionMessage());
return false;
}
@Override
public @NotNull List<String> tabComplete(
final @NotNull CommandSender sender,
final @NotNull String alias,
final String[] args,
final @Nullable Location location
) throws IllegalArgumentException {
if (args.length <= 1) {
return PlayerShopCommands.getListMatchingLast(sender, args, SUBCOMMANDS.keySet(), BASE_PERM);
}
final @Nullable Pair<String, Subcommand> subCommand = resolveCommand(args[0]);
if (subCommand != null) {
return subCommand.second().tabComplete(sender, subCommand.first(), Arrays.copyOfRange(args, 1, args.length));
}
return Collections.emptyList();
}
@Override
public boolean execute(
final @NotNull CommandSender sender,
final @NotNull String commandLabel,
final String[] args
) {
if (!testPermission(sender)) {
return true;
}
if (args.length == 0) {
sender.sendMessage(text("Usage: " + this.usageMessage, RED));
return false;
}
final @Nullable Pair<String, Subcommand> subCommand = resolveCommand(args[0]);
if (subCommand == null) {
sender.sendMessage(text("Usage: " + this.usageMessage, RED));
return false;
}
if (!testPermission(sender, subCommand.first())) {
return true;
}
final String[] choppedArgs = Arrays.copyOfRange(args, 1, args.length);
return subCommand.second().execute(sender, subCommand.first(), choppedArgs);
}
private static @Nullable Pair<String, Subcommand> resolveCommand(String label) {
label = label.toLowerCase(Locale.ENGLISH);
@Nullable Subcommand subCommand = SUBCOMMANDS.get(label);
if (subCommand == null) {
final @Nullable String command = ALIASES.get(label);
if (command != null) {
label = command;
subCommand = SUBCOMMANDS.get(command);
}
}
if (subCommand != null) {
return Pair.of(label, subCommand);
}
return null;
}
}

View File

@ -0,0 +1,58 @@
package com.alttd.playershops.commands;
import com.google.common.base.Functions;
import com.google.common.collect.Lists;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import java.util.*;
import java.util.function.Supplier;
public class PlayerShopCommands {
private PlayerShopCommands() {
}
private static final Map<String, Command> COMMANDS = new HashMap<>();
static {
COMMANDS.put("playershop", new PlayerShopCommand());
}
public static void registerCommands() {
COMMANDS.forEach((s, command) -> {
Bukkit.getCommandMap().register(s, command.getName(), command);
});
}
// Code from Mojang - copyright them | Altered to fit our needs
public static List<String> getListMatchingLast(final CommandSender sender, final String[] args, final String basePermission, final String... matches) {
return getListMatchingLast(sender, args, Arrays.asList(matches), basePermission);
}
public static boolean matches(final String s, final String s1) {
return s1.regionMatches(true, 0, s, 0, s.length());
}
public static List<String> getListMatchingLast(final CommandSender sender, final String[] strings, final Collection<?> collection, final String basePermission) {
String last = strings[strings.length - 1];
ArrayList<String> results = Lists.newArrayList();
if (!collection.isEmpty()) {
for (String s1 : collection.stream().map(Functions.toStringFunction()).toList()) {
if (matches(last, s1) && (sender.hasPermission(basePermission + "." + s1))) {
results.add(s1);
}
}
}
return results;
}
public static <T> T make(Supplier<T> factory) {
return factory.get();
}
// end copy stuff
}

View File

@ -1,56 +0,0 @@
package com.alttd.playershops.commands;
import com.alttd.playershops.PlayerShops;
import com.alttd.playershops.gui.HomeGui;
import com.alttd.playershops.utils.Util;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
// expose brig in Galaxy?
public class ShopCommand implements CommandExecutor, TabCompleter {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) return true;
if (args.length == 0) {
return true;
}
switch (args[0].toLowerCase()) {
case "reload":
PlayerShops.getInstance().reloadConfigs();
break;
case "open":
HomeGui gui = new HomeGui(player.getUniqueId());
gui.open();
break;
case "checkstock":
if (!player.hasPermission("playershops.command.playershop.checkstock")) {
sender.sendMessage(Util.parseMiniMessage("<red><hover:show_text:'<red>playershops.command.playershop.checkstock'>You do not have permission for this command</hover></red>"));
break;
}
new CheckStockCommand(PlayerShops.getInstance(), player, args);
break;
default:
sender.sendMessage("invalid command useage");
break;
}
return false;
}
@Override
public List<String> onTabComplete(CommandSender sender, Command cmd, String label, String[] args) {
if (args.length == 1) {
return Stream.of("reload", "open")
.filter(arg -> arg.startsWith(args[0].toLowerCase()))
.collect(Collectors.toList());
}
return null;
}
}

View File

@ -0,0 +1,19 @@
package com.alttd.playershops.commands;
import org.bukkit.command.CommandSender;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.framework.qual.DefaultQualifier;
import java.util.Collections;
import java.util.List;
@DefaultQualifier(NonNull.class)
public interface Subcommand {
boolean execute(CommandSender sender, String subCommand, String[] args);
default List<String> tabComplete(final CommandSender sender, final String subCommand, final String[] args) {
return Collections.emptyList();
}
}

View File

@ -1,6 +1,9 @@
package com.alttd.playershops.commands; package com.alttd.playershops.commands.subcommands;
import com.alttd.playershops.PlayerShops; import com.alttd.playershops.PlayerShops;
import com.alttd.playershops.commands.PlayerShopCommand;
import com.alttd.playershops.commands.PlayerShopCommands;
import com.alttd.playershops.commands.Subcommand;
import com.alttd.playershops.shop.PlayerShop; import com.alttd.playershops.shop.PlayerShop;
import com.alttd.playershops.utils.ShopUtil; import com.alttd.playershops.utils.ShopUtil;
import com.alttd.playershops.utils.Util; import com.alttd.playershops.utils.Util;
@ -8,34 +11,58 @@ import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.framework.qual.DefaultQualifier;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class CheckStockCommand { @DefaultQualifier(NonNull.class)
private int playerX; public class CheckStockCommand implements Subcommand {
private int playerZ;
private int radius; @Override
public boolean execute(CommandSender sender, String subCommand, String[] args) {
return this.doStockCheck(sender, args);
}
@Override
public List<String> tabComplete(final CommandSender sender, final String subCommand, final String[] args) {
// TODO give some default tab completions
if (args.length == 1) {
return PlayerShopCommands.getListMatchingLast(sender, args, PlayerShopCommand.BASE_PERM + ".checkstock", "help");
} else if (args.length == 2) {
// return PlayerShopCommands.getListMatchingLast(sender, args, "radius");
return Collections.emptyList();
}
return Collections.emptyList();
}
private int minimumStock = -1; private int minimumStock = -1;
private final PlayerShops plugin;
public CheckStockCommand(PlayerShops plugin, Player player, String[] args) { public boolean doStockCheck(final CommandSender sender, final String[] args) {
this.plugin = plugin; if (!(sender instanceof Player player)) {
sender.sendMessage("<red>Only players can use this command.");
return false;
}
if (args.length != 2 && args.length != 3) { if (args.length != 2 && args.length != 3) {
player.sendMessage(Util.parseMiniMessage("<red>Invalid command syntax, use /checkstock <radius> [minimum stock]")); player.sendMessage(Util.parseMiniMessage("<red>Invalid command syntax, use /checkstock <radius> [minimum stock]"));
return; return false;
} }
int radius;
try { try {
radius = Integer.parseInt(args[1]); radius = Integer.parseInt(args[1]);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
player.sendMessage(Util.parseMiniMessage("<red>radius has to be a valid number, use /checkstock <radius> [minimum stock]")); player.sendMessage(Util.parseMiniMessage("<red>radius has to be a valid number, use /checkstock <radius> [minimum stock]"));
return; return false;
} }
if (radius > 100 || radius <= 0) { if (radius > 100 || radius <= 0) {
player.sendMessage(Util.parseMiniMessage("<red>Please keep the radius between 1 and 100")); player.sendMessage(Util.parseMiniMessage("<red>Please keep the radius between 1 and 100"));
return; return false;
} }
if (args.length == 3) { if (args.length == 3) {
@ -43,17 +70,16 @@ public class CheckStockCommand {
minimumStock = Integer.parseInt(args[2]); minimumStock = Integer.parseInt(args[2]);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
player.sendMessage(Util.parseMiniMessage("<red>minium stock has to be a valid number, use /checkstock <radius> [minimum stock]")); player.sendMessage(Util.parseMiniMessage("<red>minium stock has to be a valid number, use /checkstock <radius> [minimum stock]"));
return; return false;
} }
} }
playerX = player.getLocation().getBlockX(); List<Stock> stockList = checkStock(player.getLocation().getBlockX(), player.getLocation().getBlockZ(), radius);
playerZ = player.getLocation().getBlockZ();
List<Stock> stockList = checkStock();
sendStockMessage(player, stockList); sendStockMessage(player, stockList);
return true;
} }
private List<Stock> checkStock() { private List<Stock> checkStock(int x, int z, int radius) {
List<PlayerShop> shops = plugin.getShopHandler().getShopsInRadius(playerX, playerZ, radius); List<PlayerShop> shops = PlayerShops.getInstance().getShopHandler().getShopsInRadius(x, z, radius);
if (minimumStock != -1) if (minimumStock != -1)
shops = shops.stream().filter(shop -> shop.getRemainingStock() < minimumStock).collect(Collectors.toList()); shops = shops.stream().filter(shop -> shop.getRemainingStock() < minimumStock).collect(Collectors.toList());
return shops.stream().map(shop -> { return shops.stream().map(shop -> {

View File

@ -0,0 +1,24 @@
package com.alttd.playershops.commands.subcommands;
import com.alttd.playershops.commands.Subcommand;
import com.alttd.playershops.gui.HomeGui;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.framework.qual.DefaultQualifier;
@DefaultQualifier(NonNull.class)
public class OpenCommand implements Subcommand {
@Override
public boolean execute(final CommandSender sender, final String subCommand, final String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage("<red>Only players can use this command.");
return false;
}
HomeGui gui = new HomeGui(player.getUniqueId());
gui.open();
return true;
}
}

View File

@ -0,0 +1,19 @@
package com.alttd.playershops.commands.subcommands;
import com.alttd.playershops.PlayerShops;
import com.alttd.playershops.commands.Subcommand;
import org.bukkit.command.CommandSender;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.framework.qual.DefaultQualifier;
@DefaultQualifier(NonNull.class)
public class ReloadCommand implements Subcommand {
@Override
public boolean execute(final CommandSender sender, final String subCommand, final String[] args) {
PlayerShops.getInstance().reloadConfigs();
// Todo message when config is reloaded
return true;
}
}