Add FarmingTracker plugin

With help from NotFoxtrot
This commit is contained in:
Max Weber
2018-04-21 08:56:35 -06:00
committed by Adam
parent 7645d6a04f
commit 7eabc16806
17 changed files with 3738 additions and 1 deletions

View File

@@ -310,7 +310,36 @@ public enum Varbits
FAIR_RING_LAST_DESTINATION(5374),
FAIRY_RING_DIAL_ADCB(3985), //Left dial
FAIRY_RIGH_DIAL_ILJK(3986), //Middle dial
FAIRY_RING_DIAL_PSRQ(3987); //Right dial
FAIRY_RING_DIAL_PSRQ(3987), //Right dial
/**
* Transmog controllers for farming
*/
FARMING_4771(4771),
FARMING_4772(4772),
FARMING_4773(4773),
FARMING_4774(4774),
/**
* Transmog controllers for grapes
*/
GRAPES_4953(4953),
GRAPES_4954(4954),
GRAPES_4955(4955),
GRAPES_4956(4956),
GRAPES_4957(4957),
GRAPES_4958(4958),
GRAPES_4959(4959),
GRAPES_4960(4960),
GRAPES_4961(4961),
GRAPES_4962(4962),
GRAPES_4963(4963),
GRAPES_4964(4964),
/**
* Automatically weed farming patches
*/
AUTOWEED(5557);
/**
* varbit id

View File

@@ -0,0 +1,32 @@
/*
* 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.api.vars;
public enum Autoweed
{
UNOWNED,
OFF,
ON
}

View File

@@ -0,0 +1,41 @@
/*
* 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.farmingtracker;
import java.awt.Color;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Getter
public enum CropState
{
HARVESTABLE(Color.GREEN),
GROWING(Color.GREEN),
DISEASED(Color.ORANGE),
DEAD(Color.RED);
private final Color color;
}

View File

@@ -0,0 +1,44 @@
/*
* 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.farmingtracker;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import net.runelite.api.Varbits;
@RequiredArgsConstructor(
access = AccessLevel.PACKAGE
)
@Getter
public class FarmingPatch
{
@Setter(AccessLevel.PACKAGE)
private FarmingRegion region;
private final String name;
private final Varbits varbit;
private final PatchImplementation implementation;
}

View File

@@ -0,0 +1,79 @@
/*
* 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.farmingtracker;
import java.awt.Dimension;
import javax.swing.GroupLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import lombok.Getter;
import net.runelite.client.ui.FontManager;
@Getter
class FarmingPatchPanel extends JPanel
{
private final FarmingPatch patch;
private final JLabel icon = new JLabel();
private final JLabel estimate = new JLabel();
private final JProgressBar progress = new JProgressBar();
FarmingPatchPanel(FarmingPatch patch)
{
this.patch = patch;
GroupLayout layout = new GroupLayout(this);
this.setLayout(layout);
final JLabel location = new JLabel(patch.getRegion().getName() + " " + patch.getName());
location.setFont(FontManager.getRunescapeSmallFont());
icon.setMinimumSize(new Dimension(36, 32));
layout.setVerticalGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER)
.addComponent(icon)
.addGroup(layout.createSequentialGroup()
.addGap(1)
.addComponent(location)
.addGap(1)
.addComponent(estimate)
)
)
.addComponent(progress, 8, 8, 8)
.addGap(4)
);
layout.setHorizontalGroup(layout.createParallelGroup()
.addGroup(layout.createSequentialGroup()
.addComponent(icon)
.addGroup(layout.createParallelGroup()
.addComponent(location)
.addComponent(estimate)
)
)
.addComponent(progress)
);
}
}

View File

@@ -0,0 +1,57 @@
/*
* 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.farmingtracker;
import lombok.Getter;
import net.runelite.api.Varbits;
import net.runelite.api.coords.WorldPoint;
@Getter
public class FarmingRegion
{
private final String name;
private final int regionID;
private final FarmingPatch[] patches;
private final Varbits[] varbits;
FarmingRegion(String name, int regionID, FarmingPatch... patches)
{
this.name = name;
this.regionID = regionID;
this.patches = patches;
this.varbits = new Varbits[patches.length];
for (int i = 0; i < patches.length; i++)
{
FarmingPatch p = patches[i];
p.setRegion(this);
varbits[i] = p.getVarbit();
}
}
public boolean isInBounds(WorldPoint loc)
{
return true;
}
}

View File

@@ -0,0 +1,69 @@
/*
* 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.farmingtracker;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
@ConfigGroup(
keyName = "farmingTracker",
name = "Farming Tracker",
description = "Configuration for the farming tracker"
)
public interface FarmingTrackerConfig extends Config
{
String KEY_NAME = "farmingTracker";
String AUTOWEED = "autoweed";
@ConfigItem(
keyName = "estimateRelative",
name = "Show relative time",
description = "Show amount of time remaining for a patch, opposed to when the patch is finished"
)
default boolean estimateRelative()
{
return false;
}
@ConfigItem(
keyName = "patch",
name = "Default patch",
description = "Default patch on opening the panel",
hidden = true
)
default Tab patch()
{
return Tab.ALLOTMENT;
}
@ConfigItem(
keyName = "patch",
name = "",
description = "",
hidden = true
)
void setPatch(Tab t);
}

View File

@@ -0,0 +1,319 @@
/*
* 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.farmingtracker;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.format.TextStyle;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
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.AsyncBufferedImage;
import net.runelite.client.game.ItemManager;
import net.runelite.client.ui.PluginPanel;
@Slf4j
class FarmingTrackerPanel extends PluginPanel
{
private final Client client;
private final ItemManager itemManager;
private final ConfigManager configManager;
private final FarmingTrackerConfig config;
private boolean active;
private List<FarmingPatchPanel> patchPanels = new ArrayList<>();
FarmingTrackerPanel(
Client client,
ItemManager itemManager,
ConfigManager configManager,
FarmingTrackerConfig config,
FarmingWorld farmingWorld
)
{
super(false);
this.client = client;
this.itemManager = itemManager;
this.configManager = configManager;
this.config = config;
setLayout(new BorderLayout());
JTabbedPane tabs = new JTabbedPane();
farmingWorld.getTabs().forEach((tab, patches) ->
{
JPanel panel = new JPanel(new GridBagLayout())
{
@Override
public Dimension getPreferredSize()
{
return new Dimension(PluginPanel.PANEL_WIDTH, super.getPreferredSize().height);
}
};
panel.setBorder(new EmptyBorder(2, 6, 6, 6));
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 1;
c.gridx = 0;
c.gridy = 0;
for (FarmingPatch patch : patches)
{
FarmingPatchPanel p = new FarmingPatchPanel(patch);
patchPanels.add(p);
panel.add(p, c);
c.gridy++;
}
JPanel wrapped = new JPanel(new BorderLayout());
wrapped.add(panel, BorderLayout.NORTH);
JScrollPane scroller = new JScrollPane(wrapped);
scroller.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scroller.getVerticalScrollBar().setUnitIncrement(16);
AsyncBufferedImage icon = itemManager.getImage(tab.getItemID());
tabs.addTab(null, null, scroller, tab.getName());
int idx = tabs.getTabCount() - 1;
Runnable resize = () ->
{
tabs.setIconAt(idx, new ImageIcon(icon.getScaledInstance(24, 21, Image.SCALE_SMOOTH)));
};
icon.onChanged(resize);
resize.run();
if (config.patch() == tab)
{
tabs.setSelectedComponent(scroller);
}
tabs.addChangeListener(e ->
{
if (tabs.getSelectedComponent() == scroller)
{
config.setPatch(tab);
}
});
});
add(tabs, BorderLayout.CENTER);
}
void update()
{
if (!active)
{
return;
}
long unixNow = Instant.now().getEpochSecond();
log.debug("Updating panel with username {}", client.getUsername());
boolean autoweed = false;
{
String group = FarmingTrackerConfig.KEY_NAME + "." + client.getUsername();
autoweed = Integer.toString(Autoweed.ON.ordinal())
.equals(configManager.getConfiguration(group, FarmingTrackerConfig.AUTOWEED));
}
for (FarmingPatchPanel panel : patchPanels)
{
FarmingPatch patch = panel.getPatch();
String group = FarmingTrackerConfig.KEY_NAME + "." + 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)
{
}
}
}
PatchState state = unixTime <= 0 ? null : patch.getImplementation().forVarbitValue(value);
if (state == null)
{
panel.getIcon().setIcon(null);
panel.getIcon().setToolTipText("Unknown state");
panel.getProgress().setMaximum(0);
panel.getProgress().setValue(0);
panel.getEstimate().setText("Unknown");
}
else
{
if (state.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());
}
int stage = state.getStage();
int stages = state.getCropState() == CropState.HARVESTABLE ?
state.getProduce().getHarvestStages() :
state.getProduce().getStages();
int tickrate = 0;
switch (state.getCropState())
{
case HARVESTABLE:
tickrate = state.getProduce().getRegrowTickrate() * 60;
break;
case GROWING:
tickrate = state.getProduce().getTickrate() * 60;
break;
}
if (autoweed && state.getProduce() == Produce.WEEDS)
{
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)
{
panel.getEstimate().setText("Done");
}
else if (config.estimateRelative())
{
int remaining = (int) (59 + doneEstimate - unixNow) / 60;
StringBuilder f = new StringBuilder();
f.append("Done in ");
int min = remaining % 60;
int hours = (remaining / 60) % 24;
int days = remaining / (60 * 24);
if (days > 0)
{
f.append(days).append("d ");
}
if (hours > 0)
{
f.append(hours).append("h ");
}
if (min > 0)
{
f.append(min).append("m ");
}
panel.getEstimate().setText(f.toString());
}
else
{
StringBuilder f = new StringBuilder();
LocalDateTime ldtTime = LocalDateTime.ofEpochSecond(doneEstimate, 0, OffsetDateTime.now().getOffset());
LocalDateTime ldtNow = LocalDateTime.now();
f.append("Done ");
if (ldtTime.getDayOfWeek() != ldtNow.getDayOfWeek())
{
f.append(ldtTime.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.getDefault())).append(" ");
}
f.append(String.format("at %d:%02d", ldtTime.getHour(), ldtTime.getMinute()));
panel.getEstimate().setText(f.toString());
}
}
else
{
switch (state.getCropState())
{
case HARVESTABLE:
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;
}
}
panel.getProgress().setBackground(state.getCropState().getColor().darker());
panel.getProgress().setMaximum(stages - 1);
panel.getProgress().setValue(stage);
}
}
}
@Override
public void onActivate()
{
active = true;
update();
}
@Override
public void onDeactivate()
{
active = false;
}
}

View File

@@ -0,0 +1,197 @@
/*
* 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.farmingtracker;
import com.google.common.eventbus.Subscribe;
import com.google.inject.Provides;
import java.awt.image.BufferedImage;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import javax.imageio.ImageIO;
import javax.inject.Inject;
import javax.swing.SwingUtilities;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.Varbits;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.UsernameChanged;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.task.Schedule;
import net.runelite.client.ui.NavigationButton;
import net.runelite.client.ui.PluginToolbar;
@PluginDescriptor(
name = "Farming Tracker"
)
@Slf4j
public class FarmingTrackerPlugin extends Plugin
{
@Inject
private PluginToolbar pluginToolbar;
@Inject
private ConfigManager configManager;
@Inject
private Client client;
@Inject
private FarmingWorld farmingWorld;
@Inject
private ItemManager itemManager;
@Inject
private FarmingTrackerConfig config;
private FarmingTrackerPanel panel;
private NavigationButton navButton;
private WorldPoint lastTickLoc;
@Provides
FarmingTrackerConfig provideConfig(ConfigManager configManager)
{
return configManager.getConfig(FarmingTrackerConfig.class);
}
@Override
protected void startUp() throws Exception
{
BufferedImage icon;
synchronized (ImageIO.class)
{
icon = ImageIO.read(getClass().getResourceAsStream("farming.png"));
}
panel = new FarmingTrackerPanel(client, itemManager, configManager, config, farmingWorld);
navButton = NavigationButton.builder()
.name("Farming Tracker")
.icon(icon)
.panel(panel)
.build();
pluginToolbar.addNavigation(navButton);
updatePanel();
}
@Subscribe
public void onUsernameChanged(UsernameChanged e)
{
updatePanel();
}
@Override
protected void shutDown() throws Exception
{
pluginToolbar.removeNavigation(navButton);
}
@Subscribe
public void onGameTick(GameTick t)
{
if (client.getGameState() != GameState.LOGGED_IN)
{
lastTickLoc = null;
return;
}
WorldPoint loc = lastTickLoc;
lastTickLoc = client.getLocalPlayer().getWorldLocation();
if (loc == null)
{
return;
}
boolean changed = false;
{
String group = FarmingTrackerConfig.KEY_NAME + "." + client.getUsername();
String autoweed = Integer.toString(client.getSetting(Varbits.AUTOWEED));
if (!autoweed.equals(configManager.getConfiguration(group, FarmingTrackerConfig.AUTOWEED)))
{
configManager.setConfiguration(group, FarmingTrackerConfig.AUTOWEED, autoweed);
changed = true;
}
}
FarmingRegion region = farmingWorld.getRegions().get(loc.getRegionID());
if (region != null && region.isInBounds(loc))
{
// Write config with new varbits
// farmingTracker.<login-username>.<regionID>.<VarbitID>=<varbitValue>:<unix time>
String group = FarmingTrackerConfig.KEY_NAME + "." + client.getUsername() + "." + region.getRegionID();
long unixNow = Instant.now().getEpochSecond();
for (Varbits varbit : region.getVarbits())
{
// Write the config value if it doesn't match what is current, or it is more than 5 minutes old
String key = Integer.toString(varbit.getId());
String strVarbit = Integer.toString(client.getSetting(varbit));
String storedValue = configManager.getConfiguration(group, key);
if (storedValue != null)
{
String[] parts = storedValue.split(":");
if (parts.length == 2 && parts[0].equals(strVarbit))
{
long unixTime = 0;
try
{
unixTime = Long.parseLong(parts[1]);
}
catch (NumberFormatException e)
{
}
if (unixTime + (5 * 60) > unixNow && unixNow + 30 > unixTime)
{
continue;
}
}
}
String value = strVarbit + ":" + unixNow;
configManager.setConfiguration(group, key, value);
changed = true;
}
}
if (changed)
{
updatePanel();
}
}
@Schedule(period = 10, unit = ChronoUnit.SECONDS)
public void updatePanel()
{
SwingUtilities.invokeLater(panel::update);
}
}

View File

@@ -0,0 +1,247 @@
/*
* Copyright (c) 2018, NotFoxtrot <https://github.com/NotFoxtrot>
* 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.farmingtracker;
import com.google.inject.Singleton;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import lombok.Getter;
import net.runelite.api.Varbits;
import net.runelite.api.coords.WorldPoint;
@Singleton
public class FarmingWorld
{
@Getter
private Map<Integer, FarmingRegion> regions = new HashMap<>();
@Getter
private Map<Tab, Set<FarmingPatch>> tabs = new HashMap<>();
private final Comparator<FarmingPatch> tabSorter = Comparator
.comparing(FarmingPatch::getImplementation)
.thenComparing((FarmingPatch p) -> p.getRegion().getName())
.thenComparing(FarmingPatch::getName);
public FarmingWorld()
{
// Some of these patches get updated in multiple regions.
// It may be worth it to add a specialization for these patches
add(new FarmingRegion("Al Kharid", 13106,
new FarmingPatch("Cactus", Varbits.FARMING_4771, PatchImplementation.CACTUS)
));
add(new FarmingRegion("Ardougne", 10290,
new FarmingPatch("Bush", Varbits.FARMING_4771, PatchImplementation.BUSH)
));
add(new FarmingRegion("Ardougne", 10548,
new FarmingPatch("North", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
new FarmingPatch("South", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
new FarmingPatch("Flower", Varbits.FARMING_4773, PatchImplementation.FLOWER),
new FarmingPatch("", Varbits.FARMING_4774, PatchImplementation.HERB)
));
add(new FarmingRegion("Brimhaven", 11058,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.FRUIT_TREE),
new FarmingPatch("Spirit Tree", Varbits.FARMING_4772, PatchImplementation.SPIRIT_TREE)
));
add(new FarmingRegion("Catherby", 11062,
new FarmingPatch("North", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
new FarmingPatch("South", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
new FarmingPatch("Flower", Varbits.FARMING_4773, PatchImplementation.FLOWER),
new FarmingPatch("", Varbits.FARMING_4774, PatchImplementation.HERB)
));
add(new FarmingRegion("Catherby", 11317,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.FRUIT_TREE)
));
add(new FarmingRegion("Champion's Guild", 12596,
new FarmingPatch("Bush", Varbits.FARMING_4771, PatchImplementation.BUSH)
));
add(new FarmingRegion("Draynor Manor", 12340,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.BELLADONNA)
));
add(new FarmingRegion("Entrana", 11060,
new FarmingPatch("Hops", Varbits.FARMING_4771, PatchImplementation.HOPS)
));
add(new FarmingRegion("Etceteria", 10300,
new FarmingPatch("Bush", Varbits.FARMING_4771, PatchImplementation.BUSH),
new FarmingPatch("Spirit Tree", Varbits.FARMING_4772, PatchImplementation.SPIRIT_TREE)
));
add(new FarmingRegion("Falador", 11828,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.TREE)
));
add(new FarmingRegion("Falador", 12083,
new FarmingPatch("North West", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
new FarmingPatch("South East", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
new FarmingPatch("Flower", Varbits.FARMING_4773, PatchImplementation.FLOWER),
new FarmingPatch("", Varbits.FARMING_4774, PatchImplementation.HERB)
)
{
@Override
public boolean isInBounds(WorldPoint loc)
{
return loc.getY() > 3280;
}
});
add(new FarmingRegion("Fossil Island", 14651,
new FarmingPatch("East", Varbits.FARMING_4771, PatchImplementation.HARDWOOD_TREE),
new FarmingPatch("Middle", Varbits.FARMING_4772, PatchImplementation.HARDWOOD_TREE),
new FarmingPatch("West", Varbits.FARMING_4773, PatchImplementation.HARDWOOD_TREE)
), 14907);
add(new FarmingRegion("Seaweed", 15008,
new FarmingPatch("North", Varbits.FARMING_4771, PatchImplementation.SEAWEED),
new FarmingPatch("South", Varbits.FARMING_4772, PatchImplementation.SEAWEED)
));
add(new FarmingRegion("Gnome Stronghold", 9781,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.TREE),
new FarmingPatch("", Varbits.FARMING_4772, PatchImplementation.FRUIT_TREE)
));
add(new FarmingRegion("Harmony", 15148,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
new FarmingPatch("", Varbits.FARMING_4772, PatchImplementation.HERB)
));
add(new FarmingRegion("Kourend", 7222,
new FarmingPatch("North East", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
new FarmingPatch("South West", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
new FarmingPatch("Flower", Varbits.FARMING_4773, PatchImplementation.FLOWER),
new FarmingPatch("", Varbits.FARMING_4774, PatchImplementation.HERB)
));
add(new FarmingRegion("Kourend", 6711,
new FarmingPatch("Spirit Tree", Varbits.FARMING_4771, PatchImplementation.SPIRIT_TREE)
));
add(new FarmingRegion("Kourend", 7223,
new FarmingPatch("West 1", Varbits.GRAPES_4953, PatchImplementation.GRAPES),
new FarmingPatch("West 2", Varbits.GRAPES_4954, PatchImplementation.GRAPES),
new FarmingPatch("West 3", Varbits.GRAPES_4955, PatchImplementation.GRAPES),
new FarmingPatch("West 4", Varbits.GRAPES_4956, PatchImplementation.GRAPES),
new FarmingPatch("West 5", Varbits.GRAPES_4957, PatchImplementation.GRAPES),
new FarmingPatch("West 6", Varbits.GRAPES_4958, PatchImplementation.GRAPES),
new FarmingPatch("East 1", Varbits.GRAPES_4959, PatchImplementation.GRAPES),
new FarmingPatch("East 2", Varbits.GRAPES_4960, PatchImplementation.GRAPES),
new FarmingPatch("East 3", Varbits.GRAPES_4961, PatchImplementation.GRAPES),
new FarmingPatch("East 4", Varbits.GRAPES_4962, PatchImplementation.GRAPES),
new FarmingPatch("East 5", Varbits.GRAPES_4963, PatchImplementation.GRAPES),
new FarmingPatch("East 6", Varbits.GRAPES_4964, PatchImplementation.GRAPES)
));
add(new FarmingRegion("Lletya", 9265,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.FRUIT_TREE)
));
add(new FarmingRegion("Lumbridge", 12851,
new FarmingPatch("Hops", Varbits.FARMING_4771, PatchImplementation.HOPS)
));
add(new FarmingRegion("Lumbridge", 12594,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.TREE)
));
add(new FarmingRegion("Morytania", 13622,
new FarmingPatch("Mushroom", Varbits.FARMING_4771, PatchImplementation.MUSHROOM)
));
add(new FarmingRegion("Morytania", 14391,
new FarmingPatch("North West", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
new FarmingPatch("South East", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
new FarmingPatch("Flower", Varbits.FARMING_4773, PatchImplementation.FLOWER),
new FarmingPatch("", Varbits.FARMING_4774, PatchImplementation.HERB)
));
add(new FarmingRegion("Port Sarim", 12082,
new FarmingPatch("Spirit tree", Varbits.FARMING_4771, PatchImplementation.SPIRIT_TREE)
));
add(new FarmingRegion("Rimmington", 11570,
new FarmingPatch("Bush", Varbits.FARMING_4771, PatchImplementation.BUSH)
), 11826);
add(new FarmingRegion("Seers' Village", 10551,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.HOPS)
));
add(new FarmingRegion("Tai Bwo Wannai", 11056,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.CALQUAT)
));
add(new FarmingRegion("Taverly", 11573,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.TREE)
));
add(new FarmingRegion("Tree Gnome Village", 9777,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.FRUIT_TREE)
));
add(new FarmingRegion("Troll Stronghold", 11321,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.HERB)
));
add(new FarmingRegion("Varrock", 12854,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.TREE)
), 12853);
add(new FarmingRegion("Yanille", 10288,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.HOPS)
));
// Finalize
this.regions = Collections.unmodifiableMap(regions);
Map<Tab, Set<FarmingPatch>> umtabs = new TreeMap<>();
for (Map.Entry<Tab, Set<FarmingPatch>> e : tabs.entrySet())
{
umtabs.put(e.getKey(), Collections.unmodifiableSet(e.getValue()));
}
this.tabs = Collections.unmodifiableMap(umtabs);
}
private void add(FarmingRegion r, int... extraRegions)
{
regions.put(r.getRegionID(), r);
for (int er : extraRegions)
{
regions.put(er, r);
}
for (FarmingPatch p : r.getPatches())
{
tabs
.computeIfAbsent(p.getImplementation().getTab(), k -> new TreeSet<>(tabSorter))
.add(p);
}
}
}

View File

@@ -0,0 +1,35 @@
/*
* 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.farmingtracker;
import lombok.Value;
@Value
public class PatchState
{
private final Produce produce;
private final CropState cropState;
private final int stage;
}

View File

@@ -0,0 +1,147 @@
/*
* Copyright (c) 2018 Abex
* Copyright (c) 2018, NotFoxtrot <https://github.com/NotFoxtrot>
* 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.farmingtracker;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import net.runelite.api.ItemID;
@RequiredArgsConstructor
@Getter
public enum Produce
{
WEEDS("Weeds", ItemID.WEEDS, 5, 4),
SCARECROW("Scarecrow", ItemID.SCARECROW, 5, 4),
// Allotment crops
POTATO("Potato", ItemID.POTATO, 10, 5, 0, 3),
ONION("Onion", ItemID.ONION, 10, 5, 0, 3),
CABBAGE("Cabbage", ItemID.CABBAGE, 10, 5, 0, 3),
TOMATO("Tomato", ItemID.TOMATO, 10, 5, 0, 3),
SWEETCORN("Sweetcorn", ItemID.SWEETCORN, 10, 6, 0, 3),
STRAWBERRY("Strawberry", ItemID.STRAWBERRY, 10, 7, 0, 3),
WATERMELON("Watermelon", ItemID.WATERMELON, 10, 8, 0, 3),
// Flower crops
MARIGOLD("Marigold", ItemID.MARIGOLDS, 5, 5),
ROSEMARY("Rosemary", ItemID.ROSEMARY, 5, 5),
NASTURTIUM("Nasturtium", ItemID.NASTURTIUMS, 5, 5),
WOAD("Woad", ItemID.WOAD_LEAF, 5, 5),
LIMPWURT("Limpwurt", ItemID.LIMPWURT_ROOT, 5, 5),
// Bush crops
REDBERRIES("Redberry", ItemID.REDBERRIES, 20, 6, 20, 5),
CADAVABERRIES("Cadavaberry", ItemID.CADAVA_BERRIES, 20, 7, 20, 5),
DWELLBERRIES("Dwellberry", ItemID.DWELLBERRIES, 20, 8, 20, 5),
JANGERBERRIES("Jangerberry", ItemID.JANGERBERRIES, 20, 9, 20, 5),
WHITEBERRIES("Whiteberry", ItemID.WHITE_BERRIES, 20, 9, 20, 5),
POISON_IVY("Poison", ItemID.POISON_IVY_BERRIES, 20, 9, 20, 5),
// Hop crops
BARLEY("Barley", ItemID.BARLEY, 10, 5, 0, 3),
HAMMERSTONE("Hammerstone", ItemID.HAMMERSTONE_HOPS, 10, 5, 0, 3),
ASGARNIAN("Asgarnian", ItemID.ASGARNIAN_HOPS, 10, 6, 0, 3),
JUTE("Jute", ItemID.JUTE_FIBRE, 10, 6, 0, 3),
YANILLIAN("Yanillian", ItemID.YANILLIAN_HOPS, 10, 7, 0, 3),
KRANDORIAN("Krandorian", ItemID.KRANDORIAN_HOPS, 10, 8, 0, 3),
WILDBLOOD("Wildblood", ItemID.WILDBLOOD_HOPS, 10, 9, 0, 3),
// Herb crops
GUAM("Guam", ItemID.GUAM_LEAF, 20, 5, 0, 3),
MARRENTILL("Marrentill", ItemID.MARRENTILL, 20, 5, 0, 3),
TARROMIN("Tarromin", ItemID.TARROMIN, 20, 5, 0, 3),
HARRALANDER("Harralander", ItemID.HARRALANDER, 20, 5, 0, 3),
RANARR("Ranarr", ItemID.RANARR_WEED, 20, 5, 0, 3),
TOADFLAX("Toadflax", ItemID.TOADFLAX, 20, 5, 0, 3),
IRIT("Irit", ItemID.IRIT_LEAF, 20, 5, 0, 3),
AVANTOE("Avantoe", ItemID.AVANTOE, 20, 5, 0, 3),
KWUARM("Kwuarm", ItemID.KWUARM, 20, 5, 0, 3),
SNAPDRAGON("Snapdragon", ItemID.SNAPDRAGON, 20, 5, 0, 3),
CADANTINE("Cadantine", ItemID.CADANTINE, 20, 5, 0, 3),
LANTADYME("Lantadyme", ItemID.LANTADYME, 20, 5, 0, 3),
DWARF_WEED("Dwarf Weed", ItemID.DWARF_WEED, 20, 5, 0, 3),
TORSTOL("Torstol", ItemID.TORSTOL, 20, 5, 0, 3),
GOUTWEED("Goutweed", ItemID.GOUTWEED, 20, 5, 0, 2),
ANYHERB("Any Herb", ItemID.GUAM_LEAF, 20, 5, 0, 3),
// Tree crops
OAK("Oak", ItemID.OAK_LOGS, 40, 6),
WILLOW("Willow", ItemID.WILLOW_LOGS, 40, 8),
MAPLE("Maple", ItemID.MAPLE_TREE, 40, 9),
YEW("Yew", ItemID.YEW_TREE, 40, 11),
MAGIC("Magic", ItemID.MAGIC_LOGS, 40, 13),
// Fruit tree crops
APPLE("Apple", ItemID.COOKING_APPLE, 160, 7, 45, 7),
BANANA("Banana", ItemID.BANANA, 160, 7, 45, 7),
ORANGE("Orange", ItemID.ORANGE, 160, 7, 45, 7),
CURRY("Curry", ItemID.CURRY_LEAF, 160, 7, 45, 7),
PINEAPPLE("Pineapple", ItemID.PINEAPPLE, 160, 7, 45, 7),
PAPAYA("Papaya", ItemID.PAPAYA_FRUIT, 160, 7, 45, 7),
PALM("Palm", ItemID.COCONUT, 160, 7, 45, 7),
// Special crops
SEAWEED("Seaweed", ItemID.GIANT_SEAWEED, 10, 8, 0, 4),
TEAK("Teak", ItemID.TEAK_LOGS, 560, 9),
GRAPE("Grape", ItemID.GRAPES, 5, 8, 0, 5),
MUSHROOM("Mushroom", ItemID.MUSHROOM, 40, 7, 0, 7),
MAHOGANY("Mahogany", ItemID.MAHOGANY_LOGS, 640, 10),
CACTUS("Cactus", ItemID.POTATO_CACTUS, 80, 8, 20, 4),
BELLADONNA("Belladonna", ItemID.CAVE_NIGHTSHADE, 80, 5),
CALQUAT("Calquat", ItemID.CALQUAT_FRUIT, 160, 9, 0, 7),
SPIRIT_TREE("Spirit Tree", ItemID.SPIRIT_TREE, 320, 13);
/**
* User-visible name
*/
private final String name;
/**
* User-visible item icon
*/
private final int itemID;
/**
* How many minutes per growth tick
*/
private final int tickrate;
/**
* How many states this crop has during groth. Typically tickcount+1
*/
private final int stages;
/**
* How many minutes to regrow crops, or zero if it doesn't regrow
*/
private final int regrowTickrate;
/**
* How many states this crop has during harvest.
* This is often called lives.
*/
private final int harvestStages;
Produce(String name, int itemID, int tickrate, int stages)
{
this(name, itemID, tickrate, stages, 0, 1);
}
}

