Merge pull request #7477 from Abextm/farming-conservative

farming: Give a more conservative estimate of when patches are done
This commit is contained in:
Adam
2019-01-26 11:55:45 -05:00
committed by GitHub
3 changed files with 161 additions and 143 deletions

View File

@@ -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<TimeablePanel<FarmingPatch>> patchPanels;
FarmingTabPanel(Client client, ItemManager itemManager, ConfigManager configManager,
TimeTrackingConfig config, Set<FarmingPatch> patches)
FarmingTabPanel(
FarmingTracker farmingTracker,
ItemManager itemManager,
TimeTrackingConfig config,
Set<FarmingPatch> 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<FarmingPatch> 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
{

View File

@@ -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;

View File

@@ -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;
}