diff --git a/runelite-api/src/main/java/net/runelite/api/NPC.java b/runelite-api/src/main/java/net/runelite/api/NPC.java index f6f2ecd281..5517e5341c 100644 --- a/runelite-api/src/main/java/net/runelite/api/NPC.java +++ b/runelite-api/src/main/java/net/runelite/api/NPC.java @@ -25,8 +25,6 @@ package net.runelite.api; -import net.runelite.rs.api.NPCComposition; - public class NPC extends Actor { private net.runelite.rs.api.NPC npc; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java index 819c195240..d52c17a018 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java @@ -30,6 +30,7 @@ import java.util.Collection; import java.util.List; import net.runelite.client.RuneLite; import net.runelite.client.plugins.boosts.Boosts; +import net.runelite.client.plugins.bosstimer.BossTimers; import net.runelite.client.plugins.fpsinfo.FPS; import net.runelite.client.plugins.hiscore.Hiscore; import net.runelite.client.plugins.opponentinfo.OpponentInfo; @@ -50,6 +51,7 @@ public class PluginManager load(new OpponentInfo()); load(new FPS()); load(new Hiscore()); + load(new BossTimers()); } private void load(Plugin plugin) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/bosstimer/Boss.java b/runelite-client/src/main/java/net/runelite/client/plugins/bosstimer/Boss.java new file mode 100644 index 0000000000..abcf878b31 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/bosstimer/Boss.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016-2017, Cameron Moberg + * Copyright (c) 2017, Adam + * 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.bosstimer; + +public class Boss +{ + private String name; + private int spawnTime; + + public String getName() + { + return name; + } + + public int getSpawnTime() + { + return spawnTime; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/bosstimer/BossTimers.java b/runelite-client/src/main/java/net/runelite/client/plugins/bosstimer/BossTimers.java new file mode 100644 index 0000000000..7eed7531b3 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/bosstimer/BossTimers.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2016-2017, Cameron Moberg + * Copyright (c) 2017, Adam + * 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.bosstimer; + +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Type; +import java.util.List; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BossTimers extends Plugin +{ + private static final Logger logger = LoggerFactory.getLogger(BossTimers.class); + + private final BossTimersOverlay overlay = new BossTimersOverlay(this, OverlayPosition.TOP_LEFT, OverlayPriority.LOW); + + private final List bosses = loadBossData(); + + @Override + public Overlay getOverlay() + { + return overlay; + } + + public Boss findBoss(String name) + { + for (Boss boss : bosses) + { + if (boss.getName().equals(name)) + { + return boss; + } + } + return null; + } + + private static List loadBossData() + { + Gson gson = new Gson(); + Type type = new TypeToken>() + { + }.getType(); + + InputStream in = BossTimers.class.getResourceAsStream("boss_timers.json"); + return gson.fromJson(new InputStreamReader(in), type); + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/bosstimer/BossTimersOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/bosstimer/BossTimersOverlay.java new file mode 100644 index 0000000000..5a0c53457a --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/bosstimer/BossTimersOverlay.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2016-2017, Cameron Moberg + * Copyright (c) 2017, Adam + * 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.bosstimer; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.time.Duration; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.List; +import net.runelite.api.Actor; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.Player; +import net.runelite.client.RuneLite; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BossTimersOverlay extends Overlay +{ + private static final Logger logger = LoggerFactory.getLogger(BossTimersOverlay.class); + + private static final int TOP_BORDER = 2; + private static final int LEFT_BORDER = 2; + private static final int RIGHT_BORDER = 2; + private static final int WIDTH = 140; + private static final int SEPARATOR = 2; + + private static final Color BACKGROUND = new Color(Color.gray.getRed(), Color.gray.getGreen(), Color.gray.getBlue(), 127); + + private final BossTimers bossTimers; + private final List timers = new ArrayList<>(); + + public BossTimersOverlay(BossTimers bossTimers, OverlayPosition position, OverlayPriority priority) + { + super(position, priority); + this.bossTimers = bossTimers; + } + + private Actor getOpponent() + { + Client client = RuneLite.getClient(); + + Player player = client.getLocalPlayer(); + if (player == null) + { + return null; + } + + return player.getInteracting(); + } + + private void checkDead() + { + Actor actor = getOpponent(); + + if (actor == null || actor.getHealthRatio() != 0) + { + return; + } + + logger.debug("NPC {} has died", actor.getName()); + + Boss boss = bossTimers.findBoss(actor.getName()); + if (boss == null) + { + return; + } + + if (findTimerFor(actor.getName()) != null) + { + return; + } + + logger.debug("Creating spawn timer for {} ({} seconds)", actor.getName(), boss.getSpawnTime()); + + Instant respawnTime = Instant.now().plus(boss.getSpawnTime(), ChronoUnit.SECONDS); + RespawnTimer respawnTimer = new RespawnTimer(boss, respawnTime); + + timers.add(respawnTimer); + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (RuneLite.getClient().getGameState() != GameState.LOGGED_IN) + { + return null; + } + + // find new dead bosses + checkDead(); + + if (timers.isEmpty()) + { + return null; + } + + FontMetrics metrics = graphics.getFontMetrics(); + + int height = TOP_BORDER + timers.size() * (SEPARATOR + metrics.getHeight()) + TOP_BORDER; + graphics.setColor(BACKGROUND); + graphics.fillRect(0, 0, WIDTH, height); + + int y = TOP_BORDER; + Instant now = Instant.now(); + + for (RespawnTimer respawnTimer : new ArrayList<>(timers)) + { + if (respawnTimer.getRespawnTime().isBefore(now)) + { + timers.remove(respawnTimer); + continue; + } + + graphics.setColor(Color.white); + + graphics.drawString(respawnTimer.getBoss().getName(), LEFT_BORDER, y + metrics.getHeight()); + + // calculate time left + Duration timeLeft = Duration.between(Instant.now(), respawnTimer.getRespawnTime()); + + String secLeft = "" + timeLeft.getSeconds(); + graphics.drawString(secLeft, WIDTH - RIGHT_BORDER - metrics.stringWidth(secLeft), y + metrics.getHeight()); + + y += metrics.getHeight() + SEPARATOR; + } + + return new Dimension(WIDTH, height); + } + + private RespawnTimer findTimerFor(String name) + { + for (RespawnTimer timer : timers) + { + if (timer.getBoss().getName().equals(name)) + { + return timer; + } + } + return null; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/bosstimer/RespawnTimer.java b/runelite-client/src/main/java/net/runelite/client/plugins/bosstimer/RespawnTimer.java new file mode 100644 index 0000000000..1440376faa --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/bosstimer/RespawnTimer.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2017, Adam + * 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.bosstimer; + +import java.time.Instant; + +public class RespawnTimer +{ + private final Boss boss; + private final Instant respawnTime; + + public RespawnTimer(Boss boss, Instant respawnTime) + { + this.boss = boss; + this.respawnTime = respawnTime; + } + + public Boss getBoss() + { + return boss; + } + + public Instant getRespawnTime() + { + return respawnTime; + } +} diff --git a/runelite-client/src/main/java/net/runelite/inject/callbacks/Hooks.java b/runelite-client/src/main/java/net/runelite/inject/callbacks/Hooks.java index 7f3808064b..1491ed09a4 100644 --- a/runelite-client/src/main/java/net/runelite/inject/callbacks/Hooks.java +++ b/runelite-client/src/main/java/net/runelite/inject/callbacks/Hooks.java @@ -57,6 +57,9 @@ public class Hooks return; } - logger.debug("Event {} triggered on {}", name, object); + if (object != null) + logger.trace("Event {} (idx {}) triggered on {}", name, idx, object); + else + logger.trace("Event {} (idx {}) triggered", name, idx); } } diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/bosstimer/boss_timers.json b/runelite-client/src/main/resources/net/runelite/client/plugins/bosstimer/boss_timers.json new file mode 100644 index 0000000000..7ef9c00c87 --- /dev/null +++ b/runelite-client/src/main/resources/net/runelite/client/plugins/bosstimer/boss_timers.json @@ -0,0 +1,49 @@ +[{ + "name": "General Graardor", + "spawnTime": 90 +}, { + "name": "K'ril Tsutsaroth", + "spawnTime": 90 +}, { + "name": "Kree'arra", + "spawnTime": 90 +}, { + "name": "Commander Zilyana", + "spawnTime": 90 +}, { + "name": "Callisto", + "spawnTime": 30 +}, { + "name": "Chaos fanatic", + "spawnTime": 30 +}, { + "name": "Crazy archaeologist", + "spawnTime": 30 +}, { + "name": "King Black Dragon", + "spawnTime": 10 +}, { + "name": "Scorpia", + "spawnTime": 10 +}, { + "name": "Venenatis", + "spawnTime": 30 +}, { + "name": "Vet'ion", + "spawnTime": 30 +}, { + "name": "Dagannoth Prime", + "spawnTime": 90 +}, { + "name": "Dagannoth Rex", + "spawnTime": 90 +}, { + "name": "Dagannoth Supreme", + "spawnTime": 90 +}, { + "name": "Corporeal Beast", + "spawnTime": 30 +}, { + "name": "Giant mole", + "spawnTime": 10 +}] \ No newline at end of file