View File

@@ -0,0 +1,43 @@
/*
* 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.farmingtracker;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import net.runelite.api.ItemID;
@RequiredArgsConstructor
@Getter
public enum Tab
{
ALLOTMENT("Allotments", ItemID.CABBAGE),
HERB("Herbs", ItemID.GRIMY_RANARR_WEED),
TREE("Trees", ItemID.MAHOGANY_LOGS),
FRUIT_TREE("Fruit Trees", ItemID.PINEAPPLE),
SPECIAL("Special", ItemID.MUSHROOM);
private final String name;
private final int itemID;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,35 @@
/*
* 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.farmingtracker;
import org.junit.Test;
public class FarmingWorldTest
{
@Test
public void testInit()
{
new FarmingWorld();
}
}

View File

@@ -0,0 +1,60 @@
/*
* 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.farmingtracker;
import org.junit.Assert;
import org.junit.Test;
public class PatchImplementationTest
{
@Test
public void testRange()
{
for (PatchImplementation impl : PatchImplementation.values())
{
for (int i = 0; i < 256; i++)
{
PatchState s = impl.forVarbitValue(i);
if (s != null)
{
String pfx = impl.name() + "[" + i + "]";
Assert.assertNotNull(pfx + ": null cropState", s.getCropState());
Assert.assertNotNull(pfx + ": null produce", s.getProduce());
Assert.assertTrue(pfx + ": " + s.getStage() + " < 0", s.getStage() >= 0);
int stages = s.getProduce().getStages();
if (s.getCropState() == CropState.HARVESTABLE)
{
stages = s.getProduce().getHarvestStages();
}
Assert.assertTrue(pfx + ": " + s.getStage() + " >= " + stages, s.getStage() < stages);
if (s.getCropState() == CropState.DEAD || s.getCropState() == CropState.DISEASED)
{
Assert.assertTrue(pfx + ": dead seed", s.getStage() > 0);
}
}
}
}
}
}