Fix some bugs with Rupture and fix a small memory leak

This commit is contained in:
nossr50 2021-04-02 20:31:19 -07:00
parent 002887e244
commit a2ee4be86a
13 changed files with 44 additions and 44 deletions

View File

@ -1,5 +1,7 @@
Version 2.1.186 Version 2.1.186
Rupture has been reworked to solve a few outstanding issues (see notes) 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 applies Rupture
Gore no longer sends a message to the Wolf owner when it triggers 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 Gore no longer sends a message to players that are hit by it
@ -27,7 +29,7 @@ Version 2.1.186
NOTES: NOTES:
The old Rupture would constantly interfere with your ability to do a Sweep Attack/Swipe with swords, the new one solves this problem 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. 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 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 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 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

View File

@ -2,7 +2,6 @@ package com.gmail.nossr50.commands.skills;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.datatypes.skills.SubSkillType; 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.listeners.InteractionManager;
import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.Permissions;

View File

@ -1,7 +1,6 @@
package com.gmail.nossr50.commands.skills; package com.gmail.nossr50.commands.skills;
import com.gmail.nossr50.config.AdvancedConfig; 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.PrimarySkillType;
import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.locale.LocaleLoader;
@ -56,7 +55,7 @@ public class SwordsCommand extends SkillCommand {
ruptureExplosionDamageAgainstPlayers = String.valueOf(AdvancedConfig.getInstance().getRuptureExplosionDamage(true, ruptureRank)); ruptureExplosionDamageAgainstPlayers = String.valueOf(AdvancedConfig.getInstance().getRuptureExplosionDamage(true, ruptureRank));
ruptureExplosionDamageAgainstMobs = String.valueOf(AdvancedConfig.getInstance().getRuptureExplosionDamage(false, 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); ruptureChanceToApplyLucky = String.valueOf(AdvancedConfig.getInstance().getRuptureChanceToApplyOnHit(ruptureRank) * 1.33);
} }

View File

@ -5,9 +5,6 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill;
import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.mcMMO;
import net.md_5.bungee.api.ChatColor; 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.ArrayList;
import java.util.List; import java.util.List;

View File

