Skip to content

Commit

Permalink
Added xp/hr tracker
Browse files Browse the repository at this point in the history
  • Loading branch information
Noremac201 authored and Adam- committed Jul 8, 2017
1 parent 292b800 commit 2b12e3b
Show file tree
Hide file tree
Showing 5 changed files with 366 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
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;
Expand Down Expand Up @@ -90,6 +91,7 @@ public void loadAll()
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"))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright (c) 2017, Cameron <[email protected]>
* 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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/*
* Copyright (c) 2017, Cameron <[email protected]>
* 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();
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* Copyright (c) 2017, Cameron <[email protected]>
* 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;
}

}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 2b12e3b

Please sign in to comment.