diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java index 9a514e277..b9e6248a3 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java @@ -1,12 +1,10 @@ package com.gmail.nossr50.datatypes.player; import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; import java.util.Map; -import java.util.Map.Entry; import java.util.Set; import java.util.UUID; +import java.util.concurrent.DelayQueue; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.config.Config; @@ -36,8 +34,8 @@ public class PlayerProfile { private final Map skillsXp = new HashMap(); // Skill & XP private final Map abilityDATS = new HashMap(); // Ability & Cooldown - // Store previous XP gains for diminished returns - private HashMap> gainedSkillsXp = new HashMap>(); + // Store previous XP gains for deminished returns + private DelayQueue gainedSkillsXp = new DelayQueue(); private HashMap rollingSkillsXp = new HashMap(); @Deprecated @@ -304,15 +302,8 @@ public class PlayerProfile { * @param skillType Skill being used * @param xp Experience amount to add */ - public void registeredXpGain(SkillType skillType, float xp) { - LinkedList gains = gainedSkillsXp.get(skillType); - - if (gains == null) { - gains = new LinkedList(); // Maybe add an initial capacity? - } - gains.addLast(new SkillXpGain(System.currentTimeMillis(), xp)); - - gainedSkillsXp.put(skillType, gains); + public void registerXpGain(SkillType skillType, float xp) { + gainedSkillsXp.add(new SkillXpGain(skillType, xp)); rollingSkillsXp.put(skillType, getRegisteredXpGain(skillType) + xp); } @@ -322,28 +313,10 @@ public class PlayerProfile { * * @param age Age in milliseconds that gains older than should be removed */ - public void removeXpGainsOlderThan(long age) { - long now = System.currentTimeMillis(); - - Iterator>> iterator = gainedSkillsXp.entrySet().iterator(); - while (iterator.hasNext()) { - Entry> skillGains = iterator.next(); - - float xp = 0; - // Because we are using a LinkedList and addLast ordering is guaranteed, so we loop through and remove things that are too old, and stop immediately once we find a young'n - Iterator gainsIterator = skillGains.getValue().iterator(); - while (gainsIterator.hasNext()) { - SkillXpGain gain = gainsIterator.next(); - - if (now - gain.getTime() >= age) { - gainsIterator.remove(); - xp += gain.getXp(); - } - else { - break; - } - } - rollingSkillsXp.put(skillGains.getKey(), rollingSkillsXp.get(skillGains.getKey()) - xp); + public void purgeExpiredXpGains() { + SkillXpGain gain = null; + while ((gain = gainedSkillsXp.poll()) != null) { + rollingSkillsXp.put(gain.getSkill(), getRegisteredXpGain(gain.getSkill()) - gain.getXp()); } } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SkillXpGain.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SkillXpGain.java index 37bd51739..bedd40821 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SkillXpGain.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SkillXpGain.java @@ -1,19 +1,54 @@ package com.gmail.nossr50.datatypes.skills; -public class SkillXpGain { - private final long time; - private final float xp; +import java.util.concurrent.Delayed; +import java.util.concurrent.TimeUnit; - public SkillXpGain(long time, float xp) { - this.time = time; +import com.gmail.nossr50.config.experience.ExperienceConfig; + +public class SkillXpGain implements Delayed { + private final long expiryTime; + private final float xp; + private final SkillType type; + + public SkillXpGain(SkillType type, float xp) { + this.expiryTime = System.currentTimeMillis() + getDuration(); this.xp = xp; + this.type = type; } - public long getTime() { - return time; + public SkillType getSkill() { + return type; } public float getXp() { return xp; } + + private static long getDuration() { + return TimeUnit.MINUTES.toMillis(ExperienceConfig.getInstance().getDiminishedReturnsTimeInterval()); + } + + public int compareTo(SkillXpGain other) { + if (this.expiryTime < other.expiryTime) { + return -1; + } + else if (this.expiryTime > other.expiryTime) { + return 1; + } + return 0; + } + + @Override + public int compareTo(Delayed other) { + if (other instanceof SkillXpGain) { + // Use more efficient method if possible (private fields) + return this.compareTo((SkillXpGain) other); + } + return (int) (getDelay(TimeUnit.MILLISECONDS) - other.getDelay(TimeUnit.MILLISECONDS)); + } + + @Override + public long getDelay(TimeUnit arg0) { + return arg0.convert(expiryTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS); + } } diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index 2ab2ef28f..341979b1a 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -497,7 +497,7 @@ public class mcMMO extends JavaPlugin { // Clear the registered XP data so players can earn XP again if (ExperienceConfig.getInstance().getDiminishedReturnsThreshold() > 0) { - new ClearRegisteredXPGainTask().runTaskTimer(this, 60 * 20, 60 * 20); + new ClearRegisteredXPGainTask().runTaskTimer(this, 60, 60); } } diff --git a/src/main/java/com/gmail/nossr50/runnables/player/ClearRegisteredXPGainTask.java b/src/main/java/com/gmail/nossr50/runnables/player/ClearRegisteredXPGainTask.java index 7c2735f6c..834c72d88 100644 --- a/src/main/java/com/gmail/nossr50/runnables/player/ClearRegisteredXPGainTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/player/ClearRegisteredXPGainTask.java @@ -2,7 +2,6 @@ package com.gmail.nossr50.runnables.player; import org.bukkit.scheduler.BukkitRunnable; -import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.util.player.UserManager; @@ -10,7 +9,7 @@ public class ClearRegisteredXPGainTask extends BukkitRunnable { @Override public void run() { for (McMMOPlayer mcMMOPlayer : UserManager.getPlayers()) { - mcMMOPlayer.getProfile().removeXpGainsOlderThan(ExperienceConfig.getInstance().getDiminishedReturnsTimeInterval() * 60 * 1000); + mcMMOPlayer.getProfile().purgeExpiredXpGains(); } } } diff --git a/src/main/java/com/gmail/nossr50/util/EventUtils.java b/src/main/java/com/gmail/nossr50/util/EventUtils.java index 288ced48e..994ba0e89 100644 --- a/src/main/java/com/gmail/nossr50/util/EventUtils.java +++ b/src/main/java/com/gmail/nossr50/util/EventUtils.java @@ -161,7 +161,7 @@ public class EventUtils { if (!isCancelled) { UserManager.getPlayer(player).addXp(skill, event.getRawXpGained()); - UserManager.getPlayer(player).getProfile().registeredXpGain(skill, event.getRawXpGained()); + UserManager.getPlayer(player).getProfile().registerXpGain(skill, event.getRawXpGained()); } return !isCancelled;