Improved the API to tell MMOItems where to check player equipment.

Fixed bug where two-handing bows/crossbows/lutes made them get the stats of both of them.
This commit is contained in:
Gunging 2021-01-12 12:31:22 -06:00
parent 54113b3a15
commit 106389600e
12 changed files with 339 additions and 42 deletions

View File

@ -7,6 +7,7 @@ import java.util.logging.Level;
import javax.annotation.Nullable;
import net.Indyuce.mmoitems.comp.inventory.*;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
@ -42,10 +43,6 @@ import net.Indyuce.mmoitems.comp.holograms.HologramSupport;
import net.Indyuce.mmoitems.comp.holograms.HologramsPlugin;
import net.Indyuce.mmoitems.comp.holograms.HolographicDisplaysPlugin;
import net.Indyuce.mmoitems.comp.holograms.TrHologramPlugin;
import net.Indyuce.mmoitems.comp.inventory.DefaultPlayerInventory;
import net.Indyuce.mmoitems.comp.inventory.OrnamentPlayerInventory;
import net.Indyuce.mmoitems.comp.inventory.PlayerInventory;
import net.Indyuce.mmoitems.comp.inventory.RPGInventoryHook;
import net.Indyuce.mmoitems.comp.itemglow.ItemGlowListener;
import net.Indyuce.mmoitems.comp.itemglow.NoGlowListener;
import net.Indyuce.mmoitems.comp.mmocore.MMOCoreMMOLoader;
@ -119,7 +116,7 @@ public class MMOItems extends JavaPlugin {
private final List<StringInputParser> stringInputParsers = new ArrayList<>();
private PlaceholderParser placeholderParser = new DefaultPlaceholderParser();
private PlayerInventory inventory = new DefaultPlayerInventory();
private PlayerInventoryHandler inventory = new PlayerInventoryHandler();
private FlagPlugin flagPlugin = new DefaultFlags();
private HologramSupport hologramSupport;
private VaultSupport vaultSupport;
@ -247,11 +244,18 @@ public class MMOItems extends JavaPlugin {
if (Bukkit.getPluginManager().getPlugin("mcMMO") != null)
Bukkit.getPluginManager().registerEvents(new McMMONonRPGHook(), this);
/*
* Registers Player Inventories. Each of these add locations of items to search for
* when doing inventory updates.
*/
registerPlayerInventory(new DefaultPlayerInventory());
if (Bukkit.getPluginManager().getPlugin("RPGInventory") != null) {
inventory = new RPGInventoryHook();
registerPlayerInventory(new RPGInventoryHook());
getLogger().log(Level.INFO, "Hooked onto RPGInventory");
} else if (MMOItems.plugin.getConfig().getBoolean("iterate-whole-inventory"))
inventory = new OrnamentPlayerInventory();
}
if (MMOItems.plugin.getConfig().getBoolean("iterate-whole-inventory")) {
registerPlayerInventory(new OrnamentPlayerInventory());
}
if (Bukkit.getPluginManager().getPlugin("AdvancedEnchantments") != null) {
Bukkit.getPluginManager().registerEvents(new AdvancedEnchantmentsHook(), this);
@ -406,13 +410,26 @@ public class MMOItems extends JavaPlugin {
return pluginUpdateManager;
}
public PlayerInventory getInventory() {
public PlayerInventoryHandler getInventory() {
return inventory;
}
/**
* The PlayerInventory interface lets MMOItems knows what items to look for
* in player inventories when doing inventory updates. By default, it only
* in player inventories whe doing inventory updates. By default, it only
* checks held items + armor slots. However other plugins like MMOInv do
* implement custom slots and therefore must register a custom
* PlayerInventory instance that tells of additional items to look for.
*/
public void registerPlayerInventory(PlayerInventory value) {
// Registers in the Inventory Handler
getInventory().register(value);
}
/**
* The PlayerInventory interface lets MMOItems knows what items to look for
* in player inventories whe doing inventory updates. By default, it only
* checks held items + armor slots. However other plugins like MMOInv do
* implement custom slots and therefore must register a custom
* PlayerInventory instance.
@ -420,9 +437,19 @@ public class MMOItems extends JavaPlugin {
* Default instance is DefaultPlayerInventory in comp.inventory
*
* @param value The player inventory subclass
* @deprecated Rather than setting this to the only inventory MMOItems will
* search equipment within, you must add your inventory to the
* handler with <code>getInventory().Register()</code>. This method
* will clear all other PlayerInventories for now, as to keep
* backwards compatibility.
*/
public void setPlayerInventory(PlayerInventory value) {
inventory = value;
// Unregisters those previously registered
getInventory().unregisterAll();
// Registers this as the only
getInventory().register(value);
}
public StatManager getStats() {

View File

@ -33,10 +33,10 @@ public class Type {
// range
public static final Type WHIP = new Type(TypeSet.RANGE, "WHIP", true, EquipmentSlot.MAIN_HAND);
public static final Type STAFF = new Type(TypeSet.RANGE, "STAFF", true, EquipmentSlot.MAIN_HAND);
public static final Type BOW = new Type(TypeSet.RANGE, "BOW", true, EquipmentSlot.BOTH_HANDS);
public static final Type CROSSBOW = new Type(TypeSet.RANGE, "CROSSBOW", false, EquipmentSlot.BOTH_HANDS);
public static final Type MUSKET = new Type(TypeSet.RANGE, "MUSKET", true, EquipmentSlot.BOTH_HANDS);
public static final Type LUTE = new Type(TypeSet.RANGE, "LUTE", true, EquipmentSlot.BOTH_HANDS);
public static final Type BOW = new Type(TypeSet.RANGE, "BOW", true, EquipmentSlot.EITHER_HAND);
public static final Type CROSSBOW = new Type(TypeSet.RANGE, "CROSSBOW", false, EquipmentSlot.EITHER_HAND);
public static final Type MUSKET = new Type(TypeSet.RANGE, "MUSKET", true, EquipmentSlot.EITHER_HAND);
public static final Type LUTE = new Type(TypeSet.RANGE, "LUTE", true, EquipmentSlot.EITHER_HAND);
// offhand
public static final Type CATALYST = new Type(TypeSet.OFFHAND, "CATALYST", false, EquipmentSlot.BOTH_HANDS);
@ -285,9 +285,20 @@ public class Type {
OFF_HAND,
/**
* Apply stats in both hands, ie shields or bows
* Apply stats in both hands, ie shields or catalysts
*/
BOTH_HANDS;
BOTH_HANDS,
/**
* Apply stats when actually held. Bows may be held in offhand but
* it is undesirable if players dual-wield bows and add their stats
* together.
* <p></p>
* This will work if the player:
* <p> > Holds this in their Main Hand
* </p> > Holds this in their Off Hand, and the mainhand held item is not of <code>MAIN_HAND</code> nor <code>EITHER_HAND</code>
*/
EITHER_HAND;
public boolean isHand() {
return this == MAIN_HAND || this == OFF_HAND || this == BOTH_HANDS;

View File

@ -5,6 +5,7 @@ import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.interaction.util.UntargetedDurabilityItem;
import net.Indyuce.mmoitems.api.player.PlayerData.CooldownType;
import net.Indyuce.mmoitems.api.player.PlayerStats;
import net.Indyuce.mmoitems.listener.ItemUse;
import net.mmogroup.mmolib.api.item.NBTItem;
import org.bukkit.GameMode;
import org.bukkit.Material;
@ -26,6 +27,8 @@ public class Crossbow extends UntargetedWeapon {
if (getPlayer().getGameMode() != GameMode.CREATIVE && !getPlayer().getInventory().containsAtLeast(new ItemStack(Material.ARROW), 1))
return;
if (!ItemUse.eitherHandSuccess(getPlayer(), getNBTItem(), slot))
return;
PlayerStats stats = getPlayerData().getStats();
if (!applyWeaponCosts(1 / getValue(stats.getStat(ItemStats.ATTACK_SPEED), MMOItems.plugin.getConfig().getDouble("default.attack-speed")),
CooldownType.ATTACK))

View File

@ -8,6 +8,7 @@ import net.Indyuce.mmoitems.api.interaction.util.UntargetedDurabilityItem;
import net.Indyuce.mmoitems.api.player.PlayerData.CooldownType;
import net.Indyuce.mmoitems.api.player.PlayerStats.CachedStats;
import net.Indyuce.mmoitems.api.util.SoundReader;
import net.Indyuce.mmoitems.listener.ItemUse;
import net.Indyuce.mmoitems.stat.LuteAttackEffectStat.LuteAttackEffect;
import net.mmogroup.mmolib.api.DamageType;
import net.mmogroup.mmolib.api.item.NBTItem;
@ -31,6 +32,8 @@ public class Lute extends UntargetedWeapon {
@Override
public void untargetedAttack(EquipmentSlot slot) {
if (!ItemUse.eitherHandSuccess(getPlayer(), getNBTItem(), slot))
return;
CachedStats stats = getPlayerData().getStats().newTemporary();
double attackSpeed = 1 / getValue(stats.getStat(ItemStats.ATTACK_SPEED), MMOItems.plugin.getConfig().getDouble("default.attack-speed"));
if (!applyWeaponCosts(attackSpeed, CooldownType.ATTACK))

View File

@ -7,6 +7,7 @@ import net.Indyuce.mmoitems.api.ItemAttackResult;
import net.Indyuce.mmoitems.api.interaction.util.UntargetedDurabilityItem;
import net.Indyuce.mmoitems.api.player.PlayerData.CooldownType;
import net.Indyuce.mmoitems.api.player.PlayerStats.CachedStats;
import net.Indyuce.mmoitems.listener.ItemUse;
import net.mmogroup.mmolib.MMOLib;
import net.mmogroup.mmolib.api.DamageType;
import net.mmogroup.mmolib.api.MMORayTraceResult;
@ -25,6 +26,8 @@ public class Musket extends UntargetedWeapon {
@Override
public void untargetedAttack(EquipmentSlot slot) {
if (!ItemUse.eitherHandSuccess(getPlayer(), getNBTItem(), slot))
return;
CachedStats stats = getPlayerData().getStats().newTemporary();
if (!applyWeaponCosts(1 / getValue(stats.getStat(ItemStats.ATTACK_SPEED), MMOItems.plugin.getConfig().getDouble("default.attack-speed")),

View File

@ -14,6 +14,7 @@ import org.bukkit.OfflinePlayer;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitRunnable;
@ -182,6 +183,22 @@ public class PlayerData {
* the updateEffects() method
*/
fullHands = areHandsFull();
//region EquipmentSlot mainheld_type = [equipment Type of whatever the player is holding]
EquipmentSlot mainheld_type = null;
ItemStack mainheld = getPlayer().getInventory().getItemInMainHand();
if (mainheld.getType().isItem()) {
NBTItem mainnbt = MMOLib.plugin.getVersion().getWrapper().getNBTItem(mainheld);
if (mainnbt != null) {
Type maintype = Type.get(mainnbt.getType());
if (maintype != null) {
mainheld_type = maintype.getEquipmentType();
}
}
}
//endregion
/*
* Find all the items the player can actually use
@ -194,7 +211,7 @@ public class PlayerData {
* If the item is a custom item, apply slot and item use
* restrictions (items which only work in a specific equipment slot)
*/
if (type != null && (!item.matches(type) || !getRPG().canUse(nbtItem, false)))
if (type != null && (!item.matches(type, mainheld_type) || !getRPG().canUse(nbtItem, false)))
continue;
inventory.getEquipped().add(new EquippedPlayerItem(item));

View File

@ -1,11 +1,15 @@
package net.Indyuce.mmoitems.api.player.inventory;
import net.Indyuce.mmoitems.MMOItems;
import org.bukkit.inventory.ItemStack;
import net.Indyuce.mmoitems.api.Type;
import net.Indyuce.mmoitems.api.Type.EquipmentSlot;
import net.mmogroup.mmolib.MMOLib;
import net.mmogroup.mmolib.api.item.NBTItem;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
public class EquippedItem {
private final NBTItem item;
@ -40,8 +44,62 @@ public class EquippedItem {
return slot;
}
public boolean matches(Type type) {
return slot == EquipmentSlot.ANY || (type.getEquipmentType() == EquipmentSlot.BOTH_HANDS ? slot.isHand()
: slot == EquipmentSlot.BOTH_HANDS ? type.getEquipmentType().isHand() : slot == type.getEquipmentType());
/**
* The slot this equipped item is defined to be, will this <code>Type</code>
* actually add its stats to the player when held here?
* <p></p>
* An <code>OFF_CATALYST</code> may only add in the <code>OFFHAND</code>, and such.
*/
public boolean matches(@NotNull Type type) { return matches(type, null); }
/**
* The slot this equipped item is defined to be, will this <code>Type</code>
* actually add its stats to the player when held here?
* <p></p>
* An <code>OFF_CATALYST</code> may only add in the <code>OFFHAND</code>, and such.
* <p></p>
* There is one type that depends on what is held in another slot: <code>EITHER_HAND</code>.
* If there is no information, it will behave like <code>MAIN_HAND</code>, but if there is,
* if will only <i>match</i> if the mainhand is not <code>MAIN_HAND</code> nor <code>EITHER_HAND</code>
*/
public boolean matches(@NotNull Type type, @Nullable EquipmentSlot mainheld) {
// Get Type Equipment
EquipmentSlot slotT = type.getEquipmentType();
// Matches any?
if (slot == EquipmentSlot.ANY) { return true; }
// Is it Either Mainhand or Offhand?
if (slotT == EquipmentSlot.EITHER_HAND) {
// Is it held in mainhand?
if (slot == EquipmentSlot.MAIN_HAND) { return true; }
// What is in the main hand?
if (mainheld != null) {
// Something else held? nope
if (mainheld == EquipmentSlot.MAIN_HAND) { return false; }
if (mainheld == EquipmentSlot.EITHER_HAND) { return false; }
// WIll match if the slot is a hand
return slot.isHand();
// No information was provided, proceed as MAIN_HAND
} else {
// WIll behave as MAIN_HAND
slotT = EquipmentSlot.OFF_HAND;
}
}
// Is it held regardless of hand used?
if (slotT == EquipmentSlot.BOTH_HANDS && slot.isHand()) { return true; }
if (slot == EquipmentSlot.BOTH_HANDS && slotT.isHand()) { return true; }
// Is it the same type?
return slot == slotT;
}
}

View File

@ -9,13 +9,23 @@ import org.bukkit.inventory.ItemStack;
import net.Indyuce.mmoitems.api.Type.EquipmentSlot;
import net.Indyuce.mmoitems.api.player.inventory.EquippedItem;
/**
* Tells MMOItems where to find equipment.
* <p></p>
* Armor slots, mainhand and offhand.
*/
public class DefaultPlayerInventory implements PlayerInventory {
@Override
public List<EquippedItem> getInventory(Player player) {
List<EquippedItem> list = new ArrayList<>();
// Mainhand
list.add(new EquippedItem(player.getEquipment().getItemInMainHand(), EquipmentSlot.MAIN_HAND));
// Offhand
list.add(new EquippedItem(player.getEquipment().getItemInOffHand(), EquipmentSlot.OFF_HAND));
// Armour
for (ItemStack armor : player.getInventory().getArmorContents())
list.add(new EquippedItem(armor, EquipmentSlot.ARMOR));

View File

@ -20,6 +20,11 @@ import net.Indyuce.mmoitems.api.player.inventory.EquippedItem;
import net.mmogroup.mmolib.MMOLib;
import net.mmogroup.mmolib.api.item.NBTItem;
/**
* Tells MMOItems where to find additional equipment.
* <p></p>
* Ornaments - Found in any inventory slot.
*/
public class OrnamentPlayerInventory implements PlayerInventory, Listener {
public OrnamentPlayerInventory() {
Bukkit.getPluginManager().registerEvents(this, MMOItems.plugin);
@ -29,11 +34,7 @@ public class OrnamentPlayerInventory implements PlayerInventory, Listener {
public List<EquippedItem> getInventory(Player player) {
List<EquippedItem> list = new ArrayList<>();
list.add(new EquippedItem(player.getEquipment().getItemInMainHand(), EquipmentSlot.MAIN_HAND));
list.add(new EquippedItem(player.getEquipment().getItemInOffHand(), EquipmentSlot.OFF_HAND));
for (ItemStack armor : player.getInventory().getArmorContents())
list.add(new EquippedItem(armor, EquipmentSlot.ARMOR));
// Ornaments
for (ItemStack item : player.getInventory().getContents()) {
NBTItem nbtItem;
if (item != null && (nbtItem = MMOLib.plugin.getVersion().getWrapper().getNBTItem(item)).hasType() && Type.get(nbtItem.getType()).getEquipmentType() == EquipmentSlot.ANY)

View File

@ -0,0 +1,94 @@
package net.Indyuce.mmoitems.comp.inventory;
import net.Indyuce.mmoitems.api.player.inventory.EquippedItem;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
/**
* Previously, only one Player Inventory was allowed.
* This makes it so plugins may register all the Player Inventories they want.
* <p></p>
* For context, a 'Player Inventory' tells MMOItems where to look for equipped items,
* (items that will add their stats to the player).
*/
public class PlayerInventoryHandler {
public PlayerInventoryHandler() {}
/**
* Gets the registered Player Inventories --- The places where MMOItems determines player equipped items.
*/
@NotNull ArrayList<PlayerInventory> registeredInventories = new ArrayList<>();
/**
* Use this to tell MMOItems to search equipment here ---
* Items that will give their stats to the player.
* <p></p>
* Note that if the items are not held in the correct slot (OFF_CATALYST not held in OFFHAND)
* they wont provide their stats. You may fool MMOItems by telling the <code>EquippedItem</code> that it is
* in their correct slot though, but that is up to you.
* <p></p>
* <b>Calling twice will cause duplicates</b> but is nevertheless allowed if you really want to.
*/
public void register(@NotNull PlayerInventory pInventory) {
// Add
registeredInventories.add(pInventory);
}
/**
* I guess if your plugin is so custom it doesnt want Armor Slots / mainahnd / offhand to add
* their stats by default you would use this.
*/
public void unregisterAll() {
// Unregister events
for (PlayerInventory inv : registeredInventories) {
// Is it a listener?
if (inv instanceof Listener) {
// Unregister events
HandlerList.unregisterAll((Listener) inv);
}
}
// Add
registeredInventories.clear();
}
/**
* Gets a copy of the list of registered inventories.
*/
public ArrayList<PlayerInventory> getAll() {
// Add
return new ArrayList<>(registeredInventories);
}
/**
* Gets the totality of items from all the PlayerInventories.
* <p></p>
* All the items that will add their stats to the player.
*/
@NotNull public List<EquippedItem> getInventory(@NotNull Player player) {
// Get and add lists from every registerde inventories
ArrayList<EquippedItem> cummulative = new ArrayList<>();
// For every registered inventory
for (PlayerInventory inv : registeredInventories) {
// Get
cummulative.addAll(inv.getInventory(player));
}
// Return thay result
return cummulative;
}
}

View File

@ -19,8 +19,12 @@ import net.mmogroup.mmolib.MMOLib;
import net.mmogroup.mmolib.api.item.NBTItem;
import ru.endlesscode.rpginventory.api.InventoryAPI;
/**
* Tells MMOItems where to find additional equipment.
* <p></p>
* RPGInventory stuff - Passive Items
*/
public class RPGInventoryHook implements PlayerInventory, Listener {
private final boolean ornaments;
/*
* RPGInventory is outdated. MI still supports it but it shall NEVER be
@ -29,30 +33,15 @@ public class RPGInventoryHook implements PlayerInventory, Listener {
*/
public RPGInventoryHook() {
Bukkit.getPluginManager().registerEvents(this, MMOItems.plugin);
if (ornaments = MMOItems.plugin.getConfig().getBoolean("iterate-whole-inventory"))
Bukkit.getPluginManager().registerEvents(new OrnamentPlayerInventory(), MMOItems.plugin);
}
@Override
public List<EquippedItem> getInventory(Player player) {
List<EquippedItem> list = new ArrayList<>();
list.add(new EquippedItem(player.getInventory().getItemInMainHand(), EquipmentSlot.MAIN_HAND));
list.add(new EquippedItem(player.getInventory().getItemInOffHand(), EquipmentSlot.OFF_HAND));
for (ItemStack passive : InventoryAPI.getPassiveItems(player))
if (passive != null)
list.add(new EquippedItem(passive, EquipmentSlot.ANY));
for (ItemStack armor : player.getInventory().getArmorContents())
if (armor != null)
list.add(new EquippedItem(armor, EquipmentSlot.ARMOR));
if (ornaments)
for (ItemStack item : player.getInventory().getContents()) {
NBTItem nbtItem;
if (item != null && (nbtItem = MMOLib.plugin.getVersion().getWrapper().getNBTItem(item)).hasType() && Type.get(nbtItem.getType()).getEquipmentType() == EquipmentSlot.ANY)
list.add(new EquippedItem(nbtItem, EquipmentSlot.ANY));
}
return list;
}

View File

@ -2,6 +2,7 @@ package net.Indyuce.mmoitems.listener;
import java.text.DecimalFormat;
import net.Indyuce.mmoitems.api.player.inventory.EquippedItem;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.Material;
@ -43,6 +44,9 @@ import net.Indyuce.mmoitems.api.util.message.Message;
import net.mmogroup.mmolib.MMOLib;
import net.mmogroup.mmolib.api.DamageType;
import net.mmogroup.mmolib.api.item.NBTItem;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
public class ItemUse implements Listener {
private static final DecimalFormat digit = new DecimalFormat("0.#");
@ -278,6 +282,10 @@ public class ItemUse implements Listener {
event.setCancelled(true);
return;
}
if (!eitherHandSuccess((Player) event.getEntity(), item, event.getHand())) {
event.setCancelled(true);
return;
}
}
Arrow arrow = (Arrow) event.getProjectile();
@ -287,6 +295,79 @@ public class ItemUse implements Listener {
event.getForce());
}
/**
* It is undesirable to fire bows whose arrows have the stats of the Mainhand weapon.
* <p></p>
* If such an item succeeds in this check, that means it can be fired. Only makes sense to
* check when you really suspect it is an EITHER_HAND weapon. Otherwise the check already
* happened when its stats where added in the first place.
*/
public static boolean eitherHandSuccess(@NotNull Player p, @NotNull NBTItem item, @NotNull EquipmentSlot held) {
/*
* Make sure it is a plugin item to begin with
*/
Type itemType = Type.get(item.getType());
if (itemType == null) { return false; }
/*
* Get the held type of the item held
*/
Type.EquipmentSlot mainheld_type = null;
// Get Mainhand Item
ItemStack mainheld = p.getInventory().getItemInMainHand();
// Existed?
if (mainheld.getType().isItem()) {
// Get as NBTItem
NBTItem mainnbt = MMOLib.plugin.getVersion().getWrapper().getNBTItem(mainheld);
// Existed?
if (mainnbt != null) {
// Get MMOItem Type
Type maintype = Type.get(mainnbt.getType());
// Existed?
if (maintype != null) {
// Remember Equipment Type
mainheld_type = maintype.getEquipmentType();
}
}
}
/*
* Perform Equipped Item Check
*/
Type.EquipmentSlot heldTranslated;
switch (held) {
case HAND:
heldTranslated = Type.EquipmentSlot.MAIN_HAND;
break;
case OFF_HAND:
heldTranslated = Type.EquipmentSlot.OFF_HAND;
break;
case FEET:
case HEAD:
case LEGS:
case CHEST:
heldTranslated = Type.EquipmentSlot.ARMOR;
break;
default:
heldTranslated = Type.EquipmentSlot.ACCESSORY;
break;
}
// Just do as if it was actually a real thing
EquippedItem eitem = new EquippedItem(item, heldTranslated);
// Does it match?
return eitem.matches(itemType, mainheld_type);
}
@EventHandler
public void g(PlayerItemConsumeEvent event) {
NBTItem item = MMOLib.plugin.getVersion().getWrapper().getNBTItem(event.getItem());