Untargeted weapon durability changes

This commit is contained in:
Indyuce 2022-02-26 10:54:24 +01:00
parent cd5421b781
commit 8253113d33
10 changed files with 293 additions and 391 deletions

View File

@ -95,7 +95,7 @@ public class MMOItems extends LuminePlugin {
private VaultSupport vaultSupport;
private RPGHandler rpgPlugin;
private static final int MYTHICLIB_COMPATIBILITY_INDEX = 7;
private static final int MYTHICLIB_COMPATIBILITY_INDEX = 8;
public MMOItems() { plugin = this; }

View File

@ -13,7 +13,6 @@ import net.Indyuce.mmoitems.api.event.item.CustomDurabilityRepair;
import net.Indyuce.mmoitems.api.item.mmoitem.LiveMMOItem;
import net.Indyuce.mmoitems.api.item.util.LoreUpdate;
import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.stat.data.DoubleData;
import net.Indyuce.mmoitems.stat.data.UpgradeData;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
@ -23,8 +22,8 @@ import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.Random;
/**
@ -38,213 +37,188 @@ import java.util.Random;
* @author indyuce
*/
public class DurabilityItem {
private final NBTItem nbtItem;
@Nullable
private final Player player;
private final int maxDurability, unbreakingLevel, initialDurability;
private final boolean barHidden;
private final NBTItem nbtItem;
private final int maxDurability, unbreakingLevel, initialDurability;
private final boolean barHidden;
private final Player player;
private int durability;
private int durability;
private static final Random RANDOM = new Random();
private static final Random RANDOM = new Random();
/**
* Use to handle durability changes for MMOItems
* without using heavy MMOItem class methods.
*
* @param player Player holding the item
* @param item Item with durability
*/
public DurabilityItem(@Nullable Player player, @NotNull ItemStack item) {
this(player, NBTItem.get(item));
}
/**
* Use to handle durability changes for MMOItems
* without using heavy MMOItem class methods.
*
* @param player Player holding the item
* @param item Item with durability
*/
public DurabilityItem(@NotNull Player player, @NotNull ItemStack item) {
this(player, NBTItem.get(item));
}
/**
* Use to handle durability changes for MMOItems
* without using heavy MMOItem class methods
*
* @param player Player holding the item
* @param item Item with durability
*/
public DurabilityItem(@Nullable Player player, @NotNull NBTItem item) {
/*Validate.notNull(this.player = player, "Player cannot be null");*/
this.player = player;
Validate.notNull(nbtItem = item, "Item cannot be null");
/**
* Use to handle durability changes for MMOItems
* without using heavy MMOItem class methods
*
* @param player Player holding the item
* @param nbtItem Item with durability
*/
public DurabilityItem(@NotNull Player player, @NotNull NBTItem nbtItem) {
this.player = Objects.requireNonNull(player, "Player cannot be null");
this.nbtItem = Objects.requireNonNull(nbtItem, "Item cannot be null");
maxDurability = nbtItem.getInteger("MMOITEMS_MAX_DURABILITY");
initialDurability = durability = nbtItem.hasTag("MMOITEMS_DURABILITY") ? nbtItem.getInteger("MMOITEMS_DURABILITY") : maxDurability;
barHidden = nbtItem.getBoolean("MMOITEMS_DURABILITY_BAR");
maxDurability = nbtItem.getInteger("MMOITEMS_MAX_DURABILITY");
initialDurability = durability = nbtItem.hasTag("MMOITEMS_DURABILITY") ? nbtItem.getInteger("MMOITEMS_DURABILITY") : maxDurability;
barHidden = nbtItem.getBoolean("MMOITEMS_DURABILITY_BAR");
unbreakingLevel = (nbtItem.getItem().getItemMeta() != null && nbtItem.getItem().getItemMeta().hasEnchant(Enchantment.DURABILITY)) ?
nbtItem.getItem().getItemMeta().getEnchantLevel(Enchantment.DURABILITY) :
0;
}
unbreakingLevel = (nbtItem.getItem().getItemMeta() != null && nbtItem.getItem().getItemMeta().hasEnchant(Enchantment.DURABILITY)) ?
nbtItem.getItem().getItemMeta().getEnchantLevel(Enchantment.DURABILITY) : 0;
}
@Nullable public Player getPlayer() {
return player;
}
public Player getPlayer() {
return player;
}
public int getMaxDurability() {
return maxDurability;
}
public int getMaxDurability() {
return maxDurability;
}
public int getDurability() {
return durability;
}
public int getDurability() {
return durability;
}
// If the green vanilla durability bar should show
public boolean isBarHidden() {
return barHidden;
}
public boolean isBarHidden() {
return barHidden;
}
/**
* @deprecated Not used anymore
*/
@Deprecated
public boolean isUnbreakable() {
return nbtItem.getBoolean("Unbreakable");
}
public int getUnbreakingLevel() {
return unbreakingLevel;
}
public int getUnbreakingLevel() {
return unbreakingLevel;
}
public NBTItem getNBTItem() {
return nbtItem;
}
public NBTItem getNBTItem() {
return nbtItem;
}
public boolean isBroken() {
return durability <= 0;
}
public boolean isBroken() {
return nbtItem.hasTag("MMOITEMS_DURABILITY") && durability <= 0;
}
public boolean isLostWhenBroken() {
return nbtItem.getBoolean("MMOITEMS_WILL_BREAK");
}
public boolean isLostWhenBroken() {
return nbtItem.getBoolean("MMOITEMS_WILL_BREAK");
}
public boolean isDowngradedWhenBroken() {
return nbtItem.getBoolean("MMOITEMS_BREAK_DOWNGRADE");
}
public boolean isDowngradedWhenBroken() {
return nbtItem.getBoolean("MMOITEMS_BREAK_DOWNGRADE");
}
/**
* <b>Assuming you already called {@link #isDowngradedWhenBroken()}</b>, when the item is
* being broken. This method will downgrade the item for one level and apply changes to
* the stored {@link #getNBTItem()}.
*
* If the item cannot be downgraded (due to not having upgrade data / reaching minimum
* upgrades), this method will return <code>null</code>, no change will be made to the
* NBTItem, and you should break the item.
*
* @return If the item could not be downgraded, and thus should break, will be <code>null</code>.
* If the item was successfully downgraded, this will uuuh, will return the NBTItem of
* the downgraded version.
*/
@Nullable public ItemStack shouldBreakWhenDowngraded() {
ItemTag uTag = ItemTag.getTagAtPath(ItemStats.UPGRADE.getNBTPath(), getNBTItem(), SupportedNBTTagValues.STRING);
if (uTag == null) { return null; }
/**
* @return If the item actually supports custom durability. It is completely
* disabled when the player is in creative mode just like vanilla durability.
*/
public boolean isValid() {
return maxDurability > 0 && player.getGameMode() != GameMode.CREATIVE;
}
try {
public DurabilityItem addDurability(int gain) {
Validate.isTrue(gain > 0, "Durability gain must be greater than 0");
// Read data
UpgradeData data = new UpgradeData(new JsonParser().parse((String) uTag.getValue()).getAsJsonObject());
CustomDurabilityRepair event = new CustomDurabilityRepair(this, gain);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled())
return this;
// If it cannot be downgraded (reached min), DEATH
if (data.getLevel() <= data.getMin()) { return null; }
durability = Math.min(durability + gain, maxDurability);
return this;
}
// Downgrading operation
LiveMMOItem mmo = new LiveMMOItem(getNBTItem());
public DurabilityItem decreaseDurability(int loss) {
Validate.isTrue(loss > 0, "Loss must be greater than 0");
// Remove one level
mmo.getUpgradeTemplate().upgradeTo(mmo, data.getLevel() - 1);
/*
* Calculate the chance of the item not losing any durability because of
* the vanilla unbreaking enchantment ; an item with unbreaking X has 1
* 1 chance out of (X + 1) to lose a durability point, that's 50% chance
* -> 33% chance -> 25% chance -> 20% chance...
*/
if (getUnbreakingLevel() > 0 && RANDOM.nextInt(getUnbreakingLevel()) != 0)
return this;
// Build NBT
NBTItem preRet = mmo.newBuilder().buildNBT();
CustomDurabilityDamage event = new CustomDurabilityDamage(this, loss);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled())
return this;
// Set durability to zero (full repair)
DurabilityItem dur = new DurabilityItem(getPlayer(), preRet);
dur.addDurability(dur.getMaxDurability());
durability = Math.max(0, Math.min(durability - loss, maxDurability));
// Yes
return dur.toItem();
// Play sound when item breaks
if (isBroken()) {
player.getWorld().playSound(player.getLocation(), Sound.ENTITY_ITEM_BREAK, 1, 1);
PlayerData.get(player).getInventory().scheduleUpdate();
}
} catch (JsonSyntaxException |IllegalStateException exception) { return null; }
}
return this;
}
/**
* Since
*
* @return If the item actually supports custom durability.
*/
public boolean isValid() {
return maxDurability > 0 && player != null && player.getGameMode() != GameMode.CREATIVE;
}
/**
* This method not only generates the newest item version taking into account
* 1) item damage
* 2) item breaking
* 3) item downgrade
*
* @return Newest version of the damaged item
*/
public ItemStack toItem() {
public DurabilityItem addDurability(int gain) {
Validate.isTrue(gain > 0, "Durability gain must be greater than 0");
// No modification needs to be done
if (durability == initialDurability)
return nbtItem.getItem();
CustomDurabilityRepair event = new CustomDurabilityRepair(this, gain);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled())
return this;
// Checks for possible downgrade
ItemTag uTag = ItemTag.getTagAtPath(ItemStats.UPGRADE.getNBTPath(), getNBTItem(), SupportedNBTTagValues.STRING);
if (uTag != null)
try {
UpgradeData data = new UpgradeData(new JsonParser().parse((String) uTag.getValue()).getAsJsonObject());
durability = Math.min(durability + gain, maxDurability);
return this;
}
// If it cannot be downgraded (reached min), DEATH
if (data.getLevel() <= data.getMin())
return null;
public DurabilityItem decreaseDurability(int loss) {
CustomDurabilityDamage event = new CustomDurabilityDamage(this, loss);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled())
return this;
// Remove one level and FULLY repair item
LiveMMOItem mmo = new LiveMMOItem(getNBTItem());
mmo.getUpgradeTemplate().upgradeTo(mmo, data.getLevel() - 1);
NBTItem preRet = mmo.newBuilder().buildNBT();
preRet.addTag(new ItemTag("MMOITEMS_DURABILITY", maxDurability));
return preRet.toItem();
/*
* Calculate the chance of the item not losing any durability because of
* the vanilla unbreaking enchantment ; an item with unbreaking X has 1
* 1 chance out of (X + 1) to lose a durability point, that's 50% chance
* -> 33% chance -> 25% chance -> 20% chance...
*/
if (getUnbreakingLevel() > 0 && RANDOM.nextInt(getUnbreakingLevel()) > 0)
return this;
} catch (JsonSyntaxException | IllegalStateException ignored) {
// Nothing
}
durability = Math.max(0, Math.min(durability - loss, maxDurability));
/*
* Cross multiplication to display the current item durability on the
* item durability bar. (1 - ratio) because minecraft works with item
* damage, and item damage is the complementary of the remaining
* durability.
*
* Make sure the vanilla bar displays at least 1 damage for display
* issues. Also makes sure the item can be mended using the vanilla
* enchant.
*/
if (!barHidden) {
int damage = (durability == maxDurability) ? 0 : Math.max(1, (int) ((1. - ((double) durability / maxDurability)) * nbtItem.getItem().getType().getMaxDurability()));
nbtItem.addTag(new ItemTag("Damage", damage));
}
// When the item breaks
if (durability <= 0 && player != null) {
player.getWorld().playSound(player.getLocation(), Sound.ENTITY_ITEM_BREAK, 1, 1);
PlayerData.get(player).getInventory().scheduleUpdate();
}
nbtItem.addTag(new ItemTag("MMOITEMS_DURABILITY", durability));
return this;
}
// Apply the NBT tags
ItemStack item = nbtItem.toItem();
public ItemStack toItem() {
// No modification needs to be done
if (durability == initialDurability)
return nbtItem.getItem();
/*
* Cross multiplication to display the current item durability on the
* item durability bar. (1 - ratio) because minecraft works with item
* damage, and item damage is the complementary of the remaining
* durability.
*
* Make sure the vanilla bar displays at least 1 damage for display
* issues. Also makes sure the item can be mended using the vanilla
* enchant.
*/
if (!barHidden) {
int damage = (durability == maxDurability) ? 0
: Math.max(1, (int) ((1. - ((double) durability / maxDurability)) * nbtItem.getItem().getType().getMaxDurability()));
nbtItem.addTag(new ItemTag("Damage", damage)); }
nbtItem.addTag(new ItemTag("MMOITEMS_DURABILITY", durability));
// Apply the NBT tags
ItemStack item = nbtItem.toItem();
// Item lore update
String format = MythicLib.inst().parseColors(MMOItems.plugin.getLanguage().getStatFormat("durability").replace("#m", String.valueOf(maxDurability)));
String old = format.replace("#c", String.valueOf(initialDurability));
String replaced = format.replace("#c", String.valueOf(durability));
return new LoreUpdate(item, old, replaced).updateLore();
}
// Item lore update
String format = MythicLib.inst().parseColors(MMOItems.plugin.getLanguage().getStatFormat("durability").replace("#m", String.valueOf(maxDurability)));
String old = format.replace("#c", String.valueOf(initialDurability));
String replaced = format.replace("#c", String.valueOf(durability));
return new LoreUpdate(item, old, replaced).updateLore();
}
}

