    001package co.aikar.commands;
    002
    003import org.spongepowered.api.Sponge;
    004import org.spongepowered.api.command.CommandSource;
    005import org.spongepowered.api.entity.living.player.Player;
    006
    007import java.util.ArrayList;
    008import java.util.Iterator;
    009import java.util.List;
    010import java.util.stream.Collectors;
    011
    012@SuppressWarnings("WeakerAccess")
    013public class ACFSpongeUtil {
    014    public static Player findPlayerSmart(CommandIssuer issuer, String search) {
    015        CommandSource requester = issuer.getIssuer();
    016        if (search == null) {
    017            return null;
    018        }
    019        String name = ACFUtil.replace(search, ":confirm", "");
    020        if (name.length() < 3) {
    021            issuer.sendError(MinecraftMessageKeys.USERNAME_TOO_SHORT);
    022            return null;
    023        }
    024        if (!isValidName(name)) {
    025            issuer.sendError(MinecraftMessageKeys.IS_NOT_A_VALID_NAME, "{name}", name);
    026            return null;
    027        }
    028
    029        List<Player> matches = matchPlayer(name);
    030        List<Player> confirmList = new ArrayList<>();
    031        findMatches(search, requester, matches, confirmList);
    032
    033
    034        if (matches.size() > 1 || confirmList.size() > 1) {
    035            String allMatches = matches.stream().map(Player::getName).collect(Collectors.joining(", "));
    036            issuer.sendError(MinecraftMessageKeys.MULTIPLE_PLAYERS_MATCH,
    037                    "{search}", name, "{all}", allMatches);
    038            return null;
    039        }
    040
    041        if (matches.isEmpty()) {
    042            Player player = ACFUtil.getFirstElement(confirmList);
    043            if (player == null) {
    044                issuer.sendError(MinecraftMessageKeys.NO_PLAYER_FOUND_SERVER, "{search}", name);
    045                return null;
    046            } else {
    047
    048                issuer.sendInfo(MinecraftMessageKeys.PLAYER_IS_VANISHED_CONFIRM, "{vanished}", player.getName());
    049                return null;
    050            }
    051        }
    052
    053        return matches.get(0);
    054    }
    055
    056    private static void findMatches(String search, CommandSource requester, List<Player> matches, List<Player> confirmList) {
    057        // Remove vanished players from smart matching.
    058        Iterator<Player> iter = matches.iterator();
    059        //noinspection Duplicates
    060        while (iter.hasNext()) {
    061            Player player = iter.next();
    062            if (requester instanceof Player && !((Player) requester).canSee(player)) {
    063                if (requester.hasPermission("acf.seevanish")) {
    064                    if (!search.endsWith(":confirm")) {
    065                        confirmList.add(player);
    066                        iter.remove();
    067                    }
    068                } else {
    069                    iter.remove();
    070                }
    071            }
    072        }
    073    }
    074
    075    public static List<Player> matchPlayer(String partialName) {
    076        List<Player> matchedPlayers = new ArrayList<>();
    077
    078        for (Player iterPlayer : Sponge.getServer().getOnlinePlayers()) {
    079            String iterPlayerName = iterPlayer.getName();
    080
    081            if (partialName.equalsIgnoreCase(iterPlayerName)) {
    082                // Exact match
    083                matchedPlayers.clear();
    084                matchedPlayers.add(iterPlayer);
    085                break;
    086            }
    087            if (iterPlayerName.toLowerCase(java.util.Locale.ENGLISH).contains(partialName.toLowerCase(java.util.Locale.ENGLISH))) {
    088                // Partial match
    089                matchedPlayers.add(iterPlayer);
    090            }
    091        }
    092
    093        return matchedPlayers;
    094    }
    095
    096    public static boolean isValidName(String name) {
    097        return name != null && !name.isEmpty() && ACFPatterns.VALID_NAME_PATTERN.matcher(name).matches();
    098    }
    099
    100}