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 org.bukkit.Bukkit; 027import org.bukkit.ChatColor; 028import org.bukkit.Location; 029import org.bukkit.Material; 030import org.bukkit.World; 031import org.bukkit.command.CommandSender; 032import org.bukkit.entity.Entity; 033import org.bukkit.entity.Player; 034import org.bukkit.inventory.ItemStack; 035import org.jetbrains.annotations.NotNull; 036 037import java.util.ArrayList; 038import java.util.Iterator; 039import java.util.List; 040import java.util.Set; 041import java.util.regex.Pattern; 042import java.util.stream.Collectors; 043 044public class ACFBukkitUtil { 045 046 public static String formatLocation(Location loc) { 047 if (loc == null) { 048 return null; 049 } 050 return loc.getWorld().getName() + 051 ":" + 052 loc.getBlockX() + 053 "," + 054 loc.getBlockY() + 055 "," + 056 loc.getBlockZ(); 057 } 058 059 public static String color(String message) { 060 return ChatColor.translateAlternateColorCodes('&', message); 061 } 062 063 /** 064 * Move to Message Keys on the CommandIssuer 065 * 066 * @deprecated 067 */ 068 @Deprecated 069 public static void sendMsg(CommandSender player, String message) { 070 message = color(message); 071 for (String msg : ACFPatterns.NEWLINE.split(message)) { 072 player.sendMessage(msg); 073 } 074 } 075 076 public static Location stringToLocation(String storedLoc) { 077 return stringToLocation(storedLoc, null); 078 } 079 080 public static Location stringToLocation(String storedLoc, World forcedWorld) { 081 if (storedLoc == null) { 082 return null; 083 } 084 String[] args = ACFPatterns.COLON.split(storedLoc); 085 if (args.length >= 4 || (args.length == 3 && forcedWorld != null)) { 086 String world = forcedWorld != null ? forcedWorld.getName() : args[0]; 087 int i = args.length == 3 ? 0 : 1; 088 double x = Double.parseDouble(args[i]); 089 double y = Double.parseDouble(args[i + 1]); 090 double z = Double.parseDouble(args[i + 2]); 091 Location loc = new Location(Bukkit.getWorld(world), x, y, z); 092 if (args.length >= 6) { 093 loc.setPitch(Float.parseFloat(args[4])); 094 loc.setYaw(Float.parseFloat(args[5])); 095 } 096 return loc; 097 } else if (args.length == 2) { 098 String[] args2 = ACFPatterns.COMMA.split(args[1]); 099 if (args2.length == 3) { 100 String world = forcedWorld != null ? forcedWorld.getName() : args[0]; 101 double x = Double.parseDouble(args2[0]); 102 double y = Double.parseDouble(args2[1]); 103 double z = Double.parseDouble(args2[2]); 104 return new Location(Bukkit.getWorld(world), x, y, z); 105 } 106 } 107 return null; 108 } 109 110 public static String fullLocationToString(Location loc) { 111 if (loc == null) { 112 return null; 113 } 114 return (new StringBuilder(64)) 115 .append(loc.getWorld().getName()) 116 .append(':') 117 .append(ACFUtil.precision(loc.getX(), 4)) 118 .append(':') 119 .append(ACFUtil.precision(loc.getY(), 4)) 120 .append(':') 121 .append(ACFUtil.precision(loc.getZ(), 4)) 122 .append(':') 123 .append(ACFUtil.precision(loc.getPitch(), 4)) 124 .append(':') 125 .append(ACFUtil.precision(loc.getYaw(), 4)) 126 .toString(); 127 } 128 129 public static String fullBlockLocationToString(Location loc) { 130 if (loc == null) { 131 return null; 132 } 133 return (new StringBuilder(64)) 134 .append(loc.getWorld().getName()) 135 .append(':') 136 .append(loc.getBlockX()) 137 .append(':') 138 .append(loc.getBlockY()) 139 .append(':') 140 .append(loc.getBlockZ()) 141 .append(':') 142 .append(ACFUtil.precision(loc.getPitch(), 4)) 143 .append(':') 144 .append(ACFUtil.precision(loc.getYaw(), 4)) 145 .toString(); 146 } 147 148 public static String blockLocationToString(Location loc) { 149 if (loc == null) { 150 return null; 151 } 152 153 return (new StringBuilder(32)) 154 .append(loc.getWorld().getName()) 155 .append(':') 156 .append(loc.getBlockX()) 157 .append(':') 158 .append(loc.getBlockY()) 159 .append(':') 160 .append(loc.getBlockZ()) 161 .toString(); 162 } 163 164 public static double distance(@NotNull Entity e1, @NotNull Entity e2) { 165 return distance(e1.getLocation(), e2.getLocation()); 166 } 167 168 public static double distance2d(@NotNull Entity e1, @NotNull Entity e2) { 169 return distance2d(e1.getLocation(), e2.getLocation()); 170 } 171 172 public static double distance2d(@NotNull Location loc1, @NotNull Location loc2) { 173 loc1 = loc1.clone(); 174 loc1.setY(loc2.getY()); 175 return distance(loc1, loc2); 176 } 177 178 public static double distance(@NotNull Location loc1, @NotNull Location loc2) { 179 if (loc1.getWorld() != loc2.getWorld()) { 180 return 0; 181 } 182 return loc1.distance(loc2); 183 } 184 185 public static Location getTargetLoc(Player player) { 186 return getTargetLoc(player, 128); 187 } 188 189 public static Location getTargetLoc(Player player, int maxDist) { 190 return getTargetLoc(player, maxDist, 1.5); 191 } 192 193 public static Location getTargetLoc(Player player, int maxDist, double addY) { 194 try { 195 Location target = player.getTargetBlock((Set<Material>) null, maxDist).getLocation(); 196 target.setY(target.getY() + addY); 197 return target; 198 } catch (Exception ignored) { 199 return null; 200 } 201 } 202 203 public static Location getRandLoc(Location loc, int radius) { 204 return getRandLoc(loc, radius, radius, radius); 205 } 206 207 public static Location getRandLoc(Location loc, int xzRadius, int yRadius) { 208 return getRandLoc(loc, xzRadius, yRadius, xzRadius); 209 } 210 211 @NotNull 212 public static Location getRandLoc(Location loc, int xRadius, int yRadius, int zRadius) { 213 Location newLoc = loc.clone(); 214 newLoc.setX(ACFUtil.rand(loc.getX() - xRadius, loc.getX() + xRadius)); 215 newLoc.setY(ACFUtil.rand(loc.getY() - yRadius, loc.getY() + yRadius)); 216 newLoc.setZ(ACFUtil.rand(loc.getZ() - zRadius, loc.getZ() + zRadius)); 217 return newLoc; 218 } 219 220 221 public static String removeColors(String msg) { 222 return ChatColor.stripColor(color(msg)); 223 } 224 225 public static String replaceChatString(String message, String replace, String with) { 226 return replaceChatString(message, Pattern.compile(Pattern.quote(replace), Pattern.CASE_INSENSITIVE), with); 227 } 228 229 public static String replaceChatString(String message, Pattern replace, String with) { 230 final String[] split = replace.split(message + "1"); 231 232 if (split.length < 2) { 233 return replace.matcher(message).replaceAll(with); 234 } 235 message = split[0]; 236 237 for (int i = 1; i < split.length; i++) { 238 final String prev = ChatColor.getLastColors(message); 239 message += with + prev + split[i]; 240 } 241 return message.substring(0, message.length() - 1); 242 } 243 244 public static boolean isWithinDistance(@NotNull Player p1, @NotNull Player p2, int dist) { 245 return isWithinDistance(p1.getLocation(), p2.getLocation(), dist); 246 } 247 248 public static boolean isWithinDistance(@NotNull Location loc1, @NotNull Location loc2, int dist) { 249 return loc1.getWorld() == loc2.getWorld() && loc1.distance(loc2) <= dist; 250 } 251 252 /** 253 * Please move to the CommandIssuer version 254 * 255 * @deprecated 256 */ 257 public static Player findPlayerSmart(CommandSender requester, String search) { 258 CommandManager manager = CommandManager.getCurrentCommandManager(); 259 if (manager != null) { 260 return findPlayerSmart(manager.getCommandIssuer(requester), search); 261 } 262 throw new IllegalStateException("You may not use the ACFBukkitUtil#findPlayerSmart(CommandSender) async to the command execution."); 263 } 264 265 public static Player findPlayerSmart(CommandIssuer issuer, String search) { 266 CommandSender requester = issuer.getIssuer(); 267 if (search == null) { 268 return null; 269 } 270 String name = ACFUtil.replace(search, ":confirm", ""); 271 272 if (!isValidName(name)) { 273 issuer.sendError(MinecraftMessageKeys.IS_NOT_A_VALID_NAME, "{name}", name); 274 return null; 275 } 276 277 List<Player> matches = Bukkit.getServer().matchPlayer(name); 278 List<Player> confirmList = new ArrayList<>(); 279 findMatches(search, requester, matches, confirmList); 280 281 282 if (matches.size() > 1 || confirmList.size() > 1) { 283 String allMatches = matches.stream().map(Player::getName).collect(Collectors.joining(", ")); 284 issuer.sendError(MinecraftMessageKeys.MULTIPLE_PLAYERS_MATCH, 285 "{search}", name, "{all}", allMatches); 286 return null; 287 } 288 289 //noinspection Duplicates 290 if (matches.isEmpty()) { 291 Player player = ACFUtil.getFirstElement(confirmList); 292 if (player == null) { 293 issuer.sendError(MinecraftMessageKeys.NO_PLAYER_FOUND_SERVER, "{search}", name); 294 return null; 295 } else { 296 issuer.sendInfo(MinecraftMessageKeys.PLAYER_IS_VANISHED_CONFIRM, "{vanished}", player.getName()); 297 return null; 298 } 299 } 300 301 return matches.get(0); 302 } 303 304 private static void findMatches(String search, CommandSender requester, List<Player> matches, List<Player> confirmList) { 305 // Remove vanished players from smart matching. 306 Iterator<Player> iter = matches.iterator(); 307 //noinspection Duplicates 308 while (iter.hasNext()) { 309 Player player = iter.next(); 310 if (requester instanceof Player && !((Player) requester).canSee(player)) { 311 if (requester.hasPermission("acf.seevanish")) { 312 if (!search.endsWith(":confirm")) { 313 confirmList.add(player); 314 iter.remove(); 315 } 316 } else { 317 iter.remove(); 318 } 319 } 320 } 321 } 322 323 324 public static boolean isValidName(String name) { 325 return name != null && !name.isEmpty() && ACFPatterns.VALID_NAME_PATTERN.matcher(name).matches(); 326 } 327 328 static boolean isValidItem(ItemStack item) { 329 return item != null && item.getType() != Material.AIR && item.getAmount() > 0; 330 } 331}