Fixing Rupture (Bleed) ConcurrentModificationException

Removed the internal limit on ticks for Rupture
Rupture no longer adds new ticks when applying bleed to an existing target, it instead refreshes the duration
This commit is contained in:
nossr50 2019-01-25 11:12:31 -08:00
parent a421bd7e4c
commit c22a1a0dd2
4 changed files with 64 additions and 81 deletions

View File

@ -37,8 +37,10 @@ Version 2.1.0
+ (MySQL) Added support for SSL for MySQL/MariaDB (On by default)
! (Skills) Taming's Gore now uses Rupture Rank 1 for its DoT calculations
! (Skills) Sword's Bleed has been renamed to Rupture
! (Skills) Sword's Rupture no longer has an internal hard coded limit
! (Skills) Sword's Serrated Strikes now uses your Rupture rank to determine the damage/ticks for its bleed effect.
! (Skills) Sword's Rupture now ticks four times as fast
! (Skills) Sword's Rupture now refreshes bleed duration instead of adding duration when applying bleed to the same target
! (Skills) Sword's Rupture will now deal lethal damage
= (Skills) Fixed a bug where Rupture would apply an incorrect amount of bleed ticks
! (Skills) Sword's Rupture now reaches its max proc chance at level 20 (200 in Retro)

View File

@ -527,7 +527,6 @@ public class EntityListener implements Listener {
return;
}
BleedTimerTask.remove(entity);
Archery.arrowRetrievalCheck(entity);
}

View File

@ -0,0 +1,18 @@
package com.gmail.nossr50.runnables.skills;
import org.bukkit.entity.LivingEntity;
public class BleedContainer {
public int bleedTicks;
public int bleedRank;
public LivingEntity target;
public LivingEntity damageSource;
public BleedContainer(LivingEntity target, int bleedTicks, int bleedRank, LivingEntity damageSource)
{
this.target = target;
this.bleedTicks = bleedTicks;
this.bleedRank = bleedRank;
this.damageSource = damageSource;
}
}

View File

