Merge pull request #1904 from Abextm/farm-varbit

Farming Tracker Plugin
This commit is contained in:
Adam
2018-04-26 21:38:17 -04:00
committed by GitHub
24 changed files with 3832 additions and 24 deletions

View File

@@ -111,8 +111,26 @@ public final class AnimationID
public static final int MAGIC_CHARGING_ORBS = 726;
public static final int BURYING_BONES = 827;
public static final int LOOKING_INTO = 832;
public static final int DIG = 830;
// NPC animations
public static final int TZTOK_JAD_MAGIC_ATTACK = 2656;
public static final int TZTOK_JAD_RANGE_ATTACK = 2652;
// Farming
public static final int FARMING_HARVEST_FRUIT_TREE = 2280;
public static final int FARMING_HARVEST_BUSH = 2281;
public static final int FARMING_HARVEST_HERB = 2282;
public static final int FARMING_USE_COMPOST = 2283;
public static final int FARMING_CURE_WITH_POTION = 2288;
public static final int FARMING_PLANT_SEED = 2291;
public static final int FARMING_HARVEST_FLOWER = 2292;
// Lunar spellbook
public static final int MAGIC_LUNAR_FERTILE_SOIL = 4413;
public static final int MAGIC_LUNAR_CURE_PLANT = 4432;
public static final int MAGIC_LUNAR_GEOMANCY = 7118;
// Arceuus spellbook
public static final int MAGIC_ARCEUUS_RESURRECT_CROPS = 7118;
}

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

@@ -165,4 +165,9 @@ public class WorldPoint
{
return new Point(x, y);
}
public int getRegionID()
{
return ((x >> 6) << 8) | (y >> 6);
}
}

View File

@@ -0,0 +1,29 @@
/*
* 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.events;
public class UsernameChanged
{
}

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

@@ -62,9 +62,7 @@ public class LocationOverlay extends Overlay
WorldPoint localWorld = client.getLocalPlayer().getWorldLocation();
LocalPoint localPoint = client.getLocalPlayer().getLocalLocation();
int regionX = localWorld.getX() >> 6;
int regionY = localWorld.getY() >> 6;
int regionID = regionX << 8 | regionY;
int regionID = localWorld.getRegionID();
if (client.isInInstancedRegion())
{

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

View File

@@ -342,9 +342,7 @@ public class GroundMarkerPlugin extends Plugin
worldPoint = WorldPoint.fromLocal(client, localPoint);
}
int regionX = worldPoint.getX() >> 6;
int regionY = worldPoint.getY() >> 6;
int regionId = regionX << 8 | regionY;
int regionId = worldPoint.getRegionID();
GroundMarkerPoint point = new GroundMarkerPoint(regionId, worldPoint.getX() & 0x3f, worldPoint.getY() & 0x3f, client.getPlane());
log.debug("Updating point: {} - {}", point, worldPoint);

View File

@@ -36,10 +36,11 @@ import lombok.Getter;
public abstract class PluginPanel extends JPanel
{
static final int PANEL_WIDTH = 225;
public static final int PANEL_WIDTH = 225;
static final int SCROLLBAR_WIDTH = 17;
private static final int OFFSET = 6;
private static final EmptyBorder BORDER_PADDING = new EmptyBorder(OFFSET, OFFSET, OFFSET, OFFSET);
private static final Dimension OUTER_PREFERRED_SIZE = new Dimension(PluginPanel.PANEL_WIDTH + SCROLLBAR_WIDTH, 0);
@Getter(AccessLevel.PROTECTED)
private final JScrollPane scrollPane;
@@ -47,33 +48,47 @@ public abstract class PluginPanel extends JPanel
@Getter(AccessLevel.PACKAGE)
private final JPanel wrappedPanel;
public PluginPanel()
protected PluginPanel()
{
this(true);
}
protected PluginPanel(boolean wrap)
{
super();
setBorder(BORDER_PADDING);
setLayout(new GridLayout(0, 1, 0, 3));
if (wrap)
{
setBorder(BORDER_PADDING);
setLayout(new GridLayout(0, 1, 0, 3));
final JPanel northPanel = new JPanel();
northPanel.setLayout(new BorderLayout());
northPanel.add(this, BorderLayout.NORTH);
final JPanel northPanel = new JPanel();
northPanel.setLayout(new BorderLayout());
northPanel.add(this, BorderLayout.NORTH);
scrollPane = new JScrollPane(northPanel);
scrollPane.getVerticalScrollBar().setUnitIncrement(16); //Otherwise scrollspeed is really slow
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane = new JScrollPane(northPanel);
scrollPane.getVerticalScrollBar().setUnitIncrement(16); //Otherwise scrollspeed is really slow
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
wrappedPanel = new JPanel();
wrappedPanel = new JPanel();
// Adjust the preferred size to expand to width of scrollbar to
// to preven scrollbar overlapping over contents
wrappedPanel.setPreferredSize(new Dimension(PluginPanel.PANEL_WIDTH + SCROLLBAR_WIDTH, 0));
wrappedPanel.setLayout(new BorderLayout());
wrappedPanel.add(scrollPane, BorderLayout.CENTER);
// Adjust the preferred size to expand to width of scrollbar to
// to preven scrollbar overlapping over contents
wrappedPanel.setPreferredSize(OUTER_PREFERRED_SIZE);
wrappedPanel.setLayout(new BorderLayout());
wrappedPanel.add(scrollPane, BorderLayout.CENTER);
}
else
{
scrollPane = null;
wrappedPanel = this;
}
}
@Override
public Dimension getPreferredSize()
{
return new Dimension(PANEL_WIDTH, super.getPreferredSize().height);
int width = this == wrappedPanel ? PANEL_WIDTH + SCROLLBAR_WIDTH : PANEL_WIDTH;
return new Dimension(width, super.getPreferredSize().height);
}
public void onActivate()

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

View File

@@ -72,6 +72,7 @@ import net.runelite.api.events.PlayerDespawned;
import net.runelite.api.events.PlayerMenuOptionsChanged;
import net.runelite.api.events.PlayerSpawned;
import net.runelite.api.events.ResizeableChanged;
import net.runelite.api.events.UsernameChanged;
import net.runelite.api.events.VarbitChanged;
import net.runelite.api.events.WidgetLoaded;
import net.runelite.api.mixins.Copy;
@@ -838,4 +839,11 @@ public abstract class RSClientMixin implements RSClient
}
rs$menuAction(var0, var1, var2, var3, var4, var5, var6, var7);
}
@FieldHook("username")
@Inject
public static void onUsernameChanged(int idx)
{
eventBus.post(new UsernameChanged());
}
}