Add 1.15 support, add ArmorEquipEvent

- Added support for version 1.15 of minecraft. From now on, the NBT constructors are private instead of public. During initialization, they're made accessible now.
- Added ArmorEquipEvent that keeps track of every possible way someone might equip armor. It is then cancelled if needed.
- Updated language file. A long and a short name of each tier is now supported, which can be used as variables.
This commit is contained in:
Pim van der Loos 2019-12-11 21:51:51 +01:00
parent e906ddfdb3
commit c5abedc89b
No known key found for this signature in database
GPG Key ID: C16F020ADAE6D5A8
13 changed files with 661 additions and 78 deletions

View File

@ -0,0 +1,163 @@
package com.codingforcookies.armorequip;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.bukkit.inventory.ItemStack;
/**
* @author Arnah
* @since Jul 30, 2015
*/
public final class ArmorEquipEvent extends PlayerEvent implements Cancellable
{
private static final HandlerList handlers = new HandlerList();
private boolean cancel = false;
private final EquipMethod equipType;
private final ArmorType type;
private ItemStack oldArmorPiece, newArmorPiece;
/**
* Constructor for the ArmorEquipEvent.
*
* @param player The player who put on / removed the armor.
* @param type The ArmorType of the armor added
* @param oldArmorPiece The ItemStack of the armor removed.
* @param newArmorPiece The ItemStack of the armor added.
*/
public ArmorEquipEvent(final Player player, final EquipMethod equipType, final ArmorType type,
final ItemStack oldArmorPiece, final ItemStack newArmorPiece)
{
super(player);
this.equipType = equipType;
this.type = type;
this.oldArmorPiece = oldArmorPiece;
this.newArmorPiece = newArmorPiece;
}
/**
* Gets a list of handlers handling this event.
*
* @return A list of handlers handling this event.
*/
public final static HandlerList getHandlerList()
{
return handlers;
}
/**
* Gets a list of handlers handling this event.
*
* @return A list of handlers handling this event.
*/
@Override
public final HandlerList getHandlers()
{
return handlers;
}
/**
* Sets if this event should be cancelled.
*
* @param cancel If this event should be cancelled.
*/
@Override
public final void setCancelled(final boolean cancel)
{
this.cancel = cancel;
}
/**
* Gets if this event is cancelled.
*
* @return If this event is cancelled
*/
@Override
public final boolean isCancelled()
{
return cancel;
}
public final ArmorType getType()
{
return type;
}
/**
* Returns the last equipped armor piece, could be a piece of armor,
* {@link Material#Air}, or null.
*/
public final ItemStack getOldArmorPiece()
{
return oldArmorPiece;
}
public final void setOldArmorPiece(final ItemStack oldArmorPiece)
{
this.oldArmorPiece = oldArmorPiece;
}
/**
* Returns the newly equipped armor, could be a piece of armor,
* {@link Material#Air}, or null.
*/
public final ItemStack getNewArmorPiece()
{
return newArmorPiece;
}
public final void setNewArmorPiece(final ItemStack newArmorPiece)
{
this.newArmorPiece = newArmorPiece;
}
/**
* Gets the method used to either equip or unequip an armor piece.
*/
public EquipMethod getMethod()
{
return equipType;
}
public enum EquipMethod
{// These have got to be the worst documentations ever.
/**
* When you shift click an armor piece to equip or unequip
*/
SHIFT_CLICK,
/**
* When you drag and drop the item to equip or unequip
*/
DRAG,
/**
* When you manually equip or unequip the item. Use to be DRAG
*/
PICK_DROP,
/**
* When you right click an armor piece in the hotbar without the inventory open
* to equip.
*/
HOTBAR,
/**
* When you press the hotbar slot number while hovering over the armor slot to
* equip or unequip
*/
HOTBAR_SWAP,
/**
* When in range of a dispenser that shoots an armor piece to equip.<br>
* Requires the spigot version to have
* {@link org.bukkit.event.block.BlockDispenseArmorEvent} implemented.
*/
DISPENSER,
/**
* When an armor piece is removed due to it losing all durability.
*/
BROKE,
/**
* When you die causing all armor to unequip
*/
DEATH,;
}
}

View File

