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. */