diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierConfig.java index 2cc9b17989..062d8bc4ec 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierConfig.java @@ -53,11 +53,22 @@ public interface IdleNotifierConfig extends Config return true; } + @ConfigItem( + keyName = "logoutidle", + name = "Idle Logout Notifications", + description = "Configures if the idle logout notifications are enabled", + position = 3 + ) + default boolean logoutIdle() + { + return true; + } + @ConfigItem( keyName = "timeout", name = "Idle Notification Delay (ms)", description = "The notification delay after the player is idle", - position = 3 + position = 4 ) default int getIdleNotificationDelay() { @@ -68,7 +79,7 @@ public interface IdleNotifierConfig extends Config keyName = "hitpoints", name = "Hitpoints Notification Threshold", description = "The amount of hitpoints to send a notification at. A value of 0 will disable notification.", - position = 4 + position = 5 ) default int getHitpointsThreshold() { @@ -79,7 +90,7 @@ public interface IdleNotifierConfig extends Config keyName = "prayer", name = "Prayer Notification Threshold", description = "The amount of prayer points to send a notification at. A value of 0 will disable notification.", - position = 5 + position = 6 ) default int getPrayerThreshold() { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java index 9378f6e9de..f2c704a734 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java @@ -37,6 +37,7 @@ import net.runelite.api.AnimationID; import static net.runelite.api.AnimationID.*; import net.runelite.api.Client; import net.runelite.api.GameState; +import net.runelite.api.Hitsplat; import net.runelite.api.NPC; import net.runelite.api.NPCComposition; import net.runelite.api.Player; @@ -45,6 +46,7 @@ import net.runelite.api.Varbits; import net.runelite.api.events.AnimationChanged; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameTick; +import net.runelite.api.events.HitsplatApplied; import net.runelite.api.events.InteractingChanged; import net.runelite.client.Notifier; import net.runelite.client.config.ConfigManager; @@ -58,7 +60,9 @@ import net.runelite.client.plugins.PluginDescriptor; ) public class IdleNotifierPlugin extends Plugin { - private static final int LOGOUT_WARNING_AFTER_TICKS = 14000; // 4 minutes and 40 seconds + private static final int LOGOUT_WARNING_AFTER_TICKS = 280 * 50; // 4 minutes and 40 seconds + private static final int LOGOUT_WARNING_AFTER_TICKS_IN_COMBAT = 1140 * 50; // 19 minutes + private static final int HIGHEST_MONSTER_ATTACK_SPEED = 8; // Except Scarab Mage, but they are with other monsters private static final Duration SIX_HOUR_LOGOUT_WARNING_AFTER_DURATION = Duration.ofMinutes(340); @Inject @@ -78,7 +82,7 @@ public class IdleNotifierPlugin extends Plugin private boolean notifyPrayer = true; private boolean notifyIdleLogout = true; private boolean notify6HourLogout = true; - + private int lastCombatCountdown = 0; private Instant sixHourWarningTime; private boolean ready; @@ -275,11 +279,29 @@ public class IdleNotifierPlugin extends Plugin } } + @Subscribe + public void onHitsplatApplied(HitsplatApplied event) + { + if (event.getActor() != client.getLocalPlayer()) + { + return; + } + + final Hitsplat hitsplat = event.getHitsplat(); + + if (hitsplat.getHitsplatType() == Hitsplat.HitsplatType.DAMAGE + || hitsplat.getHitsplatType() == Hitsplat.HitsplatType.BLOCK) + { + lastCombatCountdown = HIGHEST_MONSTER_ATTACK_SPEED; + } + } + @Subscribe public void onGameTick(GameTick event) { final Player local = client.getLocalPlayer(); final Duration waitDuration = Duration.ofMillis(config.getIdleNotificationDelay()); + lastCombatCountdown = Math.max(lastCombatCountdown - 1, 0); if (client.getGameState() != GameState.LOGGED_IN || local == null || client.getMouseIdleTicks() < 10) { @@ -287,7 +309,7 @@ public class IdleNotifierPlugin extends Plugin return; } - if (checkIdleLogout()) + if (config.logoutIdle() && checkIdleLogout()) { notifier.notify("[" + local.getName() + "] is about to log out from idling too long!"); } @@ -399,7 +421,16 @@ public class IdleNotifierPlugin extends Plugin if (client.getMouseIdleTicks() > LOGOUT_WARNING_AFTER_TICKS && client.getKeyboardIdleTicks() > LOGOUT_WARNING_AFTER_TICKS) { - if (notifyIdleLogout) + if (lastCombatCountdown > 0) + { + if (client.getMouseIdleTicks() > LOGOUT_WARNING_AFTER_TICKS_IN_COMBAT + && client.getKeyboardIdleTicks() > LOGOUT_WARNING_AFTER_TICKS_IN_COMBAT && notifyIdleLogout) + { + notifyIdleLogout = false; + return true; + } + } + else if (notifyIdleLogout) { notifyIdleLogout = false; return true; @@ -466,6 +497,9 @@ public class IdleNotifierPlugin extends Plugin { final Player local = client.getLocalPlayer(); + // Reset combat idle timer + lastCombatCountdown = 0; + // Reset animation idle timer lastAnimating = null; if (client.getGameState() == GameState.LOGIN_SCREEN || local == null || local.getAnimation() != lastAnimation) diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPluginTest.java index dc787ce1f8..4b270f3abf 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPluginTest.java @@ -31,12 +31,14 @@ import com.google.inject.testing.fieldbinder.BoundFieldModule; import net.runelite.api.AnimationID; import net.runelite.api.Client; import net.runelite.api.GameState; +import net.runelite.api.Hitsplat; import net.runelite.api.NPC; import net.runelite.api.NPCComposition; import net.runelite.api.Player; import net.runelite.api.events.AnimationChanged; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameTick; +import net.runelite.api.events.HitsplatApplied; import net.runelite.api.events.InteractingChanged; import net.runelite.client.Notifier; import org.junit.Before; @@ -102,6 +104,7 @@ public class IdleNotifierPluginTest when(client.getLocalPlayer()).thenReturn(player); // Mock config + when(config.logoutIdle()).thenReturn(true); when(config.animationIdle()).thenReturn(true); when(config.combatIdle()).thenReturn(true); when(config.getIdleNotificationDelay()).thenReturn(0); @@ -223,4 +226,19 @@ public class IdleNotifierPluginTest plugin.onGameTick(new GameTick()); verify(notifier, times(0)).notify(any()); } + + @Test + public void checkCombatLogoutIdle() + { + // Player is idle + when(client.getMouseIdleTicks()).thenReturn(282 * 50); + + // But player is being damaged (is in combat) + final HitsplatApplied hitsplatApplied = new HitsplatApplied(); + hitsplatApplied.setActor(player); + hitsplatApplied.setHitsplat(new Hitsplat(Hitsplat.HitsplatType.DAMAGE, 0, 0)); + plugin.onHitsplatApplied(hitsplatApplied); + plugin.onGameTick(new GameTick()); + verify(notifier, times(0)).notify(any()); + } } \ No newline at end of file