@ -0,0 +1,265 @@
package com.codingforcookies.armorequip;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.Event.Result;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryAction;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.event.inventory.InventoryType.SlotType;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerItemBreakEvent;
import org.bukkit.inventory.ItemStack;
import com.codingforcookies.armorequip.ArmorEquipEvent.EquipMethod;
/**
* @author Arnah
* @since Jul 30, 2015
*/
public class ArmorListener implements Listener
{
private final List<String> blockedMaterials;
public ArmorListener(List<String> blockedMaterials)
{
this.blockedMaterials = blockedMaterials;
}
@EventHandler
public final void inventoryClick(final InventoryClickEvent e)
{
boolean shift = false, numberkey = false;
if (e.isCancelled())
return;
if (e.getAction() == InventoryAction.NOTHING)
return;// Why does this get called if nothing happens??
if (e.getClick().equals(ClickType.SHIFT_LEFT) || e.getClick().equals(ClickType.SHIFT_RIGHT))
shift = true;
if (e.getClick().equals(ClickType.NUMBER_KEY))
numberkey = true;
if (e.getSlotType() != SlotType.ARMOR && e.getSlotType() != SlotType.QUICKBAR &&
e.getSlotType() != SlotType.CONTAINER)
return;
if (e.getClickedInventory() != null && !e.getClickedInventory().getType().equals(InventoryType.PLAYER))
return;
if (!e.getInventory().getType().equals(InventoryType.CRAFTING) &&
!e.getInventory().getType().equals(InventoryType.PLAYER))
return;
if (!(e.getWhoClicked() instanceof Player))
return;
ArmorType newArmorType = ArmorType.matchType(shift ? e.getCurrentItem() : e.getCursor());
if (!shift && newArmorType != null && e.getRawSlot() != newArmorType.getSlot())
// Used for drag and drop checking to make sure you aren't trying to place a
// helmet in the boots slot.
return;
if (shift)
{
newArmorType = ArmorType.matchType(e.getCurrentItem());
if (newArmorType != null)
{
boolean equipping = true;
if (e.getRawSlot() == newArmorType.getSlot())
equipping = false;
if (newArmorType.equals(ArmorType.HELMET) &&
(equipping ? isAirOrNull(e.getWhoClicked().getInventory().getHelmet()) :
!isAirOrNull(e.getWhoClicked().getInventory().getHelmet())) ||
newArmorType.equals(ArmorType.CHESTPLATE) && (equipping ?
isAirOrNull(e.getWhoClicked().getInventory().getChestplate()) :
!isAirOrNull(e.getWhoClicked().getInventory().getChestplate())) ||
newArmorType.equals(ArmorType.LEGGINGS) && (equipping ?
isAirOrNull(e.getWhoClicked().getInventory().getLeggings()) :
!isAirOrNull(e.getWhoClicked().getInventory().getLeggings())) ||
newArmorType.equals(ArmorType.BOOTS) && (equipping ?
isAirOrNull(e.getWhoClicked().getInventory().getBoots()) :
!isAirOrNull(e.getWhoClicked().getInventory().getBoots())))
{
ArmorEquipEvent armorEquipEvent = new ArmorEquipEvent((Player) e.getWhoClicked(),
EquipMethod.SHIFT_CLICK, newArmorType,
equipping ? null : e.getCurrentItem(),
equipping ? e.getCurrentItem() : null);
Bukkit.getServer().getPluginManager().callEvent(armorEquipEvent);
if (armorEquipEvent.isCancelled())
e.setCancelled(true);
}
}
}
else
{
ItemStack newArmorPiece = e.getCursor();
ItemStack oldArmorPiece = e.getCurrentItem();
if (numberkey)
if (e.getClickedInventory().getType().equals(InventoryType.PLAYER))
{ // Prevents shit in the 2by2 crafting
// e.getClickedInventory() == The players inventory
// e.getHotBarButton() == key people are pressing to equip or unequip the item
// to or from.
// e.getRawSlot() == The slot the item is going to.
// e.getSlot() == Armor slot, can't use e.getRawSlot() as that gives a hotbar
// slot ;-;
ItemStack hotbarItem = e.getClickedInventory().getItem(e.getHotbarButton());
if (!isAirOrNull(hotbarItem))
{ // Equipping
newArmorType = ArmorType.matchType(hotbarItem);
newArmorPiece = hotbarItem;
oldArmorPiece = e.getClickedInventory().getItem(e.getSlot());
}
else
// Unequipping
newArmorType = ArmorType
.matchType(!isAirOrNull(e.getCurrentItem()) ? e.getCurrentItem() : e.getCursor());
}
else
{
if (isAirOrNull(e.getCursor()) && !isAirOrNull(e.getCurrentItem()))
// unequip with no new item going into the slot.
newArmorType = ArmorType.matchType(e.getCurrentItem());
// e.getCurrentItem() == Unequip
// e.getCursor() == Equip
// newArmorType = ArmorType.matchType(!isAirOrNull(e.getCurrentItem()) ?
// e.getCurrentItem() : e.getCursor());
}
if (newArmorType != null && e.getRawSlot() == newArmorType.getSlot())
{
EquipMethod method = EquipMethod.PICK_DROP;
if (e.getAction().equals(InventoryAction.HOTBAR_SWAP) || numberkey)
method = EquipMethod.HOTBAR_SWAP;
ArmorEquipEvent armorEquipEvent = new ArmorEquipEvent((Player) e.getWhoClicked(), method, newArmorType,
oldArmorPiece, newArmorPiece);
Bukkit.getServer().getPluginManager().callEvent(armorEquipEvent);
if (armorEquipEvent.isCancelled())
e.setCancelled(true);
}
}
}
@EventHandler
public void playerInteractEvent(PlayerInteractEvent e)
{
if (e.getAction() == Action.PHYSICAL)
return;
if (e.getAction() == Action.RIGHT_CLICK_AIR || e.getAction() == Action.RIGHT_CLICK_BLOCK)
{
final Player player = e.getPlayer();
if (e.getClickedBlock() != null && e.getAction() == Action.RIGHT_CLICK_BLOCK)
{ // Having both of these checks is useless, might as well do it though.
// Some blocks have actions when you right click them which stops the client
// from equipping the armor in hand.
Material mat = e.getClickedBlock().getType();
for (String s : blockedMaterials)
if (mat.name().equalsIgnoreCase(s))
return;
}
ArmorType newArmorType = ArmorType.matchType(e.getItem());
if (newArmorType != null)
{
if (newArmorType.equals(ArmorType.HELMET) && isAirOrNull(e.getPlayer().getInventory().getHelmet()) ||
newArmorType
.equals(ArmorType.CHESTPLATE) && isAirOrNull(e.getPlayer().getInventory().getChestplate()) ||
newArmorType
.equals(ArmorType.LEGGINGS) && isAirOrNull(e.getPlayer().getInventory().getLeggings()) ||
newArmorType.equals(ArmorType.BOOTS) && isAirOrNull(e.getPlayer().getInventory().getBoots()))
{
ArmorEquipEvent armorEquipEvent = new ArmorEquipEvent(e.getPlayer(), EquipMethod.HOTBAR,
ArmorType.matchType(e.getItem()), null,
e.getItem());
Bukkit.getServer().getPluginManager().callEvent(armorEquipEvent);
if (armorEquipEvent.isCancelled())
{
e.setCancelled(true);
player.updateInventory();
}
}
}
}
}
@EventHandler
public void inventoryDrag(InventoryDragEvent event)
{
// getType() seems to always be even.
// Old Cursor gives the item you are equipping
// Raw slot is the ArmorType slot
// Can't replace armor using this method making getCursor() useless.
ArmorType type = ArmorType.matchType(event.getOldCursor());
if (event.getRawSlots().isEmpty())
return;// Idk if this will ever happen
if (type != null && type.getSlot() == event.getRawSlots().stream().findFirst().orElse(0))
{
ArmorEquipEvent armorEquipEvent = new ArmorEquipEvent((Player) event.getWhoClicked(), EquipMethod.DRAG,
type, null, event.getOldCursor());
Bukkit.getServer().getPluginManager().callEvent(armorEquipEvent);
if (armorEquipEvent.isCancelled())
{
event.setResult(Result.DENY);
event.setCancelled(true);
}
}
// Debug shit
/*
* System.out.println("Slots: " + event.getInventorySlots().toString());
* System.out.println("Raw Slots: " + event.getRawSlots().toString());
* if(event.getCursor() != null){ System.out.println("Cursor: " +
* event.getCursor().getType().name()); } if(event.getOldCursor() != null){
* System.out.println("OldCursor: " + event.getOldCursor().getType().name()); }
* System.out.println("Type: " + event.getType().name());
*/
}
@EventHandler
public void itemBreakEvent(PlayerItemBreakEvent e)
{
ArmorType type = ArmorType.matchType(e.getBrokenItem());
if (type != null)
{
Player p = e.getPlayer();
ArmorEquipEvent armorEquipEvent = new ArmorEquipEvent(p, EquipMethod.BROKE, type, e.getBrokenItem(), null);
Bukkit.getServer().getPluginManager().callEvent(armorEquipEvent);
if (armorEquipEvent.isCancelled())
{
ItemStack i = e.getBrokenItem().clone();
i.setAmount(1);
i.setDurability((short) (i.getDurability() - 1));
if (type.equals(ArmorType.HELMET))
p.getInventory().setHelmet(i);
else if (type.equals(ArmorType.CHESTPLATE))
p.getInventory().setChestplate(i);
else if (type.equals(ArmorType.LEGGINGS))
p.getInventory().setLeggings(i);
else if (type.equals(ArmorType.BOOTS))
p.getInventory().setBoots(i);
}
}
}
@EventHandler
public void playerDeathEvent(PlayerDeathEvent e)
{
Player p = e.getEntity();
for (ItemStack oldArmor : p.getInventory().getArmorContents())
if (!isAirOrNull(oldArmor))
{
ArmorType type = ArmorType.matchType(oldArmor);
Bukkit.getServer().getPluginManager().callEvent(new ArmorEquipEvent(p, EquipMethod.DEATH,
type, oldArmor, null));
// No way to cancel a death event.
}
}
/**
* A utility method to support versions that use null or air ItemStacks.
*/
private boolean isAirOrNull(ItemStack item)
{
return item == null || item.getType().equals(Material.AIR);
}
}

