diff --git a/.gitignore b/.gitignore
index 87aa62d3..dcaa91a9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,7 @@
-*
-!src
-!build.gradle
-!settings.gradle
\ No newline at end of file
+.gradle
+.idea
+build
+libs
+*.iml
+*.ipr
+*.iws
diff --git a/README.md b/README.md
index 353f4646..bb2734f7 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,9 @@ A disguise plugin made by libraryaddict which is pretty cool.
NOTE: These versions will NOT work with Spigot 1.8.8 and before.
+Spigot page: Link
+
+
When posting an issue:
Please make sure you
1) Post a stack trace error, if no stack trace, then post the odd behavior
diff --git a/src/main/java/me/libraryaddict/disguise/LibsDisguises.java b/src/main/java/me/libraryaddict/disguise/LibsDisguises.java
index 9d7587e3..d1493643 100644
--- a/src/main/java/me/libraryaddict/disguise/LibsDisguises.java
+++ b/src/main/java/me/libraryaddict/disguise/LibsDisguises.java
@@ -3,14 +3,14 @@ package me.libraryaddict.disguise;
import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
-import me.libraryaddict.disguise.commands.DisguiseCloneCommand;
+import me.libraryaddict.disguise.commands.CloneDisguiseCommand;
import me.libraryaddict.disguise.commands.DisguiseCommand;
-import me.libraryaddict.disguise.commands.DisguiseEntityCommand;
-import me.libraryaddict.disguise.commands.DisguiseHelpCommand;
-import me.libraryaddict.disguise.commands.DisguisePlayerCommand;
-import me.libraryaddict.disguise.commands.DisguiseRadiusCommand;
import me.libraryaddict.disguise.commands.DisguiseViewSelf;
+import me.libraryaddict.disguise.commands.EntityDisguiseCommand;
+import me.libraryaddict.disguise.commands.HelpDisguiseCommand;
import me.libraryaddict.disguise.commands.LibsDisguisesCommand;
+import me.libraryaddict.disguise.commands.PlayerDisguiseCommand;
+import me.libraryaddict.disguise.commands.RadiusDisguiseCommand;
import me.libraryaddict.disguise.commands.UndisguiseCommand;
import me.libraryaddict.disguise.commands.UndisguiseEntityCommand;
import me.libraryaddict.disguise.commands.UndisguisePlayerCommand;
@@ -64,14 +64,14 @@ public class LibsDisguises extends JavaPlugin {
Bukkit.getPluginManager().registerEvents(listener, this);
getCommand("disguise").setExecutor(new DisguiseCommand());
getCommand("undisguise").setExecutor(new UndisguiseCommand());
- getCommand("disguiseplayer").setExecutor(new DisguisePlayerCommand());
+ getCommand("disguiseplayer").setExecutor(new PlayerDisguiseCommand());
getCommand("undisguiseplayer").setExecutor(new UndisguisePlayerCommand());
getCommand("undisguiseentity").setExecutor(new UndisguiseEntityCommand());
- getCommand("disguiseentity").setExecutor(new DisguiseEntityCommand());
- getCommand("disguiseradius").setExecutor(new DisguiseRadiusCommand(getConfig().getInt("DisguiseRadiusMax")));
+ getCommand("disguiseentity").setExecutor(new EntityDisguiseCommand());
+ getCommand("disguiseradius").setExecutor(new RadiusDisguiseCommand(getConfig().getInt("DisguiseRadiusMax")));
getCommand("undisguiseradius").setExecutor(new UndisguiseRadiusCommand(getConfig().getInt("UndisguiseRadiusMax")));
- getCommand("disguisehelp").setExecutor(new DisguiseHelpCommand());
- getCommand("disguiseclone").setExecutor(new DisguiseCloneCommand());
+ getCommand("disguisehelp").setExecutor(new HelpDisguiseCommand());
+ getCommand("disguiseclone").setExecutor(new CloneDisguiseCommand());
getCommand("libsdisguises").setExecutor(new LibsDisguisesCommand());
getCommand("disguiseviewself").setExecutor(new DisguiseViewSelf());
registerValues();
diff --git a/src/main/java/me/libraryaddict/disguise/commands/BaseDisguiseCommand.java b/src/main/java/me/libraryaddict/disguise/commands/BaseDisguiseCommand.java
new file mode 100644
index 00000000..b17a2502
--- /dev/null
+++ b/src/main/java/me/libraryaddict/disguise/commands/BaseDisguiseCommand.java
@@ -0,0 +1,765 @@
+package me.libraryaddict.disguise.commands;
+
+import me.libraryaddict.disguise.disguisetypes.AnimalColor;
+import me.libraryaddict.disguise.disguisetypes.Disguise;
+import me.libraryaddict.disguise.disguisetypes.DisguiseType;
+import me.libraryaddict.disguise.disguisetypes.FlagWatcher;
+import me.libraryaddict.disguise.disguisetypes.MiscDisguise;
+import me.libraryaddict.disguise.disguisetypes.MobDisguise;
+import me.libraryaddict.disguise.disguisetypes.PlayerDisguise;
+import me.libraryaddict.disguise.disguisetypes.RabbitType;
+import me.libraryaddict.disguise.utilities.DisguiseUtilities;
+import org.bukkit.ChatColor;
+import org.bukkit.Material;
+import org.bukkit.block.BlockFace;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Ageable;
+import org.bukkit.entity.Animals;
+import org.bukkit.entity.Monster;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.permissions.PermissionAttachmentInfo;
+import org.bukkit.potion.PotionEffectType;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map.Entry;
+
+
+/**
+ * @author libraryaddict
+ */
+public abstract class BaseDisguiseCommand implements CommandExecutor {
+
+ public class DisguiseParseException extends Exception {
+
+ private static final long serialVersionUID = 1276971370793124510L;
+
+ public DisguiseParseException() {
+ super();
+ }
+
+ public DisguiseParseException(String string) {
+ super(string);
+ }
+ }
+
+ protected ArrayList getAllowedDisguises(HashMap, Boolean>> hashMap) {
+ ArrayList allowedDisguises = new ArrayList<>();
+ for (DisguiseType type : hashMap.keySet()) {
+ allowedDisguises.add(type.toReadable().replace(" ", "_"));
+ }
+ Collections.sort(allowedDisguises, String.CASE_INSENSITIVE_ORDER);
+ return allowedDisguises;
+ }
+
+ protected HashMap, Boolean>> getPermissions(CommandSender sender) {
+ return getPermissions(sender, "libsdisguises." + getClass().getSimpleName().replace("Command", "").toLowerCase() + ".");
+ }
+
+ protected HashMap getDisguisePermission(CommandSender sender, DisguiseType type) {
+ switch (type) {
+ case PLAYER:
+ case FALLING_BLOCK:
+ case PAINTING:
+ case SPLASH_POTION:
+ case FISHING_HOOK:
+ case DROPPED_ITEM:
+ HashMap returns = new HashMap<>();
+ String beginning = "libsdisguises.options." + getClass().getSimpleName().toLowerCase().replace("command", "") + ".";
+ for (PermissionAttachmentInfo permission : sender.getEffectivePermissions()) {
+ String lowerPerm = permission.getPermission().toLowerCase();
+ if (lowerPerm.startsWith(beginning)) {
+ String[] split = lowerPerm.substring(beginning.length()).split("\\.");
+ if (split.length > 1) {
+ if (split[0].replace("_", "").equals(type.name().toLowerCase().replace("_", ""))) {
+ for (int i = 1; i < split.length; i++) {
+ returns.put(split[i], permission.getValue());
+ }
+ }
+ }
+ }
+ }
+ return returns;
+ default:
+ return new HashMap<>();
+ }
+ }
+
+ protected Method[] getDisguiseWatcherMethods(Class extends FlagWatcher> watcherClass) {
+ Method[] methods = watcherClass.getMethods();
+ methods = Arrays.copyOf(methods, methods.length + 4);
+ int i = 4;
+ for (String methodName : new String[]{"setViewSelfDisguise", "setHideHeldItemFromSelf", "setHideArmorFromSelf",
+ "setHearSelfDisguise"}) {
+ try {
+ methods[methods.length - i--] = Disguise.class.getMethod(methodName, boolean.class);
+ } catch (Exception ex) {
+ ex.printStackTrace(System.out);
+ }
+ }
+ return methods;
+ }
+
+ /**
+ * Get perms for the node. Returns a hashmap of allowed disguisetypes and their options
+ *
+ * @param sender
+ * @param permissionNode
+ * @return
+ */
+ protected HashMap, Boolean>> getPermissions(CommandSender sender, String permissionNode) {
+ HashMap, Boolean>> singleDisguises = new HashMap<>();
+ HashMap, Boolean>> rangeDisguises = new HashMap<>();
+ HashMap perms = new HashMap<>();
+
+ for (PermissionAttachmentInfo permission : sender.getEffectivePermissions()) {
+ String perm = permission.getPermission().toLowerCase();
+ if (perm.startsWith(permissionNode) && (!perms.containsKey(perm) || !permission.getValue())) {
+ perms.put(perm, permission.getValue());
+ }
+ }
+ if (!perms.containsKey(permissionNode + "*") && sender.hasPermission(permissionNode + "*")) {
+ perms.put(permissionNode + "*", true);
+ }
+ if (!perms.containsKey(permissionNode + "*.*") && sender.hasPermission(permissionNode + "*.*")) {
+ perms.put(permissionNode + "*.*", true);
+ }
+
+ for (String perm : perms.keySet()) {
+ if (perms.get(perm)) {
+ perm = perm.substring(permissionNode.length());
+ String disguiseType = perm.split("\\.")[0];
+ DisguiseType dType = null;
+ for (DisguiseType t : DisguiseType.values()) {
+ if (t.name().replace("_", "").equalsIgnoreCase(disguiseType.replace("_", ""))) {
+ dType = t;
+ break;
+ }
+ }
+ if (dType != null) {
+ HashMap, Boolean> list;
+ if (singleDisguises.containsKey(dType)) {
+ list = singleDisguises.get(dType);
+ } else {
+ list = new HashMap<>();
+ singleDisguises.put(dType, list);
+ }
+ HashMap, Boolean> map1 = getOptions(perm);
+ list.put(map1.keySet().iterator().next(), map1.values().iterator().next());
+ } else {
+ for (DisguiseType type : DisguiseType.values()) {
+ HashMap, Boolean> options = null;
+ Class entityClass = type.getEntityClass();
+ if (disguiseType.equals("mob")) {
+ if (type.isMob()) {
+ options = getOptions(perm);
+ }
+ } else if (disguiseType.equals("animal") || disguiseType.equals("animals")) {
+ if (Animals.class.isAssignableFrom(entityClass)) {
+ options = getOptions(perm);
+ }
+ } else if (disguiseType.equals("monster") || disguiseType.equals("monsters")) {
+ if (Monster.class.isAssignableFrom(entityClass)) {
+ options = getOptions(perm);
+ }
+ } else if (disguiseType.equals("misc")) {
+ if (type.isMisc()) {
+ options = getOptions(perm);
+ }
+ } else if (disguiseType.equals("ageable")) {
+ if (Ageable.class.isAssignableFrom(entityClass)) {
+ options = getOptions(perm);
+ }
+ } else if (disguiseType.equals("*")) {
+ options = getOptions(perm);
+ }
+ if (options != null) {
+ HashMap, Boolean> list;
+ if (rangeDisguises.containsKey(type)) {
+ list = rangeDisguises.get(type);
+ } else {
+ list = new HashMap<>();
+ rangeDisguises.put(type, list);
+ }
+ HashMap, Boolean> map1 = getOptions(perm);
+ list.put(map1.keySet().iterator().next(), map1.values().iterator().next());
+ }
+ }
+ }
+ }
+ }
+ for (String perm : perms.keySet()) {
+ if (!perms.get(perm)) {
+ perm = perm.substring(permissionNode.length());
+ String disguiseType = perm.split("\\.")[0];
+ DisguiseType dType = null;
+ for (DisguiseType t : DisguiseType.values()) {
+ if (t.name().replace("_", "").equalsIgnoreCase(disguiseType.replace("_", ""))) {
+ dType = t;
+ break;
+ }
+ }
+ if (dType != null) {
+ singleDisguises.remove(dType);
+ rangeDisguises.remove(dType);
+ } else {
+ for (DisguiseType type : DisguiseType.values()) {
+ boolean foundHim = false;
+ Class entityClass = type.getEntityClass();
+ switch (disguiseType) {
+ case "mob":
+ if (type.isMob()) {
+ foundHim = true;
+ }
+ break;
+ case "animal":
+ case "animals":
+ if (Animals.class.isAssignableFrom(entityClass)) {
+ foundHim = true;
+ }
+ break;
+ case "monster":
+ case "monsters":
+ if (Monster.class.isAssignableFrom(entityClass)) {
+ foundHim = true;
+ }
+ break;
+ case "misc":
+ if (type.isMisc()) {
+ foundHim = true;
+ }
+ break;
+ case "ageable":
+ if (Ageable.class.isAssignableFrom(entityClass)) {
+ foundHim = true;
+ }
+ break;
+ case "*":
+ foundHim = true;
+ break;
+ }
+ if (foundHim) {
+ rangeDisguises.remove(type);
+ }
+ }
+ }
+ }
+ }
+ HashMap, Boolean>> map = new HashMap<>();
+ for (DisguiseType type : DisguiseType.values()) {
+ HashMap, Boolean> temp = new HashMap<>();
+ if (singleDisguises.containsKey(type)) {
+ temp.putAll(singleDisguises.get(type));
+ }
+ if (rangeDisguises.containsKey(type)) {
+ temp.putAll(rangeDisguises.get(type));
+ }
+ if (!temp.isEmpty()) {
+ map.put(type, temp);
+ }
+ }
+ return map;
+ }
+
+ private HashMap, Boolean> getOptions(String perm) {
+ ArrayList list = new ArrayList<>();
+ boolean isRemove = true;
+ String[] split = perm.split("\\.");
+ for (int i = 1; i < split.length; i++) {
+ String option = split[i];
+ boolean value = option.startsWith("-");
+ if (value) {
+ option = option.substring(1);
+ isRemove = false;
+ }
+ if (option.equals("baby")) {
+ option = "setbaby";
+ }
+ list.add(option);
+ }
+ HashMap, Boolean> options = new HashMap<>();
+ options.put(list, isRemove);
+ return options;
+ }
+
+ protected boolean isDouble(String string) {
+ try {
+ Float.parseFloat(string);
+ return true;
+ } catch (Exception ex) {
+ return false;
+ }
+ }
+
+ protected boolean isNumeric(String string) {
+ try {
+ Integer.parseInt(string);
+ return true;
+ } catch (Exception ex) {
+ return false;
+ }
+ }
+
+ /**
+ * Returns the disguise if it all parsed correctly. Returns a exception with a complete message if it didn't. The commandsender is purely used for checking permissions. Would defeat the purpose otherwise. To reach this point, the disguise has been feed a proper disguisetype.
+ *
+ * @param sender
+ * @param args
+ * @param map
+ * @return
+ * @throws BaseDisguiseCommand.DisguiseParseException
+ * @throws java.lang.IllegalAccessException
+ * @throws java.lang.reflect.InvocationTargetException
+ */
+ protected Disguise parseDisguise(CommandSender sender, String[] args, HashMap, Boolean>> map) throws DisguiseParseException,
+ IllegalAccessException, InvocationTargetException {
+ if (map.isEmpty()) {
+ throw new DisguiseParseException(ChatColor.RED + "You are forbidden to use this command.");
+ }
+ if (args.length == 0) {
+ sendCommandUsage(sender, map);
+ throw new DisguiseParseException();
+ }
+ // How many args to skip due to the disugise being constructed
+ // Time to start constructing the disguise.
+ // We will need to check between all 3 kinds of disguises
+ int toSkip = 1;
+ ArrayList usedOptions = new ArrayList<>();
+ Disguise disguise = null;
+ HashMap, Boolean> optionPermissions;
+ if (args[0].startsWith("@")) {
+ if (sender.hasPermission("libsdisguises.disguise.disguiseclone")) {
+ disguise = DisguiseUtilities.getClonedDisguise(args[0].toLowerCase());
+ if (disguise == null) {
+ throw new DisguiseParseException(ChatColor.RED + "Cannot find a disguise under the reference " + args[0]);
+ }
+ } else {
+ throw new DisguiseParseException(ChatColor.RED + "You do not have perimssion to use disguise references!");
+ }
+ optionPermissions = (map.containsKey(disguise.getType()) ? map.get(disguise.getType())
+ : new HashMap, Boolean>());
+ } else {
+ DisguiseType disguiseType = null;
+ if (args[0].equalsIgnoreCase("p")) {
+ disguiseType = DisguiseType.PLAYER;
+ } else {
+ for (DisguiseType type : DisguiseType.values()) {
+ if (args[0].equalsIgnoreCase(type.name()) || args[0].equalsIgnoreCase(type.name().replace("_", ""))) {
+ disguiseType = type;
+ break;
+ }
+ }
+ }
+ if (disguiseType == null) {
+ throw new DisguiseParseException(ChatColor.RED + "Error! The disguise " + ChatColor.GREEN + args[0]
+ + ChatColor.RED + " doesn't exist!");
+ }
+ if (disguiseType.isUnknown()) {
+ throw new DisguiseParseException(ChatColor.RED + "Error! You cannot disguise as " + ChatColor.GREEN + "Unknown!");
+ }
+ if (disguiseType.getEntityType() == null) {
+ throw new DisguiseParseException(ChatColor.RED + "Error! This version of minecraft does not have that disguise!");
+ }
+ if (!map.containsKey(disguiseType)) {
+ throw new DisguiseParseException(ChatColor.RED + "You are forbidden to use this disguise.");
+ }
+ optionPermissions = map.get(disguiseType);
+ HashMap disguiseOptions = this.getDisguisePermission(sender, disguiseType);
+ if (disguiseType.isPlayer()) {
+ // If he is doing a player disguise
+ if (args.length == 1) {
+ // He needs to give the player name
+ throw new DisguiseParseException(ChatColor.RED + "Error! You need to give a player name!");
+ } else {
+ if (!disguiseOptions.isEmpty()
+ && (!disguiseOptions.containsKey(args[1].toLowerCase()) || !disguiseOptions
+ .get(args[1].toLowerCase()))) {
+ throw new DisguiseParseException(ChatColor.RED + "Error! You don't have permission to use that name!");
+ }
+ args[1] = args[1].replace("\\_", " ");
+ // Construct the player disguise
+ disguise = new PlayerDisguise(ChatColor.translateAlternateColorCodes('&', args[1]));
+ toSkip++;
+ }
+ } else {
+ if (disguiseType.isMob()) { // Its a mob, use the mob constructor
+ boolean adult = true;
+ if (args.length > 1) {
+ if (args[1].equalsIgnoreCase("baby") || args[1].equalsIgnoreCase("adult")) {
+ usedOptions.add("setbaby");
+ doCheck(optionPermissions, usedOptions);
+ adult = args[1].equalsIgnoreCase("adult");
+ toSkip++;
+ }
+ }
+ disguise = new MobDisguise(disguiseType, adult);
+ } else if (disguiseType.isMisc()) {
+ // Its a misc, we are going to use the MiscDisguise constructor.
+ int miscId = -1;
+ int miscData = -1;
+ String secondArg = null;
+ if (args.length > 1) {
+ // They have defined more arguements!
+ // If the first arg is a number
+ if (args[1].contains(":")) {
+ String[] split = args[1].split(":");
+ if (isNumeric(split[1])) {
+ secondArg = split[1];
+ }
+ args[1] = split[0];
+ }
+ if (isNumeric(args[1])) {
+ miscId = Integer.parseInt(args[1]);
+ } else {
+ if (disguiseType == DisguiseType.FALLING_BLOCK || disguiseType == DisguiseType.DROPPED_ITEM) {
+ for (Material mat : Material.values()) {
+ if (mat.name().replace("_", "").equalsIgnoreCase(args[1].replace("_", ""))) {
+ miscId = mat.getId();
+ break;
+ }
+ }
+ }
+ }
+ if (miscId != -1) {
+ switch (disguiseType) {
+ case PAINTING:
+ case FALLING_BLOCK:
+ case SPLASH_POTION:
+ case DROPPED_ITEM:
+ case FISHING_HOOK:
+ case TIPPED_ARROW:
+ case SPECTRAL_ARROW:
+ case SMALL_FIREBALL:
+ case FIREBALL:
+ case WITHER_SKULL:
+ break;
+ default:
+ throw new DisguiseParseException(ChatColor.RED + "Error! " + disguiseType.toReadable()
+ + " doesn't know what to do with " + args[1] + "!");
+ }
+ toSkip++;
+ // If they also defined a data value
+ if (args.length > 2 && secondArg == null && isNumeric(args[2])) {
+ secondArg = args[2];
+ toSkip++;
+ }
+ if (secondArg != null) {
+ if (disguiseType != DisguiseType.FALLING_BLOCK && disguiseType != DisguiseType.DROPPED_ITEM) {
+ throw new DisguiseParseException(ChatColor.RED + "Error! Only the disguises "
+ + DisguiseType.FALLING_BLOCK.toReadable() + " and "
+ + DisguiseType.DROPPED_ITEM.toReadable() + " uses a second number!");
+ }
+ miscData = Integer.parseInt(secondArg);
+ }
+ }
+ }
+ if (!disguiseOptions.isEmpty() && miscId != -1) {
+ String toCheck = "" + miscId;
+ if (miscData == 0 || miscData == -1) {
+ if (!disguiseOptions.containsKey(toCheck) || !disguiseOptions.get(toCheck)) {
+ toCheck += ":0";
+ }
+ } else {
+ toCheck += ":" + miscData;
+ }
+ if (!disguiseOptions.containsKey(toCheck) || !disguiseOptions.get(toCheck)) {
+ throw new DisguiseParseException(ChatColor.RED
+ + "Error! You do not have permission to use the parameter " + toCheck + " on the "
+ + disguiseType.toReadable() + " disguise!");
+ }
+ }
+ if (miscId != -1) {
+ if (disguiseType == DisguiseType.FALLING_BLOCK) {
+ usedOptions.add("setblock");
+ doCheck(optionPermissions, usedOptions);
+ } else if (disguiseType == DisguiseType.PAINTING) {
+ usedOptions.add("setpainting");
+ doCheck(optionPermissions, usedOptions);
+ } else if (disguiseType == DisguiseType.SPLASH_POTION) {
+ usedOptions.add("setpotionid");
+ doCheck(optionPermissions, usedOptions);
+ }
+ }
+ // Construct the disguise
+ disguise = new MiscDisguise(disguiseType, miscId, miscData);
+ }
+ }
+ }
+ // Copy strings to their new range
+ String[] newArgs = new String[args.length - toSkip];
+ System.arraycopy(args, toSkip, newArgs, 0, args.length - toSkip);
+ args = newArgs;
+ Method[] methods = this.getDisguiseWatcherMethods(disguise.getWatcher().getClass());
+ for (int i = 0; i < args.length; i += 2) {
+ String methodName = args[i];
+ String valueString = (args.length - 1 == i ? null : args[i + 1]);
+ Method methodToUse = null;
+ Object value = null;
+ DisguiseParseException storedEx = null;
+ int c = 0;
+ while (c < methods.length) {
+ try {
+ Entry entry = getMethod(methods, methodName, c);
+ if (entry == null) {
+ break;
+ }
+ methodToUse = entry.getKey();
+ c = entry.getValue();
+ methodName = methodToUse.getName();
+ Class>[] types = methodToUse.getParameterTypes();
+ Class param = types[0];
+ if (valueString != null) {
+ if (int.class == param) {
+ // Parse to integer
+ if (isNumeric(valueString)) {
+ value = Integer.parseInt(valueString);
+ } else {
+ throw parseToException("number", valueString, methodName);
+ }
+ } else if (float.class == param || double.class == param) {
+ // Parse to number
+ if (isDouble(valueString)) {
+ float obj = Float.parseFloat(valueString);
+ if (param == float.class) {
+ value = obj;
+ } else if (param == double.class) {
+ value = (double) obj;
+ }
+ } else {
+ throw parseToException("number.0", valueString, methodName);
+ }
+ } else if (param == String.class) {
+ // Parse to string
+ value = ChatColor.translateAlternateColorCodes('&', valueString);
+ } else if (param == AnimalColor.class) {
+ // Parse to animal color
+ try {
+ value = AnimalColor.valueOf(valueString.toUpperCase());
+ } catch (Exception ex) {
+ throw parseToException("animal color", valueString, methodName);
+ }
+ } else if (param == ItemStack.class) {
+ // Parse to itemstack
+ try {
+ value = parseToItemstack(valueString);
+ } catch (Exception ex) {
+ throw new DisguiseParseException(String.format(ex.getMessage(), methodName));
+ }
+ } else if (param == ItemStack[].class) {
+ // Parse to itemstack array
+ ItemStack[] items = new ItemStack[4];
+ String[] split = valueString.split(",");
+ if (split.length == 4) {
+ for (int a = 0; a < 4; a++) {
+ try {
+ items[a] = parseToItemstack(split[a]);
+ } catch (Exception ex) {
+ throw parseToException("item ID,ID,ID,ID" + ChatColor.RED + " or " + ChatColor.GREEN
+ + "ID:Data,ID:Data,ID:Data,ID:Data combo", valueString, methodName);
+ }
+ }
+ } else {
+ throw parseToException("item ID,ID,ID,ID" + ChatColor.RED + " or " + ChatColor.GREEN
+ + "ID:Data,ID:Data,ID:Data,ID:Data combo", valueString, methodName);
+ }
+ value = items;
+ } else if (param.getSimpleName().equals("Color")) {
+ // Parse to horse color
+ value = callValueOf(param, valueString, methodName, "a horse color");
+ } else if (param.getSimpleName().equals("Style")) {
+ // Parse to horse style
+ value = callValueOf(param, valueString, methodName, "a horse style");
+ } else if (param.getSimpleName().equals("Profession")) {
+ // Parse to villager profession
+ value = callValueOf(param, valueString, methodName, "a villager profession");
+ } else if (param.getSimpleName().equals("Art")) {
+ // Parse to art type
+ value = callValueOf(param, valueString, methodName, "a painting art");
+ } else if (param.getSimpleName().equals("Type")) {
+ // Parse to ocelot type
+ value = callValueOf(param, valueString, methodName, "a ocelot type");
+ } else if (param == PotionEffectType.class) {
+ // Parse to potion effect
+ try {
+ PotionEffectType potionType = PotionEffectType.getByName(valueString.toUpperCase());
+ if (potionType == null && isNumeric(valueString)) {
+ potionType = PotionEffectType.getById(Integer.parseInt(valueString));
+ }
+ if (potionType == null) {
+ throw new DisguiseParseException();
+ }
+ value = potionType;
+ } catch (Exception ex) {
+ throw parseToException("a potioneffect type", valueString, methodName);
+ }
+ } else if (param == int[].class) {
+ String[] split = valueString.split(",");
+ int[] values = new int[split.length];
+ for (int b = 0; b < values.length; b++) {
+ try {
+ values[b] = Integer.parseInt(split[b]);
+ } catch (NumberFormatException ex) {
+ throw parseToException("Number,Number,Number...", valueString, methodName);
+ }
+ }
+ value = values;
+ } else if (param == BlockFace.class) {
+ try {
+ BlockFace face = BlockFace.valueOf(valueString.toUpperCase());
+ if (face.ordinal() > 4) {
+ throw new DisguiseParseException();
+ }
+ value = face;
+ } catch (Exception ex) {
+ throw parseToException("a direction (north, east, south, west, up)", valueString, methodName);
+ }
+ } else if (param == RabbitType.class) {
+ try {
+ for (RabbitType type : RabbitType.values()) {
+ if (type.name().replace("_", "")
+ .equalsIgnoreCase(valueString.replace("_", "").replace(" ", ""))) {
+ value = type;
+ break;
+ }
+ }
+ if (value == null) {
+ throw new Exception();
+ }
+ } catch (Exception ex) {
+ throw parseToException("rabbit type (white, brown, patches...)", valueString, methodName);
+ }
+ }
+ }
+ if (value == null && boolean.class == param) {
+ if (valueString == null) {
+ value = true;
+ i--;
+ } else if (valueString.equalsIgnoreCase("true")) {
+ value = true;
+ } else if (valueString.equalsIgnoreCase("false")) {
+ value = false;
+ } else {
+ if (getMethod(methods, valueString, 0) == null) {
+ throw parseToException("true/false", valueString, methodName);
+ } else {
+ value = true;
+ i--;
+ }
+ }
+ }
+ if (value != null) {
+ break;
+ }
+ } catch (DisguiseParseException ex) {
+ storedEx = ex;
+ methodToUse = null;
+ } catch (Exception ex) {
+ ex.printStackTrace(System.out);
+ methodToUse = null;
+ }
+ }
+ if (methodToUse == null) {
+ if (storedEx != null) {
+ throw storedEx;
+ }
+ throw new DisguiseParseException(ChatColor.RED + "Cannot find the option " + methodName);
+ }
+ if (value == null) {
+ throw new DisguiseParseException(ChatColor.RED + "No value was given for the option " + methodName);
+ }
+ if (!usedOptions.contains(methodName.toLowerCase())) {
+ usedOptions.add(methodName.toLowerCase());
+ }
+ doCheck(optionPermissions, usedOptions);
+ if (FlagWatcher.class.isAssignableFrom(methodToUse.getDeclaringClass())) {
+ methodToUse.invoke(disguise.getWatcher(), value);
+ } else {
+ methodToUse.invoke(disguise, value);
+ }
+ }
+ // Alright. We've constructed our disguise.
+ return disguise;
+ }
+
+ private Entry getMethod(Method[] methods, String methodName, int toStart) {
+ for (int i = toStart; i < methods.length; i++) {
+ Method method = methods[i];
+ if (!method.getName().startsWith("get") && method.getName().equalsIgnoreCase(methodName)
+ && method.getAnnotation(Deprecated.class) == null && method.getParameterTypes().length == 1) {
+ return new HashMap.SimpleEntry(method, ++i);
+ }
+ }
+ return null;
+ }
+
+ private Object callValueOf(Class> param, String valueString, String methodName, String description)
+ throws DisguiseParseException {
+ Object value;
+ try {
+ value = param.getMethod("valueOf", String.class).invoke(null, valueString.toUpperCase());
+ } catch (Exception ex) {
+ throw parseToException(description, valueString, methodName);
+ }
+ return value;
+ }
+
+ private boolean passesCheck(HashMap, Boolean> map1, ArrayList usedOptions) {
+ boolean hasPermission = false;
+ for (ArrayList list : map1.keySet()) {
+ boolean myPerms = true;
+ for (String option : usedOptions) {
+ if (!(map1.get(list) && list.contains("*")) && (list.contains(option) != map1.get(list))) {
+ myPerms = false;
+ break;
+ }
+ }
+ if (myPerms) {
+ hasPermission = true;
+ }
+ }
+ return hasPermission;
+ }
+
+ private void doCheck(HashMap, Boolean> optionPermissions, ArrayList usedOptions)
+ throws DisguiseParseException {
+ if (!passesCheck(optionPermissions, usedOptions)) {
+ throw new DisguiseParseException(ChatColor.RED + "You do not have the permission to use the option "
+ + usedOptions.get(usedOptions.size() - 1));
+ }
+ }
+
+ private DisguiseParseException parseToException(String expectedValue, String receivedInstead, String methodName) {
+ return new DisguiseParseException(ChatColor.RED + "Expected " + ChatColor.GREEN + expectedValue + ChatColor.RED
+ + ", received " + ChatColor.GREEN + receivedInstead + ChatColor.RED + " instead for " + ChatColor.GREEN
+ + methodName);
+ }
+
+ private ItemStack parseToItemstack(String string) throws Exception {
+ String[] split = string.split(":", -1);
+ if (isNumeric(split[0])) {
+ int itemId = Integer.parseInt(split[0]);
+ short itemDura = 0;
+ if (split.length > 1) {
+ if (isNumeric(split[1])) {
+ itemDura = Short.parseShort(split[1]);
+ } else {
+ throw parseToException("item ID:Durability combo", string, "%s");
+ }
+ }
+ return new ItemStack(itemId, 1, itemDura);
+ } else {
+ if (split.length == 1) {
+ throw parseToException("item ID", string, "%s");
+ } else {
+ throw parseToException("item ID:Durability combo", string, "%s");
+ }
+ }
+ }
+
+ protected abstract void sendCommandUsage(CommandSender sender, HashMap, Boolean>> map);
+}
diff --git a/src/main/java/me/libraryaddict/disguise/commands/DisguiseCloneCommand.java b/src/main/java/me/libraryaddict/disguise/commands/CloneDisguiseCommand.java
similarity index 97%
rename from src/main/java/me/libraryaddict/disguise/commands/DisguiseCloneCommand.java
rename to src/main/java/me/libraryaddict/disguise/commands/CloneDisguiseCommand.java
index 4559b9a9..fd77c87e 100644
--- a/src/main/java/me/libraryaddict/disguise/commands/DisguiseCloneCommand.java
+++ b/src/main/java/me/libraryaddict/disguise/commands/CloneDisguiseCommand.java
@@ -11,7 +11,7 @@ import org.bukkit.command.CommandSender;
import java.util.ArrayList;
import java.util.HashMap;
-public class DisguiseCloneCommand extends BaseDisguiseCommand {
+public class CloneDisguiseCommand extends BaseDisguiseCommand {
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
diff --git a/src/main/java/me/libraryaddict/disguise/commands/DisguiseEntityCommand.java b/src/main/java/me/libraryaddict/disguise/commands/EntityDisguiseCommand.java
similarity index 97%
rename from src/main/java/me/libraryaddict/disguise/commands/DisguiseEntityCommand.java
rename to src/main/java/me/libraryaddict/disguise/commands/EntityDisguiseCommand.java
index 7977643e..7a7d64a6 100644
--- a/src/main/java/me/libraryaddict/disguise/commands/DisguiseEntityCommand.java
+++ b/src/main/java/me/libraryaddict/disguise/commands/EntityDisguiseCommand.java
@@ -13,7 +13,7 @@ import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
-public class DisguiseEntityCommand extends BaseDisguiseCommand {
+public class EntityDisguiseCommand extends BaseDisguiseCommand {
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
diff --git a/src/main/java/me/libraryaddict/disguise/commands/DisguiseHelpCommand.java b/src/main/java/me/libraryaddict/disguise/commands/HelpDisguiseCommand.java
similarity index 99%
rename from src/main/java/me/libraryaddict/disguise/commands/DisguiseHelpCommand.java
rename to src/main/java/me/libraryaddict/disguise/commands/HelpDisguiseCommand.java
index 71391d35..2656a21f 100644
--- a/src/main/java/me/libraryaddict/disguise/commands/DisguiseHelpCommand.java
+++ b/src/main/java/me/libraryaddict/disguise/commands/HelpDisguiseCommand.java
@@ -19,7 +19,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
-public class DisguiseHelpCommand extends BaseDisguiseCommand {
+public class HelpDisguiseCommand extends BaseDisguiseCommand {
private class EnumHelp {
@@ -65,7 +65,7 @@ public class DisguiseHelpCommand extends BaseDisguiseCommand {
private ArrayList enumHelp = new ArrayList<>();
- public DisguiseHelpCommand() {
+ public HelpDisguiseCommand() {
try {
enumHelp.add(new EnumHelp("AnimalColor", "Animal colors", ChatColor.RED + "/disguisehelp AnimalColors "
+ ChatColor.GREEN + "- View all the colors you can use for a animal color", AnimalColor.values()));
diff --git a/src/main/java/me/libraryaddict/disguise/commands/DisguisePlayerCommand.java b/src/main/java/me/libraryaddict/disguise/commands/PlayerDisguiseCommand.java
similarity index 98%
rename from src/main/java/me/libraryaddict/disguise/commands/DisguisePlayerCommand.java
rename to src/main/java/me/libraryaddict/disguise/commands/PlayerDisguiseCommand.java
index ff960c62..e373cde5 100644
--- a/src/main/java/me/libraryaddict/disguise/commands/DisguisePlayerCommand.java
+++ b/src/main/java/me/libraryaddict/disguise/commands/PlayerDisguiseCommand.java
@@ -15,7 +15,7 @@ import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.HashMap;
-public class DisguisePlayerCommand extends BaseDisguiseCommand {
+public class PlayerDisguiseCommand extends BaseDisguiseCommand {
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
diff --git a/src/main/java/me/libraryaddict/disguise/commands/DisguiseRadiusCommand.java b/src/main/java/me/libraryaddict/disguise/commands/RadiusDisguiseCommand.java
similarity index 98%
rename from src/main/java/me/libraryaddict/disguise/commands/DisguiseRadiusCommand.java
rename to src/main/java/me/libraryaddict/disguise/commands/RadiusDisguiseCommand.java
index 01acb288..92feb477 100644
--- a/src/main/java/me/libraryaddict/disguise/commands/DisguiseRadiusCommand.java
+++ b/src/main/java/me/libraryaddict/disguise/commands/RadiusDisguiseCommand.java
@@ -19,12 +19,12 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
-public class DisguiseRadiusCommand extends BaseDisguiseCommand {
+public class RadiusDisguiseCommand extends BaseDisguiseCommand {
private int maxRadius = 30;
private ArrayList validClasses = new ArrayList<>();
- public DisguiseRadiusCommand(int maxRadius) {
+ public RadiusDisguiseCommand(int maxRadius) {
this.maxRadius = maxRadius;
for (Class c : ClassGetter.getClassesForPackage("org.bukkit.entity")) {
if (c != Entity.class && Entity.class.isAssignableFrom(c) && c.getAnnotation(Deprecated.class) == null) {