Remove commands from autocomplete/help list that cannot be run (#2602)

* only tabcomplete for commands the sender has permission for

* set permission defaults for spigot

* Make velocity autocomplete on arg length 0 and 1

* fix advancements perm in spigot plugin.yml and add settings perm

(whoops)

* don't show bedrock commands to java players

* modify spigot perm defaults

* censor help menu, abstract tab complete code

* Bedrock players don't get cmd argument suggestions

* update spigot plugin.yml
This commit is contained in:
Konicai 2021-10-30 21:57:54 -04:00 committed by GitHub
parent c115afba85
commit f883dfdf2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 132 additions and 30 deletions

View File

@ -63,4 +63,9 @@ public class BungeeCommandSender implements CommandSender {
}
return LanguageUtils.getDefaultLocale();
}
@Override
public boolean hasPermission(String permission) {
return handle.hasPermission(permission);
}
}

View File

@ -35,8 +35,8 @@ import org.geysermc.connector.command.GeyserCommand;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.utils.LanguageUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class GeyserBungeeCommandExecutor extends Command implements TabExecutor {
@ -82,8 +82,9 @@ public class GeyserBungeeCommandExecutor extends Command implements TabExecutor
@Override
public Iterable<String> onTabComplete(CommandSender sender, String[] args) {
if (args.length == 1) {
return connector.getCommandManager().getCommandNames();
return commandExecutor.tabComplete(new BungeeCommandSender(sender));
} else {
return Collections.emptyList();
}
return new ArrayList<>();
}
}

View File

@ -35,8 +35,8 @@ import org.geysermc.connector.command.GeyserCommand;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.utils.LanguageUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class GeyserSpigotCommandExecutor extends CommandExecutor implements TabExecutor {
@ -78,8 +78,8 @@ public class GeyserSpigotCommandExecutor extends CommandExecutor implements TabE
@Override
public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) {
if (args.length == 1) {
return connector.getCommandManager().getCommandNames();
return tabComplete(new SpigotCommandSender(sender));
}
return new ArrayList<>();
return Collections.emptyList();
}
}

View File

@ -73,6 +73,11 @@ public class SpigotCommandSender implements CommandSender {
return locale;
}
@Override
public boolean hasPermission(String permission) {
return handle.hasPermission(permission);
}
/**
* Set if we are on pre-1.12, and therefore {@code player.getLocale()} doesn't exist and we have to get
* {@code player.spigot().getLocale()}.

View File

@ -8,21 +8,32 @@ api-version: 1.13
commands:
geyser:
description: The main command for Geyser.
usage: /geyser help
usage: /geyser <subcommand>
permissions:
geyser.command.help:
description: Shows help for all registered commands.
geyser.command.advancement:
description: Shows the advancements of the player on the server.
geyser.command.dump:
description: Dumps Geyser debug information for bug reports.
geyser.command.list:
description: List all players connected through Geyser.
default: true
geyser.command.offhand:
description: Puts an items in your offhand.
geyser.command.reload:
description: Reloads the Geyser configurations. Kicks all players when used!
default: true
geyser.command.advancements:
description: Shows the advancements of the player on the server.
default: true
geyser.command.statistics:
description: Shows the statistics of the player on the server.
default: true
geyser.command.settings:
description: Modify user settings
default: true
geyser.command.list:
description: List all players connected through Geyser.
default: op
geyser.command.dump:
description: Dumps Geyser debug information for bug reports.
default: op
geyser.command.reload:
description: Reloads the Geyser configurations. Kicks all players when used!
default: false
geyser.command.version:
description: Shows the current Geyser version and checks for updates.
description: Shows the current Geyser version and checks for updates.
default: op

View File

@ -40,8 +40,8 @@ import org.spongepowered.api.world.Location;
import org.spongepowered.api.world.World;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
@ -82,9 +82,9 @@ public class GeyserSpongeCommandExecutor extends CommandExecutor implements Comm
@Override
public List<String> getSuggestions(CommandSource source, String arguments, @Nullable Location<World> targetPosition) {
if (arguments.split(" ").length == 1) {
return connector.getCommandManager().getCommandNames();
return tabComplete(new SpongeCommandSender(source));
}
return new ArrayList<>();
return Collections.emptyList();
}
@Override

View File

@ -51,4 +51,9 @@ public class SpongeCommandSender implements CommandSender {
public boolean isConsole() {
return handle instanceof ConsoleSource;
}
@Override
public boolean hasPermission(String permission) {
return handle.hasPermission(permission);
}
}

View File

@ -110,4 +110,9 @@ public class GeyserStandaloneLogger extends SimpleTerminalConsole implements Gey
public boolean isConsole() {
return true;
}
@Override
public boolean hasPermission(String permission) {
return true;
}
}

View File

@ -34,8 +34,8 @@ import org.geysermc.connector.common.ChatColor;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.utils.LanguageUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class GeyserVelocityCommandExecutor extends CommandExecutor implements SimpleCommand {
@ -71,9 +71,10 @@ public class GeyserVelocityCommandExecutor extends CommandExecutor implements Si
@Override
public List<String> suggest(Invocation invocation) {
if (invocation.arguments().length == 0) {
return connector.getCommandManager().getCommandNames();
// Velocity seems to do the splitting a bit differently. This results in the same behaviour in bungeecord/spigot.
if (invocation.arguments().length == 0 || invocation.arguments().length == 1) {
return tabComplete(new VelocityCommandSender(invocation.source()));
}
return new ArrayList<>();
return Collections.emptyList();
}
}

View File

@ -72,4 +72,9 @@ public class VelocityCommandSender implements CommandSender {
}
return LanguageUtils.getDefaultLocale();
}
@Override
public boolean hasPermission(String permission) {
return handle.hasPermission(permission);
}
}

View File

@ -29,6 +29,11 @@ import lombok.AllArgsConstructor;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.network.session.GeyserSession;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* Represents helper functions for listening to {@code /geyser} commands.
*/
@ -53,4 +58,39 @@ public class CommandExecutor {
}
return null;
}
/**
* Determine which subcommands to suggest in the tab complete for the main /geyser command by a given command sender.
*
* @param sender The command sender to receive the tab complete suggestions.
* If the command sender is a bedrock player, an empty list will be returned as bedrock players do not get command argument suggestions.
* If the command sender is not a bedrock player, bedrock commands will not be shown.
* If the command sender does not have the permission for a given command, the command will not be shown.
* @return A list of command names to include in the tab complete
*/
public List<String> tabComplete(CommandSender sender) {
if (getGeyserSession(sender) != null) {
// Bedrock doesn't get tab completions or argument suggestions
return Collections.emptyList();
}
List<String> availableCommands = new ArrayList<>();
Map<String, GeyserCommand> commands = connector.getCommandManager().getCommands();
// Only show commands they have permission to use
for (String name : commands.keySet()) {
GeyserCommand geyserCommand = commands.get(name);
if (sender.hasPermission(geyserCommand.getPermission())) {
if (geyserCommand.isBedrockOnly()) {
// Don't show commands the JE player can't run
continue;
}
availableCommands.add(name);
}
}
return availableCommands;
}
}

