diff --git a/http-api/src/main/java/net/runelite/http/api/loottracker/LootTrackerClient.java b/http-api/src/main/java/net/runelite/http/api/loottracker/LootTrackerClient.java index ab7307b186..c6a52ea419 100644 --- a/http-api/src/main/java/net/runelite/http/api/loottracker/LootTrackerClient.java +++ b/http-api/src/main/java/net/runelite/http/api/loottracker/LootTrackerClient.java @@ -53,13 +53,13 @@ public class LootTrackerClient private final UUID uuid; - public void submit(LootRecord lootRecord) + public void submit(Collection lootRecords) { HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() .addPathSegment("loottracker") .build(); - RequestBody body = RequestBody.Companion.create(GSON.toJson(lootRecord), JSON); + RequestBody body = RequestBody.Companion.create(GSON.toJson(lootRecords), JSON); Request request = new Request.Builder() .header(RuneLiteAPI.RUNELITE_AUTH, uuid.toString()) .post(body) diff --git a/http-service/src/main/java/net/runelite/http/service/account/AccountService.java b/http-service/src/main/java/net/runelite/http/service/account/AccountService.java index aa11c0e63e..19add15121 100644 --- a/http-service/src/main/java/net/runelite/http/service/account/AccountService.java +++ b/http-service/src/main/java/net/runelite/http/service/account/AccountService.java @@ -262,6 +262,8 @@ public class AccountService return; } + auth.invalidate(session.getUuid()); + try (Connection con = sql2o.open()) { con.createQuery("delete from sessions where uuid = :uuid") diff --git a/http-service/src/main/java/net/runelite/http/service/account/AuthFilter.java b/http-service/src/main/java/net/runelite/http/service/account/AuthFilter.java index 1f57127bf5..d283e71c5c 100644 --- a/http-service/src/main/java/net/runelite/http/service/account/AuthFilter.java +++ b/http-service/src/main/java/net/runelite/http/service/account/AuthFilter.java @@ -24,14 +24,18 @@ */ package net.runelite.http.service.account; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.RemovalNotification; import java.io.IOException; -import net.runelite.http.service.account.beans.SessionEntry; import java.sql.Timestamp; import java.time.Instant; import java.util.UUID; +import java.util.concurrent.TimeUnit; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import net.runelite.http.api.RuneLiteAPI; +import net.runelite.http.service.account.beans.SessionEntry; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; @@ -43,6 +47,12 @@ public class AuthFilter { private final Sql2o sql2o; + private final Cache sessionCache = CacheBuilder.newBuilder() + .maximumSize(10000L) + .expireAfterAccess(30, TimeUnit.MINUTES) + .removalListener(this::removalListener) + .build(); + @Autowired public AuthFilter(@Qualifier("Runelite SQL2O") Sql2o sql2o) { @@ -59,30 +69,48 @@ public class AuthFilter } UUID uuid = UUID.fromString(runeliteAuth); + SessionEntry sessionEntry = sessionCache.getIfPresent(uuid); + if (sessionEntry != null) + { + return sessionEntry; + } try (Connection con = sql2o.open()) { - SessionEntry sessionEntry = con.createQuery("select user, uuid, created from sessions where uuid = :uuid") + sessionEntry = con.createQuery("select user, uuid, created, last_used as lastUsed from sessions where uuid = :uuid") .addParameter("uuid", uuid.toString()) .executeAndFetchFirst(SessionEntry.class); + } - if (sessionEntry == null) - { - response.sendError(401, "Access denied"); - return null; - } + if (sessionEntry == null) + { + response.sendError(401, "Access denied"); + return null; + } - Instant now = Instant.now(); + sessionCache.put(uuid, sessionEntry); + return sessionEntry; + } + + private void removalListener(RemovalNotification notification) + { + UUID uuid = notification.getKey(); + Instant now = Instant.now(); + + try (Connection con = sql2o.open()) + { con.createQuery("update sessions set last_used = :last_used where uuid = :uuid") .addParameter("last_used", Timestamp.from(now)) .addParameter("uuid", uuid.toString()) .executeUpdate(); - - sessionEntry.setLastUsed(now); - - return sessionEntry; } } + public void invalidate(UUID uuid) + { + // If we ever run multiple services, may need to publish something here to invalidate... + sessionCache.invalidate(uuid); + } + } diff --git a/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerController.java b/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerController.java index 2c1bd77140..1033d62187 100644 --- a/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerController.java +++ b/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerController.java @@ -53,7 +53,7 @@ public class LootTrackerController private AuthFilter auth; @RequestMapping(method = RequestMethod.POST) - public void storeLootRecord(HttpServletRequest request, HttpServletResponse response, @RequestBody LootRecord record) throws IOException + public void storeLootRecord(HttpServletRequest request, HttpServletResponse response, @RequestBody Collection records) throws IOException { SessionEntry e = auth.handle(request, response); if (e == null) @@ -62,7 +62,7 @@ public class LootTrackerController return; } - service.store(record, e.getUser()); + service.store(records, e.getUser()); response.setStatus(HttpStatusCodes.STATUS_CODE_OK); } diff --git a/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerService.java b/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerService.java index b999f4eabb..8f97ce144d 100644 --- a/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerService.java +++ b/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerService.java @@ -64,7 +64,7 @@ public class LootTrackerService // Queries for inserting kills private static final String INSERT_KILL_QUERY = "INSERT INTO kills (accountId, type, eventId) VALUES (:accountId, :type, :eventId)"; - private static final String INSERT_DROP_QUERY = "INSERT INTO drops (killId, itemId, itemQuantity) VALUES (LAST_INSERT_ID(), :itemId, :itemQuantity)"; + private static final String INSERT_DROP_QUERY = "INSERT INTO drops (killId, itemId, itemQuantity) VALUES (:killId, :itemId, :itemQuantity)"; private static final String SELECT_LOOT_QUERY = "SELECT killId,time,type,eventId,itemId,itemQuantity FROM kills JOIN drops ON drops.killId = kills.id WHERE accountId = :accountId ORDER BY TIME DESC LIMIT :limit OFFSET :offset"; @@ -89,29 +89,49 @@ public class LootTrackerService /** * Store LootRecord * - * @param record LootRecord to store + * @param records LootRecords to store * @param accountId runelite account id to tie data too */ - public void store(LootRecord record, int accountId) + public void store(Collection records, int accountId) { try (Connection con = sql2o.beginTransaction()) { // Kill Entry Query - con.createQuery(INSERT_KILL_QUERY, true) - .addParameter("accountId", accountId) - .addParameter("type", record.getType()) - .addParameter("eventId", record.getEventId()) - .executeUpdate(); + Query killQuery = con.createQuery(INSERT_KILL_QUERY, true); + + for (LootRecord record : records) + { + killQuery + .addParameter("accountId", accountId) + .addParameter("type", record.getType()) + .addParameter("eventId", record.getEventId()) + .addToBatch(); + } + + killQuery.executeBatch(); + Object[] keys = con.getKeys(); + + if (keys.length != records.size()) + { + throw new RuntimeException("Mismatch in keys vs records size"); + } Query insertDrop = con.createQuery(INSERT_DROP_QUERY); // Append all queries for inserting drops - for (GameItem drop : record.getDrops()) + int idx = 0; + for (LootRecord record : records) { - insertDrop - .addParameter("itemId", drop.getId()) - .addParameter("itemQuantity", drop.getQty()) - .addToBatch(); + for (GameItem drop : record.getDrops()) + { + insertDrop + .addParameter("killId", keys[idx]) + .addParameter("itemId", drop.getId()) + .addParameter("itemQuantity", drop.getQty()) + .addToBatch(); + } + + ++idx; } insertDrop.executeBatch(); diff --git a/http-service/src/test/java/net/runelite/http/service/loottracker/LootTrackerControllerTest.java b/http-service/src/test/java/net/runelite/http/service/loottracker/LootTrackerControllerTest.java index 3c80dd72d4..ccf7ab7603 100644 --- a/http-service/src/test/java/net/runelite/http/service/loottracker/LootTrackerControllerTest.java +++ b/http-service/src/test/java/net/runelite/http/service/loottracker/LootTrackerControllerTest.java @@ -83,10 +83,10 @@ public class LootTrackerControllerTest lootRecord.setTime(Instant.now()); lootRecord.setDrops(Collections.singletonList(new GameItem(4151, 1))); - String data = RuneLiteAPI.GSON.toJson(lootRecord); + String data = RuneLiteAPI.GSON.toJson(Collections.singletonList(lootRecord)); mockMvc.perform(post("/loottracker").content(data).contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()); - verify(lootTrackerService).store(eq(lootRecord), anyInt()); + verify(lootTrackerService).store(eq(Collections.singletonList(lootRecord)), anyInt()); } } \ No newline at end of file diff --git a/runelite-api/src/main/java/net/runelite/api/Actor.java b/runelite-api/src/main/java/net/runelite/api/Actor.java index a05dc73de0..35178fa654 100644 --- a/runelite-api/src/main/java/net/runelite/api/Actor.java +++ b/runelite-api/src/main/java/net/runelite/api/Actor.java @@ -49,6 +49,7 @@ public interface Actor extends Entity * * @return the name */ + @Nullable String getName(); /** diff --git a/runelite-api/src/main/java/net/runelite/api/Client.java b/runelite-api/src/main/java/net/runelite/api/Client.java index 4e50b7e87b..527d058853 100644 --- a/runelite-api/src/main/java/net/runelite/api/Client.java +++ b/runelite-api/src/main/java/net/runelite/api/Client.java @@ -342,6 +342,7 @@ public interface Client extends GameShell * * @return the logged in player */ + @Nullable Player getLocalPlayer(); /** @@ -422,6 +423,7 @@ public interface Client extends GameShell * * @return the selected tile */ + @Nullable Tile getSelectedSceneTile(); /** @@ -436,6 +438,7 @@ public interface Client extends GameShell * * @return the dragged widget, null if not dragging any widget */ + @Nullable Widget getDraggedWidget(); /** @@ -446,6 +449,7 @@ public interface Client extends GameShell * * @return the dragged on widget, null if not dragging any widget */ + @Nullable Widget getDraggedOnWidget(); /** diff --git a/runelite-client/src/main/java/net/runelite/client/game/chatbox/ChatboxItemSearch.java b/runelite-client/src/main/java/net/runelite/client/game/chatbox/ChatboxItemSearch.java index fb60881e5a..8a4d885fb8 100644 --- a/runelite-client/src/main/java/net/runelite/client/game/chatbox/ChatboxItemSearch.java +++ b/runelite-client/src/main/java/net/runelite/client/game/chatbox/ChatboxItemSearch.java @@ -290,9 +290,9 @@ public class ChatboxItemSearch extends ChatboxTextInput for (int i = 0; i < client.getItemCount() && results.size() < MAX_RESULTS; i++) { ItemDefinition itemComposition = itemManager.getItemDefinition(itemManager.canonicalize(i)); - String name = itemComposition.getName(); + String name = itemComposition.getName().toLowerCase(); // The client assigns "null" to item names of items it doesn't know about - if (!name.equals("null") && name.toLowerCase().contains(search)) + if (!name.equals("null") && name.contains(search)) { // This may already be in the map due to canonicalize mapping the item to something we've already seen results.putIfAbsent(itemComposition.getId(), itemComposition); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java index e487707c13..54f843270c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java @@ -322,7 +322,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc new CrypticClue("More resources than I can handle, but in a very dangerous area. Can't wait to strike gold!", new WorldPoint(3183, 3941, 0), "Dig between the three gold ores in the Wilderness Resource Area."), new CrypticClue("Observing someone in a swamp, under the telescope lies treasure.", new WorldPoint(2221, 3091, 0), "Dig next to the telescope on Broken Handz's island in the poison wastes. (Accessible only through fairy ring DLR)"), new CrypticClue("A general who sets a 'shining' example.", "General Hining", new WorldPoint(2186, 3148, 0), "Talk to General Hining in Tyras Camp."), - new CrypticClue("Has no one told you it is rude to ask a lady her age?", "Lady Tangwen Trahaearn", new WorldPoint(3280, 6042, 0), "Talk to Lady Tangwen Trahaearn, SSE Prifddinas by the teleporter."), + new CrypticClue("Has no one told you it is rude to ask a lady her age?", "Mawrth", new WorldPoint(2333, 3165, 0), "Talk to Mawrth in Lletya."), new CrypticClue("Elvish onions.", new WorldPoint(3303, 6092, 0), "Dig in the onion patch east of the Prifddinas allotments.") ); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java index 123d73ef44..ce7b5119e1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java @@ -158,13 +158,13 @@ public class SkillChallengeClue extends ClueScroll implements NpcClueScroll new SkillChallengeClue("Complete a lap of Rellekka's Rooftop Agility Course", "complete a lap of the rellekka rooftop agility course whilst sporting the finest amount of grace.", true, all("A full Graceful set", any("", item(ItemID.GRACEFUL_HOOD), item(ItemID.GRACEFUL_HOOD_11851), item(ItemID.GRACEFUL_HOOD_13579), item(ItemID.GRACEFUL_HOOD_13580), item(ItemID.GRACEFUL_HOOD_13591), item(ItemID.GRACEFUL_HOOD_13592), item(ItemID.GRACEFUL_HOOD_13603), item(ItemID.GRACEFUL_HOOD_13604), item(ItemID.GRACEFUL_HOOD_13615), item(ItemID.GRACEFUL_HOOD_13616), item(ItemID.GRACEFUL_HOOD_13627), item(ItemID.GRACEFUL_HOOD_13628), item(ItemID.GRACEFUL_HOOD_13667), item(ItemID.GRACEFUL_HOOD_13668), item(ItemID.GRACEFUL_HOOD_21061), item(ItemID.GRACEFUL_HOOD_21063)), - any("", item(ItemID.GRACEFUL_CAPE), item(ItemID.GRACEFUL_CAPE_11853), item(ItemID.GRACEFUL_CAPE_13581), item(ItemID.GRACEFUL_CAPE_13582), item(ItemID.GRACEFUL_CAPE_13593), item(ItemID.GRACEFUL_CAPE_13594), item(ItemID.GRACEFUL_CAPE_13605), item(ItemID.GRACEFUL_CAPE_13606), item(ItemID.GRACEFUL_CAPE_13617), item(ItemID.GRACEFUL_CAPE_13618), item(ItemID.GRACEFUL_CAPE_13629), item(ItemID.GRACEFUL_CAPE_13630), item(ItemID.GRACEFUL_CAPE_13669), item(ItemID.GRACEFUL_CAPE_13670), item(ItemID.GRACEFUL_CAPE_21064), item(ItemID.GRACEFUL_CAPE_21066)), + any("", item(ItemID.GRACEFUL_CAPE), item(ItemID.GRACEFUL_CAPE_11853), item(ItemID.GRACEFUL_CAPE_13581), item(ItemID.GRACEFUL_CAPE_13582), item(ItemID.GRACEFUL_CAPE_13593), item(ItemID.GRACEFUL_CAPE_13594), item(ItemID.GRACEFUL_CAPE_13605), item(ItemID.GRACEFUL_CAPE_13606), item(ItemID.GRACEFUL_CAPE_13617), item(ItemID.GRACEFUL_CAPE_13618), item(ItemID.GRACEFUL_CAPE_13629), item(ItemID.GRACEFUL_CAPE_13630), item(ItemID.GRACEFUL_CAPE_13669), item(ItemID.GRACEFUL_CAPE_13670), item(ItemID.GRACEFUL_CAPE_21064), item(ItemID.GRACEFUL_CAPE_21066), item(ItemID.AGILITY_CAPE), item(ItemID.AGILITY_CAPET), item(ItemID.MAX_CAPE)), any("", item(ItemID.GRACEFUL_TOP), item(ItemID.GRACEFUL_TOP_11855), item(ItemID.GRACEFUL_TOP_13583), item(ItemID.GRACEFUL_TOP_13584), item(ItemID.GRACEFUL_TOP_13595), item(ItemID.GRACEFUL_TOP_13596), item(ItemID.GRACEFUL_TOP_13607), item(ItemID.GRACEFUL_TOP_13608), item(ItemID.GRACEFUL_TOP_13619), item(ItemID.GRACEFUL_TOP_13620), item(ItemID.GRACEFUL_TOP_13631), item(ItemID.GRACEFUL_TOP_13632), item(ItemID.GRACEFUL_TOP_13671), item(ItemID.GRACEFUL_TOP_13672), item(ItemID.GRACEFUL_TOP_21067), item(ItemID.GRACEFUL_TOP_21069)), any("", item(ItemID.GRACEFUL_LEGS), item(ItemID.GRACEFUL_LEGS_11857), item(ItemID.GRACEFUL_LEGS_13585), item(ItemID.GRACEFUL_LEGS_13586), item(ItemID.GRACEFUL_LEGS_13597), item(ItemID.GRACEFUL_LEGS_13598), item(ItemID.GRACEFUL_LEGS_13609), item(ItemID.GRACEFUL_LEGS_13610), item(ItemID.GRACEFUL_LEGS_13621), item(ItemID.GRACEFUL_LEGS_13622), item(ItemID.GRACEFUL_LEGS_13633), item(ItemID.GRACEFUL_LEGS_13634), item(ItemID.GRACEFUL_LEGS_13673), item(ItemID.GRACEFUL_LEGS_13674), item(ItemID.GRACEFUL_LEGS_21070), item(ItemID.GRACEFUL_LEGS_21072)), any("", item(ItemID.GRACEFUL_GLOVES), item(ItemID.GRACEFUL_GLOVES_11859), item(ItemID.GRACEFUL_GLOVES_13587), item(ItemID.GRACEFUL_GLOVES_13588), item(ItemID.GRACEFUL_GLOVES_13599), item(ItemID.GRACEFUL_GLOVES_13600), item(ItemID.GRACEFUL_GLOVES_13611), item(ItemID.GRACEFUL_GLOVES_13612), item(ItemID.GRACEFUL_GLOVES_13623), item(ItemID.GRACEFUL_GLOVES_13624), item(ItemID.GRACEFUL_GLOVES_13635), item(ItemID.GRACEFUL_GLOVES_13636), item(ItemID.GRACEFUL_GLOVES_13675), item(ItemID.GRACEFUL_GLOVES_13676), item(ItemID.GRACEFUL_GLOVES_21073), item(ItemID.GRACEFUL_GLOVES_21075)), any("", item(ItemID.GRACEFUL_BOOTS), item(ItemID.GRACEFUL_BOOTS_11861), item(ItemID.GRACEFUL_BOOTS_13589), item(ItemID.GRACEFUL_BOOTS_13590), item(ItemID.GRACEFUL_BOOTS_13601), item(ItemID.GRACEFUL_BOOTS_13602), item(ItemID.GRACEFUL_BOOTS_13613), item(ItemID.GRACEFUL_BOOTS_13614), item(ItemID.GRACEFUL_BOOTS_13625), item(ItemID.GRACEFUL_BOOTS_13626), item(ItemID.GRACEFUL_BOOTS_13637), item(ItemID.GRACEFUL_BOOTS_13638), item(ItemID.GRACEFUL_BOOTS_13677), item(ItemID.GRACEFUL_BOOTS_13678), item(ItemID.GRACEFUL_BOOTS_21076), item(ItemID.GRACEFUL_BOOTS_21078)))), new SkillChallengeClue("Mix an anti-venom potion.", item(ItemID.ANTIDOTE4_5952), xOfItem(ItemID.ZULRAHS_SCALES, 20)), - new SkillChallengeClue("Mine a piece of Runite ore", "mine a piece of runite ore whilst sporting the finest mining gear.", true, ANY_PICKAXE, all(item(ItemID.PROSPECTOR_HELMET), item(ItemID.PROSPECTOR_JACKET), item(ItemID.PROSPECTOR_LEGS), item(ItemID.PROSPECTOR_BOOTS))), + new SkillChallengeClue("Mine a piece of Runite ore", "mine a piece of runite ore whilst sporting the finest mining gear.", true, ANY_PICKAXE, all("Prospector kit", item(ItemID.PROSPECTOR_HELMET), item(ItemID.PROSPECTOR_JACKET), item(ItemID.PROSPECTOR_LEGS), item(ItemID.PROSPECTOR_BOOTS))), new SkillChallengeClue("Steal a gem from the Ardougne market."), new SkillChallengeClue("Pickpocket an elf."), new SkillChallengeClue("Bind a blood rune at the blood altar.", item(ItemID.DARK_ESSENCE_FRAGMENTS)), @@ -173,8 +173,8 @@ public class SkillChallengeClue extends ClueScroll implements NpcClueScroll new SkillChallengeClue("Cremate a set of fiyr remains.", any("Magic or Redwood Pyre Logs", item(ItemID.MAGIC_PYRE_LOGS), item(ItemID.REDWOOD_PYRE_LOGS)), item(ItemID.TINDERBOX), item(ItemID.FIYR_REMAINS)), new SkillChallengeClue("Dissect a sacred eel.", item(ItemID.KNIFE), any("Fishing rod", item(ItemID.FISHING_ROD), item(ItemID.PEARL_FISHING_ROD)), item(ItemID.FISHING_BAIT)), new SkillChallengeClue("Kill a lizardman shaman."), - new SkillChallengeClue("Catch an Anglerfish.", "angle for an anglerfish in your finest fishing gear.", true, any("Fishing rod", item(ItemID.FISHING_ROD), item(ItemID.PEARL_FISHING_ROD)), item(ItemID.SANDWORMS), all(item(ItemID.ANGLER_HAT), item(ItemID.ANGLER_TOP), item(ItemID.ANGLER_WADERS), item(ItemID.ANGLER_BOOTS))), - new SkillChallengeClue("Chop a redwood log.", "chop a redwood log whilst sporting the finest lumberjack gear.", true, ANY_AXE, all(item(ItemID.LUMBERJACK_HAT), item(ItemID.LUMBERJACK_TOP), item(ItemID.LUMBERJACK_LEGS), item(ItemID.LUMBERJACK_BOOTS))), + new SkillChallengeClue("Catch an Anglerfish.", "angle for an anglerfish in your finest fishing gear.", true, any("Fishing rod", item(ItemID.FISHING_ROD), item(ItemID.PEARL_FISHING_ROD)), item(ItemID.SANDWORMS), all("Angler's outfit", item(ItemID.ANGLER_HAT), item(ItemID.ANGLER_TOP), item(ItemID.ANGLER_WADERS), item(ItemID.ANGLER_BOOTS))), + new SkillChallengeClue("Chop a redwood log.", "chop a redwood log whilst sporting the finest lumberjack gear.", true, ANY_AXE, all("Lumberjack outfit", item(ItemID.LUMBERJACK_HAT), item(ItemID.LUMBERJACK_TOP), item(ItemID.LUMBERJACK_LEGS), item(ItemID.LUMBERJACK_BOOTS))), new SkillChallengeClue("Craft a light orb in the Dorgesh-Kaan bank.", item(ItemID.CAVE_GOBLIN_WIRE), item(ItemID.EMPTY_LIGHT_ORB)), new SkillChallengeClue("Kill a reanimated Abyssal Demon.", "kill a reanimated abyssal.", xOfItem(ItemID.SOUL_RUNE, 4), xOfItem(ItemID.BLOOD_RUNE, 1), any("Nature Rune x4", xOfItem(ItemID.NATURE_RUNE, 4), item(ItemID.BRYOPHYTAS_STAFF)), item(ItemID.ENSOULED_ABYSSAL_HEAD)), new SkillChallengeClue("Kill a Fiyr shade inside Mort'tons shade catacombs.", any("Any Silver Shade Key", item(ItemID.SILVER_KEY_RED), item(ItemID.SILVER_KEY_BROWN), item(ItemID.SILVER_KEY_CRIMSON), item(ItemID.SILVER_KEY_BLACK), item(ItemID.SILVER_KEY_PURPLE))) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingPlugin.java index 5539fde29e..d25e5c84aa 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingPlugin.java @@ -272,7 +272,7 @@ public class FishingPlugin extends Plugin } final NPC npc = (NPC) target; - FishingSpot spot = FishingSpot.getSPOTS().get(npc.getId()); + FishingSpot spot = FishingSpot.findSpot(npc.getId()); if (spot == null) { @@ -311,7 +311,7 @@ public class FishingPlugin extends Plugin for (NPC npc : fishingSpots) { - if (FishingSpot.getSPOTS().get(npc.getId()) == FishingSpot.MINNOW && this.showMinnowOverlay) + if (FishingSpot.findSpot(npc.getId()) == FishingSpot.MINNOW && this.showMinnowOverlay) { final int id = npc.getIndex(); final MinnowSpot minnowSpot = minnowSpots.get(id); @@ -336,7 +336,7 @@ public class FishingPlugin extends Plugin { final NPC npc = event.getNpc(); - if (!FishingSpot.getSPOTS().containsKey(npc.getId())) + if (FishingSpot.findSpot(npc.getId()) == null) { return; } @@ -448,8 +448,22 @@ public class FishingPlugin extends Plugin private void inverseSortSpotDistanceFromPlayer() { + if (fishingSpots.isEmpty()) + { + return; + } + final LocalPoint cameraPoint = new LocalPoint(client.getCameraX(), client.getCameraY()); - fishingSpots.sort(Comparator.comparing(npc -> -1 * npc.getLocalLocation().distanceTo(cameraPoint))); + fishingSpots.sort( + Comparator.comparing( + // Negate to have the furthest first + (NPC npc) -> -npc.getLocalLocation().distanceTo(cameraPoint)) + // Order by position + .thenComparing(NPC::getLocalLocation, Comparator.comparing(LocalPoint::getX) + .thenComparing(LocalPoint::getY)) + // And then by id + .thenComparing(NPC::getId) + ); } private void updateConfig() diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpot.java b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpot.java index 7277065380..7d229d27f2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpot.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpot.java @@ -170,7 +170,6 @@ enum FishingSpot COMMON_TENCH("Common tench, Bluegill, Greater siren, Mottled eel", ItemID.COMMON_TENCH, FISHING_SPOT_8523); - @Getter private static final Map SPOTS; private final String name; @@ -198,4 +197,9 @@ enum FishingSpot this.fishSpriteId = fishSpriteId; this.ids = ids; } + + static FishingSpot findSpot(int id) + { + return SPOTS.get(id); + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotMinimapOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotMinimapOverlay.java index c04ae8426b..e7ffedbb02 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotMinimapOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotMinimapOverlay.java @@ -64,7 +64,7 @@ class FishingSpotMinimapOverlay extends Overlay for (NPC npc : plugin.getFishingSpots()) { - FishingSpot spot = FishingSpot.getSPOTS().get(npc.getId()); + FishingSpot spot = FishingSpot.findSpot(npc.getId()); if (spot == null) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotOverlay.java index 7f7f058438..99b669811e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotOverlay.java @@ -41,6 +41,7 @@ import net.runelite.api.NPC; import net.runelite.api.Perspective; import net.runelite.api.Point; import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldPoint; import net.runelite.client.game.ItemManager; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayLayer; @@ -81,9 +82,11 @@ class FishingSpotOverlay extends Overlay return null; } + FishingSpot previousSpot = null; + WorldPoint previousLocation = null; for (NPC npc : plugin.getFishingSpots()) { - FishingSpot spot = FishingSpot.getSPOTS().get(npc.getId()); + FishingSpot spot = FishingSpot.findSpot(npc.getId()); if (spot == null) { @@ -95,7 +98,25 @@ class FishingSpotOverlay extends Overlay continue; } - Color color = npc.getSpotAnimation() == GraphicID.FLYING_FISH ? Color.RED : Color.CYAN; + // This relies on the sort order to keep identical npcs on the same tile adjacent to each other + if (previousSpot == spot && previousLocation.equals(npc.getWorldLocation())) + { + continue; + } + + Color color; + if (npc.getSpotAnimation() == GraphicID.FLYING_FISH) + { + color = Color.RED; + } + else if (spot == FishingSpot.COMMON_TENCH && npc.getWorldLocation().distanceTo2D(client.getLocalPlayer().getWorldLocation()) <= ONE_TICK_AERIAL_FISHING) + { + color = Color.GREEN; + } + else + { + color = Color.CYAN; + } if (spot == FishingSpot.MINNOW && plugin.isShowMinnowOverlay()) { @@ -127,12 +148,6 @@ class FishingSpotOverlay extends Overlay { Polygon poly = npc.getCanvasTilePoly(); - if (spot == FishingSpot.COMMON_TENCH - && npc.getWorldLocation().distanceTo2D(client.getLocalPlayer().getWorldLocation()) <= ONE_TICK_AERIAL_FISHING) - { - color = Color.GREEN; - } - if (poly != null) { OverlayUtil.renderPolygon(graphics, poly, color.darker()); @@ -164,17 +179,14 @@ class FishingSpotOverlay extends Overlay String text = spot.getName(); Point textLocation = npc.getCanvasTextLocation(graphics, text, npc.getLogicalHeight() + 40); - if (spot == FishingSpot.COMMON_TENCH - && npc.getWorldLocation().distanceTo2D(client.getLocalPlayer().getWorldLocation()) <= ONE_TICK_AERIAL_FISHING) - { - color = Color.GREEN; - } - if (textLocation != null) { OverlayUtil.renderTextLocation(graphics, textLocation, text, color.darker()); } } + + previousSpot = spot; + previousLocation = npc.getWorldLocation(); } return null; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/TextureManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/TextureManager.java index eadaefa9e5..8a2b01d31b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/TextureManager.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/TextureManager.java @@ -38,7 +38,6 @@ class TextureManager private static final float PERC_64 = 1f / 64f; private static final float PERC_128 = 1f / 128f; - private static final int SMALL_TEXTURE_SIZE = 64; private static final int TEXTURE_SIZE = 128; int initTextureArray(TextureProvider textureProvider, GL4 gl) @@ -130,8 +129,15 @@ class TextureManager ++cnt; - int srcSize = srcPixels.length == 4096 ? SMALL_TEXTURE_SIZE : TEXTURE_SIZE; - byte[] pixels = convertPixels(srcPixels, srcSize, srcSize, TEXTURE_SIZE, TEXTURE_SIZE); + if (srcPixels.length != TEXTURE_SIZE * TEXTURE_SIZE) + { + // The texture storage is 128x128 bytes, and will only work correctly with the + // 128x128 textures from high detail mode + log.warn("Texture size for {} is {}!", textureId, srcPixels.length); + continue; + } + + byte[] pixels = convertPixels(srcPixels, TEXTURE_SIZE, TEXTURE_SIZE, TEXTURE_SIZE, TEXTURE_SIZE); ByteBuffer pixelBuffer = ByteBuffer.wrap(pixels); gl.glTexSubImage3D(gl.GL_TEXTURE_2D_ARRAY, 0, 0, 0, textureId, TEXTURE_SIZE, TEXTURE_SIZE, 1, gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, pixelBuffer); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPlugin.java index aecdfec4bd..9d873bf7f2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPlugin.java @@ -299,7 +299,15 @@ public class GroundMarkerPlugin extends Plugin { if (hotKeyPressed && event.getOption().equals(WALK_HERE)) { + final Tile selectedSceneTile = client.getSelectedSceneTile(); + + if (selectedSceneTile == null) + { + return; + } + MenuEntry[] menuEntries = client.getMenuEntries(); + int lastIndex = menuEntries.length; menuEntries = Arrays.copyOf(menuEntries, lastIndex + 4); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemskeptondeath/FixedPriceItem.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemskeptondeath/FixedPriceItem.java index 74120a47d6..aae7d1694b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemskeptondeath/FixedPriceItem.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemskeptondeath/FixedPriceItem.java @@ -214,7 +214,10 @@ enum FixedPriceItem VERACS_FLAIL_25(ItemID.VERACS_FLAIL_25, 2500, ItemID.VERACS_FLAIL_0), VERACS_FLAIL_50(ItemID.VERACS_FLAIL_50, 5000, ItemID.VERACS_FLAIL_0), VERACS_FLAIL_75(ItemID.VERACS_FLAIL_75, 7500, ItemID.VERACS_FLAIL_0), - VERACS_FLAIL_100(ItemID.VERACS_FLAIL_100, 10000, ItemID.VERACS_FLAIL_0); + VERACS_FLAIL_100(ItemID.VERACS_FLAIL_100, 10000, ItemID.VERACS_FLAIL_0), + + AVERNIC_DEFENDER(ItemID.AVERNIC_DEFENDER, 4040000), + ; private final int itemId; private final int offset; 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 f9f1d33a91..c2e3abecc8 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 @@ -41,6 +41,7 @@ import java.io.FileReader; import java.io.IOException; import java.nio.file.Files; import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -106,6 +107,7 @@ import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.loottracker.localstorage.LTItemEntry; import net.runelite.client.plugins.loottracker.localstorage.LTRecord; import net.runelite.client.plugins.loottracker.localstorage.LootRecordWriter; +import net.runelite.client.task.Schedule; import net.runelite.client.ui.ClientToolbar; import net.runelite.client.ui.NavigationButton; import net.runelite.client.util.ImageUtil; @@ -218,6 +220,7 @@ public class LootTrackerPlugin extends Plugin private Multiset inventorySnapshot; @Getter(AccessLevel.PACKAGE) private LootTrackerClient lootTrackerClient; + private final List queuedLoots = new ArrayList<>(); private Map killCountMap = new HashMap<>(); private boolean gotPet = false; @@ -291,6 +294,7 @@ public class LootTrackerPlugin extends Plugin private void onSessionClose(SessionClose sessionClose) { + submitLoot(); lootTrackerClient = null; } @@ -331,7 +335,6 @@ public class LootTrackerPlugin extends Plugin @Override protected void startUp() throws Exception { - addSubscriptions(); ignoredItems = Text.fromCSV(config.getIgnoredItems()); @@ -421,6 +424,7 @@ public class LootTrackerPlugin extends Plugin protected void shutDown() { eventBus.unregister(this); + submitLoot(); clientToolbar.removeNavigation(navButton); lootTrackerClient = null; @@ -528,9 +532,12 @@ public class LootTrackerPlugin extends Plugin LootRecord lootRecord = new LootRecord(name, localUsername, LootRecordType.NPC, toGameItems(items), Instant.now()); - if (config.saveLoot() && lootTrackerClient != null) + if (config.saveLoot()) { - lootTrackerClient.submit(lootRecord); + synchronized (queuedLoots) + { + queuedLoots.add(lootRecord); + } } if (this.localPersistence) { @@ -578,9 +585,12 @@ public class LootTrackerPlugin extends Plugin SwingUtilities.invokeLater(() -> panel.add(name, localUsername, combat, entries)); LootRecord lootRecord = new LootRecord(name, localUsername, LootRecordType.PLAYER, toGameItems(items), Instant.now()); - if (lootTrackerClient != null && this.saveLoot) + if (this.saveLoot) { - lootTrackerClient.submit(lootRecord); + synchronized (queuedLoots) + { + queuedLoots.add(lootRecord); + } } if (config.localPersistence()) { @@ -691,9 +701,12 @@ public class LootTrackerPlugin extends Plugin final int killCount = killCountMap.getOrDefault(eventType.toUpperCase(), -1); - if (lootTrackerClient != null && this.saveLoot) + if (this.saveLoot) { - lootTrackerClient.submit(lootRecord); + synchronized (queuedLoots) + { + queuedLoots.add(lootRecord); + } } if (config.localPersistence()) { @@ -871,9 +884,12 @@ public class LootTrackerPlugin extends Plugin client.getLocalPlayer().getCombatLevel(), entries)); LootRecord lootRecord = new LootRecord(name, client.getLocalPlayer().getName(), LootRecordType.DEATH, toGameItems(itemsLost), Instant.now()); - if (lootTrackerClient != null && this.saveLoot) + if (this.saveLoot) { - lootTrackerClient.submit(lootRecord); + synchronized (queuedLoots) + { + queuedLoots.add(lootRecord); + } } if (this.localPersistence) { @@ -989,6 +1005,40 @@ public class LootTrackerPlugin extends Plugin } } + @Schedule( + period = 5, + unit = ChronoUnit.MINUTES, + asynchronous = true + ) + public void submitLootTask() + { + submitLoot(); + } + + private void submitLoot() + { + List copy; + synchronized (queuedLoots) + { + if (queuedLoots.isEmpty()) + { + return; + } + + copy = new ArrayList<>(queuedLoots); + queuedLoots.clear(); + } + + if (lootTrackerClient == null || !config.saveLoot()) + { + return; + } + + log.debug("Submitting {} loot records", copy.size()); + + lootTrackerClient.submit(copy); + } + private void takeInventorySnapshot() { final ItemContainer itemContainer = client.getItemContainer(InventoryID.INVENTORY); @@ -1045,9 +1095,12 @@ public class LootTrackerPlugin extends Plugin LootRecord lootRecord = new LootRecord(chestType, client.getLocalPlayer().getName(), LootRecordType.EVENT, toGameItems(items), Instant.now()); - if (lootTrackerClient != null && config.saveLoot()) + if (config.saveLoot()) { - lootTrackerClient.submit(lootRecord); + synchronized (queuedLoots) + { + queuedLoots.add(lootRecord); + } } if (config.localPersistence()) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/lowmemory/LowMemoryPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/lowmemory/LowMemoryPlugin.java index 039a69cac3..9129c18ad1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/lowmemory/LowMemoryPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/lowmemory/LowMemoryPlugin.java @@ -26,7 +26,10 @@ package net.runelite.client.plugins.lowmemory; import javax.inject.Inject; import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.events.GameStateChanged; import net.runelite.client.callback.ClientThread; +import net.runelite.client.eventbus.EventBus; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; @@ -44,10 +47,18 @@ public class LowMemoryPlugin extends Plugin @Inject private ClientThread clientThread; + @Inject + private EventBus eventBus; + @Override protected void startUp() { - clientThread.invoke(() -> client.changeMemoryMode(true)); + this.eventBus.subscribe(GameStateChanged.class, this, this::onGameStateChanged); + + if (client.getGameState() == GameState.LOGGED_IN) + { + clientThread.invoke(() -> client.changeMemoryMode(true)); + } } @Override @@ -55,4 +66,15 @@ public class LowMemoryPlugin extends Plugin { clientThread.invoke(() -> client.changeMemoryMode(false)); } -} \ No newline at end of file + + private void onGameStateChanged(GameStateChanged event) + { + // When the client starts it initializes the texture size based on the memory mode setting. + // Don't set low memory before the login screen is ready to prevent loading the low detail textures, + // which breaks the gpu plugin due to it requiring the 128x128px textures + if (event.getGameState() == GameState.LOGIN_SCREEN) + { + client.changeMemoryMode(true); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerPlugin.java index 184231d8ca..83426ce6c1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerPlugin.java @@ -54,6 +54,7 @@ import lombok.extern.slf4j.Slf4j; import net.runelite.api.Actor; import net.runelite.api.ChatMessageType; import net.runelite.api.Client; +import net.runelite.api.GameState; import net.runelite.api.ItemID; import net.runelite.api.MessageNode; import net.runelite.api.NPC; @@ -133,7 +134,7 @@ public class SlayerPlugin extends Plugin private static final int GROTESQUE_GUARDIANS_REGION = 6727; - private static final Set weaknessTasks = ImmutableSet.of(Task.DESERT_LIZARDS, Task.GARGOYLES, + private static final Set weaknessTasks = ImmutableSet.of(Task.LIZARDS, Task.GARGOYLES, Task.GROTESQUE_GUARDIANS, Task.GROTESQUE_GUARDIANS, Task.MUTATED_ZYGOMITES, Task.ROCKSLUGS); // Chat Command @@ -242,7 +243,7 @@ public class SlayerPlugin extends Plugin private Task weaknessTask = null; private TaskCounter counter; - private int cachedXp; + private int cachedXp = -1; private int cachedPoints; private Instant infoTimer; private List targetNames = new ArrayList<>(); @@ -328,6 +329,11 @@ public class SlayerPlugin extends Plugin clientToolbar.addNavigation(navButton); + if (client.getGameState() == GameState.LOGGED_IN) + { + cachedXp = client.getSkillExperience(SLAYER); + } + chatCommandManager.registerCommandAsync(TASK_COMMAND_STRING, this::taskLookup, this::taskSubmit); chatCommandManager.registerCommandAsync(POINTS_COMMAND_STRING, this::pointsLookup); //here @@ -348,6 +354,8 @@ public class SlayerPlugin extends Plugin chatCommandManager.unregisterCommand(TASK_COMMAND_STRING); chatCommandManager.unregisterCommand(POINTS_COMMAND_STRING); clientToolbar.removeNavigation(navButton); + + cachedXp = -1; } private void addSubscriptions() @@ -376,6 +384,7 @@ public class SlayerPlugin extends Plugin { case HOPPING: case LOGGING_IN: + cachedXp = -1; cachedPoints = 0; clearTrackedNPCs(); break; @@ -736,45 +745,47 @@ public class SlayerPlugin extends Plugin return; } - if (cachedXp != 0) + if (cachedXp == -1) { - final Task task = Task.getTask(taskName); + // this is the initial xp sent on login + cachedXp = slayerExp; + return; + } - if (task == null) + final Task task = Task.getTask(taskName); + + // null tasks are technically valid, it only means they arent explicitly defined in the Task enum + // allow them through so that if there is a task capture failure the counter will still work + final int taskKillExp = task != null ? task.getExpectedKillExp() : 0; + + // Only count exp gain as a kill if the task either has no expected exp for a kill, or if the exp gain is equal + // to the expected exp gain for the task. + if (taskKillExp == 0 || taskKillExp == slayerExp - cachedXp) + { + killedOne(); + } + else + { + // this is not the initial xp sent on login so these are new xp gains + int gains = slayerExp - cachedXp; + + // potential npcs to give xp drop are current highlighted npcs and the lingering presences + List potentialNPCs = new ArrayList<>(lingeringPresences); + for (NPC npc : highlightedTargets) { - return; + NPCPresence currentPresence = NPCPresence.buildPresence(npc); + potentialNPCs.add(currentPresence); } - final int taskKillExp = task.getExpectedKillExp(); - - // Only count exp gain as a kill if the task either has no expected exp for a kill, or if the exp gain is equal - // to the expected exp gain for the task. - if (taskKillExp == 0 || taskKillExp == slayerExp - cachedXp) + int killCount = estimateKillCount(potentialNPCs, gains); + for (int i = 0; i < killCount; i++) { killedOne(); - } - else - { - // this is not the initial xp sent on login so these are new xp gains - int gains = slayerExp - cachedXp; - - // potential npcs to give xp drop are current highlighted npcs and the lingering presences - List potentialNPCs = new ArrayList<>(lingeringPresences); - for (NPC npc : highlightedTargets) - { - NPCPresence currentPresence = NPCPresence.buildPresence(npc); - potentialNPCs.add(currentPresence); - } - - int killCount = estimateKillCount(potentialNPCs, gains); - for (int i = 0; i < killCount; i++) - { - killedOne(); - int delta = slayerExp - cachedXp; - currentTask.setElapsedXp(currentTask.getElapsedXp() + delta); - } + int delta = slayerExp - cachedXp; + currentTask.setElapsedXp(currentTask.getElapsedXp() + delta); } } + cachedXp = slayerExp; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/Task.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/Task.java index 9a0e6bd2a6..39668df0c7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/Task.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/Task.java @@ -112,8 +112,6 @@ enum Task asList("Night beast"), Collections.emptyList()), DARK_WARRIORS("Dark warriors", ItemID.BLACK_MED_HELM), DERANGED_ARCHAEOLOGIST("Deranged Archaeologist", ItemID.ARCHAEOLOGISTS_DIARY), - DESERT_LIZARDS("Desert lizards", ItemID.DESERT_LIZARD, - asList("Small lizard", "Lizard"), Collections.emptyList(), 4, ItemID.ICE_COOLER), DOGS("Dogs", ItemID.GUARD_DOG, asList("Jackal"), Collections.emptyList()), DRAKES("Drakes", ItemID.DRAKE), DUST_DEVILS("Dust devils", ItemID.DUST_DEVIL, @@ -174,6 +172,8 @@ enum Task LESSER_DEMONS("Lesser demons", ItemID.LESSER_DEMON_MASK), LIZARDMEN("Lizardmen", ItemID.LIZARDMAN_FANG, asList("Lizardman"), Collections.emptyList()), + LIZARDS("Lizards", ItemID.DESERT_LIZARD, + asList("Desert lizard", "Sulphur lizard", "Small lizard", "Lizard"), Collections.emptyList(), 4, ItemID.ICE_COOLER), MAGIC_AXES("Magic axes", ItemID.IRON_BATTLEAXE), MAMMOTHS("Mammoths", ItemID.ATTACKER_HORN, asList("Mammoth"), Collections.emptyList()), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timers/GameTimer.java b/runelite-client/src/main/java/net/runelite/client/plugins/timers/GameTimer.java index e3088c219f..6e1f787c94 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timers/GameTimer.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timers/GameTimer.java @@ -59,7 +59,7 @@ enum GameTimer ICEBURST(SpriteID.SPELL_ICE_BURST, GameTimerImageType.SPRITE, "Ice burst", GraphicID.ICE_BURST, 10, ChronoUnit.SECONDS, true), ICEBLITZ(SpriteID.SPELL_ICE_BLITZ, GameTimerImageType.SPRITE, "Ice blitz", GraphicID.ICE_BLITZ, 15, ChronoUnit.SECONDS, true), ICEBARRAGE(SpriteID.SPELL_ICE_BARRAGE, GameTimerImageType.SPRITE, "Ice barrage", GraphicID.ICE_BARRAGE, 20, ChronoUnit.SECONDS, true), - IMBUEDHEART(ItemID.IMBUED_HEART, GameTimerImageType.ITEM, "Imbued heart", GraphicID.IMBUED_HEART, 420, ChronoUnit.SECONDS), + IMBUEDHEART(ItemID.IMBUED_HEART, GameTimerImageType.ITEM, "Imbued heart", GraphicID.IMBUED_HEART, 420, ChronoUnit.SECONDS, true), VENGEANCE(SpriteID.SPELL_VENGEANCE, GameTimerImageType.SPRITE, "Vengeance", 30, ChronoUnit.SECONDS), EXSUPERANTIFIRE(ItemID.EXTENDED_SUPER_ANTIFIRE4, GameTimerImageType.ITEM, "Extended Super AntiFire", 6, ChronoUnit.MINUTES), OVERLOAD_RAID(ItemID.OVERLOAD_4_20996, GameTimerImageType.ITEM, "Overload", 5, ChronoUnit.MINUTES, true), diff --git a/runelite-client/src/main/java/net/runelite/client/rs/ClientConfigLoader.java b/runelite-client/src/main/java/net/runelite/client/rs/ClientConfigLoader.java index 735c8a459d..1f96828d6b 100644 --- a/runelite-client/src/main/java/net/runelite/client/rs/ClientConfigLoader.java +++ b/runelite-client/src/main/java/net/runelite/client/rs/ClientConfigLoader.java @@ -48,11 +48,15 @@ class ClientConfigLoader final RSConfig config = new RSConfig(); - try (final Response response = RuneLiteAPI.CLIENT.newCall(request).execute(); - final BufferedReader in = new BufferedReader(new InputStreamReader(response.body().byteStream()))) + try (final Response response = RuneLiteAPI.CLIENT.newCall(request).execute()) { - String str; + if (!response.isSuccessful()) + { + throw new IOException("Unsuccessful response: " + response.message()); + } + String str; + final BufferedReader in = new BufferedReader(new InputStreamReader(response.body().byteStream())); while ((str = in.readLine()) != null) { int idx = str.indexOf('='); diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayRenderer.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayRenderer.java index 555c7e02e9..c71201ff98 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayRenderer.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayRenderer.java @@ -276,6 +276,14 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener if (overlayPosition == OverlayPosition.DYNAMIC || overlayPosition == OverlayPosition.TOOLTIP) { safeRender(client, overlay, layer, graphics, new Point()); + + // Restore graphics2d properties + graphics.setTransform(transform); + graphics.setStroke(stroke); + graphics.setComposite(composite); + graphics.setPaint(paint); + graphics.setRenderingHints(renderingHints); + graphics.setBackground(background); } else { @@ -312,6 +320,14 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener safeRender(client, overlay, layer, graphics, location); + // Restore graphics2d properties prior to drawing bounds + graphics.setTransform(transform); + graphics.setStroke(stroke); + graphics.setComposite(composite); + graphics.setPaint(paint); + graphics.setRenderingHints(renderingHints); + graphics.setBackground(background); + final Rectangle bounds = overlay.getBounds(); if (!bounds.isEmpty()) @@ -330,14 +346,6 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener } } } - - // Restore graphics2d properties - graphics.setTransform(transform); - graphics.setStroke(stroke); - graphics.setComposite(composite); - graphics.setPaint(paint); - graphics.setRenderingHints(renderingHints); - graphics.setBackground(background); } } diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/frag.glsl b/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/frag.glsl index 03d8464642..646d5dfd7d 100644 --- a/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/frag.glsl +++ b/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/frag.glsl @@ -31,7 +31,7 @@ uniform float smoothBanding; uniform vec4 fogColor; in vec4 Color; -in float fHsl; +centroid in float fHsl; in vec4 fUv; in float fogAmount; diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/geom.glsl b/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/geom.glsl index c644b1960e..28a339f788 100644 --- a/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/geom.glsl +++ b/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/geom.glsl @@ -52,7 +52,7 @@ in vec4 vUv[]; in float vFogAmount[]; out vec4 Color; -out float fHsl; +centroid out float fHsl; out vec4 fUv; out float fogAmount; diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/skybox/skybox.txt b/runelite-client/src/main/resources/net/runelite/client/plugins/skybox/skybox.txt index 4d37a271ef..9451d6a707 100644 --- a/runelite-client/src/main/resources/net/runelite/client/plugins/skybox/skybox.txt +++ b/runelite-client/src/main/resources/net/runelite/client/plugins/skybox/skybox.txt @@ -961,3 +961,7 @@ R 49 92 51 92 // Iorwerth dungeon #030A0A R 49 193 51 194 + +// Braindeath Island +#8AD2DF +R 33 79 33 80 \ No newline at end of file diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/itemskeptondeath/ItemsKeptOnDeathPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/itemskeptondeath/ItemsKeptOnDeathPluginTest.java index 5b9a4f4103..b34298fe63 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/itemskeptondeath/ItemsKeptOnDeathPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/itemskeptondeath/ItemsKeptOnDeathPluginTest.java @@ -628,4 +628,29 @@ public class ItemsKeptOnDeathPluginTest final List lost = deathItems.getLostItems(); assertTrue(lost.contains(new ItemStack(ItemID.DRAGON_DEFENDER, 1))); } + + @Test + public void avernicDefenderPriceTest() + { + final Item defender = mItem(ItemID.AVERNIC_DEFENDER, 1, "Avernic defender", false, 0); + final int defenderOffset = FixedPriceItem.AVERNIC_DEFENDER.getOffset(); + final Integer defenderBrokenPrice = BrokenOnDeathItem.getRepairPrice(ItemID.AVERNIC_DEFENDER); + final int defenderExpectedPrice = (defenderBrokenPrice == null ? 0 : defenderBrokenPrice) + defenderOffset; + assertEquals(defenderExpectedPrice, plugin.getDeathPrice(defender)); + + final Item[] inv = new Item[] + { + defender, + mItem(ItemID.BERSERKER_RING_I, 1, "Berserker Ring (i)", false, 3042579) + }; + + plugin.isSkulled = true; + plugin.protectingItem = true; + plugin.wildyLevel = 21; + + final DeathItems deathItems = plugin.calculateKeptLostItems(inv, new Item[0]); + + final List kept = deathItems.getKeptItems(); + assertTrue(kept.contains(new ItemStack(ItemID.AVERNIC_DEFENDER, 1))); + } } diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/slayer/SlayerPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/slayer/SlayerPluginTest.java index 5ba89b19ee..50b729e58b 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/slayer/SlayerPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/slayer/SlayerPluginTest.java @@ -453,6 +453,49 @@ public class SlayerPluginTest } } + @Test + public void testCorrectlyCapturedTaskKill() + { + final Player player = mock(Player.class); + when(player.getLocalLocation()).thenReturn(new LocalPoint(0, 0)); + when(client.getLocalPlayer()).thenReturn(player); + + final ExperienceChanged experienceChanged = new ExperienceChanged(); + experienceChanged.setSkill(Skill.SLAYER); + + when(client.getSkillExperience(Skill.SLAYER)).thenReturn(100); + slayerPlugin.onExperienceChanged(experienceChanged); + + slayerPlugin.setTask("Dagannoth", 143, 143, true, 0); + + when(client.getSkillExperience(Skill.SLAYER)).thenReturn(110); + slayerPlugin.onExperienceChanged(experienceChanged); + + assertEquals(142, slayerPlugin.getCurrentTask().getAmount()); + } + + @Test + public void testIncorrectlyCapturedTaskKill() + { + final Player player = mock(Player.class); + when(player.getLocalLocation()).thenReturn(new LocalPoint(0, 0)); + when(client.getLocalPlayer()).thenReturn(player); + + final ExperienceChanged experienceChanged = new ExperienceChanged(); + experienceChanged.setSkill(Skill.SLAYER); + + when(client.getSkillExperience(Skill.SLAYER)).thenReturn(100); + slayerPlugin.onExperienceChanged(experienceChanged); + + slayerPlugin.setTask("Monster", 98, 98, true, 0); + assert Task.getTask("Monster") == null; + + when(client.getSkillExperience(Skill.SLAYER)).thenReturn(110); + slayerPlugin.onExperienceChanged(experienceChanged); + + assertEquals(97, slayerPlugin.getCurrentTask().getAmount()); + } + @Test public void testJadTaskKill() { @@ -508,4 +551,25 @@ public class SlayerPluginTest assertEquals(0, slayerPlugin.getCurrentTask().getAmount()); } + + @Test + public void testNewAccountSlayerKill() + { + final Player player = mock(Player.class); + when(player.getLocalLocation()).thenReturn(new LocalPoint(0, 0)); + when(client.getLocalPlayer()).thenReturn(player); + + final ExperienceChanged experienceChanged = new ExperienceChanged(); + experienceChanged.setSkill(Skill.SLAYER); + + slayerPlugin.setTask("Bears", 35, 35, true, 0); + + when(client.getSkillExperience(Skill.SLAYER)).thenReturn(0); + slayerPlugin.onExperienceChanged(experienceChanged); + + when(client.getSkillExperience(Skill.SLAYER)).thenReturn(27); + slayerPlugin.onExperienceChanged(experienceChanged); + + assertEquals(34, slayerPlugin.getCurrentTask().getAmount()); + } }