diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpAction.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpAction.java index 4831c47cbf..861b414a7e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpAction.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpAction.java @@ -30,6 +30,7 @@ import lombok.Data; class XpAction { private int actions = 0; + private int actionsSinceReset = 0; private boolean actionsHistoryInitialized = false; private int[] actionExps = new int[10]; private int actionExpIndex = 0; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBox.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBox.java index 343765bb79..e188a1df57 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBox.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBox.java @@ -135,6 +135,10 @@ class XpInfoBox extends JPanel final JMenuItem resetOthers = new JMenuItem("Reset others"); resetOthers.addActionListener(e -> xpTrackerPlugin.resetOtherSkillState(skill)); + // Create reset per hour menu + final JMenuItem resetPerHour = new JMenuItem("Reset/hr"); + resetPerHour.addActionListener(e -> xpTrackerPlugin.resetSkillPerHourState(skill)); + // Create reset others menu pauseSkill.addActionListener(e -> xpTrackerPlugin.pauseSkill(skill, !paused)); @@ -144,6 +148,7 @@ class XpInfoBox extends JPanel popupMenu.add(openXpTracker); popupMenu.add(reset); popupMenu.add(resetOthers); + popupMenu.add(resetPerHour); popupMenu.add(pauseSkill); popupMenu.add(canvasItem); popupMenu.addPopupMenuListener(new PopupMenuListener() diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpPanel.java index aa7af98aed..b346f2733d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpPanel.java @@ -90,6 +90,10 @@ class XpPanel extends PluginPanel final JMenuItem reset = new JMenuItem("Reset All"); reset.addActionListener(e -> xpTrackerPlugin.resetAndInitState()); + // Create reset all per hour menu + final JMenuItem resetPerHour = new JMenuItem("Reset All/hr"); + resetPerHour.addActionListener(e -> xpTrackerPlugin.resetAllSkillsPerHourState()); + // Create pause all menu final JMenuItem pauseAll = new JMenuItem("Pause All"); pauseAll.addActionListener(e -> xpTrackerPlugin.pauseAllSkills(true)); @@ -104,6 +108,7 @@ class XpPanel extends PluginPanel popupMenu.setBorder(new EmptyBorder(5, 5, 5, 5)); popupMenu.add(openXpTracker); popupMenu.add(reset); + popupMenu.add(resetPerHour); popupMenu.add(pauseAll); popupMenu.add(unpauseAll); overallPanel.setComponentPopupMenu(popupMenu); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpState.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpState.java index 1fbbdb2c49..aefae895d8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpState.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpState.java @@ -32,7 +32,7 @@ import net.runelite.api.Skill; /** * Internal state for the XpTrackerPlugin - * + *

* Note: This class's operations are not currently synchronized. * It is intended to be called by the XpTrackerPlugin on the client thread. */ @@ -53,7 +53,8 @@ class XpState /** * Resets a single skill - * @param skill Skill to reset + * + * @param skill Skill to reset * @param currentXp Current XP to set to, if unknown set to -1 */ void resetSkill(Skill skill, long currentXp) @@ -62,15 +63,26 @@ class XpState xpSkills.put(skill, new XpStateSingle(skill, currentXp)); } + /** + * Resets the per hour rates of a single skill + * + * @param skill Skill to reset per hour rates + */ + void resetSkillPerHour(Skill skill) + { + xpSkills.get(skill).resetPerHour(); + } + /** * Updates a skill with the current known XP. * When the result of this operation is XpUpdateResult.UPDATED, the UI should be updated accordingly. * This is to distinguish events that reload all the skill's current values (such as world hopping) * 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 currentXp Current known XP for this skill + * + * @param skill Skill to update + * @param currentXp Current known XP for this skill * @param goalStartXp Possible XP start goal - * @param goalEndXp Possible XP end 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 */ XpUpdateResult updateSkill(Skill skill, long currentXp, int goalStartXp, int goalEndXp) @@ -92,7 +104,7 @@ class XpState else { long startXp = state.getStartXp(); - int gainedXp = state.getXpGained(); + int gainedXp = state.getTotalXpGained(); if (startXp + gainedXp > currentXp) { @@ -119,8 +131,9 @@ class XpState /** * Updates skill with average actions based on currently interacted NPC. - * @param skill experience gained skill - * @param npc currently interacted NPC + * + * @param skill experience gained skill + * @param npc currently interacted NPC * @param npcHealth health of currently interacted NPC */ void updateNpcExperience(Skill skill, NPC npc, Integer npcHealth, int xpModifier) @@ -161,8 +174,9 @@ class XpState /** * Update number of actions performed for skill if last interacted NPC died. * (eg. amount of kills in this case) - * @param skill skill to update actions for - * @param npc npc that just died + * + * @param skill skill to update actions for + * @param npc npc that just died * @param npcHealth max health of npc that just died * @return UPDATED in case new kill was successfully added */ @@ -170,13 +184,13 @@ class XpState { XpStateSingle state = getSkill(skill); - if (state.getXpGained() <= 0 || npcHealth == null || npc != interactedNPC) + if (state.getXpGainedSinceReset() <= 0 || npcHealth == null || npc != interactedNPC) { return XpUpdateResult.NO_CHANGE; } final XpAction xpAction = state.getXpAction(XpActionType.ACTOR_HEALTH); - xpAction.setActions(xpAction.getActions() + 1); + xpAction.setActionsSinceReset(xpAction.getActionsSinceReset() + 1); return xpAction.isActionsHistoryInitialized() ? XpUpdateResult.UPDATED : XpUpdateResult.NO_CHANGE; } @@ -188,7 +202,8 @@ class XpState /** * Forcefully initialize a skill with a known start XP from the current XP. * This is used in resetAndInitState by the plugin. It should not result in showing the XP in the UI. - * @param skill Skill to initialize + * + * @param skill Skill to initialize * @param currentXp Current known XP for the skill */ void initializeSkill(Skill skill, long currentXp) @@ -211,6 +226,7 @@ class XpState /** * Obtain an immutable snapshot of the provided skill * intended for use with the UI which operates on another thread + * * @param skill Skill to obtain the snapshot for * @return An immutable snapshot of the specified skill for this session since first login or last reset */ @@ -223,6 +239,7 @@ class XpState /** * Obtain an immutable snapshot of the provided skill * intended for use with the UI which operates on another thread + * * @return An immutable snapshot of total information for this session since first login or last reset */ @NonNull diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpStateSingle.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpStateSingle.java index e10684e322..ff2308998e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpStateSingle.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpStateSingle.java @@ -45,12 +45,16 @@ class XpStateSingle private long startXp; @Getter - private int xpGained = 0; + private int xpGainedSinceReset = 0; + + private int xpGainedBeforeReset = 0; @Setter private XpActionType actionType = XpActionType.EXPERIENCE; + @Setter private long skillTime = 0; + private int startLevelExp = 0; private int endLevelExp = 0; @@ -68,12 +72,17 @@ class XpStateSingle long getCurrentXp() { - return startXp + xpGained; + return startXp + getTotalXpGained(); + } + + int getTotalXpGained() + { + return xpGainedBeforeReset + xpGainedSinceReset; } private int getActionsHr() { - return toHourly(getXpAction(actionType).getActions()); + return toHourly(getXpAction(actionType).getActionsSinceReset()); } private int toHourly(int value) @@ -136,7 +145,7 @@ class XpStateSingle // below will be a custom formatter that handles spans larger than 1 day long seconds = getTimeElapsedInSeconds(); - if (seconds <= 0 || xpGained <= 0) + if (seconds <= 0 || xpGainedSinceReset <= 0) { return -1; } @@ -144,7 +153,7 @@ class XpStateSingle // formula is xpRemaining / xpPerSecond // xpPerSecond being xpGained / seconds // This can be simplified so division is only done once and we can work in whole numbers! - return (getXpRemaining() * seconds) / xpGained; + return (getXpRemaining() * seconds) / xpGainedSinceReset; } private String getTimeTillLevel(XpGoalTimeType goalTimeType) @@ -197,7 +206,22 @@ class XpStateSingle int getXpHr() { - return toHourly(xpGained); + return toHourly(xpGainedSinceReset); + } + + void resetPerHour() + { + //reset actions per hour + for (XpAction action : actions.values()) + { + action.setActions(action.getActions() + action.getActionsSinceReset()); + action.setActionsSinceReset(0); + } + + //reset xp per hour + xpGainedBeforeReset += xpGainedSinceReset; + xpGainedSinceReset = 0; + setSkillTime(0); } boolean update(long currentXp, int goalStartXp, int goalEndXp) @@ -208,7 +232,7 @@ class XpStateSingle return false; } - long originalXp = xpGained + startXp; + long originalXp = getTotalXpGained() + startXp; int actionExp = (int) (currentXp - originalXp); // No experience gained @@ -237,10 +261,10 @@ class XpStateSingle } action.setActionExpIndex((action.getActionExpIndex() + 1) % action.getActionExps().length); - action.setActions(action.getActions() + 1); + action.setActionsSinceReset(action.getActionsSinceReset() + 1); // Calculate experience gained - xpGained = (int) (currentXp - startXp); + xpGainedSinceReset = (int) (currentXp - (startXp + xpGainedBeforeReset)); // Determine XP goals, overall has no goals if (skill != Skill.OVERALL) @@ -273,7 +297,7 @@ class XpStateSingle public void tick(long delta) { // Don't tick skills that have not gained XP or have been reset. - if (xpGained <= 0) + if (xpGainedSinceReset <= 0) { return; } @@ -285,12 +309,12 @@ class XpStateSingle return XpSnapshotSingle.builder() .startLevel(Experience.getLevelForXp(startLevelExp)) .endLevel(Experience.getLevelForXp(endLevelExp)) - .xpGainedInSession(xpGained) + .xpGainedInSession(getTotalXpGained()) .xpRemainingToGoal(getXpRemaining()) .xpPerHour(getXpHr()) .skillProgressToGoal(getSkillProgress()) .actionType(actionType) - .actionsInSession(getXpAction(actionType).getActions()) + .actionsInSession(getXpAction(actionType).getActions() + getXpAction(actionType).getActionsSinceReset()) .actionsRemainingToGoal(getActionsRemaining()) .actionsPerHour(getActionsHr()) .timeTillGoal(getTimeTillLevel(XpGoalTimeType.DAYS)) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerPlugin.java index 4fd1f02516..37d14e2a41 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerPlugin.java @@ -323,6 +323,7 @@ public class XpTrackerPlugin extends Plugin /** * Reset an individual skill with the client's current known state of the skill * Will also clear the skill from the UI. + * * @param skill Skill to reset */ void resetSkillState(Skill skill) @@ -335,6 +336,7 @@ public class XpTrackerPlugin extends Plugin /** * Reset all skills except for the one provided + * * @param skill Skill to ignore during reset */ void resetOtherSkillState(Skill skill) @@ -349,6 +351,29 @@ public class XpTrackerPlugin extends Plugin } } + /** + * Reset the xp gained since last reset of the skill + * Does not clear the skill from the UI. + * + * @param skill Skill to reset per hour rate + */ + void resetSkillPerHourState(Skill skill) + { + xpState.resetSkillPerHour(skill); + } + + /** + * Reset the xp gained since last reset of all skills including OVERALL + * Does not clear the UI. + */ + void resetAllSkillsPerHourState() + { + for (Skill skill : Skill.values()) + { + resetSkillPerHourState(skill); + } + } + @Subscribe public void onStatChanged(StatChanged statChanged) { @@ -377,7 +402,7 @@ public class XpTrackerPlugin extends Plugin final Actor interacting = client.getLocalPlayer().getInteracting(); if (interacting instanceof NPC && COMBAT.contains(skill)) { - final int xpModifier = worldSetToType(client.getWorldType()).modifier(client);; + final int xpModifier = worldSetToType(client.getWorldType()).modifier(client); final NPC npc = (NPC) interacting; xpState.updateNpcExperience(skill, npc, npcManager.getHealth(npc.getId()), xpModifier); }