diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/farming/FarmingTabPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/farming/FarmingTabPanel.java index aacbb6636b..2c262111e2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/farming/FarmingTabPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/farming/FarmingTabPanel.java @@ -35,9 +35,6 @@ import java.util.Set; import javax.swing.JLabel; import javax.swing.border.EmptyBorder; import lombok.extern.slf4j.Slf4j; -import net.runelite.api.Client; -import net.runelite.api.vars.Autoweed; -import net.runelite.client.config.ConfigManager; import net.runelite.client.game.ItemManager; import net.runelite.client.plugins.timetracking.TabContentPanel; import net.runelite.client.plugins.timetracking.TimeTrackingConfig; @@ -48,18 +45,20 @@ import net.runelite.client.ui.FontManager; @Slf4j public class FarmingTabPanel extends TabContentPanel { - private final Client client; + private final FarmingTracker farmingTracker; private final ItemManager itemManager; - private final ConfigManager configManager; private final TimeTrackingConfig config; private final List> patchPanels; - FarmingTabPanel(Client client, ItemManager itemManager, ConfigManager configManager, - TimeTrackingConfig config, Set patches) + FarmingTabPanel( + FarmingTracker farmingTracker, + ItemManager itemManager, + TimeTrackingConfig config, + Set patches + ) { - this.client = client; + this.farmingTracker = farmingTracker; this.itemManager = itemManager; - this.configManager = configManager; this.config = config; this.patchPanels = new ArrayList<>(); @@ -126,41 +125,13 @@ public class FarmingTabPanel extends TabContentPanel public void update() { long unixNow = Instant.now().getEpochSecond(); - log.debug("Updating panel with username {}", client.getUsername()); - - boolean autoweed; - { - String group = TimeTrackingConfig.CONFIG_GROUP + "." + client.getUsername(); - autoweed = Integer.toString(Autoweed.ON.ordinal()) - .equals(configManager.getConfiguration(group, TimeTrackingConfig.AUTOWEED)); - } for (TimeablePanel panel : patchPanels) { FarmingPatch patch = panel.getTimeable(); - String group = TimeTrackingConfig.CONFIG_GROUP + "." + client.getUsername() + "." + patch.getRegion().getRegionID(); - String key = Integer.toString(patch.getVarbit().getId()); - String storedValue = configManager.getConfiguration(group, key); - long unixTime = 0; - int value = 0; - if (storedValue != null) - { - String[] parts = storedValue.split(":"); - if (parts.length == 2) - { - try - { - value = Integer.parseInt(parts[0]); - unixTime = Long.parseLong(parts[1]); - } - catch (NumberFormatException e) - { - } - } - } + PatchPrediction prediction = farmingTracker.predictPatch(patch); - PatchState state = unixTime <= 0 ? null : patch.getImplementation().forVarbitValue(value); - if (state == null) + if (prediction == null) { itemManager.getImage(Produce.WEEDS.getItemID()).addTo(panel.getIcon()); panel.getIcon().setToolTipText("Unknown state"); @@ -172,84 +143,47 @@ public class FarmingTabPanel extends TabContentPanel } else { - if (state.getProduce().getItemID() < 0) + if (prediction.getProduce().getItemID() < 0) { panel.getIcon().setIcon(null); panel.getIcon().setToolTipText("Unknown state"); } else { - itemManager.getImage(state.getProduce().getItemID()).addTo(panel.getIcon()); - panel.getIcon().setToolTipText(state.getProduce().getName()); + itemManager.getImage(prediction.getProduce().getItemID()).addTo(panel.getIcon()); + panel.getIcon().setToolTipText(prediction.getProduce().getName()); } - int stage = state.getStage(); - int stages = state.getStages(); - int tickrate = state.getTickRate() * 60; - - if (autoweed && state.getProduce() == Produce.WEEDS) + switch (prediction.getCropState()) { - stage = 0; - stages = 1; - tickrate = 0; - } - if (tickrate > 0) - { - long tickNow = unixNow / tickrate; - long tickTime = unixTime / tickrate; - int delta = (int) (tickNow - tickTime); - - long doneEstimate = ((stages - 1 - stage) + tickTime) * tickrate; - - stage += delta; - if (stage >= stages) - { - stage = stages - 1; - } - - if (doneEstimate < unixNow) - { + case HARVESTABLE: panel.getEstimate().setText("Done"); - } - else - { - panel.getEstimate().setText("Done " + getFormattedEstimate(doneEstimate - unixNow, config.estimateRelative())); - } - } - else - { - switch (state.getCropState()) - { - case HARVESTABLE: + break; + case GROWING: + if (prediction.getDoneEstimate() < unixNow) + { panel.getEstimate().setText("Done"); - break; - case GROWING: - if (stage == stages - 1) - { - panel.getEstimate().setText("Done"); - } - else - { - panel.getEstimate().setText("Unknown"); - } - break; - case DISEASED: - panel.getEstimate().setText("Diseased"); - break; - case DEAD: - panel.getEstimate().setText("Dead"); - break; - } + } + else + { + panel.getEstimate().setText("Done " + getFormattedEstimate(prediction.getDoneEstimate() - unixNow, config.estimateRelative())); + } + break; + case DISEASED: + panel.getEstimate().setText("Diseased"); + break; + case DEAD: + panel.getEstimate().setText("Dead"); + break; } /* Hide any fully grown weeds' progress bar. */ - if (state.getProduce() != Produce.WEEDS - || (state.getProduce() == Produce.WEEDS && !autoweed && stage < stages - 1)) + if (prediction.getProduce() != Produce.WEEDS || prediction.getStage() < prediction.getStages() - 1) { panel.getProgress().setVisible(true); - panel.getProgress().setForeground(state.getCropState().getColor().darker()); - panel.getProgress().setMaximumValue(stages - 1); - panel.getProgress().setValue(stage); + panel.getProgress().setForeground(prediction.getCropState().getColor().darker()); + panel.getProgress().setMaximumValue(prediction.getStages() - 1); + panel.getProgress().setValue(prediction.getStage()); } else { 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 9513c684da..aa4027b98e 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 @@ -30,9 +30,11 @@ import java.time.Instant; import java.util.EnumMap; import java.util.Map; import java.util.Set; +import javax.annotation.Nullable; import net.runelite.api.Client; import net.runelite.api.Varbits; import net.runelite.api.coords.WorldPoint; +import net.runelite.api.vars.Autoweed; import net.runelite.client.config.ConfigManager; import net.runelite.client.game.ItemManager; import net.runelite.client.plugins.timetracking.SummaryState; @@ -70,7 +72,7 @@ public class FarmingTracker public FarmingTabPanel createTabPanel(Tab tab) { - return new FarmingTabPanel(client, itemManager, configManager, config, farmingWorld.getTabs().get(tab)); + return new FarmingTabPanel(this, itemManager, config, farmingWorld.getTabs().get(tab)); } /** @@ -140,6 +142,87 @@ public class FarmingTracker return changed; } + @Nullable + public PatchPrediction predictPatch(FarmingPatch patch) + { + long unixNow = Instant.now().getEpochSecond(); + + boolean autoweed; + { + String group = TimeTrackingConfig.CONFIG_GROUP + "." + client.getUsername(); + autoweed = Integer.toString(Autoweed.ON.ordinal()) + .equals(configManager.getConfiguration(group, TimeTrackingConfig.AUTOWEED)); + } + + String group = TimeTrackingConfig.CONFIG_GROUP + "." + client.getUsername() + "." + patch.getRegion().getRegionID(); + String key = Integer.toString(patch.getVarbit().getId()); + String storedValue = configManager.getConfiguration(group, key); + + if (storedValue == null) + { + return null; + } + + long unixTime = 0; + int value = 0; + { + String[] parts = storedValue.split(":"); + if (parts.length == 2) + { + try + { + value = Integer.parseInt(parts[0]); + unixTime = Long.parseLong(parts[1]); + } + catch (NumberFormatException e) + { + } + } + } + + if (unixTime <= 0) + { + return null; + } + + PatchState state = patch.getImplementation().forVarbitValue(value); + + int stage = state.getStage(); + int stages = state.getStages(); + int tickrate = state.getTickRate() * 60; + + if (autoweed && state.getProduce() == Produce.WEEDS) + { + stage = 0; + stages = 1; + tickrate = 0; + } + + long doneEstimate = 0; + if (tickrate > 0) + { + long tickNow = (unixNow + (5 * 60)) / tickrate; + long tickTime = (unixTime + (5 * 60)) / tickrate; + int delta = (int) (tickNow - tickTime); + + doneEstimate = ((stages - 1 - stage) + tickTime) * tickrate + (5 * 60); + + stage += delta; + if (stage >= stages) + { + stage = stages - 1; + } + } + + return new PatchPrediction( + state.getProduce(), + state.getCropState(), + doneEstimate, + stage, + stages + ); + } + public void loadCompletionTimes() { summaries.clear(); @@ -179,57 +262,21 @@ public class FarmingTracker for (FarmingPatch patch : tab.getValue()) { - String group = TimeTrackingConfig.CONFIG_GROUP + "." + client.getUsername() + "." + patch.getRegion().getRegionID(); - String key = Integer.toString(patch.getVarbit().getId()); - String storedValue = configManager.getConfiguration(group, key); - long unixTime = 0; - int value = 0; - - if (storedValue != null) - { - String[] parts = storedValue.split(":"); - if (parts.length == 2) - { - try - { - value = Integer.parseInt(parts[0]); - unixTime = Long.parseLong(parts[1]); - } - catch (NumberFormatException e) - { - // ignored - } - } - } - - PatchState state = unixTime <= 0 ? null : patch.getImplementation().forVarbitValue(value); - if (state == null || state.getProduce().getItemID() < 0) + PatchPrediction prediction = predictPatch(patch); + if (prediction == null || prediction.getProduce().getItemID() < 0) { continue; // unknown state } - int tickrate = state.getTickRate() * 60; - int stage = state.getStage(); - int stages = state.getStages(); + allUnknown = false; - if (state.getProduce() != Produce.WEEDS && state.getProduce() != Produce.SCARECROW) + if (prediction.getProduce() != Produce.WEEDS && prediction.getProduce() != Produce.SCARECROW) { allEmpty = false; // update max duration if this patch takes longer to grow - if (tickrate > 0) - { - long tickTime = unixTime / tickrate; - long doneEstimate = ((stages - 1 - stage) + tickTime) * tickrate; - maxCompletionTime = Math.max(maxCompletionTime, doneEstimate); - } - else if (state.getCropState() == CropState.GROWING && stage != stages - 1) - { - continue; // unknown state - } + maxCompletionTime = Math.max(maxCompletionTime, prediction.getDoneEstimate()); } - - allUnknown = false; } final SummaryState state; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/farming/PatchPrediction.java b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/farming/PatchPrediction.java new file mode 100644 index 0000000000..9a2b98aeab --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/farming/PatchPrediction.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018 Abex + * 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 lombok.Value; + +@Value +class PatchPrediction +{ + private final Produce produce; + private final CropState cropState; + private final long doneEstimate; + private final int stage; + private final int stages; +}