    001package co.aikar.commands;
    002
    003import java.util.ArrayList;
    004import java.util.Collection;
    005import java.util.Collections;
    006import java.util.List;
    007import java.util.Optional;
    008import java.util.stream.Collectors;
    009
    010import com.velocitypowered.api.command.CommandSource;
    011import com.velocitypowered.api.proxy.Player;
    012import com.velocitypowered.api.proxy.ProxyServer;
    013
    014import net.kyori.text.TextComponent;
    015import net.kyori.text.serializer.ComponentSerializers;
    016
    017public class ACFVelocityUtil {
    018
    019    @SuppressWarnings("deprecation")
    020    public static TextComponent color(String message) {
    021        return ComponentSerializers.LEGACY.deserialize(message);
    022    }
    023
    024    public static Player findPlayerSmart(ProxyServer server, CommandIssuer issuer, String search) {
    025        CommandSource requester = issuer.getIssuer();
    026        String name = ACFUtil.replace(search, ":confirm", "");
    027        if (name.length() < 3) {
    028            issuer.sendError(MinecraftMessageKeys.USERNAME_TOO_SHORT);
    029            return null;
    030        }
    031        if (!isValidName(name)) {
    032            issuer.sendError(MinecraftMessageKeys.IS_NOT_A_VALID_NAME, "{name}", name);
    033            return null;
    034        }
    035
    036        List<Player> matches = new ArrayList<>(matchPlayer(server, name));
    037
    038        if (matches.size() > 1) {
    039            String allMatches = matches.stream().map(Player::getUsername).collect(Collectors.joining(", "));
    040            issuer.sendError(MinecraftMessageKeys.MULTIPLE_PLAYERS_MATCH, "{search}", name, "{all}", allMatches);
    041            return null;
    042        }
    043
    044        if (matches.isEmpty()) {
    045            issuer.sendError(MinecraftMessageKeys.NO_PLAYER_FOUND_SERVER, "{search}", name);
    046            return null;
    047        }
    048
    049        return matches.get(0);
    050    }
    051
    052    /*
    053     * Original code written by md_5
    054     *
    055     * Modified to work with Velocity by Crypnotic
    056     */
    057    private static Collection<Player> matchPlayer(ProxyServer server, final String partialName) {
    058        // A better error message might be nice. This just mimics the previous output
    059        if (partialName == null) {
    060            throw new NullPointerException("partialName");
    061        }
    062
    063        Optional<Player> exactMatch = server.getPlayer(partialName);
    064        //noinspection OptionalIsPresent
    065        if (exactMatch.isPresent()) {
    066            return Collections.singleton(exactMatch.get());
    067        }
    068
    069        return server.getAllPlayers().stream()
    070                .filter(player -> player.getUsername().regionMatches(true, 0, partialName, 0, partialName.length()))
    071                .collect(Collectors.toList());
    072    }
    073
    074    public static boolean isValidName(String name) {
    075        return name != null && !name.isEmpty() && ACFPatterns.VALID_NAME_PATTERN.matcher(name).matches();
    076    }
    077
    078    public static <T> T validate(T object, String message, Object... values) {
    079        if (object == null) {
    080            throw new NullPointerException(String.format(message, values));
    081        }
    082        return object;
    083    }
    084}