diff --git a/runelite-api/src/main/java/net/runelite/api/Client.java b/runelite-api/src/main/java/net/runelite/api/Client.java index fa7a54ee55..7299e57573 100644 --- a/runelite-api/src/main/java/net/runelite/api/Client.java +++ b/runelite-api/src/main/java/net/runelite/api/Client.java @@ -782,6 +782,13 @@ public interface Client extends GameEngine */ int getSkillExperience(Skill skill); + /** + * Get the total experience of the player + * + * @return + */ + long getOverallExperience(); + /** * Gets the game drawing mode. * 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 f5987290eb..512be6d12e 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 @@ -28,7 +28,6 @@ package net.runelite.client.plugins.xptracker; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; -import java.io.IOException; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Collections; @@ -95,7 +94,7 @@ class XpInfoBox extends JPanel private boolean paused = false; - XpInfoBox(XpTrackerPlugin xpTrackerPlugin, XpTrackerConfig xpTrackerConfig, Client client, JPanel panel, Skill skill, SkillIconManager iconManager) throws IOException + XpInfoBox(XpTrackerPlugin xpTrackerPlugin, XpTrackerConfig xpTrackerConfig, Client client, JPanel panel, Skill skill, SkillIconManager iconManager) { this.xpTrackerConfig = xpTrackerConfig; this.panel = panel; 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 e98f4da4f7..c7bf7c3876 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 @@ -27,7 +27,6 @@ package net.runelite.client.plugins.xptracker; import java.awt.BorderLayout; import java.awt.GridLayout; -import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.swing.BoxLayout; @@ -129,20 +128,13 @@ class XpPanel extends PluginPanel layoutPanel.add(overallPanel); layoutPanel.add(infoBoxPanel); - try + for (Skill skill : Skill.values()) { - for (Skill skill : Skill.values()) + if (skill == Skill.OVERALL) { - if (skill == Skill.OVERALL) - { - break; - } - infoBoxes.put(skill, new XpInfoBox(xpTrackerPlugin, xpTrackerConfig, client, infoBoxPanel, skill, iconManager)); + break; } - } - catch (IOException e) - { - log.warn(null, e); + infoBoxes.put(skill, new XpInfoBox(xpTrackerPlugin, xpTrackerConfig, client, infoBoxPanel, skill, iconManager)); } errorPanel.setContent("Exp trackers", "You have not gained experience yet."); @@ -193,7 +185,7 @@ class XpPanel extends PluginPanel } } - void updateTotal(XpSnapshotTotal xpSnapshotTotal) + void updateTotal(XpSnapshotSingle xpSnapshotTotal) { // if player has gained exp and hasn't switched displays yet, hide error panel and show overall info if (xpSnapshotTotal.getXpGainedInSession() > 0 && !overallPanel.isVisible()) @@ -201,11 +193,16 @@ class XpPanel extends PluginPanel overallPanel.setVisible(true); remove(errorPanel); } + else if (xpSnapshotTotal.getXpGainedInSession() == 0 && overallPanel.isVisible()) + { + overallPanel.setVisible(false); + add(errorPanel); + } SwingUtilities.invokeLater(() -> rebuildAsync(xpSnapshotTotal)); } - private void rebuildAsync(XpSnapshotTotal xpSnapshotTotal) + private void rebuildAsync(XpSnapshotSingle xpSnapshotTotal) { overallExpGained.setText(XpInfoBox.htmlLabel("Gained: ", xpSnapshotTotal.getXpGainedInSession())); overallExpHour.setText(XpInfoBox.htmlLabel("Per hour: ", xpSnapshotTotal.getXpPerHour())); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpPauseState.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpPauseState.java index 9f57de71c3..194c890c42 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpPauseState.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpPauseState.java @@ -49,7 +49,7 @@ class XpPauseState return findPauseState(skill).isPaused(); } - void tickXp(Skill skill, int currentXp, int pauseAfterMinutes) + void tickXp(Skill skill, long currentXp, int pauseAfterMinutes) { final XpPauseStateSingle state = findPauseState(skill); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpPauseStateSingle.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpPauseStateSingle.java index d74d498bd1..9e5cc55622 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpPauseStateSingle.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpPauseStateSingle.java @@ -39,7 +39,7 @@ class XpPauseStateSingle @Getter private long lastChangeMillis; @Getter - private int xp; + private long xp; boolean isPaused() { @@ -66,7 +66,7 @@ class XpPauseStateSingle return pauseReasons.add(XpPauseReason.PAUSE_MANUAL); } - boolean xpChanged(int xp) + boolean xpChanged(long xp) { this.xp = xp; this.lastChangeMillis = System.currentTimeMillis(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpSnapshotTotal.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpSnapshotTotal.java deleted file mode 100644 index 72fcdd93d5..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpSnapshotTotal.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2018, Levi - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.xptracker; - -import lombok.Value; - -@Value -class XpSnapshotTotal -{ - private final int xpGainedInSession; - private final int xpPerHour; - - static XpSnapshotTotal zero() - { - return new XpSnapshotTotal(0, 0); - } -} 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 a0ebb02341..d6a10df1b8 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 @@ -40,7 +40,6 @@ class XpState { private static final double DEFAULT_XP_MODIFIER = 4.0; private static final double SHARED_XP_MODIFIER = DEFAULT_XP_MODIFIER / 3.0; - private final XpStateTotal xpTotal = new XpStateTotal(); private final Map xpSkills = new EnumMap<>(Skill.class); private NPC interactedNPC; @@ -49,7 +48,6 @@ class XpState */ void reset() { - xpTotal.reset(); xpSkills.clear(); } @@ -58,25 +56,10 @@ class XpState * @param skill Skill to reset * @param currentXp Current XP to set to, if unknown set to -1 */ - void resetSkill(Skill skill, int currentXp) + void resetSkill(Skill skill, long currentXp) { xpSkills.remove(skill); xpSkills.put(skill, new XpStateSingle(skill, currentXp)); - recalculateTotal(); - } - - /** - * Calculates the total skill changes observed in this session or since the last reset - */ - void recalculateTotal() - { - xpTotal.reset(); - - for (XpStateSingle state : xpSkills.values()) - { - xpTotal.addXpGainedInSession(state.getXpGained()); - xpTotal.addXpPerHour(state.getXpHr()); - } } /** @@ -90,7 +73,7 @@ class XpState * @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, int currentXp, int goalStartXp, int goalEndXp) + XpUpdateResult updateSkill(Skill skill, long currentXp, int goalStartXp, int goalEndXp) { XpStateSingle state = getSkill(skill); @@ -108,7 +91,7 @@ class XpState } else { - int startXp = state.getStartXp(); + long startXp = state.getStartXp(); int gainedXp = state.getXpGained(); if (startXp + gainedXp > currentXp) @@ -208,11 +191,16 @@ class XpState * @param skill Skill to initialize * @param currentXp Current known XP for the skill */ - void initializeSkill(Skill skill, int currentXp) + void initializeSkill(Skill skill, long currentXp) { xpSkills.put(skill, new XpStateSingle(skill, currentXp)); } + boolean isInitialized(Skill skill) + { + return xpSkills.containsKey(skill); + } + @NonNull XpStateSingle getSkill(Skill skill) { @@ -237,8 +225,8 @@ class XpState * @return An immutable snapshot of total information for this session since first login or last reset */ @NonNull - XpSnapshotTotal getTotalSnapshot() + XpSnapshotSingle getTotalSnapshot() { - return xpTotal.snapshot(); + return getSkill(Skill.OVERALL).snapshot(); } } 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 7f4eef8d1c..2b6c694ba1 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 @@ -42,7 +42,7 @@ class XpStateSingle private final Map actions = new HashMap<>(); @Getter - private final int startXp; + private final long startXp; @Getter private int xpGained = 0; @@ -60,7 +60,7 @@ class XpStateSingle return actions.get(type); } - private int getCurrentXp() + private long getCurrentXp() { return startXp + xpGained; } @@ -86,7 +86,7 @@ class XpStateSingle private int getXpRemaining() { - return endLevelExp - getCurrentXp(); + return endLevelExp - (int) getCurrentXp(); } private int getActionsRemaining() @@ -170,7 +170,7 @@ class XpStateSingle return toHourly(xpGained); } - boolean update(int currentXp, int goalStartXp, int goalEndXp) + boolean update(long currentXp, int goalStartXp, int goalEndXp) { if (startXp == -1) { @@ -178,8 +178,8 @@ class XpStateSingle return false; } - int originalXp = xpGained + startXp; - int actionExp = currentXp - originalXp; + long originalXp = xpGained + startXp; + int actionExp = (int) (currentXp - originalXp); // No experience gained if (actionExp == 0) @@ -210,28 +210,31 @@ class XpStateSingle action.setActions(action.getActions() + 1); // Calculate experience gained - xpGained = currentXp - startXp; + xpGained = (int) (currentXp - startXp); - // Determine XP goals - if (goalStartXp <= 0 || currentXp > goalEndXp) + // Determine XP goals, overall has no goals + if (skill != Skill.OVERALL) { - startLevelExp = Experience.getXpForLevel(Experience.getLevelForXp(currentXp)); - } - else - { - startLevelExp = goalStartXp; - } + if (goalStartXp <= 0 || currentXp > goalEndXp) + { + startLevelExp = Experience.getXpForLevel(Experience.getLevelForXp((int) currentXp)); + } + else + { + startLevelExp = goalStartXp; + } - if (goalEndXp <= 0 || currentXp > goalEndXp) - { - int currentLevel = Experience.getLevelForXp(currentXp); - endLevelExp = currentLevel + 1 <= Experience.MAX_VIRT_LEVEL - ? Experience.getXpForLevel(currentLevel + 1) - : Experience.MAX_SKILL_XP; - } - else - { - endLevelExp = goalEndXp; + if (goalEndXp <= 0 || currentXp > goalEndXp) + { + int currentLevel = Experience.getLevelForXp((int) currentXp); + endLevelExp = currentLevel + 1 <= Experience.MAX_VIRT_LEVEL + ? Experience.getXpForLevel(currentLevel + 1) + : Experience.MAX_SKILL_XP; + } + else + { + endLevelExp = goalEndXp; + } } return true; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpStateTotal.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpStateTotal.java deleted file mode 100644 index ad9492981c..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpStateTotal.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2018, Levi - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.xptracker; - -import lombok.Data; - -@Data -class XpStateTotal -{ - private int xpGainedInSession = 0; - private int xpPerHour = 0; - - void reset() - { - xpGainedInSession = 0; - xpPerHour = 0; - } - - void addXpGainedInSession(int skillXpGainedInSession) - { - xpGainedInSession += skillXpGainedInSession; - } - - void addXpPerHour(int skillXpGainedPerHour) - { - xpPerHour += skillXpGainedPerHour; - } - - XpSnapshotTotal snapshot() - { - return new XpSnapshotTotal(xpGainedInSession, xpPerHour); - } -} 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 bb43ffdd7a..c66c409a16 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 @@ -146,16 +146,6 @@ public class XpTrackerPlugin extends Plugin clientToolbar.removeNavigation(navButton); } - private long getTotalXp() - { - long total = 0; - for (Skill skill : Skill.values()) - { - total += client.getSkillExperience(skill); - } - return total; - } - @Subscribe public void onGameStateChanged(GameStateChanged event) { @@ -195,7 +185,7 @@ public class XpTrackerPlugin extends Plugin return; } - long totalXp = getTotalXp(); + long totalXp = client.getOverallExperience(); // Don't submit xptrack unless xp threshold is reached if (Math.abs(totalXp - lastXp) > XP_THRESHOLD) { @@ -229,7 +219,16 @@ public class XpTrackerPlugin extends Plugin for (Skill skill : Skill.values()) { - int currentXp = client.getSkillExperience(skill); + long currentXp; + if (skill == Skill.OVERALL) + { + currentXp = client.getOverallExperience(); + } + else + { + currentXp = client.getSkillExperience(skill); + } + xpState.initializeSkill(skill, currentXp); } } @@ -242,7 +241,7 @@ public class XpTrackerPlugin extends Plugin { xpState.reset(); xpPanel.resetAllInfoBoxes(); - xpPanel.updateTotal(XpSnapshotTotal.zero()); + xpPanel.updateTotal(new XpSnapshotSingle.XpSnapshotSingleBuilder().build()); } /** @@ -254,7 +253,6 @@ public class XpTrackerPlugin extends Plugin { int currentXp = client.getSkillExperience(skill); xpState.resetSkill(skill, currentXp); - xpState.recalculateTotal(); xpPanel.resetSkill(skill); xpPanel.updateTotal(xpState.getTotalSnapshot()); } @@ -302,10 +300,18 @@ public class XpTrackerPlugin extends Plugin } final XpUpdateResult updateResult = xpState.updateSkill(skill, currentXp, startGoalXp, endGoalXp); - final boolean updated = XpUpdateResult.UPDATED.equals(updateResult); - xpPanel.updateSkillExperience(updated, xpPauseState.isPaused(skill), skill, xpState.getSkillSnapshot(skill)); - xpState.recalculateTotal(); - xpPanel.updateTotal(xpState.getTotalSnapshot()); + xpPanel.updateSkillExperience(updateResult == XpUpdateResult.UPDATED, xpPauseState.isPaused(skill), skill, xpState.getSkillSnapshot(skill)); + + if (skill == Skill.CONSTRUCTION && updateResult == XpUpdateResult.INITIALIZED) + { + // Construction is the last skill initialized on login, now initialize the total experience + xpState.initializeSkill(Skill.OVERALL, client.getOverallExperience()); + } + else if (xpState.isInitialized(Skill.OVERALL)) + { + xpState.updateSkill(Skill.OVERALL, client.getOverallExperience(), -1, -1); + xpPanel.updateTotal(xpState.getTotalSnapshot()); + } } @Subscribe @@ -325,7 +331,6 @@ public class XpTrackerPlugin extends Plugin xpPanel.updateSkillExperience(updated, xpPauseState.isPaused(skill), skill, xpState.getSkillSnapshot(skill)); } - xpState.recalculateTotal(); xpPanel.updateTotal(xpState.getTotalSnapshot()); } @@ -335,7 +340,7 @@ public class XpTrackerPlugin extends Plugin rebuildSkills(); if (fetchXp) { - lastXp = getTotalXp(); + lastXp = client.getOverallExperience(); fetchXp = false; } } @@ -464,7 +469,17 @@ public class XpTrackerPlugin extends Plugin // Adjust unpause states for (Skill skill : Skill.values()) { - xpPauseState.tickXp(skill, client.getSkillExperience(skill), xpTrackerConfig.pauseSkillAfter()); + long skillExperience; + if (skill == Skill.OVERALL) + { + skillExperience = client.getOverallExperience(); + } + else + { + skillExperience = client.getSkillExperience(skill); + } + + xpPauseState.tickXp(skill, skillExperience, xpTrackerConfig.pauseSkillAfter()); } xpPauseState.tickLogout(xpTrackerConfig.pauseOnLogout(), !GameState.LOGIN_SCREEN.equals(client.getGameState())); @@ -498,7 +513,6 @@ public class XpTrackerPlugin extends Plugin xpPanel.updateSkillExperience(false, xpPauseState.isPaused(skill), skill, xpState.getSkillSnapshot(skill)); } - xpState.recalculateTotal(); xpPanel.updateTotal(xpState.getTotalSnapshot()); } diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java index 9b232aa760..430bfb7d35 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java @@ -504,14 +504,8 @@ public abstract class RSClientMixin implements RSClient if (skill == Skill.OVERALL) { - int totalExperience = 0; - - for (int experience : experiences) - { - totalExperience += experience; - } - - return totalExperience; + logger.debug("getSkillExperience called for {}!", skill); + return (int) getOverallExperience(); } int idx = skill.ordinal(); @@ -526,6 +520,22 @@ public abstract class RSClientMixin implements RSClient return experiences[idx]; } + @Inject + @Override + public long getOverallExperience() + { + int[] experiences = getSkillExperiences(); + + long totalExperience = 0L; + + for (int experience : experiences) + { + totalExperience += experience; + } + + return totalExperience; + } + @Inject @Override public void refreshChat()