diff --git a/src/main/java/net/Indyuce/mmoitems/MMOItems.java b/src/main/java/net/Indyuce/mmoitems/MMOItems.java index a7be24b0..08a4555c 100644 --- a/src/main/java/net/Indyuce/mmoitems/MMOItems.java +++ b/src/main/java/net/Indyuce/mmoitems/MMOItems.java @@ -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 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 getInventory().Register(). 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() { diff --git a/src/main/java/net/Indyuce/mmoitems/api/Type.java b/src/main/java/net/Indyuce/mmoitems/api/Type.java index 1654fe24..8e341057 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/Type.java +++ b/src/main/java/net/Indyuce/mmoitems/api/Type.java @@ -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. + *

+ * This will work if the player: + *

> Holds this in their Main Hand + *

> Holds this in their Off Hand, and the mainhand held item is not of MAIN_HAND nor EITHER_HAND + */ + EITHER_HAND; public boolean isHand() { return this == MAIN_HAND || this == OFF_HAND || this == BOTH_HANDS; diff --git a/src/main/java/net/Indyuce/mmoitems/api/interaction/weapon/untargeted/Crossbow.java b/src/main/java/net/Indyuce/mmoitems/api/interaction/weapon/untargeted/Crossbow.java index 4c1e80af..29f43f26 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/interaction/weapon/untargeted/Crossbow.java +++ b/src/main/java/net/Indyuce/mmoitems/api/interaction/weapon/untargeted/Crossbow.java @@ -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)) diff --git a/src/main/java/net/Indyuce/mmoitems/api/interaction/weapon/untargeted/Lute.java b/src/main/java/net/Indyuce/mmoitems/api/interaction/weapon/untargeted/Lute.java index c3dc6e3d..1f96126f 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/interaction/weapon/untargeted/Lute.java +++ b/src/main/java/net/Indyuce/mmoitems/api/interaction/weapon/untargeted/Lute.java @@ -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)) diff --git a/src/main/java/net/Indyuce/mmoitems/api/interaction/weapon/untargeted/Musket.java b/src/main/java/net/Indyuce/mmoitems/api/interaction/weapon/untargeted/Musket.java index 990d7408..0b0a8056 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/interaction/weapon/untargeted/Musket.java +++ b/src/main/java/net/Indyuce/mmoitems/api/interaction/weapon/untargeted/Musket.java @@ -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")), diff --git a/src/main/java/net/Indyuce/mmoitems/api/player/PlayerData.java b/src/main/java/net/Indyuce/mmoitems/api/player/PlayerData.java index 067f457f..a3fd3f3c 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/player/PlayerData.java +++ b/src/main/java/net/Indyuce/mmoitems/api/player/PlayerData.java @@ -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)); diff --git a/src/main/java/net/Indyuce/mmoitems/api/player/inventory/EquippedItem.java b/src/main/java/net/Indyuce/mmoitems/api/player/inventory/EquippedItem.java index 7ca56c52..8435c34c 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/player/inventory/EquippedItem.java +++ b/src/main/java/net/Indyuce/mmoitems/api/player/inventory/EquippedItem.java @@ -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 Type + * actually add its stats to the player when held here? + *

+ * An OFF_CATALYST may only add in the OFFHAND, and such. + */ + public boolean matches(@NotNull Type type) { return matches(type, null); } + + /** + * The slot this equipped item is defined to be, will this Type + * actually add its stats to the player when held here? + *

+ * An OFF_CATALYST may only add in the OFFHAND, and such. + *

+ * There is one type that depends on what is held in another slot: EITHER_HAND. + * If there is no information, it will behave like MAIN_HAND, but if there is, + * if will only match if the mainhand is not MAIN_HAND nor EITHER_HAND + */ + 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; } } \ No newline at end of file diff --git a/src/main/java/net/Indyuce/mmoitems/comp/inventory/DefaultPlayerInventory.java b/src/main/java/net/Indyuce/mmoitems/comp/inventory/DefaultPlayerInventory.java index 1ae2584e..d8e6514c 100644 --- a/src/main/java/net/Indyuce/mmoitems/comp/inventory/DefaultPlayerInventory.java +++ b/src/main/java/net/Indyuce/mmoitems/comp/inventory/DefaultPlayerInventory.java @@ -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. + *

+ * Armor slots, mainhand and offhand. + */ public class DefaultPlayerInventory implements PlayerInventory { @Override public List getInventory(Player player) { List 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)); diff --git a/src/main/java/net/Indyuce/mmoitems/comp/inventory/OrnamentPlayerInventory.java b/src/main/java/net/Indyuce/mmoitems/comp/inventory/OrnamentPlayerInventory.java index 0ec4f94f..4de088f4 100644 --- a/src/main/java/net/Indyuce/mmoitems/comp/inventory/OrnamentPlayerInventory.java +++ b/src/main/java/net/Indyuce/mmoitems/comp/inventory/OrnamentPlayerInventory.java @@ -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. + *

+ * 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 getInventory(Player player) { List 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) diff --git a/src/main/java/net/Indyuce/mmoitems/comp/inventory/PlayerInventoryHandler.java b/src/main/java/net/Indyuce/mmoitems/comp/inventory/PlayerInventoryHandler.java new file mode 100644 index 00000000..a799754d --- /dev/null +++ b/src/main/java/net/Indyuce/mmoitems/comp/inventory/PlayerInventoryHandler.java @@ -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. + *

+ * 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 registeredInventories = new ArrayList<>(); + + /** + * Use this to tell MMOItems to search equipment here --- + * Items that will give their stats to the player. + *

+ * 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 EquippedItem that it is + * in their correct slot though, but that is up to you. + *

+ * Calling twice will cause duplicates 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 getAll() { + + // Add + return new ArrayList<>(registeredInventories); + } + + /** + * Gets the totality of items from all the PlayerInventories. + *

+ * All the items that will add their stats to the player. + */ + @NotNull public List getInventory(@NotNull Player player) { + + // Get and add lists from every registerde inventories + ArrayList cummulative = new ArrayList<>(); + + // For every registered inventory + for (PlayerInventory inv : registeredInventories) { + + // Get + cummulative.addAll(inv.getInventory(player)); + } + + // Return thay result + return cummulative; + } +} diff --git a/src/main/java/net/Indyuce/mmoitems/comp/inventory/RPGInventoryHook.java b/src/main/java/net/Indyuce/mmoitems/comp/inventory/RPGInventoryHook.java index b921f4ba..61672ef3 100644 --- a/src/main/java/net/Indyuce/mmoitems/comp/inventory/RPGInventoryHook.java +++ b/src/main/java/net/Indyuce/mmoitems/comp/inventory/RPGInventoryHook.java @@ -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. + *

+ * 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 getInventory(Player player) { List 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; } diff --git a/src/main/java/net/Indyuce/mmoitems/listener/ItemUse.java b/src/main/java/net/Indyuce/mmoitems/listener/ItemUse.java index 680acc1c..569e4d7e 100644 --- a/src/main/java/net/Indyuce/mmoitems/listener/ItemUse.java +++ b/src/main/java/net/Indyuce/mmoitems/listener/ItemUse.java @@ -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. + *

+ * 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());