@ -489,6 +489,10 @@ public class EntityListener implements Listener {
if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld()))
return; return;
if(event.getEntity().hasMetadata(mcMMO.EXPLOSION_FROM_RUPTURE)) {
event.getEntity().removeMetadata(mcMMO.EXPLOSION_FROM_RUPTURE, mcMMO.p);
}
if(event.getEntity() instanceof Player) if(event.getEntity() instanceof Player)
{ {
Player player = (Player) event.getEntity(); Player player = (Player) event.getEntity();
@ -661,7 +665,7 @@ public class EntityListener implements Listener {
*/ */
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void onEntityDeathLowest(EntityDeathEvent event) { public void onEntityDeathLowest(EntityDeathEvent event) {
mcMMO.getTransientMetadataTools().cleanAllMobMetadata(event.getEntity()); mcMMO.getTransientMetadataTools().cleanAllLivingEntityMetadata(event.getEntity());
} }
/** /**

View File

@ -546,6 +546,7 @@ public class PlayerListener implements Listener {
//Use a sync save if the server is shutting down to avoid race conditions //Use a sync save if the server is shutting down to avoid race conditions
mcMMOPlayer.logout(mcMMO.isServerShutdownExecuted()); mcMMOPlayer.logout(mcMMO.isServerShutdownExecuted());
mcMMO.getTransientMetadataTools().cleanAllLivingEntityMetadata(event.getPlayer());
} }
/** /**

View File

@ -125,6 +125,7 @@ public class mcMMO extends JavaPlugin {
/* Metadata Values */ /* Metadata Values */
public static final String REPLANT_META_KEY = "mcMMO: Recently Replanted"; 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 RUPTURE_META_KEY = "mcMMO: RuptureTask";
public static final String FISH_HOOK_REF_METAKEY = "mcMMO: Fish Hook Tracker"; public static final String FISH_HOOK_REF_METAKEY = "mcMMO: Fish Hook Tracker";
public static final String DODGE_TRACKER = "mcMMO: Dodge Tracker"; public static final String DODGE_TRACKER = "mcMMO: Dodge Tracker";

View File

@ -8,6 +8,7 @@ import com.gmail.nossr50.util.skills.ParticleEffectUtils;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import org.bukkit.entity.LivingEntity; import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitRunnable;
import org.jetbrains.annotations.NotNull; 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) { public RuptureTask(@NotNull McMMOPlayer ruptureSource, @NotNull LivingEntity targetEntity, double pureTickDamage, double explosionDamage) {
this.ruptureSource = ruptureSource; this.ruptureSource = ruptureSource;
this.targetEntity = targetEntity; this.targetEntity = targetEntity;
this.expireTick = AdvancedConfig.getInstance().getRuptureDurationSeconds(targetEntity instanceof Player); this.expireTick = AdvancedConfig.getInstance().getRuptureDurationSeconds(targetEntity instanceof Player) * 20;
this.ruptureTick = 0; this.ruptureTick = 0;
this.damageTickTracker = 0; this.damageTickTracker = 0;
@ -44,12 +45,10 @@ public class RuptureTask extends BukkitRunnable {
//Rupture hasn't ended yet //Rupture hasn't ended yet
if(ruptureTick < expireTick) { if(ruptureTick < expireTick) {
//Is it time to damage? //Is it time to damage?
if(damageTickTracker >= DAMAGE_TICK_INTERVAL) { if(damageTickTracker >= DAMAGE_TICK_INTERVAL) {
damageTickTracker = 0; //Reset damageTickTracker = 0; //Reset
ParticleEffectUtils.playBleedEffect(targetEntity); //Animate ParticleEffectUtils.playBleedEffect(targetEntity); //Animate
double finalDamage = 0; //Used for mob health bars and setting last damage
if(targetEntity.getHealth() > 0.01) { if(targetEntity.getHealth() > 0.01) {
double healthBeforeRuptureIsApplied = targetEntity.getHealth(); double healthBeforeRuptureIsApplied = targetEntity.getHealth();
@ -59,22 +58,9 @@ public class RuptureTask extends BukkitRunnable {
mcMMO.p.getLogger().severe("DEBUG: Miscalculating Rupture tick damage"); mcMMO.p.getLogger().severe("DEBUG: Miscalculating Rupture tick damage");
} else { } else {
targetEntity.setHealth(damagedHealth); //Hurt entity without the unwanted side effects of damage() 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 { } else {
explode(); explode();
} }
@ -84,8 +70,15 @@ public class RuptureTask extends BukkitRunnable {
} }
} }
public void refreshRupture() {
damageTickTracker = DAMAGE_TICK_INTERVAL;
ruptureTick = 0;
}
public void explode() { 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()) { if(ruptureSource.getPlayer() != null && ruptureSource.getPlayer().isValid()) {
targetEntity.damage(getExplosionDamage(), ruptureSource.getPlayer()); targetEntity.damage(getExplosionDamage(), ruptureSource.getPlayer());
@ -94,6 +87,7 @@ public class RuptureTask extends BukkitRunnable {
} }
targetEntity.removeMetadata(mcMMO.RUPTURE_META_KEY, mcMMO.p); targetEntity.removeMetadata(mcMMO.RUPTURE_META_KEY, mcMMO.p);
this.cancel(); //Task no longer needed this.cancel(); //Task no longer needed
} }

View File

@ -63,19 +63,20 @@ public class SwordsManager extends SkillManager {
* *
* @param target The defending entity * @param target The defending entity
*/ */
public void processRupture(@NotNull LivingEntity target) throws IllegalStateException { public void processRupture(@NotNull LivingEntity target) {
if(target.hasMetadata(mcMMO.REPLANT_META_KEY)) { if(target.hasMetadata(mcMMO.RUPTURE_META_KEY)) {
RuptureTaskMeta ruptureTaskMeta = (RuptureTaskMeta) target.getMetadata(mcMMO.RUPTURE_META_KEY);
if(mmoPlayer.isDebugMode()) { if(mmoPlayer.isDebugMode()) {
mmoPlayer.getPlayer().sendMessage("Rupture task ongoing for target " + target.toString()); mmoPlayer.getPlayer().sendMessage("Rupture task ongoing for target " + target.toString());
RuptureTaskMeta ruptureTaskMeta = (RuptureTaskMeta) target.getMetadata(mcMMO.RUPTURE_META_KEY); mmoPlayer.getPlayer().sendMessage(ruptureTaskMeta.getRuptureTimerTask().toString());
RuptureTask ruptureTask = (RuptureTask) target.getMetadata(mcMMO.RUPTURE_META_KEY);
mmoPlayer.getPlayer().sendMessage(ruptureTask.toString());
} }
ruptureTaskMeta.getRuptureTimerTask().refreshRupture();
return; //Don't apply bleed 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) { if (target instanceof Player) {
Player defender = (Player) target; Player defender = (Player) target;

View File

@ -131,7 +131,7 @@ public final class MobHealthbarUtils {
return null; 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; int grayDisplay = fullDisplay - coloredDisplay;
StringBuilder healthbar = new StringBuilder(color + ""); StringBuilder healthbar = new StringBuilder(color + "");

View File

@ -2,16 +2,17 @@ package com.gmail.nossr50.util;
import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.mcMMO;
import org.bukkit.entity.LivingEntity; import org.bukkit.entity.LivingEntity;
import org.jetbrains.annotations.NotNull;
public class TransientMetadataTools { public class TransientMetadataTools {
public static final String OLD_NAME_METAKEY = TransientMetadataTools.OLD_NAME_METAKEY; public static final String OLD_NAME_METAKEY = TransientMetadataTools.OLD_NAME_METAKEY;
private final mcMMO pluginRef; private final mcMMO pluginRef;
public TransientMetadataTools(mcMMO pluginRef) { public TransientMetadataTools(@NotNull mcMMO pluginRef) {
this.pluginRef = 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 //Since its not written anywhere, apparently the GC won't touch objects with metadata still present on them
if (livingEntity.hasMetadata(mcMMO.customNameKey)) { if (livingEntity.hasMetadata(mcMMO.customNameKey)) {
livingEntity.setCustomName(livingEntity.getMetadata(mcMMO.customNameKey).get(0).asString()); livingEntity.setCustomName(livingEntity.getMetadata(mcMMO.customNameKey).get(0).asString());
@ -33,10 +34,13 @@ public class TransientMetadataTools {
livingEntity.removeMetadata(mcMMO.travelingBlock, pluginRef); livingEntity.removeMetadata(mcMMO.travelingBlock, pluginRef);
} }
if(livingEntity.hasMetadata(mcMMO.REPLANT_META_KEY)) { if(livingEntity.hasMetadata(mcMMO.RUPTURE_META_KEY)) {
livingEntity.removeMetadata(mcMMO.REPLANT_META_KEY, pluginRef); livingEntity.removeMetadata(mcMMO.RUPTURE_META_KEY, pluginRef);
} }
if(livingEntity.hasMetadata(mcMMO.EXPLOSION_FROM_RUPTURE)) {
livingEntity.removeMetadata(mcMMO.EXPLOSION_FROM_RUPTURE, pluginRef);
}
//Cleanup mob metadata //Cleanup mob metadata
mcMMO.getCompatibilityManager().getPersistentDataLayer().removeMobFlags(livingEntity); mcMMO.getCompatibilityManager().getPersistentDataLayer().removeMobFlags(livingEntity);

View File

@ -12,6 +12,7 @@ import com.gmail.nossr50.events.fake.FakeEntityDamageByEntityEvent;
import com.gmail.nossr50.events.fake.FakeEntityDamageEvent; import com.gmail.nossr50.events.fake.FakeEntityDamageEvent;
import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.party.PartyManager; 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.acrobatics.AcrobaticsManager;
import com.gmail.nossr50.skills.archery.ArcheryManager; import com.gmail.nossr50.skills.archery.ArcheryManager;
import com.gmail.nossr50.skills.axes.AxesManager; import com.gmail.nossr50.skills.axes.AxesManager;
@ -40,7 +41,6 @@ import org.bukkit.potion.PotionEffectType;
import org.bukkit.projectiles.ProjectileSource; import org.bukkit.projectiles.ProjectileSource;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.gmail.nossr50.runnables.skills.AwardCombatXpTask;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.HashMap; import java.util.HashMap;
@ -93,8 +93,7 @@ public final class CombatUtils {
mcMMOPlayer.checkAbilityActivation(PrimarySkillType.SWORDS); mcMMOPlayer.checkAbilityActivation(PrimarySkillType.SWORDS);
} }
if(target.getHealth() - event.getFinalDamage() >= 1) if(target.getHealth() - event.getFinalDamage() > 0) {
{
if (swordsManager.canUseRupture()) { if (swordsManager.canUseRupture()) {
swordsManager.processRupture(target); swordsManager.processRupture(target);
} }

View File

@ -1,19 +1,18 @@
package com.gmail.nossr50.util.skills; package com.gmail.nossr50.util.skills;
import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.Config;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.sounds.SoundManager; import com.gmail.nossr50.util.sounds.SoundManager;
import com.gmail.nossr50.util.sounds.SoundType; import com.gmail.nossr50.util.sounds.SoundType;
import org.apache.commons.lang.math.RandomUtils; 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.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.entity.LivingEntity; import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.Arrays;
public final class ParticleEffectUtils { public final class ParticleEffectUtils {
private ParticleEffectUtils() {} private ParticleEffectUtils() {}