Add support for player experience goals to tracker
- Add new fields for start and end goal XP to xp tracker state - Use Varps for determining start and end goal Closes: #1168 Signed-off-by: Tomas Slusny <slusnucky@gmail.com>
This commit is contained in:
@@ -186,15 +186,15 @@ class XpInfoBox extends JPanel
|
|||||||
// Update progress bar
|
// Update progress bar
|
||||||
progressBar.setValue(xpSnapshotSingle.getSkillProgressToGoal());
|
progressBar.setValue(xpSnapshotSingle.getSkillProgressToGoal());
|
||||||
progressBar.setCenterLabel(xpSnapshotSingle.getSkillProgressToGoal() + "%");
|
progressBar.setCenterLabel(xpSnapshotSingle.getSkillProgressToGoal() + "%");
|
||||||
progressBar.setLeftLabel("Lvl. " + xpSnapshotSingle.getCurrentLevel());
|
progressBar.setLeftLabel("Lvl. " + xpSnapshotSingle.getStartLevel());
|
||||||
progressBar.setRightLabel("Lvl. " + (xpSnapshotSingle.getCurrentLevel() + 1));
|
progressBar.setRightLabel("Lvl. " + (xpSnapshotSingle.getEndLevel()));
|
||||||
|
|
||||||
progressBar.setToolTipText("<html>"
|
progressBar.setToolTipText("<html>"
|
||||||
+ xpSnapshotSingle.getActionsInSession() + " actions done"
|
+ xpSnapshotSingle.getActionsInSession() + " actions done"
|
||||||
+ "<br/>"
|
+ "<br/>"
|
||||||
+ xpSnapshotSingle.getActionsPerHour() + " actions/hr"
|
+ xpSnapshotSingle.getActionsPerHour() + " actions/hr"
|
||||||
+ "<br/>"
|
+ "<br/>"
|
||||||
+ xpSnapshotSingle.getTimeTillGoal() + " till next lvl"
|
+ xpSnapshotSingle.getTimeTillGoal() + " till goal lvl"
|
||||||
+ "</html>");
|
+ "</html>");
|
||||||
|
|
||||||
progressBar.repaint();
|
progressBar.repaint();
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ import lombok.Value;
|
|||||||
@Value
|
@Value
|
||||||
class XpSnapshotSingle
|
class XpSnapshotSingle
|
||||||
{
|
{
|
||||||
private int currentLevel;
|
private int startLevel;
|
||||||
|
private int endLevel;
|
||||||
private int xpGainedInSession;
|
private int xpGainedInSession;
|
||||||
private int xpRemainingToGoal;
|
private int xpRemainingToGoal;
|
||||||
private int xpPerHour;
|
private int xpPerHour;
|
||||||
|
|||||||
@@ -82,9 +82,11 @@ class XpState
|
|||||||
* and also first-login when the skills are not initialized (the start XP will be -1 in this case).
|
* and also first-login when the skills are not initialized (the start XP will be -1 in this case).
|
||||||
* @param skill Skill to update
|
* @param skill Skill to update
|
||||||
* @param currentXp Current known XP for this skill
|
* @param currentXp Current known XP for this skill
|
||||||
|
* @param goalStartXp Possible XP start goal
|
||||||
|
* @param goalEndXp Possible XP end goal
|
||||||
* @return Whether or not the skill has been initialized, there was no change, or it has been updated
|
* @return Whether or not the skill has been initialized, there was no change, or it has been updated
|
||||||
*/
|
*/
|
||||||
XpUpdateResult updateSkill(Skill skill, int currentXp)
|
XpUpdateResult updateSkill(Skill skill, int currentXp, int goalStartXp, int goalEndXp)
|
||||||
{
|
{
|
||||||
XpStateSingle state = getSkill(skill);
|
XpStateSingle state = getSkill(skill);
|
||||||
|
|
||||||
@@ -113,7 +115,7 @@ class XpState
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return state.update(currentXp) ? XpUpdateResult.UPDATED : XpUpdateResult.NO_CHANGE;
|
return state.update(currentXp, goalStartXp, goalEndXp) ? XpUpdateResult.UPDATED : XpUpdateResult.NO_CHANGE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,30 +27,35 @@ package net.runelite.client.plugins.xptracker;
|
|||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import lombok.Data;
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.runelite.api.Experience;
|
import net.runelite.api.Experience;
|
||||||
import net.runelite.api.Skill;
|
import net.runelite.api.Skill;
|
||||||
|
|
||||||
@Data
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
class XpStateSingle
|
class XpStateSingle
|
||||||
{
|
{
|
||||||
private final Skill skill;
|
private final Skill skill;
|
||||||
|
|
||||||
|
@Getter
|
||||||
private final int startXp;
|
private final int startXp;
|
||||||
private Instant skillTimeStart = null;
|
|
||||||
|
@Getter
|
||||||
private int xpGained = 0;
|
private int xpGained = 0;
|
||||||
|
|
||||||
|
private Instant skillTimeStart = null;
|
||||||
private int actions = 0;
|
private int actions = 0;
|
||||||
private int nextLevelExp = 0;
|
|
||||||
private int startLevelExp = 0;
|
private int startLevelExp = 0;
|
||||||
private int level = 0;
|
private int endLevelExp = 0;
|
||||||
private boolean actionsHistoryInitialized = false;
|
private boolean actionsHistoryInitialized = false;
|
||||||
private int[] actionExps = new int[10];
|
private int[] actionExps = new int[10];
|
||||||
private int actionExpIndex = 0;
|
private int actionExpIndex = 0;
|
||||||
|
|
||||||
int getXpHr()
|
private int getCurrentXp()
|
||||||
{
|
{
|
||||||
return toHourly(xpGained);
|
return startXp + xpGained;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getActionsHr()
|
private int getActionsHr()
|
||||||
@@ -84,7 +89,7 @@ class XpStateSingle
|
|||||||
|
|
||||||
private int getXpRemaining()
|
private int getXpRemaining()
|
||||||
{
|
{
|
||||||
return nextLevelExp - (startXp + xpGained);
|
return endLevelExp - getCurrentXp();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getActionsRemaining()
|
private int getActionsRemaining()
|
||||||
@@ -92,19 +97,19 @@ class XpStateSingle
|
|||||||
if (actionsHistoryInitialized)
|
if (actionsHistoryInitialized)
|
||||||
{
|
{
|
||||||
long xpRemaining = getXpRemaining() * actionExps.length;
|
long xpRemaining = getXpRemaining() * actionExps.length;
|
||||||
long actionExp = 0;
|
long totalActionXp = 0;
|
||||||
|
|
||||||
for (int i = 0; i < actionExps.length; i++)
|
for (int actionXp : actionExps)
|
||||||
{
|
{
|
||||||
actionExp += actionExps[i];
|
totalActionXp += actionXp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let's not divide by zero (or negative)
|
// Let's not divide by zero (or negative)
|
||||||
if (actionExp > 0)
|
if (totalActionXp > 0)
|
||||||
{
|
{
|
||||||
// Make sure to account for the very last action at the end
|
// Make sure to account for the very last action at the end
|
||||||
long remainder = xpRemaining % actionExp;
|
long remainder = xpRemaining % totalActionXp;
|
||||||
long quotient = xpRemaining / actionExp;
|
long quotient = xpRemaining / totalActionXp;
|
||||||
return Math.toIntExact(quotient + (remainder > 0 ? 1 : 0));
|
return Math.toIntExact(quotient + (remainder > 0 ? 1 : 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,10 +119,8 @@ class XpStateSingle
|
|||||||
|
|
||||||
private int getSkillProgress()
|
private int getSkillProgress()
|
||||||
{
|
{
|
||||||
int currentXp = startXp + xpGained;
|
double xpGained = getCurrentXp() - startLevelExp;
|
||||||
|
double xpGoal = endLevelExp - startLevelExp;
|
||||||
double xpGained = currentXp - startLevelExp;
|
|
||||||
double xpGoal = nextLevelExp - startLevelExp;
|
|
||||||
return (int) ((xpGained / xpGoal) * 100);
|
return (int) ((xpGained / xpGoal) * 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +166,12 @@ class XpStateSingle
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
boolean update(int currentXp)
|
int getXpHr()
|
||||||
|
{
|
||||||
|
return toHourly(xpGained);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean update(int currentXp, int goalStartXp, int goalEndXp)
|
||||||
{
|
{
|
||||||
if (startXp == -1)
|
if (startXp == -1)
|
||||||
{
|
{
|
||||||
@@ -174,6 +182,7 @@ class XpStateSingle
|
|||||||
int originalXp = xpGained + startXp;
|
int originalXp = xpGained + startXp;
|
||||||
int actionExp = currentXp - originalXp;
|
int actionExp = currentXp - originalXp;
|
||||||
|
|
||||||
|
// No experience gained
|
||||||
if (actionExp == 0)
|
if (actionExp == 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -195,17 +204,32 @@ class XpStateSingle
|
|||||||
}
|
}
|
||||||
|
|
||||||
actionExpIndex = (actionExpIndex + 1) % actionExps.length;
|
actionExpIndex = (actionExpIndex + 1) % actionExps.length;
|
||||||
|
|
||||||
actions++;
|
actions++;
|
||||||
|
|
||||||
|
// Calculate experience gained
|
||||||
xpGained = currentXp - startXp;
|
xpGained = currentXp - startXp;
|
||||||
startLevelExp = Experience.getXpForLevel(Experience.getLevelForXp(currentXp));
|
|
||||||
|
|
||||||
int currentLevel = Experience.getLevelForXp(currentXp);
|
// Determine XP goals
|
||||||
|
if (goalStartXp <= 0)
|
||||||
|
{
|
||||||
|
startLevelExp = Experience.getXpForLevel(Experience.getLevelForXp(currentXp));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
startLevelExp = goalStartXp;
|
||||||
|
}
|
||||||
|
|
||||||
level = currentLevel;
|
if (goalEndXp <= 0 || currentXp > goalEndXp)
|
||||||
|
{
|
||||||
nextLevelExp = currentLevel + 1 <= Experience.MAX_VIRT_LEVEL ? Experience.getXpForLevel(currentLevel + 1) : -1;
|
int currentLevel = Experience.getLevelForXp(currentXp);
|
||||||
|
endLevelExp = currentLevel + 1 <= Experience.MAX_VIRT_LEVEL ? Experience.getXpForLevel(currentLevel + 1) : -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
endLevelExp = goalEndXp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is first time we are updating, we just started tracking
|
||||||
if (skillTimeStart == null)
|
if (skillTimeStart == null)
|
||||||
{
|
{
|
||||||
skillTimeStart = Instant.now();
|
skillTimeStart = Instant.now();
|
||||||
@@ -217,12 +241,13 @@ class XpStateSingle
|
|||||||
XpSnapshotSingle snapshot()
|
XpSnapshotSingle snapshot()
|
||||||
{
|
{
|
||||||
return XpSnapshotSingle.builder()
|
return XpSnapshotSingle.builder()
|
||||||
.currentLevel(getLevel())
|
.startLevel(Experience.getLevelForXp(startLevelExp))
|
||||||
.xpGainedInSession(getXpGained())
|
.endLevel(Experience.getLevelForXp(endLevelExp))
|
||||||
|
.xpGainedInSession(xpGained)
|
||||||
.xpRemainingToGoal(getXpRemaining())
|
.xpRemainingToGoal(getXpRemaining())
|
||||||
.xpPerHour(getXpHr())
|
.xpPerHour(getXpHr())
|
||||||
.skillProgressToGoal(getSkillProgress())
|
.skillProgressToGoal(getSkillProgress())
|
||||||
.actionsInSession(getActions())
|
.actionsInSession(actions)
|
||||||
.actionsRemainingToGoal(getActionsRemaining())
|
.actionsRemainingToGoal(getActionsRemaining())
|
||||||
.actionsPerHour(getActionsHr())
|
.actionsPerHour(getActionsHr())
|
||||||
.timeTillGoal(getTimeTillLevel())
|
.timeTillGoal(getTimeTillLevel())
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import net.runelite.api.Client;
|
|||||||
import net.runelite.api.GameState;
|
import net.runelite.api.GameState;
|
||||||
import net.runelite.api.Player;
|
import net.runelite.api.Player;
|
||||||
import net.runelite.api.Skill;
|
import net.runelite.api.Skill;
|
||||||
|
import net.runelite.api.VarPlayer;
|
||||||
import net.runelite.api.events.ExperienceChanged;
|
import net.runelite.api.events.ExperienceChanged;
|
||||||
import net.runelite.api.events.GameStateChanged;
|
import net.runelite.api.events.GameStateChanged;
|
||||||
import net.runelite.api.events.GameTick;
|
import net.runelite.api.events.GameTick;
|
||||||
@@ -259,12 +260,15 @@ public class XpTrackerPlugin extends Plugin
|
|||||||
public void onXpChanged(ExperienceChanged event)
|
public void onXpChanged(ExperienceChanged event)
|
||||||
{
|
{
|
||||||
final Skill skill = event.getSkill();
|
final Skill skill = event.getSkill();
|
||||||
int currentXp = client.getSkillExperience(skill);
|
final int currentXp = client.getSkillExperience(skill);
|
||||||
|
final VarPlayer startGoal = startGoalVarpForSkill(skill);
|
||||||
|
final VarPlayer endGoal = endGoalVarpForSkill(skill);
|
||||||
|
final int startGoalXp = startGoal != null ? client.getVar(startGoal) : -1;
|
||||||
|
final int endGoalXp = endGoal != null ? client.getVar(endGoal) : -1;
|
||||||
|
|
||||||
XpUpdateResult updateResult = xpState.updateSkill(skill, currentXp);
|
final XpUpdateResult updateResult = xpState.updateSkill(skill, currentXp, startGoalXp, endGoalXp);
|
||||||
|
|
||||||
boolean updated = XpUpdateResult.UPDATED.equals(updateResult);
|
|
||||||
|
|
||||||
|
final boolean updated = XpUpdateResult.UPDATED.equals(updateResult);
|
||||||
xpPanel.updateSkillExperience(updated, skill, xpState.getSkillSnapshot(skill));
|
xpPanel.updateSkillExperience(updated, skill, xpState.getSkillSnapshot(skill));
|
||||||
xpState.recalculateTotal();
|
xpState.recalculateTotal();
|
||||||
xpPanel.updateTotal(xpState.getTotalSnapshot());
|
xpPanel.updateTotal(xpState.getTotalSnapshot());
|
||||||
@@ -287,4 +291,114 @@ public class XpTrackerPlugin extends Plugin
|
|||||||
{
|
{
|
||||||
return xpState.getSkillSnapshot(skill);
|
return xpState.getSkillSnapshot(skill);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static VarPlayer startGoalVarpForSkill(final Skill skill)
|
||||||
|
{
|
||||||
|
switch (skill)
|
||||||
|
{
|
||||||
|
case ATTACK:
|
||||||
|
return VarPlayer.ATTACK_GOAL_START;
|
||||||
|
case MINING:
|
||||||
|
return VarPlayer.MINING_GOAL_START;
|
||||||
|
case WOODCUTTING:
|
||||||
|
return VarPlayer.WOODCUTTING_GOAL_START;
|
||||||
|
case DEFENCE:
|
||||||
|
return VarPlayer.DEFENCE_GOAL_START;
|
||||||
|
case MAGIC:
|
||||||
|
return VarPlayer.MAGIC_GOAL_START;
|
||||||
|
case RANGED:
|
||||||
|
return VarPlayer.RANGED_GOAL_START;
|
||||||
|
case HITPOINTS:
|
||||||
|
return VarPlayer.HITPOINTS_GOAL_START;
|
||||||
|
case AGILITY:
|
||||||
|
return VarPlayer.AGILITY_GOAL_START;
|
||||||
|
case STRENGTH:
|
||||||
|
return VarPlayer.STRENGTH_GOAL_START;
|
||||||
|
case PRAYER:
|
||||||
|
return VarPlayer.PRAYER_GOAL_START;
|
||||||
|
case SLAYER:
|
||||||
|
return VarPlayer.SLAYER_GOAL_START;
|
||||||
|
case FISHING:
|
||||||
|
return VarPlayer.FISHING_GOAL_START;
|
||||||
|
case RUNECRAFT:
|
||||||
|
return VarPlayer.RUNECRAFT_GOAL_START;
|
||||||
|
case HERBLORE:
|
||||||
|
return VarPlayer.HERBLORE_GOAL_START;
|
||||||
|
case FIREMAKING:
|
||||||
|
return VarPlayer.FIREMAKING_GOAL_START;
|
||||||
|
case CONSTRUCTION:
|
||||||
|
return VarPlayer.CONSTRUCTION_GOAL_START;
|
||||||
|
case HUNTER:
|
||||||
|
return VarPlayer.HUNTER_GOAL_START;
|
||||||
|
case COOKING:
|
||||||
|
return VarPlayer.COOKING_GOAL_START;
|
||||||
|
case FARMING:
|
||||||
|
return VarPlayer.FARMING_GOAL_START;
|
||||||
|
case CRAFTING:
|
||||||
|
return VarPlayer.CRAFTING_GOAL_START;
|
||||||
|
case SMITHING:
|
||||||
|
return VarPlayer.SMITHING_GOAL_START;
|
||||||
|
case THIEVING:
|
||||||
|
return VarPlayer.THIEVING_GOAL_START;
|
||||||
|
case FLETCHING:
|
||||||
|
return VarPlayer.FLETCHING_GOAL_START;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static VarPlayer endGoalVarpForSkill(final Skill skill)
|
||||||
|
{
|
||||||
|
switch (skill)
|
||||||
|
{
|
||||||
|
case ATTACK:
|
||||||
|
return VarPlayer.ATTACK_GOAL_END;
|
||||||
|
case MINING:
|
||||||
|
return VarPlayer.MINING_GOAL_END;
|
||||||
|
case WOODCUTTING:
|
||||||
|
return VarPlayer.WOODCUTTING_GOAL_END;
|
||||||
|
case DEFENCE:
|
||||||
|
return VarPlayer.DEFENCE_GOAL_END;
|
||||||
|
case MAGIC:
|
||||||
|
return VarPlayer.MAGIC_GOAL_END;
|
||||||
|
case RANGED:
|
||||||
|
return VarPlayer.RANGED_GOAL_END;
|
||||||
|
case HITPOINTS:
|
||||||
|
return VarPlayer.HITPOINTS_GOAL_END;
|
||||||
|
case AGILITY:
|
||||||
|
return VarPlayer.AGILITY_GOAL_END;
|
||||||
|
case STRENGTH:
|
||||||
|
return VarPlayer.STRENGTH_GOAL_END;
|
||||||
|
case PRAYER:
|
||||||
|
return VarPlayer.PRAYER_GOAL_END;
|
||||||
|
case SLAYER:
|
||||||
|
return VarPlayer.SLAYER_GOAL_END;
|
||||||
|
case FISHING:
|
||||||
|
return VarPlayer.FISHING_GOAL_END;
|
||||||
|
case RUNECRAFT:
|
||||||
|
return VarPlayer.RUNECRAFT_GOAL_END;
|
||||||
|
case HERBLORE:
|
||||||
|
return VarPlayer.HERBLORE_GOAL_END;
|
||||||
|
case FIREMAKING:
|
||||||
|
return VarPlayer.FIREMAKING_GOAL_END;
|
||||||
|
case CONSTRUCTION:
|
||||||
|
return VarPlayer.CONSTRUCTION_GOAL_END;
|
||||||
|
case HUNTER:
|
||||||
|
return VarPlayer.HUNTER_GOAL_END;
|
||||||
|
case COOKING:
|
||||||
|
return VarPlayer.COOKING_GOAL_END;
|
||||||
|
case FARMING:
|
||||||
|
return VarPlayer.FARMING_GOAL_END;
|
||||||
|
case CRAFTING:
|
||||||
|
return VarPlayer.CRAFTING_GOAL_END;
|
||||||
|
case SMITHING:
|
||||||
|
return VarPlayer.SMITHING_GOAL_END;
|
||||||
|
case THIEVING:
|
||||||
|
return VarPlayer.THIEVING_GOAL_END;
|
||||||
|
case FLETCHING:
|
||||||
|
return VarPlayer.FLETCHING_GOAL_END;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user