farming: Centralize patch prediction

This commit is contained in:
Max Weber
2019-01-20 19:31:01 -07:00
parent 1c78fc528b
commit c71682d28b
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.JLabel;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import lombok.extern.slf4j.Slf4j; 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.game.ItemManager;
import net.runelite.client.plugins.timetracking.TabContentPanel; import net.runelite.client.plugins.timetracking.TabContentPanel;
import net.runelite.client.plugins.timetracking.TimeTrackingConfig; import net.runelite.client.plugins.timetracking.TimeTrackingConfig;
@@ -48,18 +45,20 @@ import net.runelite.client.ui.FontManager;
@Slf4j @Slf4j
public class FarmingTabPanel extends TabContentPanel public class FarmingTabPanel extends TabContentPanel
{ {
private final Client client; private final FarmingTracker farmingTracker;
private final ItemManager itemManager; private final ItemManager itemManager;
private final ConfigManager configManager;
private final TimeTrackingConfig config; private final TimeTrackingConfig config;
private final List<TimeablePanel<FarmingPatch>> patchPanels; private final List<TimeablePanel<FarmingPatch>> patchPanels;
FarmingTabPanel(Client client, ItemManager itemManager, ConfigManager configManager, FarmingTabPanel(
TimeTrackingConfig config, Set<FarmingPatch> patches) FarmingTracker farmingTracker,
ItemManager itemManager,
TimeTrackingConfig config,
Set<FarmingPatch> patches
)
{ {
this.client = client; this.farmingTracker = farmingTracker;
this.itemManager = itemManager; this.itemManager = itemManager;
this.configManager = configManager;
this.config = config; this.config = config;
this.patchPanels = new ArrayList<>(); this.patchPanels = new ArrayList<>();
@@ -126,41 +125,13 @@ public class FarmingTabPanel extends TabContentPanel
public void update() public void update()
{ {
long unixNow = Instant.now().getEpochSecond(); 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) for (TimeablePanel<FarmingPatch> panel : patchPanels)
{ {
FarmingPatch patch = panel.getTimeable(); FarmingPatch patch = panel.getTimeable();
String group = TimeTrackingConfig.CONFIG_GROUP + "." + client.getUsername() + "." + patch.getRegion().getRegionID(); PatchPrediction prediction = farmingTracker.predictPatch(patch);
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)
{
}
}
}
PatchState state = unixTime <= 0 ? null : patch.getImplementation().forVarbitValue(value); if (prediction == null)
if (state == null)
{ {
itemManager.getImage(Produce.WEEDS.getItemID()).addTo(panel.getIcon()); itemManager.getImage(Produce.WEEDS.getItemID()).addTo(panel.getIcon());
panel.getIcon().setToolTipText("Unknown state"); panel.getIcon().setToolTipText("Unknown state");
@@ -172,84 +143,47 @@ public class FarmingTabPanel extends TabContentPanel
} }
else else
{ {
if (state.getProduce().getItemID() < 0) if (prediction.getProduce().getItemID() < 0)
{ {
panel.getIcon().setIcon(null); panel.getIcon().setIcon(null);
panel.getIcon().setToolTipText("Unknown state"); panel.getIcon().setToolTipText("Unknown state");
} }
else else
{ {
itemManager.getImage(state.getProduce().getItemID()).addTo(panel.getIcon()); itemManager.getImage(prediction.getProduce().getItemID()).addTo(panel.getIcon());
panel.getIcon().setToolTipText(state.getProduce().getName()); panel.getIcon().setToolTipText(prediction.getProduce().getName());
} }
int stage = state.getStage(); switch (prediction.getCropState())
int stages = state.getStages();
int tickrate = state.getTickRate() * 60;
if (autoweed && state.getProduce() == Produce.WEEDS)
{ {
stage = 0; case HARVESTABLE:
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)
{
panel.getEstimate().setText("Done"); panel.getEstimate().setText("Done");
} break;
else case GROWING:
{ if (prediction.getDoneEstimate() < unixNow)
panel.getEstimate().setText("Done " + getFormattedEstimate(doneEstimate - unixNow, config.estimateRelative())); {
}
}
else
{
switch (state.getCropState())
{
case HARVESTABLE:
panel.getEstimate().setText("Done"); panel.getEstimate().setText("Done");
break; }
case GROWING: else
if (stage == stages - 1) {
{ panel.getEstimate().setText("Done " + getFormattedEstimate(prediction.getDoneEstimate() - unixNow, config.estimateRelative()));
panel.getEstimate().setText("Done"); }
} break;
else case DISEASED:
{ panel.getEstimate().setText("Diseased");
panel.getEstimate().setText("Unknown"); break;
} case DEAD:
break; panel.getEstimate().setText("Dead");
case DISEASED: break;
panel.getEstimate().setText("Diseased");
break;
case DEAD:
panel.getEstimate().setText("Dead");
break;
}
} }
/* Hide any fully grown weeds' progress bar. */ /* Hide any fully grown weeds' progress bar. */
if (state.getProduce() != Produce.WEEDS if (prediction.getProduce() != Produce.WEEDS || prediction.getStage() < prediction.getStages() - 1)
|| (state.getProduce() == Produce.WEEDS && !autoweed && stage < stages - 1))
{ {
panel.getProgress().setVisible(true); panel.getProgress().setVisible(true);
panel.getProgress().setForeground(state.getCropState().getColor().darker()); panel.getProgress().setForeground(prediction.getCropState().getColor().darker());
panel.getProgress().setMaximumValue(stages - 1); panel.getProgress().setMaximumValue(prediction.getStages() - 1);
panel.getProgress().setValue(stage); panel.getProgress().setValue(prediction.getStage());
} }
else else
{ {

View File

@@ -30,9 +30,11 @@ import java.time.Instant;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.annotation.Nullable;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.Varbits; import net.runelite.api.Varbits;
import net.runelite.api.coords.WorldPoint; import net.runelite.api.coords.WorldPoint;
import net.runelite.api.vars.Autoweed;
import net.runelite.client.config.ConfigManager; import net.runelite.client.config.ConfigManager;
import net.runelite.client.game.ItemManager; import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.timetracking.SummaryState; import net.runelite.client.plugins.timetracking.SummaryState;
@@ -70,7 +72,7 @@ public class FarmingTracker
public FarmingTabPanel createTabPanel(Tab tab) 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; 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 / tickrate;
long tickTime = unixTime / tickrate;
int delta = (int) (tickNow - tickTime);
doneEstimate = ((stages - 1 - stage) + tickTime) * tickrate;
stage += delta;
if (stage >= stages)
{
stage = stages - 1;
}
}
return new PatchPrediction(
state.getProduce(),
state.getCropState(),
doneEstimate,
stage,
stages
);
}
public void loadCompletionTimes() public void loadCompletionTimes()
{ {
summaries.clear(); summaries.clear();
@@ -179,57 +262,21 @@ public class FarmingTracker
for (FarmingPatch patch : tab.getValue()) for (FarmingPatch patch : tab.getValue())
{ {
String group = TimeTrackingConfig.CONFIG_GROUP + "." + client.getUsername() + "." + patch.getRegion().getRegionID(); PatchPrediction prediction = predictPatch(patch);
String key = Integer.toString(patch.getVarbit().getId()); if (prediction == null || prediction.getProduce().getItemID() < 0)
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)
{ {
continue; // unknown state continue; // unknown state
} }
int tickrate = state.getTickRate() * 60; allUnknown = false;
int stage = state.getStage();
int stages = state.getStages();
if (state.getProduce() != Produce.WEEDS && state.getProduce() != Produce.SCARECROW) if (prediction.getProduce() != Produce.WEEDS && prediction.getProduce() != Produce.SCARECROW)
{ {
allEmpty = false; allEmpty = false;
// update max duration if this patch takes longer to grow // update max duration if this patch takes longer to grow
if (tickrate > 0) maxCompletionTime = Math.max(maxCompletionTime, prediction.getDoneEstimate());
{
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
}
} }
allUnknown = false;
} }
final SummaryState state; 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;
}