View File

@ -1,72 +1,38 @@
package net.Indyuce.mmoitems.api.interaction.util;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import io.lumine.mythic.lib.api.item.ItemTag;
import io.lumine.mythic.lib.api.item.SupportedNBTTagValues;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.stat.data.UpgradeData;
import org.bukkit.entity.Player;
import io.lumine.mythic.lib.api.item.NBTItem;
import org.bukkit.inventory.ItemStack;
public class UntargetedDurabilityItem extends DurabilityItem {
private final EquipmentSlot slot;
private final EquipmentSlot slot;
/*
* Allows to handle custom durability for target weapons when they are
* left/right click while using the same durability system for both weapon
* types
*/
public UntargetedDurabilityItem(Player player, NBTItem item, EquipmentSlot slot) {
super(player, item);
/**
* Allows to handle custom durability for target weapons when
* they are left/right clicked while using the same durability
* system for both weapon types
*/
public UntargetedDurabilityItem(Player player, NBTItem item, EquipmentSlot slot) {
super(player, item);
this.slot = slot;
}
this.slot = slot;
}
@Override
public UntargetedDurabilityItem decreaseDurability(int loss) {
return (UntargetedDurabilityItem) super.decreaseDurability(loss);
}
@Override
public UntargetedDurabilityItem decreaseDurability(int loss) {
return (UntargetedDurabilityItem) super.decreaseDurability(loss);
}
public void update() {
public void inventoryUpdate() {
// Cannot update null player
if (getPlayer() == null) { return; }
if (isBroken() && isLostWhenBroken()) {
if (slot == EquipmentSlot.OFF_HAND)
getPlayer().getInventory().setItemInOffHand(null);
else
getPlayer().getInventory().setItemInMainHand(null);
return;
}
// If it broke (funny)
if (isBroken()) {
// Attempt to counter by downgrading
if (isDowngradedWhenBroken()) {
ItemStack counterUpgraded = shouldBreakWhenDowngraded();
if (counterUpgraded != null) {
// Edit item
getNBTItem().getItem().setItemMeta(counterUpgraded.getItemMeta());
// No more
return;
}
}
// Still here? Remove if lost when broken
if (isLostWhenBroken()) {
// Delete item
if (slot == EquipmentSlot.OFF_HAND) {
getPlayer().getInventory().setItemInOffHand(null);
} else { getPlayer().getInventory().setItemInMainHand(null); }
// No more
return;
}
}
getNBTItem().getItem().setItemMeta(toItem().getItemMeta());
}
getNBTItem().getItem().setItemMeta(toItem().getItemMeta());
}
}

