001/* 002 * Copyright (c) 2016-2017 Daniel Ennis (Aikar) - MIT License 003 * 004 * Permission is hereby granted, free of charge, to any person obtaining 005 * a copy of this software and associated documentation files (the 006 * "Software"), to deal in the Software without restriction, including 007 * without limitation the rights to use, copy, modify, merge, publish, 008 * distribute, sublicense, and/or sell copies of the Software, and to 009 * permit persons to whom the Software is furnished to do so, subject to 010 * the following conditions: 011 * 012 * The above copyright notice and this permission notice shall be 013 * included in all copies or substantial portions of the Software. 014 * 015 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 016 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 017 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 018 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 019 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 020 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 021 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 022 */ 023 024package co.aikar.commands; 025 026import net.md_5.bungee.api.ChatColor; 027import net.md_5.bungee.api.CommandSender; 028import net.md_5.bungee.api.ProxyServer; 029import net.md_5.bungee.api.connection.ProxiedPlayer; 030import org.jetbrains.annotations.Nullable; 031 032import java.util.ArrayList; 033import java.util.List; 034import java.util.regex.Pattern; 035import java.util.stream.Collectors; 036 037public class ACFBungeeUtil { 038 039 public static String color(String message) { 040 return ChatColor.translateAlternateColorCodes('&', message); 041 } 042 043 /** 044 * Move to Message Keys on the CommandIssuer 045 * 046 * @deprecated 047 */ 048 @Deprecated 049 public static void sendMsg(CommandSender player, String message) { 050 message = color(message); 051 for (String msg : ACFPatterns.NEWLINE.split(message)) { 052 player.sendMessage(msg); 053 } 054 } 055 056 public static String removeColors(String msg) { 057 return ChatColor.stripColor(color(msg)); 058 } 059 060 public static String replaceChatString(String message, String replace, String with) { 061 return replaceChatString(message, Pattern.compile(Pattern.quote(replace), Pattern.CASE_INSENSITIVE), with); 062 } 063 064 public static String replaceChatString(String message, Pattern replace, String with) { 065 final String[] split = replace.split(message + "1"); 066 067 if (split.length < 2) { 068 return replace.matcher(message).replaceAll(with); 069 } 070 message = split[0]; 071 072 for (int i = 1; i < split.length; i++) { 073 final String prev = getLastColors(message); 074 message += with + prev + split[i]; 075 } 076 return message.substring(0, message.length() - 1); 077 } 078 079 //Imported from org.bukkit.ChatColor 080 081 public static final char COLOR_CHAR = '\u00A7'; 082 083 public static String getLastColors(String input) { 084 StringBuilder result = new StringBuilder(); 085 int length = input.length(); 086 087 // Search backwards from the end as it is faster 088 for (int index = length - 1; index > -1; index--) { 089 char section = input.charAt(index); 090 if (section == COLOR_CHAR && index < length - 1) { 091 char c = input.charAt(index + 1); 092 ChatColor color = ChatColor.getByChar(c); 093 094 if (color != null) { 095 result.insert(0, color.toString()); 096 097 // Once we find a color or reset we can stop searching 098 if (isChatColorAColor(color) || color.equals(ChatColor.RESET)) { 099 break; 100 } 101 } 102 } 103 } 104 return result.toString(); 105 } 106 107 public static boolean isChatColorAColor(ChatColor chatColor) { 108 return chatColor != ChatColor.MAGIC && chatColor != ChatColor.BOLD 109 && chatColor != ChatColor.STRIKETHROUGH && chatColor != ChatColor.UNDERLINE 110 && chatColor != ChatColor.ITALIC; 111 } 112 113 114 public static ProxiedPlayer findPlayerSmart(CommandIssuer issuer, String search) { 115 CommandSender requester = issuer.getIssuer(); 116 String name = ACFUtil.replace(search, ":confirm", ""); 117 118 List<ProxiedPlayer> matches = new ArrayList<>(ProxyServer.getInstance().matchPlayer(name)); 119 120 if (matches.size() > 1) { 121 String allMatches = matches.stream().map(ProxiedPlayer::getName).collect(Collectors.joining(", ")); 122 issuer.sendError(MinecraftMessageKeys.MULTIPLE_PLAYERS_MATCH, 123 "{search}", name, "{all}", allMatches); 124 return null; 125 } 126 127 if (matches.isEmpty()) { 128 if (!issuer.getManager().isValidName(name)) { 129 issuer.sendError(MinecraftMessageKeys.IS_NOT_A_VALID_NAME, "{name}", name); 130 return null; 131 } 132 issuer.sendError(MinecraftMessageKeys.NO_PLAYER_FOUND_SERVER, 133 "{search}", name); 134 return null; 135 } 136 137 return matches.get(0); 138 } 139 140 /** 141 * Please move to the CommandIssuer version 142 * 143 * @deprecated 144 */ 145 public static ProxiedPlayer findPlayerSmart(CommandSender requester, String search) { 146 CommandManager manager = CommandManager.getCurrentCommandManager(); 147 if (manager != null) { 148 return findPlayerSmart(manager.getCommandIssuer(requester), search); 149 } 150 throw new IllegalStateException("You may not use the ACFBungeeUtil#findPlayerSmart(CommandSender) async to the command execution."); 151 } 152 153 public static boolean isValidName(@Nullable String name) { 154 return name != null && !name.isEmpty() && ACFPatterns.VALID_NAME_PATTERN.matcher(name).matches(); 155 } 156 157 public static <T> T validate(T object, String message, Object... values) { 158 if (object == null) { 159 throw new NullPointerException(String.format(message, values)); 160 } 161 return object; 162 } 163}