From 525c64b8dfa239b9bba5e8e7e12ee8684ac130ef Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 9 Feb 2021 11:43:12 -0500 Subject: [PATCH] farming tracker: don't send notifications for empty crop state --- .../timetracking/farming/FarmingTracker.java | 168 ++++++++++-------- .../farming/FarmingTrackerTest.java | 132 ++++++++++++++ 2 files changed, 221 insertions(+), 79 deletions(-) create mode 100644 runelite-client/src/test/java/net/runelite/client/plugins/timetracking/farming/FarmingTrackerTest.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/farming/FarmingTracker.java b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/farming/FarmingTracker.java index e01c451b8d..4a381220b2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/farming/FarmingTracker.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/farming/FarmingTracker.java @@ -24,6 +24,7 @@ */ package net.runelite.client.plugins.timetracking.farming; +import com.google.common.annotations.VisibleForTesting; import com.google.inject.Inject; import com.google.inject.Singleton; import java.time.Instant; @@ -500,14 +501,12 @@ public class FarmingTracker Integer offsetPrecisionMins = configManager.getConfiguration(TimeTrackingConfig.CONFIG_GROUP, profile.getKey(), TimeTrackingConfig.FARM_TICK_OFFSET_PRECISION, int.class); Integer offsetTimeMins = configManager.getConfiguration(TimeTrackingConfig.CONFIG_GROUP, profile.getKey(), TimeTrackingConfig.FARM_TICK_OFFSET, int.class); - RuneScapeProfileType profileType = profile.getType(); - for (Map.Entry> tab : farmingWorld.getTabs().entrySet()) { for (FarmingPatch patch : tab.getValue()) { ProfilePatch profilePatch = new ProfilePatch(patch, profile.getKey()); - boolean patchNotified = (wasNotified.get(profilePatch) != null ? wasNotified.get(profilePatch) : false); + boolean patchNotified = wasNotified.getOrDefault(profilePatch, false); String configKey = patch.notifyConfigKey(); boolean shouldNotify = Boolean.TRUE .equals(configManager.getConfiguration(TimeTrackingConfig.CONFIG_GROUP, profile.getKey(), configKey, Boolean.class)); @@ -519,94 +518,105 @@ public class FarmingTracker } int tickRate = prediction.getProduce().getTickrate(); - + if (offsetPrecisionMins == null || offsetTimeMins == null || (offsetPrecisionMins < tickRate && offsetPrecisionMins < 40) || prediction.getProduce() == Produce.WEEDS - || unixNow <= prediction.getDoneEstimate() || patchNotified || prediction.getCropState() == CropState.FILLING) + || unixNow <= prediction.getDoneEstimate() || patchNotified || prediction.getCropState() == CropState.FILLING || prediction.getCropState() == CropState.EMPTY) { continue; } wasNotified.put(profilePatch, true); - if (!firstNotifyCheck && shouldNotify) + if (!firstNotifyCheck && shouldNotify) { - final StringBuilder notificationStringBuilder = new StringBuilder(); - // Same RS account - if (client.getGameState() == GameState.LOGGED_IN && profile.getDisplayName().equals(client.getLocalPlayer().getName())) - { - // Same RS account but different profile type - if (profileType != RuneScapeProfileType.getCurrent(client)) - { - notificationStringBuilder.append("(") - .append(Text.titleCase(profile.getType())) - .append(") "); - } - // Same RS account AND profile falls through here so no bracketed prefix is added - } - else - { - // Different RS account AND profile type - if (profileType != RuneScapeProfileType.getCurrent(client) || client.getGameState() == GameState.LOGIN_SCREEN) - { - //Don't print profile type when logged out if is STANDARD - if (client.getGameState() == GameState.LOGIN_SCREEN && profileType == RuneScapeProfileType.STANDARD) - { - notificationStringBuilder.append("(") - .append(profile.getDisplayName()) - .append(") "); - } - else - { - notificationStringBuilder.append("(") - .append(profile.getDisplayName()) - .append(" - ") - .append(Text.titleCase(profile.getType())) - .append(") "); - } - } - // Different RS account but same profile type - else - { - notificationStringBuilder.append("(") - .append(profile.getDisplayName()) - .append(") "); - } - } - - notificationStringBuilder - .append("Your ") - .append(prediction.getProduce().getName()); - - switch (prediction.getCropState()) - { - case HARVESTABLE: - case GROWING: - if (prediction.getProduce().getName().toLowerCase(Locale.ENGLISH).contains("compost")) - { - notificationStringBuilder.append(" is ready to collect in "); - } - else - { - notificationStringBuilder.append(" is ready to harvest in "); - } - break; - case DISEASED: - notificationStringBuilder.append(" has become diseased in "); - break; - case DEAD: - notificationStringBuilder.append(" has died in "); - break; - } - - notificationStringBuilder.append(patch.getRegion().isDefinite() ? "the " : "") - .append(patch.getRegion().getName()) - .append("."); - - notifier.notify(notificationStringBuilder.toString()); + sendNotification(profile, prediction, patch); } } } } firstNotifyCheck = false; } + + @VisibleForTesting + void sendNotification(RuneScapeProfile profile, PatchPrediction prediction, FarmingPatch patch) + { + final RuneScapeProfileType profileType = profile.getType(); + + final StringBuilder stringBuilder = new StringBuilder(); + // Same RS account + if (client.getGameState() == GameState.LOGGED_IN && profile.getDisplayName().equals(client.getLocalPlayer().getName())) + { + // Same RS account but different profile type + if (profileType != RuneScapeProfileType.getCurrent(client)) + { + stringBuilder.append("(") + .append(Text.titleCase(profile.getType())) + .append(") "); + } + // Same RS account AND profile falls through here so no bracketed prefix is added + } + else + { + // Different RS account AND profile type + if (profileType != RuneScapeProfileType.getCurrent(client) || client.getGameState() == GameState.LOGIN_SCREEN) + { + //Don't print profile type when logged out if is STANDARD + if (client.getGameState() == GameState.LOGIN_SCREEN && profileType == RuneScapeProfileType.STANDARD) + { + stringBuilder.append("(") + .append(profile.getDisplayName()) + .append(") "); + } + else + { + stringBuilder.append("(") + .append(profile.getDisplayName()) + .append(" - ") + .append(Text.titleCase(profile.getType())) + .append(") "); + } + } + // Different RS account but same profile type + else + { + stringBuilder.append("(") + .append(profile.getDisplayName()) + .append(") "); + } + } + + stringBuilder + .append("Your ") + .append(prediction.getProduce().getName()); + + switch (prediction.getCropState()) + { + case HARVESTABLE: + case GROWING: + if (prediction.getProduce().getName().toLowerCase(Locale.ENGLISH).contains("compost")) + { + stringBuilder.append(" is ready to collect in "); + } + else + { + stringBuilder.append(" is ready to harvest in "); + } + break; + case DISEASED: + stringBuilder.append(" has become diseased in "); + break; + case DEAD: + stringBuilder.append(" has died in "); + break; + default: + // EMPTY and FILLING are caught above + throw new IllegalStateException(); + } + + stringBuilder.append(patch.getRegion().isDefinite() ? "the " : "") + .append(patch.getRegion().getName()) + .append("."); + + notifier.notify(stringBuilder.toString()); + } } diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/timetracking/farming/FarmingTrackerTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/timetracking/farming/FarmingTrackerTest.java new file mode 100644 index 0000000000..f407fd0a34 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/timetracking/farming/FarmingTrackerTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2021, 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.timetracking.farming; + +import com.google.inject.Guice; +import com.google.inject.Inject; +import com.google.inject.testing.fieldbinder.Bind; +import com.google.inject.testing.fieldbinder.BoundFieldModule; +import java.util.EnumSet; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.Player; +import net.runelite.api.Varbits; +import net.runelite.api.WorldType; +import net.runelite.client.Notifier; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.config.RuneScapeProfile; +import net.runelite.client.config.RuneScapeProfileType; +import net.runelite.client.game.ItemManager; +import net.runelite.client.plugins.timetracking.TimeTrackingConfig; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class FarmingTrackerTest +{ + @Inject + private FarmingTracker farmingTracker; + + @Mock + @Bind + private Client client; + + @Mock + @Bind + private ItemManager itemManager; + + @Mock + @Bind + private ConfigManager configManager; + + @Mock + @Bind + private TimeTrackingConfig config; + + @Mock + @Bind + private FarmingWorld farmingWorld; + + @Mock + @Bind + private Notifier notifier; + + @Before + public void before() + { + Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this); + + when(client.getGameState()).thenReturn(GameState.LOGGED_IN); + when(client.getWorldType()).thenReturn(EnumSet.noneOf(WorldType.class)); + + Player player = mock(Player.class); + when(player.getName()).thenReturn("Adam"); + when(client.getLocalPlayer()).thenReturn(player); + } + + @Test(expected = IllegalStateException.class) + public void testEmptyNotification() + { + RuneScapeProfile runeScapeProfile = new RuneScapeProfile("Adam", RuneScapeProfileType.STANDARD, null, null); + + PatchPrediction patchPrediction = new PatchPrediction(Produce.EMPTY_COMPOST_BIN, CropState.EMPTY, 0L, 0, 0); + FarmingRegion region = new FarmingRegion("Ardougne", 10548, false, + new FarmingPatch("North", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT), + new FarmingPatch("South", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT), + new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER), + new FarmingPatch("", Varbits.FARMING_4774, PatchImplementation.HERB), + new FarmingPatch("", Varbits.FARMING_4775, PatchImplementation.COMPOST) + ); + FarmingPatch patch = region.getPatches()[4]; + patch.setRegion(region); + farmingTracker.sendNotification(runeScapeProfile, patchPrediction, patch); + } + + @Test + public void testHarvestableNotification() + { + RuneScapeProfile runeScapeProfile = new RuneScapeProfile("Adam", RuneScapeProfileType.STANDARD, null, null); + + PatchPrediction patchPrediction = new PatchPrediction(Produce.RANARR, CropState.HARVESTABLE, 0L, 0, 0); + FarmingRegion region = new FarmingRegion("Ardougne", 10548, false, + new FarmingPatch("North", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT), + new FarmingPatch("South", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT), + new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER), + new FarmingPatch("", Varbits.FARMING_4774, PatchImplementation.HERB), + new FarmingPatch("", Varbits.FARMING_4775, PatchImplementation.COMPOST) + ); + FarmingPatch patch = region.getPatches()[3]; + patch.setRegion(region); + farmingTracker.sendNotification(runeScapeProfile, patchPrediction, patch); + + verify(notifier).notify("Your Ranarr is ready to harvest in Ardougne."); + } +} \ No newline at end of file