Use a DelayQueue to manage rolling diminished returns

This commit is contained in:
riking 2013-10-26 22:44:03 -07:00 committed by TfT_02
parent 2a443cd9db
commit 332860b9ce
5 changed files with 54 additions and 47 deletions

View File

@ -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<SkillType, Float> skillsXp = new HashMap<SkillType, Float>(); // Skill & XP
private final Map<AbilityType, Integer> abilityDATS = new HashMap<AbilityType, Integer>(); // Ability & Cooldown
// Store previous XP gains for diminished returns
private HashMap<SkillType, LinkedList<SkillXpGain>> gainedSkillsXp = new HashMap<SkillType, LinkedList<SkillXpGain>>();
// Store previous XP gains for deminished returns
private DelayQueue<SkillXpGain> gainedSkillsXp = new DelayQueue<SkillXpGain>();
private HashMap<SkillType, Float> rollingSkillsXp = new HashMap<SkillType, Float>();
@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<SkillXpGain> gains = gainedSkillsXp.get(skillType);
if (gains == null) {
gains = new LinkedList<SkillXpGain>(); // 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<Entry<SkillType, LinkedList<SkillXpGain>>> iterator = gainedSkillsXp.entrySet().iterator();
while (iterator.hasNext()) {
Entry<SkillType, LinkedList<SkillXpGain>> 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<SkillXpGain> 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());
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}
}

View File

@ -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;