diff --git a/runelite-client/src/main/java/net/runelite/client/RuneLite.java b/runelite-client/src/main/java/net/runelite/client/RuneLite.java index 9312cce4b7..0441ad97e0 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuneLite.java +++ b/runelite-client/src/main/java/net/runelite/client/RuneLite.java @@ -30,6 +30,7 @@ import com.google.gson.Gson; import java.awt.AWTException; import java.awt.Image; import java.awt.SystemTray; +import java.awt.Toolkit; import java.awt.TrayIcon; import java.io.File; import java.io.FileInputStream; @@ -326,6 +327,17 @@ public class RuneLite return trayIcon; } + public void notify(String message) + { + notify(message, TrayIcon.MessageType.NONE); + } + + public void notify(String message, TrayIcon.MessageType type) + { + getTrayIcon().displayMessage("RuneLite", message, type); + Toolkit.getDefaultToolkit().beep(); + } + public AccountSession getAccountSession() { return accountSession; 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 d39d4f44fa..fd3ac56f3e 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 @@ -36,6 +36,7 @@ import net.runelite.client.plugins.account.AccountPlugin; import net.runelite.client.plugins.boosts.Boosts; import net.runelite.client.plugins.bosstimer.BossTimers; import net.runelite.client.plugins.clanchat.ClanChat; +import net.runelite.client.plugins.combatnotifier.CombatNotifier; import net.runelite.client.plugins.config.ConfigPlugin; import net.runelite.client.plugins.devtools.DevTools; import net.runelite.client.plugins.fpsinfo.FPS; @@ -85,6 +86,7 @@ public class PluginManager plugins.add(new GroundItems()); plugins.add(new Implings()); plugins.add(new XpGlobes()); + plugins.add(new CombatNotifier()); if (RuneLite.getOptions().has("developer-mode")) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/combatnotifier/CombatNotifier.java b/runelite-client/src/main/java/net/runelite/client/plugins/combatnotifier/CombatNotifier.java new file mode 100644 index 0000000000..876e1fc425 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/combatnotifier/CombatNotifier.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2017, Kronos + * 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.combatnotifier; + +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.plugins.Plugin; + +import java.awt.*; +import java.time.Duration; +import java.time.Instant; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class CombatNotifier extends Plugin +{ + private static final int CHECK_INTERVAL = 1; + + private final Client client = RuneLite.getClient(); + private final RuneLite runelite = RuneLite.getRunelite(); + private final CombatNotifierConfig config = runelite.getConfigManager() + .getConfig(CombatNotifierConfig.class); + + private ScheduledFuture future; + private Instant lastInteracting; + + @Override + protected void startUp() throws Exception + { + ScheduledExecutorService executor = RuneLite.getRunelite().getExecutor(); + future = executor.scheduleAtFixedRate(this::checkIdle, CHECK_INTERVAL, CHECK_INTERVAL, TimeUnit.SECONDS); + } + + @Override + protected void shutDown() throws Exception + { + future.cancel(true); + } + + private void checkIdle() + { + if (client.getGameState() != GameState.LOGGED_IN || !config.isEnabled()) + { + return; + } + + Player local = client.getLocalPlayer(); + Actor opponent = local.getInteracting(); + if (opponent != null && opponent.getCombatLevel() > 0) + { + lastInteracting = Instant.now(); + } + + Duration waitDuration = Duration.ofMillis(config.getTimeout()); + if (lastInteracting != null && Instant.now().compareTo(lastInteracting.plus(waitDuration)) >= 0) + { + runelite.notify("[" + local.getName() + "] is now out of combat!"); + lastInteracting = null; + } + } + +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/combatnotifier/CombatNotifierConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/combatnotifier/CombatNotifierConfig.java new file mode 100644 index 0000000000..1c9d14429e --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/combatnotifier/CombatNotifierConfig.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2017, Kronos + * 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.combatnotifier; + +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup( + keyName = "combatnotifier", + name = "Combat Notifier", + description = "Notifies when the player is out of combat" +) +public interface CombatNotifierConfig +{ + @ConfigItem( + keyName = "enabled", + name = "Enabled", + description = "Toggles out of combat notifications" + ) + default boolean isEnabled() + { + return false; + } + + @ConfigItem( + keyName = "timeout", + name = "Idle Timeout (ms)", + description = "The notification delay after the player is out of combat" + ) + default int getTimeout() + { + return 10000; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifier.java b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifier.java index b51a1beab7..5dd8b725e9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifier.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifier.java @@ -35,6 +35,7 @@ import java.util.concurrent.TimeUnit; import static net.runelite.api.AnimationID.*; import net.runelite.api.Client; import net.runelite.api.GameState; +import net.runelite.api.Player; import net.runelite.client.RuneLite; import net.runelite.client.events.AnimationChanged; import net.runelite.client.plugins.Plugin; @@ -46,6 +47,7 @@ public class IdleNotifier extends Plugin private static final Duration WAIT_DURATION = Duration.ofMillis(2500L); private final Client client = RuneLite.getClient(); + private final RuneLite runelite = RuneLite.getRunelite(); private final TrayIcon trayIcon = RuneLite.getTrayIcon(); private ScheduledFuture future; @@ -55,7 +57,7 @@ public class IdleNotifier extends Plugin @Override protected void startUp() throws Exception { - ScheduledExecutorService executor = RuneLite.getRunelite().getExecutor(); + ScheduledExecutorService executor = runelite.getExecutor(); future = executor.scheduleAtFixedRate(this::checkIdle, CHECK_INTERVAL, CHECK_INTERVAL, TimeUnit.SECONDS); } @@ -148,16 +150,11 @@ public class IdleNotifier extends Plugin private void checkIdle() { - if (notifyIdle && client.getLocalPlayer().getAnimation() == IDLE + Player local = client.getLocalPlayer(); + if (notifyIdle && local.getAnimation() == IDLE && Instant.now().compareTo(lastAnimating.plus(WAIT_DURATION)) >= 0) { - trayIcon.displayMessage("RuneLite", "You are now idle.", TrayIcon.MessageType.NONE); - - if (OPERATING_SYSTEM.startsWith("Windows")) - { - Toolkit.getDefaultToolkit().beep(); - } - + runelite.notify("[" + local.getName() + "] is now idle!"); notifyIdle = false; } }