diff --git a/Core/src/main/java/com/plotsquared/core/command/Deny.java b/Core/src/main/java/com/plotsquared/core/command/Deny.java index 4ed0d0ed5..1cb862304 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Deny.java +++ b/Core/src/main/java/com/plotsquared/core/command/Deny.java @@ -33,9 +33,12 @@ import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.Permissions; +import com.plotsquared.core.util.TabCompletions; import com.plotsquared.core.util.WorldUtil; import com.sk89q.worldedit.world.gamemode.GameModes; +import java.util.Collection; +import java.util.Collections; import java.util.UUID; import java.util.concurrent.TimeoutException; @@ -112,6 +115,10 @@ public class Deny extends SubCommand { return true; } + @Override public Collection tab(final PlotPlayer player, final String[] args, final boolean space) { + return TabCompletions.completePlayers(String.join(",", args).trim(), Collections.emptyList()); + } + private void handleKick(PlotPlayer player, Plot plot) { if (player == null) { return; diff --git a/Core/src/main/java/com/plotsquared/core/command/Kick.java b/Core/src/main/java/com/plotsquared/core/command/Kick.java index 0c83fa24e..6dc3aaa97 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Kick.java +++ b/Core/src/main/java/com/plotsquared/core/command/Kick.java @@ -33,8 +33,11 @@ import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.Permissions; +import com.plotsquared.core.util.TabCompletions; import com.plotsquared.core.util.WorldUtil; +import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.UUID; @@ -122,4 +125,14 @@ public class Kick extends SubCommand { return true; } + + @Override public Collection tab(final PlotPlayer player, final String[] args, final boolean space) { + Location location = player.getLocation(); + Plot plot = location.getPlotAbs(); + if (plot == null) { + return Collections.emptyList(); + } + return TabCompletions.completePlayersInPlot(plot, String.join(",", args).trim(), + Collections.singletonList(player.getName())); + } } diff --git a/Core/src/main/java/com/plotsquared/core/command/Remove.java b/Core/src/main/java/com/plotsquared/core/command/Remove.java index da00e5748..871bd2b60 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Remove.java +++ b/Core/src/main/java/com/plotsquared/core/command/Remove.java @@ -33,7 +33,10 @@ import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.Permissions; +import com.plotsquared.core.util.TabCompletions; +import java.util.Collection; +import java.util.Collections; import java.util.UUID; import java.util.concurrent.TimeoutException; @@ -120,4 +123,14 @@ public class Remove extends SubCommand { return true; } + @Override public Collection tab(final PlotPlayer player, final String[] args, final boolean space) { + Location location = player.getLocation(); + Plot plot = location.getPlotAbs(); + if (plot == null) { + return Collections.emptyList(); + } + return TabCompletions.completeAddedPlayers(plot, String.join(",", args).trim(), + Collections.singletonList(player.getName())); + } + } diff --git a/Core/src/main/java/com/plotsquared/core/util/TabCompletions.java b/Core/src/main/java/com/plotsquared/core/util/TabCompletions.java index 91454b3bb..bb6c74bd4 100644 --- a/Core/src/main/java/com/plotsquared/core/util/TabCompletions.java +++ b/Core/src/main/java/com/plotsquared/core/util/TabCompletions.java @@ -33,6 +33,7 @@ import com.plotsquared.core.command.CommandCategory; import com.plotsquared.core.command.RequiredType; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.player.PlotPlayer; +import com.plotsquared.core.plot.Plot; import com.plotsquared.core.uuid.UUIDMapping; import lombok.experimental.UtilityClass; import org.jetbrains.annotations.NotNull; @@ -43,7 +44,9 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Locale; +import java.util.UUID; import java.util.concurrent.TimeUnit; +import java.util.function.Predicate; import java.util.stream.Collectors; /** @@ -70,35 +73,37 @@ public class TabCompletions { */ @NotNull public List completePlayers(@NotNull final String input, @NotNull final List existing) { - List players; - if (Settings.Enabled_Components.EXTENDED_USERNAME_COMPLETION) { - players = cachedCompletionValues.getIfPresent("players"); - if (players == null) { - final Collection mappings = - PlotSquared.get().getImpromptuUUIDPipeline().getAllImmediately(); - players = new ArrayList<>(mappings.size()); - for (final UUIDMapping mapping : mappings) { - players.add(mapping.getUsername()); - } - cachedCompletionValues.put("players", players); - } - } else { - final Collection onlinePlayers = PlotSquared.imp().getPlayerManager().getPlayers(); - players = new ArrayList<>(onlinePlayers.size()); - for (final PlotPlayer player : onlinePlayers) { + return completePlayers("players", input, existing, uuid -> true); + } + + /** + * Get a list of tab completions corresponding to player names added to the given plot. + * + * @param plot Plot to complete added players for + * @param input Command input + * @param existing Players that should not be included in completions + * @return List of completions + */ + @NotNull public List completeAddedPlayers(@NotNull final Plot plot, @NotNull final String input, + @NotNull final List existing) { + return completePlayers("added" + plot, input, existing, + uuid -> plot.getMembers().contains(uuid) + || plot.getTrusted().contains(uuid) + || plot.getDenied().contains(uuid)); + } + + @NotNull public List completePlayersInPlot(@NotNull final Plot plot, @NotNull final String input, + @NotNull final List existing) { + List players = cachedCompletionValues.getIfPresent("inPlot" + plot); + if (players == null) { + final List> inPlot = plot.getPlayersInPlot(); + players = new ArrayList<>(inPlot.size()); + for (PlotPlayer player : inPlot) { players.add(player.getName()); } + cachedCompletionValues.put("inPlot" + plot, players); } - final String processedInput = input.toLowerCase(Locale.ENGLISH); - return players.stream() - .filter(player -> player.toLowerCase(Locale.ENGLISH).startsWith(processedInput)) - .filter(player -> !existing.contains(player)).map( - player -> new Command(null, false, player, "", RequiredType.NONE, - CommandCategory.INFO) { - }) - /* If there are more than 200 suggestions, just send the first 200 */ - .limit(200) - .collect(Collectors.toList()); + return filterCached(players, input, existing); } /** @@ -129,4 +134,52 @@ public class TabCompletions { return Collections.emptyList(); } + /** + * @param cacheIdentifier Cache key + * @param input Command input + * @param existing Players that should not be included in completions + * @param uuidFilter Filter applied before caching values + * @return List of completions + */ + private List completePlayers(@NotNull final String cacheIdentifier, @NotNull final String input, + @NotNull final List existing, + @NotNull final Predicate uuidFilter) { + List players; + if (Settings.Enabled_Components.EXTENDED_USERNAME_COMPLETION) { + players = cachedCompletionValues.getIfPresent(cacheIdentifier); + if (players == null) { + final Collection mappings = + PlotSquared.get().getImpromptuUUIDPipeline().getAllImmediately(); + players = new ArrayList<>(mappings.size()); + for (final UUIDMapping mapping : mappings) { + if (uuidFilter.test(mapping.getUuid())) { + players.add(mapping.getUsername()); + } + } + cachedCompletionValues.put(cacheIdentifier, players); + } + } else { + final Collection> onlinePlayers = PlotSquared.imp().getPlayerManager().getPlayers(); + players = new ArrayList<>(onlinePlayers.size()); + for (final PlotPlayer player : onlinePlayers) { + if (uuidFilter.test(player.getUUID())) { + players.add(player.getName()); + } + } + } + return filterCached(players, input, existing); + } + + private List filterCached(Collection playerNames, String input, List existing) { + final String processedInput = input.toLowerCase(Locale.ENGLISH); + return playerNames.stream().filter(player -> player.toLowerCase(Locale.ENGLISH).startsWith(processedInput)) + .filter(player -> !existing.contains(player)).map( + player -> new Command(null, false, player, "", RequiredType.NONE, + CommandCategory.INFO) { + }) + /* If there are more than 200 suggestions, just send the first 200 */ + .limit(200) + .collect(Collectors.toList()); + } + }