Supplies tracker (#79)
* Catch IndexOutOfBoundsException in SuppliesTracker * Cleanup supplies tracker
This commit is contained in:
@@ -30,7 +30,5 @@ package net.runelite.client.plugins.suppliestracker;
|
||||
*/
|
||||
public enum ActionType
|
||||
{
|
||||
|
||||
CONSUMABLE, TELEPORT, CAST;
|
||||
|
||||
}
|
||||
@@ -26,8 +26,13 @@ package net.runelite.client.plugins.suppliestracker;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import static net.runelite.api.ItemID.*;
|
||||
import static net.runelite.api.ItemID.ADAMANT_DART;
|
||||
import static net.runelite.api.ItemID.BRONZE_DART;
|
||||
import static net.runelite.api.ItemID.DRAGON_DART;
|
||||
import static net.runelite.api.ItemID.IRON_DART;
|
||||
import static net.runelite.api.ItemID.MITHRIL_DART;
|
||||
import static net.runelite.api.ItemID.RUNE_DART;
|
||||
import static net.runelite.api.ItemID.STEEL_DART;
|
||||
|
||||
/**
|
||||
* Type of darts that can be put into the blowpipe
|
||||
|
||||
@@ -34,13 +34,12 @@ import net.runelite.api.Item;
|
||||
@AllArgsConstructor
|
||||
public class MenuAction
|
||||
{
|
||||
|
||||
@Getter
|
||||
private ActionType type;
|
||||
@Getter
|
||||
private Item[] oldInventory;
|
||||
|
||||
public static class ItemAction extends MenuAction
|
||||
static class ItemAction extends MenuAction
|
||||
{
|
||||
|
||||
@Getter
|
||||
@@ -48,13 +47,11 @@ public class MenuAction
|
||||
@Getter
|
||||
private int slot;
|
||||
|
||||
public ItemAction(ActionType type, Item[] oldInventory, int itemID, int slot)
|
||||
ItemAction(ActionType type, Item[] oldInventory, int itemID, int slot)
|
||||
{
|
||||
super(type, oldInventory);
|
||||
this.itemID = itemID;
|
||||
this.slot = slot;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,8 +25,20 @@
|
||||
*/
|
||||
package net.runelite.client.plugins.suppliestracker;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.GridLayout;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import static net.runelite.api.ItemID.*;
|
||||
import net.runelite.client.game.AsyncBufferedImage;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
@@ -35,16 +47,7 @@ import net.runelite.client.util.StackFormatter;
|
||||
import net.runelite.client.util.Text;
|
||||
import net.runelite.http.api.item.ItemPrice;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static net.runelite.api.ItemID.*;
|
||||
import static net.runelite.api.ItemID.HALF_A_MEAT_PIE;
|
||||
|
||||
public class SuppliesBox extends JPanel
|
||||
class SuppliesBox extends JPanel
|
||||
{
|
||||
private static final int ITEMS_PER_ROW = 5;
|
||||
|
||||
@@ -129,7 +132,7 @@ public class SuppliesBox extends JPanel
|
||||
setVisible(trackedItems.size() > 0);
|
||||
}
|
||||
|
||||
void remove(SuppliesTrackerItem item)
|
||||
private void remove(SuppliesTrackerItem item)
|
||||
{
|
||||
trackedItems.removeIf(r -> r.getId() == item.getId());
|
||||
plugin.clearItem(item.getId());
|
||||
@@ -142,7 +145,7 @@ public class SuppliesBox extends JPanel
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
public long getTotalSupplies()
|
||||
long getTotalSupplies()
|
||||
{
|
||||
long totalSupplies = 0;
|
||||
for (SuppliesTrackerItem item : trackedItems)
|
||||
@@ -152,7 +155,7 @@ public class SuppliesBox extends JPanel
|
||||
return totalSupplies;
|
||||
}
|
||||
|
||||
public long getTotalPrice()
|
||||
long getTotalPrice()
|
||||
{
|
||||
return totalPrice;
|
||||
}
|
||||
|
||||
@@ -32,9 +32,9 @@ import net.runelite.client.config.ConfigItem;
|
||||
public interface SuppliesTrackerConfig extends Config
|
||||
{
|
||||
@ConfigItem(
|
||||
keyName = "blowpipeAmmo",
|
||||
name = "Ammo used in your blowpipe",
|
||||
description = "What type of dart are you using in your toxic blowpipe"
|
||||
keyName = "blowpipeAmmo",
|
||||
name = "Ammo used in your blowpipe",
|
||||
description = "What type of dart are you using in your toxic blowpipe"
|
||||
)
|
||||
default BlowpipeDartType blowpipeAmmo()
|
||||
{
|
||||
|
||||
@@ -28,7 +28,6 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@AllArgsConstructor
|
||||
|
||||
class SuppliesTrackerItem
|
||||
{
|
||||
@Getter
|
||||
|
||||
@@ -26,13 +26,11 @@
|
||||
*/
|
||||
package net.runelite.client.plugins.suppliestracker;
|
||||
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.ui.PluginPanel;
|
||||
import net.runelite.client.ui.components.PluginErrorPanel;
|
||||
import net.runelite.client.util.ColorUtil;
|
||||
import net.runelite.client.util.StackFormatter;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
@@ -40,12 +38,13 @@ import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.ui.PluginPanel;
|
||||
import net.runelite.client.ui.components.PluginErrorPanel;
|
||||
import net.runelite.client.util.ColorUtil;
|
||||
import net.runelite.client.util.StackFormatter;
|
||||
|
||||
|
||||
class SuppliesTrackerPanel extends PluginPanel
|
||||
@@ -60,23 +59,16 @@ class SuppliesTrackerPanel extends PluginPanel
|
||||
|
||||
private final PluginErrorPanel errorPanel = new PluginErrorPanel();
|
||||
|
||||
private final ScheduledExecutorService executor;
|
||||
|
||||
// Handle overall session data
|
||||
private final JPanel overallPanel = new JPanel();
|
||||
private final JLabel overallSuppliesUsedLabel = new JLabel();
|
||||
private final JLabel overallCostLabel = new JLabel();
|
||||
private final JLabel overallIcon = new JLabel();
|
||||
private final ItemManager itemManager;
|
||||
private final SuppliesTrackerPlugin plugin;
|
||||
private int overallSuppliesUsed;
|
||||
private int overallCost;
|
||||
|
||||
SuppliesTrackerPanel(final ItemManager itemManager, ScheduledExecutorService executor, SuppliesTrackerPlugin plugin)
|
||||
SuppliesTrackerPanel(final ItemManager itemManager, SuppliesTrackerPlugin plugin)
|
||||
{
|
||||
this.executor = executor;
|
||||
this.itemManager = itemManager;
|
||||
this.plugin = plugin;
|
||||
setBorder(new EmptyBorder(6, 6, 6, 6));
|
||||
setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
setLayout(new BorderLayout());
|
||||
@@ -146,7 +138,7 @@ class SuppliesTrackerPanel extends PluginPanel
|
||||
* loads an img to the icon on the header
|
||||
* @param img the img for the header icon
|
||||
*/
|
||||
public void loadHeaderIcon(BufferedImage img)
|
||||
void loadHeaderIcon(BufferedImage img)
|
||||
{
|
||||
overallIcon.setIcon(new ImageIcon(img));
|
||||
}
|
||||
@@ -167,7 +159,7 @@ class SuppliesTrackerPanel extends PluginPanel
|
||||
* Add an item to the supply panel by placing it into the correct box
|
||||
* @param item the item to add
|
||||
*/
|
||||
public void addItem(SuppliesTrackerItem item)
|
||||
void addItem(SuppliesTrackerItem item)
|
||||
{
|
||||
ItemType category = ItemType.categorize(item);
|
||||
for (SuppliesBox box : boxList)
|
||||
@@ -186,7 +178,7 @@ class SuppliesTrackerPanel extends PluginPanel
|
||||
* Updates overall stats to calculate overall used and overall cost from
|
||||
* the info in each box
|
||||
*/
|
||||
public void updateOverall()
|
||||
void updateOverall()
|
||||
{
|
||||
overallSuppliesUsed = 0;
|
||||
for (SuppliesBox box : boxList)
|
||||
|
||||
@@ -30,35 +30,49 @@ package net.runelite.client.plugins.suppliestracker;
|
||||
|
||||
|
||||
import com.google.inject.Provides;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.inject.Inject;
|
||||
import javax.swing.SwingUtilities;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.*;
|
||||
import net.runelite.api.events.*;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import static net.runelite.api.AnimationID.BLOWPIPE_ATTACK;
|
||||
import static net.runelite.api.AnimationID.HIGH_LEVEL_MAGIC_ATTACK;
|
||||
import static net.runelite.api.AnimationID.LOW_LEVEL_MAGIC_ATTACK;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.EquipmentInventorySlot;
|
||||
import net.runelite.api.InventoryID;
|
||||
import net.runelite.api.Item;
|
||||
import net.runelite.api.ItemComposition;
|
||||
import net.runelite.api.ItemContainer;
|
||||
import net.runelite.api.ItemID;
|
||||
import static net.runelite.api.ItemID.*;
|
||||
import net.runelite.api.Player;
|
||||
import net.runelite.api.VarPlayer;
|
||||
import net.runelite.api.events.AnimationChanged;
|
||||
import net.runelite.api.events.CannonballFired;
|
||||
import net.runelite.api.events.GameTick;
|
||||
import net.runelite.api.events.ItemContainerChanged;
|
||||
import net.runelite.api.events.MenuOptionClicked;
|
||||
import net.runelite.api.events.VarbitChanged;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.game.SpriteManager;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginDescriptor;
|
||||
import net.runelite.client.plugins.PluginType;
|
||||
import static net.runelite.client.plugins.suppliestracker.ActionType.CAST;
|
||||
import static net.runelite.client.plugins.suppliestracker.ActionType.CONSUMABLE;
|
||||
import static net.runelite.client.plugins.suppliestracker.ActionType.TELEPORT;
|
||||
import net.runelite.client.ui.ClientToolbar;
|
||||
import net.runelite.client.ui.NavigationButton;
|
||||
import net.runelite.client.util.ImageUtil;
|
||||
import net.runelite.http.api.item.ItemPrice;
|
||||
|
||||
import static net.runelite.api.AnimationID.*;
|
||||
import static net.runelite.api.ItemID.*;
|
||||
import static net.runelite.client.plugins.suppliestracker.ActionType.CONSUMABLE;
|
||||
import static net.runelite.client.plugins.suppliestracker.ActionType.TELEPORT;
|
||||
import static net.runelite.client.plugins.suppliestracker.ActionType.CAST;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.inject.Inject;
|
||||
import javax.swing.SwingUtilities;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
|
||||
@PluginDescriptor(
|
||||
name = "Supplies Used Tracker",
|
||||
@@ -70,7 +84,6 @@ import java.awt.image.BufferedImage;
|
||||
@Slf4j
|
||||
public class SuppliesTrackerPlugin extends Plugin
|
||||
{
|
||||
|
||||
private static final String POTION_PATTERN = "[(]\\d[)]";
|
||||
|
||||
private static final String EAT_PATTERN = "^eat";
|
||||
@@ -128,26 +141,17 @@ public class SuppliesTrackerPlugin extends Plugin
|
||||
@Inject
|
||||
private ItemManager itemManager;
|
||||
|
||||
@Inject
|
||||
private SpriteManager spriteManager;
|
||||
|
||||
@Inject
|
||||
private SuppliesTrackerConfig config;
|
||||
|
||||
@Inject
|
||||
private Client client;
|
||||
|
||||
@Inject
|
||||
private ScheduledExecutorService executorService;
|
||||
|
||||
@Inject
|
||||
private ClientThread clientThread;
|
||||
|
||||
|
||||
@Override
|
||||
protected void startUp() throws Exception
|
||||
{
|
||||
panel = new SuppliesTrackerPanel(itemManager, executorService, this);
|
||||
panel = new SuppliesTrackerPanel(itemManager, this);
|
||||
final BufferedImage header = ImageUtil.getResourceStreamFromClass(getClass(), "panel_icon.png");
|
||||
panel.loadHeaderIcon(header);
|
||||
final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "panel_icon.png");
|
||||
@@ -185,14 +189,13 @@ public class SuppliesTrackerPlugin extends Plugin
|
||||
if (ticks == ticksInAnimation && (player.getAnimation() == BLOWPIPE_ATTACK))
|
||||
{
|
||||
double ava_percent = getAccumulatorPercent();
|
||||
double scale_percent = SCALES_PERCENT;
|
||||
// randomize the usage of supplies since we CANNOT actually get real supplies used
|
||||
if (random.nextDouble() <= ava_percent)
|
||||
{
|
||||
buildEntries(config.blowpipeAmmo().getDartID());
|
||||
|
||||
}
|
||||
if (random.nextDouble() <= scale_percent)
|
||||
if (random.nextDouble() <= SCALES_PERCENT)
|
||||
{
|
||||
buildEntries(ZULRAHS_SCALES);
|
||||
}
|
||||
@@ -209,7 +212,7 @@ public class SuppliesTrackerPlugin extends Plugin
|
||||
{
|
||||
double percent = NO_AVAS_PERCENT;
|
||||
ItemContainer equipment = client.getItemContainer(InventoryID.EQUIPMENT);
|
||||
if (equipment.getItems().length > EQUIPMENT_CAPE_SLOT)
|
||||
if (equipment != null && equipment.getItems().length > EQUIPMENT_CAPE_SLOT)
|
||||
{
|
||||
int capeID = equipment.getItems()[EQUIPMENT_CAPE_SLOT].getId();
|
||||
switch (capeID)
|
||||
@@ -220,7 +223,7 @@ public class SuppliesTrackerPlugin extends Plugin
|
||||
break;
|
||||
case AVAS_ACCUMULATOR:
|
||||
case ACCUMULATOR_MAX_CAPE:
|
||||
// TODO: the ranging cape can be used as an attractor so this could be wrong
|
||||
// TODO: the ranging cape can be used as an attractor so this could be wrong
|
||||
case RANGING_CAPE:
|
||||
percent = ACCUMULATOR_PERCENT;
|
||||
break;
|
||||
@@ -268,28 +271,32 @@ public class SuppliesTrackerPlugin extends Plugin
|
||||
*/
|
||||
private void checkUsedRunes(ItemContainer itemContainer, Item[] oldInv)
|
||||
{
|
||||
for (int i = 0; i < itemContainer.getItems().length; i++)
|
||||
try
|
||||
{
|
||||
Item newItem = itemContainer.getItems()[i];
|
||||
Item oldItem = oldInv[i];
|
||||
boolean isRune = false;
|
||||
for (int j = 0; j < RUNE_IDS.length; j++)
|
||||
for (int i = 0; i < itemContainer.getItems().length; i++)
|
||||
{
|
||||
if (oldItem.getId() == RUNE_IDS[j])
|
||||
Item newItem = itemContainer.getItems()[i];
|
||||
Item oldItem = oldInv[i];
|
||||
boolean isRune = false;
|
||||
for (int runeId : RUNE_IDS)
|
||||
{
|
||||
isRune = true;
|
||||
if (oldItem.getId() == runeId)
|
||||
{
|
||||
isRune = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isRune && (newItem.getId() != oldItem.getId() || newItem.getQuantity() != oldItem.getQuantity()))
|
||||
{
|
||||
int quantity = oldItem.getQuantity();
|
||||
if (newItem.getId() == oldItem.getId())
|
||||
if (isRune && (newItem.getId() != oldItem.getId() || newItem.getQuantity() != oldItem.getQuantity()))
|
||||
{
|
||||
quantity -= newItem.getQuantity();
|
||||
int quantity = oldItem.getQuantity();
|
||||
if (newItem.getId() == oldItem.getId())
|
||||
{
|
||||
quantity -= newItem.getQuantity();
|
||||
}
|
||||
buildEntries(oldItem.getId(), quantity);
|
||||
}
|
||||
buildEntries(oldItem.getId(), quantity);
|
||||
}
|
||||
}
|
||||
catch (IndexOutOfBoundsException ignored) {}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
@@ -330,8 +337,8 @@ public class SuppliesTrackerPlugin extends Plugin
|
||||
{
|
||||
old = client.getItemContainer(InventoryID.INVENTORY);
|
||||
|
||||
if (old.getItems() != null && !actionStack.stream().anyMatch(a ->
|
||||
a.getType() == CAST))
|
||||
if (old != null && old.getItems() != null && actionStack.stream().noneMatch(a ->
|
||||
a.getType() == CAST))
|
||||
{
|
||||
MenuAction newAction = new MenuAction(CAST, old.getItems());
|
||||
actionStack.push(newAction);
|
||||
@@ -342,8 +349,8 @@ public class SuppliesTrackerPlugin extends Plugin
|
||||
{
|
||||
old = client.getItemContainer(InventoryID.INVENTORY);
|
||||
|
||||
if (old.getItems() != null && !actionStack.stream().anyMatch(a ->
|
||||
a.getType() == CAST))
|
||||
if (old != null && old.getItems() != null && actionStack.stream().noneMatch(a ->
|
||||
a.getType() == CAST))
|
||||
{
|
||||
MenuAction newAction = new MenuAction(CAST, old.getItems());
|
||||
actionStack.push(newAction);
|
||||
@@ -488,7 +495,7 @@ public class SuppliesTrackerPlugin extends Plugin
|
||||
Pattern drinkPattern = Pattern.compile(DRINK_PATTERN);
|
||||
if (eatPattern.matcher(event.getMenuTarget().toLowerCase()).find() || drinkPattern.matcher(event.getMenuTarget().toLowerCase()).find())
|
||||
{
|
||||
if (!actionStack.stream().anyMatch(a ->
|
||||
if (actionStack.stream().noneMatch(a ->
|
||||
{
|
||||
if (a instanceof MenuAction.ItemAction)
|
||||
{
|
||||
@@ -518,8 +525,8 @@ public class SuppliesTrackerPlugin extends Plugin
|
||||
old = client.getItemContainer(InventoryID.INVENTORY);
|
||||
|
||||
// Makes stack only contains one teleport type to stop from adding multiple of one teleport
|
||||
if (old.getItems() != null && !actionStack.stream().anyMatch(a ->
|
||||
a.getType() == TELEPORT))
|
||||
if (old != null && old.getItems() != null && actionStack.stream().noneMatch(a ->
|
||||
a.getType() == TELEPORT))
|
||||
{
|
||||
int teleid = event.getId();
|
||||
MenuAction newAction = new MenuAction.ItemAction(TELEPORT, old.getItems(), teleid, event.getActionParam());
|
||||
@@ -535,8 +542,8 @@ public class SuppliesTrackerPlugin extends Plugin
|
||||
{
|
||||
old = client.getItemContainer(InventoryID.INVENTORY);
|
||||
|
||||
if (old.getItems() != null && !actionStack.stream().anyMatch(a ->
|
||||
a.getType() == CAST))
|
||||
if (old != null && old.getItems() != null && actionStack.stream().noneMatch(a ->
|
||||
a.getType() == CAST))
|
||||
{
|
||||
MenuAction newAction = new MenuAction(CAST, old.getItems());
|
||||
actionStack.push(newAction);
|
||||
@@ -601,7 +608,7 @@ public class SuppliesTrackerPlugin extends Plugin
|
||||
* Add an item to the supply tracker (with 1 count for that item)
|
||||
* @param itemId the id of the item
|
||||
*/
|
||||
void buildEntries(int itemId)
|
||||
private void buildEntries(int itemId)
|
||||
{
|
||||
buildEntries(itemId, 1);
|
||||
}
|
||||
@@ -611,7 +618,7 @@ public class SuppliesTrackerPlugin extends Plugin
|
||||
* @param itemId the id of the item
|
||||
* @param count the amount of the item to add to the tracker
|
||||
*/
|
||||
void buildEntries(int itemId, int count)
|
||||
private void buildEntries(int itemId, int count)
|
||||
{
|
||||
final ItemComposition itemComposition = itemManager.getItemComposition(itemId);
|
||||
String name = itemComposition.getName();
|
||||
@@ -663,15 +670,13 @@ public class SuppliesTrackerPlugin extends Plugin
|
||||
|
||||
suppliesEntry.put(itemId, newEntry);
|
||||
SwingUtilities.invokeLater(() ->
|
||||
{
|
||||
panel.addItem(newEntry);
|
||||
});
|
||||
panel.addItem(newEntry));
|
||||
}
|
||||
|
||||
/**
|
||||
* reset all item stacks
|
||||
*/
|
||||
public void clearSupplies()
|
||||
void clearSupplies()
|
||||
{
|
||||
suppliesEntry.clear();
|
||||
}
|
||||
@@ -680,7 +685,7 @@ public class SuppliesTrackerPlugin extends Plugin
|
||||
* reset an individual item stack
|
||||
* @param itemId the id of the item stack
|
||||
*/
|
||||
public void clearItem(int itemId)
|
||||
void clearItem(int itemId)
|
||||
{
|
||||
suppliesEntry.remove(itemId);
|
||||
}
|
||||
@@ -769,5 +774,4 @@ public class SuppliesTrackerPlugin extends Plugin
|
||||
}
|
||||
return itemId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user