diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitAsyncCommandExecutor.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitAsyncCommandExecutor.java index 327d1475c..9771227da 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitAsyncCommandExecutor.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitAsyncCommandExecutor.java @@ -26,27 +26,19 @@ package me.lucko.luckperms.bukkit; import com.destroystokyo.paper.event.server.AsyncTabCompleteEvent; - import me.lucko.luckperms.common.command.utils.ArgumentTokenizer; import me.lucko.luckperms.common.sender.Sender; - import org.bukkit.command.Command; import org.bukkit.command.PluginCommand; import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; import java.util.List; -public class BukkitAsyncCommandExecutor extends BukkitCommandExecutor implements Listener { +public class BukkitAsyncCommandExecutor extends BukkitCommandExecutor { public BukkitAsyncCommandExecutor(LPBukkitPlugin plugin, PluginCommand command) { super(plugin, command); } - public void register() { - super.register(); - this.plugin.getBootstrap().getServer().getPluginManager().registerEvents(this, this.plugin.getBootstrap()); - } - @EventHandler(ignoreCancelled = true) public void onAsyncTabComplete(AsyncTabCompleteEvent e) { if (!e.isCommand()) { diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitCommandExecutor.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitCommandExecutor.java index 2fc9d75fa..eab4c9f00 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitCommandExecutor.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitCommandExecutor.java @@ -29,21 +29,19 @@ import me.lucko.luckperms.common.command.CommandManager; import me.lucko.luckperms.common.command.utils.ArgumentTokenizer; import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.sender.Sender; - import org.bukkit.Server; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; -import org.bukkit.command.PluginCommand; -import org.bukkit.command.TabExecutor; +import org.bukkit.command.*; import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.server.ServerCommandEvent; import org.checkerframework.checker.nullness.qual.NonNull; import java.util.List; import java.util.ListIterator; import java.util.stream.Collectors; -public class BukkitCommandExecutor extends CommandManager implements CommandExecutor, TabExecutor { +public class BukkitCommandExecutor extends CommandManager implements CommandExecutor, TabExecutor, Listener { private static final boolean SELECT_ENTITIES_SUPPORTED; static { @@ -69,6 +67,7 @@ public class BukkitCommandExecutor extends CommandManager implements CommandExec public void register() { this.command.setExecutor(this); this.command.setTabCompleter(this); + this.plugin.getBootstrap().getServer().getPluginManager().registerEvents(this, this.plugin.getBootstrap()); } @Override @@ -86,6 +85,36 @@ public class BukkitCommandExecutor extends CommandManager implements CommandExec return tabCompleteCommand(wrapped, arguments); } + // Support LP commands prefixed with a '/' from the console. + @EventHandler(ignoreCancelled = true) + public void onConsoleCommand(ServerCommandEvent e) { + if (!(e.getSender() instanceof ConsoleCommandSender)) { + return; + } + + String buffer = e.getCommand(); + if (buffer.isEmpty() || buffer.charAt(0) != '/') { + return; + } + + buffer = buffer.substring(1); + + String commandLabel; + int firstSpace = buffer.indexOf(' '); + if (firstSpace == -1) { + commandLabel = buffer; + } else { + commandLabel = buffer.substring(0, firstSpace); + } + + Command command = this.plugin.getBootstrap().getServer().getCommandMap().getCommand(commandLabel); + if (command != this.command) { + return; + } + + e.setCommand(buffer); + } + private List resolveSelectors(CommandSender sender, List args) { if (!SELECT_ENTITIES_SUPPORTED) { return args; diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeCommandExecutor.java b/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeCommandExecutor.java index e27db32eb..3f80d3244 100644 --- a/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeCommandExecutor.java +++ b/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeCommandExecutor.java @@ -28,23 +28,56 @@ package me.lucko.luckperms.bungee; import me.lucko.luckperms.common.command.CommandManager; import me.lucko.luckperms.common.command.utils.ArgumentTokenizer; import me.lucko.luckperms.common.sender.Sender; - import net.md_5.bungee.api.CommandSender; +import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.plugin.Command; import net.md_5.bungee.api.plugin.TabExecutor; +import java.util.Arrays; import java.util.List; +import java.util.stream.Stream; public class BungeeCommandExecutor extends Command implements TabExecutor { + /** The main command name */ + private static final String NAME = "luckpermsbungee"; + + /** The command aliases */ + private static final String[] ALIASES = {"lpb", "bperm", "bperms", "bpermission", "bpermissions"}; + + /** The main command name + aliases, prefixed with '/' */ + private static final String[] SLASH_ALIASES = Stream.concat( + Stream.of(NAME), + Arrays.stream(ALIASES) + ).map(s -> '/' + s).toArray(String[]::new); + + /** + * The aliases to register, {@link #ALIASES} + {@link #SLASH_ALIASES}. + * + *

SLASH_ALIASES are registered too so the console can run '/lpb' + * in the same way as 'lpb'.

+ */ + private static final String[] ALIASES_TO_REGISTER = Stream.concat( + Arrays.stream(ALIASES), + Arrays.stream(SLASH_ALIASES) + ).toArray(String[]::new); + private final LPBungeePlugin plugin; private final CommandManager manager; public BungeeCommandExecutor(LPBungeePlugin plugin, CommandManager manager) { - super("luckpermsbungee", null, "lpb", "bperm", "bperms", "bpermission", "bpermissions"); + super(NAME, null, ALIASES_TO_REGISTER); this.plugin = plugin; this.manager = manager; } + public void register() { + ProxyServer proxy = this.plugin.getBootstrap().getProxy(); + proxy.getPluginManager().registerCommand(this.plugin.getBootstrap(), this); + + // don't allow players to execute the slash aliases - these are just for the console. + proxy.getDisabledCommands().addAll(Arrays.asList(SLASH_ALIASES)); + } + @Override public void execute(CommandSender sender, String[] args) { Sender wrapped = this.plugin.getSenderFactory().wrap(sender); diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java b/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java index 2a9398b8c..3f1014a0b 100644 --- a/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java +++ b/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java @@ -49,7 +49,6 @@ import me.lucko.luckperms.common.plugin.util.AbstractConnectionListener; import me.lucko.luckperms.common.sender.Sender; import me.lucko.luckperms.common.tasks.CacheHousekeepingTask; import me.lucko.luckperms.common.tasks.ExpireTemporaryTask; - import net.luckperms.api.LuckPerms; import net.luckperms.api.query.QueryOptions; import net.md_5.bungee.api.connection.ProxiedPlayer; @@ -118,7 +117,8 @@ public class LPBungeePlugin extends AbstractLuckPermsPlugin { @Override protected void registerCommands() { this.commandManager = new CommandManager(this); - this.bootstrap.getProxy().getPluginManager().registerCommand(this.bootstrap, new BungeeCommandExecutor(this, this.commandManager)); + BungeeCommandExecutor command = new BungeeCommandExecutor(this, this.commandManager); + command.register(); // disable the default Bungee /perms command so it gets handled by the Bukkit plugin this.bootstrap.getProxy().getDisabledCommands().add("perms"); diff --git a/nukkit/src/main/java/me/lucko/luckperms/nukkit/LPNukkitPlugin.java b/nukkit/src/main/java/me/lucko/luckperms/nukkit/LPNukkitPlugin.java index 53f1d0818..bbd3e219d 100644 --- a/nukkit/src/main/java/me/lucko/luckperms/nukkit/LPNukkitPlugin.java +++ b/nukkit/src/main/java/me/lucko/luckperms/nukkit/LPNukkitPlugin.java @@ -25,6 +25,12 @@ package me.lucko.luckperms.nukkit; +import cn.nukkit.Player; +import cn.nukkit.command.PluginCommand; +import cn.nukkit.permission.Permission; +import cn.nukkit.plugin.PluginManager; +import cn.nukkit.plugin.service.ServicePriority; +import cn.nukkit.utils.Config; import me.lucko.luckperms.common.api.LuckPermsApiProvider; import me.lucko.luckperms.common.api.implementation.ApiUser; import me.lucko.luckperms.common.calculator.CalculatorFactory; @@ -49,26 +55,13 @@ import me.lucko.luckperms.nukkit.inject.PermissionDefault; import me.lucko.luckperms.nukkit.inject.permissible.LuckPermsPermissible; import me.lucko.luckperms.nukkit.inject.permissible.PermissibleInjector; import me.lucko.luckperms.nukkit.inject.permissible.PermissibleMonitoringInjector; -import me.lucko.luckperms.nukkit.inject.server.InjectorDefaultsMap; -import me.lucko.luckperms.nukkit.inject.server.InjectorPermissionMap; -import me.lucko.luckperms.nukkit.inject.server.InjectorSubscriptionMap; -import me.lucko.luckperms.nukkit.inject.server.LuckPermsDefaultsMap; -import me.lucko.luckperms.nukkit.inject.server.LuckPermsPermissionMap; -import me.lucko.luckperms.nukkit.inject.server.LuckPermsSubscriptionMap; +import me.lucko.luckperms.nukkit.inject.server.*; import me.lucko.luckperms.nukkit.listeners.NukkitConnectionListener; import me.lucko.luckperms.nukkit.listeners.NukkitPlatformListener; - import net.luckperms.api.LuckPerms; import net.luckperms.api.event.user.UserDataRecalculateEvent; import net.luckperms.api.query.QueryOptions; -import cn.nukkit.Player; -import cn.nukkit.command.PluginCommand; -import cn.nukkit.permission.Permission; -import cn.nukkit.plugin.PluginManager; -import cn.nukkit.plugin.service.ServicePriority; -import cn.nukkit.utils.Config; - import java.io.File; import java.util.Map; import java.util.Optional; @@ -125,9 +118,9 @@ public class LPNukkitPlugin extends AbstractLuckPermsPlugin { @Override protected void registerCommands() { - this.commandManager = new NukkitCommandExecutor(this); - PluginCommand cmd = (PluginCommand) this.bootstrap.getServer().getPluginCommand("luckperms"); - cmd.setExecutor(this.commandManager); + PluginCommand command = (PluginCommand) this.bootstrap.getServer().getPluginCommand("luckperms"); + this.commandManager = new NukkitCommandExecutor(this, command); + this.commandManager.register(); } @Override diff --git a/nukkit/src/main/java/me/lucko/luckperms/nukkit/NukkitCommandExecutor.java b/nukkit/src/main/java/me/lucko/luckperms/nukkit/NukkitCommandExecutor.java index 03058dbf3..b3a1a1ed9 100644 --- a/nukkit/src/main/java/me/lucko/luckperms/nukkit/NukkitCommandExecutor.java +++ b/nukkit/src/main/java/me/lucko/luckperms/nukkit/NukkitCommandExecutor.java @@ -25,22 +25,29 @@ package me.lucko.luckperms.nukkit; +import cn.nukkit.command.*; +import cn.nukkit.event.EventHandler; +import cn.nukkit.event.Listener; +import cn.nukkit.event.server.ServerCommandEvent; import me.lucko.luckperms.common.command.CommandManager; import me.lucko.luckperms.common.command.utils.ArgumentTokenizer; import me.lucko.luckperms.common.sender.Sender; -import cn.nukkit.command.Command; -import cn.nukkit.command.CommandExecutor; -import cn.nukkit.command.CommandSender; - import java.util.List; -public class NukkitCommandExecutor extends CommandManager implements CommandExecutor { +public class NukkitCommandExecutor extends CommandManager implements CommandExecutor, Listener { private final LPNukkitPlugin plugin; + private final PluginCommand command; - public NukkitCommandExecutor(LPNukkitPlugin plugin) { + public NukkitCommandExecutor(LPNukkitPlugin plugin, PluginCommand command) { super(plugin); this.plugin = plugin; + this.command = command; + } + + public void register() { + this.command.setExecutor(this); + this.plugin.getBootstrap().getServer().getPluginManager().registerEvents(this, this.plugin.getBootstrap()); } @Override @@ -50,4 +57,34 @@ public class NukkitCommandExecutor extends CommandManager implements CommandExec executeCommand(wrapped, label, arguments); return true; } + + // Support LP commands prefixed with a '/' from the console. + @EventHandler(ignoreCancelled = true) + public void onConsoleCommand(ServerCommandEvent e) { + if (!(e.getSender() instanceof ConsoleCommandSender)) { + return; + } + + String buffer = e.getCommand(); + if (buffer.isEmpty() || buffer.charAt(0) != '/') { + return; + } + + buffer = buffer.substring(1); + + String commandLabel; + int firstSpace = buffer.indexOf(' '); + if (firstSpace == -1) { + commandLabel = buffer; + } else { + commandLabel = buffer.substring(0, firstSpace); + } + + Command command = this.plugin.getBootstrap().getServer().getCommandMap().getCommand(commandLabel); + if (command != this.command) { + return; + } + + e.setCommand(buffer); + } } diff --git a/velocity/src/main/java/me/lucko/luckperms/velocity/LPVelocityPlugin.java b/velocity/src/main/java/me/lucko/luckperms/velocity/LPVelocityPlugin.java index 3b1c11c07..4af952d56 100644 --- a/velocity/src/main/java/me/lucko/luckperms/velocity/LPVelocityPlugin.java +++ b/velocity/src/main/java/me/lucko/luckperms/velocity/LPVelocityPlugin.java @@ -26,7 +26,6 @@ package me.lucko.luckperms.velocity; import com.velocitypowered.api.proxy.Player; - import me.lucko.luckperms.common.api.LuckPermsApiProvider; import me.lucko.luckperms.common.calculator.CalculatorFactory; import me.lucko.luckperms.common.command.CommandManager; @@ -51,7 +50,6 @@ import me.lucko.luckperms.velocity.context.VelocityContextManager; import me.lucko.luckperms.velocity.listeners.MonitoringPermissionCheckListener; import me.lucko.luckperms.velocity.listeners.VelocityConnectionListener; import me.lucko.luckperms.velocity.messaging.VelocityMessagingFactory; - import net.luckperms.api.LuckPerms; import net.luckperms.api.query.QueryOptions; @@ -127,7 +125,7 @@ public class LPVelocityPlugin extends AbstractLuckPermsPlugin { @Override protected void registerCommands() { this.commandManager = new VelocityCommandExecutor(this); - this.bootstrap.getProxy().getCommandManager().register(this.commandManager, "luckpermsvelocity", "lpv", "vperm", "vperms", "vpermission", "vpermissions"); + this.commandManager.register(); } @Override diff --git a/velocity/src/main/java/me/lucko/luckperms/velocity/VelocityCommandExecutor.java b/velocity/src/main/java/me/lucko/luckperms/velocity/VelocityCommandExecutor.java index 106805370..e463ce565 100644 --- a/velocity/src/main/java/me/lucko/luckperms/velocity/VelocityCommandExecutor.java +++ b/velocity/src/main/java/me/lucko/luckperms/velocity/VelocityCommandExecutor.java @@ -27,16 +27,23 @@ package me.lucko.luckperms.velocity; import com.velocitypowered.api.command.Command; import com.velocitypowered.api.command.CommandSource; - +import com.velocitypowered.api.proxy.ConsoleCommandSource; +import com.velocitypowered.api.proxy.ProxyServer; import me.lucko.luckperms.common.command.CommandManager; import me.lucko.luckperms.common.command.utils.ArgumentTokenizer; import me.lucko.luckperms.common.sender.Sender; - import org.checkerframework.checker.nullness.qual.NonNull; +import java.util.Arrays; import java.util.List; public class VelocityCommandExecutor extends CommandManager implements Command { + /** The command aliases */ + private static final String[] ALIASES = {"luckpermsvelocity", "lpv", "vperm", "vperms", "vpermission", "vpermissions"}; + + /** The command aliases, prefixed with '/' */ + private static final String[] SLASH_ALIASES = Arrays.stream(ALIASES).map(s -> '/' + s).toArray(String[]::new); + private final LPVelocityPlugin plugin; public VelocityCommandExecutor(LPVelocityPlugin plugin) { @@ -44,6 +51,19 @@ public class VelocityCommandExecutor extends CommandManager implements Command { this.plugin = plugin; } + public void register() { + ProxyServer proxy = this.plugin.getBootstrap().getProxy(); + proxy.getCommandManager().register(this, ALIASES); + + // register slash aliases so the console can run '/lpv' in the same way as 'lpv'. + proxy.getCommandManager().register(new ForwardingCommand(this) { + @Override + public boolean hasPermission(CommandSource source, @NonNull String[] args) { + return source instanceof ConsoleCommandSource; + } + }, SLASH_ALIASES); + } + @Override public void execute(@NonNull CommandSource source, @NonNull String[] args) { Sender wrapped = this.plugin.getSenderFactory().wrap(source); @@ -57,4 +77,27 @@ public class VelocityCommandExecutor extends CommandManager implements Command { List arguments = ArgumentTokenizer.TAB_COMPLETE.tokenizeInput(args); return tabCompleteCommand(wrapped, arguments); } + + private static class ForwardingCommand implements Command { + private final Command delegate; + + private ForwardingCommand(Command delegate) { + this.delegate = delegate; + } + + @Override + public void execute(CommandSource source, @NonNull String[] args) { + this.delegate.execute(source, args); + } + + @Override + public List suggest(CommandSource source, @NonNull String[] currentArgs) { + return this.delegate.suggest(source, currentArgs); + } + + @Override + public boolean hasPermission(CommandSource source, @NonNull String[] args) { + return this.delegate.hasPermission(source, args); + } + } }