diff --git a/Changelog.txt b/Changelog.txt index af2ed248c..8640fd27b 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -169,6 +169,20 @@ Version 2.2.0 Added API method to grab the level cap of a skill by its PrimarySkillType ENUM definition Added API method to check if a skill was being level capped Added 'UndefinedSkillBehaviour' for trying to use a method that has no behaviour defined for the provided skill +Version 2.1.81 + Fixed a bug where Arrow Deflect would never trigger outside of PVP + Fixed a bug where failing to salvage enchantments incorrectly colored the text + mcMMO no longer allows players to keep enchantments exceeding normal limitations by default when salvaging or repairing (you can turn this off in the config, see below) + Added new setting 'ExploitFix.UnsafeEnchantments' to experience.yml, turn this on to allow players to salvage/repair enchantments higher than normal game restrictions + + NOTES: + If a player tries to salvage/repair an item with an illegal enchant (for example Sharpness X) it will downgrade that item to the highest legal version when calculating rewards + If you don't like this change you can turn it off in experience.yml under 'ExploitFix.UnsafeEnchantments' + + +Version 2.1.80 + (Fix) mcMMO now respects the NBT "Unbreakable" tag and does not deal durability damage to items with that tag + Version 2.1.79 Updated Japanese locale (Thanks snake0053) Fixed a NPE that could happen when using Tree Feller with an unenchanted Axe diff --git a/src/main/java/com/gmail/nossr50/config/MainConfig.java b/src/main/java/com/gmail/nossr50/config/MainConfig.java index 114e3fa10..d17c671a5 100644 --- a/src/main/java/com/gmail/nossr50/config/MainConfig.java +++ b/src/main/java/com/gmail/nossr50/config/MainConfig.java @@ -5,7 +5,6 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.StringUtils; import ninja.leaping.configurate.objectmapping.serialize.ConfigSerializable; import org.bukkit.Material; -import org.bukkit.block.data.BlockData; import org.bukkit.entity.EntityType; import java.util.ArrayList; diff --git a/src/main/java/com/gmail/nossr50/config/hocon/antiexploit/AntiExploit.java b/src/main/java/com/gmail/nossr50/config/hocon/antiexploit/AntiExploit.java deleted file mode 100644 index 33e021f8a..000000000 --- a/src/main/java/com/gmail/nossr50/config/hocon/antiexploit/AntiExploit.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.gmail.nossr50.config.hocon.antiexploit; - -import ninja.leaping.configurate.objectmapping.Setting; -import ninja.leaping.configurate.objectmapping.serialize.ConfigSerializable; - -@ConfigSerializable -public class AntiExploit { - public static final boolean SPAWNED_MOBS_DEFAULT = true; - private static final boolean ENDERMEN_ENDERMITE_DEFAULT = true; - private static final boolean PISTONS_MARK_BLOCKS_DEFAULT = true; - - /* - * CONFIG NODES - */ - @Setting(value = "Endermen-Endermite-Fix", - comment = "Removes XP from Endermen that target endermite, this is a common exploit in The End because of how rapidly they can spawn." + - "\nIt is recommended that you leave this on as it allows players to easily gain massive amounts of combat XP" + - "\nDefault value: " + ENDERMEN_ENDERMITE_DEFAULT) - private boolean endermenEndermiteFix = ENDERMEN_ENDERMITE_DEFAULT; - - @Setting(value = "Pistons-Mark-Blocks-As-Unnatural", - comment = "Unnatural blocks give no XP." + - "This helps prevent complex automated stone farms that enable auto clickers to gain XP passively.") - private boolean pistonsMarkBlocksUnnatural = PISTONS_MARK_BLOCKS_DEFAULT; - - @Setting(value = "Spawned-Mobs-Give-No-XP", - comment = "Spawned mobs will not give players combat XP." + - "\nThis includes mobs spawned from a nether portal, mob spawner, or eggs." + - "\nThis will not include mobs spawned from commands, typically.") - private boolean spawnedMobsGiveNoXP = SPAWNED_MOBS_DEFAULT; -} diff --git a/src/main/java/com/gmail/nossr50/config/hocon/antiexploit/ConfigExploitPrevention.java b/src/main/java/com/gmail/nossr50/config/hocon/antiexploit/ConfigExploitPrevention.java index 212e06784..dde48be6e 100644 --- a/src/main/java/com/gmail/nossr50/config/hocon/antiexploit/ConfigExploitPrevention.java +++ b/src/main/java/com/gmail/nossr50/config/hocon/antiexploit/ConfigExploitPrevention.java @@ -103,4 +103,12 @@ public class ConfigExploitPrevention { public boolean isPreventVehicleAutoFarming() { return configSectionExploitSkills.isPreventVehicleAutoFarming(); } + + public ConfigSectionExploitRepair getConfigSectionExploitRepair() { + return configSectionExploitSkills.getConfigSectionExploitRepair(); + } + + public ConfigSectionExploitSalvage getConfigSectionExploitSalvage() { + return configSectionExploitSkills.getConfigSectionExploitSalvage(); + } } diff --git a/src/main/java/com/gmail/nossr50/config/hocon/antiexploit/ConfigSectionExploitRepair.java b/src/main/java/com/gmail/nossr50/config/hocon/antiexploit/ConfigSectionExploitRepair.java new file mode 100644 index 000000000..1b34d856a --- /dev/null +++ b/src/main/java/com/gmail/nossr50/config/hocon/antiexploit/ConfigSectionExploitRepair.java @@ -0,0 +1,20 @@ +package com.gmail.nossr50.config.hocon.antiexploit; + +import ninja.leaping.configurate.objectmapping.Setting; +import ninja.leaping.configurate.objectmapping.serialize.ConfigSerializable; + +@ConfigSerializable +public class ConfigSectionExploitRepair { + + private static final boolean ALLOW_UNSAFE_DEFAULT = false; + + @Setting(value = "Allow-Illegal-Enchantments", comment = "If set to true, mcMMO will allow repair to keep illegal enchantments on equipment when repairing." + + "\nIf set to false, mcMMO will downgrade the enchantment to its native max level before calculating results." + + "\nAn illegal enchant is one that is not obtainable through normal gameplay without mods or cheats." + + "\nDefault value: "+ALLOW_UNSAFE_DEFAULT) + private boolean allowUnsafeEnchants = ALLOW_UNSAFE_DEFAULT; + + public boolean isAllowUnsafeEnchants() { + return allowUnsafeEnchants; + } +} diff --git a/src/main/java/com/gmail/nossr50/config/hocon/antiexploit/ConfigSectionExploitSalvage.java b/src/main/java/com/gmail/nossr50/config/hocon/antiexploit/ConfigSectionExploitSalvage.java new file mode 100644 index 000000000..d6408a670 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/config/hocon/antiexploit/ConfigSectionExploitSalvage.java @@ -0,0 +1,19 @@ +package com.gmail.nossr50.config.hocon.antiexploit; + +import ninja.leaping.configurate.objectmapping.Setting; + +public class ConfigSectionExploitSalvage { + + private static final boolean ALLOW_UNSAFE_DEFAULT = false; + + @Setting(value = "Allow-Illegal-Enchantments", comment = "If set to true, mcMMO will allow salvage to create books with illegal enchants." + + "\nIf set to false, mcMMO will downgrade the enchantment to its native max level before calculating results." + + "\nAn illegal enchant is one that is not obtainable through normal gameplay without mods or cheats." + + "\nDefault value: "+ALLOW_UNSAFE_DEFAULT) + private boolean allowUnsafeEnchants = ALLOW_UNSAFE_DEFAULT; + + public boolean isAllowUnsafeEnchants() { + return allowUnsafeEnchants; + } + +} diff --git a/src/main/java/com/gmail/nossr50/config/hocon/antiexploit/ConfigSectionExploitSkills.java b/src/main/java/com/gmail/nossr50/config/hocon/antiexploit/ConfigSectionExploitSkills.java index 806c070bb..8a0a4e0f7 100644 --- a/src/main/java/com/gmail/nossr50/config/hocon/antiexploit/ConfigSectionExploitSkills.java +++ b/src/main/java/com/gmail/nossr50/config/hocon/antiexploit/ConfigSectionExploitSkills.java @@ -17,6 +17,12 @@ public class ConfigSectionExploitSkills { @Setting(value = "Herbalism", comment = "Exploit settings related to Herbalism.") private ConfigSectionExploitHerbalism configSectionExploitHerbalism = new ConfigSectionExploitHerbalism(); + @Setting(value = "Repair", comment = "Exploit settings related to Repair.") + private ConfigSectionExploitRepair configSectionExploitRepair = new ConfigSectionExploitRepair(); + + @Setting(value = "Salvage", comment = "Exploit settings related to Salvage") + private ConfigSectionExploitSalvage configSectionExploitSalvage = new ConfigSectionExploitSalvage(); + public ConfigSectionExploitAcrobatics getConfigSectionExploitAcrobatics() { return configSectionExploitAcrobatics; } @@ -76,4 +82,12 @@ public class ConfigSectionExploitSkills { public boolean isPreventAcrobaticsAbuse() { return configSectionExploitAcrobatics.isPreventAcrobaticsAbuse(); } + + public ConfigSectionExploitRepair getConfigSectionExploitRepair() { + return configSectionExploitRepair; + } + + public ConfigSectionExploitSalvage getConfigSectionExploitSalvage() { + return configSectionExploitSalvage; + } } diff --git a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java index e5e067809..69b039a6a 100644 --- a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.listeners; -import com.gmail.nossr50.config.MainConfig; import com.gmail.nossr50.config.WorldBlacklist; import com.gmail.nossr50.core.MetadataConstants; import com.gmail.nossr50.datatypes.meta.BonusDropMeta; diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index c8bf50c84..b8a22159a 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -15,6 +15,7 @@ import com.gmail.nossr50.skills.mining.BlastMining; import com.gmail.nossr50.skills.mining.MiningManager; import com.gmail.nossr50.skills.taming.Taming; import com.gmail.nossr50.skills.taming.TamingManager; +import com.gmail.nossr50.skills.unarmed.UnarmedManager; import com.gmail.nossr50.util.BlockUtils; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; @@ -325,7 +326,20 @@ public class EntityListener implements Listener { if (projectileSource instanceof LivingEntity) { attacker = (LivingEntity) projectileSource; } - } else if (attacker instanceof Tameable) { + + if(defender instanceof Player) { + Player playerDefender = (Player) defender; + UnarmedManager unarmedManager = UserManager.getPlayer(playerDefender).getUnarmedManager(); + + if (unarmedManager.canDeflect()) { + if(unarmedManager.deflectCheck()) { + event.setCancelled(true); + return; + } + } + } + } + else if (attacker instanceof Tameable) { AnimalTamer animalTamer = ((Tameable) attacker).getOwner(); if (animalTamer != null && ((OfflinePlayer) animalTamer).isOnline()) { diff --git a/src/main/java/com/gmail/nossr50/listeners/SelfListener.java b/src/main/java/com/gmail/nossr50/listeners/SelfListener.java index d22840b7d..1bf824d6b 100644 --- a/src/main/java/com/gmail/nossr50/listeners/SelfListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/SelfListener.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.listeners; -import com.gmail.nossr50.config.MainConfig; import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; diff --git a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java index 21efbefad..77892da88 100644 --- a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java +++ b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.skills.mining; import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.MainConfig; import com.gmail.nossr50.core.MetadataConstants; import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.interactions.NotificationType; diff --git a/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java b/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java index 0366e997b..56f137f72 100644 --- a/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java +++ b/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java @@ -328,10 +328,19 @@ public class RepairManager extends SkillManager { boolean downgraded = false; for (Entry enchant : enchants.entrySet()) { + int enchantLevel = enchant.getValue(); + + if(!mcMMO.getConfigManager().getConfigExploitPrevention().getConfigSectionExploitRepair().isAllowUnsafeEnchants()) { + if(enchantLevel > enchant.getKey().getMaxLevel()) { + enchantLevel = enchant.getKey().getMaxLevel(); + + item.addEnchantment(enchant.getKey(), enchantLevel); + } + } + Enchantment enchantment = enchant.getKey(); if (RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getKeepEnchantChance(), getPlayer(), SubSkillType.REPAIR_ARCANE_FORGING))) { - int enchantLevel = enchant.getValue(); if (mcMMO.getConfigManager().getConfigRepair().getArcaneForging().isDowngradesEnabled() && enchantLevel > 1 && (!RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(100 - getDowngradeEnchantChance(), getPlayer(), SubSkillType.REPAIR_ARCANE_FORGING)))) { @@ -346,11 +355,13 @@ public class RepairManager extends SkillManager { Map newEnchants = item.getEnchantments(); if (newEnchants.isEmpty()) { - mcMMO.getNotificationManager().sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE_FAILED, "Repair.Arcane.Fail"); - } else if (downgraded || newEnchants.size() < enchants.size()) { - mcMMO.getNotificationManager().sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE_FAILED, "Repair.Arcane.Downgrade"); - } else { - mcMMO.getNotificationManager().sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Repair.Arcane.Perfect"); + mcMMO.getNotificationManager().sendPlayerInformationChatOnly(getPlayer(), "Repair.Arcane.Fail"); + } + else if (downgraded || newEnchants.size() < enchants.size()) { + mcMMO.getNotificationManager().sendPlayerInformationChatOnly(getPlayer(), "Repair.Arcane.Downgrade"); + } + else { + mcMMO.getNotificationManager().sendPlayerInformationChatOnly(getPlayer(), "Repair.Arcane.Perfect"); } } diff --git a/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java b/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java index 6112bbdd2..b58369b02 100644 --- a/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java +++ b/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java @@ -211,7 +211,7 @@ public class SalvageManager extends SkillManager { Player player = getPlayer(); if (!RankUtils.hasUnlockedSubskill(player, SubSkillType.SALVAGE_ARCANE_SALVAGE) || !Permissions.arcaneSalvage(player)) { - mcMMO.getNotificationManager().sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Salvage.Skills.ArcaneFailed"); + mcMMO.getNotificationManager().sendPlayerInformationChatOnly(player, "Salvage.Skills.ArcaneFailed"); return null; } @@ -222,25 +222,38 @@ public class SalvageManager extends SkillManager { int arcaneFailureCount = 0; for (Entry enchant : enchants.entrySet()) { + + int enchantLevel = enchant.getValue(); + + if(!mcMMO.getConfigManager().getConfigExploitPrevention().getConfigSectionExploitSkills().getConfigSectionExploitSalvage().isAllowUnsafeEnchants()) { + if(enchantLevel > enchant.getKey().getMaxLevel()) { + enchantLevel = enchant.getKey().getMaxLevel(); + } + } + if (!Salvage.arcaneSalvageEnchantLoss || Permissions.hasSalvageEnchantBypassPerk(player) || RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getExtractFullEnchantChance(), getPlayer(), SubSkillType.SALVAGE_ARCANE_SALVAGE))) { - enchantMeta.addStoredEnchant(enchant.getKey(), enchant.getValue(), true); - } else if (enchant.getValue() > 1 + + enchantMeta.addStoredEnchant(enchant.getKey(), enchantLevel, true); + } + else if (enchantLevel > 1 && Salvage.arcaneSalvageDowngrades && RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getExtractPartialEnchantChance(), getPlayer(), SubSkillType.SALVAGE_ARCANE_SALVAGE))) { - enchantMeta.addStoredEnchant(enchant.getKey(), enchant.getValue() - 1, true); + enchantMeta.addStoredEnchant(enchant.getKey(), enchantLevel - 1, true); downgraded = true; } else { arcaneFailureCount++; } } - if (failedAllEnchants(arcaneFailureCount, enchants.entrySet().size())) { - mcMMO.getNotificationManager().sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Salvage.Skills.ArcaneFailed"); + if(failedAllEnchants(arcaneFailureCount, enchants.entrySet().size())) + { + mcMMO.getNotificationManager().sendPlayerInformationChatOnly(player, "Salvage.Skills.ArcaneFailed"); return null; - } else if (downgraded) { - mcMMO.getNotificationManager().sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Salvage.Skills.ArcanePartial"); + } else if(downgraded) + { + mcMMO.getNotificationManager().sendPlayerInformationChatOnly(player, "Salvage.Skills.ArcanePartial"); } book.setItemMeta(enchantMeta); diff --git a/src/main/java/com/gmail/nossr50/skills/unarmed/Unarmed.java b/src/main/java/com/gmail/nossr50/skills/unarmed/Unarmed.java index 40e32e873..2f6290884 100644 --- a/src/main/java/com/gmail/nossr50/skills/unarmed/Unarmed.java +++ b/src/main/java/com/gmail/nossr50/skills/unarmed/Unarmed.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.skills.unarmed; -import com.gmail.nossr50.config.MainConfig; import com.gmail.nossr50.util.sounds.SoundManager; import com.gmail.nossr50.util.sounds.SoundType; import org.bukkit.entity.Player; diff --git a/src/main/java/com/gmail/nossr50/skills/woodcutting/Woodcutting.java b/src/main/java/com/gmail/nossr50/skills/woodcutting/Woodcutting.java index 5a08dc964..8005da294 100644 --- a/src/main/java/com/gmail/nossr50/skills/woodcutting/Woodcutting.java +++ b/src/main/java/com/gmail/nossr50/skills/woodcutting/Woodcutting.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.skills.woodcutting; -import com.gmail.nossr50.config.MainConfig; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.BlockUtils; import com.gmail.nossr50.util.Misc; @@ -138,8 +137,8 @@ public final class Woodcutting { */ protected static boolean handleDurabilityLoss(Set treeFellerBlocks, ItemStack inHand) { - if(inHand.getItemMeta().getEnchants().get(Enchantment.DURABILITY) != null - && inHand.getItemMeta().getEnchants().get(Enchantment.DURABILITY) >= 1) { + if((inHand.getItemMeta().getEnchants().get(Enchantment.DURABILITY) != null && inHand.getItemMeta().getEnchants().get(Enchantment.DURABILITY) >= 1) + || (inHand.getItemMeta() != null && inHand.getItemMeta().isUnbreakable())) { return true; } diff --git a/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java b/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java index b67630d55..d910dac78 100644 --- a/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java +++ b/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java @@ -59,9 +59,8 @@ public class NotificationManager { /** * Sends players notifications from mcMMO - * This does this by sending out an event so other plugins can cancel it - * - * @param player target player + * Does so by sending out an event so other plugins can cancel it + * @param player target player * @param notificationType notifications defined type * @param key the locale key for the notifications defined message */ diff --git a/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java b/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java index ac3dd07ed..a5b5572c5 100644 --- a/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java +++ b/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java @@ -25,9 +25,9 @@ public class RandomChanceUtil { * non-RNG skills just fire the cancellable event and succeed if they go uncancelled * * @param skillActivationType this value represents what kind of activation procedures this sub-skill uses - * @param subSkillType The identifier for this specific sub-skill - * @param player The owner of this sub-skill - * @return returns true if all conditions are met and they event is not cancelled + * @param subSkillType The identifier for this specific sub-skill + * @param player The owner of this sub-skill + * @return returns true if all conditions are met and the event is not cancelled */ public static boolean isActivationSuccessful(SkillActivationType skillActivationType, SubSkillType subSkillType, Player player) { switch (skillActivationType) { diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java index db180cb9a..ad33136bc 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java @@ -227,7 +227,8 @@ public class SkillUtils { * @param maxDamageModifier the amount to adjust the max damage by */ public static void handleDurabilityChange(ItemStack itemStack, double durabilityModifier, double maxDamageModifier) { - if (itemStack.getEnchantments().get(Enchantment.DURABILITY) != null && itemStack.getEnchantments().get(Enchantment.DURABILITY) >= 1) { + if((itemStack.getItemMeta().getEnchants().get(Enchantment.DURABILITY) != null && itemStack.getItemMeta().getEnchants().get(Enchantment.DURABILITY) >= 1) + || (itemStack.getItemMeta() != null && itemStack.getItemMeta().isUnbreakable())) { return; } diff --git a/src/main/resources/experience.yml b/src/main/resources/experience.yml index 79fc4118a..c44365f92 100644 --- a/src/main/resources/experience.yml +++ b/src/main/resources/experience.yml @@ -26,6 +26,7 @@ EarlyGameBoost: #Used to determine the cap of the max boot, with default level cap it will be 5 on standard, and 50 on retro MaxLevelMultiplier: 0.05 ExploitFix: + UnsafeEnchantments: false # Prevent many exploits related to fishing Fishing: true EndermanEndermiteFarms: true