diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java index 3f8ee667ff..b42de607c9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java @@ -51,6 +51,7 @@ class DevToolsPanel extends PluginPanel private final WidgetInspector widgetInspector; private final VarInspector varInspector; private final ScriptInspector scriptInspector; + private final InventoryInspector inventoryInspector; private final InfoBoxManager infoBoxManager; private final ScheduledExecutorService scheduledExecutorService; @@ -61,6 +62,7 @@ class DevToolsPanel extends PluginPanel WidgetInspector widgetInspector, VarInspector varInspector, ScriptInspector scriptInspector, + InventoryInspector inventoryInspector, Notifier notifier, InfoBoxManager infoBoxManager, ScheduledExecutorService scheduledExecutorService) @@ -70,6 +72,7 @@ class DevToolsPanel extends PluginPanel this.plugin = plugin; this.widgetInspector = widgetInspector; this.varInspector = varInspector; + this.inventoryInspector = inventoryInspector; this.scriptInspector = scriptInspector; this.notifier = notifier; this.infoBoxManager = infoBoxManager; @@ -180,6 +183,19 @@ class DevToolsPanel extends PluginPanel clearInfoboxBtn.addActionListener(e -> infoBoxManager.removeIf(i -> true)); container.add(clearInfoboxBtn); + container.add(plugin.getInventoryInspector()); + plugin.getInventoryInspector().addActionListener((ev) -> + { + if (plugin.getInventoryInspector().isActive()) + { + inventoryInspector.close(); + } + else + { + inventoryInspector.open(); + } + }); + return container; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPlugin.java index a15e1d7cc7..038533f1c4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPlugin.java @@ -140,6 +140,7 @@ public class DevToolsPlugin extends Plugin private DevToolsButton varInspector; private DevToolsButton soundEffects; private DevToolsButton scriptInspector; + private DevToolsButton inventoryInspector; private NavigationButton navButton; @Provides @@ -182,6 +183,7 @@ public class DevToolsPlugin extends Plugin varInspector = new DevToolsButton("Var Inspector"); soundEffects = new DevToolsButton("Sound Effects"); scriptInspector = new DevToolsButton("Script Inspector"); + inventoryInspector = new DevToolsButton("Inventory Inspector"); overlayManager.add(overlay); overlayManager.add(locationOverlay); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/InventoryDeltaPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/InventoryDeltaPanel.java new file mode 100644 index 0000000000..665a1fa674 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/InventoryDeltaPanel.java @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2020, TheStonedTurtle + * 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.devtools; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.GridLayout; +import java.awt.Rectangle; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.text.DecimalFormat; +import javax.annotation.Nullable; +import javax.swing.BoxLayout; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.Scrollable; +import javax.swing.SwingConstants; +import javax.swing.border.EmptyBorder; +import net.runelite.api.Constants; +import net.runelite.api.Item; +import net.runelite.client.game.ItemManager; +import net.runelite.client.ui.ColorScheme; +import net.runelite.client.ui.FontManager; + +class InventoryDeltaPanel extends JPanel implements Scrollable +{ + private static final DecimalFormat COMMA_FORMAT = new DecimalFormat("#,###"); + private static final Dimension ITEM_SIZE = new Dimension(Constants.ITEM_SPRITE_WIDTH + 4, Constants.ITEM_SPRITE_HEIGHT); + + private final ItemManager itemManager; + private final JPanel addedGrid = new JPanel(); + private final JPanel removedGrid = new JPanel(); + private final JPanel currentGrid = new JPanel(); + + InventoryDeltaPanel(final ItemManager itemManager) + { + this.itemManager = itemManager; + + setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); + + final EmptyBorder border = new EmptyBorder(2, 2, 2, 2); + setBorder(border); + addedGrid.setBorder(border); + removedGrid.setBorder(border); + currentGrid.setBorder(border); + + final GridLayout layout = new GridLayout(0, 1, 1, 1); + addedGrid.setLayout(layout); + removedGrid.setLayout(layout); + currentGrid.setLayout(layout); + + // Listen for resize events + addComponentListener(new ComponentAdapter() + { + public void componentResized(final ComponentEvent componentEvent) + { + // Account for container and slot padding + final int cols = Math.max((getWidth() - 4) / (ITEM_SIZE.width + 1), 1); + final GridLayout layout = new GridLayout(0, cols, 1, 1); + addedGrid.setLayout(layout); + removedGrid.setLayout(layout); + currentGrid.setLayout(layout); + } + }); + } + + void clear() + { + addedGrid.removeAll(); + removedGrid.removeAll(); + currentGrid.removeAll(); + removeAll(); + revalidate(); + repaint(); + } + + void displayItems(final InventoryItem[] items, @Nullable final InventoryItem[] added, @Nullable final InventoryItem[] removed) + { + clear(); + + if (added != null && added.length > 0) + { + final JLabel label = new JLabel("Items Added:", JLabel.CENTER); + label.setAlignmentX(JLabel.CENTER_ALIGNMENT); + add(label); + add(addedGrid); + + for (final InventoryItem item : added) + { + addItemToPanel(item, addedGrid).setBackground(new Color(0, 100, 0)); + } + } + + if (removed != null && removed.length > 0) + { + final JLabel label = new JLabel("Items Removed:", JLabel.CENTER); + label.setAlignmentX(JLabel.CENTER_ALIGNMENT); + add(label); + add(removedGrid); + + for (final InventoryItem item : removed) + { + addItemToPanel(item, removedGrid).setBackground(new Color(120, 0, 0)); + } + } + + final JLabel label = new JLabel("Items in Inventory:", JLabel.CENTER); + label.setAlignmentX(JLabel.CENTER_ALIGNMENT); + add(label); + add(currentGrid); + + for (final InventoryItem item : items) + { + final JLabel gridItem = addItemToPanel(item, currentGrid); + // Add hover effect + gridItem.addMouseListener(new MouseAdapter() + { + @Override + public void mouseEntered(MouseEvent e) + { + final JLabel label = (JLabel) e.getSource(); + label.setBackground(ColorScheme.DARKER_GRAY_HOVER_COLOR); + } + + @Override + public void mouseExited(MouseEvent e) + { + final JLabel label = (JLabel) e.getSource(); + label.setBackground(ColorScheme.DARKER_GRAY_COLOR); + } + }); + gridItem.setToolTipText("Name: " + item.getName() + + "
Item ID: " + item.getItem().getId() + + "
Quantity: " + COMMA_FORMAT.format(item.getItem().getQuantity()) + + "
Slot: " + item.getSlot() + + ""); + } + + revalidate(); + repaint(); + } + + private JLabel addItemToPanel(final InventoryItem inventoryItem, final JPanel panel) + { + final JLabel gridItem = new JLabel(); + gridItem.setOpaque(true); + gridItem.setPreferredSize(ITEM_SIZE); + gridItem.setVerticalAlignment(SwingConstants.CENTER); + gridItem.setHorizontalAlignment(SwingConstants.CENTER); + gridItem.setFont(FontManager.getRunescapeSmallFont()); + + final Item item = inventoryItem.getItem(); + if (item.getId() == -1) + { + gridItem.setText("EMPTY"); + } + else + { + itemManager.getImage(item.getId(), item.getQuantity(), item.getQuantity() > 1).addTo(gridItem); + gridItem.setToolTipText("Name: " + inventoryItem.getName() + + "
Item ID: " + item.getId() + + "
Quantity: " + COMMA_FORMAT.format(item.getQuantity()) + + ""); + } + + panel.add(gridItem); + return gridItem; + } + + @Override + public Dimension getPreferredScrollableViewportSize() + { + return null; + } + + @Override + public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) + { + return 1 + (orientation == SwingConstants.VERTICAL ? ITEM_SIZE.height : ITEM_SIZE.width); + } + + @Override + public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) + { + return 1 + (orientation == SwingConstants.VERTICAL ? ITEM_SIZE.height : ITEM_SIZE.width); + } + + @Override + public boolean getScrollableTracksViewportWidth() + { + return true; + } + + @Override + public boolean getScrollableTracksViewportHeight() + { + return false; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/InventoryInspector.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/InventoryInspector.java new file mode 100644 index 0000000000..60afafd2f1 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/InventoryInspector.java @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2020, TheStonedTurtle + * 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.devtools; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.event.AdjustmentEvent; +import java.awt.event.AdjustmentListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import javax.annotation.Nullable; +import javax.inject.Inject; +import javax.inject.Singleton; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollBar; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTree; +import javax.swing.SwingUtilities; +import javax.swing.border.EmptyBorder; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeNode; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import net.runelite.api.InventoryID; +import net.runelite.api.Item; +import net.runelite.api.ItemComposition; +import net.runelite.api.events.ItemContainerChanged; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.eventbus.EventBus; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.game.ItemManager; +import net.runelite.client.ui.ClientUI; +import net.runelite.client.ui.ColorScheme; + +@Slf4j +@Singleton +class InventoryInspector extends JFrame +{ + private static final int MAX_LOG_ENTRIES = 25; + + private final Client client; + private final EventBus eventBus; + private final ItemManager itemManager; + + private final Map nodeMap = new HashMap<>(); + private final Map logMap = new HashMap<>(); + private final DefaultMutableTreeNode trackerRootNode = new DefaultMutableTreeNode(); + private final JTree tree = new JTree(trackerRootNode); + private final InventoryDeltaPanel deltaPanel; + + @Inject + InventoryInspector(Client client, EventBus eventBus, DevToolsPlugin plugin, ItemManager itemManager, ClientThread clientThread) + { + this.client = client; + this.eventBus = eventBus; + this.itemManager = itemManager; + + this.deltaPanel = new InventoryDeltaPanel(itemManager); + + setLayout(new BorderLayout()); + setTitle("RuneLite Inventory Inspector"); + setIconImage(ClientUI.ICON); + + setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + // Reset highlight on close + addWindowListener(new WindowAdapter() + { + @Override + public void windowClosing(WindowEvent e) + { + close(); + plugin.getInventoryInspector().setActive(false); + } + }); + + tree.setBorder(new EmptyBorder(2, 2, 2, 2)); + tree.setRootVisible(false); + tree.setShowsRootHandles(true); + tree.addTreeSelectionListener(e -> + { + if (e.getNewLeadSelectionPath() == null) + { + return; + } + + final Object node = e.getNewLeadSelectionPath().getLastPathComponent(); + if (node instanceof InventoryLogNode) + { + clientThread.invoke(() -> displayItemSnapshot((InventoryLogNode) node)); + } + }); + tree.setModel(new DefaultTreeModel(trackerRootNode)); + + final JPanel leftSide = new JPanel(); + leftSide.setLayout(new BorderLayout()); + + final JScrollPane trackerScroller = new JScrollPane(tree); + trackerScroller.setPreferredSize(new Dimension(200, 400)); + + final JScrollBar vertical = trackerScroller.getVerticalScrollBar(); + vertical.addAdjustmentListener(new AdjustmentListener() + { + int lastMaximum = actualMax(); + + private int actualMax() + { + return vertical.getMaximum() - vertical.getModel().getExtent(); + } + + @Override + public void adjustmentValueChanged(AdjustmentEvent e) + { + if (vertical.getValue() >= lastMaximum) + { + vertical.setValue(actualMax()); + } + lastMaximum = actualMax(); + } + }); + + leftSide.add(trackerScroller, BorderLayout.CENTER); + + final JButton refreshBtn = new JButton("Refresh"); + refreshBtn.setFocusable(false); + refreshBtn.addActionListener(e -> refreshTracker()); + + final JButton clearBtn = new JButton("Clear"); + clearBtn.setFocusable(false); + clearBtn.addActionListener(e -> clearTracker()); + + final JPanel bottomRow = new JPanel(); + bottomRow.add(refreshBtn); + bottomRow.add(clearBtn); + + leftSide.add(bottomRow, BorderLayout.SOUTH); + + final JScrollPane gridScroller = new JScrollPane(deltaPanel); + gridScroller.getViewport().setBackground(ColorScheme.DARK_GRAY_COLOR); + gridScroller.setPreferredSize(new Dimension(200, 400)); + + final JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftSide, gridScroller); + add(split, BorderLayout.CENTER); + + pack(); + } + + public void open() + { + eventBus.register(this); + setVisible(true); + toFront(); + repaint(); + } + + public void close() + { + eventBus.unregister(this); + clearTracker(); + setVisible(false); + } + + @Subscribe + public void onItemContainerChanged(ItemContainerChanged event) + { + final int id = event.getContainerId(); + final InventoryLog log = new InventoryLog(id, getNameForInventoryID(id), event.getItemContainer().getItems(), client.getTickCount()); + + // Delay updates until refresh button is pressed + logMap.put(id, log); + } + + private void addLog(final InventoryLog invLog) + { + final InventoryTreeNode node = nodeMap.computeIfAbsent(invLog.getContainerId(), (k) -> new InventoryTreeNode(invLog.getContainerId(), invLog.getContainerName())); + node.add(new InventoryLogNode(invLog)); + + // Cull very old stuff + for (; node.getChildCount() > MAX_LOG_ENTRIES; ) + { + node.remove(0); + } + } + + private void clearTracker() + { + logMap.clear(); + nodeMap.clear(); + deltaPanel.clear(); + trackerRootNode.removeAllChildren(); + tree.setModel(new DefaultTreeModel(trackerRootNode)); + } + + private void refreshTracker() + { + deltaPanel.clear(); + + if (logMap.size() > 0) + { + logMap.values().forEach(this::addLog); + logMap.clear(); + } + + SwingUtilities.invokeLater(() -> + { + trackerRootNode.removeAllChildren(); + nodeMap.values().forEach(trackerRootNode::add); + tree.setModel(new DefaultTreeModel(trackerRootNode)); + }); + } + + private void displayItemSnapshot(final InventoryLogNode logNode) + { + final InventoryTreeNode treeNode = nodeMap.get(logNode.getLog().getContainerId()); + if (treeNode == null) + { + log.warn("Clicked on a JTree node that doesn't map anywhere: {}", logNode); + return; + } + + final Item[] curItems = logNode.getLog().getItems(); + final InventoryItem[] curInventory = convertToInventoryItems(curItems); + + InventoryItem[][] deltas = null; + // Compare against previous snapshot + if (treeNode.getIndex(logNode) > 0) + { + final TreeNode prevNode = treeNode.getChildBefore(logNode); + if (prevNode instanceof InventoryLogNode) + { + final InventoryLogNode prevLogNode = (InventoryLogNode) prevNode; + deltas = compareItemSnapshots(prevLogNode.getLog().getItems(), curItems); + } + } + + final InventoryItem[] added = deltas == null ? null : deltas[0]; + final InventoryItem[] removed = deltas == null ? null : deltas[1]; + + SwingUtilities.invokeLater(() -> deltaPanel.displayItems(curInventory, added, removed)); + } + + private InventoryItem[] convertToInventoryItems(final Item[] items) + { + final InventoryItem[] out = new InventoryItem[items.length]; + for (int i = 0; i < items.length; i++) + { + final Item item = items[i]; + final ItemComposition c = itemManager.getItemComposition(item.getId()); + out[i] = new InventoryItem(i, item, c.getName(), c.isStackable()); + } + + return out; + } + + /** + * Compares the current inventory to the old one returning the InventoryItems that were added and removed. + * @param previous old snapshot + * @param current new snapshot + * @return The first InventoryItem[] contains the items that were added and the second contains the items that were removed + */ + private InventoryItem[][] compareItemSnapshots(final Item[] previous, final Item[] current) + { + final Map qtyMap = new HashMap<>(); + + // ItemContainers shouldn't become smaller over time, but just in case + final int maxSlots = Math.max(previous.length, current.length); + for (int i = 0; i < maxSlots; i++) + { + final Item prev = previous.length > i ? previous[i] : null; + final Item cur = current.length > i ? current[i] : null; + + if (prev != null) + { + qtyMap.merge(prev.getId(), -1 * prev.getQuantity(), Integer::sum); + } + if (cur != null) + { + qtyMap.merge(cur.getId(), cur.getQuantity(), Integer::sum); + } + } + + final Map> result = qtyMap.entrySet().stream() + .filter(e -> e.getValue() != 0) + .flatMap(e -> + { + final int id = e.getKey(); + final int qty = e.getValue(); + final ItemComposition c = itemManager.getItemComposition(e.getKey()); + + InventoryItem[] items = new InventoryItem[]{ + new InventoryItem(-1, new Item(id, qty), c.getName(), c.isStackable()) + }; + if (!c.isStackable() && (qty > 1 || qty < -1)) + { + items = new InventoryItem[Math.abs(qty)]; + for (int i = 0; i < Math.abs(qty); i++) + { + final Item item = new Item(id, Integer.signum(qty)); + items[i] = new InventoryItem(-1, item, c.getName(), c.isStackable()); + } + } + + return Arrays.stream(items); + }) + .collect(Collectors.partitioningBy(item -> item.getItem().getQuantity() > 0)); + + final InventoryItem[] added = result.get(true).toArray(new InventoryItem[0]); + final InventoryItem[] removed = result.get(false).stream() + // Make quantities positive now that its been sorted. + .peek(i -> i.setItem(new Item(i.getItem().getId(), -i.getItem().getQuantity()))) + .toArray(InventoryItem[]::new); + + return new InventoryItem[][]{ + added, removed + }; + } + + @Nullable + private static String getNameForInventoryID(final int id) + { + for (final InventoryID inv : InventoryID.values()) + { + if (inv.getId() == id) + { + return inv.name(); + } + } + + return null; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/InventoryItem.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/InventoryItem.java new file mode 100644 index 0000000000..2409fea7f9 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/InventoryItem.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020, TheStonedTurtle + * 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.devtools; + +import lombok.AllArgsConstructor; +import lombok.Data; +import net.runelite.api.Item; + +@Data +@AllArgsConstructor +class InventoryItem +{ + private final int slot; + private Item item; + private final String name; + private final boolean stackable; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/InventoryLog.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/InventoryLog.java new file mode 100644 index 0000000000..266b90fc39 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/InventoryLog.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020, TheStonedTurtle + * 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.devtools; + +import javax.annotation.Nullable; +import lombok.Value; +import net.runelite.api.Item; + +@Value +class InventoryLog +{ + int containerId; + @Nullable + String containerName; + Item[] items; + int tick; +} + diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/InventoryLogNode.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/InventoryLogNode.java new file mode 100644 index 0000000000..9cb9bc96c2 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/InventoryLogNode.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020, TheStonedTurtle + * 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.devtools; + +import javax.swing.tree.DefaultMutableTreeNode; +import lombok.Getter; + +@Getter +class InventoryLogNode extends DefaultMutableTreeNode +{ + private final InventoryLog log; + + InventoryLogNode(final InventoryLog log) + { + super(); + + this.log = log; + } + + @Override + public String toString() + { + return "Tick: " + log.getTick(); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/InventoryTreeNode.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/InventoryTreeNode.java new file mode 100644 index 0000000000..de4b5db4c0 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/InventoryTreeNode.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020, TheStonedTurtle + * 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.devtools; + +import javax.annotation.Nullable; +import javax.swing.tree.DefaultMutableTreeNode; +import lombok.Getter; + +@Getter +class InventoryTreeNode extends DefaultMutableTreeNode +{ + final int id; + @Nullable + final String name; + + InventoryTreeNode(final int id, @Nullable final String name) + { + super(); + + this.id = id; + this.name = name; + } + + @Override + public String toString() + { + return id + (name == null ? "" : " - " + name); + } +}