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