View File

@ -26,17 +26,17 @@ public class Crossbow extends UntargetedWeapon {
if (getPlayer().getGameMode() != GameMode.CREATIVE && !getPlayer().getInventory().containsAtLeast(new ItemStack(Material.ARROW), 1))
return;
UntargetedDurabilityItem durItem = new UntargetedDurabilityItem(getPlayer(), getNBTItem(), slot);
if (durItem.isBroken())
return;
PlayerMetadata stats = getPlayerData().getStats().newTemporary(slot);
if (!applyWeaponCosts(1 / getValue(stats.getStat("ATTACK_SPEED"), MMOItems.plugin.getConfig().getDouble("default.attack-speed")),
CooldownType.ATTACK))
return;
UntargetedDurabilityItem durItem = new UntargetedDurabilityItem(getPlayer(), getNBTItem(), slot);
if (durItem.isBroken())
return;
if (durItem.isValid())
durItem.decreaseDurability(1).update();
durItem.decreaseDurability(1).inventoryUpdate();
// consume arrow
// has to be after the CD check

View File

@ -35,17 +35,18 @@ public class Lute extends UntargetedWeapon {
@Override
public void untargetedAttack(EquipmentSlot slot) {
PlayerMetadata stats = getPlayerData().getStats().newTemporary(slot);
double attackSpeed = 1 / getValue(stats.getStat("ATTACK_SPEED"), MMOItems.plugin.getConfig().getDouble("default.attack-speed"));
if (!applyWeaponCosts(attackSpeed, CooldownType.ATTACK))
return;
UntargetedDurabilityItem durItem = new UntargetedDurabilityItem(getPlayer(), getNBTItem(), slot);
if (durItem.isBroken())
return;
PlayerMetadata stats = getPlayerData().getStats().newTemporary(slot);
double attackSpeed = 1 / getValue(stats.getStat("ATTACK_SPEED"), MMOItems.plugin.getConfig().getDouble("default.attack-speed"));
if (!applyWeaponCosts(attackSpeed, CooldownType.ATTACK))
return;
if (durItem.isValid())
durItem.decreaseDurability(1).update();
durItem.decreaseDurability(1).inventoryUpdate();
double attackDamage = getValue(stats.getStat("ATTACK_DAMAGE"), 7);
double range = getValue(getNBTItem().getStat(ItemStats.RANGE.getId()), MMOItems.plugin.getConfig().getDouble("default.range"));

View File

@ -28,18 +28,18 @@ public class Musket extends UntargetedWeapon {
@Override
public void untargetedAttack(EquipmentSlot slot) {
PlayerMetadata stats = getPlayerData().getStats().newTemporary(slot);
if (!applyWeaponCosts(1 / getValue(stats.getStat("ATTACK_SPEED"), MMOItems.plugin.getConfig().getDouble("default.attack-speed")),
CooldownType.ATTACK))
return;
UntargetedDurabilityItem durItem = new UntargetedDurabilityItem(getPlayer(), getNBTItem(), slot);
if (durItem.isBroken())
return;
PlayerMetadata stats = getPlayerData().getStats().newTemporary(slot);
if (!applyWeaponCosts(1 / getValue(stats.getStat("ATTACK_SPEED"), MMOItems.plugin.getConfig().getDouble("default.attack-speed")),
CooldownType.ATTACK))
return;
if (durItem.isValid())
durItem.decreaseDurability(1).update();
durItem.decreaseDurability(1).inventoryUpdate();
double attackDamage = stats.getStat("ATTACK_DAMAGE");
double range = getValue(getNBTItem().getStat(ItemStats.RANGE.getId()), MMOItems.plugin.getConfig().getDouble("default.range"));

View File

@ -32,17 +32,17 @@ public class Staff extends UntargetedWeapon {
@Override
public void untargetedAttack(EquipmentSlot slot) {
UntargetedDurabilityItem durItem = new UntargetedDurabilityItem(getPlayer(), getNBTItem(), slot);
if (durItem.isBroken())
return;
PlayerMetadata stats = getPlayerData().getStats().newTemporary(slot);
if (!applyWeaponCosts(1 / getValue(stats.getStat("ATTACK_SPEED"), MMOItems.plugin.getConfig().getDouble("default.attack-speed")),
CooldownType.ATTACK))
return;
UntargetedDurabilityItem durItem = new UntargetedDurabilityItem(getPlayer(), getNBTItem(), slot);
if (durItem.isBroken())
return;
if (durItem.isValid())
durItem.decreaseDurability(1).update();
durItem.decreaseDurability(1).inventoryUpdate();
double attackDamage = getValue(stats.getStat("ATTACK_DAMAGE"), 1);
double range = getValue(getNBTItem().getStat(ItemStats.RANGE.getId()), MMOItems.plugin.getConfig().getDouble("default.range"));

View File

@ -29,17 +29,17 @@ public class Whip extends UntargetedWeapon {
@Override
public void untargetedAttack(EquipmentSlot slot) {
UntargetedDurabilityItem durItem = new UntargetedDurabilityItem(getPlayer(), getNBTItem(), slot);
if (durItem.isBroken())
return;
PlayerMetadata stats = getPlayerData().getStats().newTemporary(slot);
if (!applyWeaponCosts(1 / getValue(stats.getStat("ATTACK_SPEED"), MMOItems.plugin.getConfig().getDouble("default.attack-speed")),
CooldownType.ATTACK))
return;
UntargetedDurabilityItem durItem = new UntargetedDurabilityItem(getPlayer(), getNBTItem(), slot);
if (durItem.isBroken())
return;
if (durItem.isValid())
durItem.decreaseDurability(1).update();
durItem.decreaseDurability(1).inventoryUpdate();
double attackDamage = getValue(stats.getStat("ATTACK_DAMAGE"), 7);
double range = getValue(getNBTItem().getStat(ItemStats.RANGE.getId()), MMOItems.plugin.getConfig().getDouble("default.range"));

View File

@ -1,9 +1,8 @@
package net.Indyuce.mmoitems.api.item.mmoitem;
import io.lumine.mythic.lib.api.item.NBTItem;
import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.api.Type;
import io.lumine.mythic.lib.api.item.NBTItem;
import net.Indyuce.mmoitems.api.interaction.util.DurabilityItem;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.Damageable;
import org.bukkit.inventory.meta.ItemMeta;
@ -15,7 +14,7 @@ public abstract class ReadMMOItem extends MMOItem {
/**
* This class is used when reading an MMOItem from an ItemStack (the
* opposite of ItemStackBuilder, like an ItemStackReader)
*
*
* @param item
* The NBTItem being read to generate an MMOItem
*/
@ -29,19 +28,11 @@ public abstract class ReadMMOItem extends MMOItem {
public int getDamage() {
// Does it use custom durability?
if (hasData(ItemStats.MAX_DURABILITY)) {
if (hasData(ItemStats.MAX_DURABILITY))
return getNBT().hasTag("MMOITEMS_DURABILITY") ? getNBT().getInteger("MMOITEMS_MAX_DURABILITY") - getNBT().getInteger("MMOITEMS_DURABILITY") : 0;
// Use the correct class
DurabilityItem dItem = new DurabilityItem(null, getNBT());
int max = dItem.getMaxDurability();
int current = dItem.getDurability();
// Difference
return max - current;
// Its using vanilla durability-yo
} else {
// Its using vanilla durability-yo
else {
// Uh use the item stack I guess
ItemStack asStack = getNBT().getItem();

View File

@ -22,145 +22,115 @@ import java.util.Arrays;
import java.util.List;
public class DurabilityListener implements Listener {
private final List<DamageCause> ignoredCauses = Arrays.asList(DamageCause.DROWNING, DamageCause.SUICIDE, DamageCause.FALL, DamageCause.VOID,
DamageCause.FIRE_TICK, DamageCause.SUFFOCATION, DamageCause.POISON, DamageCause.WITHER, DamageCause.STARVATION, DamageCause.MAGIC);
private final List<DamageCause> ignoredCauses = Arrays.asList(DamageCause.DROWNING, DamageCause.SUICIDE, DamageCause.FALL, DamageCause.VOID,
DamageCause.FIRE_TICK, DamageCause.SUFFOCATION, DamageCause.POISON, DamageCause.WITHER, DamageCause.STARVATION, DamageCause.MAGIC);
private final EquipmentSlot[] armorSlots = { EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET };
private final EquipmentSlot[] armorSlots = {EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET};
/**
* Handles custom durability for non-'vanilla durability' items
*/
@EventHandler(ignoreCancelled = true)
public void playerDamage(EntityDamageEvent event) {
if (event.getEntityType() != EntityType.PLAYER || ignoredCauses.contains(event.getCause()))
return;
/**
* Handles custom durability for non-'vanilla durability' items
*/
@EventHandler(ignoreCancelled = true)
public void playerDamage(EntityDamageEvent event) {
if (event.getEntityType() != EntityType.PLAYER || ignoredCauses.contains(event.getCause()))
return;
Player player = (Player) event.getEntity();
int damage = Math.max((int) event.getDamage() / 4, 1);
for (EquipmentSlot slot : armorSlots)
if (hasItem(player, slot))
handleVanillaDamage(player.getInventory().getItem(slot), player, slot, damage);
}
Player player = (Player) event.getEntity();
int damage = Math.max((int) event.getDamage() / 4, 1);
for (EquipmentSlot slot : armorSlots)
if (hasItem(player, slot))
handleVanillaDamage(player.getInventory().getItem(slot), player, slot, damage);
}
@EventHandler(ignoreCancelled = true)
public void playerMeleeAttack(EntityDamageByEntityEvent event) {
if (event.getDamage() == 0 || event.getCause() != DamageCause.ENTITY_ATTACK || !(event.getEntity() instanceof LivingEntity)
|| !(event.getDamager() instanceof Player) || event.getEntity().hasMetadata("NPC") || event.getDamager().hasMetadata("NPC"))
return;
Player player = (Player) event.getDamager();
ItemStack item = player.getInventory().getItemInMainHand();
@EventHandler(ignoreCancelled = true)
public void playerMeleeAttack(EntityDamageByEntityEvent event) {
if (event.getDamage() == 0 || event.getCause() != DamageCause.ENTITY_ATTACK || !(event.getEntity() instanceof LivingEntity)
|| !(event.getDamager() instanceof Player) || event.getEntity().hasMetadata("NPC") || event.getDamager().hasMetadata("NPC"))
return;
Player player = (Player) event.getDamager();
ItemStack item = player.getInventory().getItemInMainHand();
handleVanillaDamage(item, player, EquipmentSlot.HAND, 1);
}
handleVanillaDamage(item, player, EquipmentSlot.HAND, 1);
}
@EventHandler(ignoreCancelled = true)
public void playerBowAttack(EntityShootBowEvent event) {
if (!(event.getEntity() instanceof Player))
return;
Player player = (Player) event.getEntity();
ItemStack item = event.getBow();
@EventHandler(ignoreCancelled = true)
public void playerBowAttack(EntityShootBowEvent event) {
if (!(event.getEntity() instanceof Player))
return;
Player player = (Player) event.getEntity();
ItemStack item = event.getBow();
handleVanillaDamage(item, player, EquipmentSlot.HAND, 1);
}
handleVanillaDamage(item, player, EquipmentSlot.HAND, 1);
}
@EventHandler(ignoreCancelled = true)
public void itemDamage(PlayerItemDamageEvent event) {
DurabilityItem item = new DurabilityItem(event.getPlayer(), event.getItem());
@EventHandler(ignoreCancelled = true)
public void itemDamage(PlayerItemDamageEvent event) {
DurabilityItem item = new DurabilityItem(event.getPlayer(), event.getItem());
if (item.isValid()) {
if (item.isValid()) {
// Calculate item durability loss
item.decreaseDurability(event.getDamage());
// Calculate item durability loss
item.decreaseDurability(event.getDamage());
/*
* If the item is broken and if it is meant to be lost when broken,
* do NOT cancel the event and make sure the item is destroyed
*/
if (item.isBroken()) {
/*
* If the item is broken and if it is meant to be lost when broken,
* do NOT cancel the event and make sure the item is destroyed
*/
if (item.isBroken()) {
// Still here? Remove if lost when broken
if (item.isLostWhenBroken()) {
// Attempt to counter by downgrading
if (item.isDowngradedWhenBroken()) {
// Delete item
event.setDamage(999);
ItemStack counterUpgraded = item.shouldBreakWhenDowngraded();
if (counterUpgraded != null) {
// Allow event to proceed
return;
}
}
// Counter Event
event.setCancelled(true);
event.getItem().setItemMeta(counterUpgraded.getItemMeta());
event.setCancelled(true);
event.getItem().setItemMeta(item.toItem().getItemMeta());
}
}
// No more
return;
}
}
// Still here? Remove if lost when broken
if (item.isLostWhenBroken()) {
// Delete item
event.setDamage(999);
// Allow event to proceed
return;
}
}
event.setCancelled(true);
event.getItem().setItemMeta(item.toItem().getItemMeta());
}
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void mendEvent(PlayerItemMendEvent event) {
DurabilityItem durItem = new DurabilityItem(event.getPlayer(), event.getItem());
if (durItem.isValid()) {
event.getItem().setItemMeta(durItem.addDurability(event.getRepairAmount()).toItem().getItemMeta());
event.setCancelled(true);
}
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void mendEvent(PlayerItemMendEvent event) {
DurabilityItem durItem = new DurabilityItem(event.getPlayer(), event.getItem());
if (durItem.isValid()) {
event.getItem().setItemMeta(durItem.addDurability(event.getRepairAmount()).toItem().getItemMeta());
event.setCancelled(true);
}
}
/**
* This method is for all the items which have 0 max durability
* i.E which are not breakable hence the {@link Material#getMaxDurability()} call
*/
private void handleVanillaDamage(ItemStack stack, Player player, EquipmentSlot slot, int damage) {
DurabilityItem item = new DurabilityItem(player, stack);
private void handleVanillaDamage(ItemStack stack, Player player, EquipmentSlot slot, int damage) {
DurabilityItem item = new DurabilityItem(player, stack);
if (item.isValid() && stack.getType().getMaxDurability() == 0) {
item.decreaseDurability(damage);
if (item.isValid() && stack.getType().getMaxDurability() == 0) {
item.decreaseDurability(damage);
if (item.isBroken()) {
if (item.isBroken()) {
// Attempt to counter by downgrading
if (item.isDowngradedWhenBroken()) {
// Still here? Remove if lost when broken
if (item.isLostWhenBroken()) {
ItemStack counterUpgraded = item.shouldBreakWhenDowngraded();
if (counterUpgraded != null) {
// Delete item
player.getInventory().setItem(slot, null);
player.getWorld().playSound(player.getLocation(), Sound.ENTITY_ITEM_BREAK, 1.0f, 1.0f);
// Edit item
player.getInventory().getItem(slot).setItemMeta(counterUpgraded.getItemMeta());
// No more
return;
}
}
// No more
return;
}
}
player.getInventory().getItem(slot).setItemMeta(item.toItem().getItemMeta());
}
}
// Still here? Remove if lost when broken
if (item.isLostWhenBroken()) {
// Delete item
player.getInventory().setItem(slot, null);
player.getWorld().playSound(player.getLocation(), Sound.ENTITY_ITEM_BREAK, 1.0f, 1.0f);
// No more
return;
}
}
player.getInventory().getItem(slot).setItemMeta(item.toItem().getItemMeta());
}
}
private boolean hasItem(Player player, EquipmentSlot slot) {
return player.getInventory().getItem(slot) != null && player.getInventory().getItem(slot).getType() != Material.AIR;
}
private boolean hasItem(Player player, EquipmentSlot slot) {
return player.getInventory().getItem(slot) != null && player.getInventory().getItem(slot).getType() != Material.AIR;
}
}