diff --git a/runelite-client/src/main/java/net/runelite/client/game/ItemManager.java b/runelite-client/src/main/java/net/runelite/client/game/ItemManager.java index 199e73f473..edffbf23b2 100644 --- a/runelite-client/src/main/java/net/runelite/client/game/ItemManager.java +++ b/runelite-client/src/main/java/net/runelite/client/game/ItemManager.java @@ -29,6 +29,10 @@ import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import java.awt.image.BufferedImage; import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -36,6 +40,7 @@ import javax.annotation.Nullable; import javax.inject.Inject; import javax.inject.Singleton; import lombok.Value; +import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; import static net.runelite.api.Constants.CLIENT_DEFAULT_ZOOM; import net.runelite.api.ItemComposition; @@ -45,6 +50,7 @@ import net.runelite.http.api.item.ItemPrice; import net.runelite.http.api.item.SearchResult; @Singleton +@Slf4j public class ItemManager { @Value @@ -58,17 +64,19 @@ public class ItemManager /** * not yet looked up */ - static final ItemPrice EMPTY = new ItemPrice(); + /** * has no price */ static final ItemPrice NONE = new ItemPrice(); private final Client client; + private final ScheduledExecutorService scheduledExecutorService; + private final ItemClient itemClient = new ItemClient(); private final LoadingCache itemSearches; - private final LoadingCache itemPrices; + private final LoadingCache itemPriceCache; private final LoadingCache itemImages; private final LoadingCache itemCompositions; @@ -76,8 +84,10 @@ public class ItemManager public ItemManager(@Nullable Client client, ScheduledExecutorService executor) { this.client = client; - itemPrices = CacheBuilder.newBuilder() - .maximumSize(512L) + this.scheduledExecutorService = executor; + + itemPriceCache = CacheBuilder.newBuilder() + .maximumSize(1024L) .expireAfterAccess(1, TimeUnit.HOURS) .build(new ItemPriceLoader(executor, itemClient)); @@ -126,16 +136,74 @@ public class ItemManager */ public ItemPrice getItemPriceAsync(int itemId) { - ItemPrice itemPrice = itemPrices.getIfPresent(itemId); + ItemPrice itemPrice = itemPriceCache.getIfPresent(itemId); if (itemPrice != null && itemPrice != EMPTY) { return itemPrice == NONE ? null : itemPrice; } - itemPrices.refresh(itemId); + itemPriceCache.refresh(itemId); return null; } + /** + * Look up bulk item prices asynchronously + * + * @param itemIds array of item Ids + * @return a future called with the looked up prices + */ + public CompletableFuture getItemPriceBatch(List itemIds) + { + final List lookup = new ArrayList<>(); + final List existing = new ArrayList<>(); + for (int itemId : itemIds) + { + ItemPrice itemPrice = itemPriceCache.getIfPresent(itemId); + if (itemPrice != null) + { + existing.add(itemPrice); + } + else + { + lookup.add(itemId); + } + } + // All cached? + if (lookup.isEmpty()) + { + return CompletableFuture.completedFuture(existing.toArray(new ItemPrice[existing.size()])); + } + + final CompletableFuture future = new CompletableFuture<>(); + scheduledExecutorService.execute(() -> + { + try + { + // Do a query for the items not in the cache + ItemPrice[] itemPrices = itemClient.lookupItemPrice(lookup.toArray(new Integer[lookup.size()])); + if (itemPrices != null) + { + for (int itemId : lookup) + { + itemPriceCache.put(itemId, NONE); + } + for (ItemPrice itemPrice : itemPrices) + { + itemPriceCache.put(itemPrice.getItem().getId(), itemPrice); + } + // Append these to the already cached items + Arrays.stream(itemPrices).forEach(existing::add); + } + future.complete(existing.toArray(new ItemPrice[existing.size()])); + } + catch (Exception ex) + { + future.completeExceptionally(ex); + } + }); + return future; + } + /** * Look up an item's price synchronously * @@ -145,7 +213,7 @@ public class ItemManager */ public ItemPrice getItemPrice(int itemId) throws IOException { - ItemPrice itemPrice = itemPrices.getIfPresent(itemId); + ItemPrice itemPrice = itemPriceCache.getIfPresent(itemId); if (itemPrice != null && itemPrice != EMPTY) { return itemPrice == NONE ? null : itemPrice; @@ -154,11 +222,11 @@ public class ItemManager itemPrice = itemClient.lookupItemPrice(itemId); if (itemPrice == null) { - itemPrices.put(itemId, NONE); + itemPriceCache.put(itemId, NONE); return null; } - itemPrices.put(itemId, itemPrice); + itemPriceCache.put(itemId, itemPrice); return itemPrice; }