From 62b789dff532042267ce360228e01be45578c8f4 Mon Sep 17 00:00:00 2001 From: benwoo1110 <30431861+benwoo1110@users.noreply.github.com> Date: Sun, 21 Feb 2021 16:47:13 +0800 Subject: [PATCH] Add support to find players based on name, UUID or selectors. --- .../MultiverseCore/commands/CheckCommand.java | 3 +- .../MultiverseCore/commands/SpawnCommand.java | 3 +- .../commands/TeleportCommand.java | 3 +- .../MultiverseCore/utils/PlayerFinder.java | 176 ++++++++++++++++++ 4 files changed, 182 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/onarandombox/MultiverseCore/utils/PlayerFinder.java diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/CheckCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/CheckCommand.java index 34fa7791..7bc4ba48 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commands/CheckCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/CheckCommand.java @@ -11,6 +11,7 @@ import com.onarandombox.MultiverseCore.MultiverseCore; import com.onarandombox.MultiverseCore.api.MVDestination; import com.onarandombox.MultiverseCore.destination.InvalidDestination; import com.onarandombox.MultiverseCore.utils.MVPermissions; +import com.onarandombox.MultiverseCore.utils.PlayerFinder; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -37,7 +38,7 @@ public class CheckCommand extends MultiverseCommand { @Override public void runCommand(CommandSender sender, List args) { - Player p = this.plugin.getServer().getPlayerExact(args.get(0)); + Player p = PlayerFinder.get(args.get(0), sender); if (p == null) { sender.sendMessage("Could not find player " + ChatColor.GREEN + args.get(0)); sender.sendMessage("Are they online?"); diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/SpawnCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/SpawnCommand.java index 5536e76c..8e865545 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commands/SpawnCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/SpawnCommand.java @@ -9,6 +9,7 @@ package com.onarandombox.MultiverseCore.commands; import com.onarandombox.MultiverseCore.MultiverseCore; import com.onarandombox.MultiverseCore.api.MultiverseWorld; +import com.onarandombox.MultiverseCore.utils.PlayerFinder; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.command.CommandSender; @@ -50,7 +51,7 @@ public class SpawnCommand extends MultiverseCommand { sender.sendMessage("You don't have permission to teleport another player to spawn. (multiverse.core.spawn.other)"); return; } - Player target = this.plugin.getServer().getPlayerExact(args.get(0)); + Player target = PlayerFinder.get(args.get(0), sender); if (target != null) { target.sendMessage("Teleporting to this world's spawn..."); spawnAccurately(target); diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/TeleportCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/TeleportCommand.java index 17ad7714..b2f8bd03 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commands/TeleportCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/TeleportCommand.java @@ -18,6 +18,7 @@ import com.onarandombox.MultiverseCore.destination.WorldDestination; import com.onarandombox.MultiverseCore.enums.TeleportResult; import com.onarandombox.MultiverseCore.event.MVTeleportEvent; import com.onarandombox.MultiverseCore.api.SafeTTeleporter; +import com.onarandombox.MultiverseCore.utils.PlayerFinder; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.World; @@ -59,7 +60,7 @@ public class TeleportCommand extends MultiverseCommand { String destinationName; if (args.size() == 2) { - teleportee = this.plugin.getServer().getPlayerExact(args.get(0)); + teleportee = PlayerFinder.get(args.get(0), sender); if (teleportee == null) { this.messaging.sendMessage(sender, String.format("Sorry, I couldn't find player: %s%s", ChatColor.GOLD, args.get(0)), false); diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/PlayerFinder.java b/src/main/java/com/onarandombox/MultiverseCore/utils/PlayerFinder.java new file mode 100644 index 00000000..87f5b57a --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/utils/PlayerFinder.java @@ -0,0 +1,176 @@ +package com.onarandombox.MultiverseCore.utils; + +import com.dumptruckman.minecraft.util.Logging; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * Helper class to get {@link Player} from name, UUID or Selectors. + */ +public class PlayerFinder { + + private static final Pattern UUID_REGEX = Pattern.compile("[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[34][0-9a-fA-F]{3}-[89ab][0-9a-fA-F]{3}-[0-9a-fA-F]{12}"); + private static final Pattern COMMA_SPLIT = Pattern.compile(","); + + /** + * Get a {@link Player} based on an identifier of name UUID or selector. + * + * @param playerIdentifier An identifier of name UUID or selector. + * @param sender Target sender for selector. + * @return The player if found, else null. + */ + @Nullable + public static Player get(@NotNull String playerIdentifier, + @NotNull CommandSender sender) { + + Player targetPlayer = getByName(playerIdentifier); + if (targetPlayer != null) { + return targetPlayer; + } + targetPlayer = getByUuid(playerIdentifier); + if (targetPlayer != null) { + return targetPlayer; + } + return getBySelector(playerIdentifier, sender); + } + + /** + * Get multiple {@link Player} based on many identifiers of name UUID or selector. + * + * @param playerIdentifiers An identifier of multiple names, UUIDs or selectors, separated by comma. + * @param sender Target sender for selector. + * @return A list of all the {@link Player} found. + */ + @Nullable + public static List getMulti(@NotNull String playerIdentifiers, + @NotNull CommandSender sender) { + + String[] playerIdentifierArray = COMMA_SPLIT.split(playerIdentifiers); + if (playerIdentifierArray == null || playerIdentifierArray.length == 0) { + return null; + } + + List playerResults = new ArrayList<>(); + for (String playerIdentifier : playerIdentifierArray) { + Player targetPlayer = getByName(playerIdentifier); + if (targetPlayer != null) { + playerResults.add(targetPlayer); + continue; + } + targetPlayer = getByUuid(playerIdentifier); + if (targetPlayer != null) { + playerResults.add(targetPlayer); + continue; + } + List targetPlayers = getMultiBySelector(playerIdentifier, sender); + if (targetPlayers != null) { + playerResults.addAll(targetPlayers); + } + } + return playerResults; + } + + /** + * Get a {@link Player} based on player name. + * + * @param playerName Name of a {@link Player}. + * @return The player if found, else null. + */ + @Nullable + public static Player getByName(@NotNull String playerName) { + return Bukkit.getPlayerExact(playerName); + } + + /** + * Get a {@link Player} based on player UUID. + * + * @param playerUuid UUID of a player. + * @return The player if found, else null. + */ + @Nullable + public static Player getByUuid(@NotNull String playerUuid) { + if (!UUID_REGEX.matcher(playerUuid).matches()) { + return null; + } + UUID uuid; + try { + uuid = UUID.fromString(playerUuid); + } catch (Exception e) { + return null; + } + return getByUuid(uuid); + } + + /** + * Get a {@link Player} based on playerUUID. + * + * @param playerUuid UUID of a player. + * @return The player if found, else null. + */ + @Nullable + public static Player getByUuid(@NotNull UUID playerUuid) { + return Bukkit.getPlayer(playerUuid); + } + + /** + * Get a {@link Player} based on vanilla selectors. + * https://minecraft.gamepedia.com/Commands#Target_selectors + * + * @param playerSelector A target selector, usually starts with an '@'. + * @param sender Target sender for selector. + * @return The player if only one found, else null. + */ + @Nullable + public static Player getBySelector(@NotNull String playerSelector, + @NotNull CommandSender sender) { + + List matchedPlayers = getMultiBySelector(playerSelector, sender); + if (matchedPlayers == null || matchedPlayers.isEmpty()) { + Logging.warning("No player found with selector '%s' for %s.", playerSelector, sender.getName()); + return null; + } + if (matchedPlayers.size() > 1) { + Logging.warning("Ambiguous selector result '%s' for %s (more than one player matched) - %s", + playerSelector, sender.getName(), matchedPlayers.toString()); + return null; + } + return matchedPlayers.get(0); + } + + /** + * Get multiple {@link Player} based on selector. + * https://minecraft.gamepedia.com/Commands#Target_selectors + * + * @param playerSelector A target selector, usually starts with an '@'. + * @param sender Target sender for selector. + * @return A list of all the {@link Player} found. + */ + @Nullable + public static List getMultiBySelector(@NotNull String playerSelector, + @NotNull CommandSender sender) { + + if (playerSelector.charAt(0) != '@') { + return null; + } + try { + return Bukkit.selectEntities(sender, playerSelector).stream() + .filter(e -> e instanceof Player) + .map(e -> ((Player) e)) + .collect(Collectors.toList()); + } catch (IllegalArgumentException e) { + Logging.warning("An error occurred while parsing selector '%s' for %s. Is it is the correct format?", + playerSelector, sender.getName()); + e.printStackTrace(); + return null; + } + } +}