View File

@ -56,4 +56,12 @@ public interface CommandSender {
default String getLocale() {
return LanguageUtils.getDefaultLocale();
}
/**
* Checks if the CommandSender has a permission
*
* @param permission The permission node to check
* @return true if the CommandSender has the requested permission, false if not
*/
boolean hasPermission(String permission);
}

View File

@ -33,9 +33,7 @@ import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.utils.LanguageUtils;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class HelpCommand extends GeyserCommand {
private final GeyserConnector connector;
@ -47,16 +45,33 @@ public class HelpCommand extends GeyserCommand {
this.setAliases(Collections.singletonList("?"));
}
/**
* Sends the help menu to a command sender. Will not show certain commands depending on the command sender and session.
*
* @param session The Geyser session of the command sender, if it is a bedrock player. If null, bedrock-only commands will be hidden.
* @param sender The CommandSender to send the help message to.
* @param args Not used.
*/
@Override
public void execute(GeyserSession session, CommandSender sender, String[] args) {
int page = 1;
int maxPage = 1;
String header = LanguageUtils.getPlayerLocaleString("geyser.commands.help.header", sender.getLocale(), page, maxPage);
sender.sendMessage(header);
Map<String, GeyserCommand> cmds = connector.getCommandManager().getCommands();
List<String> commands = connector.getCommandManager().getCommands().keySet().stream().sorted().collect(Collectors.toList());
commands.forEach(cmd -> sender.sendMessage(ChatColor.YELLOW + "/geyser " + cmd + ChatColor.WHITE + ": " +
LanguageUtils.getPlayerLocaleString(cmds.get(cmd).getDescription(), sender.getLocale())));
for (String cmdName : cmds.keySet()) {
GeyserCommand cmd = cmds.get(cmdName);
if (sender.hasPermission(cmd.getPermission())) {
// Only list commands the player can actually run
if (cmd.isBedrockOnly() && session == null) {
continue;
}
sender.sendMessage(ChatColor.YELLOW + "/geyser " + cmdName + ChatColor.WHITE + ": " +
LanguageUtils.getPlayerLocaleString(cmd.getDescription(), sender.getLocale()));
}
}
}
}

View File

@ -1381,7 +1381,8 @@ public class GeyserSession implements CommandSender {
* @param permission The permission node to check
* @return true if the player has the requested permission, false if not
*/
public Boolean hasPermission(String permission) {
@Override
public boolean hasPermission(String permission) {
return connector.getWorldManager().hasPermission(this, permission);
}