View File

@ -0,0 +1,53 @@
package com.codingforcookies.armorequip;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
/**
* @author Arnah
* @since Jul 30, 2015
*/
public enum ArmorType
{
HELMET (5),
CHESTPLATE (6),
LEGGINGS (7),
BOOTS (8);
private final int slot;
ArmorType(int slot)
{
this.slot = slot;
}
/**
* Attempts to match the ArmorType for the specified ItemStack.
*
* @param itemStack The ItemStack to parse the type of.
* @return The parsed ArmorType. (null if none were found.)
*/
public final static ArmorType matchType(final ItemStack itemStack)
{
if (itemStack == null || itemStack.getType().equals(Material.AIR))
return null;
if (itemStack.getType().equals(Material.ELYTRA))
return CHESTPLATE;
String type = itemStack.getType().name();
if (type.endsWith("_HELMET") || type.endsWith("_SKULL"))
return HELMET;
else if (type.endsWith("_CHESTPLATE"))
return CHESTPLATE;
else if (type.endsWith("_LEGGINGS"))
return LEGGINGS;
else if (type.endsWith("_BOOTS"))
return BOOTS;
else
return null;
}
public int getSlot()
{
return slot;
}
}

View File

@ -0,0 +1,30 @@
package com.codingforcookies.armorequip;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockDispenseArmorEvent;
/**
* @author Arnah
* @since Feb 08, 2019
*/
public class DispenserArmorListener implements Listener
{
@EventHandler
public void dispenseArmorEvent(BlockDispenseArmorEvent event)
{
ArmorType type = ArmorType.matchType(event.getItem());
if (type != null)
if (event.getTargetEntity() instanceof Player)
{
Player p = (Player) event.getTargetEntity();
ArmorEquipEvent armorEquipEvent = new ArmorEquipEvent(p, ArmorEquipEvent.EquipMethod.DISPENSER, type,
null, event.getItem());
Bukkit.getServer().getPluginManager().callEvent(armorEquipEvent);
if (armorEquipEvent.isCancelled())
event.setCancelled(true);
}
}
}

