client: Async-ify or improve data loading methods (#1782)

client: Async-ify or improve data loading methods
This commit is contained in:
Owain van Brakel
2019-10-15 18:33:12 +02:00
committed by GitHub
33 changed files with 750 additions and 149992 deletions

View File

@@ -24,77 +24,78 @@
*/
package net.runelite.client;
import java.io.IOException;
import io.reactivex.schedulers.Schedulers;
import java.time.temporal.ChronoUnit;
import java.util.UUID;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.task.Schedule;
@Singleton
@Slf4j
public class ClientSessionManager
{
private final SessionClient sessionClient = new SessionClient(this);
private final ScheduledExecutorService executorService;
private ScheduledFuture<?> scheduledFuture;
private final SessionClient sessionClient;
private final ClientThread clientThread;
private UUID sessionId;
@Inject
ClientSessionManager(ScheduledExecutorService executorService)
ClientSessionManager(ClientThread clientThread)
{
this.executorService = executorService;
this.sessionClient = new SessionClient();
this.clientThread = clientThread;
}
public void start()
void start()
{
sessionClient.open();
scheduledFuture = executorService.scheduleWithFixedDelay(this::ping, 1, 10, TimeUnit.MINUTES);
sessionClient.openSession()
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.from(clientThread))
.subscribe(this::setUuid, this::error);
}
void setUuid(UUID uuid)
@Schedule(period = 10, unit = ChronoUnit.MINUTES, asynchronous = true)
private void ping()
{
this.sessionId = uuid;
log.debug("Opened session {}", sessionId);
}
if (sessionId == null)
{
start();
return;
}
void error(IOException e)
{
log.warn("Client session error, resetting UUID", e.getCause());
sessionId = null;
sessionClient.pingSession(sessionId)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.from(clientThread))
.doOnError(e -> this.error((Throwable) e))
.subscribe();
}
public void shutdown()
{
if (sessionId != null)
{
try
{
sessionClient.delete(sessionId);
}
catch (IOException ex)
{
log.warn(null, ex);
}
sessionClient.delete(sessionId)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.from(clientThread))
.doOnError(e -> this.error((Throwable) e))
.subscribe();
sessionId = null;
}
scheduledFuture.cancel(true);
}
private void ping()
private void setUuid(UUID uuid)
{
if (sessionId == null)
{
sessionClient.open();
return;
}
this.sessionId = uuid;
log.debug("Opened session {}.", sessionId);
}
sessionClient.ping(sessionId);
private void error(Throwable error)
{
log.debug("Error in client session.");
log.trace(null, error);
}
}

View File

@@ -375,6 +375,7 @@ public class RuneLite
if (this.client != null)
{
scheduler.registerObject(modelOutlineRenderer.get());
scheduler.registerObject(clientSessionManager);
}
// Close the splash screen

View File

@@ -24,106 +24,68 @@
*/
package net.runelite.client;
import com.google.gson.JsonParseException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import io.reactivex.Observable;
import java.util.UUID;
import net.runelite.http.api.RuneLiteAPI;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.HttpUrl;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import org.jetbrains.annotations.NotNull;
class SessionClient
{
private final ClientSessionManager manager;
SessionClient(ClientSessionManager manager)
Observable<UUID> openSession()
{
this.manager = manager;
}
final HttpUrl url = RuneLiteAPI.getSessionBase();
void open()
{
HttpUrl url = RuneLiteAPI.getopenosrsSessionBase().newBuilder()
.build();
Request request = new Request.Builder()
.url(url)
.build();
RuneLiteAPI.CLIENT.newCall(request).enqueue(new Callback()
return Observable.fromCallable(() ->
{
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e)
Request request = new Request.Builder()
.url(url)
.build();
try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute())
{
manager.error(e);
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response)
{
try
{
ResponseBody body = response.body();
InputStream in = body.byteStream();
manager.setUuid(RuneLiteAPI.GSON.fromJson(new InputStreamReader(in), UUID.class));
}
catch (JsonParseException | IllegalArgumentException ex) // UUID.fromString can throw IllegalArgumentException
{
manager.error(new IOException(ex));
}
return RuneLiteAPI.GSON.fromJson(response.body().string(), UUID.class);
}
});
}
void ping(UUID uuid)
Observable pingSession(UUID uuid)
{
HttpUrl url = RuneLiteAPI.getopenosrsSessionBase().newBuilder()
final HttpUrl url = RuneLiteAPI.getSessionBase().newBuilder()
.addPathSegment("ping")
.addQueryParameter("session", uuid.toString())
.build();
Request request = new Request.Builder()
.url(url)
.build();
RuneLiteAPI.CLIENT.newCall(request).enqueue(new Callback()
return Observable.defer(() ->
{
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e)
{
manager.error(e);
}
Request request = new Request.Builder()
.url(url)
.build();
@Override
public void onResponse(@NotNull Call call, @NotNull Response response)
try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute())
{
if (!response.isSuccessful())
{
manager.error(new IOException("Failed ping"));
}
return Observable.empty();
}
});
}
void delete(UUID uuid) throws IOException
Observable delete(UUID uuid)
{
HttpUrl url = RuneLiteAPI.getopenosrsSessionBase().newBuilder()
final HttpUrl url = RuneLiteAPI.getSessionBase().newBuilder()
.addQueryParameter("session", uuid.toString())
.build();
Request request = new Request.Builder()
.delete()
.url(url)
.build();
return Observable.defer(() ->
{
Request request = new Request.Builder()
.delete()
.url(url)
.build();
RuneLiteAPI.CLIENT.newCall(request).execute().close();
RuneLiteAPI.CLIENT.newCall(request).execute().close();
return Observable.empty();
});
}
}

