diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..be5de33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.idea/ +libs/ +out/ +ArmorStand.iml \ No newline at end of file diff --git a/src/com/gmail/St3venAU/plugins/ArmorStandTools/ArmorStandTool.java b/src/com/gmail/St3venAU/plugins/ArmorStandTools/ArmorStandTool.java new file mode 100644 index 0000000..8ae055c --- /dev/null +++ b/src/com/gmail/St3venAU/plugins/ArmorStandTools/ArmorStandTool.java @@ -0,0 +1,100 @@ +package com.gmail.St3venAU.plugins.ArmorStandTools; + +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.inventory.meta.ItemMeta; + +public enum ArmorStandTool { + HEADX ("headX", Material.JACK_O_LANTERN, (short) 0, 27, true), + HEADY ("headY", Material.JACK_O_LANTERN, (short) 0, 28, true), + HEADZ ("headZ", Material.JACK_O_LANTERN, (short) 0, 29, true), + LARMX ("lArmX", Material.TORCH, (short) 0, 30, true), + LARMY ("lArmY", Material.TORCH, (short) 0, 31, true), + LARMZ ("lArmZ", Material.TORCH, (short) 0, 32, true), + RARMX ("rArmX", Material.REDSTONE_TORCH_ON, (short) 0, 33, true), + RARMY ("rArmY", Material.REDSTONE_TORCH_ON, (short) 0, 34, true), + RARMZ ("rArmZ", Material.REDSTONE_TORCH_ON, (short) 0, 35, true), + MOVEX ("moveX", Material.SHEARS, (short) 0, 24, true), + MOVEY ("moveY", Material.SHEARS, (short) 0, 25, true), + MOVEZ ("moveZ", Material.SHEARS, (short) 0, 26, true), + ROTAT ("rotat", Material.MAGMA_CREAM, (short) 0, 6, true), + INVIS ("invis", Material.GOLD_NUGGET, (short) 0, 5, true), + SUMMON ("summon", Material.ARMOR_STAND, (short) 0, 0, true), + CLONE ("clone", Material.GLOWSTONE_DUST, (short) 0, 16, true), + SAVE ("save", Material.DIAMOND, (short) 0, 17, true), + LLEGX ("lLegX", Material.BONE, (short) 0, 18, true), + LLEGY ("lLegY", Material.BONE, (short) 0, 19, true), + LLEGZ ("lLegZ", Material.BONE, (short) 0, 20, true), + RLEGX ("rLegX", Material.BLAZE_ROD, (short) 0, 21, true), + RLEGY ("rLegY", Material.BLAZE_ROD, (short) 0, 22, true), + RLEGZ ("rLegZ", Material.BLAZE_ROD, (short) 0, 23, true), + BODYX ("bodyX", Material.NETHER_BRICK_ITEM, (short) 0, 9, true), + BODYY ("bodyY", Material.NETHER_BRICK_ITEM, (short) 0, 10, true), + BODYZ ("bodyZ", Material.NETHER_BRICK_ITEM, (short) 0, 11, true), + SIZE ("size", Material.EMERALD, (short) 0, 3, true), + BASE ("base", Material.BOOK, (short) 0, 4, true), + GRAV ("grav", Material.GHAST_TEAR, (short) 0, 1, true), + ARMS ("arms", Material.ARROW, (short) 0, 2, true), + NAME ("name", Material.NAME_TAG, (short) 0, 7, true), + SLOTS ("slots", Material.IRON_HOE, (short) 0, 13, true), + PHEAD ("pHead", Material.SKULL_ITEM, (short) 3, 8, true), + INVUL ("invul", Material.GOLDEN_CARROT, (short) 0, 12, true), + MOVE ("move", Material.FEATHER, (short) 0, 14, true), + NODEL ("noDel", Material.WOOD_SPADE, (short) 0, 15, false); // Developer tool, disabled by default + + private final ItemStack item; + private final String id; + private final int slot; + private final boolean enabled; + + ArmorStandTool(String id, Material m, short data, int slot, boolean enabled) { + item = new ItemStack(m, 1, data); + this.id = id; + this.slot = slot; + this.enabled = enabled; + } + + ItemStack getItem() { + return item; + } + + boolean is(ItemStack is) { + return is != null && is.getType() == item.getType() && is.hasItemMeta() && + is.getItemMeta().hasDisplayName() && + is.getItemMeta().getDisplayName().equals(item.getItemMeta().getDisplayName()); + } + + static void updateTools(FileConfiguration config) { + for(ArmorStandTool t : values()) { + ItemMeta im = t.item.getItemMeta(); + im.setDisplayName(ChatColor.GREEN + config.getString("tool." + t.id + ".name")); + im.setLore(config.getStringList("tool." + t.id + ".lore")); + t.item.setItemMeta(im); + } + } + + static void give(Player p) { + PlayerInventory i = p.getInventory(); + for(ArmorStandTool t : values()) { + if(t.enabled) { + i.setItem(t.slot, t.item); + } + } + } + + static ArmorStandTool get(ItemStack is) { + if(is == null || !is.hasItemMeta() || !is.getItemMeta().hasDisplayName()) return null; + for(ArmorStandTool t : values()) { + if(t.is(is)) return t; + } + return null; + } + + static boolean isTool(ItemStack is) { + return get(is) != null; + } +} diff --git a/src/com/gmail/St3venAU/plugins/ArmorStandTools/Commands.java b/src/com/gmail/St3venAU/plugins/ArmorStandTools/Commands.java new file mode 100644 index 0000000..75dd1fc --- /dev/null +++ b/src/com/gmail/St3venAU/plugins/ArmorStandTools/Commands.java @@ -0,0 +1,53 @@ +package com.gmail.St3venAU.plugins.ArmorStandTools; + +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.util.UUID; + +class Commands implements CommandExecutor { + + private final Main plugin; + + Commands(Main main) { + plugin = main; + } + + @Override + public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) { + if (!(sender instanceof Player)) { + System.out.println(Config.notConsole); + return false; + } + Player p = (Player) sender; + if(args.length == 0) { + UUID uuid = p.getUniqueId(); + if(plugin.savedInventories.containsKey(uuid)) { + p.getInventory().setContents(plugin.savedInventories.get(uuid)); + plugin.savedInventories.remove(uuid); + p.sendMessage(ChatColor.GREEN + Config.invReturned); + return true; + } else { + plugin.savedInventories.put(uuid, p.getInventory().getContents()); + ArmorStandTool.give(p); + p.sendMessage(ChatColor.GREEN + Config.giveMsg1); + p.sendMessage(ChatColor.AQUA + Config.giveMsg2); + return true; + } + } + if(args[0].equalsIgnoreCase("reload")) { + if(p.hasPermission("astools.reload")) { + Config.reload(); + p.sendMessage(ChatColor.GREEN + Config.conReload); + return true; + } else { + p.sendMessage(ChatColor.RED + Config.noRelPerm); + return true; + } + } + return false; + } +} diff --git a/src/com/gmail/St3venAU/plugins/ArmorStandTools/Config.java b/src/com/gmail/St3venAU/plugins/ArmorStandTools/Config.java new file mode 100644 index 0000000..4dfab37 --- /dev/null +++ b/src/com/gmail/St3venAU/plugins/ArmorStandTools/Config.java @@ -0,0 +1,156 @@ +package com.gmail.St3venAU.plugins.ArmorStandTools; + +import com.sk89q.worldguard.bukkit.WorldGuardPlugin; +import org.bukkit.Material; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.Plugin; + +import java.io.File; +import java.io.InputStream; +import java.util.logging.Level; + +class Config { + + private static Main plugin; + private static File languageConfigFile; + private static FileConfiguration languageConfig; + + public static WorldGuardPlugin worldGuardPlugin; + + public static ItemStack helmet, chest, pants, boots, itemInHand; + public static boolean isVisible = true; + public static boolean isSmall = false; + public static boolean hasArms = true; + public static boolean hasBasePlate = false; + public static boolean hasGravity = false; + public static String defaultName = ""; + public static boolean invulnerable = false; + public static boolean equipmentLock = false; + + public static String + invReturned, asDropped, asVisible, isTrue, isFalse, + asCloned, carrying, noPerm, cbCreated, size, small, + normal, basePlate, isOn, isOff, gravity, arms, invul, + equip, locked, unLocked, notConsole, giveMsg1, + giveMsg2, conReload, noRelPerm, noAirError, + pleaseWait, appliedHead, noHead, invalidName, + wgNoPerm; + + public static void reload(Main main) { + plugin = main; + reload(); + } + + public static void reload() { + reloadMainConfig(); + saveDefaultLanguageConfig(); + reloadLanguageConfig(); + ArmorStandTool.updateTools(languageConfig); + invReturned = languageConfig.getString("invReturned"); + asDropped = languageConfig.getString("asDropped"); + asVisible = languageConfig.getString("asVisible"); + isTrue = languageConfig.getString("isTrue"); + isFalse = languageConfig.getString("isFalse"); + asCloned = languageConfig.getString("asCloned"); + carrying = languageConfig.getString("carrying"); + noPerm = languageConfig.getString("noPerm"); + cbCreated = languageConfig.getString("cbCreated"); + size = languageConfig.getString("size"); + small = languageConfig.getString("small"); + normal = languageConfig.getString("normal"); + basePlate = languageConfig.getString("basePlate"); + isOn = languageConfig.getString("isOn"); + isOff = languageConfig.getString("isOff"); + gravity = languageConfig.getString("gravity"); + arms = languageConfig.getString("arms"); + invul = languageConfig.getString("invul"); + equip = languageConfig.getString("equip"); + locked = languageConfig.getString("locked"); + unLocked = languageConfig.getString("unLocked"); + notConsole = languageConfig.getString("notConsole"); + giveMsg1 = languageConfig.getString("giveMsg1"); + giveMsg2 = languageConfig.getString("giveMsg2"); + conReload = languageConfig.getString("conReload"); + noRelPerm = languageConfig.getString("noRelPerm"); + noAirError = languageConfig.getString("noAirError"); + pleaseWait = languageConfig.getString("pleaseWait"); + appliedHead = languageConfig.getString("appliedHead"); + noHead = languageConfig.getString("noHead"); + invalidName = languageConfig.getString("invalidName"); + wgNoPerm = languageConfig.getString("wgNoPerm"); + } + + private static void reloadMainConfig() { + plugin.saveDefaultConfig(); + plugin.reloadConfig(); + FileConfiguration config = plugin.getConfig(); + helmet = toItemStack(config.getString("helmet")); + chest = toItemStack(config.getString("chest")); + pants = toItemStack(config.getString("pants")); + boots = toItemStack(config.getString("boots")); + itemInHand = toItemStack(config.getString("inHand")); + isVisible = config.getBoolean("isVisible"); + isSmall = config.getBoolean("isSmall"); + hasArms = config.getBoolean("hasArms"); + hasBasePlate = config.getBoolean("hasBasePlate"); + hasGravity = config.getBoolean("hasGravity"); + defaultName = config.getString("name"); + invulnerable = config.getBoolean("invulnerable"); + equipmentLock = config.getBoolean("equipmentLock"); + plugin.carryingArmorStand.clear(); + Plugin worldGuard = plugin.getServer().getPluginManager().getPlugin("WorldGuard"); + worldGuardPlugin = worldGuard == null || !(worldGuard instanceof WorldGuardPlugin) ? null : (WorldGuardPlugin) worldGuard; + if(config.getBoolean("integrateWithWorldGuard")) { + plugin.getLogger().log(Level.INFO, worldGuardPlugin == null ? "WorldGuard plugin not found. Continuing without WorldGuard support." : "WorldGuard plugin found. WorldGuard support enabled."); + } else if(worldGuardPlugin != null) { + plugin.getLogger().log(Level.WARNING, "WorldGuard plugin was found, but integrateWithWorldGuard is set to false in config.yml. Continuing without WorldGuard support."); + } + } + + @SuppressWarnings("deprecation") + private static void reloadLanguageConfig() { + languageConfigFile = new File(plugin.getDataFolder(), "language.yml"); + languageConfig = YamlConfiguration.loadConfiguration(languageConfigFile); + InputStream defConfigStream = plugin.getResource("language.yml"); + if (defConfigStream != null) { + languageConfig.setDefaults(YamlConfiguration.loadConfiguration(defConfigStream)); + } + } + + private static void saveDefaultLanguageConfig() { + languageConfigFile = new File(plugin.getDataFolder(), "language.yml"); + if (!languageConfigFile.exists()) { + plugin.saveResource("language.yml", false); + } + } + + private static ItemStack toItemStack(String s) { + if(s == null || s.length() == 0) { + return new ItemStack(Material.AIR); + } + String[] split = s.split(" "); + if(split.length > 2) { + System.out.println("[ArmorStandTools] Error in Config: Must use the format: MATERIAL_NAME dataValue. Continuing using AIR instead."); + return new ItemStack(Material.AIR); + } + byte dataValue = (byte) 0; + if(split.length == 2) { + try { + dataValue = Byte.parseByte(split[1]); + } catch (NumberFormatException nfe) { + System.out.println("[ArmorStandTools] Error in Config: Invalid data value specifed. Continuing using data value 0 instead."); + } + } + Material m; + try { + m = Material.valueOf(split[0].toUpperCase()); + } catch(IllegalArgumentException iae) { + System.out.println("[ArmorStandTools] Error in Config: Invalid material name specifed. Continuing using AIR instead."); + return new ItemStack(Material.AIR); + } + return new ItemStack(m, 1, dataValue); + } + +} diff --git a/src/com/gmail/St3venAU/plugins/ArmorStandTools/Main.java b/src/com/gmail/St3venAU/plugins/ArmorStandTools/Main.java new file mode 100644 index 0000000..083206f --- /dev/null +++ b/src/com/gmail/St3venAU/plugins/ArmorStandTools/Main.java @@ -0,0 +1,59 @@ +package com.gmail.St3venAU.plugins.ArmorStandTools; + +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.command.CommandExecutor; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.MetadataValue; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.HashMap; +import java.util.UUID; + +public class Main extends JavaPlugin { + + public final HashMap carryingArmorStand = new HashMap(); + public final HashMap savedInventories = new HashMap(); + static String NMS_VERSION; + + @Override + public void onEnable() { + NMS_VERSION = getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3]; + getServer().getPluginManager().registerEvents(new MainListener(this), this); + CommandExecutor ce = new Commands(this); + getCommand("astools").setExecutor(ce); + Config.reload(this); + } + + @Override + public void onDisable() { + for(ArmorStand as : carryingArmorStand.values()) { + returnArmorStand(as); + } + carryingArmorStand.clear(); + Player p; + for(UUID uuid : savedInventories.keySet()) { + p = getServer().getPlayer(uuid); + if(p != null && p.isOnline()) { + p.getInventory().setContents(savedInventories.get(uuid)); + p.sendMessage(ChatColor.GREEN + Config.invReturned); + } + } + savedInventories.clear(); + } + + void returnArmorStand(ArmorStand as) { + if(as.hasMetadata("startLoc")) { + for (MetadataValue value : as.getMetadata("startLoc")) { + if (value.getOwningPlugin() == this) { + as.teleport((Location) value.value()); + as.removeMetadata("startLoc", this); + return; + } + } + } + as.remove(); + } +} \ No newline at end of file diff --git a/src/com/gmail/St3venAU/plugins/ArmorStandTools/MainListener.java b/src/com/gmail/St3venAU/plugins/ArmorStandTools/MainListener.java new file mode 100644 index 0000000..80849d1 --- /dev/null +++ b/src/com/gmail/St3venAU/plugins/ArmorStandTools/MainListener.java @@ -0,0 +1,620 @@ +package com.gmail.St3venAU.plugins.ArmorStandTools; + +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.SkullType; +import org.bukkit.block.Block; +import org.bukkit.block.CommandBlock; +import org.bukkit.block.Skull; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.ItemFrame; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.block.SignChangeEvent; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.inventory.InventoryAction; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryDragEvent; +import org.bukkit.event.player.PlayerDropItemEvent; +import org.bukkit.event.player.PlayerInteractAtEntityEvent; +import org.bukkit.event.player.PlayerInteractEntityEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.metadata.MetadataValue; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.EulerAngle; + +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import java.util.regex.Pattern; + +public class MainListener implements Listener { + + private final Pattern MC_USERNAME_PATTERN = Pattern.compile("^[a-zA-Z0-9_]{3,16}$"); + private final EulerAngle zero = new EulerAngle(0D, 0D, 0D); + private final Main plugin; + + MainListener(Main main) { + this.plugin = main; + } + + @SuppressWarnings("ConstantConditions") + @EventHandler + public void onPlayerInteractAtEntity(PlayerInteractAtEntityEvent event) { + if (event.getRightClicked() instanceof ArmorStand) { + Player p = event.getPlayer(); + if(plugin.carryingArmorStand.containsKey(p.getUniqueId()) && !permissionCheck(plugin.carryingArmorStand.get(p.getUniqueId()).getLocation().getBlock(), p)) { + plugin.carryingArmorStand.remove(p.getUniqueId()); + Utils.actionBarMsg(p, Config.asDropped); + event.setCancelled(true); + return; + } + if (!p.hasPermission("astools.use") && !p.isOp()) return; + ArmorStandTool tool = ArmorStandTool.get(p.getItemInHand()); + if(tool == null) return; + ArmorStand as = (ArmorStand) event.getRightClicked(); + Block b = as.getLocation().getBlock(); + double num = event.getClickedPosition().getY() - 0.05; + if (num < 0) { + num = 0; + } else if (num > 2) { + num = 2; + } + num = 2.0 - num; + double angle = num * Math.PI; + boolean cancel = true; + + switch(tool) { + case HEADX: + if(permissionCheck(b, p)) return; + as.setHeadPose(as.getHeadPose().setX(angle)); + break; + case HEADY: + if(permissionCheck(b, p)) return; + as.setHeadPose(as.getHeadPose().setY(angle)); + break; + case HEADZ: + if(permissionCheck(b, p)) return; + as.setHeadPose(as.getHeadPose().setZ(angle)); + break; + case LARMX: + if(permissionCheck(b, p)) return; + as.setLeftArmPose(as.getLeftArmPose().setX(angle)); + break; + case LARMY: + if(permissionCheck(b, p)) return; + as.setLeftArmPose(as.getLeftArmPose().setY(angle)); + break; + case LARMZ: + if(permissionCheck(b, p)) return; + as.setLeftArmPose(as.getLeftArmPose().setZ(angle)); + break; + case RARMX: + if(permissionCheck(b, p)) return; + as.setRightArmPose(as.getRightArmPose().setX(angle)); + break; + case RARMY: + if(permissionCheck(b, p)) return; + as.setRightArmPose(as.getRightArmPose().setY(angle)); + break; + case RARMZ: + if(permissionCheck(b, p)) return; + as.setRightArmPose(as.getRightArmPose().setZ(angle)); + break; + case LLEGX: + if(permissionCheck(b, p)) return; + as.setLeftLegPose(as.getLeftLegPose().setX(angle)); + break; + case LLEGY: + if(permissionCheck(b, p)) return; + as.setLeftLegPose(as.getLeftLegPose().setY(angle)); + break; + case LLEGZ: + if(permissionCheck(b, p)) return; + as.setLeftLegPose(as.getLeftLegPose().setZ(angle)); + break; + case RLEGX: + if(permissionCheck(b, p)) return; + as.setRightLegPose(as.getRightLegPose().setX(angle)); + break; + case RLEGY: + if(permissionCheck(b, p)) return; + as.setRightLegPose(as.getRightLegPose().setY(angle)); + break; + case RLEGZ: + if(permissionCheck(b, p)) return; + as.setRightLegPose(as.getRightLegPose().setZ(angle)); + break; + case BODYX: + if(permissionCheck(b, p)) return; + as.setBodyPose(as.getBodyPose().setX(angle)); + break; + case BODYY: + if(permissionCheck(b, p)) return; + as.setBodyPose(as.getBodyPose().setY(angle)); + break; + case BODYZ: + if(permissionCheck(b, p)) return; + as.setBodyPose(as.getBodyPose().setZ(angle)); + break; + case MOVEX: + if(permissionCheck(b, p)) return; + as.teleport(as.getLocation().add(0.05 * (p.isSneaking() ? -1 : 1), 0.0, 0.0)); + break; + case MOVEY: + if(permissionCheck(b, p)) return; + as.teleport(as.getLocation().add(0.0, 0.05 * (p.isSneaking() ? -1 : 1), 0.0)); + break; + case MOVEZ: + if(permissionCheck(b, p)) return; + as.teleport(as.getLocation().add(0.0, 0.0, 0.05 * (p.isSneaking() ? -1 : 1))); + break; + case ROTAT: + if(permissionCheck(b, p)) return; + Location l = as.getLocation(); + l.setYaw(((float) num) * 180F); + as.teleport(l); + break; + case INVIS: + if(permissionCheck(b, p)) return; + as.setVisible(!as.isVisible()); + p.sendMessage(ChatColor.GREEN + Config.asVisible + ": " + (as.isVisible() ? Config.isTrue : Config.isFalse)); + break; + case CLONE: + if (p.hasPermission("astools.clone") || p.isOp()) { + if(permissionCheck(b, p)) return; + pickUpArmorStand(clone(as), p, true); + p.sendMessage(ChatColor.GREEN + Config.asCloned); + Utils.actionBarMsg(p, ChatColor.GREEN + Config.carrying); + } else { + p.sendMessage(ChatColor.RED + Config.noPerm); + } + break; + case SAVE: + if (p.hasPermission("astools.cmdblock") || p.isOp()) { + if(permissionCheck(b, p)) return; + generateCmdBlock(p.getLocation(), as); + p.sendMessage(ChatColor.GREEN + Config.cbCreated); + } else { + p.sendMessage(ChatColor.RED + Config.noPerm); + } + break; + case SIZE: + if(permissionCheck(b, p)) return; + as.setSmall(!as.isSmall()); + p.sendMessage(ChatColor.GREEN + Config.size + ": " + (as.isSmall() ? Config.small : Config.normal)); + break; + case BASE: + if(permissionCheck(b, p)) return; + as.setBasePlate(!as.hasBasePlate()); + p.sendMessage(ChatColor.GREEN + Config.basePlate + ": " + (as.hasBasePlate() ? Config.isOn : Config.isOff)); + break; + case GRAV: + if(permissionCheck(b, p)) return; + as.setGravity(!as.hasGravity()); + p.sendMessage(ChatColor.GREEN + Config.gravity + ": " + (as.hasGravity() ? Config.isOn : Config.isOff)); + break; + case ARMS: + if(permissionCheck(b, p)) return; + as.setArms(!as.hasArms()); + p.sendMessage(ChatColor.GREEN + Config.arms + ": " + (as.hasArms() ? Config.isOn : Config.isOff)); + break; + case NAME: + if(permissionCheck(b, p)) return; + setName(p, as); + break; + case PHEAD: + if(permissionCheck(b, p)) return; + setPlayerSkull(p, as); + break; + case INVUL: + if(permissionCheck(b, p)) return; + p.sendMessage(ChatColor.GREEN + Config.invul + ": " + (NBT.toggleInvulnerability(as) ? Config.isOn : Config.isOff)); + break; + case SLOTS: + if(permissionCheck(b, p)) return; + p.sendMessage(ChatColor.GREEN + Config.equip + ": " + (NBT.toggleSlotsDisabled(as) ? Config.locked : Config.unLocked)); + break; + case MOVE: + if(permissionCheck(b, p)) return; + UUID uuid = p.getUniqueId(); + if(plugin.carryingArmorStand.containsKey(uuid)) { + plugin.carryingArmorStand.remove(uuid); + Utils.actionBarMsg(p, Config.asDropped); + } else { + pickUpArmorStand(as, p, false); + Utils.actionBarMsg(p, ChatColor.GREEN + Config.carrying); + } + break; + case NODEL: + if(as.getMaxHealth() == 50) { + as.setMaxHealth(2); + p.sendMessage(ChatColor.GREEN + "Deletion Protection: Disabled"); + } else { + as.setMaxHealth(50); + p.sendMessage(ChatColor.GREEN + "Deletion Protection: Enabled"); + } + break; + default: + cancel = tool == ArmorStandTool.SUMMON || tool == ArmorStandTool.SAVE || event.isCancelled(); + } + event.setCancelled(cancel); + } + } + + @SuppressWarnings("deprecation") + @EventHandler + public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { + if (event.getRightClicked() instanceof ItemFrame && ArmorStandTool.isTool(event.getPlayer().getItemInHand())) { + event.setCancelled(true); + event.getPlayer().updateInventory(); + } + } + + private ArmorStand clone(ArmorStand as) { + ArmorStand clone = (ArmorStand) as.getWorld().spawnEntity(as.getLocation().add(1, 0, 0), EntityType.ARMOR_STAND); + clone.setGravity(as.hasGravity()); + clone.setHelmet(as.getHelmet()); + clone.setChestplate(as.getChestplate()); + clone.setLeggings(as.getLeggings()); + clone.setBoots(as.getBoots()); + clone.setItemInHand(as.getItemInHand()); + clone.setHeadPose(as.getHeadPose()); + clone.setBodyPose(as.getBodyPose()); + clone.setLeftArmPose(as.getLeftArmPose()); + clone.setRightArmPose(as.getRightArmPose()); + clone.setLeftLegPose(as.getLeftLegPose()); + clone.setRightLegPose(as.getRightLegPose()); + clone.setVisible(as.isVisible()); + clone.setBasePlate(as.hasBasePlate()); + clone.setArms(as.hasArms()); + clone.setCustomName(as.getCustomName()); + clone.setCustomNameVisible(as.isCustomNameVisible()); + clone.setSmall(as.isSmall()); + clone.setMaxHealth(as.getMaxHealth()); + NBT.setSlotsDisabled(clone, NBT.getDisabledSlots(as) == 2039583); + NBT.setInvulnerable(clone, NBT.isInvulnerable(as)); + return clone; + } + + @EventHandler + public void onBlockPlace(BlockPlaceEvent event) { + if(ArmorStandTool.isTool(event.getItemInHand())) { + event.setCancelled(true); + } + } + + @SuppressWarnings("deprecation") + @EventHandler + public void onPlayerMove(PlayerMoveEvent event) { + Player p = event.getPlayer(); + if(plugin.carryingArmorStand.containsKey(p.getUniqueId())) { + ArmorStand as = plugin.carryingArmorStand.get(p.getUniqueId()); + if (as == null || as.isDead()) { + plugin.carryingArmorStand.remove(p.getUniqueId()); + Utils.actionBarMsg(p, Config.asDropped); + return; + } + as.teleport(Utils.getLocationFacingPlayer(p)); + Utils.actionBarMsg(p, ChatColor.GREEN + Config.carrying); + } + } + + @EventHandler + public void onPlayerDeath(PlayerDeathEvent event) { + final Player p = event.getEntity(); + if(p.getWorld().getGameRuleValue("keepInventory").equalsIgnoreCase("true")) return; + List drops = event.getDrops(); + for(ArmorStandTool t : ArmorStandTool.values()) { + drops.remove(t.getItem()); + } + if(plugin.savedInventories.containsKey(p.getUniqueId())) { + drops.addAll(Arrays.asList(plugin.savedInventories.get(p.getUniqueId()))); + plugin.savedInventories.remove(p.getUniqueId()); + } + } + + @SuppressWarnings("deprecation") + @EventHandler + public void onInventoryClick(InventoryClickEvent event) { + if (event.isCancelled() || !(event.getWhoClicked() instanceof Player)) return; + final Player p = (Player) event.getWhoClicked(); + ItemStack item = event.getCurrentItem(); + if(event.getInventory().getHolder() != p && ArmorStandTool.isTool(item)) { + event.setCancelled(true); + p.updateInventory(); + return; + } + if(event.getAction() == InventoryAction.HOTBAR_SWAP || event.getAction() == InventoryAction.HOTBAR_MOVE_AND_READD) { + if(Utils.hasItems(p)) { + event.setCancelled(true); + p.updateInventory(); + } + } + } + + @SuppressWarnings("deprecation") + @EventHandler + public void onInventoryDrag(InventoryDragEvent event) { + if (event.isCancelled() || !(event.getWhoClicked() instanceof Player)) return; + final Player p = (Player) event.getWhoClicked(); + if (event.getInventory().getHolder() != p && Utils.containsItems(event.getNewItems().values())) { + event.setCancelled(true); + p.updateInventory(); + } + } + + @EventHandler + public void onPlayerDropItem(final PlayerDropItemEvent event) { + if(ArmorStandTool.isTool(event.getItemDrop().getItemStack())) { + event.getItemDrop().remove(); + } + } + + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + UUID uuid = event.getPlayer().getUniqueId(); + if(plugin.carryingArmorStand.containsKey(uuid)) { + plugin.returnArmorStand(plugin.carryingArmorStand.get(uuid)); + plugin.carryingArmorStand.remove(uuid); + } + if(plugin.savedInventories.containsKey(uuid)) { + event.getPlayer().getInventory().setContents(plugin.savedInventories.get(uuid)); + plugin.savedInventories.remove(uuid); + } + } + + @SuppressWarnings("deprecation") + @EventHandler + public void onPlayerInteract(PlayerInteractEvent event) { + Player p = event.getPlayer(); + ItemStack inHand = event.getItem(); + if(plugin.carryingArmorStand.containsKey(p.getUniqueId()) && !permissionCheck(plugin.carryingArmorStand.get(p.getUniqueId()).getLocation().getBlock(), p)) { + plugin.carryingArmorStand.remove(p.getUniqueId()); + Utils.actionBarMsg(p, Config.asDropped); + event.setCancelled(true); + return; + } + if(event.getAction() == Action.LEFT_CLICK_AIR || event.getAction() == Action.LEFT_CLICK_BLOCK) { + if (ArmorStandTool.isTool(inHand)) { + event.setCancelled(true); + Utils.cycleInventory(p); + } + } else if(event.getAction() == Action.RIGHT_CLICK_BLOCK || event.getAction() == Action.RIGHT_CLICK_AIR) { + if(ArmorStandTool.SUMMON.is(inHand)) { + event.setCancelled(true); + Location l = Utils.getLocationFacingPlayer(p); + if(permissionCheck(l.getBlock(), p)) return; + pickUpArmorStand(spawnArmorStand(l), p, true); + Utils.actionBarMsg(p, ChatColor.GREEN + Config.carrying); + p.updateInventory(); + } else if(ArmorStandTool.NAME.is(inHand)) { + event.setCancelled(true); + } + } + } + + @EventHandler + public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { + if(event.getEntity() instanceof ArmorStand && event.getDamager() instanceof Player && ArmorStandTool.isTool(((Player) event.getDamager()).getItemInHand())) { + event.setCancelled(true); + Utils.cycleInventory((Player) event.getDamager()); + } + } + + private ArmorStand spawnArmorStand(Location l) { + ArmorStand as = (ArmorStand) l.getWorld().spawnEntity(l, EntityType.ARMOR_STAND); + as.setHelmet(Config.helmet); + as.setChestplate(Config.chest); + as.setLeggings(Config.pants); + as.setBoots(Config.boots); + as.setItemInHand(Config.itemInHand); + as.setVisible(Config.isVisible); + as.setSmall(Config.isSmall); + as.setArms(Config.hasArms); + as.setBasePlate(Config.hasBasePlate); + as.setGravity(Config.hasGravity); + if(Config.defaultName.length() > 0) { + as.setCustomName(Config.defaultName); + as.setCustomNameVisible(true); + } + NBT.setSlotsDisabled(as, Config.equipmentLock); + NBT.setInvulnerable(as, Config.invulnerable); + return as; + } + + @SuppressWarnings({"deprecation", "ConstantConditions"}) + private void generateCmdBlock(Location l, ArmorStand as) { + Location loc = as.getLocation(); + int dSlots = NBT.getDisabledSlots(as); + int hand = as.getItemInHand() == null ? 0 : as.getItemInHand().getTypeId(); + int handDmg = as.getItemInHand() == null ? 0 : as.getItemInHand().getDurability(); + int boots = as.getBoots() == null ? 0 : as.getBoots().getTypeId(); + int bootsDmg = as.getBoots() == null ? 0 : as.getBoots().getDurability(); + int legs = as.getLeggings() == null ? 0 : as.getLeggings().getTypeId(); + int legsDmg = as.getLeggings() == null ? 0 : as.getLeggings().getDurability(); + int chest = as.getChestplate() == null ? 0 : as.getChestplate().getTypeId(); + int chestDmg = as.getChestplate() == null ? 0 : as.getChestplate().getDurability(); + int helm = as.getHelmet() == null ? 0 : as.getHelmet().getTypeId(); + int helmDmg = as.getHelmet() == null ? 0 : as.getHelmet().getDurability(); + EulerAngle he = as.getHeadPose(); + EulerAngle ll = as.getLeftLegPose(); + EulerAngle rl = as.getRightLegPose(); + EulerAngle la = as.getLeftArmPose(); + EulerAngle ra = as.getRightArmPose(); + EulerAngle bo = as.getBodyPose(); + String cmd = + "summon ArmorStand " + Utils.twoDec(loc.getX()) + " " + Utils.twoDec(loc.getY()) + " " + Utils.twoDec(loc.getZ()) + " {" + + (as.getMaxHealth() != 2 ? "Attributes:[{Name:\"generic.maxHealth\", Base:" + as.getMaxHealth() + "}]," : "") + + (as.isVisible() ? "" : "Invisible:1,") + + (as.hasBasePlate() ? "" : "NoBasePlate:1,") + + (as.hasGravity() ? "" : "NoGravity:1,") + + (as.hasArms() ? "ShowArms:1," : "") + + (as.isSmall() ? "Small:1," : "") + + (NBT.isInvulnerable(as) ? "Invulnerable:1," : "") + + (dSlots == 0 ? "" : ("DisabledSlots:" + dSlots + ",")) + + (as.isCustomNameVisible() ? "CustomNameVisible:1," : "") + + (as.getCustomName() == null ? "" : ("CustomName:\"" + as.getCustomName() + "\",")) + + (loc.getYaw() == 0F ? "" : ("Rotation:[" + Utils.twoDec(loc.getYaw()) + "f],")) + + (hand == 0 && boots == 0 && legs == 0 && chest == 0 && helm == 0 ? "" : ( + "Equipment:[" + + "{id:" + hand + ",Damage:" + handDmg + NBT.getItemStackTags(as.getItemInHand()) + "}," + + "{id:" + boots + ",Damage:" + bootsDmg + NBT.getItemStackTags(as.getBoots()) + "}," + + "{id:" + legs + ",Damage:" + legsDmg + NBT.getItemStackTags(as.getLeggings()) + "}," + + "{id:" + chest + ",Damage:" + chestDmg + NBT.getItemStackTags(as.getChestplate()) + "}," + + "{id:" + helm + ",Damage:" + helmDmg + NBT.getItemStackTags(as.getHelmet()) + NBT.skullOwner(as.getHelmet()) + "}],")) + + "Pose:{" + + (bo.equals(zero) ? "" : ("Body:[" + Utils.angle(bo.getX()) + "f," + Utils.angle(bo.getY()) + "f," + Utils.angle(bo.getZ()) + "f],")) + + (he.equals(zero) ? "" : ("Head:[" + Utils.angle(he.getX()) + "f," + Utils.angle(he.getY()) + "f," + Utils.angle(he.getZ()) + "f],")) + + (ll.equals(zero) ? "" : ("LeftLeg:[" + Utils.angle(ll.getX()) + "f," + Utils.angle(ll.getY()) + "f," + Utils.angle(ll.getZ()) + "f],")) + + (rl.equals(zero) ? "" : ("RightLeg:[" + Utils.angle(rl.getX()) + "f," + Utils.angle(rl.getY()) + "f," + Utils.angle(rl.getZ()) + "f],")) + + (la.equals(zero) ? "" : ("LeftArm:[" + Utils.angle(la.getX()) + "f," + Utils.angle(la.getY()) + "f," + Utils.angle(la.getZ()) + "f],")) + + "RightArm:[" + Utils.angle(ra.getX()) + "f," + Utils.angle(ra.getY()) + "f," + Utils.angle(ra.getZ()) + "f]}}"; + Block b = l.getBlock(); + b.setType(Material.COMMAND); + b.setData((byte) 0); + CommandBlock cb = (CommandBlock) b.getState(); + cb.setCommand(cmd); + cb.update(); + } + + @SuppressWarnings("deprecation") + @EventHandler + public void onSignChange(final SignChangeEvent event) { + if(event.getBlock().hasMetadata("armorStand")) { + final Block b = event.getBlock(); + final ArmorStand as = getArmorStand(b); + boolean delete = true; + if (as != null) { + String input = ""; + for (String line : event.getLines()) { + if (line != null && line.length() > 0) { + input += ChatColor.translateAlternateColorCodes('&', line); + } + } + if(b.hasMetadata("setName")) { + if (input.length() > 0) { + as.setCustomName(input); + as.setCustomNameVisible(true); + } else { + as.setCustomName(""); + as.setCustomNameVisible(false); + as.setCustomNameVisible(false); + } + } else if(b.hasMetadata("setSkull")) { + if(MC_USERNAME_PATTERN.matcher(input).matches()) { + final String name = input; + b.setType(Material.SKULL); + final Skull s = (Skull) b.getState(); + s.setSkullType(SkullType.PLAYER); + delete = false; + event.getPlayer().sendMessage(ChatColor.GOLD + Config.pleaseWait); + new BukkitRunnable() { + @Override + public void run() { + final boolean ok = Utils.loadProfile(name); + new BukkitRunnable() { + @Override + public void run() { + if (ok) { + s.setOwner(name); + s.update(); + as.setHelmet(b.getDrops().iterator().next()); + event.getPlayer().sendMessage(ChatColor.GREEN + Config.appliedHead + ChatColor.GOLD + " " + name); + } else { + event.getPlayer().sendMessage(ChatColor.RED + Config.noHead + ChatColor.GOLD + " " + name); + } + b.setType(Material.AIR); + b.setData((byte) 0); + } + }.runTask(plugin); + } + }.runTaskAsynchronously(plugin); + } else { + event.getPlayer().sendMessage(ChatColor.RED + input + " " + Config.invalidName); + } + } + } + event.setCancelled(true); + b.removeMetadata("armorStand", plugin); + b.removeMetadata("setName", plugin); + b.removeMetadata("setSkull", plugin); + if(delete) { + b.setType(Material.AIR); + b.setData((byte) 0); + } + } + } + + @SuppressWarnings("deprecation") + private void setName(Player p, ArmorStand as) { + Block b = Utils.findAnAirBlock(p.getLocation()); + if(b == null) { + p.sendMessage(ChatColor.RED + Config.noAirError); + return; + } + b.setData((byte) 0); + b.setType(Material.SIGN_POST); + Utils.openSign(p, b); + b.setMetadata("armorStand", new FixedMetadataValue(plugin, as.getUniqueId())); + b.setMetadata("setName", new FixedMetadataValue(plugin, true)); + } + + @SuppressWarnings("deprecation") + private void setPlayerSkull(Player p, ArmorStand as) { + Block b = Utils.findAnAirBlock(p.getLocation()); + if(b == null) { + p.sendMessage(ChatColor.RED + Config.noAirError); + return; + } + b.setData((byte) 0); + b.setType(Material.SIGN_POST); + Utils.openSign(p, b); + b.setMetadata("armorStand", new FixedMetadataValue(plugin, as.getUniqueId())); + b.setMetadata("setSkull", new FixedMetadataValue(plugin, true)); + } + + private ArmorStand getArmorStand(Block b) { + UUID uuid = null; + for (MetadataValue value : b.getMetadata("armorStand")) { + if (value.getOwningPlugin() == this) { + uuid = (UUID) value.value(); + } + } + b.removeMetadata("armorStand", plugin); + if (uuid != null) { + for(org.bukkit.entity.Entity e : b.getWorld().getEntities()) { + if(e instanceof ArmorStand && e.getUniqueId().equals(uuid)) { + return (ArmorStand) e; + } + } + } + return null; + } + + boolean permissionCheck(Block b, Player p) { + if(Config.worldGuardPlugin == null) return false; + boolean canBuild = Config.worldGuardPlugin.canBuild(p, b); + if(!canBuild) { + p.sendMessage(ChatColor.RED + Config.wgNoPerm); + } + return !canBuild; + } + + void pickUpArmorStand(ArmorStand as, Player p, boolean newlySummoned) { + plugin.carryingArmorStand.put(p.getUniqueId(), as); + if(newlySummoned) return; + as.setMetadata("startLoc", new FixedMetadataValue(plugin, as.getLocation())); + } + +} diff --git a/src/com/gmail/St3venAU/plugins/ArmorStandTools/NBT.java b/src/com/gmail/St3venAU/plugins/ArmorStandTools/NBT.java new file mode 100644 index 0000000..fa58b03 --- /dev/null +++ b/src/com/gmail/St3venAU/plugins/ArmorStandTools/NBT.java @@ -0,0 +1,187 @@ +package com.gmail.St3venAU.plugins.ArmorStandTools; + +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.ArmorStand; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.LeatherArmorMeta; +import org.bukkit.inventory.meta.SkullMeta; + +import java.lang.reflect.Method; +import java.util.Map; + +class NBT { + + static boolean toggleSlotsDisabled(ArmorStand as) { + Object nmsEntity = getNmsEntity(as); + if(nmsEntity == null) return false; + Object tag = getTag(nmsEntity); + if(tag == null) return false; + boolean slotsDisabled = getInt(tag, "DisabledSlots") == 0; + setInt(tag, "DisabledSlots", slotsDisabled ? 2039583 : 0); + saveTagA(nmsEntity, tag); + return slotsDisabled; + } + + static boolean toggleInvulnerability(ArmorStand as) { + Object nmsEntity = getNmsEntity(as); + if(nmsEntity == null) return false; + Object tag = getTag(nmsEntity); + if(tag == null) return false; + boolean invulnerable = !getBoolean(tag, "Invulnerable"); + setBoolean(tag, "Invulnerable", invulnerable); + saveTagF(nmsEntity, tag); + return invulnerable; + } + + static void setSlotsDisabled(ArmorStand as, boolean slotsDisabled) { + Object nmsEntity = getNmsEntity(as); + if(nmsEntity == null) return; + Object tag = getTag(nmsEntity); + if(tag == null) return; + setInt(tag, "DisabledSlots", slotsDisabled ? 2039583 : 0); + saveTagA(nmsEntity, tag); + } + + static void setInvulnerable(ArmorStand as, boolean invulnerable) { + Object nmsEntity = getNmsEntity(as); + if(nmsEntity == null) return; + Object tag = getTag(nmsEntity); + if(tag == null) return; + setBoolean(tag, "Invulnerable", invulnerable); + saveTagF(nmsEntity, tag); + } + + static boolean isInvulnerable(ArmorStand as) { + Object nmsEntity = getNmsEntity(as); + if (nmsEntity == null) return false; + Object tag = getTag(nmsEntity); + return tag != null && getBoolean(tag, "Invulnerable"); + } + + static int getDisabledSlots(ArmorStand as) { + Object nmsEntity = getNmsEntity(as); + if(nmsEntity == null) return 0; + Object tag = getTag(nmsEntity); + if (tag == null) return 0; + return getInt(tag, "DisabledSlots"); + } + + private static Object getNmsEntity(org.bukkit.entity.Entity entity) { + try { + return entity.getClass().getMethod("getHandle").invoke(entity); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + private static Object getTag(Object nmsEntity) { + try { + Method method = nmsEntity.getClass().getMethod("getNBTTag"); + Object tag = method.invoke(nmsEntity); + if(tag == null) { + tag = Utils.getNMSClass("NBTTagCompound").newInstance(); + } + method = nmsEntity.getClass().getMethod("c", Utils.getNMSClass("NBTTagCompound")); + method.invoke(nmsEntity, tag); + return tag; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + @SuppressWarnings("deprecation") + static String getItemStackTags(ItemStack is) { + if(is == null) { + return ""; + } + StringBuilder tags = new StringBuilder(""); + if(is.getItemMeta() != null && is.getItemMeta() instanceof LeatherArmorMeta) { + LeatherArmorMeta armorMeta = (LeatherArmorMeta) is.getItemMeta(); + tags.append("display:{color:"); + tags.append(armorMeta.getColor().asRGB()); + tags.append("}"); + } + Map enchants = is.getEnchantments(); + if(enchants.size() > 0) { + if(tags.length() > 0) { + tags.append(","); + } + tags.append("ench:["); + + for(Enchantment e : enchants.keySet()) { + tags.append("{id:"); + tags.append(e.getId()); + tags.append(",lvl:"); + tags.append(enchants.get(e)); + tags.append("},"); + } + + tags.setCharAt(tags.length() - 1, ']'); + } + return tags.length() == 0 ? "" : (",tag:{" + tags.toString() + "}"); + } + + static String skullOwner(ItemStack is) { + if(is == null || is.getItemMeta() == null || !(is.getItemMeta() instanceof SkullMeta)) { + return ""; + } + SkullMeta skull = (SkullMeta) is.getItemMeta(); + if(skull.hasOwner()) { + return ",tag:{SkullOwner:\"" + skull.getOwner() + "\"}"; + } else { + return ""; + } + } + + private static int getInt(Object tag, String name) { + try { + return (Integer) tag.getClass().getMethod("getInt", String.class).invoke(tag, name); + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + private static boolean getBoolean(Object tag, String name) { + try { + return (Boolean) tag.getClass().getMethod("getBoolean", String.class).invoke(tag, name); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + private static void setInt(Object tag, String name, int value) { + try { + tag.getClass().getMethod("setInt", String.class, int.class).invoke(tag, name, value); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static void setBoolean(Object tag, String name, boolean value) { + try { + tag.getClass().getMethod("setBoolean", String.class, boolean.class).invoke(tag, name, value); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static void saveTagA(Object nmsEntity, Object tag) { + try { + nmsEntity.getClass().getMethod("a", Utils.getNMSClass("NBTTagCompound")).invoke(nmsEntity, tag); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static void saveTagF(Object nmsEntity, Object tag) { + try { + nmsEntity.getClass().getMethod("f", Utils.getNMSClass("NBTTagCompound")).invoke(nmsEntity, tag); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/com/gmail/St3venAU/plugins/ArmorStandTools/Utils.java b/src/com/gmail/St3venAU/plugins/ArmorStandTools/Utils.java new file mode 100644 index 0000000..21ac61a --- /dev/null +++ b/src/com/gmail/St3venAU/plugins/ArmorStandTools/Utils.java @@ -0,0 +1,144 @@ +package com.gmail.St3venAU.plugins.ArmorStandTools; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Collection; + +class Utils { + + private static DecimalFormat twoDec; + + static boolean containsItems(Collection items) { + for(ItemStack i : items) { + if(items.contains(i)) { + return true; + } + } + return false; + } + + static boolean hasItems(Player p) { + for(ItemStack i : p.getInventory()) { + if(ArmorStandTool.isTool(i)) { + return true; + } + } + return false; + } + + static Location getLocationFacingPlayer(Player p) { + Vector v = p.getLocation().getDirection(); + v.setY(0); + v.multiply(3); + Location l = p.getLocation().add(v); + l.setYaw(p.getLocation().getYaw() + 180); + int n; + boolean ok = false; + for (n = 0; n < 5; n++) { + if (l.getBlock().getType().isSolid()) { + l.add(0, 1, 0); + } else { + ok = true; + break; + } + } + if (!ok) { + l.subtract(0, 5, 0); + } + return l; + } + + @SuppressWarnings("deprecation") + static void cycleInventory(Player p) { + Inventory i = p.getInventory(); + ItemStack temp; + for (int n = 0; n < 9; n++) { + temp = i.getItem(n); + i.setItem(n, i.getItem(27 + n)); + i.setItem(27 + n, i.getItem(18 + n)); + i.setItem(18 + n, i.getItem(9 + n)); + i.setItem(9 + n, temp); + } + p.updateInventory(); + } + + static void actionBarMsg(Player p, String msg) { + try { + Object chat = getNMSClass("ChatSerializer").getMethod("a", String.class).invoke(null, "{text:\"" + msg + "\"}"); + Object packet = getNMSClass("PacketPlayOutChat").getConstructor(getNMSClass("IChatBaseComponent"), byte.class).newInstance(chat, (byte) 2); + sendPacket(p, packet); + } catch (Exception e) { + e.printStackTrace(); + } + } + + static void openSign(Player p, Block b) { + try { + Object world = b.getWorld().getClass().getMethod("getHandle").invoke(b.getWorld()); + Object blockPos = getNMSClass("BlockPosition").getConstructor(int.class, int.class, int.class).newInstance(b.getX(), b.getY(), b.getZ()); + Object sign = world.getClass().getMethod("getTileEntity", getNMSClass("BlockPosition")).invoke(world, blockPos); + Object player = p.getClass().getMethod("getHandle").invoke(p); + player.getClass().getMethod("openSign", getNMSClass("TileEntitySign")).invoke(player, sign); + } catch (Exception e) { + e.printStackTrace(); + } + } + + static Class getNMSClass(String nmsClassString) throws ClassNotFoundException { + if(nmsClassString.equals("ChatSerializer") && !Main.NMS_VERSION.equals("v1_8_R1")) { + nmsClassString = "IChatBaseComponent$ChatSerializer"; + } + return Class.forName("net.minecraft.server." + Main.NMS_VERSION + "." + nmsClassString); + } + + static boolean loadProfile(String name) { + try { + Object server = getNMSClass("MinecraftServer").getMethod("getServer").invoke(null); + Object cache = server.getClass().getMethod("getUserCache").invoke(server); + return cache.getClass().getMethod("getProfile", String.class).invoke(cache, name) != null; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + private static void sendPacket(Player p, Object packet) { + try { + Object player = p.getClass().getMethod("getHandle").invoke(p); + Object connection = player.getClass().getField("playerConnection").get(player); + connection.getClass().getMethod("sendPacket", getNMSClass("Packet")).invoke(connection, packet); + } catch (Exception e) { + e.printStackTrace(); + } + } + + static String angle(double d) { + return twoDec(d * 180.0 / Math.PI); + } + + static String twoDec(double d) { + if(twoDec == null) { + twoDec = new DecimalFormat("0.0#"); + DecimalFormatSymbols symbols = new DecimalFormatSymbols(); + symbols.setDecimalSeparator('.'); + twoDec.setDecimalFormatSymbols(symbols); + } + return twoDec.format(d); + } + + static Block findAnAirBlock(Location l) { + while(l.getY() < 255 && l.getBlock().getType() != Material.AIR) { + l.add(0, 1, 0); + } + return l.getY() < 255 && l.getBlock().getType() == Material.AIR ? l.getBlock() : null; + } + +} diff --git a/src/config.yml b/src/config.yml new file mode 100644 index 0000000..61f67d1 --- /dev/null +++ b/src/config.yml @@ -0,0 +1,46 @@ +# Armor Stand Tools v1.7 +# +# by St3venAU (St3venAU@gmail.com) +# +# Features: +# - Summon armor stands +# - Name armor stands +# - Toggle: Gravity, Visibility, Arms, Base, Size, Invulnerability, Equipment Lock +# - Manipulate the position of the Head, Body, Arms and Legs +# - Clone armor stand tool +# - Create command block tool: Creates a command block with the command that will summon this +# armor stand in its current state +# - Player head tool: Set's an armor stand's head to the head of a specified player. +# - Support for WorldGuard regions. +# - User customizable language config. +# +# Commands: +# /astools Give yourself all of the armor stand tools (Note: Clears your inventory) +# /astools reload Reload the armor stand tools plugin config file +# /ast Alias for the /astools +# +# Permissions: +# astools.command Permission for the /astools command +# astools.reload Permission to reload the plugin with /astools reload +# astools.use Permission for using any of the tools (except the ones below) +# astools.clone Permission to use the clone tool +# astools.cmdblock Permission to use the save tool (Creates a command block) +# +# These are the defaults for spawning new armor stands with the /astools (or /ast) armor stand +# The helmet, chest, pants, boots and inHand items are set like this: MATERIAL dataValue +# e.g. To have red wool in the armor stands hand by default: inHand: WOOL 14 +# +integrateWithWorldGuard: true +helmet: SKULL_ITEM 3 +chest: IRON_CHESTPLATE 0 +pants: IRON_LEGGINGS 0 +boots: IRON_BOOTS 0 +inHand: AIR 0 +isVisible: true +isSmall: false +hasArms: true +hasBasePlate: false +hasGravity: false +name: '' +invulnerable: false +equipmentLock: false \ No newline at end of file diff --git a/src/language.yml b/src/language.yml new file mode 100644 index 0000000..ad8561c --- /dev/null +++ b/src/language.yml @@ -0,0 +1,227 @@ +# Armor Stand Tools Language Config +# +# Edit these strings if you wish to customize the wording +# or the language of the text used in this plugin. +# +# IMPORTANT: Only edit the text that is between the single +# quotation marks: 'like this' +# If you change anything outside of the quotation marks, +# errors will occur. +# Do not use ' marks inside the string itself. +# +# If you ever wish to return to the default language config +# then delete this file and reload the plugin. A new default +# file will be generated. +# +#################### +# General Messages # +#################### +invReturned: 'Inventory contents returned' +asDropped: 'Armor stand dropped' +asVisible: 'Armor stand visible' +isTrue: 'True' +isFalse: 'False' +asCloned: 'Armor stand cloned' +carrying: 'Carrying armor stand. Click to drop.' +noPerm: 'You do not have permission to use this tool' +cbCreated: 'Command block created' +size: 'Size' +small: 'Small' +normal: 'Normal' +basePlate: 'Base plate' +isOn: 'On' +isOff: 'Off' +gravity: 'Gravity' +arms: 'Arms' +invul: 'Invulnerability' +equip: 'Equipment' +locked: 'Locked' +unLocked: 'Un-Locked' +notConsole: 'This command can not be run from console' +giveMsg1: 'Given armor stand tools. L-click any tool to cycle through tools.' +giveMsg2: 'Run this command again to return your inventory.' +conReload: 'Armor Stand Tools config reloaded' +noRelPerm: 'You do not have permission to reload the plugin' +noAirError: 'Error: Failed to find a near-by air block. Move and try again.' +pleaseWait: 'Please wait, this may take a few seconds...' +appliedHead: 'Applied the head of player' +noHead: 'No player head found for player' +invalidName: 'is not a valid minecraft username' +wgNoPerm: 'You do not have permission to alter an armor stand in this region' +# +############################# +# Tool names & descriptions # +############################# +tool: + headX: + name: 'Head X' + lore: + - 'R-Click armor stand to change Head X Value' + - 'Value depends on how high up the body you click' + headY: + name: 'Head Y' + lore: + - 'R-Click armor stand to change Head Y Value' + - 'Value depends on how high up the body you click' + headZ: + name: 'Head Z' + lore: + - 'R-Click armor stand to change Head Z Value' + - 'Value depends on how high up the body you click' + lArmX: + name: 'Left Arm X' + lore: + - 'R-Click armor stand to change Left Arm X Value' + - 'Value depends on how high up the body you click' + lArmY: + name: 'Left Arm Y' + lore: + - 'R-Click armor stand to change Left Arm Y Value' + - 'Value depends on how high up the body you click' + lArmZ: + name: 'Left Arm Z' + lore: + - 'R-Click armor stand to change Left Arm Z Value' + - 'Value depends on how high up the body you click' + rArmX: + name: 'Right Arm X' + lore: + - 'R-Click armor stand to change Right Arm X Value' + - 'Value depends on how high up the body you click' + rArmY: + name: 'Right Arm Y' + lore: + - 'R-Click armor stand to change Right Arm Y Value' + - 'Value depends on how high up the body you click' + rArmZ: + name: 'Right Arm Z' + lore: + - 'R-Click armor stand to change Right Arm Z Value' + - 'Value depends on how high up the body you click' + moveX: + name: 'Move X' + lore: + - 'R-Click armor stand to move +0.1 X' + - 'Crouch R-Click for -0.1 X' + moveY: + name: 'Move Y' + lore: + - 'R-Click armor stand to move +0.1 Y' + - 'Crouch R-Click for -0.1 Y' + moveZ: + name: 'Move Z' + lore: + - 'R-Click armor stand to move +0.1 Z' + - 'Crouch R-Click for -0.1 Z' + rotat: + name: 'Rotation' + lore: + - 'R-Click armor stand to change its Rotation' + - 'Value depends on how high up the body you click' + invis: + name: 'Toggle Visibility' + lore: + - 'R-Click armor stand to toggle its visibility' + summon: + name: 'Summon Armor Stand' + lore: + - 'R-Click to summon an armor stand and pick it up' + - 'Any click will drop it' + - 'To change summoned armor stand defaults, edit config.yml' + clone: + name: 'Clone' + lore: + - 'R-Click armor stand to pick up a clone of it' + - 'Any click will drop it' + save: + name: 'Create Command Block' + lore: + - 'R-Click armor stand to create command block' + - 'with a summon command for this armor stand' + lLegX: + name: 'Left Leg X' + lore: + - 'R-Click armor stand to change Left Leg X' + - 'Value depends on how high up the body you click' + lLegY: + name: 'Left Leg Y' + lore: + - 'R-Click armor stand to change Left Leg Y' + - 'Value depends on how high up the body you click' + lLegZ: + name: 'Left Leg Z' + lore: + - 'R-Click armor stand to change Left Leg Z' + - 'Value depends on how high up the body you click' + rLegX: + name: 'Right Leg X' + lore: + - 'R-Click armor stand to change Right Leg X' + - 'Value depends on how high up the body you click' + rLegY: + name: 'Right Leg Y' + lore: + - 'R-Click armor stand to change Right Leg Y' + - 'Value depends on how high up the body you click' + rLegZ: + name: 'Right Leg Z' + lore: + - 'R-Click armor stand to change Right Leg Z' + - 'Value depends on how high up the body you click' + bodyX: + name: 'Body X' + lore: + - 'R-Click armor stand to change Body Z' + - 'Value depends on how high up the body you click' + bodyY: + name: 'Body Y' + lore: + - 'R-Click armor stand to change Body Z' + - 'Value depends on how high up the body you click' + bodyZ: + name: 'Body Z' + lore: + - 'R-Click armor stand to change Body Z' + - 'Value depends on how high up the body you click' + size: + name: 'Toggle Size' + lore: + - 'R-Click armor stand to toggle its size' + base: + name: 'Toggle Base' + lore: + - 'R-Click armor stand to toggle its base' + grav: + name: 'Toggle Gravity' + lore: + - 'R-Click armor stand to toggle its gravity' + arms: + name: 'Toggle Arms' + lore: + - 'R-Click armor stand to toggle its arms' + name: + name: 'Set Name' + lore: + - 'R-Click armor stand to set its name' + - 'Standard color codes accepted' + slots: + name: 'Toggle Equipment Lock' + lore: + - 'R-Click armor stand to toggle equipment lock' + - 'When equipment is locked, players can not take or add equipment' + pHead: + name: 'Give a Player Head' + lore: + - 'R-Click armor stand and specify a player name to' + - 'give it that players head' + - '(Will not work if used multiple times too fast)' + invul: + name: 'Toggle Invulnerability' + lore: + - 'R-Click armor stand to toggle invulnerability' + - 'Note: Creative mode players can break invulnerable armor stands' + move: + name: 'Pick Up (Move)' + lore: + - 'R-Click armor stand to pick it up and move it' + - 'Any click will drop it again' \ No newline at end of file diff --git a/src/plugin.yml b/src/plugin.yml new file mode 100644 index 0000000..726383e --- /dev/null +++ b/src/plugin.yml @@ -0,0 +1,13 @@ +main: com.gmail.St3venAU.plugins.ArmorStandTools.Main +name: ArmorStandTools +version: 1.7 +author: St3venAU +description: Armor stand manipulation tools +softdepend: [WorldGuard] +commands: + astools: + description: Give yourself all of the armor stand tools (Warning; clears your inventory). + aliases: ast + usage: Usage /astools or /astools reload + permission: astools.command + permission-message: You don't have permission to use this command \ No newline at end of file