Added xp/hr tracker

This commit is contained in:
Cameron Moberg
2017-07-08 16:15:48 -07:00
committed by Adam
parent ebf39b286b
commit fd6b5dbc63
5 changed files with 366 additions and 0 deletions

View File

@@ -51,6 +51,7 @@ import net.runelite.client.plugins.opponentinfo.OpponentInfo;
import net.runelite.client.plugins.pestcontrol.PestControl;
import net.runelite.client.plugins.runecraft.Runecraft;
import net.runelite.client.plugins.xpglobes.XpGlobes;
import net.runelite.client.plugins.xptracker.XPTracker;
import net.runelite.client.plugins.xtea.Xtea;
import net.runelite.client.plugins.zulrah.Zulrah;
import org.slf4j.Logger;
@@ -90,6 +91,7 @@ public class PluginManager
plugins.add(new XpGlobes());
plugins.add(new CombatNotifier());
plugins.add(new JewelryCount());
plugins.add(new XPTracker());
plugins.add(new ExaminePlugin());
if (RuneLite.getOptions().has("developer-mode"))

View File

@@ -0,0 +1,85 @@
/*
* Copyright (c) 2017, Cameron <moberg@tuta.io>
* 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 net.runelite.api.Skill;
import java.time.Duration;
import java.time.Instant;
public class SkillXPInfo
{
private Skill skill;
private Instant skillTimeStart = null;
private int xpGained = 0;
private int loginXp = 0;
public SkillXPInfo(int loginXp, Skill skill)
{
this.skill = skill;
this.loginXp = loginXp;
}
public int getXpHr()
{
long timeElapsedInSeconds = Duration.between(
skillTimeStart, Instant.now()).getSeconds();
return (int) ((1.0 / (timeElapsedInSeconds / 3600.0)) * xpGained);
}
public void reset(int loginXp)
{
xpGained = 0;
this.loginXp = loginXp;
skillTimeStart = null;
}
public void update(int currentXp)
{
xpGained = currentXp - loginXp;
if (skillTimeStart == null)
skillTimeStart = Instant.now();
}
public Instant getSkillTimeStart()
{
return skillTimeStart;
}
public int getXpGained()
{
return xpGained;
}
public int getLoginXp()
{
return loginXp;
}
public Skill getSkill()
{
return this.skill;
}
}

View File

@@ -0,0 +1,160 @@
/*
* Copyright (c) 2017, Cameron <moberg@tuta.io>
* 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 net.runelite.api.Client;
import net.runelite.api.Skill;
import net.runelite.client.RuneLite;
import net.runelite.client.ui.PluginPanel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.Map;
public class XPPanel extends PluginPanel
{
private static final Client client = RuneLite.getClient();
private static final Logger logger = LoggerFactory.getLogger(XPPanel.class);
private Map<Skill, JPanel> labelMap = new HashMap<>();
private final XPTracker xpTracker;
private JPanel statsPanel;
public XPPanel(RuneLite runelite, XPTracker xpTracker)
{
this.xpTracker = xpTracker;
setMinimumSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT));
setPreferredSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT));
setSize(PANEL_WIDTH, PANEL_HEIGHT);
setVisible(true);
statsPanel = new JPanel();
statsPanel.setLayout(new GridLayout(24, 1));
try
{
for (Skill skill : Skill.values())
{
if (skill == Skill.OVERALL)
break;
JLabel skillLabel = new JLabel();
labelMap.put(skill, makeSkillPanel(skill, skillLabel));
}
}
catch (IOException e)
{
logger.warn(null, e);
}
JButton resetButton = new JButton("Reset All");
resetButton.setPreferredSize(new Dimension(PANEL_WIDTH, 32));
resetButton.addActionListener((ActionEvent e) ->
runelite.getExecutor().execute(this::resetAllSkillXpHr));
statsPanel.add(resetButton);
JScrollPane scroll = new JScrollPane(statsPanel);
scroll.add(statsPanel);
add(statsPanel);
}
private JButton makeSkillResetButton(Skill skill) throws IOException
{
ImageIcon resetIcon = new ImageIcon(ImageIO.read(getClass().getResourceAsStream("reset.png")));
JButton resetButton = new JButton(resetIcon);
resetButton.setPreferredSize(new Dimension(32, 32));
resetButton.addActionListener(actionEvent -> resetSkillXpHr(skill));
return resetButton;
}
private JPanel makeSkillPanel(Skill skill, JLabel levelLabel) throws IOException
{
BorderLayout borderLayout = new BorderLayout();
borderLayout.setHgap(12);
JPanel iconLevel = new JPanel(borderLayout);
iconLevel.setPreferredSize(new Dimension(PANEL_WIDTH, 32));
String skillIcon = "/skill_icons/" + skill.getName().toLowerCase() + ".png";
logger.debug("Loading skill icon from {}", skillIcon);
JLabel icon = new JLabel(new ImageIcon(ImageIO.read(XPPanel.class.getResourceAsStream(skillIcon))));
iconLevel.add(icon, BorderLayout.LINE_START);
iconLevel.add(levelLabel, BorderLayout.CENTER);
iconLevel.add(makeSkillResetButton(skill), BorderLayout.LINE_END);
return iconLevel;
}
public void resetSkillXpHr(Skill skill)
{
int skillIdx = skill.ordinal();
xpTracker.getXpInfos()[skillIdx].reset(client.getSkillExperience(skill));
statsPanel.remove(labelMap.get(skill));
statsPanel.revalidate();
statsPanel.repaint();
}
public void resetAllSkillXpHr()
{
for (SkillXPInfo skillInfo : xpTracker.getXpInfos())
{
if (skillInfo != null && skillInfo.getSkillTimeStart() != null)
resetSkillXpHr(skillInfo.getSkill());
}
}
public void updateAllSkillXpHr()
{
for (SkillXPInfo skillInfo : xpTracker.getXpInfos())
{
if (skillInfo != null && skillInfo.getSkillTimeStart() != null &&
skillInfo.getXpGained() != 0)
updateSkillXpHr(skillInfo);
}
}
public void updateSkillXpHr(SkillXPInfo skillXPInfo)
{
JPanel skillPanel = labelMap.get(skillXPInfo.getSkill());
JLabel xpHr = (JLabel) skillPanel.getComponent(1);
xpHr.setText(NumberFormat.getInstance().format(skillXPInfo.getXpHr()) + " xp/hr");
if (skillPanel.getParent() != statsPanel)
{
statsPanel.add(skillPanel);
statsPanel.revalidate();
statsPanel.repaint();
}
}
}

View File

@@ -0,0 +1,119 @@
/*
* Copyright (c) 2017, Cameron <moberg@tuta.io>
* 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 com.google.common.eventbus.Subscribe;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.Player;
import net.runelite.api.Skill;
import net.runelite.client.RuneLite;
import net.runelite.client.events.ExperienceChanged;
import net.runelite.client.events.GameStateChanged;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.ui.ClientUI;
import net.runelite.client.ui.NavigationButton;
import net.runelite.client.util.RunnableExceptionLogger;
import java.awt.Font;
import java.awt.GraphicsEnvironment;
import java.awt.event.ActionEvent;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class XPTracker extends Plugin
{
private static final int NUMBER_OF_SKILLS = Skill.values().length - 1; //ignore overall
private final RuneLite runeLite = RuneLite.getRunelite();
private final ClientUI ui = runeLite.getGui();
private final Client client = RuneLite.getClient();
private ScheduledFuture<?> future;
private final NavigationButton navButton = new NavigationButton("XP Tracker");
private final XPPanel xpPanel = new XPPanel(runeLite, this);
private SkillXPInfo[] xpInfos = new SkillXPInfo[NUMBER_OF_SKILLS];
@Subscribe
public void onGameStateChanged(GameStateChanged event)
{
if (event.getGameState() != GameState.LOGGED_IN)
xpPanel.resetAllSkillXpHr();
}
@Subscribe
public void onXpChanged(ExperienceChanged event)
{
Skill skill = event.getSkill();
String currentUser = client.getLocalPlayer().getName();
int skillIdx = skill.ordinal();
//To catch login ExperienceChanged event.
if (xpInfos[skillIdx] != null)
{
xpInfos[skillIdx].update(client.getSkillExperience(skill));
}
else
{
xpInfos[skillIdx] = new SkillXPInfo(client.getSkillExperience(skill),
skill);
}
}
private void setPluginPanel(ActionEvent e)
{
ui.expand(xpPanel);
}
@Override
protected void startUp() throws Exception
{
navButton.getButton().addActionListener(this::setPluginPanel);
navButton.getButton().setText("XP");
ui.getNavigationPanel().addNavigation(navButton);
ScheduledExecutorService executor = RuneLite.getRunelite().getExecutor();
future = executor.scheduleAtFixedRate(RunnableExceptionLogger.wrap(
xpPanel::updateAllSkillXpHr), 0, 600, TimeUnit.MILLISECONDS);
Font font = Font.createFont(Font.TRUETYPE_FONT, getClass().getResourceAsStream("/runescape.ttf"));
font = font.deriveFont(Font.BOLD, 16);
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
ge.registerFont(font);
}
@Override
protected void shutDown() throws Exception
{
future.cancel(true);
}
public SkillXPInfo[] getXpInfos()
{
return xpInfos;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB