From 0d0bccada584a270132d34d6f0bbbf376b3ad023 Mon Sep 17 00:00:00 2001 From: PKLite Date: Thu, 6 Jun 2019 23:57:10 -0400 Subject: [PATCH 1/8] Added pvp deaths to loottracking plugin. Signed-off-by: PKLite --- .../http/api/loottracker/LootRecordType.java | 1 + .../plugins/loottracker/LootTrackerBox.java | 4 +- .../loottracker/LootTrackerPlugin.java | 119 ++++++++++++++++++ .../loottracker/LootTrackerRecord.java | 104 +++++++-------- 4 files changed, 175 insertions(+), 53 deletions(-) diff --git a/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecordType.java b/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecordType.java index c91817b410..daf515b896 100644 --- a/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecordType.java +++ b/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecordType.java @@ -29,5 +29,6 @@ public enum LootRecordType NPC, PLAYER, EVENT, + DEATH, UNKNOWN } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerBox.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerBox.java index f37be3eb43..2022e5f72c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerBox.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerBox.java @@ -229,7 +229,7 @@ class LootTrackerBox extends JPanel } } - if (quantity > 0) + if (quantity != 0) { int newQuantity = entry.getQuantity() + quantity; long pricePerItem = entry.getPrice() == 0 ? 0 : (entry.getPrice() / entry.getQuantity()); @@ -263,7 +263,7 @@ class LootTrackerBox extends JPanel imageLabel.setVerticalAlignment(SwingConstants.CENTER); imageLabel.setHorizontalAlignment(SwingConstants.CENTER); - AsyncBufferedImage itemImage = itemManager.getImage(item.getId(), item.getQuantity(), item.getQuantity() > 1); + AsyncBufferedImage itemImage = itemManager.getImage(item.getId(), Math.abs(item.getQuantity()), Math.abs(item.getQuantity()) > 1); if (item.isIgnored()) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java index 77c151bfc4..24e2a92e80 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java @@ -27,6 +27,7 @@ package net.runelite.client.plugins.loottracker; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Multiset; import com.google.common.collect.Multisets; import com.google.inject.Provides; @@ -58,10 +59,13 @@ import net.runelite.api.ItemContainer; import net.runelite.api.NPC; import net.runelite.api.Player; import net.runelite.api.SpriteID; +import net.runelite.api.Varbits; +import net.runelite.api.WorldType; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.ChatMessage; import net.runelite.api.events.ConfigChanged; import net.runelite.api.events.ItemContainerChanged; +import net.runelite.api.events.LocalPlayerDeath; import net.runelite.api.events.WidgetLoaded; import net.runelite.api.widgets.WidgetID; import net.runelite.client.account.AccountSession; @@ -116,6 +120,16 @@ public class LootTrackerPlugin extends Plugin 11573, "Crystal Chest" ); + // Player death handling + private static final String PLAYER_DEATH_MESSAGE = "Oh dear, you are dead!"; + private static final Set RESPAWN_REGIONS = ImmutableSet.of( + 12850, // Lumbridge + 11828, // Falador + 12342, // Edgeville + 11062 // Camelot + ); + private boolean pvpDeath = false; + @Inject private ClientToolbar clientToolbar; @@ -151,6 +165,7 @@ public class LootTrackerPlugin extends Plugin private Multiset inventorySnapshot; + @Getter(AccessLevel.PACKAGE) private LootTrackerClient lootTrackerClient; @@ -209,6 +224,16 @@ public class LootTrackerPlugin extends Plugin lootTrackerClient = null; } + @Subscribe + public void onLocalPlayerDeath(LocalPlayerDeath event) + { + if (client.getVar(Varbits.IN_WILDERNESS) == 1 || WorldType.isPvpWorld(client.getWorldType())) + { + deathInventorySnapshot(); + pvpDeath = true; + } + } + @Subscribe public void onConfigChanged(ConfigChanged event) { @@ -416,6 +441,34 @@ public class LootTrackerPlugin extends Plugin final String message = event.getMessage(); + if (message.equals(PLAYER_DEATH_MESSAGE)) + { + ItemContainer inventory = client.getItemContainer(InventoryID.INVENTORY); + if (inventorySnapshot != null) + { + Multiset currentInventory = HashMultiset.create(); + if (inventory != null) + { + Arrays.stream(client.getItemContainer(InventoryID.INVENTORY).getItems()) + .forEach(item -> currentInventory.add(item.getId(), item.getQuantity())); + } + + final Multiset diff = Multisets.difference(inventorySnapshot, currentInventory); + + log.info(inventorySnapshot.toString()); + log.info(currentInventory.toString()); + log.info(diff.toString()); + + List itemsLost = diff.entrySet().stream() + .map(e -> new ItemStack(e.getElement(), (-1 * e.getCount()), client.getLocalPlayer().getLocalLocation())) + .collect(Collectors.toList()); + + final LootTrackerItem[] entries = buildEntries(stack(itemsLost)); + SwingUtilities.invokeLater(() -> panel.add("Death: " + client.getLocalPlayer().getName(), + client.getLocalPlayer().getCombatLevel(), entries)); + } + } + if (message.equals(CHEST_LOOTED_MESSAGE)) { final int regionID = client.getLocalPlayer().getWorldLocation().getRegionID(); @@ -470,6 +523,50 @@ public class LootTrackerPlugin extends Plugin @Subscribe public void onItemContainerChanged(ItemContainerChanged event) { + final ItemContainer itemContainer = event.getItemContainer(); + + if (pvpDeath && RESPAWN_REGIONS.contains(client.getLocalPlayer().getWorldLocation().getRegionID())) + { + Multiset snapshot = HashMultiset.create(); + snapshot = inventorySnapshot; + deathInventorySnapshot(); + if (inventorySnapshot != snapshot) + { + inventorySnapshot = snapshot; + ItemContainer inventory = client.getItemContainer(InventoryID.INVENTORY); + if (inventorySnapshot != null) + { + Multiset currentInventory = HashMultiset.create(); + if (inventory != null) + { + Arrays.stream(client.getItemContainer(InventoryID.INVENTORY).getItems()) + .forEach(item -> currentInventory.add(item.getId(), item.getQuantity())); + } + + final Multiset diff = Multisets.difference(inventorySnapshot, currentInventory); + + List itemsLost = diff.entrySet().stream() + .map(e -> new ItemStack(e.getElement(), (-1 * e.getCount()), client.getLocalPlayer().getLocalLocation())) + .collect(Collectors.toList()); + + final LootTrackerItem[] entries = buildEntries(stack(itemsLost)); + String name = "Death: " + client.getLocalPlayer().getName(); + SwingUtilities.invokeLater(() -> panel.add(name, + client.getLocalPlayer().getCombatLevel(), entries)); + + if (lootTrackerClient != null && config.saveLoot()) + { + LootRecord lootRecord = new LootRecord(name, LootRecordType.DEATH, toGameItems(itemsLost), + Instant.now()); + lootTrackerClient.submit(lootRecord); + } + + pvpDeath = false; + inventorySnapshot = null; + } + } + + } if (eventType != null && (CHEST_EVENT_TYPES.containsValue(eventType) || HERBIBOR_EVENT.equals(eventType))) { if (event.getItemContainer() != client.getItemContainer(InventoryID.INVENTORY)) @@ -482,6 +579,28 @@ public class LootTrackerPlugin extends Plugin } } + /** + * Takes a snapshot of the local player's inventory and equipment right before respawn. + */ + private void deathInventorySnapshot() + { + final ItemContainer inventory = client.getItemContainer(InventoryID.INVENTORY); + final ItemContainer equipment = client.getItemContainer(InventoryID.EQUIPMENT); + inventorySnapshot = HashMultiset.create(); + if (inventory != null) + { + + Arrays.stream(inventory.getItems()) + .forEach(item -> inventorySnapshot.add(item.getId(), item.getQuantity())); + } + + if (equipment != null) + { + Arrays.stream(equipment.getItems()) + .forEach(item -> inventorySnapshot.add(item.getId(), item.getQuantity())); + } + } + private void takeInventorySnapshot() { final ItemContainer itemContainer = client.getItemContainer(InventoryID.INVENTORY); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerRecord.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerRecord.java index df03f7a75b..f3118b416a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerRecord.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerRecord.java @@ -1,52 +1,54 @@ -/* - * Copyright (c) 2018, Psikoi - * 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.loottracker; - -import lombok.Value; - -@Value -class LootTrackerRecord -{ - private final String title; - private final String subTitle; - private final LootTrackerItem[] items; - private final long timestamp; - - /** - * Checks if this record matches specified id - * - * @param id other record id - * @return true if match is made - */ - boolean matches(final String id) - { - if (id == null) - { - return true; - } - - return title.equals(id); - } +/* + * Copyright (c) 2018, Psikoi + * 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.loottracker; + +import com.google.gson.annotations.SerializedName; +import lombok.Value; + +@Value +class LootTrackerRecord +{ + private final String title; + private final String subTitle; + @SerializedName("item_records") + private final LootTrackerItem[] items; + private final long timestamp; + + /** + * Checks if this record matches specified id + * + * @param id other record id + * @return true if match is made + */ + boolean matches(final String id) + { + if (id == null) + { + return true; + } + + return title.equals(id); + } } \ No newline at end of file From eee22165a9cd0dc39d902f8dfa92bae984c5b707 Mon Sep 17 00:00:00 2001 From: PKLite Date: Fri, 7 Jun 2019 04:02:15 -0400 Subject: [PATCH 2/8] Add local local loottracker data persistence Signed-off-by: PKLite --- .../loottracker/LootTrackerConfig.java | 12 ++ .../loottracker/LootTrackerPlugin.java | 110 +++++++++++++++--- 2 files changed, 103 insertions(+), 19 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java index 597dcfddf9..8410c8a5be 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java @@ -80,4 +80,16 @@ public interface LootTrackerConfig extends Config { return true; } + + @ConfigItem( + keyName = "localPersistence", + name = "Local Record Persistence", + description = "Stores/syncs loot records locally in the JSON format. Note: records will not be saved locally" + + " if they are successfully saved online. " + ) + default boolean localPersistence() + { + return true; + } + } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java index 24e2a92e80..6d4e744e5d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java @@ -30,9 +30,19 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Multiset; import com.google.common.collect.Multisets; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonStreamParser; +import com.google.gson.reflect.TypeToken; import com.google.inject.Provides; import java.awt.image.BufferedImage; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; import java.io.IOException; +import java.nio.file.Files; import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; @@ -68,6 +78,7 @@ import net.runelite.api.events.ItemContainerChanged; import net.runelite.api.events.LocalPlayerDeath; import net.runelite.api.events.WidgetLoaded; import net.runelite.api.widgets.WidgetID; +import net.runelite.client.RuneLite; import net.runelite.client.account.AccountSession; import net.runelite.client.account.SessionManager; import net.runelite.client.callback.ClientThread; @@ -91,6 +102,7 @@ import net.runelite.client.ui.NavigationButton; import net.runelite.client.util.ImageUtil; import net.runelite.client.util.StackFormatter; import net.runelite.client.util.Text; +import net.runelite.http.api.RuneLiteAPI; import net.runelite.http.api.loottracker.GameItem; import net.runelite.http.api.loottracker.LootRecord; import net.runelite.http.api.loottracker.LootRecordType; @@ -120,8 +132,9 @@ public class LootTrackerPlugin extends Plugin 11573, "Crystal Chest" ); - // Player death handling + // Player deaths private static final String PLAYER_DEATH_MESSAGE = "Oh dear, you are dead!"; + private static final File LOOT_RECORDS_FILE = new File(RuneLite.RUNELITE_DIR, "lootRecords.json"); private static final Set RESPAWN_REGIONS = ImmutableSet.of( 12850, // Lumbridge 11828, // Falador @@ -168,6 +181,9 @@ public class LootTrackerPlugin extends Plugin @Getter(AccessLevel.PACKAGE) private LootTrackerClient lootTrackerClient; + private BufferedReader bufferedReader; + private JsonStreamParser jsonStreamParser; + private Collection lootRecords = new ArrayList<>(); private static Collection stack(Collection items) { @@ -263,9 +279,10 @@ public class LootTrackerPlugin extends Plugin clientToolbar.addNavigation(navButton); AccountSession accountSession = sessionManager.getAccountSession(); - if (accountSession != null) + LOOT_RECORDS_FILE.createNewFile(); + bufferedReader = Files.newBufferedReader(LOOT_RECORDS_FILE.toPath()); + if (accountSession != null || config.localPersistence()) { - lootTrackerClient = new LootTrackerClient(accountSession.getUuid()); clientThread.invokeLater(() -> { @@ -278,28 +295,41 @@ public class LootTrackerPlugin extends Plugin executor.submit(() -> { - Collection lootRecords; - if (!config.syncPanel()) + if (config.syncPanel() && lootTrackerClient != null) { - return; + lootTrackerClient = new LootTrackerClient(accountSession.getUuid()); + try + { + lootRecords = lootTrackerClient.get(); + } + catch (IOException e) + { + log.debug("Unable to look up loot", e); + return; + } + log.debug("Loaded {} remote data entries", lootRecords.size()); } - try + if (config.localPersistence() ) { - lootRecords = lootTrackerClient.get(); - } - catch (IOException e) - { - log.debug("Unable to look up loot", e); - return; + try + { + lootRecords.addAll(RuneLiteAPI.GSON.fromJson(new FileReader(LOOT_RECORDS_FILE), + new TypeToken>() + { }.getType())); + } + catch (IOException e) + { + e.printStackTrace(); + } } - log.debug("Loaded {} data entries", lootRecords.size()); + Collection finalLootRecords = lootRecords; clientThread.invokeLater(() -> { - Collection records = convertToLootTrackerRecord(lootRecords); + Collection records = convertToLootTrackerRecord(finalLootRecords); SwingUtilities.invokeLater(() -> panel.addRecords(records)); }); }); @@ -324,12 +354,16 @@ public class LootTrackerPlugin extends Plugin final int combat = npc.getCombatLevel(); final LootTrackerItem[] entries = buildEntries(stack(items)); SwingUtilities.invokeLater(() -> panel.add(name, combat, entries)); + LootRecord lootRecord = new LootRecord(name, LootRecordType.NPC, toGameItems(items), Instant.now()); if (lootTrackerClient != null && config.saveLoot()) { - LootRecord lootRecord = new LootRecord(name, LootRecordType.NPC, toGameItems(items), Instant.now()); lootTrackerClient.submit(lootRecord); } + if (config.localPersistence()) + { + saveLocalLootRecord(lootRecord); + } } @Subscribe @@ -341,12 +375,16 @@ public class LootTrackerPlugin extends Plugin final int combat = player.getCombatLevel(); final LootTrackerItem[] entries = buildEntries(stack(items)); SwingUtilities.invokeLater(() -> panel.add(name, combat, entries)); + LootRecord lootRecord = new LootRecord(name, LootRecordType.PLAYER, toGameItems(items), Instant.now()); if (lootTrackerClient != null && config.saveLoot()) { - LootRecord lootRecord = new LootRecord(name, LootRecordType.PLAYER, toGameItems(items), Instant.now()); lootTrackerClient.submit(lootRecord); } + if (config.localPersistence() && lootTrackerClient == null) + { + saveLocalLootRecord(lootRecord); + } } @Subscribe @@ -553,13 +591,17 @@ public class LootTrackerPlugin extends Plugin String name = "Death: " + client.getLocalPlayer().getName(); SwingUtilities.invokeLater(() -> panel.add(name, client.getLocalPlayer().getCombatLevel(), entries)); + LootRecord lootRecord = new LootRecord(name, LootRecordType.DEATH, toGameItems(itemsLost), + Instant.now()); if (lootTrackerClient != null && config.saveLoot()) { - LootRecord lootRecord = new LootRecord(name, LootRecordType.DEATH, toGameItems(itemsLost), - Instant.now()); lootTrackerClient.submit(lootRecord); } + if (config.localPersistence() && lootTrackerClient == null) + { + saveLocalLootRecord(lootRecord); + } pvpDeath = false; inventorySnapshot = null; @@ -579,6 +621,36 @@ public class LootTrackerPlugin extends Plugin } } + private void saveLocalLootRecord(LootRecord lootRecord) + { + lootRecords.add(lootRecord); + try + { + BufferedWriter bufferedWriter = Files.newBufferedWriter(LOOT_RECORDS_FILE.toPath()); + + GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.setPrettyPrinting(); + Gson gson = gsonBuilder.create(); + bufferedWriter.append(gson.toJson(lootRecords)); + bufferedWriter.close(); + } + catch (IOException e) + { + if (e instanceof FileNotFoundException) + { + try + { + LOOT_RECORDS_FILE.createNewFile(); + } + catch (IOException ex) + { + ex.printStackTrace(); + } + } + e.printStackTrace(); + } + } + /** * Takes a snapshot of the local player's inventory and equipment right before respawn. */ From 1af704c6085965f8136359636be2eb888d309df5 Mon Sep 17 00:00:00 2001 From: PKLite Date: Sat, 8 Jun 2019 01:08:58 -0400 Subject: [PATCH 3/8] Revert to old project structure Signed-off-by: PKLite --- .../http/api/loottracker/LootRecordType.java | 1 + .../plugins/loottracker/LootTrackerBox.java | 4 +- .../loottracker/LootTrackerConfig.java | 12 + .../loottracker/LootTrackerPlugin.java | 223 ++++++++++++++++-- .../loottracker/LootTrackerRecord.java | 2 + 5 files changed, 224 insertions(+), 18 deletions(-) diff --git a/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecordType.java b/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecordType.java index c91817b410..daf515b896 100644 --- a/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecordType.java +++ b/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecordType.java @@ -29,5 +29,6 @@ public enum LootRecordType NPC, PLAYER, EVENT, + DEATH, UNKNOWN } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerBox.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerBox.java index f37be3eb43..2022e5f72c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerBox.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerBox.java @@ -229,7 +229,7 @@ class LootTrackerBox extends JPanel } } - if (quantity > 0) + if (quantity != 0) { int newQuantity = entry.getQuantity() + quantity; long pricePerItem = entry.getPrice() == 0 ? 0 : (entry.getPrice() / entry.getQuantity()); @@ -263,7 +263,7 @@ class LootTrackerBox extends JPanel imageLabel.setVerticalAlignment(SwingConstants.CENTER); imageLabel.setHorizontalAlignment(SwingConstants.CENTER); - AsyncBufferedImage itemImage = itemManager.getImage(item.getId(), item.getQuantity(), item.getQuantity() > 1); + AsyncBufferedImage itemImage = itemManager.getImage(item.getId(), Math.abs(item.getQuantity()), Math.abs(item.getQuantity()) > 1); if (item.isIgnored()) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java index 597dcfddf9..8410c8a5be 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java @@ -80,4 +80,16 @@ public interface LootTrackerConfig extends Config { return true; } + + @ConfigItem( + keyName = "localPersistence", + name = "Local Record Persistence", + description = "Stores/syncs loot records locally in the JSON format. Note: records will not be saved locally" + + " if they are successfully saved online. " + ) + default boolean localPersistence() + { + return true; + } + } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java index 77c151bfc4..6d4e744e5d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java @@ -27,11 +27,22 @@ package net.runelite.client.plugins.loottracker; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Multiset; import com.google.common.collect.Multisets; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonStreamParser; +import com.google.gson.reflect.TypeToken; import com.google.inject.Provides; import java.awt.image.BufferedImage; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; import java.io.IOException; +import java.nio.file.Files; import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; @@ -58,12 +69,16 @@ import net.runelite.api.ItemContainer; import net.runelite.api.NPC; import net.runelite.api.Player; import net.runelite.api.SpriteID; +import net.runelite.api.Varbits; +import net.runelite.api.WorldType; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.ChatMessage; import net.runelite.api.events.ConfigChanged; import net.runelite.api.events.ItemContainerChanged; +import net.runelite.api.events.LocalPlayerDeath; import net.runelite.api.events.WidgetLoaded; import net.runelite.api.widgets.WidgetID; +import net.runelite.client.RuneLite; import net.runelite.client.account.AccountSession; import net.runelite.client.account.SessionManager; import net.runelite.client.callback.ClientThread; @@ -87,6 +102,7 @@ import net.runelite.client.ui.NavigationButton; import net.runelite.client.util.ImageUtil; import net.runelite.client.util.StackFormatter; import net.runelite.client.util.Text; +import net.runelite.http.api.RuneLiteAPI; import net.runelite.http.api.loottracker.GameItem; import net.runelite.http.api.loottracker.LootRecord; import net.runelite.http.api.loottracker.LootRecordType; @@ -116,6 +132,17 @@ public class LootTrackerPlugin extends Plugin 11573, "Crystal Chest" ); + // Player deaths + private static final String PLAYER_DEATH_MESSAGE = "Oh dear, you are dead!"; + private static final File LOOT_RECORDS_FILE = new File(RuneLite.RUNELITE_DIR, "lootRecords.json"); + private static final Set RESPAWN_REGIONS = ImmutableSet.of( + 12850, // Lumbridge + 11828, // Falador + 12342, // Edgeville + 11062 // Camelot + ); + private boolean pvpDeath = false; + @Inject private ClientToolbar clientToolbar; @@ -151,8 +178,12 @@ public class LootTrackerPlugin extends Plugin private Multiset inventorySnapshot; + @Getter(AccessLevel.PACKAGE) private LootTrackerClient lootTrackerClient; + private BufferedReader bufferedReader; + private JsonStreamParser jsonStreamParser; + private Collection lootRecords = new ArrayList<>(); private static Collection stack(Collection items) { @@ -209,6 +240,16 @@ public class LootTrackerPlugin extends Plugin lootTrackerClient = null; } + @Subscribe + public void onLocalPlayerDeath(LocalPlayerDeath event) + { + if (client.getVar(Varbits.IN_WILDERNESS) == 1 || WorldType.isPvpWorld(client.getWorldType())) + { + deathInventorySnapshot(); + pvpDeath = true; + } + } + @Subscribe public void onConfigChanged(ConfigChanged event) { @@ -238,9 +279,10 @@ public class LootTrackerPlugin extends Plugin clientToolbar.addNavigation(navButton); AccountSession accountSession = sessionManager.getAccountSession(); - if (accountSession != null) + LOOT_RECORDS_FILE.createNewFile(); + bufferedReader = Files.newBufferedReader(LOOT_RECORDS_FILE.toPath()); + if (accountSession != null || config.localPersistence()) { - lootTrackerClient = new LootTrackerClient(accountSession.getUuid()); clientThread.invokeLater(() -> { @@ -253,28 +295,41 @@ public class LootTrackerPlugin extends Plugin executor.submit(() -> { - Collection lootRecords; - if (!config.syncPanel()) + if (config.syncPanel() && lootTrackerClient != null) { - return; + lootTrackerClient = new LootTrackerClient(accountSession.getUuid()); + try + { + lootRecords = lootTrackerClient.get(); + } + catch (IOException e) + { + log.debug("Unable to look up loot", e); + return; + } + log.debug("Loaded {} remote data entries", lootRecords.size()); } - try + if (config.localPersistence() ) { - lootRecords = lootTrackerClient.get(); - } - catch (IOException e) - { - log.debug("Unable to look up loot", e); - return; + try + { + lootRecords.addAll(RuneLiteAPI.GSON.fromJson(new FileReader(LOOT_RECORDS_FILE), + new TypeToken>() + { }.getType())); + } + catch (IOException e) + { + e.printStackTrace(); + } } - log.debug("Loaded {} data entries", lootRecords.size()); + Collection finalLootRecords = lootRecords; clientThread.invokeLater(() -> { - Collection records = convertToLootTrackerRecord(lootRecords); + Collection records = convertToLootTrackerRecord(finalLootRecords); SwingUtilities.invokeLater(() -> panel.addRecords(records)); }); }); @@ -299,12 +354,16 @@ public class LootTrackerPlugin extends Plugin final int combat = npc.getCombatLevel(); final LootTrackerItem[] entries = buildEntries(stack(items)); SwingUtilities.invokeLater(() -> panel.add(name, combat, entries)); + LootRecord lootRecord = new LootRecord(name, LootRecordType.NPC, toGameItems(items), Instant.now()); if (lootTrackerClient != null && config.saveLoot()) { - LootRecord lootRecord = new LootRecord(name, LootRecordType.NPC, toGameItems(items), Instant.now()); lootTrackerClient.submit(lootRecord); } + if (config.localPersistence()) + { + saveLocalLootRecord(lootRecord); + } } @Subscribe @@ -316,12 +375,16 @@ public class LootTrackerPlugin extends Plugin final int combat = player.getCombatLevel(); final LootTrackerItem[] entries = buildEntries(stack(items)); SwingUtilities.invokeLater(() -> panel.add(name, combat, entries)); + LootRecord lootRecord = new LootRecord(name, LootRecordType.PLAYER, toGameItems(items), Instant.now()); if (lootTrackerClient != null && config.saveLoot()) { - LootRecord lootRecord = new LootRecord(name, LootRecordType.PLAYER, toGameItems(items), Instant.now()); lootTrackerClient.submit(lootRecord); } + if (config.localPersistence() && lootTrackerClient == null) + { + saveLocalLootRecord(lootRecord); + } } @Subscribe @@ -416,6 +479,34 @@ public class LootTrackerPlugin extends Plugin final String message = event.getMessage(); + if (message.equals(PLAYER_DEATH_MESSAGE)) + { + ItemContainer inventory = client.getItemContainer(InventoryID.INVENTORY); + if (inventorySnapshot != null) + { + Multiset currentInventory = HashMultiset.create(); + if (inventory != null) + { + Arrays.stream(client.getItemContainer(InventoryID.INVENTORY).getItems()) + .forEach(item -> currentInventory.add(item.getId(), item.getQuantity())); + } + + final Multiset diff = Multisets.difference(inventorySnapshot, currentInventory); + + log.info(inventorySnapshot.toString()); + log.info(currentInventory.toString()); + log.info(diff.toString()); + + List itemsLost = diff.entrySet().stream() + .map(e -> new ItemStack(e.getElement(), (-1 * e.getCount()), client.getLocalPlayer().getLocalLocation())) + .collect(Collectors.toList()); + + final LootTrackerItem[] entries = buildEntries(stack(itemsLost)); + SwingUtilities.invokeLater(() -> panel.add("Death: " + client.getLocalPlayer().getName(), + client.getLocalPlayer().getCombatLevel(), entries)); + } + } + if (message.equals(CHEST_LOOTED_MESSAGE)) { final int regionID = client.getLocalPlayer().getWorldLocation().getRegionID(); @@ -470,6 +561,54 @@ public class LootTrackerPlugin extends Plugin @Subscribe public void onItemContainerChanged(ItemContainerChanged event) { + final ItemContainer itemContainer = event.getItemContainer(); + + if (pvpDeath && RESPAWN_REGIONS.contains(client.getLocalPlayer().getWorldLocation().getRegionID())) + { + Multiset snapshot = HashMultiset.create(); + snapshot = inventorySnapshot; + deathInventorySnapshot(); + if (inventorySnapshot != snapshot) + { + inventorySnapshot = snapshot; + ItemContainer inventory = client.getItemContainer(InventoryID.INVENTORY); + if (inventorySnapshot != null) + { + Multiset currentInventory = HashMultiset.create(); + if (inventory != null) + { + Arrays.stream(client.getItemContainer(InventoryID.INVENTORY).getItems()) + .forEach(item -> currentInventory.add(item.getId(), item.getQuantity())); + } + + final Multiset diff = Multisets.difference(inventorySnapshot, currentInventory); + + List itemsLost = diff.entrySet().stream() + .map(e -> new ItemStack(e.getElement(), (-1 * e.getCount()), client.getLocalPlayer().getLocalLocation())) + .collect(Collectors.toList()); + + final LootTrackerItem[] entries = buildEntries(stack(itemsLost)); + String name = "Death: " + client.getLocalPlayer().getName(); + SwingUtilities.invokeLater(() -> panel.add(name, + client.getLocalPlayer().getCombatLevel(), entries)); + LootRecord lootRecord = new LootRecord(name, LootRecordType.DEATH, toGameItems(itemsLost), + Instant.now()); + + if (lootTrackerClient != null && config.saveLoot()) + { + lootTrackerClient.submit(lootRecord); + } + if (config.localPersistence() && lootTrackerClient == null) + { + saveLocalLootRecord(lootRecord); + } + + pvpDeath = false; + inventorySnapshot = null; + } + } + + } if (eventType != null && (CHEST_EVENT_TYPES.containsValue(eventType) || HERBIBOR_EVENT.equals(eventType))) { if (event.getItemContainer() != client.getItemContainer(InventoryID.INVENTORY)) @@ -482,6 +621,58 @@ public class LootTrackerPlugin extends Plugin } } + private void saveLocalLootRecord(LootRecord lootRecord) + { + lootRecords.add(lootRecord); + try + { + BufferedWriter bufferedWriter = Files.newBufferedWriter(LOOT_RECORDS_FILE.toPath()); + + GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.setPrettyPrinting(); + Gson gson = gsonBuilder.create(); + bufferedWriter.append(gson.toJson(lootRecords)); + bufferedWriter.close(); + } + catch (IOException e) + { + if (e instanceof FileNotFoundException) + { + try + { + LOOT_RECORDS_FILE.createNewFile(); + } + catch (IOException ex) + { + ex.printStackTrace(); + } + } + e.printStackTrace(); + } + } + + /** + * Takes a snapshot of the local player's inventory and equipment right before respawn. + */ + private void deathInventorySnapshot() + { + final ItemContainer inventory = client.getItemContainer(InventoryID.INVENTORY); + final ItemContainer equipment = client.getItemContainer(InventoryID.EQUIPMENT); + inventorySnapshot = HashMultiset.create(); + if (inventory != null) + { + + Arrays.stream(inventory.getItems()) + .forEach(item -> inventorySnapshot.add(item.getId(), item.getQuantity())); + } + + if (equipment != null) + { + Arrays.stream(equipment.getItems()) + .forEach(item -> inventorySnapshot.add(item.getId(), item.getQuantity())); + } + } + private void takeInventorySnapshot() { final ItemContainer itemContainer = client.getItemContainer(InventoryID.INVENTORY); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerRecord.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerRecord.java index a47dc0c07f..f3118b416a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerRecord.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerRecord.java @@ -24,6 +24,7 @@ */ package net.runelite.client.plugins.loottracker; +import com.google.gson.annotations.SerializedName; import lombok.Value; @Value @@ -31,6 +32,7 @@ class LootTrackerRecord { private final String title; private final String subTitle; + @SerializedName("item_records") private final LootTrackerItem[] items; private final long timestamp; From ede14db9b200fa2301cf0c5523eb9ccfdfad3b0a Mon Sep 17 00:00:00 2001 From: PKLite Date: Sun, 9 Jun 2019 00:08:12 -0400 Subject: [PATCH 4/8] Automatically filters loot tracker loot to only show loot that the currently logged in account has received and to show all loot from all accounts on login screen Signed-off-by: PKLite --- .../http/api/loottracker/LootRecord.java | 3 + .../plugins/loottracker/LootTrackerPanel.java | 42 +++++++-- .../loottracker/LootTrackerPlugin.java | 87 +++++++++---------- .../loottracker/LootTrackerRecord.java | 1 + 4 files changed, 82 insertions(+), 51 deletions(-) diff --git a/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecord.java b/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecord.java index fc945220f1..4a802a12fb 100644 --- a/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecord.java +++ b/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecord.java @@ -28,6 +28,7 @@ import java.time.Instant; import java.util.Collection; import lombok.AllArgsConstructor; import lombok.Data; +import lombok.Getter; import lombok.NoArgsConstructor; @Data @@ -36,6 +37,8 @@ import lombok.NoArgsConstructor; public class LootRecord { private String eventId; + @Getter + private String username; private LootRecordType type; private Collection drops; private Instant time; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPanel.java index d9729ee97c..f8442137e3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPanel.java @@ -35,6 +35,7 @@ import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Objects; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.ImageIcon; @@ -43,6 +44,8 @@ import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.border.EmptyBorder; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.GameState; import net.runelite.client.game.ItemManager; import net.runelite.client.ui.ColorScheme; import net.runelite.client.ui.FontManager; @@ -53,6 +56,7 @@ import net.runelite.client.util.ImageUtil; import net.runelite.client.util.StackFormatter; import net.runelite.http.api.loottracker.LootTrackerClient; +@Slf4j class LootTrackerPanel extends PluginPanel { private static final int MAX_LOOT_BOXES = 500; @@ -131,6 +135,8 @@ class LootTrackerPanel extends PluginPanel INVISIBLE_ICON_HOVER = new ImageIcon(ImageUtil.alphaOffset(invisibleImg, -220)); } + private final JPanel displaySelector; + LootTrackerPanel(final LootTrackerPlugin plugin, final ItemManager itemManager, final LootTrackerConfig config) { this.itemManager = itemManager; @@ -289,6 +295,11 @@ class LootTrackerPanel extends PluginPanel overallPanel.add(overallIcon, BorderLayout.WEST); overallPanel.add(overallInfo, BorderLayout.CENTER); + displaySelector = new JPanel(); + displaySelector.setLayout(new GridLayout(1, 1)); + displaySelector.setBorder(new EmptyBorder(2, 10, 10, 10)); + displaySelector.setBackground(ColorScheme.DARKER_GRAY_COLOR); + // Create reset all menu final JMenuItem reset = new JMenuItem("Reset All"); reset.addActionListener(e -> @@ -318,6 +329,7 @@ class LootTrackerPanel extends PluginPanel logsContainer.setLayout(new BoxLayout(logsContainer, BoxLayout.Y_AXIS)); layoutPanel.add(actionsContainer); layoutPanel.add(overallPanel); + layoutPanel.add(displaySelector); layoutPanel.add(logsContainer); // Add error pane @@ -335,10 +347,10 @@ class LootTrackerPanel extends PluginPanel * Creates a subtitle, adds a new entry and then passes off to the render methods, that will decide * how to display this new data. */ - void add(final String eventName, final int actorLevel, LootTrackerItem[] items) + void add(final String eventName, final String localUsername, final int actorLevel, LootTrackerItem[] items) { final String subTitle = actorLevel > -1 ? "(lvl-" + actorLevel + ")" : ""; - final LootTrackerRecord record = new LootTrackerRecord(eventName, subTitle, items, System.currentTimeMillis()); + final LootTrackerRecord record = new LootTrackerRecord( eventName, localUsername, subTitle, items, System.currentTimeMillis()); records.add(record); LootTrackerBox box = buildBox(record); if (box != null) @@ -405,8 +417,9 @@ class LootTrackerPanel extends PluginPanel /** * Rebuilds all the boxes from scratch using existing listed records, depending on the grouping mode. */ - private void rebuild() + public void rebuild() { + logsContainer.removeAll(); boxes.clear(); int start = 0; @@ -422,6 +435,8 @@ class LootTrackerPanel extends PluginPanel updateOverall(); logsContainer.revalidate(); logsContainer.repaint(); + + } /** @@ -431,12 +446,21 @@ class LootTrackerPanel extends PluginPanel */ private LootTrackerBox buildBox(LootTrackerRecord record) { + // If this record is not part of current view, return if (!record.matches(currentView)) { return null; } + if (this.plugin.client.getGameState().equals(GameState.LOGGED_IN)) + { + if (!(this.plugin.client.getLocalPlayer().getName().equals(record.getLocalUsername()))) + { + return null; + } + } + // Group all similar loot together if (groupLoot) { @@ -456,7 +480,8 @@ class LootTrackerPanel extends PluginPanel overallPanel.setVisible(true); // Create box - final LootTrackerBox box = new LootTrackerBox(itemManager, record.getTitle(), record.getSubTitle(), hideIgnoredItems, plugin::toggleItem); + final LootTrackerBox box = new LootTrackerBox(itemManager, record.getTitle(), record.getSubTitle(), + hideIgnoredItems, plugin::toggleItem); box.combine(record); // Create popup menu @@ -519,6 +544,14 @@ class LootTrackerPanel extends PluginPanel { continue; } + if (Objects.nonNull(record.getLocalUsername()) && Objects.nonNull(plugin.client.getLocalPlayer())) + { + if (!record.getLocalUsername().equals(plugin.client.getLocalPlayer().getName())) + { + + continue; + } + } int present = record.getItems().length; @@ -542,7 +575,6 @@ class LootTrackerPanel extends PluginPanel overallKillsLabel.setText(htmlLabel("Total count: ", overallKills)); overallGpLabel.setText(htmlLabel("Total value: ", overallGp)); } - private static String htmlLabel(String key, long value) { final String valueStr = StackFormatter.quantityToStackSize(value); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java index f3ce3d939f..b7e11c29c5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java @@ -64,8 +64,8 @@ import net.runelite.api.ChatMessageType; import net.runelite.api.Client; import net.runelite.api.InventoryID; import net.runelite.api.Item; -import net.runelite.api.ItemDefinition; import net.runelite.api.ItemContainer; +import net.runelite.api.ItemDefinition; import net.runelite.api.NPC; import net.runelite.api.Player; import net.runelite.api.SpriteID; @@ -76,6 +76,7 @@ import net.runelite.api.events.ChatMessage; import net.runelite.api.events.ConfigChanged; import net.runelite.api.events.ItemContainerChanged; import net.runelite.api.events.LocalPlayerDeath; +import net.runelite.api.events.PlayerSpawned; import net.runelite.api.events.WidgetLoaded; import net.runelite.api.widgets.WidgetID; import net.runelite.client.RuneLite; @@ -133,7 +134,8 @@ public class LootTrackerPlugin extends Plugin ); // Player deaths - private static final String PLAYER_DEATH_MESSAGE = "Oh dear, you are dead!"; + public static HashSet usernameSet = new HashSet(Arrays.stream(new String[]{"All Records"}).collect(Collectors.toList())); + private static final File LOOT_RECORDS_FILE = new File(RuneLite.RUNELITE_DIR, "lootRecords.json"); private static final Set RESPAWN_REGIONS = ImmutableSet.of( 12850, // Lumbridge @@ -159,7 +161,7 @@ public class LootTrackerPlugin extends Plugin private LootTrackerConfig config; @Inject - private Client client; + public Client client; @Inject private ClientThread clientThread; @@ -178,7 +180,6 @@ public class LootTrackerPlugin extends Plugin private Multiset inventorySnapshot; - @Getter(AccessLevel.PACKAGE) private LootTrackerClient lootTrackerClient; private BufferedReader bufferedReader; @@ -318,6 +319,7 @@ public class LootTrackerPlugin extends Plugin lootRecords.addAll(RuneLiteAPI.GSON.fromJson(new FileReader(LOOT_RECORDS_FILE), new TypeToken>() { }.getType())); + } catch (IOException e) { @@ -343,6 +345,7 @@ public class LootTrackerPlugin extends Plugin { clientToolbar.removeNavigation(navButton); lootTrackerClient = null; + lootRecords = new ArrayList(); } @Subscribe @@ -353,8 +356,10 @@ public class LootTrackerPlugin extends Plugin final String name = npc.getName(); final int combat = npc.getCombatLevel(); final LootTrackerItem[] entries = buildEntries(stack(items)); - SwingUtilities.invokeLater(() -> panel.add(name, combat, entries)); - LootRecord lootRecord = new LootRecord(name, LootRecordType.NPC, toGameItems(items), Instant.now()); + String localUsername = client.getLocalPlayer().getName(); + SwingUtilities.invokeLater(() -> panel.add(name, localUsername, combat, entries)); + LootRecord lootRecord = new LootRecord( name, localUsername, LootRecordType.NPC, + toGameItems(items), Instant.now()); if (lootTrackerClient != null && config.saveLoot()) { @@ -366,6 +371,16 @@ public class LootTrackerPlugin extends Plugin } } + + @Subscribe + public void onPlayerSpawned(PlayerSpawned event) + { + if (event.getPlayer().equals(client.getLocalPlayer())) + { + SwingUtilities.invokeLater(() -> panel.rebuild()); + } + } + @Subscribe public void onPlayerLootReceived(final PlayerLootReceived playerLootReceived) { @@ -374,9 +389,10 @@ public class LootTrackerPlugin extends Plugin final String name = player.getName(); final int combat = player.getCombatLevel(); final LootTrackerItem[] entries = buildEntries(stack(items)); - SwingUtilities.invokeLater(() -> panel.add(name, combat, entries)); - LootRecord lootRecord = new LootRecord(name, LootRecordType.PLAYER, toGameItems(items), Instant.now()); - + String localUsername = client.getLocalPlayer().getName(); + SwingUtilities.invokeLater(() -> panel.add(name, localUsername, combat, entries)); + LootRecord lootRecord = new LootRecord(localUsername, name, LootRecordType.PLAYER, + toGameItems(items), Instant.now()); if (lootTrackerClient != null && config.saveLoot()) { lootTrackerClient.submit(lootRecord); @@ -447,6 +463,11 @@ public class LootTrackerPlugin extends Plugin .build()); } + if (event.getGroupId() == WidgetID.CHATBOX_GROUP_ID) + { + panel.rebuild(); + } + // Convert container items to array of ItemStack final Collection items = Arrays.stream(container.getItems()) .filter(item -> item.getId() > 0) @@ -460,11 +481,12 @@ public class LootTrackerPlugin extends Plugin } final LootTrackerItem[] entries = buildEntries(stack(items)); - SwingUtilities.invokeLater(() -> panel.add(eventType, -1, entries)); + SwingUtilities.invokeLater(() -> panel.add(client.getLocalPlayer().getName(), eventType, -1, entries)); if (lootTrackerClient != null && config.saveLoot()) { - LootRecord lootRecord = new LootRecord(eventType, LootRecordType.EVENT, toGameItems(items), Instant.now()); + LootRecord lootRecord = new LootRecord(client.getLocalPlayer().getName(), eventType, LootRecordType.EVENT, + toGameItems(items), Instant.now()); lootTrackerClient.submit(lootRecord); } } @@ -479,34 +501,6 @@ public class LootTrackerPlugin extends Plugin final String message = event.getMessage(); - if (message.equals(PLAYER_DEATH_MESSAGE)) - { - ItemContainer inventory = client.getItemContainer(InventoryID.INVENTORY); - if (inventorySnapshot != null) - { - Multiset currentInventory = HashMultiset.create(); - if (inventory != null) - { - Arrays.stream(client.getItemContainer(InventoryID.INVENTORY).getItems()) - .forEach(item -> currentInventory.add(item.getId(), item.getQuantity())); - } - - final Multiset diff = Multisets.difference(inventorySnapshot, currentInventory); - - log.info(inventorySnapshot.toString()); - log.info(currentInventory.toString()); - log.info(diff.toString()); - - List itemsLost = diff.entrySet().stream() - .map(e -> new ItemStack(e.getElement(), (-1 * e.getCount()), client.getLocalPlayer().getLocalLocation())) - .collect(Collectors.toList()); - - final LootTrackerItem[] entries = buildEntries(stack(itemsLost)); - SwingUtilities.invokeLater(() -> panel.add("Death: " + client.getLocalPlayer().getName(), - client.getLocalPlayer().getCombatLevel(), entries)); - } - } - if (message.equals(CHEST_LOOTED_MESSAGE)) { final int regionID = client.getLocalPlayer().getWorldLocation().getRegionID(); @@ -589,11 +583,10 @@ public class LootTrackerPlugin extends Plugin final LootTrackerItem[] entries = buildEntries(stack(itemsLost)); String name = "Death: " + client.getLocalPlayer().getName(); - SwingUtilities.invokeLater(() -> panel.add(name, + SwingUtilities.invokeLater(() -> panel.add(name, client.getLocalPlayer().getName(), client.getLocalPlayer().getCombatLevel(), entries)); - LootRecord lootRecord = new LootRecord(name, LootRecordType.DEATH, toGameItems(itemsLost), - Instant.now()); - + LootRecord lootRecord = new LootRecord(name, client.getLocalPlayer().getName(), LootRecordType.DEATH, + toGameItems(itemsLost), Instant.now()); if (lootTrackerClient != null && config.saveLoot()) { lootTrackerClient.submit(lootRecord); @@ -699,11 +692,12 @@ public class LootTrackerPlugin extends Plugin .collect(Collectors.toList()); final LootTrackerItem[] entries = buildEntries(stack(items)); - SwingUtilities.invokeLater(() -> panel.add(chestType, -1, entries)); + SwingUtilities.invokeLater(() -> panel.add(client.getLocalPlayer().getName(), chestType, -1, entries)); if (lootTrackerClient != null && config.saveLoot()) { - LootRecord lootRecord = new LootRecord(chestType, LootRecordType.EVENT, toGameItems(items), Instant.now()); + LootRecord lootRecord = new LootRecord(client.getLocalPlayer().getName(), chestType, + LootRecordType.EVENT, toGameItems(items), Instant.now()); lootTrackerClient.submit(lootRecord); } @@ -771,7 +765,8 @@ public class LootTrackerPlugin extends Plugin buildLootTrackerItem(itemStack.getId(), itemStack.getQty()) ).toArray(LootTrackerItem[]::new); - trackerRecords.add(new LootTrackerRecord(record.getEventId(), "", drops, -1)); + trackerRecords.add(new LootTrackerRecord(record.getEventId(), record.getUsername(), + "", drops, -1)); } return trackerRecords; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerRecord.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerRecord.java index f3118b416a..a92ff0009f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerRecord.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerRecord.java @@ -31,6 +31,7 @@ import lombok.Value; class LootTrackerRecord { private final String title; + private String localUsername; private final String subTitle; @SerializedName("item_records") private final LootTrackerItem[] items; From e3aa3fd2fd8a43786f480c5cff84a2c514bbc9b8 Mon Sep 17 00:00:00 2001 From: PKLite Date: Sun, 9 Jun 2019 00:55:11 -0400 Subject: [PATCH 5/8] Add Loot Record Comparator enum for sorting LootRecords Signed-off-by: PKLite --- .../loottracker/LootRecordSortType.java | 39 +++++++++++++++++++ .../plugins/loottracker/LootTrackerBox.java | 1 + 2 files changed, 40 insertions(+) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootRecordSortType.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootRecordSortType.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootRecordSortType.java new file mode 100644 index 0000000000..6efd941100 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootRecordSortType.java @@ -0,0 +1,39 @@ +package net.runelite.client.plugins.loottracker; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.stream.IntStream; + +/** + * + */ +public enum LootRecordSortType implements Comparator +{ + TIMESTAMP + { + @Override + public int compare(LootTrackerRecord o1, LootTrackerRecord o2) + { + return Math.toIntExact(o1.getTimestamp() - o2.getTimestamp()); + } + }, + TOTAL_VALUE + { + @Override + public int compare(LootTrackerRecord o1, LootTrackerRecord o2) + { + int sum = Arrays.stream(o1.getItems()).flatMapToInt(lootTrackerItem -> + IntStream.of((int) lootTrackerItem.getPrice() * lootTrackerItem.getQuantity())).sum(); + return sum - Arrays.stream(o2.getItems()).flatMapToInt(lootTrackerItem -> + IntStream.of((int) lootTrackerItem.getPrice() * lootTrackerItem.getQuantity())).sum(); + } + }, + ITEM_COUNT + { + @Override + public int compare(LootTrackerRecord o1, LootTrackerRecord o2) + { + return o1.getItems().length - o2.getItems().length; + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerBox.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerBox.java index 2022e5f72c..a05890f57a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerBox.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerBox.java @@ -32,6 +32,7 @@ import java.awt.GridLayout; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.function.BiConsumer; import javax.annotation.Nullable; From 7b2e0ded2b5d234eaf875223b34bf11114b9d473 Mon Sep 17 00:00:00 2001 From: PKLite Date: Sun, 9 Jun 2019 01:48:56 -0400 Subject: [PATCH 6/8] implement record sorting Signed-off-by: PKLite --- .../loottracker/LootRecordSortType.java | 2 +- .../plugins/loottracker/LootTrackerBox.java | 4 ++-- .../loottracker/LootTrackerConfig.java | 9 ++++++++ .../plugins/loottracker/LootTrackerPanel.java | 6 +++++ .../loottracker/LootTrackerPlugin.java | 23 +++++++++++++------ 5 files changed, 34 insertions(+), 10 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootRecordSortType.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootRecordSortType.java index 6efd941100..88696b94bd 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootRecordSortType.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootRecordSortType.java @@ -14,7 +14,7 @@ public enum LootRecordSortType implements Comparator @Override public int compare(LootTrackerRecord o1, LootTrackerRecord o2) { - return Math.toIntExact(o1.getTimestamp() - o2.getTimestamp()); + return Long.compare(o1.getTimestamp(), o2.getTimestamp()); } }, TOTAL_VALUE diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerBox.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerBox.java index a05890f57a..b111fde570 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerBox.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerBox.java @@ -32,7 +32,6 @@ import java.awt.GridLayout; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.function.BiConsumer; import javax.annotation.Nullable; @@ -121,7 +120,8 @@ class LootTrackerBox extends JPanel private long getTotalKills() { return hideIgnoredItems - ? records.stream().filter(r -> !Arrays.stream(r.getItems()).allMatch(LootTrackerItem::isIgnored)).count() + ? records.stream().filter( + r -> !Arrays.stream(r.getItems()).allMatch(LootTrackerItem::isIgnored)).count() : records.size(); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java index 8410c8a5be..0e800a8094 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java @@ -91,5 +91,14 @@ public interface LootTrackerConfig extends Config { return true; } + @ConfigItem( + keyName = "sortType", + name = "Sorting", + description = "The method for sorting Loot Tracker entries" + ) + default LootRecordSortType sortType() + { + return LootRecordSortType.TIMESTAMP; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPanel.java index f8442137e3..51cfaf3e3c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPanel.java @@ -44,6 +44,8 @@ import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.border.EmptyBorder; +import lombok.Getter; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; import net.runelite.api.GameState; import net.runelite.client.game.ItemManager; @@ -137,6 +139,9 @@ class LootTrackerPanel extends PluginPanel private final JPanel displaySelector; + @Getter @Setter + private LootRecordSortType lootRecordSortType = LootRecordSortType.TIMESTAMP; + LootTrackerPanel(final LootTrackerPlugin plugin, final ItemManager itemManager, final LootTrackerConfig config) { this.itemManager = itemManager; @@ -423,6 +428,7 @@ class LootTrackerPanel extends PluginPanel logsContainer.removeAll(); boxes.clear(); int start = 0; + records.sort(lootRecordSortType); if (!groupLoot && records.size() > MAX_LOOT_BOXES) { start = records.size() - MAX_LOOT_BOXES; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java index b7e11c29c5..b0d1d0c90c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java @@ -256,9 +256,18 @@ public class LootTrackerPlugin extends Plugin { if (event.getGroup().equals("loottracker")) { - ignoredItems = Text.fromCSV(config.getIgnoredItems()); - SwingUtilities.invokeLater(panel::updateIgnoredRecords); + if (event.getKey().equals("ignoredItems")) + { + ignoredItems = Text.fromCSV(config.getIgnoredItems()); + SwingUtilities.invokeLater(panel::updateIgnoredRecords); + } + if (event.getKey().equals("sortType")) + { + panel.setLootRecordSortType(config.sortType()); + SwingUtilities.invokeLater(panel::rebuild); + } } + } @Override @@ -391,7 +400,7 @@ public class LootTrackerPlugin extends Plugin final LootTrackerItem[] entries = buildEntries(stack(items)); String localUsername = client.getLocalPlayer().getName(); SwingUtilities.invokeLater(() -> panel.add(name, localUsername, combat, entries)); - LootRecord lootRecord = new LootRecord(localUsername, name, LootRecordType.PLAYER, + LootRecord lootRecord = new LootRecord( name, localUsername, LootRecordType.PLAYER, toGameItems(items), Instant.now()); if (lootTrackerClient != null && config.saveLoot()) { @@ -481,11 +490,11 @@ public class LootTrackerPlugin extends Plugin } final LootTrackerItem[] entries = buildEntries(stack(items)); - SwingUtilities.invokeLater(() -> panel.add(client.getLocalPlayer().getName(), eventType, -1, entries)); + SwingUtilities.invokeLater(() -> panel.add(eventType, client.getLocalPlayer().getName(), -1, entries)); if (lootTrackerClient != null && config.saveLoot()) { - LootRecord lootRecord = new LootRecord(client.getLocalPlayer().getName(), eventType, LootRecordType.EVENT, + LootRecord lootRecord = new LootRecord(eventType, client.getLocalPlayer().getName(), LootRecordType.EVENT, toGameItems(items), Instant.now()); lootTrackerClient.submit(lootRecord); } @@ -692,11 +701,11 @@ public class LootTrackerPlugin extends Plugin .collect(Collectors.toList()); final LootTrackerItem[] entries = buildEntries(stack(items)); - SwingUtilities.invokeLater(() -> panel.add(client.getLocalPlayer().getName(), chestType, -1, entries)); + SwingUtilities.invokeLater(() -> panel.add(chestType, client.getLocalPlayer().getName(), -1, entries)); if (lootTrackerClient != null && config.saveLoot()) { - LootRecord lootRecord = new LootRecord(client.getLocalPlayer().getName(), chestType, + LootRecord lootRecord = new LootRecord(chestType, client.getLocalPlayer().getName(), LootRecordType.EVENT, toGameItems(items), Instant.now()); lootTrackerClient.submit(lootRecord); } From 7ece7ab7965b1816e0789505737495a84eecfec4 Mon Sep 17 00:00:00 2001 From: PKLite Date: Sun, 9 Jun 2019 07:51:34 -0400 Subject: [PATCH 7/8] sorting is kinda bugged. need to wait until ground item glitch gets fixed for easier testing Signed-off-by: PKLite --- .../loottracker/LootRecordSortType.java | 21 +++++++++++++++++-- .../plugins/loottracker/LootTrackerPanel.java | 12 +++++++++++ .../loottracker/LootTrackerPlugin.java | 7 +++++-- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootRecordSortType.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootRecordSortType.java index 88696b94bd..61050d2552 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootRecordSortType.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootRecordSortType.java @@ -3,10 +3,13 @@ package net.runelite.client.plugins.loottracker; import java.util.Arrays; import java.util.Comparator; import java.util.stream.IntStream; +import lombok.extern.slf4j.Slf4j; +import net.runelite.http.api.loottracker.LootRecordType; /** * */ +@Slf4j public enum LootRecordSortType implements Comparator { TIMESTAMP @@ -22,9 +25,23 @@ public enum LootRecordSortType implements Comparator @Override public int compare(LootTrackerRecord o1, LootTrackerRecord o2) { + + // We want deaths at the bottom of the list + if (o1.getSubTitle().equals(LootRecordType.DEATH.name())) + { + return Arrays.stream(o1.getItems()).flatMapToInt(lootTrackerItem -> + IntStream.of((int) lootTrackerItem.getPrice() * lootTrackerItem.getQuantity())).sum(); + } + if (o2.getSubTitle().equals(LootRecordType.DEATH.name())) + { + return Arrays.stream(o1.getItems()).flatMapToInt(lootTrackerItem -> + IntStream.of((int) lootTrackerItem.getPrice() * lootTrackerItem.getQuantity())).sum(); + } int sum = Arrays.stream(o1.getItems()).flatMapToInt(lootTrackerItem -> IntStream.of((int) lootTrackerItem.getPrice() * lootTrackerItem.getQuantity())).sum(); - return sum - Arrays.stream(o2.getItems()).flatMapToInt(lootTrackerItem -> + log.info(String.valueOf(sum + Arrays.stream(o2.getItems()).flatMapToInt(lootTrackerItem -> + IntStream.of((int) lootTrackerItem.getPrice() * lootTrackerItem.getQuantity())).sum())); + return sum + Arrays.stream(o2.getItems()).flatMapToInt(lootTrackerItem -> IntStream.of((int) lootTrackerItem.getPrice() * lootTrackerItem.getQuantity())).sum(); } }, @@ -33,7 +50,7 @@ public enum LootRecordSortType implements Comparator @Override public int compare(LootTrackerRecord o1, LootTrackerRecord o2) { - return o1.getItems().length - o2.getItems().length; + return Integer.compare(o1.getItems().length, o2.getItems().length); } } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPanel.java index 51cfaf3e3c..b26f83f0ff 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPanel.java @@ -33,9 +33,11 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Objects; +import java.util.stream.IntStream; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.ImageIcon; @@ -435,7 +437,17 @@ class LootTrackerPanel extends PluginPanel } for (int i = start; i < records.size(); i++) { + + if (this.plugin.client.getGameState().equals(GameState.LOGGED_IN)) + { + if (!(this.plugin.client.getLocalPlayer().getName().equals(records.get(i).getLocalUsername()))) + { + continue; + } + } buildBox(records.get(i)); + log.info(String.valueOf(Arrays.stream(records.get(i).getItems()).flatMapToInt(a -> IntStream.of(a.getQuantity() * (int) a.getPrice())).sum())); + } boxes.forEach(LootTrackerBox::rebuild); updateOverall(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java index b0d1d0c90c..2f572275eb 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java @@ -25,6 +25,7 @@ */ package net.runelite.client.plugins.loottracker; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -184,7 +185,8 @@ public class LootTrackerPlugin extends Plugin private LootTrackerClient lootTrackerClient; private BufferedReader bufferedReader; private JsonStreamParser jsonStreamParser; - private Collection lootRecords = new ArrayList<>(); + @VisibleForTesting + public Collection lootRecords = new ArrayList<>(); private static Collection stack(Collection items) { @@ -736,6 +738,7 @@ public class LootTrackerPlugin extends Plugin return ignoredItems.contains(name); } + @VisibleForTesting private LootTrackerItem buildLootTrackerItem(int itemId, int quantity) { final ItemDefinition itemComposition = itemManager.getItemDefinition(itemId); @@ -765,7 +768,7 @@ public class LootTrackerPlugin extends Plugin .collect(Collectors.toList()); } - private Collection convertToLootTrackerRecord(final Collection records) + public Collection convertToLootTrackerRecord(final Collection records) { Collection trackerRecords = new ArrayList<>(); for (LootRecord record : records) From 70f6d207acad0dbe6b6e8d491bdd9989d0b5e15b Mon Sep 17 00:00:00 2001 From: PKLite Date: Tue, 11 Jun 2019 21:02:37 -0400 Subject: [PATCH 8/8] Adds constructor for data retrieved from http api (just uses a blank username for now) Signed-off-by: PKLite --- .../http/api/loottracker/LootRecord.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecord.java b/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecord.java index 4a802a12fb..993959ee88 100644 --- a/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecord.java +++ b/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecord.java @@ -26,6 +26,7 @@ package net.runelite.http.api.loottracker; import java.time.Instant; import java.util.Collection; +import java.util.List; import lombok.AllArgsConstructor; import lombok.Data; import lombok.Getter; @@ -42,4 +43,21 @@ public class LootRecord private LootRecordType type; private Collection drops; private Instant time; + + /** + * constructor for lootRecords retrieved by http api (doesn't store/retrieve username) + * @param eventId - the eventID or the name/title of the LootRecord + * @param type - The LootRecordType + * @param gameItems - the list of items/quantities + * @param time - the Instant that the Loot Record was received + */ + public LootRecord(String eventId, LootRecordType type, List gameItems, Instant time) + { + // Insert blank username + this.username = ""; + this.eventId = eventId; + this.type = type; + this.drops = gameItems; + this.time = time; + } }