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 71d09fc289..3d2fce1e5e 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 @@ -51,6 +51,7 @@ import net.runelite.client.plugins.mousehighlight.MouseHighlight; 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.woodcutting.WoodcuttingPlugin; import net.runelite.client.plugins.xpglobes.XpGlobes; import net.runelite.client.plugins.xptracker.XPTracker; import net.runelite.client.plugins.xtea.Xtea; @@ -95,6 +96,7 @@ public class PluginManager plugins.add(new XPTracker()); plugins.add(new ExaminePlugin()); plugins.add(new FishingPlugin()); + plugins.add(new WoodcuttingPlugin()); if (RuneLite.getOptions().has("developer-mode")) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingConfig.java new file mode 100644 index 0000000000..a89aa76338 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingConfig.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2017, Seth + * 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.woodcutting; + +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup( + keyName = "woodcutting", + name = "Woodcutting", + description = "Configuration for the woodcutting plugin" +) +public interface WoodcuttingConfig +{ + @ConfigItem( + keyName = "enabled", + name = "Enable", + description = "Configures whether the woodcutting plugin is displayed" + ) + default boolean enabled() + { + return true; + } + + @ConfigItem( + keyName = "statTimeout", + name = "Reset stats (minutes)", + description = "Configures the time until statistic is reset" + ) + default int statTimeout() + { + return 5; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingOverlay.java new file mode 100644 index 0000000000..fdcf274b17 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingOverlay.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2017, Seth + * 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.woodcutting; + +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.util.stream.IntStream; +import static net.runelite.api.AnimationID.*; +import net.runelite.api.Client; +import net.runelite.api.GameState; +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; + +class WoodcuttingOverlay extends Overlay +{ + private static final int WIDTH = 140; + + 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 BOTTOM_BORDER = 2; + private static final int SEPARATOR = 2; + + private static final Color BACKGROUND = new Color(Color.gray.getRed(), Color.gray.getGreen(), Color.gray.getBlue(), 127); + + private static final int[] animationIds = + { + WOODCUTTING_BRONZE, WOODCUTTING_IRON, WOODCUTTING_STEEL, WOODCUTTING_BLACK, + WOODCUTTING_MITHRIL, WOODCUTTING_ADAMANT, WOODCUTTING_RUNE, WOODCUTTING_DRAGON, + WOODCUTTING_INFERNAL + }; + + private final Client client = RuneLite.getClient(); + + private final WoodcuttingPlugin plugin; + private final WoodcuttingConfig config; + + public WoodcuttingOverlay(WoodcuttingPlugin plugin) + { + super(OverlayPosition.TOP_LEFT, OverlayPriority.LOW); + this.plugin = plugin; + this.config = plugin.getConfig(); + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (client.getGameState() != GameState.LOGGED_IN || !config.enabled()) + { + return null; + } + + WoodcuttingSession session = plugin.getSession(); + + if (session.getLastLogCut() == null) + { + return null; + } + + Duration statTimeout = Duration.ofMinutes(config.statTimeout()); + Duration sinceCut = Duration.between(session.getLastLogCut(), Instant.now()); + + if (sinceCut.compareTo(statTimeout) >= 0) + { + return null; + } + + FontMetrics metrics = graphics.getFontMetrics(); + + int height = TOP_BORDER + (metrics.getHeight() * 3) + SEPARATOR * 3 + BOTTOM_BORDER; + int y = TOP_BORDER + metrics.getHeight(); + + graphics.setColor(BACKGROUND); + graphics.fillRect(0, 0, WIDTH, height); + + if (IntStream.of(animationIds).anyMatch(x -> x == client.getLocalPlayer().getAnimation())) + { + graphics.setColor(Color.green); + String str = "You are woodcutting"; + graphics.drawString(str, (WIDTH - metrics.stringWidth(str)) / 2, y); + } + else + { + graphics.setColor(Color.red); + String str = "You are NOT woodcutting"; + graphics.drawString(str, (WIDTH - metrics.stringWidth(str)) / 2, y); + } + + y += metrics.getHeight() + SEPARATOR; + + graphics.setColor(Color.white); + graphics.drawString("Logs cut:", LEFT_BORDER, y); + + String totalCutStr = Integer.toString(session.getTotalCut()); + graphics.drawString(totalCutStr, WIDTH - RIGHT_BORDER - metrics.stringWidth(totalCutStr), y); + + y += metrics.getHeight() + SEPARATOR; + + graphics.drawString("Logs/hr:", LEFT_BORDER, y); + + String perHourStr; + if (session.getRecentCut() > 2) + { + perHourStr = Integer.toString(session.getPerHour()); + } + else + { + perHourStr = "~"; + } + graphics.drawString(perHourStr, WIDTH - RIGHT_BORDER - metrics.stringWidth(perHourStr), y); + + return new Dimension(WIDTH, height); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java new file mode 100644 index 0000000000..261a44932d --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2017, Seth + * 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.woodcutting; + +import com.google.common.eventbus.Subscribe; +import java.time.Duration; +import java.time.Instant; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import net.runelite.api.ChatMessageType; +import net.runelite.client.RuneLite; +import net.runelite.client.events.ChatMessage; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.ui.overlay.Overlay; + +public class WoodcuttingPlugin extends Plugin +{ + private static final int CHECK_INTERVAL = 1; + + private final RuneLite runelite = RuneLite.getRunelite(); + private final WoodcuttingConfig config = runelite.getConfigManager().getConfig(WoodcuttingConfig.class); + private final WoodcuttingOverlay overlay = new WoodcuttingOverlay(this); + + private WoodcuttingSession session = new WoodcuttingSession(); + private ScheduledFuture future; + + @Override + public Overlay getOverlay() + { + return overlay; + } + + @Override + protected void startUp() throws Exception + { + ScheduledExecutorService executor = runelite.getExecutor(); + future = executor.scheduleAtFixedRate(this::checkCutting, CHECK_INTERVAL, CHECK_INTERVAL, TimeUnit.SECONDS); + } + + @Override + protected void shutDown() throws Exception + { + future.cancel(true); + } + + public WoodcuttingConfig getConfig() + { + return config; + } + + public WoodcuttingSession getSession() + { + return session; + } + + @Subscribe + public void onChatMessage(ChatMessage event) + { + if (event.getType() != ChatMessageType.FILTERED) + { + return; + } + + if (event.getMessage().startsWith("You get some")) + { + session.incrementLogCut(); + } + } + + private void checkCutting() + { + Instant lastLogCut = session.getLastLogCut(); + if (lastLogCut == null) + { + return; + } + + // reset recentCut if you haven't cut anything recently + Duration statTimeout = Duration.ofMinutes(config.statTimeout()); + Duration sinceCut = Duration.between(lastLogCut, Instant.now()); + + if (sinceCut.compareTo(statTimeout) >= 0) + { + session.resetRecent(); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingSession.java b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingSession.java new file mode 100644 index 0000000000..6a86f1e05f --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingSession.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2017, Seth + * 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.woodcutting; + +import java.time.Duration; +import java.time.Instant; + +public class WoodcuttingSession +{ + private static final Duration HOUR = Duration.ofHours(1); + + private int perHour; + + private Instant lastLogCut; + private int totalCut; + + private Instant recentLogCut; + private int recentCut; + + public void incrementLogCut() + { + Instant now = Instant.now(); + + lastLogCut = now; + ++totalCut; + + if (recentCut == 0) + { + recentLogCut = now; + } + ++recentCut; + + Duration timeSinceStart = Duration.between(recentLogCut, now); + if (!timeSinceStart.isZero()) + { + perHour = (int) ((double) recentCut * (double) HOUR.toMillis() / (double) timeSinceStart.toMillis()); + } + } + + public void resetRecent() + { + recentLogCut = null; + recentCut = 0; + } + + public int getPerHour() + { + return perHour; + } + + public Instant getLastLogCut() + { + return lastLogCut; + } + + public int getTotalCut() + { + return totalCut; + } + + public Instant getRecentLogCut() + { + return recentLogCut; + } + + public int getRecentCut() + { + return recentCut; + } +}