View File

@ -1,7 +1,10 @@
package nl.pim16aap2.armoredElytra;
import java.util.EnumMap;
import java.util.Map;
import java.util.Objects;
import java.util.logging.Level;
import java.util.regex.Pattern;
import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
@ -18,6 +21,7 @@ import nl.pim16aap2.armoredElytra.handlers.LoginHandler;
import nl.pim16aap2.armoredElytra.handlers.Uninstaller;
import nl.pim16aap2.armoredElytra.nbtEditor.NBTEditor;
import nl.pim16aap2.armoredElytra.util.ArmorTier;
import nl.pim16aap2.armoredElytra.util.ArmorTierName;
import nl.pim16aap2.armoredElytra.util.ConfigLoader;
import nl.pim16aap2.armoredElytra.util.Messages;
import nl.pim16aap2.armoredElytra.util.Update;
@ -33,7 +37,8 @@ public class ArmoredElytra extends JavaPlugin implements Listener
private Messages messages;
private ConfigLoader config;
private String leatherName, ironName, goldName, chainName, diamondName;
// private String leatherName, ironName, goldName, chainName, diamondName;
private final Map<ArmorTier, ArmorTierName> armorTierNames = new EnumMap(ArmorTier.class);
private String elytraReceivedMessage;
private String usageDeniedMessage;
private String elytraLore;
@ -137,18 +142,29 @@ public class ArmoredElytra extends JavaPlugin implements Listener
return messages;
}
private final String getColorCodedStringFromConfig(final String configEntry)
{
return getMyMessages().getString(configEntry).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
}
private void readMessages()
{
// Replace color codes by the corresponding colors.
usageDeniedMessage = getMyMessages().getString("MESSAGES.UsageDenied" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
elytraReceivedMessage = getMyMessages().getString("MESSAGES.ElytraReceived").replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
elytraLore = getMyMessages().getString("MESSAGES.Lore" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
usageDeniedMessage = getColorCodedStringFromConfig("MESSAGES.UsageDenied");
elytraReceivedMessage = getColorCodedStringFromConfig("MESSAGES.ElytraReceived");
elytraLore = getColorCodedStringFromConfig("MESSAGES.Lore");
leatherName = getMyMessages().getString("TIER.Leather" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
goldName = getMyMessages().getString("TIER.Gold" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
chainName = getMyMessages().getString("TIER.Chain" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
ironName = getMyMessages().getString("TIER.Iron" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
diamondName = getMyMessages().getString("TIER.Diamond" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
armorTierNames.put(ArmorTier.NONE, new ArmorTierName("NONE", "NONE")); // Shouldn't be used.
armorTierNames.put(ArmorTier.LEATHER, new ArmorTierName(getColorCodedStringFromConfig("TIER.Leather"),
getColorCodedStringFromConfig("TIER.SHORT.Leather")));
armorTierNames.put(ArmorTier.GOLD, new ArmorTierName(getColorCodedStringFromConfig("TIER.Gold"),
getColorCodedStringFromConfig("TIER.SHORT.Gold")));
armorTierNames.put(ArmorTier.CHAIN, new ArmorTierName(getColorCodedStringFromConfig("TIER.Chain"),
getColorCodedStringFromConfig("TIER.SHORT.Chain")));
armorTierNames.put(ArmorTier.IRON, new ArmorTierName(getColorCodedStringFromConfig("TIER.Iron"),
getColorCodedStringFromConfig("TIER.SHORT.Iron")));
armorTierNames.put(ArmorTier.DIAMOND, new ArmorTierName(getColorCodedStringFromConfig("TIER.Diamond"),
getColorCodedStringFromConfig("TIER.SHORT.Diamond")));
// Change the string to null if it says "NONE".
usageDeniedMessage = (Objects.equals(usageDeniedMessage, new String("NONE")) ? null : usageDeniedMessage );
@ -216,10 +232,20 @@ public class ArmoredElytra extends JavaPlugin implements Listener
}
}
private static final Pattern ARMOR_TIER = Pattern.compile("%ARMOR_TIER%");
private static final Pattern ARMOR_TIER_SHORT = Pattern.compile("%ARMOR_TIER_SHORT%");
// Replace %ARMOR_TIER% by the name of that armor tier in a string, but strip %ARMOR_TIER% of its color.
public String fillInArmorTierInStringNoColor(String string, ArmorTier armorTier)
{
return string.replace("%ARMOR_TIER%", ChatColor.stripColor(getArmoredElytrName(armorTier)));
if (armorTier == null)
{
getLogger().log(Level.INFO, "ArmorTier was null! Failed to obtain proper string!");
return string;
}
final ArmorTierName tierName = armorTierNames.get(armorTier);
return ARMOR_TIER_SHORT.matcher(ARMOR_TIER.matcher(string).replaceAll(ChatColor.stripColor(tierName.getLongName())))
.replaceAll(ChatColor.stripColor(tierName.getShortName()));
}
// Print a string to the log.
@ -254,30 +280,14 @@ public class ArmoredElytra extends JavaPlugin implements Listener
return elytraLore;
}
public String getArmoredElytrName(ArmorTier tier)
public String getArmoredElytraName(ArmorTier tier)
{
String ret;
switch(tier)
if (tier == null)
{
case LEATHER:
ret = leatherName;
break;
case GOLD:
ret = goldName;
break;
case CHAIN:
ret = chainName;
break;
case IRON:
ret = ironName;
break;
case DIAMOND:
ret = diamondName;
break;
default:
ret = "NONE";
getLogger().log(Level.INFO, "ArmorTier was null! Failed to obtain proper string!");
return "NULL";
}
return ret;
return armorTierNames.get(tier).getLongName();
}
public void setUpToDate(boolean upToDate)

View File

@ -48,6 +48,7 @@ public class CommandHandler implements CommandExecutor
String tier = null;
Player receiver;
boolean allowed = false;
if (args.length == 1)
{
receiver = player;

View File

@ -277,8 +277,9 @@ public class EventHandlers implements Listener
// If the armored elytra is not of the leather tier, but itemTwo is leather,
// Pick the block action, as that would repair the elytra by default (vanilla).
// Also block Armored Elytra + Elytra.
if (tier != ArmorTier.LEATHER && matTwo == Material.LEATHER || matTwo == Material.ELYTRA)
// Also block Armored Elytra + Elytra and Elytra + Membrane
if (tier != ArmorTier.LEATHER && matTwo == Material.LEATHER || matTwo == Material.ELYTRA ||
matTwo.equals(XMaterial.PHANTOM_MEMBRANE.parseMaterial()))
return Action.BLOCK;
}
return Action.NONE;

View File

@ -66,7 +66,7 @@ public class NBTEditor
String version;
try
{
version = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3];
version = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3];
}
catch (final ArrayIndexOutOfBoundsException useAVersionMentionedInTheDescriptionPleaseException)
{
@ -74,9 +74,11 @@ public class NBTEditor
return;
}
// Old versions use the old format. It is assumed here that all versions from 1.13.2 on will use the new format.
// Spigot's 1.13.1 uses the old format, but 1.13.2 uses the new format. They share the same version number though.
if (version.equals("v1_9_R1" ) || version.equals("v1_9_R2" ) || version.equals("v1_10_R1") ||
// Old versions use the old format. It is assumed here that all versions from
// 1.13.2 on will use the new format.
// Spigot's 1.13.1 uses the old format, but 1.13.2 uses the new format. They
// share the same version number though.
if (version.equals("v1_9_R1") || version.equals("v1_9_R2") || version.equals("v1_10_R1") ||
version.equals("v1_11_R1") || version.equals("v1_12_R1") || version.equals("v1_13_R1") ||
version.equals("v1_13_R2") && Bukkit.getVersion().split(" ")[2].equals("1.13.1)"))
getArmorValue = new GetArmorValueOld(plugin);
@ -98,24 +100,27 @@ public class NBTEditor
getTag = NMSItemStack.getMethod("getTag");
CraftItemStack = getCraftClass("inventory.CraftItemStack");
asNMSCopy = CraftItemStack.getMethod("asNMSCopy", ItemStack.class);
asBukkitCopy = CraftItemStack.getMethod("asBukkitCopy", NMSItemStack);
asNMSCopy = CraftItemStack.getMethod("asNMSCopy", ItemStack.class);
asBukkitCopy = CraftItemStack.getMethod("asBukkitCopy", NMSItemStack);
NBTBase = getNMSClass("NBTBase");
NBTTagString = getNMSClass("NBTTagString");
NBTTagStringCtor = NBTTagString.getConstructor(String.class);
NBTTagString = getNMSClass("NBTTagString");
NBTTagStringCtor = NBTTagString.getDeclaredConstructor(String.class);
NBTTagStringCtor.setAccessible(true);
NBTTagByte = getNMSClass("NBTTagByte");
NBTTagByteCtor = NBTTagByte.getConstructor(byte.class);
NBTTagByte = getNMSClass("NBTTagByte");
NBTTagByteCtor = NBTTagByte.getDeclaredConstructor(byte.class);
NBTTagByteCtor.setAccessible(true);
NBTTagInt = getNMSClass("NBTTagInt");
NBTTagIntCtor = NBTTagInt.getConstructor(int.class);
NBTTagInt = getNMSClass("NBTTagInt");
NBTTagIntCtor = NBTTagInt.getDeclaredConstructor(int.class);
NBTTagIntCtor.setAccessible(true);
NBTTagCompound = getNMSClass("NBTTagCompound");
setTag = NBTTagCompound.getMethod("set", String.class, NBTBase);
setTag = NBTTagCompound.getMethod("set", String.class, NBTBase);
NBTTagList = getNMSClass("NBTTagList");
NBTTagList = getNMSClass("NBTTagList");
// Starting in 1.14, you also need to provide an int value when adding nbt tags.
try
{
@ -127,7 +132,7 @@ public class NBTEditor
}
setCompoundTagList = NBTTagCompound.getMethod("set", String.class, NBTBase);
setCompoundByte = NBTTagCompound.getMethod("set", String.class, NBTBase);
setCompoundByte = NBTTagCompound.getMethod("set", String.class, NBTBase);
success = true;
}
@ -138,7 +143,8 @@ public class NBTEditor
}
}
private void addCompound(Object instance, Object nbtbase) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
private void addCompound(Object instance, Object nbtbase)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
{
if (addCompound.getParameterCount() == 2)
addCompound.invoke(instance, 0, nbtbase);
@ -151,36 +157,38 @@ public class NBTEditor
{
try
{
ItemMeta itemmeta = item.getItemMeta();
ItemMeta itemmeta = item.getItemMeta();
int armorProtection = ArmorTier.getArmor(armorTier);
int armorToughness = ArmorTier.getToughness(armorTier);
int armorToughness = ArmorTier.getToughness(armorTier);
itemmeta.setDisplayName(plugin.getArmoredElytrName(armorTier));
itemmeta.setDisplayName(plugin.getArmoredElytraName(armorTier));
if (plugin.getElytraLore() != null)
itemmeta.setLore(Arrays.asList(plugin.fillInArmorTierInStringNoColor(plugin.getElytraLore(), armorTier)));
itemmeta
.setLore(Arrays.asList(plugin.fillInArmorTierInStringNoColor(plugin.getElytraLore(), armorTier)));
item.setItemMeta(itemmeta);
Object nmsStack = asNMSCopy.invoke(null, item);
Object compound = ((boolean) hasTag.invoke(nmsStack) ? getTag.invoke(nmsStack) : NBTTagCompound.newInstance());
Object modifiers = NBTTagList.newInstance();
Object armor = NBTTagCompound.newInstance(); // I should be able to simply add custom tags here!
setTag.invoke (armor, "AttributeName", NBTTagStringCtor.newInstance("generic.armor"));
setTag.invoke (armor, "Name", NBTTagStringCtor.newInstance("generic.armor"));
setTag.invoke (armor, "Amount", NBTTagIntCtor.newInstance(armorProtection));
setTag.invoke (armor, "Operation", NBTTagIntCtor.newInstance(0));
setTag.invoke (armor, "UUIDLeast", NBTTagIntCtor.newInstance(894654));
setTag.invoke (armor, "UUIDMost", NBTTagIntCtor.newInstance(2872));
setTag.invoke (armor, "Slot", NBTTagStringCtor.newInstance("chest"));
Object nmsStack = asNMSCopy.invoke(null, item);
Object compound = ((boolean) hasTag.invoke(nmsStack) ? getTag.invoke(nmsStack) :
NBTTagCompound.newInstance());
Object modifiers = NBTTagList.newInstance();
Object armor = NBTTagCompound.newInstance(); // I should be able to simply add custom tags here!
setTag.invoke(armor, "AttributeName", NBTTagStringCtor.newInstance("generic.armor"));
setTag.invoke(armor, "Name", NBTTagStringCtor.newInstance("generic.armor"));
setTag.invoke(armor, "Amount", NBTTagIntCtor.newInstance(armorProtection));
setTag.invoke(armor, "Operation", NBTTagIntCtor.newInstance(0));
setTag.invoke(armor, "UUIDLeast", NBTTagIntCtor.newInstance(894654));
setTag.invoke(armor, "UUIDMost", NBTTagIntCtor.newInstance(2872));
setTag.invoke(armor, "Slot", NBTTagStringCtor.newInstance("chest"));
addCompound(modifiers, armor);
Object armorTough = NBTTagCompound.newInstance();
setTag.invoke (armorTough, "AttributeName", NBTTagStringCtor.newInstance("generic.armorToughness"));
setTag.invoke (armorTough, "Name", NBTTagStringCtor.newInstance("generic.armorToughness"));
setTag.invoke (armorTough, "Amount", NBTTagIntCtor.newInstance(armorToughness));
setTag.invoke (armorTough, "Operation", NBTTagIntCtor.newInstance(0));
setTag.invoke (armorTough, "UUIDLeast", NBTTagIntCtor.newInstance(894654));
setTag.invoke (armorTough, "UUIDMost", NBTTagIntCtor.newInstance(2872));
setTag.invoke (armorTough, "Slot", NBTTagStringCtor.newInstance("chest"));
setTag.invoke(armorTough, "AttributeName", NBTTagStringCtor.newInstance("generic.armorToughness"));
setTag.invoke(armorTough, "Name", NBTTagStringCtor.newInstance("generic.armorToughness"));
setTag.invoke(armorTough, "Amount", NBTTagIntCtor.newInstance(armorToughness));
setTag.invoke(armorTough, "Operation", NBTTagIntCtor.newInstance(0));
setTag.invoke(armorTough, "UUIDLeast", NBTTagIntCtor.newInstance(894654));
setTag.invoke(armorTough, "UUIDMost", NBTTagIntCtor.newInstance(2872));
setTag.invoke(armorTough, "Slot", NBTTagStringCtor.newInstance("chest"));
addCompound(modifiers, armorTough);
if (unbreakable)
@ -192,7 +200,8 @@ public class NBTEditor
}
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | InstantiationException e)
{
// TODO: Log this or something. Pretty serious issue for a plugin based entirely on this code.
// TODO: Log this or something. Pretty serious issue for a plugin based entirely
// on this code.
e.printStackTrace();
}
return item;

View File

@ -0,0 +1,39 @@
/**
*
*/
package nl.pim16aap2.armoredElytra.util;
/**
*
* @author Pim
*/
public class ArmorTierName
{
private String longName, shortName;
public ArmorTierName(final String longName, final String shortName)
{
this.longName = longName;
this.shortName = shortName;
}
public String getLongName()
{
return longName;
}
public String getShortName()
{
return shortName;
}
public void setLongName(final String longName)
{
this.longName = longName;
}
public void setShortName(final String shortName)
{
this.shortName = shortName;
}
}

View File

@ -56,7 +56,7 @@ public class Messages
while ((sCurrentLine = br.readLine()) != null)
{
// Ignore comments.
if (sCurrentLine.startsWith("#"))
if (sCurrentLine.startsWith("#") || sCurrentLine.isEmpty())
continue;
String key, value;
String[] parts = sCurrentLine.split("=", 2);

View File

@ -62,6 +62,7 @@ public enum XMaterial
GOLDEN_CHESTPLATE(0, "GOLD_CHESTPLATE"),
IRON_CHESTPLATE(0, ""),
LEATHER_CHESTPLATE(0, ""),
PHANTOM_MEMBRANE(0, "1.13"),
AIR(0, ""),
;

View File

@ -4,15 +4,25 @@
# The format is "key=value" (without quotation marks). You can modify the values, but not the keys.
# Order doesn't matter and you can use comments if you so desire.
# Please do note that white space does matter! (so spaces at the end of lines, for example).
# The long names (without 'SHORT') are the names the elytras will have.
TIER.Leather=&2Leather Armored Elytra
TIER.Gold=&EGolden Armored Elytra
TIER.Chain=&8Chain Armored Elytra
TIER.Iron=&7Iron Armored Elytra
TIER.Diamond=&BDiamond Armored Elytra
MESSAGES.Lore=Elytra with %ARMOR_TIER% level protection
MESSAGES.UsageDenied=You do not have the required permissions to wear %ARMOR_TIER%!
MESSAGES.ElytraReceived=&2A(n) %ARMOR_TIER% has been bestowed upon you!
TIER.SHORT.Leather=&2Leather
TIER.SHORT.Gold=&EGold
TIER.SHORT.Chain=&8Chain
TIER.SHORT.Iron=&7Iron
TIER.SHORT.Diamond=&BDiamond
MESSAGES.UninstallMode=&cPlugin in uninstall mode! New Armored Elytras are not allowed!
MESSAGES.UnsupportedTier=&cNot a supported armor tier! Try one of these: leather, gold, chain, iron, diamond.
MESSAGES.NoGivePermission=&cYou do not have the required permission node to give %ARMOR_TIER%s.
MESSAGES.RepairNeeded=&cYou cannot equip this elytra! Please repair it in an anvil first.
MESSAGES.RepairNeeded=&cYou cannot equip this elytra! Please repair it in an anvil first.
# The following messages support the following variables:
# - %ARMOR_TIER% (refers to TIER.X (e.g. TIER.Leather))
# - %ARMOR_TIER_SHORT% (refers to TIER.SHORT.X (e.g. TIER.SHORT.Leather)).
MESSAGES.Lore=Elytra with %ARMOR_TIER_SHORT% level protection.
MESSAGES.NoGivePermission=&cYou do not have the required permission node to give a(n) %ARMOR_TIER%s.
MESSAGES.UsageDenied=You do not have the required permissions to wear a(n) %ARMOR_TIER%!
MESSAGES.ElytraReceived=&2A(n) %ARMOR_TIER% has been bestowed upon you!

View File

@ -2,6 +2,7 @@ name: ArmoredElytra
main: nl.pim16aap2.armoredElytra.ArmoredElytra
version: ${project.version}
author: pim16aap2
api-version: 1.13
commands:
ArmoredElytra:
description: Give an armored elytra of the specified tier.