View File

@@ -25,6 +25,7 @@
package net.runelite.client.account;
import com.google.gson.Gson;
import io.reactivex.schedulers.Schedulers;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
@@ -37,7 +38,6 @@ import javax.inject.Singleton;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.client.RuneLite;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.events.SessionClose;
import net.runelite.client.events.SessionOpen;
@@ -57,13 +57,11 @@ public class SessionManager
private AccountSession accountSession;
private final EventBus eventBus;
private final ConfigManager configManager;
private final WSClient wsClient;
@Inject
private SessionManager(ConfigManager configManager, EventBus eventBus, WSClient wsClient)
private SessionManager(EventBus eventBus, WSClient wsClient)
{
this.configManager = configManager;
this.eventBus = eventBus;
this.wsClient = wsClient;
@@ -94,13 +92,26 @@ public class SessionManager
// Check if session is still valid
AccountClient accountClient = new AccountClient(session.getUuid());
if (!accountClient.sessionCheck())
{
log.debug("Loaded session {} is invalid", session.getUuid());
return;
}
openSession(session, false);
accountClient.sessionCheck()
.subscribeOn(Schedulers.io())
.subscribe(b ->
{
if (!b)
{
log.debug("Loaded session {} is invalid", session.getUuid());
}
else
{
openSession(session, false);
}
}, ex ->
{
if (ex instanceof IOException)
{
log.debug("Unable to verify session", ex);
openSession(session, false);
}
});
}
private void saveSession()
@@ -143,13 +154,6 @@ public class SessionManager
accountSession = session;
if (session.getUsername() != null)
{
// Initialize config for new session
// If the session isn't logged in yet, don't switch to the new config
configManager.switchSession();
}
eventBus.post(SessionOpen.class, new SessionOpen());
}
@@ -176,9 +180,6 @@ public class SessionManager
accountSession = null; // No more account
// Restore config
configManager.switchSession();
eventBus.post(SessionClose.class, new SessionClose());
}

View File

