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