@ -1,8 +1,10 @@
package com.gmail.nossr50.runnables.skills;
import com.gmail.nossr50.config.AdvancedConfig;
import com.gmail.nossr50.datatypes.interactions.NotificationType;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.MobHealthbarUtils;
import com.gmail.nossr50.util.player.NotificationManager;
import com.gmail.nossr50.util.skills.CombatUtils;
import com.gmail.nossr50.util.skills.ParticleEffectUtils;
import com.gmail.nossr50.util.sounds.SoundManager;
@ -11,29 +13,26 @@ import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
public class BleedTimerTask extends BukkitRunnable {
private final static int MAX_BLEED_TICKS = 100; //The cap has been raised :)
private static Map<LivingEntity, Integer> bleedList = new HashMap<LivingEntity, Integer>();
private static Map<LivingEntity, Integer> bleedDamage = new HashMap<LivingEntity, Integer>();
private static Map<LivingEntity, LivingEntity> attackerMap = new HashMap<>();
private static ArrayList<LivingEntity> cleanupList = new ArrayList<>();
private static ArrayList<LivingEntity> lowerList = new ArrayList<>();
private static Map<LivingEntity, BleedContainer> bleedList = new HashMap<LivingEntity, BleedContainer>();
@Override
public void run() {
lowerBleedTicks(); //Lower bleed ticks
cleanEntities(); //Remove unwanted entities
synchronized public void run() {
Iterator<Entry<LivingEntity, BleedContainer>> bleedIterator = bleedList.entrySet().iterator();
for(LivingEntity target : bleedList.keySet())
{
//mcMMO.p.getServer().broadcastMessage("Entity "+target.getName()+" has "+bleedList.get(target)+" ticks of bleed left");
while (bleedIterator.hasNext()) {
Entry<LivingEntity, BleedContainer> containerEntry = bleedIterator.next();
LivingEntity target = containerEntry.getKey();
if (bleedList.get(target) <= 0 || !target.isValid()) {
cleanupList.add(target);
int bleedTicks = containerEntry.getValue().bleedTicks;
if (containerEntry.getValue().bleedTicks <= 0 || !target.isValid()) {
bleedIterator.remove();
continue;
}
@ -43,59 +42,49 @@ public class BleedTimerTask extends BukkitRunnable {
damage = AdvancedConfig.getInstance().getRuptureDamagePlayer();
//Above Bleed Rank 3 deals 50% more damage
if(bleedDamage.get(target) >= 3)
if (containerEntry.getValue().bleedRank >= 3)
damage = damage * 1.5;
Player player = (Player) target;
if (!player.isOnline()) {
cleanupList.add(target);
continue;
}
/*if (bleedList.get(target) <= 0) {
NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Swords.Combat.Bleeding.Stopped");
}*/
}
else {
NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Swords.Combat.Bleeding.Stopped");
} else {
damage = AdvancedConfig.getInstance().getRuptureDamageMobs();
//Above Bleed Rank 3 deals 50% more damage
if (containerEntry.getValue().bleedRank >= 3)
damage = damage * 1.5;
MobHealthbarUtils.handleMobHealthbars(target, damage, mcMMO.p); //Update health bars
}
CombatUtils.dealNoInvulnerabilityTickDamage(target, damage, attackerMap.get(target));
CombatUtils.dealNoInvulnerabilityTickDamage(target, damage, containerEntry.getValue().damageSource);
//Play Bleed Sound
SoundManager.worldSendSound(target.getWorld(), target.getLocation(), SoundType.BLEED);
ParticleEffectUtils.playBleedEffect(target);
lowerBleedDurationTicks(target);
//Lower Bleed Ticks
BleedContainer loweredBleedContainer = copyContainer(containerEntry.getValue());
loweredBleedContainer.bleedTicks -= 1;
containerEntry.setValue(loweredBleedContainer);
}
}
private void lowerBleedTicks() {
for(LivingEntity lower : lowerList)
{
if(bleedList.containsKey(lower))
bleedList.put(lower, bleedList.get(lower) - 1);
}
public static BleedContainer copyContainer(BleedContainer container)
{
LivingEntity target = container.target;
LivingEntity source = container.damageSource;
int bleedTicks = container.bleedTicks;
int bleedRank = container.bleedRank;
lowerList.clear();
}
private void cleanEntities() {
for(LivingEntity cleanTarget : cleanupList)
{
if(bleedList.containsKey(cleanTarget))
{
remove(cleanTarget);
}
}
cleanupList.clear(); //Reset List
}
private void lowerBleedDurationTicks(LivingEntity target) {
if(bleedList.get(target) != null)
lowerList.add(target);
BleedContainer newContainer = new BleedContainer(target, bleedTicks, bleedRank, source);
return newContainer;
}
/**
@ -104,24 +93,12 @@ public class BleedTimerTask extends BukkitRunnable {
* @param entity LivingEntity to bleed out
*/
public static void bleedOut(LivingEntity entity) {
if (bleedList.containsKey(entity)) {
CombatUtils.dealNoInvulnerabilityTickDamage(entity, bleedList.get(entity) * 2, attackerMap.get(entity));
bleedList.remove(entity);
bleedDamage.remove(entity);
attackerMap.remove(entity);
}
}
/*
* Don't remove anything from the list outside of run()
*/
/**
* Remove a LivingEntity from the bleedList if it is in it
*
* @param entity LivingEntity to remove
*/
public static void remove(LivingEntity entity) {
if (bleedList.containsKey(entity)) {
bleedList.remove(entity);
bleedDamage.remove(entity);
attackerMap.remove(entity);
CombatUtils.dealNoInvulnerabilityTickDamage(entity, bleedList.get(entity).bleedTicks * 2, bleedList.get(entity).damageSource);
}
}
@ -131,22 +108,9 @@ public class BleedTimerTask extends BukkitRunnable {
* @param entity LivingEntity to add
* @param ticks Number of bleeding ticks
*/
public static void add(LivingEntity entity, LivingEntity attacker, int ticks, int bleedRank) {
int newTicks = ticks;
if (bleedList.containsKey(entity)) {
newTicks += bleedList.get(entity);
bleedList.put(entity, Math.min(MAX_BLEED_TICKS, newTicks));
//Override the current bleed rank only if this one is higher
if(bleedDamage.get(entity) < bleedRank)
bleedDamage.put(entity, bleedRank);
}
else {
bleedList.put(entity, Math.min(MAX_BLEED_TICKS, newTicks));
bleedDamage.put(entity, bleedRank);
attackerMap.put(entity, attacker);
}
public synchronized static void add(LivingEntity entity, LivingEntity attacker, int ticks, int bleedRank) {
BleedContainer newBleedContainer = new BleedContainer(entity, ticks, bleedRank, attacker);
bleedList.put(entity, newBleedContainer);
}
public static boolean isBleeding(LivingEntity entity) {