@@ -28,14 +28,10 @@ import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import io.reactivex.Completable;
import io.reactivex.schedulers.Schedulers;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -137,12 +133,11 @@ public class ItemManager
private final Client client;
private final ClientThread clientThread;
private final ItemClient itemClient;
private final ImmutableMap<Integer, ItemStats> itemStatMap;
private final LoadingCache<ImageKey, AsyncBufferedImage> itemImages;
private final LoadingCache<Integer, ItemDefinition> itemDefinitions;
private final LoadingCache<OutlineKey, BufferedImage> itemOutlines;
private Map<Integer, ItemPrice> itemPrices = Collections.emptyMap();
private Map<Integer, ItemStats> itemStats = Collections.emptyMap();
private ImmutableMap<Integer, ItemStats> itemStats = ImmutableMap.of();
@Inject
public ItemManager(
@@ -166,7 +161,7 @@ public class ItemManager
.build(new CacheLoader<ImageKey, AsyncBufferedImage>()
{
@Override
public AsyncBufferedImage load(@NotNull ImageKey key) throws Exception
public AsyncBufferedImage load(@NotNull ImageKey key)
{
return loadImage(key.itemId, key.itemQuantity, key.stackable);
}
@@ -178,7 +173,7 @@ public class ItemManager
.build(new CacheLoader<Integer, ItemDefinition>()
{
@Override
public ItemDefinition load(@NotNull Integer key) throws Exception
public ItemDefinition load(@NotNull Integer key)
{
return client.getItemDefinition(key);
}
@@ -190,24 +185,21 @@ public class ItemManager
.build(new CacheLoader<OutlineKey, BufferedImage>()
{
@Override
public BufferedImage load(@NotNull OutlineKey key) throws Exception
public BufferedImage load(@NotNull OutlineKey key)
{
return loadItemOutline(key.itemId, key.itemQuantity, key.outlineColor);
}
});
final Gson gson = new Gson();
final Type typeToken = new TypeToken<Map<Integer, ItemStats>>()
{
}.getType();
final InputStream statsFile = getClass().getResourceAsStream("/item_stats.json");
final Map<Integer, ItemStats> stats = gson.fromJson(new InputStreamReader(statsFile), typeToken);
itemStatMap = ImmutableMap.copyOf(stats);
eventbus.subscribe(GameStateChanged.class, this, this::onGameStateChanged);
eventbus.subscribe(PostItemDefinition.class, this, this::onPostItemDefinition);
Completable.fromAction(ItemVariationMapping::load)
.subscribeOn(Schedulers.computation())
.subscribe(
() -> log.debug("Loaded {} item variations", ItemVariationMapping.getSize()),
ex -> log.warn("Error loading item variations", ex)
);
}
private void loadPrices()
@@ -215,21 +207,9 @@ public class ItemManager
itemClient.getPrices()
.subscribeOn(Schedulers.io())
.subscribe(
(prices) ->
{
if (prices != null)
{
ImmutableMap.Builder<Integer, ItemPrice> map = ImmutableMap.builderWithExpectedSize(prices.length);
for (ItemPrice price : prices)
{
map.put(price.getId(), price);
}
itemPrices = map.build();
}
log.debug("Loaded {} prices", itemPrices.size());
},
(e) -> log.warn("error loading prices!", e)
m -> itemPrices = m,
e -> log.warn("Error loading prices", e),
() -> log.debug("Loaded {} prices", itemPrices.size())
);
}
@@ -238,16 +218,9 @@ public class ItemManager
itemClient.getStats()
.subscribeOn(Schedulers.io())
.subscribe(
(stats) ->
{
if (stats != null)
{
itemStats = ImmutableMap.copyOf(stats);
}
log.debug("Loaded {} stats", itemStats.size());
},
(e) -> log.warn("error loading stats!", e)
m -> itemStats = m,
e -> log.warn("Error fetching stats", e),
() -> log.debug("Loaded {} stats", itemStats.size())
);
}
@@ -376,12 +349,12 @@ public class ItemManager
{
ItemDefinition itemDefinition = getItemDefinition(itemId);
if (itemDefinition.getName() == null || !allowNote && itemDefinition.getNote() != -1)
if (!allowNote && itemDefinition.getNote() != -1)
{
return null;
}
return itemStatMap.get(canonicalize(itemId));
return itemStats.get(canonicalize(itemId));
}
/**

View File

@@ -1,27 +0,0 @@
package net.runelite.client.game;
import lombok.Value;
@Value
public class ItemStat
{
private int slot;
private int astab;
private int aslash;
private int acrush;
private int amagic;
private int arange;
private int dstab;
private int dslash;
private int dcrush;
private int dmagic;
private int drange;
private int str;
private int rstr;
private int mdmg;
private int prayer;
private int aspeed;
}

View File

@@ -26,44 +26,20 @@
package net.runelite.client.game;
import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.io.InputStream;
import com.google.gson.stream.JsonReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Collection;
import java.util.Iterator;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
/**
* Converts variation items to it's base item counterparts
*/
@Slf4j
public class ItemVariationMapping
{
private static final Map<Integer, Integer> MAPPINGS;
static
{
final Gson gson = new Gson();
final TypeToken<Map<String, Collection<Integer>>> typeToken = new TypeToken<Map<String, Collection<Integer>>>()
{
};
final InputStream geLimitData = ItemVariationMapping.class.getResourceAsStream("/item_variations.json");
final Map<String, Collection<Integer>> itemVariations = gson.fromJson(new InputStreamReader(geLimitData), typeToken.getType());
ImmutableMap.Builder<Integer, Integer> builder = new ImmutableMap.Builder<>();
for (Collection<Integer> value : itemVariations.values())
{
final Iterator<Integer> iterator = value.iterator();
final int base = iterator.next();
while (iterator.hasNext())
{
builder.put(iterator.next(), base);
}
}
MAPPINGS = builder.build();
}
private static Map<Integer, Integer> MAPPINGS;
/**
* Get base item id for provided variation item id.
@@ -75,4 +51,39 @@ public class ItemVariationMapping
{
return MAPPINGS.getOrDefault(itemId, itemId);
}
static void load() throws IOException
{
try (JsonReader reader = new JsonReader(new InputStreamReader(ItemVariationMapping.class.getResourceAsStream("/item_variations.json"), StandardCharsets.UTF_8)))
{
ImmutableMap.Builder<Integer, Integer> builder = ImmutableMap.builderWithExpectedSize(5039);
reader.beginObject();
while (reader.hasNext())
{
// Names are useless
reader.skipValue();
reader.beginArray();
int base = reader.nextInt();
while (reader.hasNext())
{
builder.put(
reader.nextInt(),
base
);
}
reader.endArray();
}
reader.endObject();
MAPPINGS = builder.build();
}
}
static int getSize()
{
return MAPPINGS.size();
}
}

View File

@@ -26,12 +26,12 @@
package net.runelite.client.game;
import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.io.InputStream;
import com.google.gson.stream.JsonReader;
import io.reactivex.Completable;
import io.reactivex.schedulers.Schedulers;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.util.Map;
import java.nio.charset.StandardCharsets;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -41,20 +41,37 @@ import lombok.extern.slf4j.Slf4j;
@Singleton
public class NPCManager
{
private final ImmutableMap<Integer, NPCStats> statsMap;
private ImmutableMap<Integer, NPCStats> statsMap;
@Inject
private NPCManager()
{
final Gson gson = new Gson();
Completable.fromAction(this::loadStats)
.subscribeOn(Schedulers.computation())
.subscribe(
() -> log.debug("Loaded {} NPC stats", statsMap.size()),
ex -> log.warn("Error loading NPC stats", ex)
);
}
final Type typeToken = new TypeToken<Map<Integer, NPCStats>>()
private void loadStats() throws IOException
{
try (JsonReader reader = new JsonReader(new InputStreamReader(NPCManager.class.getResourceAsStream("/npc_stats.json"), StandardCharsets.UTF_8)))
{
}.getType();
ImmutableMap.Builder<Integer, NPCStats> builder = ImmutableMap.builderWithExpectedSize(2821);
reader.beginObject();
final InputStream statsFile = getClass().getResourceAsStream("/npc_stats.json");
final Map<Integer, NPCStats> stats = gson.fromJson(new InputStreamReader(statsFile), typeToken);
statsMap = ImmutableMap.copyOf(stats);
while (reader.hasNext())
{
builder.put(
Integer.parseInt(reader.nextName()),
NPCStats.NPC_STATS_TYPE_ADAPTER.read(reader)
);
}
reader.endObject();
statsMap = builder.build();
}
}
/**

View File

@@ -24,9 +24,15 @@
*/
package net.runelite.client.game;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import lombok.Builder;
import lombok.Value;
@Value
@Builder(builderClassName = "Builder")
public class NPCStats
{
private final String name;
@@ -77,4 +83,120 @@ public class NPCStats
return (1 + Math.floor(averageLevel * (averageDefBonus + bonusStrength + bonusAttack) / 5120) / 40);
}
// Because this class is here we can't add the TypeAdapter to gson (easily)
// doesn't mean we can't use one to do it a bit quicker
public static final TypeAdapter<NPCStats> NPC_STATS_TYPE_ADAPTER = new TypeAdapter<NPCStats>()
{
@Override
public void write(JsonWriter out, NPCStats value)
{
throw new UnsupportedOperationException("Not supported");
}
@Override
public NPCStats read(JsonReader in) throws IOException
{
in.beginObject();
NPCStats.Builder builder = NPCStats.builder();
// Name is the only one that's guaranteed
in.skipValue();
builder.name(in.nextString());
while (in.hasNext())
{
switch (in.nextName())
{
case "hitpoints":
builder.hitpoints(in.nextInt());
break;
case "combatLevel":
builder.combatLevel(in.nextInt());
break;
case "slayerLevel":
builder.slayerLevel(in.nextInt());
break;
case "attackSpeed":
builder.attackSpeed(in.nextInt());
break;
case "attackLevel":
builder.attackLevel(in.nextInt());
break;
case "strengthLevel":
builder.strengthLevel(in.nextInt());
break;
case "defenceLevel":
builder.defenceLevel(in.nextInt());
break;
case "rangeLevel":
builder.rangeLevel(in.nextInt());
break;
case "magicLevel":
builder.magicLevel(in.nextInt());
break;
case "stab":
builder.stab(in.nextInt());
break;
case "slash":
builder.slash(in.nextInt());
break;
case "crush":
builder.crush(in.nextInt());
break;
case "range":
builder.range(in.nextInt());
break;
case "magic":
builder.magic(in.nextInt());
break;
case "stabDef":
builder.stabDef(in.nextInt());
break;
case "slashDef":
builder.slashDef(in.nextInt());
break;
case "crushDef":
builder.crushDef(in.nextInt());
break;
case "rangeDef":
builder.rangeDef(in.nextInt());
break;
case "magicDef":
builder.magicDef(in.nextInt());
break;
case "bonusAttack":
builder.bonusAttack(in.nextInt());
break;
case "bonusStrength":
builder.bonusStrength(in.nextInt());
break;
case "bonusRangeStrength":
builder.bonusRangeStrength(in.nextInt());
break;
case "bonusMagicDamage":
builder.bonusMagicDamage(in.nextInt());
break;
case "poisonImmune":
builder.poisonImmune(in.nextBoolean());
break;
case "venomImmune":
builder.venomImmune(in.nextBoolean());
break;
case "dragon":
builder.dragon(in.nextBoolean());
break;
case "demon":
builder.demon(in.nextBoolean());
break;
case "undead":
builder.undead(in.nextBoolean());
break;
}
}
in.endObject();
return builder.build();
}
};
}

View File

@@ -56,9 +56,9 @@ public class HighAlchemyOverlay extends WidgetItemOverlay
this.itemManager = itemManager;
this.plugin = plugin;
int natPrice = itemManager.getItemPrice(ItemID.NATURE_RUNE);
int natPrice = itemManager.getItemPrice(ItemID.NATURE_RUNE, true);
this.alchPrice = natPrice;
this.alchPriceNoStaff = natPrice + 5 * itemManager.getItemPrice(ItemID.FIRE_RUNE);
this.alchPriceNoStaff = natPrice + 5 * itemManager.getItemPrice(ItemID.FIRE_RUNE, true);
showOnBank();
showOnInventory();

View File

@@ -48,7 +48,7 @@ import net.runelite.http.api.item.ItemStats;
public class ItemStatOverlay extends Overlay
{
// Unarmed attack speed is 6
private static final ItemStats UNARMED = new ItemStats("", false, true, 0,
private static final ItemStats UNARMED = new ItemStats(false, true, 0,
ItemEquipmentStats.builder()
.aspeed(6)
.build());

View File

@@ -551,6 +551,7 @@ public class PlayerScouter extends Plugin
}
ItemStats item = itemManager.getItemStats(gear, false);
String name = itemManager.getItemDefinition(gear).getName();
if (item == null)
{
@@ -559,7 +560,7 @@ public class PlayerScouter extends Plugin
}
fieldList.add(FieldEmbed.builder()
.name(item.getName())
.name(name)
.value("Value: " + StackFormatter.quantityToRSDecimalStack(value))
.inline(true)
.build());

View File

@@ -77,10 +77,13 @@ public class StonedTrackerPlugin extends Plugin
@Inject
private ClientToolbar clientToolbar;
@Inject
public StonedTrackerConfig config;
@Inject
private Client client;
@Inject
private ItemManager itemManager;

View File

@@ -25,6 +25,7 @@
*/
package net.runelite.client.plugins.timetracking.farming;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Singleton;
import java.util.Collections;
import java.util.Comparator;
@@ -42,7 +43,7 @@ import net.runelite.client.plugins.timetracking.Tab;
class FarmingWorld
{
@Getter
private Map<Integer, FarmingRegion> regions = new HashMap<>();
private final ImmutableMap<Integer, FarmingRegion> regions;
@Getter
private Map<Tab, Set<FarmingPatch>> tabs = new HashMap<>();
@@ -54,58 +55,60 @@ class FarmingWorld
FarmingWorld()
{
ImmutableMap.Builder<Integer, FarmingRegion> regionBuilder = ImmutableMap.builderWithExpectedSize(40);
// Some of these patches get updated in multiple regions.
// It may be worth it to add a specialization for these patches
add(new FarmingRegion("Al Kharid", 13106,
add(regionBuilder, new FarmingRegion("Al Kharid", 13106,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.CACTUS)
));
add(new FarmingRegion("Ardougne", 10290,
add(regionBuilder, new FarmingRegion("Ardougne", 10290,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.BUSH)
));
add(new FarmingRegion("Ardougne", 10548,
add(regionBuilder, new FarmingRegion("Ardougne", 10548,
new FarmingPatch("North", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
new FarmingPatch("South", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
new FarmingPatch("", Varbits.FARMING_4774, PatchImplementation.HERB)
));
add(new FarmingRegion("Brimhaven", 11058,
add(regionBuilder, new FarmingRegion("Brimhaven", 11058,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.FRUIT_TREE),
new FarmingPatch("", Varbits.FARMING_4772, PatchImplementation.SPIRIT_TREE)
));
add(new FarmingRegion("Catherby", 11062,
add(regionBuilder, new FarmingRegion("Catherby", 11062,
new FarmingPatch("North", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
new FarmingPatch("South", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
new FarmingPatch("", Varbits.FARMING_4774, PatchImplementation.HERB)
));
add(new FarmingRegion("Catherby", 11317,
add(regionBuilder, new FarmingRegion("Catherby", 11317,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.FRUIT_TREE)
));
add(new FarmingRegion("Champions' Guild", 12596,
add(regionBuilder, new FarmingRegion("Champions' Guild", 12596,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.BUSH)
));
add(new FarmingRegion("Draynor Manor", 12340,
add(regionBuilder, new FarmingRegion("Draynor Manor", 12340,
new FarmingPatch("Belladonna", Varbits.FARMING_4771, PatchImplementation.BELLADONNA)
));
add(new FarmingRegion("Entrana", 11060,
add(regionBuilder, new FarmingRegion("Entrana", 11060,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.HOPS)
));
add(new FarmingRegion("Etceteria", 10300,
add(regionBuilder, new FarmingRegion("Etceteria", 10300,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.BUSH),
new FarmingPatch("", Varbits.FARMING_4772, PatchImplementation.SPIRIT_TREE)
));
add(new FarmingRegion("Falador", 11828,
add(regionBuilder, new FarmingRegion("Falador", 11828,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.TREE)
));
add(new FarmingRegion("Falador", 12083,
add(regionBuilder, new FarmingRegion("Falador", 12083,
new FarmingPatch("North West", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
new FarmingPatch("South East", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
@@ -119,36 +122,36 @@ class FarmingWorld
}
});
add(new FarmingRegion("Fossil Island", 14651,
add(regionBuilder, new FarmingRegion("Fossil Island", 14651,
new FarmingPatch("East", Varbits.FARMING_4771, PatchImplementation.HARDWOOD_TREE),
new FarmingPatch("Middle", Varbits.FARMING_4772, PatchImplementation.HARDWOOD_TREE),
new FarmingPatch("West", Varbits.FARMING_4773, PatchImplementation.HARDWOOD_TREE)
), 14907);
add(new FarmingRegion("Seaweed", 15008,
add(regionBuilder, new FarmingRegion("Seaweed", 15008,
new FarmingPatch("North", Varbits.FARMING_4771, PatchImplementation.SEAWEED),
new FarmingPatch("South", Varbits.FARMING_4772, PatchImplementation.SEAWEED)
));
add(new FarmingRegion("Gnome Stronghold", 9781,
add(regionBuilder, new FarmingRegion("Gnome Stronghold", 9781,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.TREE),
new FarmingPatch("", Varbits.FARMING_4772, PatchImplementation.FRUIT_TREE)
));
add(new FarmingRegion("Harmony", 15148,
add(regionBuilder, new FarmingRegion("Harmony", 15148,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
new FarmingPatch("", Varbits.FARMING_4772, PatchImplementation.HERB)
));
add(new FarmingRegion("Kourend", 6967,
add(regionBuilder, new FarmingRegion("Kourend", 6967,
new FarmingPatch("North East", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
new FarmingPatch("South West", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
new FarmingPatch("", Varbits.FARMING_4774, PatchImplementation.HERB)
));
add(new FarmingRegion("Kourend", 6711,
add(regionBuilder, new FarmingRegion("Kourend", 6711,
new FarmingPatch("", Varbits.FARMING_7904, PatchImplementation.SPIRIT_TREE)
));
add(new FarmingRegion("Kourend", 7223,
add(regionBuilder, new FarmingRegion("Kourend", 7223,
new FarmingPatch("East 1", Varbits.GRAPES_4953, PatchImplementation.GRAPES),
new FarmingPatch("East 2", Varbits.GRAPES_4954, PatchImplementation.GRAPES),
new FarmingPatch("East 3", Varbits.GRAPES_4955, PatchImplementation.GRAPES),
@@ -163,21 +166,21 @@ class FarmingWorld
new FarmingPatch("West 6", Varbits.GRAPES_4964, PatchImplementation.GRAPES)
));
add(new FarmingRegion("Lletya", 9265,
add(regionBuilder, new FarmingRegion("Lletya", 9265,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.FRUIT_TREE)
));
add(new FarmingRegion("Lumbridge", 12851,
add(regionBuilder, new FarmingRegion("Lumbridge", 12851,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.HOPS)
));
add(new FarmingRegion("Lumbridge", 12594,
add(regionBuilder, new FarmingRegion("Lumbridge", 12594,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.TREE)
));
add(new FarmingRegion("Morytania", 13622,
add(regionBuilder, new FarmingRegion("Morytania", 13622,
new FarmingPatch("Mushroom", Varbits.FARMING_4771, PatchImplementation.MUSHROOM)
));
add(new FarmingRegion("Morytania", 14391,
add(regionBuilder, new FarmingRegion("Morytania", 14391,
new FarmingPatch("North West", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
new FarmingPatch("South East", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
@@ -185,51 +188,51 @@ class FarmingWorld
));
add(new FarmingRegion("Port Sarim", 12082,
add(regionBuilder, new FarmingRegion("Port Sarim", 12082,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.SPIRIT_TREE)
));
add(new FarmingRegion("Rimmington", 11570,
add(regionBuilder, new FarmingRegion("Rimmington", 11570,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.BUSH)
), 11826);
add(new FarmingRegion("Seers' Village", 10551,
add(regionBuilder, new FarmingRegion("Seers' Village", 10551,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.HOPS)
));
add(new FarmingRegion("Tai Bwo Wannai", 11056,
add(regionBuilder, new FarmingRegion("Tai Bwo Wannai", 11056,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.CALQUAT)
));
add(new FarmingRegion("Taverley", 11573,
add(regionBuilder, new FarmingRegion("Taverley", 11573,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.TREE)
));
add(new FarmingRegion("Tree Gnome Village", 9777,
add(regionBuilder, new FarmingRegion("Tree Gnome Village", 9777,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.FRUIT_TREE)
));
add(new FarmingRegion("Troll Stronghold", 11321,
add(regionBuilder, new FarmingRegion("Troll Stronghold", 11321,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.HERB)
));
add(new FarmingRegion("Varrock", 12854,
add(regionBuilder, new FarmingRegion("Varrock", 12854,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.TREE)
), 12853);
add(new FarmingRegion("Yanille", 10288,
add(regionBuilder, new FarmingRegion("Yanille", 10288,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.HOPS)
));
add(new FarmingRegion("Weiss", 11325,
add(regionBuilder, new FarmingRegion("Weiss", 11325,
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.HERB)
));
add(new FarmingRegion("Farming Guild", 5021,
add(regionBuilder, new FarmingRegion("Farming Guild", 5021,
new FarmingPatch("Hespori", Varbits.FARMING_7908, PatchImplementation.HESPORI)
));
add(new FarmingRegion("Farming Guild", 4922,
add(regionBuilder, new FarmingRegion("Farming Guild", 4922,
new FarmingPatch("", Varbits.FARMING_7905, PatchImplementation.TREE),
new FarmingPatch("", Varbits.FARMING_4775, PatchImplementation.HERB),
new FarmingPatch("", Varbits.FARMING_4772, PatchImplementation.BUSH),
@@ -244,7 +247,7 @@ class FarmingWorld
new FarmingPatch("", Varbits.FARMING_7907, PatchImplementation.REDWOOD)
));
add(new FarmingRegion("Prifddinas", 13151,
add(regionBuilder, new FarmingRegion("Prifddinas", 13151,
new FarmingPatch("North", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
new FarmingPatch("South", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
@@ -252,7 +255,8 @@ class FarmingWorld
));
// Finalize
this.regions = Collections.unmodifiableMap(regions);
this.regions = regionBuilder.build();
Map<Tab, Set<FarmingPatch>> umtabs = new TreeMap<>();
for (Map.Entry<Tab, Set<FarmingPatch>> e : tabs.entrySet())
{
@@ -261,12 +265,12 @@ class FarmingWorld
this.tabs = Collections.unmodifiableMap(umtabs);
}
private void add(FarmingRegion r, int... extraRegions)
private void add(ImmutableMap.Builder<Integer, FarmingRegion> builder, FarmingRegion r, int... extraRegions)
{
regions.put(r.getRegionID(), r);
builder.put(r.getRegionID(), r);
for (int er : extraRegions)
{
regions.put(er, r);
builder.put(er, r);
}
for (FarmingPatch p : r.getPatches())
{

View File

@@ -25,8 +25,10 @@
*/
package net.runelite.client.plugins.worldmap;
import java.awt.image.BufferedImage;
import lombok.Getter;
import net.runelite.api.coords.WorldPoint;
import net.runelite.client.util.ImageUtil;
@Getter
enum TeleportLocationData
@@ -188,6 +190,24 @@ enum TeleportLocationData
private final String tooltip;
private final WorldPoint location;
private final String iconPath;
private BufferedImage image;
BufferedImage getImage()
{
if (image == null)
{
try
{
image = ImageUtil.getResourceStreamFromClass(WorldMapPlugin.class, this.getIconPath());
}
catch (RuntimeException e)
{
return WorldMapPlugin.BLANK_ICON;
}
}
return image;
}
TeleportLocationData(TeleportType type, String destination, int magicLevel, WorldPoint location, String iconPath)
{

View File

@@ -26,14 +26,12 @@
package net.runelite.client.plugins.worldmap;
import net.runelite.client.ui.overlay.worldmap.WorldMapPoint;
import net.runelite.client.util.ImageUtil;
class TeleportPoint extends WorldMapPoint
{
TeleportPoint(TeleportLocationData data)
{
super(data.getLocation(), WorldMapPlugin.BLANK_ICON);
super(data.getLocation(), data.getImage());
setTooltip(data.getTooltip());
setImage(ImageUtil.getResourceStreamFromClass(WorldMapPlugin.class, data.getIconPath()));
}
}

View File

@@ -29,6 +29,7 @@ import com.google.inject.Inject;
import com.google.inject.Provides;
import java.awt.image.BufferedImage;
import java.util.Arrays;
import java.util.concurrent.ScheduledExecutorService;
import net.runelite.api.Client;
import net.runelite.api.Experience;
import net.runelite.api.GameState;
@@ -127,6 +128,9 @@ public class WorldMapPlugin extends Plugin
@Inject
private EventBus eventBus;
@Inject
private ScheduledExecutorService executor;
private int agilityLevel = 0;
private int woodcuttingLevel = 0;
@@ -308,30 +312,33 @@ public class WorldMapPlugin extends Plugin
}
worldMapPointManager.removeIf(TeleportPoint.class::isInstance);
Arrays.stream(TeleportLocationData.values())
.filter(data ->
{
switch (data.getType())
// This next part gets 142 icons from disk, and does so on the EDT (at first run)
executor.submit(() ->
Arrays.stream(TeleportLocationData.values())
.filter(data ->
{
case NORMAL_MAGIC:
return this.normalTeleportIcon;
case ANCIENT_MAGICKS:
return this.ancientTeleportIcon;
case LUNAR_MAGIC:
return this.lunarTeleportIcon;
case ARCEUUS_MAGIC:
return this.arceuusTeleportIcon;
case JEWELLERY:
return this.jewelleryTeleportIcon;
case SCROLL:
return this.scrollTeleportIcon;
case OTHER:
return this.miscellaneousTeleportIcon;
default:
return false;
}
}).map(TeleportPoint::new)
.forEach(worldMapPointManager::add);
switch (data.getType())
{
case NORMAL_MAGIC:
return this.normalTeleportIcon;
case ANCIENT_MAGICKS:
return this.ancientTeleportIcon;
case LUNAR_MAGIC:
return this.lunarTeleportIcon;
case ARCEUUS_MAGIC:
return this.arceuusTeleportIcon;
case JEWELLERY:
return this.jewelleryTeleportIcon;
case SCROLL:
return this.scrollTeleportIcon;
case OTHER:
return this.miscellaneousTeleportIcon;
default:
return false;
}
}).map(TeleportPoint::new)
.forEach(worldMapPointManager::add)
);
}
private void updateQuestStartPointIcons()

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -340,8 +340,10 @@ public class ItemVariationMappingTest
}};
@Test
public void testMappedNames()
public void testMappedNames() throws Exception
{
ItemVariationMapping.load();
ITEMS_MAP.forEach((key, value) ->
{
assertEquals(value, (Integer) ItemVariationMapping.map(key));