diff --git a/docs/acf-bukkit/co/aikar/commands/ACFBukkitUtil.html b/docs/acf-bukkit/co/aikar/commands/ACFBukkitUtil.html index 721953d0..5cd33ea7 100644 --- a/docs/acf-bukkit/co/aikar/commands/ACFBukkitUtil.html +++ b/docs/acf-bukkit/co/aikar/commands/ACFBukkitUtil.html @@ -108,7 +108,7 @@ var activeTableTab = "activeTableTab";
public class ACFBukkitUtil +public class ACFBukkitUtil extends Object
public ACFBukkitUtil()+
public ACFBukkitUtil()
public static String formatLocation(org.bukkit.Location loc)+
public static String formatLocation(org.bukkit.Location loc)
public static String color(String message)+
public static String color(String message)
@Deprecated
-public static void sendMsg(org.bukkit.command.CommandSender player,
+public static void sendMsg(org.bukkit.command.CommandSender player,
String message)
public static org.bukkit.Location stringToLocation(String storedLoc)+
public static org.bukkit.Location stringToLocation(String storedLoc)
public static org.bukkit.Location stringToLocation(String storedLoc, +public static org.bukkit.Location stringToLocation(String storedLoc, org.bukkit.World forcedWorld)
public static String fullLocationToString(org.bukkit.Location loc)+
public static String fullLocationToString(org.bukkit.Location loc)
public static String fullBlockLocationToString(org.bukkit.Location loc)+
public static String fullBlockLocationToString(org.bukkit.Location loc)
public static String blockLocationToString(org.bukkit.Location loc)+
public static String blockLocationToString(org.bukkit.Location loc)
public static double distance(@NotNull +public static double distance(@NotNull @NotNull org.bukkit.entity.Entity e1, @NotNull @NotNull org.bukkit.entity.Entity e2)@@ -412,7 +412,7 @@ public static voiddistance2d
-public static double distance2d(@NotNull +public static double distance2d(@NotNull @NotNull org.bukkit.entity.Entity e1, @NotNull @NotNull org.bukkit.entity.Entity e2)@@ -424,7 +424,7 @@ public static voiddistance2d
-public static double distance2d(@NotNull +public static double distance2d(@NotNull @NotNull org.bukkit.Location loc1, @NotNull @NotNull org.bukkit.Location loc2)@@ -436,7 +436,7 @@ public static voiddistance
-public static double distance(@NotNull +public static double distance(@NotNull @NotNull org.bukkit.Location loc1, @NotNull @NotNull org.bukkit.Location loc2)@@ -448,7 +448,7 @@ public static void@@ -457,7 +457,7 @@ public static void getTargetLoc
-public static org.bukkit.Location getTargetLoc(org.bukkit.entity.Player player)+public static org.bukkit.Location getTargetLoc(org.bukkit.entity.Player player)@@ -467,7 +467,7 @@ public static void getTargetLoc
-public static org.bukkit.Location getTargetLoc(org.bukkit.entity.Player player, +public static org.bukkit.Location getTargetLoc(org.bukkit.entity.Player player, int maxDist)@@ -478,7 +478,7 @@ public static void getTargetLoc
-public static org.bukkit.Location getTargetLoc(org.bukkit.entity.Player player, +public static org.bukkit.Location getTargetLoc(org.bukkit.entity.Player player, int maxDist, double addY)@@ -488,7 +488,7 @@ public static void getRandLoc
-public static org.bukkit.Location getRandLoc(org.bukkit.Location loc, +public static org.bukkit.Location getRandLoc(org.bukkit.Location loc, int radius)@@ -500,7 +500,7 @@ public static void getRandLoc
-public static org.bukkit.Location getRandLoc(org.bukkit.Location loc, +public static org.bukkit.Location getRandLoc(org.bukkit.Location loc, int xzRadius, int yRadius)getRandLoc
@NotNull -public static @NotNull org.bukkit.Location getRandLoc(org.bukkit.Location loc, +public static @NotNull org.bukkit.Location getRandLoc(org.bukkit.Location loc, int xRadius, int yRadius, int zRadius)@@ -512,7 +512,7 @@ public static @NotNull org.bukkit.Location@@ -521,7 +521,7 @@ public static @NotNull org.bukkit.Location removeColors
-public static String removeColors(String msg)+public static String removeColors(String msg)@@ -532,7 +532,7 @@ public static @NotNull org.bukkit.Location replaceChatString
-public static String replaceChatString(String message, +public static String replaceChatString(String message, String replace, String with)@@ -543,7 +543,7 @@ public static @NotNull org.bukkit.Location replaceChatString
-public static String replaceChatString(String message, +public static String replaceChatString(String message, Pattern replace, String with)isWithinDistance
-public static boolean isWithinDistance(@NotNull +public static boolean isWithinDistance(@NotNull @NotNull org.bukkit.entity.Player p1, @NotNull @NotNull org.bukkit.entity.Player p2, @@ -556,7 +556,7 @@ public static @NotNull org.bukkit.LocationisWithinDistance
-public static boolean isWithinDistance(@NotNull +public static boolean isWithinDistance(@NotNull @NotNull org.bukkit.Location loc1, @NotNull @NotNull org.bukkit.Location loc2, @@ -569,7 +569,7 @@ public static @NotNull org.bukkit.Locationdiff --git a/docs/acf-bukkit/src-html/co/aikar/commands/ACFBukkitUtil.html b/docs/acf-bukkit/src-html/co/aikar/commands/ACFBukkitUtil.html index e80b42ea..96eb72cc 100644 --- a/docs/acf-bukkit/src-html/co/aikar/commands/ACFBukkitUtil.html +++ b/docs/acf-bukkit/src-html/co/aikar/commands/ACFBukkitUtil.html @@ -31,301 +31,300 @@ 023 024package co.aikar.commands; 025 -026import com.google.common.collect.Iterables; -027import org.bukkit.Bukkit; -028import org.bukkit.ChatColor; -029import org.bukkit.Location; -030import org.bukkit.Material; -031import org.bukkit.World; -032import org.bukkit.command.CommandSender; -033import org.bukkit.entity.Entity; -034import org.bukkit.entity.Player; -035import org.bukkit.inventory.ItemStack; -036import org.jetbrains.annotations.NotNull; -037 -038import java.util.ArrayList; -039import java.util.Iterator; -040import java.util.List; -041import java.util.Set; -042import java.util.regex.Pattern; -043import java.util.stream.Collectors; -044 -045public class ACFBukkitUtil { -046 -047 public static String formatLocation(Location loc) { -048 if (loc == null) { -049 return null; -050 } -051 return loc.getWorld().getName() + -052 ":" + -053 loc.getBlockX() + -054 "," + -055 loc.getBlockY() + -056 "," + -057 loc.getBlockZ(); -058 } -059 -060 public static String color(String message) { -061 return ChatColor.translateAlternateColorCodes('&', message); -062 } -063 -064 /** -065 * Move to Message Keys on the CommandIssuer -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 public static Location stringToLocation(String storedLoc, World forcedWorld) { -080 if (storedLoc == null) { -081 return null; -082 } -083 String[] args = ACFPatterns.COLON.split(storedLoc); -084 if (args.length >= 4 || (args.length == 3 && forcedWorld != null)) { -085 String world = forcedWorld != null ? forcedWorld.getName() : args[0]; -086 int i = args.length == 3 ? 0 : 1; -087 double x = Double.parseDouble(args[i]); -088 double y = Double.parseDouble(args[i + 1]); -089 double z = Double.parseDouble(args[i + 2]); -090 Location loc = new Location(Bukkit.getWorld(world), x, y, z); -091 if (args.length >= 6) { -092 loc.setPitch(Float.parseFloat(args[4])); -093 loc.setYaw(Float.parseFloat(args[5])); -094 } -095 return loc; -096 } else if (args.length == 2) { -097 String[] args2 = ACFPatterns.COMMA.split(args[1]); -098 if (args2.length == 3) { -099 String world = forcedWorld != null ? forcedWorld.getName() : args[0]; -100 double x = Double.parseDouble(args2[0]); -101 double y = Double.parseDouble(args2[1]); -102 double z = Double.parseDouble(args2[2]); -103 return new Location(Bukkit.getWorld(world), x, y, z); -104 } -105 } -106 return null; -107 } -108 -109 public static String fullLocationToString(Location loc) { -110 if (loc == null) { -111 return null; -112 } -113 return (new StringBuilder(64)) -114 .append(loc.getWorld().getName()) -115 .append(':') -116 .append(ACFUtil.precision(loc.getX(), 4)) -117 .append(':') -118 .append(ACFUtil.precision(loc.getY(), 4)) -119 .append(':') -120 .append(ACFUtil.precision(loc.getZ(), 4)) -121 .append(':') -122 .append(ACFUtil.precision(loc.getPitch(), 4)) -123 .append(':') -124 .append(ACFUtil.precision(loc.getYaw(), 4)) -125 .toString(); -126 } -127 -128 public static String fullBlockLocationToString(Location loc) { -129 if (loc == null) { -130 return null; -131 } -132 return (new StringBuilder(64)) -133 .append(loc.getWorld().getName()) -134 .append(':') -135 .append(loc.getBlockX()) -136 .append(':') -137 .append(loc.getBlockY()) -138 .append(':') -139 .append(loc.getBlockZ()) -140 .append(':') -141 .append(ACFUtil.precision(loc.getPitch(), 4)) -142 .append(':') -143 .append(ACFUtil.precision(loc.getYaw(), 4)) -144 .toString(); -145 } -146 -147 public static String blockLocationToString(Location loc) { -148 if (loc == null) { -149 return null; -150 } -151 -152 return (new StringBuilder(32)) -153 .append(loc.getWorld().getName()) -154 .append(':') -155 .append(loc.getBlockX()) -156 .append(':') -157 .append(loc.getBlockY()) -158 .append(':') -159 .append(loc.getBlockZ()) -160 .toString(); -161 } -162 -163 public static double distance(@NotNull Entity e1, @NotNull Entity e2) { -164 return distance(e1.getLocation(), e2.getLocation()); -165 } -166 public static double distance2d(@NotNull Entity e1, @NotNull Entity e2) { -167 return distance2d(e1.getLocation(), e2.getLocation()); -168 } -169 public static double distance2d(@NotNull Location loc1, @NotNull Location loc2) { -170 loc1 = loc1.clone(); -171 loc1.setY(loc2.getY()); -172 return distance(loc1, loc2); -173 } -174 public static double distance(@NotNull Location loc1, @NotNull Location loc2) { -175 if (loc1.getWorld() != loc2.getWorld()) { -176 return 0; -177 } -178 return loc1.distance(loc2); -179 } -180 -181 public static Location getTargetLoc(Player player) { -182 return getTargetLoc(player, 128); -183 } -184 public static Location getTargetLoc(Player player, int maxDist) { -185 return getTargetLoc(player, maxDist, 1.5); -186 } -187 public static Location getTargetLoc(Player player, int maxDist, double addY) { -188 try { -189 Location target = player.getTargetBlock((Set<Material>) null, maxDist).getLocation(); -190 target.setY(target.getY() + addY); -191 return target; -192 } catch (Exception ignored) { -193 return null; -194 } -195 } -196 -197 public static Location getRandLoc(Location loc, int radius) { -198 return getRandLoc(loc, radius, radius, radius); -199 } -200 public static Location getRandLoc(Location loc, int xzRadius, int yRadius) { -201 return getRandLoc(loc, xzRadius, yRadius, xzRadius); -202 } -203 @NotNull public static Location getRandLoc(Location loc, int xRadius, int yRadius, int zRadius) { -204 Location newLoc = loc.clone(); -205 newLoc.setX(ACFUtil.rand(loc.getX()-xRadius, loc.getX()+xRadius)); -206 newLoc.setY(ACFUtil.rand(loc.getY()-yRadius, loc.getY()+yRadius)); -207 newLoc.setZ(ACFUtil.rand(loc.getZ()-zRadius, loc.getZ()+zRadius)); -208 return newLoc; -209 } +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 * @deprecated +066 */ +067 @Deprecated +068 public static void sendMsg(CommandSender player, String message) { +069 message = color(message); +070 for (String msg : ACFPatterns.NEWLINE.split(message)) { +071 player.sendMessage(msg); +072 } +073 } +074 +075 public static Location stringToLocation(String storedLoc) { +076 return stringToLocation(storedLoc, null); +077 } +078 public static Location stringToLocation(String storedLoc, World forcedWorld) { +079 if (storedLoc == null) { +080 return null; +081 } +082 String[] args = ACFPatterns.COLON.split(storedLoc); +083 if (args.length >= 4 || (args.length == 3 && forcedWorld != null)) { +084 String world = forcedWorld != null ? forcedWorld.getName() : args[0]; +085 int i = args.length == 3 ? 0 : 1; +086 double x = Double.parseDouble(args[i]); +087 double y = Double.parseDouble(args[i + 1]); +088 double z = Double.parseDouble(args[i + 2]); +089 Location loc = new Location(Bukkit.getWorld(world), x, y, z); +090 if (args.length >= 6) { +091 loc.setPitch(Float.parseFloat(args[4])); +092 loc.setYaw(Float.parseFloat(args[5])); +093 } +094 return loc; +095 } else if (args.length == 2) { +096 String[] args2 = ACFPatterns.COMMA.split(args[1]); +097 if (args2.length == 3) { +098 String world = forcedWorld != null ? forcedWorld.getName() : args[0]; +099 double x = Double.parseDouble(args2[0]); +100 double y = Double.parseDouble(args2[1]); +101 double z = Double.parseDouble(args2[2]); +102 return new Location(Bukkit.getWorld(world), x, y, z); +103 } +104 } +105 return null; +106 } +107 +108 public static String fullLocationToString(Location loc) { +109 if (loc == null) { +110 return null; +111 } +112 return (new StringBuilder(64)) +113 .append(loc.getWorld().getName()) +114 .append(':') +115 .append(ACFUtil.precision(loc.getX(), 4)) +116 .append(':') +117 .append(ACFUtil.precision(loc.getY(), 4)) +118 .append(':') +119 .append(ACFUtil.precision(loc.getZ(), 4)) +120 .append(':') +121 .append(ACFUtil.precision(loc.getPitch(), 4)) +122 .append(':') +123 .append(ACFUtil.precision(loc.getYaw(), 4)) +124 .toString(); +125 } +126 +127 public static String fullBlockLocationToString(Location loc) { +128 if (loc == null) { +129 return null; +130 } +131 return (new StringBuilder(64)) +132 .append(loc.getWorld().getName()) +133 .append(':') +134 .append(loc.getBlockX()) +135 .append(':') +136 .append(loc.getBlockY()) +137 .append(':') +138 .append(loc.getBlockZ()) +139 .append(':') +140 .append(ACFUtil.precision(loc.getPitch(), 4)) +141 .append(':') +142 .append(ACFUtil.precision(loc.getYaw(), 4)) +143 .toString(); +144 } +145 +146 public static String blockLocationToString(Location loc) { +147 if (loc == null) { +148 return null; +149 } +150 +151 return (new StringBuilder(32)) +152 .append(loc.getWorld().getName()) +153 .append(':') +154 .append(loc.getBlockX()) +155 .append(':') +156 .append(loc.getBlockY()) +157 .append(':') +158 .append(loc.getBlockZ()) +159 .toString(); +160 } +161 +162 public static double distance(@NotNull Entity e1, @NotNull Entity e2) { +163 return distance(e1.getLocation(), e2.getLocation()); +164 } +165 public static double distance2d(@NotNull Entity e1, @NotNull Entity e2) { +166 return distance2d(e1.getLocation(), e2.getLocation()); +167 } +168 public static double distance2d(@NotNull Location loc1, @NotNull Location loc2) { +169 loc1 = loc1.clone(); +170 loc1.setY(loc2.getY()); +171 return distance(loc1, loc2); +172 } +173 public static double distance(@NotNull Location loc1, @NotNull Location loc2) { +174 if (loc1.getWorld() != loc2.getWorld()) { +175 return 0; +176 } +177 return loc1.distance(loc2); +178 } +179 +180 public static Location getTargetLoc(Player player) { +181 return getTargetLoc(player, 128); +182 } +183 public static Location getTargetLoc(Player player, int maxDist) { +184 return getTargetLoc(player, maxDist, 1.5); +185 } +186 public static Location getTargetLoc(Player player, int maxDist, double addY) { +187 try { +188 Location target = player.getTargetBlock((Set<Material>) null, maxDist).getLocation(); +189 target.setY(target.getY() + addY); +190 return target; +191 } catch (Exception ignored) { +192 return null; +193 } +194 } +195 +196 public static Location getRandLoc(Location loc, int radius) { +197 return getRandLoc(loc, radius, radius, radius); +198 } +199 public static Location getRandLoc(Location loc, int xzRadius, int yRadius) { +200 return getRandLoc(loc, xzRadius, yRadius, xzRadius); +201 } +202 @NotNull public static Location getRandLoc(Location loc, int xRadius, int yRadius, int zRadius) { +203 Location newLoc = loc.clone(); +204 newLoc.setX(ACFUtil.rand(loc.getX()-xRadius, loc.getX()+xRadius)); +205 newLoc.setY(ACFUtil.rand(loc.getY()-yRadius, loc.getY()+yRadius)); +206 newLoc.setZ(ACFUtil.rand(loc.getZ()-zRadius, loc.getZ()+zRadius)); +207 return newLoc; +208 } +209 210 -211 -212 public static String removeColors(String msg) { -213 return ChatColor.stripColor(color(msg)); -214 } -215 -216 public static String replaceChatString(String message, String replace, String with) { -217 return replaceChatString(message, Pattern.compile(Pattern.quote(replace), Pattern.CASE_INSENSITIVE), with); -218 } -219 public static String replaceChatString(String message, Pattern replace, String with) { -220 final String[] split = replace.split(message + "1"); -221 -222 if (split.length < 2) { -223 return replace.matcher(message).replaceAll(with); -224 } -225 message = split[0]; -226 -227 for (int i = 1; i < split.length; i++) { -228 final String prev = ChatColor.getLastColors(message); -229 message += with + prev + split[i]; -230 } -231 return message.substring(0, message.length() - 1); -232 } -233 -234 public static boolean isWithinDistance(@NotNull Player p1, @NotNull Player p2, int dist) { -235 return isWithinDistance(p1.getLocation(), p2.getLocation(), dist); -236 } -237 public static boolean isWithinDistance(@NotNull Location loc1, @NotNull Location loc2, int dist) { -238 return loc1.getWorld() == loc2.getWorld() && loc1.distance(loc2) <= dist; -239 } -240 -241 /** -242 * Please move to the CommandIssuer version -243 * @deprecated -244 */ -245 public static Player findPlayerSmart(CommandSender requester, String search) { -246 CommandManager manager = CommandManager.getCurrentCommandManager(); -247 if (manager != null) { -248 return findPlayerSmart(manager.getCommandIssuer(requester), search); -249 } -250 throw new IllegalStateException("You may not use the ACFBukkitUtil#findPlayerSmart(CommandSender) async to the command execution."); -251 } -252 -253 public static Player findPlayerSmart(CommandIssuer issuer, String search) { -254 CommandSender requester = issuer.getIssuer(); -255 if (search == null) { -256 return null; -257 } -258 String name = ACFUtil.replace(search, ":confirm", ""); -259 -260 if (!isValidName(name)) { -261 issuer.sendError(MinecraftMessageKeys.IS_NOT_A_VALID_NAME, "{name}", name); -262 return null; -263 } -264 -265 List<Player> matches = Bukkit.getServer().matchPlayer(name); -266 List<Player> confirmList = new ArrayList<>(); -267 findMatches(search, requester, matches, confirmList); +211 public static String removeColors(String msg) { +212 return ChatColor.stripColor(color(msg)); +213 } +214 +215 public static String replaceChatString(String message, String replace, String with) { +216 return replaceChatString(message, Pattern.compile(Pattern.quote(replace), Pattern.CASE_INSENSITIVE), with); +217 } +218 public static String replaceChatString(String message, Pattern replace, String with) { +219 final String[] split = replace.split(message + "1"); +220 +221 if (split.length < 2) { +222 return replace.matcher(message).replaceAll(with); +223 } +224 message = split[0]; +225 +226 for (int i = 1; i < split.length; i++) { +227 final String prev = ChatColor.getLastColors(message); +228 message += with + prev + split[i]; +229 } +230 return message.substring(0, message.length() - 1); +231 } +232 +233 public static boolean isWithinDistance(@NotNull Player p1, @NotNull Player p2, int dist) { +234 return isWithinDistance(p1.getLocation(), p2.getLocation(), dist); +235 } +236 public static boolean isWithinDistance(@NotNull Location loc1, @NotNull Location loc2, int dist) { +237 return loc1.getWorld() == loc2.getWorld() && loc1.distance(loc2) <= dist; +238 } +239 +240 /** +241 * Please move to the CommandIssuer version +242 * @deprecated +243 */ +244 public static Player findPlayerSmart(CommandSender requester, String search) { +245 CommandManager manager = CommandManager.getCurrentCommandManager(); +246 if (manager != null) { +247 return findPlayerSmart(manager.getCommandIssuer(requester), search); +248 } +249 throw new IllegalStateException("You may not use the ACFBukkitUtil#findPlayerSmart(CommandSender) async to the command execution."); +250 } +251 +252 public static Player findPlayerSmart(CommandIssuer issuer, String search) { +253 CommandSender requester = issuer.getIssuer(); +254 if (search == null) { +255 return null; +256 } +257 String name = ACFUtil.replace(search, ":confirm", ""); +258 +259 if (!isValidName(name)) { +260 issuer.sendError(MinecraftMessageKeys.IS_NOT_A_VALID_NAME, "{name}", name); +261 return null; +262 } +263 +264 List<Player> matches = Bukkit.getServer().matchPlayer(name); +265 List<Player> confirmList = new ArrayList<>(); +266 findMatches(search, requester, matches, confirmList); +267 268 -269 -270 if (matches.size() > 1 || confirmList.size() > 1) { -271 String allMatches = matches.stream().map(Player::getName).collect(Collectors.joining(", ")); -272 issuer.sendError(MinecraftMessageKeys.MULTIPLE_PLAYERS_MATCH, -273 "{search}", name, "{all}", allMatches); -274 return null; -275 } -276 -277 //noinspection Duplicates -278 if (matches.isEmpty()) { -279 if (confirmList.isEmpty()) { -280 issuer.sendError(MinecraftMessageKeys.NO_PLAYER_FOUND_SERVER, -281 "{search}", name); -282 return null; -283 } else { -284 Player player = Iterables.getOnlyElement(confirmList); -285 issuer.sendInfo(MinecraftMessageKeys.PLAYER_IS_VANISHED_CONFIRM, "{vanished}", player.getName()); -286 return null; -287 } -288 } -289 -290 return matches.get(0); -291 } -292 -293 private static void findMatches(String search, CommandSender requester, List<Player> matches, List<Player> confirmList) { -294 // Remove vanished players from smart matching. -295 Iterator<Player> iter = matches.iterator(); -296 //noinspection Duplicates -297 while (iter.hasNext()) { -298 Player player = iter.next(); -299 if (requester instanceof Player && !((Player) requester).canSee(player)) { -300 if (requester.hasPermission("acf.seevanish")) { -301 if (!search.endsWith(":confirm")) { -302 confirmList.add(player); -303 iter.remove(); -304 } -305 } else { -306 iter.remove(); -307 } -308 } -309 } -310 } +269 if (matches.size() > 1 || confirmList.size() > 1) { +270 String allMatches = matches.stream().map(Player::getName).collect(Collectors.joining(", ")); +271 issuer.sendError(MinecraftMessageKeys.MULTIPLE_PLAYERS_MATCH, +272 "{search}", name, "{all}", allMatches); +273 return null; +274 } +275 +276 //noinspection Duplicates +277 if (matches.isEmpty()) { +278 if (confirmList.isEmpty()) { +279 issuer.sendError(MinecraftMessageKeys.NO_PLAYER_FOUND_SERVER, +280 "{search}", name); +281 return null; +282 } else { +283 Player player = ACFUtil.getFirstElement(confirmList); +284 issuer.sendInfo(MinecraftMessageKeys.PLAYER_IS_VANISHED_CONFIRM, "{vanished}", player.getName()); +285 return null; +286 } +287 } +288 +289 return matches.get(0); +290 } +291 +292 private static void findMatches(String search, CommandSender requester, List<Player> matches, List<Player> confirmList) { +293 // Remove vanished players from smart matching. +294 Iterator<Player> iter = matches.iterator(); +295 //noinspection Duplicates +296 while (iter.hasNext()) { +297 Player player = iter.next(); +298 if (requester instanceof Player && !((Player) requester).canSee(player)) { +299 if (requester.hasPermission("acf.seevanish")) { +300 if (!search.endsWith(":confirm")) { +301 confirmList.add(player); +302 iter.remove(); +303 } +304 } else { +305 iter.remove(); +306 } +307 } +308 } +309 } +310 311 -312 -313 public static boolean isValidName(String name) { -314 return name != null && !name.isEmpty() && ACFPatterns.VALID_NAME_PATTERN.matcher(name).matches(); -315 } -316 -317 static boolean isValidItem(ItemStack item) { -318 return item != null && item.getType() != Material.AIR && item.getAmount() > 0; -319 } -320} +312 public static boolean isValidName(String name) { +313 return name != null && !name.isEmpty() && ACFPatterns.VALID_NAME_PATTERN.matcher(name).matches(); +314 } +315 +316 static boolean isValidItem(ItemStack item) { +317 return item != null && item.getType() != Material.AIR && item.getAmount() > 0; +318 } +319} diff --git a/docs/acf-core/co/aikar/commands/ACFUtil.html b/docs/acf-core/co/aikar/commands/ACFUtil.html index 15fc1016..23106290 100644 --- a/docs/acf-core/co/aikar/commands/ACFUtil.html +++ b/docs/acf-core/co/aikar/commands/ACFUtil.html @@ -18,7 +18,7 @@ catch(err) { } //--> -var methods = {"i0":9,"i1":9,"i2":9,"i3":9,"i4":9,"i5":9,"i6":9,"i7":9,"i8":9,"i9":9,"i10":9,"i11":9,"i12":9,"i13":9,"i14":9,"i15":9,"i16":9,"i17":9,"i18":9,"i19":9,"i20":9,"i21":9,"i22":9,"i23":9,"i24":9,"i25":9,"i26":9,"i27":9,"i28":9,"i29":9,"i30":9,"i31":9,"i32":9,"i33":9,"i34":9,"i35":9,"i36":9,"i37":9,"i38":9,"i39":9,"i40":9,"i41":9,"i42":9,"i43":9,"i44":9,"i45":9,"i46":9,"i47":9,"i48":9,"i49":9,"i50":41,"i51":9,"i52":9,"i53":9,"i54":9,"i55":9,"i56":9,"i57":9,"i58":9,"i59":9,"i60":9,"i61":9,"i62":9,"i63":9,"i64":9,"i65":9,"i66":9,"i67":9}; +var methods = {"i0":9,"i1":9,"i2":9,"i3":9,"i4":9,"i5":9,"i6":9,"i7":9,"i8":9,"i9":9,"i10":9,"i11":9,"i12":9,"i13":9,"i14":9,"i15":9,"i16":9,"i17":9,"i18":9,"i19":9,"i20":9,"i21":9,"i22":9,"i23":9,"i24":9,"i25":9,"i26":9,"i27":9,"i28":9,"i29":9,"i30":9,"i31":9,"i32":9,"i33":9,"i34":9,"i35":9,"i36":9,"i37":9,"i38":9,"i39":9,"i40":9,"i41":9,"i42":9,"i43":9,"i44":9,"i45":9,"i46":9,"i47":9,"i48":9,"i49":9,"i50":9,"i51":41,"i52":9,"i53":9,"i54":9,"i55":9,"i56":9,"i57":9,"i58":9,"i59":9,"i60":9,"i61":9,"i62":9,"i63":9,"i64":9,"i65":9,"i66":9,"i67":9,"i68":9}; var tabs = {65535:["t0","All Methods"],1:["t1","Static Methods"],8:["t4","Concrete Methods"],32:["t6","Deprecated Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -108,7 +108,7 @@ var activeTableTab = "activeTableTab"; findPlayerSmart
-public static org.bukkit.entity.Player findPlayerSmart(org.bukkit.command.CommandSender requester, +public static org.bukkit.entity.Player findPlayerSmart(org.bukkit.command.CommandSender requester, String search)Deprecated.Please move to the CommandIssuer version@@ -581,7 +581,7 @@ public static @NotNull org.bukkit.Location@@ -591,7 +591,7 @@ public static @NotNull org.bukkit.Location findPlayerSmart
-public static org.bukkit.entity.Player findPlayerSmart(co.aikar.commands.CommandIssuer issuer, +public static org.bukkit.entity.Player findPlayerSmart(co.aikar.commands.CommandIssuer issuer, String search)isValidName
-public static boolean isValidName(String name)+public static boolean isValidName(String name)@@ -199,179 +199,183 @@ extends +
-public final class ACFUtil +public final class ACFUtil extends Object+ static <T> T+ + getFirstElement(Iterable<T> iterable)- static <T> booleanhasIntersection(Collection<T> list1, Collection<T> list2)+ - static intindexOf(String arg, String[] split)+ - static <T> Collection<T>intersection(Collection<T> list1, Collection<T> list2)+ - static StringintToRoman(int integer)+ - static booleanisBetween(float num, double min, double max)+ - static booleanisDouble(String string)+ - static booleanisFloat(String string)+ - static booleanisInteger(String string)+ - static booleanisNumber(String str)+ - static booleanisTruthy(String test)+ - static Stringjoin(Collection<String> args)+ - static Stringjoin(Collection<String> args, String sep)+ - static Stringjoin(String[] args)+ - static Stringjoin(String[] args, char sep)+ - static Stringjoin(String[] args, int index)+ - static Stringjoin(String[] args, int index, char sep)+ - static Stringjoin(String[] args, String sep)+ - static Stringlimit(String str, int limit)+ - static Stringltrim(String s)+ - static Stringnormalize(String s)+ - static <T> TnullDefault(Object val, Object def)+ - static StringpadLeft(String s, int n)+ - static StringpadRight(String s, int n)+ - static BigDecimalparseBigNumber(String num, boolean suffixes)+ - static DoubleparseDouble(String var)+ - static DoubleparseDouble(String var, Double def)+ - static FloatparseFloat(String var)+ - static FloatparseFloat(String var, Float def)+ - static IntegerparseInt(String var)+ - static IntegerparseInt(String var, Integer def)+ - static LongparseLong(String var)+ - static LongparseLong(String var, Long def)+ - static NumberparseNumber(String num, boolean suffixes)+ - static doubleprecision(double x, int p)+ - static <T> List<T>preformOnImmutable(List<T> list, Consumer<List<T>> action)+ - static doublerand(double min, double max)+ - static intrand(int min, int max)+ static intrand(int min1, int max1, @@ -381,25 +385,25 @@ extends +- static booleanrandBool()+ - static <T extends Enum<?>>
Trandom(Class<? extends T> enm)Deprecated.+ - static <T> Trandom(List<T> arr)+ - static <T> Trandom(T[] arr)+ - static Stringreplace(String string, Pattern pattern, @@ -407,7 +411,7 @@ extends Plain string replacement, escapes replace value.+ - static Stringreplace(String string, String pattern, @@ -415,7 +419,7 @@ extends Plain String replacement.+ - static StringreplacePattern(String string, Pattern pattern, @@ -423,7 +427,7 @@ extends Regex version ofreplace(String, Pattern, String)+ - static StringreplacePattern(String string, String pattern, @@ -431,7 +435,7 @@ extends Regex version ofreplace(String, String, String)+ - static StringreplacePatternMatch(String string, Pattern pattern, @@ -439,7 +443,7 @@ extends Pure Regex Pattern matching and replacement, no escaping+ - static StringreplacePatternMatch(String string, String pattern, @@ -447,44 +451,44 @@ extends Pure Regex Pattern matching and replacement, no escaping+ - static StringreplacePatterns(String string, String... replacements)+ - static StringreplaceStrings(String string, String... replacements)+ - static doubleround(double x, int scale)+ - static introundUp(int num, int multiple)+ - static Stringrtrim(String s)+ - static <E extends Enum<E>>
EsimpleMatch(Class<? extends Enum<?>> list, String item)+ - static StringsimplifyString(String str)+ - static voidsneaky(Throwable t)+ @@ -516,7 +520,7 @@ extends static Stringucfirst(String str)@@ -533,7 +537,7 @@ extends RANDOM
-public static final Random RANDOM+public static final Random RANDOM@@ -543,7 +547,7 @@ extends padRight
-public static String padRight(String s, +public static String padRight(String s, int n)@@ -553,7 +557,7 @@ extends padLeft
-public static String padLeft(String s, +public static String padLeft(String s, int n)@@ -564,7 +568,7 @@ extends formatNumber
-public static String formatNumber(Integer balance)+public static String formatNumber(Integer balance)@@ -576,7 +580,7 @@ extends getEnumFromName
-public static <T extends Enum> T getEnumFromName(T[] types, +public static <T extends Enum> T getEnumFromName(T[] types, String name)@@ -589,7 +593,7 @@ extends getEnumFromName
-public static <T extends Enum> T getEnumFromName(T[] types, +public static <T extends Enum> T getEnumFromName(T[] types, String name, T def)@@ -599,7 +603,7 @@ extends getEnumFromOrdinal
-public static <T extends Enum> T getEnumFromOrdinal(T[] types, +public static <T extends Enum> T getEnumFromOrdinal(T[] types, int ordinal)@@ -608,7 +612,7 @@ extends ucfirst
-public static String ucfirst(String str)+public static String ucfirst(String str)@@ -617,7 +621,7 @@ extends parseDouble
-public static Double parseDouble(String var)+public static Double parseDouble(String var)@@ -627,7 +631,7 @@ extends parseDouble
-public static Double parseDouble(String var, +public static Double parseDouble(String var, Double def)@@ -636,7 +640,7 @@ extends parseFloat
-public static Float parseFloat(String var)+public static Float parseFloat(String var)@@ -646,7 +650,7 @@ extends parseFloat
-public static Float parseFloat(String var, +public static Float parseFloat(String var, Float def)@@ -655,7 +659,7 @@ extends parseLong
-public static Long parseLong(String var)+public static Long parseLong(String var)@@ -665,7 +669,7 @@ extends parseLong
-public static Long parseLong(String var, +public static Long parseLong(String var, Long def)@@ -674,7 +678,7 @@ extends parseInt
-public static Integer parseInt(String var)+public static Integer parseInt(String var)@@ -684,7 +688,7 @@ extends parseInt
-public static Integer parseInt(String var, +public static Integer parseInt(String var, Integer def)@@ -693,7 +697,7 @@ extends randBool
-public static boolean randBool()+public static boolean randBool()@@ -703,7 +707,7 @@ extends nullDefault
-public static <T> T nullDefault(Object val, +public static <T> T nullDefault(Object val, Object def)@@ -712,7 +716,7 @@ extends join
-public static String join(Collection<String> args)+public static String join(Collection<String> args)@@ -722,7 +726,7 @@ extends join
-public static String join(Collection<String> args, +public static String join(Collection<String> args, String sep)@@ -731,7 +735,7 @@ extends join
-public static String join(String[] args)+public static String join(String[] args)@@ -741,7 +745,7 @@ extends join
-public static String join(String[] args, +public static String join(String[] args, String sep)@@ -751,7 +755,7 @@ extends join
-public static String join(String[] args, +public static String join(String[] args, char sep)@@ -761,7 +765,7 @@ extends join
-public static String join(String[] args, +public static String join(String[] args, int index)@@ -772,7 +776,7 @@ extends join
-public static String join(String[] args, +public static String join(String[] args, int index, char sep)@@ -781,7 +785,7 @@ extends simplifyString
-public static String simplifyString(String str)+public static String simplifyString(String str)@@ -791,7 +795,7 @@ extends round
-public static double round(double x, +public static double round(double x, int scale)@@ -801,7 +805,7 @@ extends roundUp
-public static int roundUp(int num, +public static int roundUp(int num, int multiple)@@ -811,7 +815,7 @@ extends limit
-public static String limit(String str, +public static String limit(String str, int limit)replace
-public static String replace(String string, +public static String replace(String string, Pattern pattern, String repl)Plain string replacement, escapes replace value.@@ -830,7 +834,7 @@ extendsreplacePattern
-public static String replacePattern(String string, +public static String replacePattern(String string, Pattern pattern, String repl)Regex version of@@ -849,7 +853,7 @@ extendsreplace(String, Pattern, String)replace
-public static String replace(String string, +public static String replace(String string, String pattern, String repl)Plain String replacement. If you need regex patterns, see@@ -868,7 +872,7 @@ extendsreplacePattern(String, String, String)replacePattern
-public static String replacePattern(String string, +public static String replacePattern(String string, String pattern, String repl)Regex version of@@ -887,7 +891,7 @@ extendsreplace(String, String, String)diff --git a/docs/acf-core/co/aikar/commands/BaseCommand.html b/docs/acf-core/co/aikar/commands/BaseCommand.html index b59aab72..6d419e28 100644 --- a/docs/acf-core/co/aikar/commands/BaseCommand.html +++ b/docs/acf-core/co/aikar/commands/BaseCommand.html @@ -112,7 +112,7 @@ var activeTableTab = "activeTableTab"; replacePatternMatch
-public static String replacePatternMatch(String string, +public static String replacePatternMatch(String string, Pattern pattern, String repl)Pure Regex Pattern matching and replacement, no escaping@@ -906,7 +910,7 @@ extends@@ -1099,7 +1103,7 @@ public static <E extends replacePatternMatch
-public static String replacePatternMatch(String string, +public static String replacePatternMatch(String string, String pattern, String repl)Pure Regex Pattern matching and replacement, no escaping@@ -925,7 +929,7 @@ extends@@ -935,7 +939,7 @@ extends replaceStrings
-public static String replaceStrings(String string, +public static String replaceStrings(String string, String... replacements)@@ -945,7 +949,7 @@ extends replacePatterns
-public static String replacePatterns(String string, +public static String replacePatterns(String string, String... replacements)@@ -955,7 +959,7 @@ extends capitalize
-public static String capitalize(String str, +public static String capitalize(String str, char[] delimiters)@@ -966,7 +970,7 @@ extends random
-public static <T> T random(List<T> arr)+public static <T> T random(List<T> arr)@@ -976,7 +980,7 @@ extends random
-public static <T> T random(T[] arr)+public static <T> T random(T[] arr)random
@Deprecated -public static <T extends Enum<?>> T random(Class<? extends T> enm)+public static <T extends Enum<?>> T random(Class<? extends T> enm)Deprecated.Added as im sure we will try to "Find this" again. This is no different than Enum.values() passed to above method logically but the array version is slightly faster.@@ -995,7 +999,7 @@ public static <T extends@@ -1004,7 +1008,7 @@ public static <T extends normalize
-public static String normalize(String s)+public static String normalize(String s)@@ -1014,7 +1018,7 @@ public static <T extends indexOf
-public static int indexOf(String arg, +public static int indexOf(String arg, String[] split)@@ -1023,7 +1027,7 @@ public static <T extends capitalizeFirst
-public static String capitalizeFirst(String name)+public static String capitalizeFirst(String name)@@ -1033,7 +1037,7 @@ public static <T extends capitalizeFirst
-public static String capitalizeFirst(String name, +public static String capitalizeFirst(String name, char separator)@@ -1042,7 +1046,7 @@ public static <T extends ltrim
-public static String ltrim(String s)+public static String ltrim(String s)@@ -1051,7 +1055,7 @@ public static <T extends rtrim
-public static String rtrim(String s)+public static String rtrim(String s)@@ -1060,7 +1064,7 @@ public static <T extends enumNames
-public static List<String> enumNames(Enum<?>[] values)+public static List<String> enumNames(Enum<?>[] values)@@ -1069,7 +1073,7 @@ public static <T extends enumNames
-public static List<String> enumNames(Class<? extends Enum<?>> cls)+public static List<String> enumNames(Class<? extends Enum<?>> cls)@@ -1078,7 +1082,7 @@ public static <T extends combine
-public static String combine(String[] args)+public static String combine(String[] args)@@ -1089,7 +1093,7 @@ public static <T extends combine
-public static String combine(String[] args, +public static String combine(String[] args, int start)simpleMatch
@Nullable -public static <E extends Enum<E>> E simpleMatch(Class<? extends Enum<?>> list, +public static <E extends Enum<E>> E simpleMatch(Class<? extends Enum<?>> list, String item)@@ -1108,7 +1112,7 @@ public static <E extends isTruthy
-public static boolean isTruthy(String test)+public static boolean isTruthy(String test)@@ -1118,7 +1122,7 @@ public static <E extends parseNumber
-public static Number parseNumber(String num, +public static Number parseNumber(String num, boolean suffixes)@@ -1128,7 +1132,7 @@ public static <E extends parseBigNumber
-public static BigDecimal parseBigNumber(String num, +public static BigDecimal parseBigNumber(String num, boolean suffixes)@@ -1138,7 +1142,7 @@ public static <E extends hasIntersection
-public static <T> boolean hasIntersection(Collection<T> list1, +public static <T> boolean hasIntersection(Collection<T> list1, Collection<T> list2)@@ -1148,7 +1152,7 @@ public static <E extends intersection
-public static <T> Collection<T> intersection(Collection<T> list1, +public static <T> Collection<T> intersection(Collection<T> list1, Collection<T> list2)@@ -1158,7 +1162,7 @@ public static <E extends rand
-public static int rand(int min, +public static int rand(int min, int max)rand
-public static int rand(int min1, +public static int rand(int min1, int max1, int min2, int max2)@@ -1180,7 +1184,7 @@ public static <E extends@@ -1190,7 +1194,7 @@ public static <E extends rand
-public static double rand(double min, +public static double rand(double min, double max)@@ -1199,7 +1203,7 @@ public static <E extends isNumber
-public static boolean isNumber(String str)+public static boolean isNumber(String str)@@ -1208,7 +1212,7 @@ public static <E extends intToRoman
-public static String intToRoman(int integer)+public static String intToRoman(int integer)@@ -1217,7 +1221,7 @@ public static <E extends isInteger
-public static boolean isInteger(String string)+public static boolean isInteger(String string)@@ -1226,7 +1230,7 @@ public static <E extends isFloat
-public static boolean isFloat(String string)+public static boolean isFloat(String string)@@ -1235,7 +1239,7 @@ public static <E extends isDouble
-public static boolean isDouble(String string)+public static boolean isDouble(String string)@@ -1246,7 +1250,7 @@ public static <E extends isBetween
-public static boolean isBetween(float num, +public static boolean isBetween(float num, double min, double max)@@ -1256,19 +1260,28 @@ public static <E extends precision
-public static double precision(double x, +public static double precision(double x, int p)- sneaky
-public static void sneaky(Throwable t)+public static void sneaky(Throwable t)+
+ + + +
preformOnImmutable
-public static <T> List<T> preformOnImmutable(List<T> list, +public static <T> List<T> preformOnImmutable(List<T> list, Consumer<List<T>> action)+
- +
+getFirstElement
+public static <T> T getFirstElement(Iterable<T> iterable)+
-public abstract class BaseCommand +public abstract class BaseCommand extends ObjectA Base command is defined as a command group of related commands. A BaseCommand does not imply nor enforce that they use the same root command. @@ -336,7 +336,7 @@ extends@@ -346,7 +346,7 @@ extends BaseCommand
-public BaseCommand()+public BaseCommand()BaseCommand
@Deprecated -public BaseCommand(@Nullable +public BaseCommand(@Nullable @Nullable String cmd)Deprecated. Please switch toCommandAliasfor defining all root commands.Constructor based defining of commands will be removed in the next version bump.@@ -370,7 +370,7 @@ publicgetExecCommandLabel
-public String getExecCommandLabel()+public String getExecCommandLabel()Gets the root command name that the user actually typed
- Returns:
@@ -384,7 +384,7 @@ public- diff --git a/docs/acf-sponge/src-html/co/aikar/commands/ACFSpongeUtil.html b/docs/acf-sponge/src-html/co/aikar/commands/ACFSpongeUtil.html index 300a183c..3ca3c637 100644 --- a/docs/acf-sponge/src-html/co/aikar/commands/ACFSpongeUtil.html +++ b/docs/acf-sponge/src-html/co/aikar/commands/ACFSpongeUtil.html @@ -8,105 +8,104 @@
getExecSubcommand
-public String getExecSubcommand()+public String getExecSubcommand()Gets the actual sub command name the user typed
- Returns:
@@ -398,7 +398,7 @@ public- @@ -203,7 +203,7 @@ extends
getOrigArgs
-public String[] getOrigArgs()+public String[] getOrigArgs()Gets the actual args in string form the user typed
- Returns:
@@ -412,7 +412,7 @@ public- @@ -423,7 +423,7 @@ public
execute
-public void execute(CommandIssuer issuer, +public void execute(CommandIssuer issuer, String commandLabel, String[] args)getCurrentCommandIssuer
-public CommandIssuer getCurrentCommandIssuer()+public CommandIssuer getCurrentCommandIssuer()Gets the current command issuer.
- Returns:
@@ -437,7 +437,7 @@ public- diff --git a/docs/acf-core/index-all.html b/docs/acf-core/index-all.html index 79aa5c8f..c040d682 100644 --- a/docs/acf-core/index-all.html +++ b/docs/acf-core/index-all.html @@ -678,6 +678,8 @@
getCurrentCommandManager
-public CommandManager getCurrentCommandManager()+public CommandManager getCurrentCommandManager()Gets the current command manager.
- Returns:
@@ -452,7 +452,7 @@ publiccanExecute
@Deprecated -public boolean canExecute(CommandIssuer issuer, +public boolean canExecute(CommandIssuer issuer, RegisteredCommand<?> cmd)Deprecated. SeeCommandConditionsPlease use command conditions for restricting execution@@ -470,7 +470,7 @@ public boolean- @@ -538,7 +538,7 @@ public void
tabComplete
-public List<String> tabComplete(CommandIssuer issuer, +public List<String> tabComplete(CommandIssuer issuer, String commandLabel, String[] args)Gets tab completed data from the given command from the user.@@ -490,7 +490,7 @@ public boolean- @@ -528,7 +528,7 @@ public
tabComplete
-public List<String> tabComplete(CommandIssuer issuer, +public List<String> tabComplete(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) @@ -517,7 +517,7 @@ public booleangetCommandHelp
@Deprecated -public CommandHelp getCommandHelp()+public CommandHelp getCommandHelp()Deprecated. Unstable APIshowCommandHelp
@Deprecated -public void showCommandHelp()+public void showCommandHelp()Deprecated. Unstable API- @@ -548,7 +548,7 @@ public void
help
-public void help(Object issuer, +public void help(Object issuer, String[] args)- @@ -558,7 +558,7 @@ public void
help
-public void help(CommandIssuer issuer, +public void help(CommandIssuer issuer, String[] args)- @@ -568,7 +568,7 @@ public void
doHelp
-public void doHelp(Object issuer, +public void doHelp(Object issuer, String... args)- @@ -578,7 +578,7 @@ public void
doHelp
-public void doHelp(CommandIssuer issuer, +public void doHelp(CommandIssuer issuer, String... args)- @@ -588,7 +588,7 @@ public void
showSyntax
-public void showSyntax(CommandIssuer issuer, +public void showSyntax(CommandIssuer issuer, RegisteredCommand<?> cmd)- @@ -597,7 +597,7 @@ public void
hasPermission
-public boolean hasPermission(Object issuer)+public boolean hasPermission(Object issuer)- @@ -606,7 +606,7 @@ public void
hasPermission
-public boolean hasPermission(CommandIssuer issuer)+public boolean hasPermission(CommandIssuer issuer)- @@ -615,7 +615,7 @@ public void
getRequiredPermissions
-public Set<String> getRequiredPermissions()+public Set<String> getRequiredPermissions()- @@ -624,7 +624,7 @@ public void
requiresPermission
-public boolean requiresPermission(String permission)+public boolean requiresPermission(String permission)- @@ -633,7 +633,7 @@ public void
getName
-public String getName()+public String getName()- @@ -642,7 +642,7 @@ public void
getExceptionHandler
-public ExceptionHandler getExceptionHandler()+public ExceptionHandler getExceptionHandler()- @@ -651,7 +651,7 @@ public void
setExceptionHandler
-public BaseCommand setExceptionHandler(ExceptionHandler exceptionHandler)+public BaseCommand setExceptionHandler(ExceptionHandler exceptionHandler)- @@ -660,7 +660,7 @@ public void
getDefaultRegisteredCommand
-public RegisteredCommand getDefaultRegisteredCommand()+public RegisteredCommand getDefaultRegisteredCommand()- @@ -670,7 +670,7 @@ public void
setContextFlags
-public String setContextFlags(Class<?> cls, +public String setContextFlags(Class<?> cls, String flags)getContextFlags
-public String getContextFlags(Class<?> cls)+public String getContextFlags(Class<?> cls)- getFirstArg() - Method in class co.aikar.commands.CommandExecutionContext
- +
- getFirstElement(Iterable<T>) - Static method in class co.aikar.commands.ACFUtil
+- getFlags() - Method in class co.aikar.commands.CommandExecutionContext
- getFlags() - Method in class co.aikar.commands.CommandParameter
diff --git a/docs/acf-core/src-html/co/aikar/commands/ACFUtil.html b/docs/acf-core/src-html/co/aikar/commands/ACFUtil.html index e62243b8..baea72e9 100644 --- a/docs/acf-core/src-html/co/aikar/commands/ACFUtil.html +++ b/docs/acf-core/src-html/co/aikar/commands/ACFUtil.html @@ -41,598 +41,609 @@ 033import java.text.NumberFormat; 034import java.util.ArrayList; 035import java.util.Collection; -036import java.util.List; -037import java.util.Random; -038import java.util.function.Consumer; -039import java.util.regex.Matcher; -040import java.util.regex.Pattern; -041import java.util.stream.Collectors; -042import java.util.stream.Stream; -043 -044@SuppressWarnings({"WeakerAccess", "unused"}) -045public final class ACFUtil { -046 -047 public static final Random RANDOM = new Random(); -048 -049 private ACFUtil() {} -050 -051 public static String padRight(String s, int n) { -052 return String.format("%1$-" + n + "s", s); -053 } -054 -055 public static String padLeft(String s, int n) { -056 return String.format("%1$" + n + "s", s); -057 } -058 -059 public static String formatNumber(Integer balance) { -060 return NumberFormat.getInstance().format(balance); -061 } -062 -063 public static <T extends Enum> T getEnumFromName(T[] types, String name) { -064 return getEnumFromName(types, name, null); -065 } -066 public static <T extends Enum> T getEnumFromName(T[] types, String name, T def) { -067 for (T type : types) { -068 if (type.name().equalsIgnoreCase(name)) { -069 return type; -070 } -071 } -072 return def; -073 } -074 public static <T extends Enum> T getEnumFromOrdinal(T[] types, int ordinal) { -075 for (T type : types) { -076 if (type.ordinal() == ordinal) { -077 return type; -078 } -079 } -080 return null; -081 } -082 -083 public static String ucfirst(String str) { -084 return ApacheCommonsLangUtil.capitalizeFully(str); -085 } -086 -087 public static Double parseDouble(String var) { -088 return parseDouble(var, null); -089 } -090 -091 public static Double parseDouble(String var, Double def) { -092 if (var == null) { -093 return def; -094 } -095 try { -096 return Double.parseDouble(var); -097 } catch (NumberFormatException ignored) {} -098 return def; -099 } -100 -101 public static Float parseFloat(String var) { -102 return parseFloat(var, null); -103 } -104 public static Float parseFloat(String var, Float def) { -105 if (var == null) { -106 return def; -107 } -108 try { -109 return Float.parseFloat(var); -110 } catch (NumberFormatException ignored) {} -111 return def; -112 } -113 public static Long parseLong(String var) { -114 return parseLong(var, null); -115 } -116 public static Long parseLong(String var, Long def) { -117 if (var == null) { -118 return def; -119 } -120 try { -121 return Long.parseLong(var); -122 } catch (NumberFormatException ignored) {} -123 return def; -124 } -125 -126 public static Integer parseInt(String var) { -127 return parseInt(var, null); -128 } -129 public static Integer parseInt(String var, Integer def) { -130 if (var == null) { -131 return def; -132 } -133 try { -134 return Integer.parseInt(var); -135 } catch (NumberFormatException ignored) {} -136 return def; -137 } -138 -139 public static boolean randBool() { -140 return RANDOM.nextBoolean(); -141 } -142 -143 public static <T> T nullDefault(Object val, Object def) { -144 //noinspection unchecked -145 return (T) (val != null ? val : def); -146 } -147 -148 public static String join(Collection<String> args) { -149 return ApacheCommonsLangUtil.join(args, " "); -150 } -151 public static String join(Collection<String> args, String sep) { -152 return ApacheCommonsLangUtil.join(args, sep); -153 } -154 public static String join(String[] args) { -155 return join(args, 0, ' '); -156 } -157 -158 public static String join(String[] args, String sep) { -159 return ApacheCommonsLangUtil.join(args, sep); -160 } -161 public static String join(String[] args, char sep) { -162 return join(args, 0, sep); -163 } -164 -165 public static String join(String[] args, int index) { -166 return join(args, index, ' '); -167 } -168 -169 public static String join(String[] args, int index, char sep) { -170 return ApacheCommonsLangUtil.join(args, sep, index, args.length); -171 } -172 -173 public static String simplifyString(String str) { -174 if (str == null) { -175 return null; -176 } -177 return ACFPatterns.NON_ALPHA_NUMERIC.matcher(str.toLowerCase()).replaceAll(""); -178 } -179 -180 public static double round(double x, int scale) { -181 try { -182 return (new BigDecimal -183 (Double.toString(x)) -184 .setScale(scale, BigDecimal.ROUND_HALF_UP)) -185 .doubleValue(); -186 } catch (NumberFormatException ex) { -187 if (Double.isInfinite(x)) { -188 return x; -189 } else { -190 return Double.NaN; -191 } -192 } -193 } -194 public static int roundUp(int num, int multiple) { -195 if(multiple == 0) { -196 return num; -197 } -198 -199 int remainder = num % multiple; -200 if (remainder == 0) { -201 return num; -202 } -203 return num + multiple - remainder; -204 -205 } -206 -207 public static String limit(String str, int limit) { -208 return str.length() > limit ? str.substring(0, limit) : str; -209 } -210 -211 /** -212 * Plain string replacement, escapes replace value. -213 * @param string -214 * @param pattern -215 * @param repl -216 * @return -217 */ -218 public static String replace(String string, Pattern pattern, String repl) { -219 return pattern.matcher(string).replaceAll(Matcher.quoteReplacement(repl)); -220 } -221 -222 /** -223 * Regex version of {@link #replace(String, Pattern, String)} -224 * @param string -225 * @param pattern -226 * @param repl -227 * @return -228 */ -229 public static String replacePattern(String string, Pattern pattern, String repl) { -230 return pattern.matcher(string).replaceAll(repl); -231 } -232 -233 /** -234 * Plain String replacement. If you need regex patterns, see {@link #replacePattern(String, String, String)} -235 * @param string -236 * @param pattern -237 * @param repl -238 * @return -239 */ -240 public static String replace(String string, String pattern, String repl) { -241 return replace(string, ACFPatterns.getPattern(Pattern.quote(pattern)), repl); -242 } -243 -244 /** -245 * Regex version of {@link #replace(String, String, String)} -246 * @param string -247 * @param pattern -248 * @param repl -249 * @return -250 */ -251 public static String replacePattern(String string, String pattern, String repl) { -252 return replace(string, ACFPatterns.getPattern(pattern), repl); -253 } -254 /** -255 * Pure Regex Pattern matching and replacement, no escaping -256 * @param string -257 * @param pattern -258 * @param repl -259 * @return -260 */ -261 public static String replacePatternMatch(String string, Pattern pattern, String repl) { -262 return pattern.matcher(string).replaceAll(repl); -263 } -264 -265 /** -266 * Pure Regex Pattern matching and replacement, no escaping -267 * @param string -268 * @param pattern -269 * @param repl -270 * @return -271 */ -272 public static String replacePatternMatch(String string, String pattern, String repl) { -273 return replacePatternMatch(string, ACFPatterns.getPattern(pattern), repl); -274 } -275 -276 public static String replaceStrings(String string, String... replacements) { -277 if (replacements.length < 2 || replacements.length % 2 != 0) { -278 throw new IllegalArgumentException("Invalid Replacements"); -279 } -280 for (int i = 0; i < replacements.length; i += 2) { -281 String key = replacements[i]; -282 String value = replacements[i+1]; -283 if (value == null) value = ""; -284 string = replace(string, key, value); -285 } -286 return string; -287 } -288 public static String replacePatterns(String string, String... replacements) { -289 if (replacements.length < 2 || replacements.length % 2 != 0) { -290 throw new IllegalArgumentException("Invalid Replacements"); -291 } -292 for (int i = 0; i < replacements.length; i += 2) { -293 String key = replacements[i]; -294 String value = replacements[i+1]; -295 if (value == null) value = ""; -296 string = replacePattern(string, key, value); -297 } -298 return string; -299 } -300 -301 public static String capitalize(String str, char[] delimiters) { -302 return ApacheCommonsLangUtil.capitalize(str, delimiters); -303 } -304 private static boolean isDelimiter(char ch, char[] delimiters) { -305 return ApacheCommonsLangUtil.isDelimiter(ch, delimiters); -306 } -307 -308 public static <T> T random(List<T> arr) { -309 if (arr == null || arr.isEmpty()) { -310 return null; -311 } -312 return arr.get(RANDOM.nextInt(arr.size())); -313 } -314 public static <T> T random(T[] arr) { -315 if (arr == null || arr.length == 0) { -316 return null; -317 } -318 return arr[RANDOM.nextInt(arr.length)]; -319 } -320 -321 /** -322 * Added as im sure we will try to "Find this" again. This is no different than Enum.values() passed to above method logically -323 * but the array version is slightly faster. -324 * @param enm -325 * @param <T> -326 * @return -327 */ -328 @Deprecated -329 public static <T extends Enum<?>> T random(Class<? extends T> enm) { -330 return random(enm.getEnumConstants()); -331 } -332 -333 public static String normalize(String s) { -334 if (s == null) { -335 return null; -336 } -337 return ACFPatterns.NON_PRINTABLE_CHARACTERS.matcher(Normalizer.normalize(s, Form.NFD)).replaceAll(""); -338 } -339 -340 public static int indexOf(String arg, String[] split) { -341 for (int i = 0; i < split.length; i++) { -342 if (arg == null) { -343 if (split[i] == null) { -344 return i; -345 } -346 } else if (arg.equals(split[i])) { -347 return i; -348 } -349 } -350 return -1; -351 } -352 -353 public static String capitalizeFirst(String name) { -354 return capitalizeFirst(name, '_'); -355 } -356 -357 public static String capitalizeFirst(String name, char separator) { -358 name = name.toLowerCase(); -359 String[] split = name.split(Character.toString(separator)); -360 StringBuilder total = new StringBuilder(3); -361 for (String s : split) { -362 total.append(Character.toUpperCase(s.charAt(0))).append(s.substring(1)).append(' '); -363 } -364 -365 return total.toString().trim(); -366 } -367 -368 public static String ltrim(String s) { -369 int i = 0; -370 while (i < s.length() && Character.isWhitespace(s.charAt(i))) { -371 i++; -372 } -373 return s.substring(i); -374 } -375 -376 public static String rtrim(String s) { -377 int i = s.length()-1; -378 while (i >= 0 && Character.isWhitespace(s.charAt(i))) { -379 i--; -380 } -381 return s.substring(0,i+1); -382 } -383 -384 public static List<String> enumNames(Enum<?>[] values) { -385 return Stream.of(values).map(Enum::name).collect(Collectors.toList()); -386 } -387 -388 public static List<String> enumNames(Class<? extends Enum<?>> cls) { -389 return enumNames(cls.getEnumConstants()); -390 } -391 -392 public static String combine(String[] args) { -393 return combine(args, 0); -394 } -395 public static String combine(String[] args, int start) { -396 int size = 0; -397 for (int i = start; i < args.length; i++) { -398 size += args[i].length(); -399 } -400 StringBuilder sb = new StringBuilder(size); -401 for (int i = start; i < args.length; i++) { -402 sb.append(args[i]); -403 } -404 return sb.toString(); -405 } -406 +036import java.util.Iterator; +037import java.util.List; +038import java.util.Random; +039import java.util.function.Consumer; +040import java.util.regex.Matcher; +041import java.util.regex.Pattern; +042import java.util.stream.Collectors; +043import java.util.stream.Stream; +044 +045@SuppressWarnings({"WeakerAccess", "unused"}) +046public final class ACFUtil { +047 +048 public static final Random RANDOM = new Random(); +049 +050 private ACFUtil() {} +051 +052 public static String padRight(String s, int n) { +053 return String.format("%1$-" + n + "s", s); +054 } +055 +056 public static String padLeft(String s, int n) { +057 return String.format("%1$" + n + "s", s); +058 } +059 +060 public static String formatNumber(Integer balance) { +061 return NumberFormat.getInstance().format(balance); +062 } +063 +064 public static <T extends Enum> T getEnumFromName(T[] types, String name) { +065 return getEnumFromName(types, name, null); +066 } +067 public static <T extends Enum> T getEnumFromName(T[] types, String name, T def) { +068 for (T type : types) { +069 if (type.name().equalsIgnoreCase(name)) { +070 return type; +071 } +072 } +073 return def; +074 } +075 public static <T extends Enum> T getEnumFromOrdinal(T[] types, int ordinal) { +076 for (T type : types) { +077 if (type.ordinal() == ordinal) { +078 return type; +079 } +080 } +081 return null; +082 } +083 +084 public static String ucfirst(String str) { +085 return ApacheCommonsLangUtil.capitalizeFully(str); +086 } +087 +088 public static Double parseDouble(String var) { +089 return parseDouble(var, null); +090 } +091 +092 public static Double parseDouble(String var, Double def) { +093 if (var == null) { +094 return def; +095 } +096 try { +097 return Double.parseDouble(var); +098 } catch (NumberFormatException ignored) {} +099 return def; +100 } +101 +102 public static Float parseFloat(String var) { +103 return parseFloat(var, null); +104 } +105 public static Float parseFloat(String var, Float def) { +106 if (var == null) { +107 return def; +108 } +109 try { +110 return Float.parseFloat(var); +111 } catch (NumberFormatException ignored) {} +112 return def; +113 } +114 public static Long parseLong(String var) { +115 return parseLong(var, null); +116 } +117 public static Long parseLong(String var, Long def) { +118 if (var == null) { +119 return def; +120 } +121 try { +122 return Long.parseLong(var); +123 } catch (NumberFormatException ignored) {} +124 return def; +125 } +126 +127 public static Integer parseInt(String var) { +128 return parseInt(var, null); +129 } +130 public static Integer parseInt(String var, Integer def) { +131 if (var == null) { +132 return def; +133 } +134 try { +135 return Integer.parseInt(var); +136 } catch (NumberFormatException ignored) {} +137 return def; +138 } +139 +140 public static boolean randBool() { +141 return RANDOM.nextBoolean(); +142 } +143 +144 public static <T> T nullDefault(Object val, Object def) { +145 //noinspection unchecked +146 return (T) (val != null ? val : def); +147 } +148 +149 public static String join(Collection<String> args) { +150 return ApacheCommonsLangUtil.join(args, " "); +151 } +152 public static String join(Collection<String> args, String sep) { +153 return ApacheCommonsLangUtil.join(args, sep); +154 } +155 public static String join(String[] args) { +156 return join(args, 0, ' '); +157 } +158 +159 public static String join(String[] args, String sep) { +160 return ApacheCommonsLangUtil.join(args, sep); +161 } +162 public static String join(String[] args, char sep) { +163 return join(args, 0, sep); +164 } +165 +166 public static String join(String[] args, int index) { +167 return join(args, index, ' '); +168 } +169 +170 public static String join(String[] args, int index, char sep) { +171 return ApacheCommonsLangUtil.join(args, sep, index, args.length); +172 } +173 +174 public static String simplifyString(String str) { +175 if (str == null) { +176 return null; +177 } +178 return ACFPatterns.NON_ALPHA_NUMERIC.matcher(str.toLowerCase()).replaceAll(""); +179 } +180 +181 public static double round(double x, int scale) { +182 try { +183 return (new BigDecimal +184 (Double.toString(x)) +185 .setScale(scale, BigDecimal.ROUND_HALF_UP)) +186 .doubleValue(); +187 } catch (NumberFormatException ex) { +188 if (Double.isInfinite(x)) { +189 return x; +190 } else { +191 return Double.NaN; +192 } +193 } +194 } +195 public static int roundUp(int num, int multiple) { +196 if(multiple == 0) { +197 return num; +198 } +199 +200 int remainder = num % multiple; +201 if (remainder == 0) { +202 return num; +203 } +204 return num + multiple - remainder; +205 +206 } +207 +208 public static String limit(String str, int limit) { +209 return str.length() > limit ? str.substring(0, limit) : str; +210 } +211 +212 /** +213 * Plain string replacement, escapes replace value. +214 * @param string +215 * @param pattern +216 * @param repl +217 * @return +218 */ +219 public static String replace(String string, Pattern pattern, String repl) { +220 return pattern.matcher(string).replaceAll(Matcher.quoteReplacement(repl)); +221 } +222 +223 /** +224 * Regex version of {@link #replace(String, Pattern, String)} +225 * @param string +226 * @param pattern +227 * @param repl +228 * @return +229 */ +230 public static String replacePattern(String string, Pattern pattern, String repl) { +231 return pattern.matcher(string).replaceAll(repl); +232 } +233 +234 /** +235 * Plain String replacement. If you need regex patterns, see {@link #replacePattern(String, String, String)} +236 * @param string +237 * @param pattern +238 * @param repl +239 * @return +240 */ +241 public static String replace(String string, String pattern, String repl) { +242 return replace(string, ACFPatterns.getPattern(Pattern.quote(pattern)), repl); +243 } +244 +245 /** +246 * Regex version of {@link #replace(String, String, String)} +247 * @param string +248 * @param pattern +249 * @param repl +250 * @return +251 */ +252 public static String replacePattern(String string, String pattern, String repl) { +253 return replace(string, ACFPatterns.getPattern(pattern), repl); +254 } +255 /** +256 * Pure Regex Pattern matching and replacement, no escaping +257 * @param string +258 * @param pattern +259 * @param repl +260 * @return +261 */ +262 public static String replacePatternMatch(String string, Pattern pattern, String repl) { +263 return pattern.matcher(string).replaceAll(repl); +264 } +265 +266 /** +267 * Pure Regex Pattern matching and replacement, no escaping +268 * @param string +269 * @param pattern +270 * @param repl +271 * @return +272 */ +273 public static String replacePatternMatch(String string, String pattern, String repl) { +274 return replacePatternMatch(string, ACFPatterns.getPattern(pattern), repl); +275 } +276 +277 public static String replaceStrings(String string, String... replacements) { +278 if (replacements.length < 2 || replacements.length % 2 != 0) { +279 throw new IllegalArgumentException("Invalid Replacements"); +280 } +281 for (int i = 0; i < replacements.length; i += 2) { +282 String key = replacements[i]; +283 String value = replacements[i+1]; +284 if (value == null) value = ""; +285 string = replace(string, key, value); +286 } +287 return string; +288 } +289 public static String replacePatterns(String string, String... replacements) { +290 if (replacements.length < 2 || replacements.length % 2 != 0) { +291 throw new IllegalArgumentException("Invalid Replacements"); +292 } +293 for (int i = 0; i < replacements.length; i += 2) { +294 String key = replacements[i]; +295 String value = replacements[i+1]; +296 if (value == null) value = ""; +297 string = replacePattern(string, key, value); +298 } +299 return string; +300 } +301 +302 public static String capitalize(String str, char[] delimiters) { +303 return ApacheCommonsLangUtil.capitalize(str, delimiters); +304 } +305 private static boolean isDelimiter(char ch, char[] delimiters) { +306 return ApacheCommonsLangUtil.isDelimiter(ch, delimiters); +307 } +308 +309 public static <T> T random(List<T> arr) { +310 if (arr == null || arr.isEmpty()) { +311 return null; +312 } +313 return arr.get(RANDOM.nextInt(arr.size())); +314 } +315 public static <T> T random(T[] arr) { +316 if (arr == null || arr.length == 0) { +317 return null; +318 } +319 return arr[RANDOM.nextInt(arr.length)]; +320 } +321 +322 /** +323 * Added as im sure we will try to "Find this" again. This is no different than Enum.values() passed to above method logically +324 * but the array version is slightly faster. +325 * @param enm +326 * @param <T> +327 * @return +328 */ +329 @Deprecated +330 public static <T extends Enum<?>> T random(Class<? extends T> enm) { +331 return random(enm.getEnumConstants()); +332 } +333 +334 public static String normalize(String s) { +335 if (s == null) { +336 return null; +337 } +338 return ACFPatterns.NON_PRINTABLE_CHARACTERS.matcher(Normalizer.normalize(s, Form.NFD)).replaceAll(""); +339 } +340 +341 public static int indexOf(String arg, String[] split) { +342 for (int i = 0; i < split.length; i++) { +343 if (arg == null) { +344 if (split[i] == null) { +345 return i; +346 } +347 } else if (arg.equals(split[i])) { +348 return i; +349 } +350 } +351 return -1; +352 } +353 +354 public static String capitalizeFirst(String name) { +355 return capitalizeFirst(name, '_'); +356 } +357 +358 public static String capitalizeFirst(String name, char separator) { +359 name = name.toLowerCase(); +360 String[] split = name.split(Character.toString(separator)); +361 StringBuilder total = new StringBuilder(3); +362 for (String s : split) { +363 total.append(Character.toUpperCase(s.charAt(0))).append(s.substring(1)).append(' '); +364 } +365 +366 return total.toString().trim(); +367 } +368 +369 public static String ltrim(String s) { +370 int i = 0; +371 while (i < s.length() && Character.isWhitespace(s.charAt(i))) { +372 i++; +373 } +374 return s.substring(i); +375 } +376 +377 public static String rtrim(String s) { +378 int i = s.length()-1; +379 while (i >= 0 && Character.isWhitespace(s.charAt(i))) { +380 i--; +381 } +382 return s.substring(0,i+1); +383 } +384 +385 public static List<String> enumNames(Enum<?>[] values) { +386 return Stream.of(values).map(Enum::name).collect(Collectors.toList()); +387 } +388 +389 public static List<String> enumNames(Class<? extends Enum<?>> cls) { +390 return enumNames(cls.getEnumConstants()); +391 } +392 +393 public static String combine(String[] args) { +394 return combine(args, 0); +395 } +396 public static String combine(String[] args, int start) { +397 int size = 0; +398 for (int i = start; i < args.length; i++) { +399 size += args[i].length(); +400 } +401 StringBuilder sb = new StringBuilder(size); +402 for (int i = start; i < args.length; i++) { +403 sb.append(args[i]); +404 } +405 return sb.toString(); +406 } 407 -408 @Nullable public static <E extends Enum<E>> E simpleMatch(Class<? extends Enum<?>> list, String item) { -409 if (item == null) { -410 return null; -411 } -412 item = ACFUtil.simplifyString(item); -413 for (Enum<?> s : list.getEnumConstants()) { -414 String simple = ACFUtil.simplifyString(s.name()); -415 if (item.equals(simple)) { -416 //noinspection unchecked -417 return (E) s; -418 } -419 } -420 -421 return null; -422 } -423 -424 public static boolean isTruthy(String test) { -425 switch (test) { -426 case "t": -427 case "true": -428 case "on": -429 case "y": -430 case "yes": -431 case "1": -432 return true; -433 } -434 return false; -435 } -436 +408 +409 @Nullable public static <E extends Enum<E>> E simpleMatch(Class<? extends Enum<?>> list, String item) { +410 if (item == null) { +411 return null; +412 } +413 item = ACFUtil.simplifyString(item); +414 for (Enum<?> s : list.getEnumConstants()) { +415 String simple = ACFUtil.simplifyString(s.name()); +416 if (item.equals(simple)) { +417 //noinspection unchecked +418 return (E) s; +419 } +420 } +421 +422 return null; +423 } +424 +425 public static boolean isTruthy(String test) { +426 switch (test) { +427 case "t": +428 case "true": +429 case "on": +430 case "y": +431 case "yes": +432 case "1": +433 return true; +434 } +435 return false; +436 } 437 -438 public static Number parseNumber(String num, boolean suffixes) { -439 ApplyModifierToNumber applyModifierToNumber = new ApplyModifierToNumber(num, suffixes).invoke(); -440 num = applyModifierToNumber.getNum(); -441 double mod = applyModifierToNumber.getMod(); -442 -443 return Double.parseDouble(num) * mod; -444 } -445 -446 public static BigDecimal parseBigNumber(String num, boolean suffixes) { -447 ApplyModifierToNumber applyModifierToNumber = new ApplyModifierToNumber(num, suffixes).invoke(); -448 num = applyModifierToNumber.getNum(); -449 double mod = applyModifierToNumber.getMod(); -450 -451 BigDecimal big = new BigDecimal(num); -452 return (mod == 1) ? big : big.multiply(new BigDecimal(mod)); -453 } -454 -455 public static <T> boolean hasIntersection(Collection<T> list1, Collection<T> list2) { -456 for (T t : list1) { -457 if (list2.contains(t)) { -458 return true; -459 } -460 } -461 -462 return false; -463 } -464 -465 public static <T> Collection<T> intersection(Collection<T> list1, Collection<T> list2) { -466 List<T> list = new ArrayList<>(); -467 -468 for (T t : list1) { -469 if(list2.contains(t)) { -470 list.add(t); -471 } -472 } -473 -474 return list; -475 } -476 -477 public static int rand(int min, int max) { -478 return min + RANDOM.nextInt(max - min + 1); -479 } -480 -481 /** -482 * Calculate random between 2 points, excluding a center -483 * ex: Util.rand(-12, -6, 6, 12) would not return -5 to 5 -484 * @param min1 -485 * @param max1 -486 * @param min2 -487 * @param max2 -488 * @return -489 */ -490 public static int rand(int min1, int max1, int min2, int max2) { -491 return randBool() ? rand(min1, max1) : rand(min2, max2); -492 } -493 -494 public static double rand(double min, double max) { -495 return RANDOM.nextDouble() * (max - min) + min; -496 } -497 -498 public static boolean isNumber(String str) { -499 return ApacheCommonsLangUtil.isNumeric(str); -500 } -501 -502 public static String intToRoman(int integer) { -503 if (integer == 1) { -504 return "I"; -505 } -506 if (integer == 2) { -507 return "II"; -508 } -509 if (integer == 3) { -510 return "III"; -511 } -512 if (integer == 4) { -513 return "IV"; -514 } -515 if (integer == 5) { -516 return "V"; -517 } -518 if (integer == 6) { -519 return "VI"; -520 } -521 if (integer == 7) { -522 return "VII"; -523 } -524 if (integer == 8) { -525 return "VIII"; -526 } -527 if (integer == 9) { -528 return "IX"; -529 } -530 if (integer == 10) { -531 return "X"; -532 } -533 return null; -534 } -535 -536 public static boolean isInteger(String string) { -537 return ACFPatterns.INTEGER.matcher(string).matches(); -538 } -539 -540 public static boolean isFloat(String string) { -541 try { -542 //noinspection ResultOfMethodCallIgnored -543 Float.parseFloat(string); -544 return true; -545 } catch (Exception e) { -546 return false; -547 } -548 } -549 -550 public static boolean isDouble(String string) { -551 try { -552 //noinspection ResultOfMethodCallIgnored -553 Double.parseDouble(string); -554 return true; -555 } catch (Exception e) { -556 return false; -557 } -558 } -559 -560 public static boolean isBetween(float num, double min, double max) { -561 return num >= min && num <= max; -562 } -563 -564 @SuppressWarnings("SameParameterValue") -565 public static double precision(double x, int p) { -566 double pow = Math.pow(10, p); -567 return Math.round(x * pow) / pow; -568 } -569 -570 public static void sneaky(Throwable t) { -571 //noinspection RedundantTypeArguments -572 throw ACFUtil.<RuntimeException>superSneaky( t ); -573 } -574 -575 private static <T extends Throwable> T superSneaky(Throwable t) throws T { -576 //noinspection ConstantConditions,unchecked -577 throw (T) t; -578 } -579 -580 public static <T> List<T> preformOnImmutable(List<T> list, Consumer<List<T>> action) { -581 try { -582 action.accept(list); -583 } catch (UnsupportedOperationException ex) { -584 list = new ArrayList<>(list); -585 action.accept(list); -586 } -587 -588 return list; -589 } -590 -591 private static class ApplyModifierToNumber { -592 private String num; -593 private boolean suffixes; -594 private double mod; -595 -596 public ApplyModifierToNumber(String num, boolean suffixes) { -597 this.num = num; -598 this.suffixes = suffixes; -599 } -600 -601 public String getNum() { -602 return num; -603 } -604 -605 public double getMod() { -606 return mod; -607 } -608 -609 public ApplyModifierToNumber invoke() { -610 mod = 1; -611 if (suffixes) { -612 switch (num.charAt(num.length()-1)) { -613 case 'M': -614 case 'm': -615 mod = 1000000D; -616 num = num.substring(0, num.length()-1); -617 break; -618 case 'K': -619 case 'k': -620 mod = 1000D; -621 num = num.substring(0, num.length()-1); -622 } -623 } -624 return this; -625 } -626 } -627} +438 +439 public static Number parseNumber(String num, boolean suffixes) { +440 ApplyModifierToNumber applyModifierToNumber = new ApplyModifierToNumber(num, suffixes).invoke(); +441 num = applyModifierToNumber.getNum(); +442 double mod = applyModifierToNumber.getMod(); +443 +444 return Double.parseDouble(num) * mod; +445 } +446 +447 public static BigDecimal parseBigNumber(String num, boolean suffixes) { +448 ApplyModifierToNumber applyModifierToNumber = new ApplyModifierToNumber(num, suffixes).invoke(); +449 num = applyModifierToNumber.getNum(); +450 double mod = applyModifierToNumber.getMod(); +451 +452 BigDecimal big = new BigDecimal(num); +453 return (mod == 1) ? big : big.multiply(new BigDecimal(mod)); +454 } +455 +456 public static <T> boolean hasIntersection(Collection<T> list1, Collection<T> list2) { +457 for (T t : list1) { +458 if (list2.contains(t)) { +459 return true; +460 } +461 } +462 +463 return false; +464 } +465 +466 public static <T> Collection<T> intersection(Collection<T> list1, Collection<T> list2) { +467 List<T> list = new ArrayList<>(); +468 +469 for (T t : list1) { +470 if(list2.contains(t)) { +471 list.add(t); +472 } +473 } +474 +475 return list; +476 } +477 +478 public static int rand(int min, int max) { +479 return min + RANDOM.nextInt(max - min + 1); +480 } +481 +482 /** +483 * Calculate random between 2 points, excluding a center +484 * ex: Util.rand(-12, -6, 6, 12) would not return -5 to 5 +485 * @param min1 +486 * @param max1 +487 * @param min2 +488 * @param max2 +489 * @return +490 */ +491 public static int rand(int min1, int max1, int min2, int max2) { +492 return randBool() ? rand(min1, max1) : rand(min2, max2); +493 } +494 +495 public static double rand(double min, double max) { +496 return RANDOM.nextDouble() * (max - min) + min; +497 } +498 +499 public static boolean isNumber(String str) { +500 return ApacheCommonsLangUtil.isNumeric(str); +501 } +502 +503 public static String intToRoman(int integer) { +504 if (integer == 1) { +505 return "I"; +506 } +507 if (integer == 2) { +508 return "II"; +509 } +510 if (integer == 3) { +511 return "III"; +512 } +513 if (integer == 4) { +514 return "IV"; +515 } +516 if (integer == 5) { +517 return "V"; +518 } +519 if (integer == 6) { +520 return "VI"; +521 } +522 if (integer == 7) { +523 return "VII"; +524 } +525 if (integer == 8) { +526 return "VIII"; +527 } +528 if (integer == 9) { +529 return "IX"; +530 } +531 if (integer == 10) { +532 return "X"; +533 } +534 return null; +535 } +536 +537 public static boolean isInteger(String string) { +538 return ACFPatterns.INTEGER.matcher(string).matches(); +539 } +540 +541 public static boolean isFloat(String string) { +542 try { +543 //noinspection ResultOfMethodCallIgnored +544 Float.parseFloat(string); +545 return true; +546 } catch (Exception e) { +547 return false; +548 } +549 } +550 +551 public static boolean isDouble(String string) { +552 try { +553 //noinspection ResultOfMethodCallIgnored +554 Double.parseDouble(string); +555 return true; +556 } catch (Exception e) { +557 return false; +558 } +559 } +560 +561 public static boolean isBetween(float num, double min, double max) { +562 return num >= min && num <= max; +563 } +564 +565 @SuppressWarnings("SameParameterValue") +566 public static double precision(double x, int p) { +567 double pow = Math.pow(10, p); +568 return Math.round(x * pow) / pow; +569 } +570 +571 public static void sneaky(Throwable t) { +572 //noinspection RedundantTypeArguments +573 throw ACFUtil.<RuntimeException>superSneaky( t ); +574 } +575 +576 private static <T extends Throwable> T superSneaky(Throwable t) throws T { +577 //noinspection ConstantConditions,unchecked +578 throw (T) t; +579 } +580 +581 public static <T> List<T> preformOnImmutable(List<T> list, Consumer<List<T>> action) { +582 try { +583 action.accept(list); +584 } catch (UnsupportedOperationException ex) { +585 list = new ArrayList<>(list); +586 action.accept(list); +587 } +588 +589 return list; +590 } +591 +592 public static <T> T getFirstElement(Iterable<T> iterable) { +593 Iterator<T> iterator = iterable.iterator(); +594 T first = iterator.next(); +595 if (!iterator.hasNext()) { +596 return first; +597 } +598 +599 throw new IllegalArgumentException("Expected one element in iterable"); +600 } +601 +602 private static class ApplyModifierToNumber { +603 private String num; +604 private boolean suffixes; +605 private double mod; +606 +607 public ApplyModifierToNumber(String num, boolean suffixes) { +608 this.num = num; +609 this.suffixes = suffixes; +610 } +611 +612 public String getNum() { +613 return num; +614 } +615 +616 public double getMod() { +617 return mod; +618 } +619 +620 public ApplyModifierToNumber invoke() { +621 mod = 1; +622 if (suffixes) { +623 switch (num.charAt(num.length()-1)) { +624 case 'M': +625 case 'm': +626 mod = 1000000D; +627 num = num.substring(0, num.length()-1); +628 break; +629 case 'K': +630 case 'k': +631 mod = 1000D; +632 num = num.substring(0, num.length()-1); +633 } +634 } +635 return this; +636 } +637 } +638} diff --git a/docs/acf-core/src-html/co/aikar/commands/BaseCommand.html b/docs/acf-core/src-html/co/aikar/commands/BaseCommand.html index 9591a63a..016f15c5 100644 --- a/docs/acf-core/src-html/co/aikar/commands/BaseCommand.html +++ b/docs/acf-core/src-html/co/aikar/commands/BaseCommand.html @@ -43,977 +43,976 @@ 035import co.aikar.commands.annotation.UnknownHandler; 036import co.aikar.commands.apachecommonslang.ApacheCommonsLangUtil; 037import com.google.common.collect.HashMultimap; -038import com.google.common.collect.Iterables; -039import com.google.common.collect.SetMultimap; -040import org.jetbrains.annotations.Nullable; -041 -042import java.lang.reflect.Constructor; -043import java.lang.reflect.InvocationTargetException; -044import java.lang.reflect.Method; -045import java.lang.reflect.Parameter; -046import java.util.ArrayList; -047import java.util.Arrays; -048import java.util.Collections; -049import java.util.HashMap; -050import java.util.HashSet; -051import java.util.List; -052import java.util.Map; -053import java.util.Objects; -054import java.util.Optional; -055import java.util.Set; -056import java.util.Stack; -057import java.util.stream.Collectors; -058import java.util.stream.Stream; -059 -060/** -061 * A Base command is defined as a command group of related commands. -062 * A BaseCommand does not imply nor enforce that they use the same root command. -063 * -064 * It is up to the end user how to organize their command. you could use 1 base command per -065 * command in your application. -066 * -067 * Optionally (and encouraged), you can use the base command to represent a root command, and -068 * then each actionable command is a sub command -069 */ -070 -071@SuppressWarnings("unused") -072public abstract class BaseCommand { -073 -074 /** -075 * This is a field which contains the magic key in the {@link #subCommands} map for the method to catch any unknown -076 * argument to command states. -077 */ -078 static final String CATCHUNKNOWN = "__catchunknown"; -079 /** -080 * This is a field which contains the magic key in the {@link #subCommands} map for the method which is default for the -081 * entire base command. -082 */ -083 static final String DEFAULT = "__default"; -084 -085 /** -086 * A map of all the registered commands for this base command, keyed to each potential subcommand to access it. -087 */ -088 final SetMultimap<String, RegisteredCommand> subCommands = HashMultimap.create(); -089 -090 /** -091 * A map of flags to pass to Context Resolution for every parameter of the type. This is like an automatic @Flags on each. -092 */ -093 final Map<Class<?>, String> contextFlags = new HashMap<>(); -094 -095 /** -096 * What method was annoated with {@link PreCommand} to execute before commands. -097 */ -098 @Nullable private Method preCommandHandler; -099 -100 /** -101 * What root command the user actually entered to access the currently executing command -102 */ -103 @SuppressWarnings("WeakerAccess") -104 private String execLabel; -105 /** -106 * What subcommand the user actually entered to access the currently executing command -107 */ -108 @SuppressWarnings("WeakerAccess") -109 private String execSubcommand; -110 /** -111 * What arguments the user actually entered after the root command to access the currently executing command -112 */ -113 @SuppressWarnings("WeakerAccess") -114 private String[] origArgs; -115 -116 /** -117 * The manager this is registered to -118 */ -119 CommandManager<?, ?, ?, ?, ?, ?> manager = null; -120 -121 /** -122 * The command which owns this. This may be null if there are no owners. -123 */ -124 BaseCommand parentCommand; -125 Map<String, RootCommand> registeredCommands = new HashMap<>(); -126 /** -127 * The description of the command. This may be null if no description has been provided. -128 * Used for help documentation -129 */ -130 @Nullable String description; -131 /** -132 * The name of the command. This may be null if no name has been provided. -133 */ -134 @Nullable String commandName; -135 /** -136 * The permission of the command. This may be null if no permission has been provided. -137 */ -138 @Nullable String permission; -139 /** -140 * The conditions of the command. This may be null if no conditions has been provided. -141 */ -142 @Nullable String conditions; -143 /** -144 * Identifies if the command has an explicit help command annotated with {@link HelpCommand} -145 */ -146 boolean hasHelpCommand; -147 -148 /** -149 * The handler of all uncaught exceptions thrown by the user's command implementation. -150 */ -151 private ExceptionHandler exceptionHandler = null; -152 /** -153 * The last operative context data of this command. This may be null if this command hasn't been run yet. -154 */ -155 @Nullable CommandOperationContext lastCommandOperationContext; -156 /** -157 * If a parent exists to this command, and it has a Subcommand annotation, prefix all subcommands in this class with this -158 */ -159 @Nullable private String parentSubcommand; -160 -161 public BaseCommand() {} -162 -163 /** -164 * Constructor based defining of commands will be removed in the next version bump. -165 * @deprecated Please switch to {@link CommandAlias} for defining all root commands. -166 * @param cmd -167 */ -168 @Deprecated -169 public BaseCommand(@Nullable String cmd) { -170 this.commandName = cmd; -171 } -172 -173 /** -174 * Gets the root command name that the user actually typed -175 * @return Name -176 */ -177 public String getExecCommandLabel() { -178 return execLabel; -179 } -180 -181 /** -182 * Gets the actual sub command name the user typed -183 * @return Name -184 */ -185 public String getExecSubcommand() { -186 return execSubcommand; -187 } -188 -189 /** -190 * Gets the actual args in string form the user typed -191 * @return Args -192 */ -193 public String[] getOrigArgs() { -194 return origArgs; -195 } -196 -197 /** -198 * This should be called whenever the command gets registered. -199 * It sets all required fields correctly and injects dependencies. -200 * -201 * @param manager -202 * The manager to register as this command's owner and handler. -203 */ -204 void onRegister(CommandManager manager) { -205 onRegister(manager, this.commandName); -206 } -207 -208 /** -209 * This should be called whenever the command gets registered. -210 * It sets all required fields correctly and injects dependencies. -211 * -212 * @param manager -213 * The manager to register as this command's owner and handler. -214 * @param cmd -215 * The command name to use register with. -216 */ -217 private void onRegister(CommandManager manager, String cmd) { -218 manager.injectDependencies(this); -219 this.manager = manager; -220 -221 final Annotations annotations = manager.getAnnotations(); -222 final Class<? extends BaseCommand> self = this.getClass(); -223 -224 String[] cmdAliases = annotations.getAnnotationValues(self, CommandAlias.class, Annotations.REPLACEMENTS | Annotations.LOWERCASE | Annotations.NO_EMPTY); -225 -226 if (cmd == null && cmdAliases != null) { -227 cmd = cmdAliases[0]; -228 } -229 -230 this.commandName = cmd != null ? cmd : self.getSimpleName().toLowerCase(); -231 this.permission = annotations.getAnnotationValue(self, CommandPermission.class, Annotations.REPLACEMENTS); -232 this.description = this.commandName + " commands"; -233 this.parentSubcommand = getParentSubcommand(self); -234 this.conditions = annotations.getAnnotationValue(self, Conditions.class, Annotations.REPLACEMENTS | Annotations.NO_EMPTY); -235 -236 registerSubcommands(); -237 -238 if (cmdAliases != null) { -239 Set<String> cmdList = new HashSet<>(); -240 Collections.addAll(cmdList, cmdAliases); -241 cmdList.remove(cmd); -242 for (String cmdAlias : cmdList) { -243 register(cmdAlias, this); -244 } -245 } -246 -247 if (cmd != null) { -248 register(cmd, this); -249 } -250 registerSubclasses(cmd); -251 -252 } -253 -254 /** -255 * This recursively registers all subclasses of the command as subcommands, if they are of type {@link BaseCommand}. -256 * -257 * @param cmd -258 * The command name of this command. -259 */ -260 private void registerSubclasses(String cmd) { -261 for (Class<?> clazz : this.getClass().getDeclaredClasses()) { -262 if (BaseCommand.class.isAssignableFrom(clazz)) { -263 try { -264 BaseCommand subCommand = null; -265 Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors(); -266 for (Constructor<?> declaredConstructor : declaredConstructors) { -267 -268 declaredConstructor.setAccessible(true); -269 Parameter[] parameters = declaredConstructor.getParameters(); -270 if (parameters.length == 1) { -271 subCommand = (BaseCommand) declaredConstructor.newInstance(this); -272 } else { -273 manager.log(LogLevel.INFO, "Found unusable constructor: " + declaredConstructor.getName() + "(" + Stream.of(parameters).map(p -> p.getType().getSimpleName() + " " + p.getName()).collect(Collectors.joining("<c2>,</c2> ")) + ")"); -274 } -275 } -276 if (subCommand != null) { -277 subCommand.parentCommand = this; -278 subCommand.onRegister(manager, cmd); -279 this.subCommands.putAll(subCommand.subCommands); -280 this.registeredCommands.putAll(subCommand.registeredCommands); -281 } else { -282 this.manager.log(LogLevel.ERROR, "Could not find a subcommand ctor for " + clazz.getName()); -283 } -284 } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { -285 this.manager.log(LogLevel.ERROR, "Error registering subclass", e); -286 } -287 } -288 } -289 } -290 -291 /** -292 * This registers all subcommands of the command. -293 */ -294 private void registerSubcommands() { -295 final Annotations annotations = manager.getAnnotations(); -296 boolean foundDefault = false; -297 boolean foundCatchUnknown = false; -298 boolean isParentEmpty = parentSubcommand == null || parentSubcommand.isEmpty(); -299 -300 for (Method method : this.getClass().getMethods()) { -301 method.setAccessible(true); -302 String sublist = null; -303 String sub = getSubcommandValue(method); -304 final boolean def = annotations.hasAnnotation(method, Default.class); -305 final String helpCommand = annotations.getAnnotationValue(method, HelpCommand.class, Annotations.NOTHING); -306 final String commandAliases = annotations.getAnnotationValue(method, CommandAlias.class, Annotations.NOTHING); -307 -308 if (!isParentEmpty && def) { -309 sub = parentSubcommand; -310 } -311 if (isParentEmpty && (def || (!foundDefault && helpCommand != null))) { -312 if (!foundDefault) { -313 if (def) { -314 this.subCommands.get(DEFAULT).clear(); -315 foundDefault = true; -316 } -317 registerSubcommand(method, DEFAULT); -318 } else { -319 ACFUtil.sneaky(new IllegalStateException("Multiple @Default/@HelpCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName())); -320 } -321 } -322 -323 if (sub != null) { -324 sublist = sub; -325 } else if (commandAliases != null) { -326 sublist = commandAliases; -327 } else if (helpCommand != null) { -328 sublist = helpCommand; -329 hasHelpCommand = true; -330 } -331 -332 boolean preCommand = annotations.hasAnnotation(method, PreCommand.class); -333 boolean hasCatchUnknown = annotations.hasAnnotation(method, CatchUnknown.class) || -334 annotations.hasAnnotation(method, CatchAll.class) || -335 annotations.hasAnnotation(method, UnknownHandler.class); -336 -337 if (hasCatchUnknown || (!foundCatchUnknown && helpCommand != null)) { -338 if (!foundCatchUnknown) { -339 if (hasCatchUnknown) { -340 this.subCommands.get(CATCHUNKNOWN).clear(); -341 foundCatchUnknown = true; -342 } -343 registerSubcommand(method, CATCHUNKNOWN); -344 } else { -345 ACFUtil.sneaky(new IllegalStateException("Multiple @UnknownHandler/@HelpCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName())); -346 } -347 } else if (preCommand) { -348 if (this.preCommandHandler == null) { -349 this.preCommandHandler = method; -350 } else { -351 ACFUtil.sneaky(new IllegalStateException("Multiple @PreCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName())); -352 } -353 } -354 if (Objects.equals(method.getDeclaringClass(), this.getClass()) && sublist != null) { -355 registerSubcommand(method, sublist); -356 } -357 } -358 } -359 -360 /** -361 * Gets the subcommand name of the method given. -362 * -363 * @param method -364 * The method to check. -365 * -366 * @return The name of the subcommand. It returns null if the input doesn't have {@link Subcommand} attached. -367 */ -368 private String getSubcommandValue(Method method) { -369 final String sub = manager.getAnnotations().getAnnotationValue(method, Subcommand.class, Annotations.NOTHING); -370 if (sub == null) { -371 return null; -372 } -373 Class<?> clazz = method.getDeclaringClass(); -374 String parent = getParentSubcommand(clazz); -375 return parent == null || parent.isEmpty() ? sub : parent + " " + sub; -376 } -377 -378 private String getParentSubcommand(Class<?> clazz) { -379 List<String> subList = new ArrayList<>(); -380 while (clazz != null) { -381 String sub = manager.getAnnotations().getAnnotationValue(clazz, Subcommand.class, Annotations.NOTHING); -382 if (sub != null) { -383 subList.add(sub); -384 } -385 clazz = clazz.getEnclosingClass(); -386 } -387 Collections.reverse(subList); -388 return ACFUtil.join(subList, " "); -389 } -390 -391 /** -392 * Registers the given {@link BaseCommand cmd} as a child of the {@link RootCommand} linked to the name given. -393 * -394 * @param name -395 * Name of the parent to cmd. -396 * @param cmd -397 * The {@link BaseCommand} to add as a child to the {@link RootCommand} owned name field. -398 */ -399 private void register(String name, BaseCommand cmd) { -400 String nameLower = name.toLowerCase(); -401 RootCommand rootCommand = manager.obtainRootCommand(nameLower); -402 rootCommand.addChild(cmd); -403 -404 this.registeredCommands.put(nameLower, rootCommand); -405 } -406 -407 /** -408 * Registers the given {@link Method} as a subcommand. -409 * -410 * @param method -411 * The method to register as a subcommand. -412 * @param subCommand -413 * The subcommand's name(s). -414 */ -415 private void registerSubcommand(Method method, String subCommand) { -416 subCommand = manager.getCommandReplacements().replace(subCommand.toLowerCase()); -417 final String[] subCommandParts = ACFPatterns.SPACE.split(subCommand); -418 // Must run getSubcommandPossibility BEFORE we rewrite it just after this. -419 Set<String> cmdList = getSubCommandPossibilityList(subCommandParts); -420 -421 // Strip pipes off for auto complete addition -422 for (int i = 0; i < subCommandParts.length; i++) { -423 String[] split = ACFPatterns.PIPE.split(subCommandParts[i]); -424 if (split.length == 0 || split[0].isEmpty()) { -425 throw new IllegalArgumentException("Invalid @Subcommand configuration for " + method.getName() + " - parts can not start with | or be empty"); -426 } -427 subCommandParts[i] = split[0]; -428 } -429 String prefSubCommand = ApacheCommonsLangUtil.join(subCommandParts, " "); -430 final String[] aliasNames = manager.getAnnotations().getAnnotationValues(method, CommandAlias.class, Annotations.REPLACEMENTS | Annotations.LOWERCASE); -431 -432 String cmdName = aliasNames != null ? aliasNames[0] : this.commandName + " "; -433 RegisteredCommand cmd = manager.createRegisteredCommand(this, cmdName, method, prefSubCommand); -434 -435 for (String subcmd : cmdList) { -436 subCommands.put(subcmd, cmd); -437 } -438 cmd.addSubcommands(cmdList); -439 -440 if (aliasNames != null) { -441 for (String name : aliasNames) { -442 register(name, new ForwardingCommand(this, subCommandParts)); -443 } -444 } -445 } -446 -447 /** -448 * Takes a string like "foo|bar baz|qux" and generates a list of -449 * - foo baz -450 * - foo qux -451 * - bar baz -452 * - bar qux -453 * -454 * For every possible sub command combination -455 * -456 * @param subCommandParts -457 * @return List of all sub command possibilities -458 */ -459 private static Set<String> getSubCommandPossibilityList(String[] subCommandParts) { -460 int i = 0; -461 Set<String> current = null; -462 while (true) { -463 Set<String> newList = new HashSet<>(); -464 -465 if (i < subCommandParts.length) { -466 for (String s1 : ACFPatterns.PIPE.split(subCommandParts[i])) { -467 if (current != null) { -468 newList.addAll(current.stream().map(s -> s + " " + s1).collect(Collectors.toList())); -469 } else { -470 newList.add(s1); -471 } -472 } -473 } -474 -475 if (i + 1 < subCommandParts.length) { -476 current = newList; -477 i = i + 1; -478 continue; -479 } -480 -481 return newList; -482 } -483 } -484 -485 public void execute(CommandIssuer issuer, String commandLabel, String[] args) { -486 commandLabel = commandLabel.toLowerCase(); -487 try { -488 CommandOperationContext commandContext = preCommandOperation(issuer, commandLabel, args, false); -489 -490 if (args.length > 0) { -491 CommandSearch cmd = findSubCommand(args); -492 if (cmd != null) { -493 execSubcommand = cmd.getCheckSub(); -494 final String[] execargs = Arrays.copyOfRange(args, cmd.argIndex, args.length); -495 executeCommand(commandContext, issuer, execargs, cmd.cmd); -496 return; -497 } -498 } -499 -500 if (subCommands.get(DEFAULT) != null && args.length == 0) { -501 findAndExecuteCommand(commandContext, DEFAULT, issuer, args); -502 } else if (subCommands.get(CATCHUNKNOWN) != null) { -503 if (!findAndExecuteCommand(commandContext, CATCHUNKNOWN, issuer, args)) { -504 help(issuer, args); -505 } -506 } else if (subCommands.get(DEFAULT) != null) { -507 findAndExecuteCommand(commandContext, DEFAULT, issuer, args); -508 } -509 -510 } finally { -511 postCommandOperation(); -512 } -513 } -514 -515 /** -516 * Gets the registered command of the given arguments. -517 * @param args -518 * The arguments given by the user. -519 * -520 * @return The subcommand or null if none were found. -521 * -522 * @see #findSubCommand(String[]) -523 */ -524 RegisteredCommand<?> getRegisteredCommand(String[] args) { -525 final CommandSearch cmd = findSubCommand(args); -526 return cmd != null ? cmd.cmd : null; -527 } -528 -529 /** -530 * This is ran after any command operation has been performed. -531 */ -532 private void postCommandOperation() { -533 CommandManager.commandOperationContext.get().pop(); -534 execSubcommand = null; -535 execLabel = null; -536 origArgs = new String[]{}; -537 } -538 -539 /** -540 * This is ran before any command operation has been performed. -541 * -542 * @param issuer -543 * The user who executed the command. -544 * @param commandLabel -545 * The label the user used to execute the command. This is not the command name, but their input. -546 * When there is multiple aliases, this is which alias was used -547 * @param args -548 * The arguments passed to the command when executing it. -549 * @param isAsync -550 * Whether the command is executed off of the main thread. -551 * -552 * @return The context which is being registered to the {@link CommandManager}'s {@link -553 * CommandManager#commandOperationContext thread local stack}. -554 */ -555 private CommandOperationContext preCommandOperation(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) { -556 Stack<CommandOperationContext> contexts = CommandManager.commandOperationContext.get(); -557 CommandOperationContext context = this.manager.createCommandOperationContext(this, issuer, commandLabel, args, isAsync); -558 contexts.push(context); -559 lastCommandOperationContext = context; -560 execSubcommand = null; -561 execLabel = commandLabel; -562 origArgs = args; -563 return context; -564 } -565 -566 /** -567 * Gets the current command issuer. -568 * -569 * @return The current command issuer. -570 */ -571 public CommandIssuer getCurrentCommandIssuer() { -572 return CommandManager.getCurrentCommandIssuer(); -573 } -574 -575 /** -576 * Gets the current command manager. -577 * -578 * @return The current command manager. -579 */ -580 public CommandManager getCurrentCommandManager() { -581 return CommandManager.getCurrentCommandManager(); -582 } -583 -584 /** -585 * Finds a subcommand of the given arguments. -586 * -587 * @param args -588 * The arguments the user input. -589 * -590 * @return The identified subcommand. -591 * -592 * @see #findSubCommand(String[], boolean) -593 */ -594 private CommandSearch findSubCommand(String[] args) { -595 return findSubCommand(args, false); -596 } -597 -598 /** -599 * Finds a subcommand of the given arguments. -600 * -601 * @param args -602 * The arguments the user input. -603 * @param completion -604 * Whether or not completion of arguments should kick in. This may end up with worse than wanted results. -605 * -606 * @return The identified subcommand. -607 */ -608 private CommandSearch findSubCommand(String[] args, boolean completion) { -609 for (int i = args.length; i >= 0; i--) { -610 String checkSub = ApacheCommonsLangUtil.join(args, " ", 0, i).toLowerCase(); -611 Set<RegisteredCommand> cmds = subCommands.get(checkSub); -612 -613 final int extraArgs = args.length - i; -614 if (!cmds.isEmpty()) { -615 RegisteredCommand cmd = null; -616 if (cmds.size() == 1) { -617 cmd = Iterables.getOnlyElement(cmds); -618 } else { -619 Optional<RegisteredCommand> optCmd = cmds.stream().filter(c -> { -620 int required = c.requiredResolvers; -621 int optional = c.optionalResolvers; -622 return extraArgs <= required + optional && (completion || extraArgs >= required); -623 }).min((c1, c2) -> { -624 int a = c1.consumeInputResolvers; -625 int b = c2.consumeInputResolvers; -626 -627 if (a == b) { -628 return 0; -629 } -630 return a < b ? 1 : -1; -631 }); -632 if (optCmd.isPresent()) { -633 cmd = optCmd.get(); -634 } -635 } -636 if (cmd != null) { -637 return new CommandSearch(cmd, i, checkSub); -638 } -639 } -640 } -641 return null; -642 } -643 -644 private void executeCommand(CommandOperationContext commandOperationContext, -645 CommandIssuer issuer, String[] args, RegisteredCommand cmd) { -646 if (cmd.hasPermission(issuer)) { -647 commandOperationContext.setRegisteredCommand(cmd); -648 if (checkPrecommand(commandOperationContext, cmd, issuer, args)) { -649 return; -650 } -651 List<String> sargs = Arrays.asList(args); -652 cmd.invoke(issuer, sargs, commandOperationContext); -653 } else { -654 issuer.sendMessage(MessageType.ERROR, MessageKeys.PERMISSION_DENIED); -655 } -656 } -657 -658 /** -659 * Please use command conditions for restricting execution -660 * @deprecated See {@link CommandConditions} -661 * @param issuer -662 * @param cmd -663 * @return -664 */ -665 @SuppressWarnings("DeprecatedIsStillUsed") -666 @Deprecated -667 public boolean canExecute(CommandIssuer issuer, RegisteredCommand<?> cmd) { -668 return true; -669 } -670 -671 /** -672 * Gets tab completed data from the given command from the user. -673 * -674 * @param issuer -675 * The user who executed the tabcomplete. -676 * @param commandLabel -677 * The label which is being used by the user. -678 * @param args -679 * The arguments the user has typed so far. -680 * -681 * @return All possibilities in the tab complete. -682 */ -683 public List<String> tabComplete(CommandIssuer issuer, String commandLabel, String[] args) { -684 return tabComplete(issuer, commandLabel, args, false); -685 } -686 -687 /** -688 * Gets the tab complete suggestions from a given command. This will automatically find anything -689 * which is valid for the specified command through the command's implementation. -690 * -691 * @param issuer -692 * The issuer of the command. -693 * @param commandLabel -694 * The command name as entered by the user instead of the ACF registered name. -695 * @param args -696 * All arguments entered by the user. -697 * @param isAsync -698 * Whether this is run off of the main thread. -699 * -700 * @return The possibilities to tab complete in no particular order. -701 */ -702 @SuppressWarnings("WeakerAccess") -703 public List<String> tabComplete(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) -704 throws IllegalArgumentException { -705 -706 commandLabel = commandLabel.toLowerCase(); -707 if (args.length == 0) { -708 args = new String[]{""}; -709 } -710 try { -711 CommandOperationContext commandOperationContext = preCommandOperation(issuer, commandLabel, args, isAsync); -712 -713 final CommandSearch search = findSubCommand(args, true); +038import com.google.common.collect.SetMultimap; +039import org.jetbrains.annotations.Nullable; +040 +041import java.lang.reflect.Constructor; +042import java.lang.reflect.InvocationTargetException; +043import java.lang.reflect.Method; +044import java.lang.reflect.Parameter; +045import java.util.ArrayList; +046import java.util.Arrays; +047import java.util.Collections; +048import java.util.HashMap; +049import java.util.HashSet; +050import java.util.List; +051import java.util.Map; +052import java.util.Objects; +053import java.util.Optional; +054import java.util.Set; +055import java.util.Stack; +056import java.util.stream.Collectors; +057import java.util.stream.Stream; +058 +059/** +060 * A Base command is defined as a command group of related commands. +061 * A BaseCommand does not imply nor enforce that they use the same root command. +062 * +063 * It is up to the end user how to organize their command. you could use 1 base command per +064 * command in your application. +065 * +066 * Optionally (and encouraged), you can use the base command to represent a root command, and +067 * then each actionable command is a sub command +068 */ +069 +070@SuppressWarnings("unused") +071public abstract class BaseCommand { +072 +073 /** +074 * This is a field which contains the magic key in the {@link #subCommands} map for the method to catch any unknown +075 * argument to command states. +076 */ +077 static final String CATCHUNKNOWN = "__catchunknown"; +078 /** +079 * This is a field which contains the magic key in the {@link #subCommands} map for the method which is default for the +080 * entire base command. +081 */ +082 static final String DEFAULT = "__default"; +083 +084 /** +085 * A map of all the registered commands for this base command, keyed to each potential subcommand to access it. +086 */ +087 final SetMultimap<String, RegisteredCommand> subCommands = HashMultimap.create(); +088 +089 /** +090 * A map of flags to pass to Context Resolution for every parameter of the type. This is like an automatic @Flags on each. +091 */ +092 final Map<Class<?>, String> contextFlags = new HashMap<>(); +093 +094 /** +095 * What method was annoated with {@link PreCommand} to execute before commands. +096 */ +097 @Nullable private Method preCommandHandler; +098 +099 /** +100 * What root command the user actually entered to access the currently executing command +101 */ +102 @SuppressWarnings("WeakerAccess") +103 private String execLabel; +104 /** +105 * What subcommand the user actually entered to access the currently executing command +106 */ +107 @SuppressWarnings("WeakerAccess") +108 private String execSubcommand; +109 /** +110 * What arguments the user actually entered after the root command to access the currently executing command +111 */ +112 @SuppressWarnings("WeakerAccess") +113 private String[] origArgs; +114 +115 /** +116 * The manager this is registered to +117 */ +118 CommandManager<?, ?, ?, ?, ?, ?> manager = null; +119 +120 /** +121 * The command which owns this. This may be null if there are no owners. +122 */ +123 BaseCommand parentCommand; +124 Map<String, RootCommand> registeredCommands = new HashMap<>(); +125 /** +126 * The description of the command. This may be null if no description has been provided. +127 * Used for help documentation +128 */ +129 @Nullable String description; +130 /** +131 * The name of the command. This may be null if no name has been provided. +132 */ +133 @Nullable String commandName; +134 /** +135 * The permission of the command. This may be null if no permission has been provided. +136 */ +137 @Nullable String permission; +138 /** +139 * The conditions of the command. This may be null if no conditions has been provided. +140 */ +141 @Nullable String conditions; +142 /** +143 * Identifies if the command has an explicit help command annotated with {@link HelpCommand} +144 */ +145 boolean hasHelpCommand; +146 +147 /** +148 * The handler of all uncaught exceptions thrown by the user's command implementation. +149 */ +150 private ExceptionHandler exceptionHandler = null; +151 /** +152 * The last operative context data of this command. This may be null if this command hasn't been run yet. +153 */ +154 @Nullable CommandOperationContext lastCommandOperationContext; +155 /** +156 * If a parent exists to this command, and it has a Subcommand annotation, prefix all subcommands in this class with this +157 */ +158 @Nullable private String parentSubcommand; +159 +160 public BaseCommand() {} +161 +162 /** +163 * Constructor based defining of commands will be removed in the next version bump. +164 * @deprecated Please switch to {@link CommandAlias} for defining all root commands. +165 * @param cmd +166 */ +167 @Deprecated +168 public BaseCommand(@Nullable String cmd) { +169 this.commandName = cmd; +170 } +171 +172 /** +173 * Gets the root command name that the user actually typed +174 * @return Name +175 */ +176 public String getExecCommandLabel() { +177 return execLabel; +178 } +179 +180 /** +181 * Gets the actual sub command name the user typed +182 * @return Name +183 */ +184 public String getExecSubcommand() { +185 return execSubcommand; +186 } +187 +188 /** +189 * Gets the actual args in string form the user typed +190 * @return Args +191 */ +192 public String[] getOrigArgs() { +193 return origArgs; +194 } +195 +196 /** +197 * This should be called whenever the command gets registered. +198 * It sets all required fields correctly and injects dependencies. +199 * +200 * @param manager +201 * The manager to register as this command's owner and handler. +202 */ +203 void onRegister(CommandManager manager) { +204 onRegister(manager, this.commandName); +205 } +206 +207 /** +208 * This should be called whenever the command gets registered. +209 * It sets all required fields correctly and injects dependencies. +210 * +211 * @param manager +212 * The manager to register as this command's owner and handler. +213 * @param cmd +214 * The command name to use register with. +215 */ +216 private void onRegister(CommandManager manager, String cmd) { +217 manager.injectDependencies(this); +218 this.manager = manager; +219 +220 final Annotations annotations = manager.getAnnotations(); +221 final Class<? extends BaseCommand> self = this.getClass(); +222 +223 String[] cmdAliases = annotations.getAnnotationValues(self, CommandAlias.class, Annotations.REPLACEMENTS | Annotations.LOWERCASE | Annotations.NO_EMPTY); +224 +225 if (cmd == null && cmdAliases != null) { +226 cmd = cmdAliases[0]; +227 } +228 +229 this.commandName = cmd != null ? cmd : self.getSimpleName().toLowerCase(); +230 this.permission = annotations.getAnnotationValue(self, CommandPermission.class, Annotations.REPLACEMENTS); +231 this.description = this.commandName + " commands"; +232 this.parentSubcommand = getParentSubcommand(self); +233 this.conditions = annotations.getAnnotationValue(self, Conditions.class, Annotations.REPLACEMENTS | Annotations.NO_EMPTY); +234 +235 registerSubcommands(); +236 +237 if (cmdAliases != null) { +238 Set<String> cmdList = new HashSet<>(); +239 Collections.addAll(cmdList, cmdAliases); +240 cmdList.remove(cmd); +241 for (String cmdAlias : cmdList) { +242 register(cmdAlias, this); +243 } +244 } +245 +246 if (cmd != null) { +247 register(cmd, this); +248 } +249 registerSubclasses(cmd); +250 +251 } +252 +253 /** +254 * This recursively registers all subclasses of the command as subcommands, if they are of type {@link BaseCommand}. +255 * +256 * @param cmd +257 * The command name of this command. +258 */ +259 private void registerSubclasses(String cmd) { +260 for (Class<?> clazz : this.getClass().getDeclaredClasses()) { +261 if (BaseCommand.class.isAssignableFrom(clazz)) { +262 try { +263 BaseCommand subCommand = null; +264 Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors(); +265 for (Constructor<?> declaredConstructor : declaredConstructors) { +266 +267 declaredConstructor.setAccessible(true); +268 Parameter[] parameters = declaredConstructor.getParameters(); +269 if (parameters.length == 1) { +270 subCommand = (BaseCommand) declaredConstructor.newInstance(this); +271 } else { +272 manager.log(LogLevel.INFO, "Found unusable constructor: " + declaredConstructor.getName() + "(" + Stream.of(parameters).map(p -> p.getType().getSimpleName() + " " + p.getName()).collect(Collectors.joining("<c2>,</c2> ")) + ")"); +273 } +274 } +275 if (subCommand != null) { +276 subCommand.parentCommand = this; +277 subCommand.onRegister(manager, cmd); +278 this.subCommands.putAll(subCommand.subCommands); +279 this.registeredCommands.putAll(subCommand.registeredCommands); +280 } else { +281 this.manager.log(LogLevel.ERROR, "Could not find a subcommand ctor for " + clazz.getName()); +282 } +283 } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { +284 this.manager.log(LogLevel.ERROR, "Error registering subclass", e); +285 } +286 } +287 } +288 } +289 +290 /** +291 * This registers all subcommands of the command. +292 */ +293 private void registerSubcommands() { +294 final Annotations annotations = manager.getAnnotations(); +295 boolean foundDefault = false; +296 boolean foundCatchUnknown = false; +297 boolean isParentEmpty = parentSubcommand == null || parentSubcommand.isEmpty(); +298 +299 for (Method method : this.getClass().getMethods()) { +300 method.setAccessible(true); +301 String sublist = null; +302 String sub = getSubcommandValue(method); +303 final boolean def = annotations.hasAnnotation(method, Default.class); +304 final String helpCommand = annotations.getAnnotationValue(method, HelpCommand.class, Annotations.NOTHING); +305 final String commandAliases = annotations.getAnnotationValue(method, CommandAlias.class, Annotations.NOTHING); +306 +307 if (!isParentEmpty && def) { +308 sub = parentSubcommand; +309 } +310 if (isParentEmpty && (def || (!foundDefault && helpCommand != null))) { +311 if (!foundDefault) { +312 if (def) { +313 this.subCommands.get(DEFAULT).clear(); +314 foundDefault = true; +315 } +316 registerSubcommand(method, DEFAULT); +317 } else { +318 ACFUtil.sneaky(new IllegalStateException("Multiple @Default/@HelpCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName())); +319 } +320 } +321 +322 if (sub != null) { +323 sublist = sub; +324 } else if (commandAliases != null) { +325 sublist = commandAliases; +326 } else if (helpCommand != null) { +327 sublist = helpCommand; +328 hasHelpCommand = true; +329 } +330 +331 boolean preCommand = annotations.hasAnnotation(method, PreCommand.class); +332 boolean hasCatchUnknown = annotations.hasAnnotation(method, CatchUnknown.class) || +333 annotations.hasAnnotation(method, CatchAll.class) || +334 annotations.hasAnnotation(method, UnknownHandler.class); +335 +336 if (hasCatchUnknown || (!foundCatchUnknown && helpCommand != null)) { +337 if (!foundCatchUnknown) { +338 if (hasCatchUnknown) { +339 this.subCommands.get(CATCHUNKNOWN).clear(); +340 foundCatchUnknown = true; +341 } +342 registerSubcommand(method, CATCHUNKNOWN); +343 } else { +344 ACFUtil.sneaky(new IllegalStateException("Multiple @UnknownHandler/@HelpCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName())); +345 } +346 } else if (preCommand) { +347 if (this.preCommandHandler == null) { +348 this.preCommandHandler = method; +349 } else { +350 ACFUtil.sneaky(new IllegalStateException("Multiple @PreCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName())); +351 } +352 } +353 if (Objects.equals(method.getDeclaringClass(), this.getClass()) && sublist != null) { +354 registerSubcommand(method, sublist); +355 } +356 } +357 } +358 +359 /** +360 * Gets the subcommand name of the method given. +361 * +362 * @param method +363 * The method to check. +364 * +365 * @return The name of the subcommand. It returns null if the input doesn't have {@link Subcommand} attached. +366 */ +367 private String getSubcommandValue(Method method) { +368 final String sub = manager.getAnnotations().getAnnotationValue(method, Subcommand.class, Annotations.NOTHING); +369 if (sub == null) { +370 return null; +371 } +372 Class<?> clazz = method.getDeclaringClass(); +373 String parent = getParentSubcommand(clazz); +374 return parent == null || parent.isEmpty() ? sub : parent + " " + sub; +375 } +376 +377 private String getParentSubcommand(Class<?> clazz) { +378 List<String> subList = new ArrayList<>(); +379 while (clazz != null) { +380 String sub = manager.getAnnotations().getAnnotationValue(clazz, Subcommand.class, Annotations.NOTHING); +381 if (sub != null) { +382 subList.add(sub); +383 } +384 clazz = clazz.getEnclosingClass(); +385 } +386 Collections.reverse(subList); +387 return ACFUtil.join(subList, " "); +388 } +389 +390 /** +391 * Registers the given {@link BaseCommand cmd} as a child of the {@link RootCommand} linked to the name given. +392 * +393 * @param name +394 * Name of the parent to cmd. +395 * @param cmd +396 * The {@link BaseCommand} to add as a child to the {@link RootCommand} owned name field. +397 */ +398 private void register(String name, BaseCommand cmd) { +399 String nameLower = name.toLowerCase(); +400 RootCommand rootCommand = manager.obtainRootCommand(nameLower); +401 rootCommand.addChild(cmd); +402 +403 this.registeredCommands.put(nameLower, rootCommand); +404 } +405 +406 /** +407 * Registers the given {@link Method} as a subcommand. +408 * +409 * @param method +410 * The method to register as a subcommand. +411 * @param subCommand +412 * The subcommand's name(s). +413 */ +414 private void registerSubcommand(Method method, String subCommand) { +415 subCommand = manager.getCommandReplacements().replace(subCommand.toLowerCase()); +416 final String[] subCommandParts = ACFPatterns.SPACE.split(subCommand); +417 // Must run getSubcommandPossibility BEFORE we rewrite it just after this. +418 Set<String> cmdList = getSubCommandPossibilityList(subCommandParts); +419 +420 // Strip pipes off for auto complete addition +421 for (int i = 0; i < subCommandParts.length; i++) { +422 String[] split = ACFPatterns.PIPE.split(subCommandParts[i]); +423 if (split.length == 0 || split[0].isEmpty()) { +424 throw new IllegalArgumentException("Invalid @Subcommand configuration for " + method.getName() + " - parts can not start with | or be empty"); +425 } +426 subCommandParts[i] = split[0]; +427 } +428 String prefSubCommand = ApacheCommonsLangUtil.join(subCommandParts, " "); +429 final String[] aliasNames = manager.getAnnotations().getAnnotationValues(method, CommandAlias.class, Annotations.REPLACEMENTS | Annotations.LOWERCASE); +430 +431 String cmdName = aliasNames != null ? aliasNames[0] : this.commandName + " "; +432 RegisteredCommand cmd = manager.createRegisteredCommand(this, cmdName, method, prefSubCommand); +433 +434 for (String subcmd : cmdList) { +435 subCommands.put(subcmd, cmd); +436 } +437 cmd.addSubcommands(cmdList); +438 +439 if (aliasNames != null) { +440 for (String name : aliasNames) { +441 register(name, new ForwardingCommand(this, subCommandParts)); +442 } +443 } +444 } +445 +446 /** +447 * Takes a string like "foo|bar baz|qux" and generates a list of +448 * - foo baz +449 * - foo qux +450 * - bar baz +451 * - bar qux +452 * +453 * For every possible sub command combination +454 * +455 * @param subCommandParts +456 * @return List of all sub command possibilities +457 */ +458 private static Set<String> getSubCommandPossibilityList(String[] subCommandParts) { +459 int i = 0; +460 Set<String> current = null; +461 while (true) { +462 Set<String> newList = new HashSet<>(); +463 +464 if (i < subCommandParts.length) { +465 for (String s1 : ACFPatterns.PIPE.split(subCommandParts[i])) { +466 if (current != null) { +467 newList.addAll(current.stream().map(s -> s + " " + s1).collect(Collectors.toList())); +468 } else { +469 newList.add(s1); +470 } +471 } +472 } +473 +474 if (i + 1 < subCommandParts.length) { +475 current = newList; +476 i = i + 1; +477 continue; +478 } +479 +480 return newList; +481 } +482 } +483 +484 public void execute(CommandIssuer issuer, String commandLabel, String[] args) { +485 commandLabel = commandLabel.toLowerCase(); +486 try { +487 CommandOperationContext commandContext = preCommandOperation(issuer, commandLabel, args, false); +488 +489 if (args.length > 0) { +490 CommandSearch cmd = findSubCommand(args); +491 if (cmd != null) { +492 execSubcommand = cmd.getCheckSub(); +493 final String[] execargs = Arrays.copyOfRange(args, cmd.argIndex, args.length); +494 executeCommand(commandContext, issuer, execargs, cmd.cmd); +495 return; +496 } +497 } +498 +499 if (subCommands.get(DEFAULT) != null && args.length == 0) { +500 findAndExecuteCommand(commandContext, DEFAULT, issuer, args); +501 } else if (subCommands.get(CATCHUNKNOWN) != null) { +502 if (!findAndExecuteCommand(commandContext, CATCHUNKNOWN, issuer, args)) { +503 help(issuer, args); +504 } +505 } else if (subCommands.get(DEFAULT) != null) { +506 findAndExecuteCommand(commandContext, DEFAULT, issuer, args); +507 } +508 +509 } finally { +510 postCommandOperation(); +511 } +512 } +513 +514 /** +515 * Gets the registered command of the given arguments. +516 * @param args +517 * The arguments given by the user. +518 * +519 * @return The subcommand or null if none were found. +520 * +521 * @see #findSubCommand(String[]) +522 */ +523 RegisteredCommand<?> getRegisteredCommand(String[] args) { +524 final CommandSearch cmd = findSubCommand(args); +525 return cmd != null ? cmd.cmd : null; +526 } +527 +528 /** +529 * This is ran after any command operation has been performed. +530 */ +531 private void postCommandOperation() { +532 CommandManager.commandOperationContext.get().pop(); +533 execSubcommand = null; +534 execLabel = null; +535 origArgs = new String[]{}; +536 } +537 +538 /** +539 * This is ran before any command operation has been performed. +540 * +541 * @param issuer +542 * The user who executed the command. +543 * @param commandLabel +544 * The label the user used to execute the command. This is not the command name, but their input. +545 * When there is multiple aliases, this is which alias was used +546 * @param args +547 * The arguments passed to the command when executing it. +548 * @param isAsync +549 * Whether the command is executed off of the main thread. +550 * +551 * @return The context which is being registered to the {@link CommandManager}'s {@link +552 * CommandManager#commandOperationContext thread local stack}. +553 */ +554 private CommandOperationContext preCommandOperation(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) { +555 Stack<CommandOperationContext> contexts = CommandManager.commandOperationContext.get(); +556 CommandOperationContext context = this.manager.createCommandOperationContext(this, issuer, commandLabel, args, isAsync); +557 contexts.push(context); +558 lastCommandOperationContext = context; +559 execSubcommand = null; +560 execLabel = commandLabel; +561 origArgs = args; +562 return context; +563 } +564 +565 /** +566 * Gets the current command issuer. +567 * +568 * @return The current command issuer. +569 */ +570 public CommandIssuer getCurrentCommandIssuer() { +571 return CommandManager.getCurrentCommandIssuer(); +572 } +573 +574 /** +575 * Gets the current command manager. +576 * +577 * @return The current command manager. +578 */ +579 public CommandManager getCurrentCommandManager() { +580 return CommandManager.getCurrentCommandManager(); +581 } +582 +583 /** +584 * Finds a subcommand of the given arguments. +585 * +586 * @param args +587 * The arguments the user input. +588 * +589 * @return The identified subcommand. +590 * +591 * @see #findSubCommand(String[], boolean) +592 */ +593 private CommandSearch findSubCommand(String[] args) { +594 return findSubCommand(args, false); +595 } +596 +597 /** +598 * Finds a subcommand of the given arguments. +599 * +600 * @param args +601 * The arguments the user input. +602 * @param completion +603 * Whether or not completion of arguments should kick in. This may end up with worse than wanted results. +604 * +605 * @return The identified subcommand. +606 */ +607 private CommandSearch findSubCommand(String[] args, boolean completion) { +608 for (int i = args.length; i >= 0; i--) { +609 String checkSub = ApacheCommonsLangUtil.join(args, " ", 0, i).toLowerCase(); +610 Set<RegisteredCommand> cmds = subCommands.get(checkSub); +611 +612 final int extraArgs = args.length - i; +613 if (!cmds.isEmpty()) { +614 RegisteredCommand cmd = null; +615 if (cmds.size() == 1) { +616 cmd = ACFUtil.getFirstElement(cmds); +617 } else { +618 Optional<RegisteredCommand> optCmd = cmds.stream().filter(c -> { +619 int required = c.requiredResolvers; +620 int optional = c.optionalResolvers; +621 return extraArgs <= required + optional && (completion || extraArgs >= required); +622 }).min((c1, c2) -> { +623 int a = c1.consumeInputResolvers; +624 int b = c2.consumeInputResolvers; +625 +626 if (a == b) { +627 return 0; +628 } +629 return a < b ? 1 : -1; +630 }); +631 if (optCmd.isPresent()) { +632 cmd = optCmd.get(); +633 } +634 } +635 if (cmd != null) { +636 return new CommandSearch(cmd, i, checkSub); +637 } +638 } +639 } +640 return null; +641 } +642 +643 private void executeCommand(CommandOperationContext commandOperationContext, +644 CommandIssuer issuer, String[] args, RegisteredCommand cmd) { +645 if (cmd.hasPermission(issuer)) { +646 commandOperationContext.setRegisteredCommand(cmd); +647 if (checkPrecommand(commandOperationContext, cmd, issuer, args)) { +648 return; +649 } +650 List<String> sargs = Arrays.asList(args); +651 cmd.invoke(issuer, sargs, commandOperationContext); +652 } else { +653 issuer.sendMessage(MessageType.ERROR, MessageKeys.PERMISSION_DENIED); +654 } +655 } +656 +657 /** +658 * Please use command conditions for restricting execution +659 * @deprecated See {@link CommandConditions} +660 * @param issuer +661 * @param cmd +662 * @return +663 */ +664 @SuppressWarnings("DeprecatedIsStillUsed") +665 @Deprecated +666 public boolean canExecute(CommandIssuer issuer, RegisteredCommand<?> cmd) { +667 return true; +668 } +669 +670 /** +671 * Gets tab completed data from the given command from the user. +672 * +673 * @param issuer +674 * The user who executed the tabcomplete. +675 * @param commandLabel +676 * The label which is being used by the user. +677 * @param args +678 * The arguments the user has typed so far. +679 * +680 * @return All possibilities in the tab complete. +681 */ +682 public List<String> tabComplete(CommandIssuer issuer, String commandLabel, String[] args) { +683 return tabComplete(issuer, commandLabel, args, false); +684 } +685 +686 /** +687 * Gets the tab complete suggestions from a given command. This will automatically find anything +688 * which is valid for the specified command through the command's implementation. +689 * +690 * @param issuer +691 * The issuer of the command. +692 * @param commandLabel +693 * The command name as entered by the user instead of the ACF registered name. +694 * @param args +695 * All arguments entered by the user. +696 * @param isAsync +697 * Whether this is run off of the main thread. +698 * +699 * @return The possibilities to tab complete in no particular order. +700 */ +701 @SuppressWarnings("WeakerAccess") +702 public List<String> tabComplete(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) +703 throws IllegalArgumentException { +704 +705 commandLabel = commandLabel.toLowerCase(); +706 if (args.length == 0) { +707 args = new String[]{""}; +708 } +709 try { +710 CommandOperationContext commandOperationContext = preCommandOperation(issuer, commandLabel, args, isAsync); +711 +712 final CommandSearch search = findSubCommand(args, true); +713 714 -715 -716 final List<String> cmds = new ArrayList<>(); -717 -718 if (search != null) { -719 cmds.addAll(completeCommand(issuer, search.cmd, Arrays.copyOfRange(args, search.argIndex, args.length), commandLabel, isAsync)); -720 } else if (subCommands.get(CATCHUNKNOWN).size() == 1) { -721 cmds.addAll(completeCommand(issuer, Iterables.getOnlyElement(subCommands.get(CATCHUNKNOWN)), args, commandLabel, isAsync)); -722 } else if (subCommands.get(DEFAULT).size() == 1) { -723 cmds.addAll(completeCommand(issuer, Iterables.getOnlyElement(subCommands.get(DEFAULT)), args, commandLabel, isAsync)); -724 } -725 -726 return filterTabComplete(args[args.length - 1], cmds); -727 } finally { -728 postCommandOperation(); -729 } -730 } -731 -732 /** -733 * Gets all subcommands which are possible to tabcomplete. -734 * -735 * @param issuer -736 * The command issuer. -737 * @param args -738 * -739 * @return -740 */ -741 List<String> getCommandsForCompletion(CommandIssuer issuer, String[] args) { -742 final Set<String> cmds = new HashSet<>(); -743 final int cmdIndex = Math.max(0, args.length - 1); -744 String argString = ApacheCommonsLangUtil.join(args, " ").toLowerCase(); -745 for (Map.Entry<String, RegisteredCommand> entry : subCommands.entries()) { -746 final String key = entry.getKey(); -747 if (key.startsWith(argString) && !CATCHUNKNOWN.equals(key) && !DEFAULT.equals(key)) { -748 final RegisteredCommand value = entry.getValue(); -749 if (!value.hasPermission(issuer) || value.isPrivate) { -750 continue; -751 } -752 -753 String[] split = ACFPatterns.SPACE.split(value.prefSubCommand); -754 cmds.add(split[cmdIndex]); -755 } -756 } -757 return new ArrayList<>(cmds); -758 } -759 -760 /** -761 * Complete a command properly per issuer and input. -762 * -763 * @param issuer -764 * The user who executed this. -765 * @param cmd -766 * The command to be completed. -767 * @param args -768 * All arguments given by the user. -769 * @param commandLabel -770 * The command name the user used. -771 * @param isAsync -772 * Whether the command was executed async. -773 * -774 * @return All results to complete the command. -775 */ -776 private List<String> completeCommand(CommandIssuer issuer, RegisteredCommand cmd, String[] args, String commandLabel, boolean isAsync) { -777 if (!cmd.hasPermission(issuer) || args.length > cmd.consumeInputResolvers || args.length == 0 || cmd.complete == null) { -778 return Collections.emptyList(); -779 } -780 -781 List<String> cmds = manager.getCommandCompletions().of(cmd, issuer, args, isAsync); -782 return filterTabComplete(args[args.length-1], cmds); -783 } -784 -785 /** -786 * Gets the actual args in string form the user typed -787 * This returns a list of all tab complete options which are possible with the given argument and commands. -788 * @param arg -789 * Argument which was pressed tab on. -790 * @param cmds -791 * The possibilities to return. -792 * -793 * @return All possible options. This may be empty. -794 */ -795 private static List<String> filterTabComplete(String arg, List<String> cmds) { -796 return cmds.stream() -797 .distinct() -798 .filter(cmd -> cmd != null && (arg.isEmpty() || ApacheCommonsLangUtil.startsWithIgnoreCase(cmd, arg))) -799 .collect(Collectors.toList()); -800 } -801 -802 /** -803 * Gets a registered command under the given subcommand name. -804 * -805 * @param subcommand -806 * The name of the subcommand requested. -807 * -808 * @return The subcommand found or null if none. -809 */ -810 private RegisteredCommand getCommandBySubcommand(String subcommand) { -811 return getCommandBySubcommand(subcommand, false); -812 } -813 -814 /** -815 * Gets a registered command under the given name. -816 * If requireOne is true, it won't accept more than a single matching subcommand. -817 * -818 * @param subcommand -819 * Name of the subcommand wanted. -820 * @param requireOne -821 * Whether to only accept 1 result. -822 * -823 * @return The subcommand found, or null if none/too many. -824 */ -825 private RegisteredCommand getCommandBySubcommand(String subcommand, boolean requireOne) { -826 final Set<RegisteredCommand> commands = subCommands.get(subcommand); -827 if (!commands.isEmpty() && (!requireOne || commands.size() == 1)) { -828 return commands.iterator().next(); -829 } -830 return null; -831 } -832 -833 /** -834 * Internally calls {@link #executeCommand(CommandOperationContext, CommandIssuer, String[], RegisteredCommand)} -835 * and gets through {@link #getCommandBySubcommand(String)}. -836 * -837 * @param commandContext -838 * The command context to use. -839 * @param subcommand -840 * The subcommand to find the executor of. -841 * @param issuer -842 * The issuer who executed the subcommand. -843 * @param args -844 * All arguments given by the issuer. -845 * -846 * @return Whether it found a command or not. -847 * -848 * @see #executeCommand(CommandOperationContext, CommandIssuer, String[], RegisteredCommand) -849 * @see #getCommandBySubcommand(String) -850 * @see RegisteredCommand#invoke(CommandIssuer, List, CommandOperationContext) -851 */ -852 private boolean findAndExecuteCommand(CommandOperationContext commandContext, String subcommand, CommandIssuer issuer, String... args) { -853 final RegisteredCommand cmd = this.getCommandBySubcommand(subcommand); -854 if (cmd != null) { -855 executeCommand(commandContext, issuer, args, cmd); -856 return true; -857 } -858 -859 return false; -860 } -861 -862 /** -863 * Executes the precommand and sees whether something is wrong. Ideally, you get false from this. -864 * -865 * @param commandOperationContext -866 * The context to use. -867 * @param cmd -868 * The command executed. -869 * @param issuer -870 * The issuer who executed the command. -871 * @param args -872 * The arguments the issuer provided. -873 * -874 * @return Whether something went wrong. -875 */ -876 private boolean checkPrecommand(CommandOperationContext commandOperationContext, RegisteredCommand cmd, CommandIssuer issuer, String[] args) { -877 Method pre = this.preCommandHandler; -878 if (pre != null) { -879 try { -880 Class<?>[] types = pre.getParameterTypes(); -881 Object[] parameters = new Object[pre.getParameterCount()]; -882 for (int i = 0; i < parameters.length; i++) { -883 Class<?> type = types[i]; -884 Object issuerObject = issuer.getIssuer(); -885 if (manager.isCommandIssuer(type) && type.isAssignableFrom(issuerObject.getClass())) { -886 parameters[i] = issuerObject; -887 } else if (CommandIssuer.class.isAssignableFrom(type)) { -888 parameters[i] = issuer; -889 } else if (RegisteredCommand.class.isAssignableFrom(type)) { -890 parameters[i] = cmd; -891 } else if (String[].class.isAssignableFrom((type))) { -892 parameters[i] = args; -893 } else { -894 parameters[i] = null; -895 } -896 } -897 -898 return (boolean) pre.invoke(this, parameters); -899 } catch (IllegalAccessException | InvocationTargetException e) { -900 this.manager.log(LogLevel.ERROR, "Exception encountered while command pre-processing", e); -901 } -902 } -903 return false; -904 } -905 -906 /** @deprecated Unstable API */ @Deprecated @UnstableAPI -907 public CommandHelp getCommandHelp() { -908 return manager.generateCommandHelp(); -909 } -910 -911 /** @deprecated Unstable API */ @Deprecated @UnstableAPI -912 public void showCommandHelp() { -913 getCommandHelp().showHelp(); -914 } -915 -916 public void help(Object issuer, String[] args) { -917 help(manager.getCommandIssuer(issuer), args); -918 } -919 public void help(CommandIssuer issuer, String[] args) { -920 issuer.sendMessage(MessageType.ERROR, MessageKeys.UNKNOWN_COMMAND); -921 } -922 public void doHelp(Object issuer, String... args) { -923 doHelp(manager.getCommandIssuer(issuer), args); -924 } -925 public void doHelp(CommandIssuer issuer, String... args) { -926 help(issuer, args); -927 } -928 -929 public void showSyntax(CommandIssuer issuer, RegisteredCommand<?> cmd) { -930 issuer.sendMessage(MessageType.SYNTAX, MessageKeys.INVALID_SYNTAX, -931 "{command}", manager.getCommandPrefix(issuer) + cmd.command, -932 "{syntax}", cmd.syntaxText -933 ); -934 } -935 -936 public boolean hasPermission(Object issuer) { -937 return hasPermission(manager.getCommandIssuer(issuer)); -938 } -939 -940 public boolean hasPermission(CommandIssuer issuer) { -941 return permission == null || permission.isEmpty() || (manager.hasPermission(issuer, permission) && (parentCommand == null || parentCommand.hasPermission(issuer))); -942 } +715 final List<String> cmds = new ArrayList<>(); +716 +717 if (search != null) { +718 cmds.addAll(completeCommand(issuer, search.cmd, Arrays.copyOfRange(args, search.argIndex, args.length), commandLabel, isAsync)); +719 } else if (subCommands.get(CATCHUNKNOWN).size() == 1) { +720 cmds.addAll(completeCommand(issuer, ACFUtil.getFirstElement(subCommands.get(CATCHUNKNOWN)), args, commandLabel, isAsync)); +721 } else if (subCommands.get(DEFAULT).size() == 1) { +722 cmds.addAll(completeCommand(issuer, ACFUtil.getFirstElement(subCommands.get(DEFAULT)), args, commandLabel, isAsync)); +723 } +724 +725 return filterTabComplete(args[args.length - 1], cmds); +726 } finally { +727 postCommandOperation(); +728 } +729 } +730 +731 /** +732 * Gets all subcommands which are possible to tabcomplete. +733 * +734 * @param issuer +735 * The command issuer. +736 * @param args +737 * +738 * @return +739 */ +740 List<String> getCommandsForCompletion(CommandIssuer issuer, String[] args) { +741 final Set<String> cmds = new HashSet<>(); +742 final int cmdIndex = Math.max(0, args.length - 1); +743 String argString = ApacheCommonsLangUtil.join(args, " ").toLowerCase(); +744 for (Map.Entry<String, RegisteredCommand> entry : subCommands.entries()) { +745 final String key = entry.getKey(); +746 if (key.startsWith(argString) && !CATCHUNKNOWN.equals(key) && !DEFAULT.equals(key)) { +747 final RegisteredCommand value = entry.getValue(); +748 if (!value.hasPermission(issuer) || value.isPrivate) { +749 continue; +750 } +751 +752 String[] split = ACFPatterns.SPACE.split(value.prefSubCommand); +753 cmds.add(split[cmdIndex]); +754 } +755 } +756 return new ArrayList<>(cmds); +757 } +758 +759 /** +760 * Complete a command properly per issuer and input. +761 * +762 * @param issuer +763 * The user who executed this. +764 * @param cmd +765 * The command to be completed. +766 * @param args +767 * All arguments given by the user. +768 * @param commandLabel +769 * The command name the user used. +770 * @param isAsync +771 * Whether the command was executed async. +772 * +773 * @return All results to complete the command. +774 */ +775 private List<String> completeCommand(CommandIssuer issuer, RegisteredCommand cmd, String[] args, String commandLabel, boolean isAsync) { +776 if (!cmd.hasPermission(issuer) || args.length > cmd.consumeInputResolvers || args.length == 0 || cmd.complete == null) { +777 return Collections.emptyList(); +778 } +779 +780 List<String> cmds = manager.getCommandCompletions().of(cmd, issuer, args, isAsync); +781 return filterTabComplete(args[args.length-1], cmds); +782 } +783 +784 /** +785 * Gets the actual args in string form the user typed +786 * This returns a list of all tab complete options which are possible with the given argument and commands. +787 * @param arg +788 * Argument which was pressed tab on. +789 * @param cmds +790 * The possibilities to return. +791 * +792 * @return All possible options. This may be empty. +793 */ +794 private static List<String> filterTabComplete(String arg, List<String> cmds) { +795 return cmds.stream() +796 .distinct() +797 .filter(cmd -> cmd != null && (arg.isEmpty() || ApacheCommonsLangUtil.startsWithIgnoreCase(cmd, arg))) +798 .collect(Collectors.toList()); +799 } +800 +801 /** +802 * Gets a registered command under the given subcommand name. +803 * +804 * @param subcommand +805 * The name of the subcommand requested. +806 * +807 * @return The subcommand found or null if none. +808 */ +809 private RegisteredCommand getCommandBySubcommand(String subcommand) { +810 return getCommandBySubcommand(subcommand, false); +811 } +812 +813 /** +814 * Gets a registered command under the given name. +815 * If requireOne is true, it won't accept more than a single matching subcommand. +816 * +817 * @param subcommand +818 * Name of the subcommand wanted. +819 * @param requireOne +820 * Whether to only accept 1 result. +821 * +822 * @return The subcommand found, or null if none/too many. +823 */ +824 private RegisteredCommand getCommandBySubcommand(String subcommand, boolean requireOne) { +825 final Set<RegisteredCommand> commands = subCommands.get(subcommand); +826 if (!commands.isEmpty() && (!requireOne || commands.size() == 1)) { +827 return commands.iterator().next(); +828 } +829 return null; +830 } +831 +832 /** +833 * Internally calls {@link #executeCommand(CommandOperationContext, CommandIssuer, String[], RegisteredCommand)} +834 * and gets through {@link #getCommandBySubcommand(String)}. +835 * +836 * @param commandContext +837 * The command context to use. +838 * @param subcommand +839 * The subcommand to find the executor of. +840 * @param issuer +841 * The issuer who executed the subcommand. +842 * @param args +843 * All arguments given by the issuer. +844 * +845 * @return Whether it found a command or not. +846 * +847 * @see #executeCommand(CommandOperationContext, CommandIssuer, String[], RegisteredCommand) +848 * @see #getCommandBySubcommand(String) +849 * @see RegisteredCommand#invoke(CommandIssuer, List, CommandOperationContext) +850 */ +851 private boolean findAndExecuteCommand(CommandOperationContext commandContext, String subcommand, CommandIssuer issuer, String... args) { +852 final RegisteredCommand cmd = this.getCommandBySubcommand(subcommand); +853 if (cmd != null) { +854 executeCommand(commandContext, issuer, args, cmd); +855 return true; +856 } +857 +858 return false; +859 } +860 +861 /** +862 * Executes the precommand and sees whether something is wrong. Ideally, you get false from this. +863 * +864 * @param commandOperationContext +865 * The context to use. +866 * @param cmd +867 * The command executed. +868 * @param issuer +869 * The issuer who executed the command. +870 * @param args +871 * The arguments the issuer provided. +872 * +873 * @return Whether something went wrong. +874 */ +875 private boolean checkPrecommand(CommandOperationContext commandOperationContext, RegisteredCommand cmd, CommandIssuer issuer, String[] args) { +876 Method pre = this.preCommandHandler; +877 if (pre != null) { +878 try { +879 Class<?>[] types = pre.getParameterTypes(); +880 Object[] parameters = new Object[pre.getParameterCount()]; +881 for (int i = 0; i < parameters.length; i++) { +882 Class<?> type = types[i]; +883 Object issuerObject = issuer.getIssuer(); +884 if (manager.isCommandIssuer(type) && type.isAssignableFrom(issuerObject.getClass())) { +885 parameters[i] = issuerObject; +886 } else if (CommandIssuer.class.isAssignableFrom(type)) { +887 parameters[i] = issuer; +888 } else if (RegisteredCommand.class.isAssignableFrom(type)) { +889 parameters[i] = cmd; +890 } else if (String[].class.isAssignableFrom((type))) { +891 parameters[i] = args; +892 } else { +893 parameters[i] = null; +894 } +895 } +896 +897 return (boolean) pre.invoke(this, parameters); +898 } catch (IllegalAccessException | InvocationTargetException e) { +899 this.manager.log(LogLevel.ERROR, "Exception encountered while command pre-processing", e); +900 } +901 } +902 return false; +903 } +904 +905 /** @deprecated Unstable API */ @Deprecated @UnstableAPI +906 public CommandHelp getCommandHelp() { +907 return manager.generateCommandHelp(); +908 } +909 +910 /** @deprecated Unstable API */ @Deprecated @UnstableAPI +911 public void showCommandHelp() { +912 getCommandHelp().showHelp(); +913 } +914 +915 public void help(Object issuer, String[] args) { +916 help(manager.getCommandIssuer(issuer), args); +917 } +918 public void help(CommandIssuer issuer, String[] args) { +919 issuer.sendMessage(MessageType.ERROR, MessageKeys.UNKNOWN_COMMAND); +920 } +921 public void doHelp(Object issuer, String... args) { +922 doHelp(manager.getCommandIssuer(issuer), args); +923 } +924 public void doHelp(CommandIssuer issuer, String... args) { +925 help(issuer, args); +926 } +927 +928 public void showSyntax(CommandIssuer issuer, RegisteredCommand<?> cmd) { +929 issuer.sendMessage(MessageType.SYNTAX, MessageKeys.INVALID_SYNTAX, +930 "{command}", manager.getCommandPrefix(issuer) + cmd.command, +931 "{syntax}", cmd.syntaxText +932 ); +933 } +934 +935 public boolean hasPermission(Object issuer) { +936 return hasPermission(manager.getCommandIssuer(issuer)); +937 } +938 +939 public boolean hasPermission(CommandIssuer issuer) { +940 return permission == null || permission.isEmpty() || (manager.hasPermission(issuer, permission) && (parentCommand == null || parentCommand.hasPermission(issuer))); +941 } +942 943 -944 -945 public Set<String> getRequiredPermissions() { -946 if (this.permission == null || this.permission.isEmpty()) { -947 return Collections.emptySet(); -948 } -949 return new HashSet<>(Arrays.asList(ACFPatterns.COMMA.split(this.permission))); -950 } -951 -952 public boolean requiresPermission(String permission) { -953 return getRequiredPermissions().contains(permission) || this.parentCommand != null && parentCommand.requiresPermission(permission); -954 } -955 -956 public String getName() { -957 return commandName; -958 } -959 -960 public ExceptionHandler getExceptionHandler() { -961 return exceptionHandler; -962 } -963 -964 public BaseCommand setExceptionHandler(ExceptionHandler exceptionHandler) { -965 this.exceptionHandler = exceptionHandler; -966 return this; -967 } -968 -969 public RegisteredCommand getDefaultRegisteredCommand() { -970 return this.getCommandBySubcommand(DEFAULT); -971 } -972 -973 public String setContextFlags(Class<?> cls, String flags) { -974 return this.contextFlags.put(cls, flags); -975 } -976 -977 public String getContextFlags(Class<?> cls) { -978 return this.contextFlags.get(cls); -979 } -980 -981 private static class CommandSearch { RegisteredCommand cmd; int argIndex; String checkSub; -982 -983 CommandSearch(RegisteredCommand cmd, int argIndex, String checkSub) { -984 this.cmd = cmd; -985 this.argIndex = argIndex; -986 this.checkSub = checkSub; -987 } -988 -989 String getCheckSub() { -990 return this.checkSub; -991 } -992 -993 @Override -994 public boolean equals(Object o) { -995 if (this == o) return true; -996 if (o == null || getClass() != o.getClass()) return false; -997 CommandSearch that = (CommandSearch) o; -998 return argIndex == that.argIndex && -999 Objects.equals(cmd, that.cmd) && -1000 Objects.equals(checkSub, that.checkSub); -1001 } -1002 -1003 @Override -1004 public int hashCode() { -1005 return Objects.hash(cmd, argIndex, checkSub); -1006 } -1007 } -1008} +944 public Set<String> getRequiredPermissions() { +945 if (this.permission == null || this.permission.isEmpty()) { +946 return Collections.emptySet(); +947 } +948 return new HashSet<>(Arrays.asList(ACFPatterns.COMMA.split(this.permission))); +949 } +950 +951 public boolean requiresPermission(String permission) { +952 return getRequiredPermissions().contains(permission) || this.parentCommand != null && parentCommand.requiresPermission(permission); +953 } +954 +955 public String getName() { +956 return commandName; +957 } +958 +959 public ExceptionHandler getExceptionHandler() { +960 return exceptionHandler; +961 } +962 +963 public BaseCommand setExceptionHandler(ExceptionHandler exceptionHandler) { +964 this.exceptionHandler = exceptionHandler; +965 return this; +966 } +967 +968 public RegisteredCommand getDefaultRegisteredCommand() { +969 return this.getCommandBySubcommand(DEFAULT); +970 } +971 +972 public String setContextFlags(Class<?> cls, String flags) { +973 return this.contextFlags.put(cls, flags); +974 } +975 +976 public String getContextFlags(Class<?> cls) { +977 return this.contextFlags.get(cls); +978 } +979 +980 private static class CommandSearch { RegisteredCommand cmd; int argIndex; String checkSub; +981 +982 CommandSearch(RegisteredCommand cmd, int argIndex, String checkSub) { +983 this.cmd = cmd; +984 this.argIndex = argIndex; +985 this.checkSub = checkSub; +986 } +987 +988 String getCheckSub() { +989 return this.checkSub; +990 } +991 +992 @Override +993 public boolean equals(Object o) { +994 if (this == o) return true; +995 if (o == null || getClass() != o.getClass()) return false; +996 CommandSearch that = (CommandSearch) o; +997 return argIndex == that.argIndex && +998 Objects.equals(cmd, that.cmd) && +999 Objects.equals(checkSub, that.checkSub); +1000 } +1001 +1002 @Override +1003 public int hashCode() { +1004 return Objects.hash(cmd, argIndex, checkSub); +1005 } +1006 } +1007} diff --git a/docs/acf-jda/src-html/co/aikar/commands/JDACommandPermissionResolver.html b/docs/acf-jda/src-html/co/aikar/commands/JDACommandPermissionResolver.html index 3a9bba31..be04dfb4 100644 --- a/docs/acf-jda/src-html/co/aikar/commands/JDACommandPermissionResolver.html +++ b/docs/acf-jda/src-html/co/aikar/commands/JDACommandPermissionResolver.html @@ -30,16 +30,21 @@ 022 return true; 023 } 024 -025 Integer permissionOffset = discordPermissionOffsets.get(permission); -026 if (permissionOffset == null) { +025 // Return false on webhook messages, as they cannot have permissions defined. +026 if (event.getIssuer().isWebhookMessage()) { 027 return false; 028 } 029 -030 return event.getIssuer().getMember().hasPermission( -031 Permission.getFromOffset(permissionOffset) -032 ); -033 } -034} +030 Integer permissionOffset = discordPermissionOffsets.get(permission); +031 if (permissionOffset == null) { +032 return false; +033 } +034 +035 return event.getIssuer().getMember().hasPermission( +036 Permission.getFromOffset(permissionOffset) +037 ); +038 } +039} diff --git a/docs/acf-sponge/co/aikar/commands/ACFSpongeUtil.html b/docs/acf-sponge/co/aikar/commands/ACFSpongeUtil.html index b1421d66..4263da0e 100644 --- a/docs/acf-sponge/co/aikar/commands/ACFSpongeUtil.html +++ b/docs/acf-sponge/co/aikar/commands/ACFSpongeUtil.html @@ -108,7 +108,7 @@ var activeTableTab = "activeTableTab";- @@ -186,7 +186,7 @@ extends
-public class ACFSpongeUtil +public class ACFSpongeUtil extends ObjectACFSpongeUtil
-public ACFSpongeUtil()+public ACFSpongeUtil()- @@ -213,7 +213,7 @@ extends
findPlayerSmart
-public static org.spongepowered.api.entity.living.player.Player findPlayerSmart(co.aikar.commands.CommandIssuer issuer, +public static org.spongepowered.api.entity.living.player.Player findPlayerSmart(co.aikar.commands.CommandIssuer issuer, String search)- @@ -222,7 +222,7 @@ extends
matchPlayer
-public static List<org.spongepowered.api.entity.living.player.Player> matchPlayer(String partialName)+public static List<org.spongepowered.api.entity.living.player.Player> matchPlayer(String partialName)isValidName
-public static boolean isValidName(String name)+public static boolean isValidName(String name)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); +003import org.spongepowered.api.Sponge; +004import org.spongepowered.api.command.CommandSource; +005import org.spongepowered.api.entity.living.player.Player; +006 +007import java.util.ArrayList; +008import java.util.Iterator; +009import java.util.List; +010import java.util.stream.Collectors; +011 +012@SuppressWarnings("WeakerAccess") +013public class ACFSpongeUtil { +014 public static Player findPlayerSmart(CommandIssuer issuer, String search) { +015 CommandSource requester = issuer.getIssuer(); +016 if (search == null) { +017 return null; +018 } +019 String name = ACFUtil.replace(search, ":confirm", ""); +020 if (name.length() < 3) { +021 issuer.sendError(MinecraftMessageKeys.USERNAME_TOO_SHORT); +022 return null; +023 } +024 if (!isValidName(name)) { +025 issuer.sendError(MinecraftMessageKeys.IS_NOT_A_VALID_NAME, "{name}", name); +026 return null; +027 } +028 +029 List<Player> matches = matchPlayer(name); +030 List<Player> confirmList = new ArrayList<>(); +031 findMatches(search, requester, matches, confirmList); +032 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} +034 if (matches.size() > 1 || confirmList.size() > 1) { +035 String allMatches = matches.stream().map(Player::getName).collect(Collectors.joining(", ")); +036 issuer.sendError(MinecraftMessageKeys.MULTIPLE_PLAYERS_MATCH, +037 "{search}", name, "{all}", allMatches); +038 return null; +039 } +040 +041 if (matches.isEmpty()) { +042 if (confirmList.isEmpty()) { +043 issuer.sendError(MinecraftMessageKeys.NO_PLAYER_FOUND_SERVER, +044 "{search}", name); +045 return null; +046 } else { +047 Player player = ACFUtil.getFirstElement(confirmList); +048 issuer.sendInfo(MinecraftMessageKeys.PLAYER_IS_VANISHED_CONFIRM, "{vanished}", player.getName()); +049 return null; +050 } +051 } +052 +053 return matches.get(0); +054 } +055 +056 private static void findMatches(String search, CommandSource requester, List<Player> matches, List<Player> confirmList) { +057 // Remove vanished players from smart matching. +058 Iterator<Player> iter = matches.iterator(); +059 //noinspection Duplicates +060 while (iter.hasNext()) { +061 Player player = iter.next(); +062 if (requester instanceof Player && !((Player) requester).canSee(player)) { +063 if (requester.hasPermission("acf.seevanish")) { +064 if (!search.endsWith(":confirm")) { +065 confirmList.add(player); +066 iter.remove(); +067 } +068 } else { +069 iter.remove(); +070 } +071 } +072 } +073 } +074 +075 public static List<Player> matchPlayer(String partialName) { +076 List<Player> matchedPlayers = new ArrayList<>(); +077 +078 for (Player iterPlayer : Sponge.getServer().getOnlinePlayers()) { +079 String iterPlayerName = iterPlayer.getName(); +080 +081 if (partialName.equalsIgnoreCase(iterPlayerName)) { +082 // Exact match +083 matchedPlayers.clear(); +084 matchedPlayers.add(iterPlayer); +085 break; +086 } +087 if (iterPlayerName.toLowerCase(java.util.Locale.ENGLISH).contains(partialName.toLowerCase(java.util.Locale.ENGLISH))) { +088 // Partial match +089 matchedPlayers.add(iterPlayer); +090 } +091 } +092 +093 return matchedPlayers; +094 } +095 +096 public static boolean isValidName(String name) { +097 return name != null && !name.isEmpty() && ACFPatterns.VALID_NAME_PATTERN.matcher(name).matches(); +098 } +099 +100}