From a2ee4be86a7719d768ccb7bf93af2458ee85b31f Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 2 Apr 2021 20:31:19 -0700 Subject: [PATCH] Fix some bugs with Rupture and fix a small memory leak --- Changelog.txt | 4 ++- .../commands/skills/MmoInfoCommand.java | 1 - .../commands/skills/SwordsCommand.java | 3 +- .../gmail/nossr50/config/AdvancedConfig.java | 3 -- .../nossr50/listeners/EntityListener.java | 6 +++- .../nossr50/listeners/PlayerListener.java | 1 + src/main/java/com/gmail/nossr50/mcMMO.java | 1 + .../nossr50/runnables/skills/RuptureTask.java | 28 ++++++++----------- .../nossr50/skills/swords/SwordsManager.java | 13 +++++---- .../gmail/nossr50/util/MobHealthbarUtils.java | 2 +- .../nossr50/util/TransientMetadataTools.java | 12 +++++--- .../nossr50/util/skills/CombatUtils.java | 5 ++-- .../util/skills/ParticleEffectUtils.java | 9 +++--- 13 files changed, 44 insertions(+), 44 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 46a178ee0..5d8e8ce0f 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,5 +1,7 @@ Version 2.1.186 Rupture has been reworked to solve a few outstanding issues (see notes) + Fixed an exploit involving enchantments (thanks TheBusyBiscuit) + Fixed a very small memory leak that would only happen in very rare situations Gore no longer applies Rupture Gore no longer sends a message to the Wolf owner when it triggers Gore no longer sends a message to players that are hit by it @@ -27,7 +29,7 @@ Version 2.1.186 NOTES: The old Rupture would constantly interfere with your ability to do a Sweep Attack/Swipe with swords, the new one solves this problem Targets will bleed and take "pure" damage while bleeding, this never kills the target. It will reduce them to 0.01 HP. - After 5 seconds since your last attack on the target have transpired Rupture "explodes" dealing a large amount of damage, this damage is not pure and is affected by armor etc. + After 5 seconds of not applying Rupture on the target Rupture explodes dealing a large amount of damage, this damage is not pure and is affected by armor etc. Rupture no longer tells you that you that you applied it to the target, it should be obvious from the sounds/particle effects The new Rupture no longer constantly interferes with the vanilla Swipe (the AOE attack built into Minecraft) The new Rupture has not had a fine tuned balance pass, I will be balancing it frequently after this patch, it may be too weak or too strong in its current form diff --git a/src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java index 0169c3918..e724ee8cd 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java @@ -2,7 +2,6 @@ package com.gmail.nossr50.commands.skills; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; -import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; import com.gmail.nossr50.listeners.InteractionManager; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.util.Permissions; diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java index 3fbe8726f..69a5e86ec 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.commands.skills; import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.locale.LocaleLoader; @@ -56,7 +55,7 @@ public class SwordsCommand extends SkillCommand { ruptureExplosionDamageAgainstPlayers = String.valueOf(AdvancedConfig.getInstance().getRuptureExplosionDamage(true, ruptureRank)); ruptureExplosionDamageAgainstMobs = String.valueOf(AdvancedConfig.getInstance().getRuptureExplosionDamage(false, ruptureRank)); - ruptureChanceToApply = String.valueOf(AdvancedConfig.getInstance().getRuptureChanceToApplyOnHit(ruptureRank)); + ruptureChanceToApply = String.valueOf(AdvancedConfig.getInstance().getRuptureChanceToApplyOnHit(ruptureRank) + "%"); ruptureChanceToApplyLucky = String.valueOf(AdvancedConfig.getInstance().getRuptureChanceToApplyOnHit(ruptureRank) * 1.33); } diff --git a/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java b/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java index 37784f28e..7e6f8e8a3 100644 --- a/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java +++ b/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java @@ -5,9 +5,6 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; import com.gmail.nossr50.mcMMO; import net.md_5.bungee.api.ChatColor; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index 414bbde52..f01a13d71 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -489,6 +489,10 @@ public class EntityListener implements Listener { if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) return; + if(event.getEntity().hasMetadata(mcMMO.EXPLOSION_FROM_RUPTURE)) { + event.getEntity().removeMetadata(mcMMO.EXPLOSION_FROM_RUPTURE, mcMMO.p); + } + if(event.getEntity() instanceof Player) { Player player = (Player) event.getEntity(); @@ -661,7 +665,7 @@ public class EntityListener implements Listener { */ @EventHandler(priority = EventPriority.LOWEST) public void onEntityDeathLowest(EntityDeathEvent event) { - mcMMO.getTransientMetadataTools().cleanAllMobMetadata(event.getEntity()); + mcMMO.getTransientMetadataTools().cleanAllLivingEntityMetadata(event.getEntity()); } /** diff --git a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java index b8b9153c2..481258b96 100644 --- a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java @@ -546,6 +546,7 @@ public class PlayerListener implements Listener { //Use a sync save if the server is shutting down to avoid race conditions mcMMOPlayer.logout(mcMMO.isServerShutdownExecuted()); + mcMMO.getTransientMetadataTools().cleanAllLivingEntityMetadata(event.getPlayer()); } /** diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index 9e442355b..cdeb9768b 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -125,6 +125,7 @@ public class mcMMO extends JavaPlugin { /* Metadata Values */ public static final String REPLANT_META_KEY = "mcMMO: Recently Replanted"; + public static final String EXPLOSION_FROM_RUPTURE = "mcMMO: Rupture Explosion"; public static final String RUPTURE_META_KEY = "mcMMO: RuptureTask"; public static final String FISH_HOOK_REF_METAKEY = "mcMMO: Fish Hook Tracker"; public static final String DODGE_TRACKER = "mcMMO: Dodge Tracker"; diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/RuptureTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/RuptureTask.java index 4ef254b57..9e4f3ee2b 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/RuptureTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/RuptureTask.java @@ -8,6 +8,7 @@ import com.gmail.nossr50.util.skills.ParticleEffectUtils; import com.google.common.base.Objects; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; +import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.scheduler.BukkitRunnable; import org.jetbrains.annotations.NotNull; @@ -27,7 +28,7 @@ public class RuptureTask extends BukkitRunnable { public RuptureTask(@NotNull McMMOPlayer ruptureSource, @NotNull LivingEntity targetEntity, double pureTickDamage, double explosionDamage) { this.ruptureSource = ruptureSource; this.targetEntity = targetEntity; - this.expireTick = AdvancedConfig.getInstance().getRuptureDurationSeconds(targetEntity instanceof Player); + this.expireTick = AdvancedConfig.getInstance().getRuptureDurationSeconds(targetEntity instanceof Player) * 20; this.ruptureTick = 0; this.damageTickTracker = 0; @@ -44,12 +45,10 @@ public class RuptureTask extends BukkitRunnable { //Rupture hasn't ended yet if(ruptureTick < expireTick) { - //Is it time to damage? if(damageTickTracker >= DAMAGE_TICK_INTERVAL) { damageTickTracker = 0; //Reset ParticleEffectUtils.playBleedEffect(targetEntity); //Animate - double finalDamage = 0; //Used for mob health bars and setting last damage if(targetEntity.getHealth() > 0.01) { double healthBeforeRuptureIsApplied = targetEntity.getHealth(); @@ -59,21 +58,8 @@ public class RuptureTask extends BukkitRunnable { mcMMO.p.getLogger().severe("DEBUG: Miscalculating Rupture tick damage"); } else { targetEntity.setHealth(damagedHealth); //Hurt entity without the unwanted side effects of damage() - - //TODO: Do we need to set last damage? Double check - finalDamage = healthBeforeRuptureIsApplied - targetEntity.getHealth(); - - if(finalDamage <= 0) { - mcMMO.p.getLogger().severe("DEBUG: Miscalculating final damage for Rupture"); - } else { - //Actually should this even be done? - targetEntity.setLastDamage(finalDamage); - } } } - - //Update Health bars - MobHealthbarUtils.handleMobHealthbars(targetEntity, finalDamage, mcMMO.p); } } else { explode(); @@ -84,8 +70,15 @@ public class RuptureTask extends BukkitRunnable { } } + public void refreshRupture() { + damageTickTracker = DAMAGE_TICK_INTERVAL; + ruptureTick = 0; + } + public void explode() { - ParticleEffectUtils.playBleedEffect(targetEntity); //Animate + targetEntity.setMetadata(mcMMO.EXPLOSION_FROM_RUPTURE, new FixedMetadataValue(mcMMO.p, "null")); + + ParticleEffectUtils.playGreaterImpactEffect(targetEntity); //Animate if(ruptureSource.getPlayer() != null && ruptureSource.getPlayer().isValid()) { targetEntity.damage(getExplosionDamage(), ruptureSource.getPlayer()); @@ -94,6 +87,7 @@ public class RuptureTask extends BukkitRunnable { } targetEntity.removeMetadata(mcMMO.RUPTURE_META_KEY, mcMMO.p); + this.cancel(); //Task no longer needed } diff --git a/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java b/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java index a24ee24e4..66d285934 100644 --- a/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java @@ -63,19 +63,20 @@ public class SwordsManager extends SkillManager { * * @param target The defending entity */ - public void processRupture(@NotNull LivingEntity target) throws IllegalStateException { - if(target.hasMetadata(mcMMO.REPLANT_META_KEY)) { + public void processRupture(@NotNull LivingEntity target) { + if(target.hasMetadata(mcMMO.RUPTURE_META_KEY)) { + RuptureTaskMeta ruptureTaskMeta = (RuptureTaskMeta) target.getMetadata(mcMMO.RUPTURE_META_KEY); + if(mmoPlayer.isDebugMode()) { mmoPlayer.getPlayer().sendMessage("Rupture task ongoing for target " + target.toString()); - RuptureTaskMeta ruptureTaskMeta = (RuptureTaskMeta) target.getMetadata(mcMMO.RUPTURE_META_KEY); - RuptureTask ruptureTask = (RuptureTask) target.getMetadata(mcMMO.RUPTURE_META_KEY); - mmoPlayer.getPlayer().sendMessage(ruptureTask.toString()); + mmoPlayer.getPlayer().sendMessage(ruptureTaskMeta.getRuptureTimerTask().toString()); } + ruptureTaskMeta.getRuptureTimerTask().refreshRupture(); return; //Don't apply bleed } - if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.SWORDS_RUPTURE, getPlayer())) { + if (RandomChanceUtil.rollDice(AdvancedConfig.getInstance().getRuptureChanceToApplyOnHit(getRuptureRank()), 100)) { if (target instanceof Player) { Player defender = (Player) target; diff --git a/src/main/java/com/gmail/nossr50/util/MobHealthbarUtils.java b/src/main/java/com/gmail/nossr50/util/MobHealthbarUtils.java index 57c7afe92..9c1f6b76e 100644 --- a/src/main/java/com/gmail/nossr50/util/MobHealthbarUtils.java +++ b/src/main/java/com/gmail/nossr50/util/MobHealthbarUtils.java @@ -131,7 +131,7 @@ public final class MobHealthbarUtils { return null; } - int coloredDisplay = (int) Math.ceil(fullDisplay * (healthPercentage / 100.0D)); + int coloredDisplay = (int) Math.max(Math.ceil(fullDisplay * (healthPercentage / 100.0D)), 0.5); int grayDisplay = fullDisplay - coloredDisplay; StringBuilder healthbar = new StringBuilder(color + ""); diff --git a/src/main/java/com/gmail/nossr50/util/TransientMetadataTools.java b/src/main/java/com/gmail/nossr50/util/TransientMetadataTools.java index 6a55c5a43..b32945525 100644 --- a/src/main/java/com/gmail/nossr50/util/TransientMetadataTools.java +++ b/src/main/java/com/gmail/nossr50/util/TransientMetadataTools.java @@ -2,16 +2,17 @@ package com.gmail.nossr50.util; import com.gmail.nossr50.mcMMO; import org.bukkit.entity.LivingEntity; +import org.jetbrains.annotations.NotNull; public class TransientMetadataTools { public static final String OLD_NAME_METAKEY = TransientMetadataTools.OLD_NAME_METAKEY; private final mcMMO pluginRef; - public TransientMetadataTools(mcMMO pluginRef) { + public TransientMetadataTools(@NotNull mcMMO pluginRef) { this.pluginRef = pluginRef; } - public void cleanAllMobMetadata(LivingEntity livingEntity) { + public void cleanAllLivingEntityMetadata(@NotNull LivingEntity livingEntity) { //Since its not written anywhere, apparently the GC won't touch objects with metadata still present on them if (livingEntity.hasMetadata(mcMMO.customNameKey)) { livingEntity.setCustomName(livingEntity.getMetadata(mcMMO.customNameKey).get(0).asString()); @@ -33,10 +34,13 @@ public class TransientMetadataTools { livingEntity.removeMetadata(mcMMO.travelingBlock, pluginRef); } - if(livingEntity.hasMetadata(mcMMO.REPLANT_META_KEY)) { - livingEntity.removeMetadata(mcMMO.REPLANT_META_KEY, pluginRef); + if(livingEntity.hasMetadata(mcMMO.RUPTURE_META_KEY)) { + livingEntity.removeMetadata(mcMMO.RUPTURE_META_KEY, pluginRef); } + if(livingEntity.hasMetadata(mcMMO.EXPLOSION_FROM_RUPTURE)) { + livingEntity.removeMetadata(mcMMO.EXPLOSION_FROM_RUPTURE, pluginRef); + } //Cleanup mob metadata mcMMO.getCompatibilityManager().getPersistentDataLayer().removeMobFlags(livingEntity); diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index f28f6762e..615ad89eb 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -12,6 +12,7 @@ import com.gmail.nossr50.events.fake.FakeEntityDamageByEntityEvent; import com.gmail.nossr50.events.fake.FakeEntityDamageEvent; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.party.PartyManager; +import com.gmail.nossr50.runnables.skills.AwardCombatXpTask; import com.gmail.nossr50.skills.acrobatics.AcrobaticsManager; import com.gmail.nossr50.skills.archery.ArcheryManager; import com.gmail.nossr50.skills.axes.AxesManager; @@ -40,7 +41,6 @@ import org.bukkit.potion.PotionEffectType; import org.bukkit.projectiles.ProjectileSource; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import com.gmail.nossr50.runnables.skills.AwardCombatXpTask; import java.util.EnumMap; import java.util.HashMap; @@ -93,8 +93,7 @@ public final class CombatUtils { mcMMOPlayer.checkAbilityActivation(PrimarySkillType.SWORDS); } - if(target.getHealth() - event.getFinalDamage() >= 1) - { + if(target.getHealth() - event.getFinalDamage() > 0) { if (swordsManager.canUseRupture()) { swordsManager.processRupture(target); } diff --git a/src/main/java/com/gmail/nossr50/util/skills/ParticleEffectUtils.java b/src/main/java/com/gmail/nossr50/util/skills/ParticleEffectUtils.java index 8d0f75937..f63b5dd83 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/ParticleEffectUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/ParticleEffectUtils.java @@ -1,19 +1,18 @@ package com.gmail.nossr50.util.skills; import com.gmail.nossr50.config.Config; -import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.sounds.SoundManager; import com.gmail.nossr50.util.sounds.SoundType; import org.apache.commons.lang.math.RandomUtils; -import org.bukkit.*; +import org.bukkit.Effect; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; -import java.util.ArrayList; -import java.util.Arrays; - public final class ParticleEffectUtils { private ParticleEffectUtils() {}