client: Async-ify or improve data loading methods (#1782)
client: Async-ify or improve data loading methods
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -9,6 +9,7 @@ dependencies {
|
||||
compileOnly group: 'org.projectlombok', name: 'lombok', version: lombok
|
||||
|
||||
implementation group: 'com.google.code.gson', name: 'gson', version: gson
|
||||
implementation group: 'com.google.guava', name: 'guava', version: guava
|
||||
implementation group: 'com.squareup.okhttp3', name: 'okhttp', version: okhttp3
|
||||
implementation group: 'io.reactivex.rxjava2', name: 'rxjava', version: rxjava
|
||||
implementation group: 'org.apache.commons', name: 'commons-csv', version: apacheCommonsCsv
|
||||
|
||||
@@ -26,6 +26,10 @@ package net.runelite.http.api;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import net.runelite.http.api.item.ItemEquipmentStats;
|
||||
import net.runelite.http.api.item.ItemPrice;
|
||||
import net.runelite.http.api.item.ItemStats;
|
||||
import net.runelite.http.api.util.TypeAdapters;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.OkHttpClient;
|
||||
@@ -37,7 +41,6 @@ import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
@@ -52,26 +55,33 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class RuneLiteAPI
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(RuneLiteAPI.class);
|
||||
|
||||
public static final String RUNELITE_AUTH = "RUNELITE-AUTH";
|
||||
|
||||
public static final OkHttpClient CLIENT;
|
||||
public static final Gson GSON = new GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(ItemStats.class, TypeAdapters.ITEMSTATS)
|
||||
.registerTypeAdapter(ItemEquipmentStats.class, TypeAdapters.EQUIPMENTSTATS)
|
||||
.registerTypeAdapter(ItemPrice.class, TypeAdapters.ITEMPRICE)
|
||||
.create();
|
||||
|
||||
private static final String BASE = "https://api.runelite.net";
|
||||
private static final String WSBASE = "https://api.runelite.net/ws";
|
||||
private static final String STATICBASE = "https://static.runelite.net";
|
||||
|
||||
private static final String OPENOSRS_BASE = /*"https://api.openosrs.com*/ "https://api.runelitepl.us";
|
||||
private static final String OPENOSRS_SESSION = "https://session.openosrs.com";
|
||||
private static final String MAVEN_METADATA = "http://repo.runelite.net/net/runelite/runelite-parent/maven-metadata.xml";
|
||||
|
||||
private static final Properties properties = new Properties();
|
||||
private static String userAgent;
|
||||
|
||||
private static String version;
|
||||
private static String upstreamVersion;
|
||||
private static int rsVersion;
|
||||
|
||||
public static final String RUNELITE_AUTH = "RUNELITE-AUTH";
|
||||
public static final OkHttpClient CLIENT;
|
||||
public static final OkHttpClient RLP_CLIENT;
|
||||
public static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
|
||||
private static final Logger logger = LoggerFactory.getLogger(RuneLiteAPI.class);
|
||||
private static final String BASE = "https://api.runelite.net";
|
||||
private static final String OPENOSRS_BASE = /*"https://api.openosrs.com*/ "https://api.runelitepl.us";
|
||||
private static final String OPENOSRS_SESSION = "https://session.openosrs.com";
|
||||
private static final String WSBASE = "https://api.runelite.net/ws";
|
||||
private static final String STATICBASE = "https://static.runelite.net";
|
||||
private static final String MAVEN_METADATA =
|
||||
"http://repo.runelite.net/net/runelite/runelite-parent/maven-metadata.xml";
|
||||
private static final Properties properties = new Properties();
|
||||
private static String rlUserAgent;
|
||||
private static String openosrsUserAgent;
|
||||
|
||||
static
|
||||
{
|
||||
try
|
||||
@@ -80,11 +90,11 @@ public class RuneLiteAPI
|
||||
properties.load(in);
|
||||
|
||||
version = properties.getProperty("runelite.version");
|
||||
String rlpCommit = properties.getProperty("runelite.commit");
|
||||
String commit = properties.getProperty("runelite.commit");
|
||||
boolean dirty = Boolean.parseBoolean(properties.getProperty("runelite.dirty"));
|
||||
|
||||
openosrsUserAgent = "openosrs/" + version + "-" + rlpCommit + (dirty ? "+" : "");
|
||||
rlUserAgent = "openosrs/" + version;
|
||||
userAgent = "OpenOSRS/" + version + "-" + commit + (dirty ? "+" : "");
|
||||
|
||||
rsVersion = Integer.parseInt(properties.getProperty("rs.version"));
|
||||
|
||||
parseMavenVersion();
|
||||
@@ -101,8 +111,6 @@ public class RuneLiteAPI
|
||||
|
||||
CLIENT = new OkHttpClient.Builder()
|
||||
.pingInterval(30, TimeUnit.SECONDS)
|
||||
.connectTimeout(8655, TimeUnit.MILLISECONDS)
|
||||
.writeTimeout(8655, TimeUnit.MILLISECONDS)
|
||||
.addNetworkInterceptor(new Interceptor()
|
||||
{
|
||||
@Override
|
||||
@@ -110,25 +118,7 @@ public class RuneLiteAPI
|
||||
{
|
||||
Request userAgentRequest = chain.request()
|
||||
.newBuilder()
|
||||
.header("User-Agent", rlUserAgent)
|
||||
.build();
|
||||
return chain.proceed(userAgentRequest);
|
||||
}
|
||||
})
|
||||
.build();
|
||||
|
||||
RLP_CLIENT = new OkHttpClient.Builder()
|
||||
.pingInterval(30, TimeUnit.SECONDS)
|
||||
.writeTimeout(5655, TimeUnit.MILLISECONDS)
|
||||
.connectTimeout(2655, TimeUnit.MILLISECONDS)
|
||||
.addNetworkInterceptor(new Interceptor()
|
||||
{
|
||||
@Override
|
||||
public Response intercept(Chain chain) throws IOException
|
||||
{
|
||||
Request userAgentRequest = chain.request()
|
||||
.newBuilder()
|
||||
.header("User-Agent", openosrsUserAgent)
|
||||
.header("User-Agent", userAgent)
|
||||
.build();
|
||||
return chain.proceed(userAgentRequest);
|
||||
}
|
||||
@@ -136,7 +126,7 @@ public class RuneLiteAPI
|
||||
.build();
|
||||
}
|
||||
|
||||
public static HttpUrl getopenosrsSessionBase()
|
||||
public static HttpUrl getSessionBase()
|
||||
{
|
||||
return HttpUrl.parse(OPENOSRS_SESSION);
|
||||
}
|
||||
@@ -153,7 +143,7 @@ public class RuneLiteAPI
|
||||
return HttpUrl.parse(BASE + "/runelite-" + getVersion());
|
||||
}
|
||||
|
||||
public static HttpUrl getPlusApiBase()
|
||||
public static HttpUrl getOpenOSRSApiBase()
|
||||
{
|
||||
return HttpUrl.parse(OPENOSRS_BASE + "/http-service-" + getRlpVersion());
|
||||
}
|
||||
@@ -206,7 +196,7 @@ public class RuneLiteAPI
|
||||
byte[] chunk = new byte[4096];
|
||||
int bytesRead;
|
||||
URLConnection conn = toDownload.openConnection();
|
||||
conn.setRequestProperty("User-Agent", openosrsUserAgent);
|
||||
conn.setRequestProperty("User-Agent", userAgent);
|
||||
stream = conn.getInputStream();
|
||||
|
||||
while ((bytesRead = stream.read(chunk)) > 0)
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
package net.runelite.http.api.account;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
import io.reactivex.Observable;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
@@ -96,7 +97,7 @@ public class AccountClient
|
||||
}
|
||||
}
|
||||
|
||||
public boolean sessionCheck()
|
||||
public Observable<Boolean> sessionCheck()
|
||||
{
|
||||
HttpUrl url = RuneLiteAPI.getApiBase().newBuilder()
|
||||
.addPathSegment("account")
|
||||
@@ -105,6 +106,8 @@ public class AccountClient
|
||||
|
||||
logger.debug("Built URI: {}", url);
|
||||
|
||||
return Observable.fromCallable(() ->
|
||||
{
|
||||
Request request = new Request.Builder()
|
||||
.header(RuneLiteAPI.RUNELITE_AUTH, uuid.toString())
|
||||
.url(url)
|
||||
@@ -119,5 +122,6 @@ public class AccountClient
|
||||
logger.debug("Unable to verify session", ex);
|
||||
return true; // assume it is still valid if the server is unreachable
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ public class AnimationClient
|
||||
{
|
||||
String json = RuneLiteAPI.GSON.toJson(animationRequest);
|
||||
|
||||
HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder()
|
||||
HttpUrl url = RuneLiteAPI.getOpenOSRSApiBase().newBuilder()
|
||||
.addPathSegment("animation")
|
||||
.build();
|
||||
|
||||
@@ -65,7 +65,7 @@ public class AnimationClient
|
||||
|
||||
try
|
||||
{
|
||||
try (Response response = RuneLiteAPI.RLP_CLIENT.newCall(request).execute())
|
||||
try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute())
|
||||
{
|
||||
logger.debug("animation response " + response.code());
|
||||
}
|
||||
@@ -75,7 +75,7 @@ public class AnimationClient
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
RuneLiteAPI.RLP_CLIENT.newCall(request).enqueue(new Callback()
|
||||
RuneLiteAPI.CLIENT.newCall(request).enqueue(new Callback()
|
||||
{
|
||||
@Override
|
||||
public void onFailure(Call call, IOException e)
|
||||
@@ -103,7 +103,7 @@ public class AnimationClient
|
||||
|
||||
public List<AnimationKey> get() throws IOException
|
||||
{
|
||||
HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder()
|
||||
HttpUrl url = RuneLiteAPI.getOpenOSRSApiBase().newBuilder()
|
||||
.addPathSegment("animation")
|
||||
.build();
|
||||
|
||||
@@ -111,7 +111,7 @@ public class AnimationClient
|
||||
.url(url)
|
||||
.build();
|
||||
|
||||
try (Response response = RuneLiteAPI.RLP_CLIENT.newCall(request).execute())
|
||||
try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute())
|
||||
{
|
||||
InputStream in = response.body().byteStream();
|
||||
// CHECKSTYLE:OFF
|
||||
@@ -128,7 +128,7 @@ public class AnimationClient
|
||||
|
||||
public AnimationKey get(int npcid) throws IOException
|
||||
{
|
||||
HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder()
|
||||
HttpUrl url = RuneLiteAPI.getOpenOSRSApiBase().newBuilder()
|
||||
.addPathSegment("animation")
|
||||
.addPathSegment(Integer.toString(npcid))
|
||||
.build();
|
||||
@@ -137,7 +137,7 @@ public class AnimationClient
|
||||
.url(url)
|
||||
.build();
|
||||
|
||||
try (Response response = RuneLiteAPI.RLP_CLIENT.newCall(request).execute())
|
||||
try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute())
|
||||
{
|
||||
InputStream in = response.body().byteStream();
|
||||
return RuneLiteAPI.GSON.fromJson(new InputStreamReader(in), AnimationKey.class);
|
||||
|
||||
@@ -275,7 +275,7 @@ public class ChatClient
|
||||
throw new IOException("Layout " + layout + " is not valid!");
|
||||
}
|
||||
|
||||
HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder()
|
||||
HttpUrl url = RuneLiteAPI.getOpenOSRSApiBase().newBuilder()
|
||||
.addPathSegment("chat")
|
||||
.addPathSegment("layout")
|
||||
.addQueryParameter("name", username)
|
||||
@@ -287,7 +287,7 @@ public class ChatClient
|
||||
.url(url)
|
||||
.build();
|
||||
|
||||
try (Response response = RuneLiteAPI.RLP_CLIENT.newCall(request).execute())
|
||||
try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute())
|
||||
{
|
||||
return response.isSuccessful();
|
||||
}
|
||||
@@ -318,7 +318,7 @@ public class ChatClient
|
||||
|
||||
public String getLayout(String username) throws IOException
|
||||
{
|
||||
HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder()
|
||||
HttpUrl url = RuneLiteAPI.getOpenOSRSApiBase().newBuilder()
|
||||
.addPathSegment("chat")
|
||||
.addPathSegment("layout")
|
||||
.addQueryParameter("name", username)
|
||||
@@ -328,7 +328,7 @@ public class ChatClient
|
||||
.url(url)
|
||||
.build();
|
||||
|
||||
try (Response response = RuneLiteAPI.RLP_CLIENT.newCall(request).execute())
|
||||
try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute())
|
||||
{
|
||||
if (!response.isSuccessful())
|
||||
{
|
||||
@@ -353,7 +353,7 @@ public class ChatClient
|
||||
|
||||
public House[] getHosts(int world, String location) throws IOException
|
||||
{
|
||||
HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder()
|
||||
HttpUrl url = RuneLiteAPI.getOpenOSRSApiBase().newBuilder()
|
||||
.addPathSegment("chat")
|
||||
.addPathSegment("hosts")
|
||||
.addQueryParameter("world", Integer.toString(world))
|
||||
@@ -364,7 +364,7 @@ public class ChatClient
|
||||
.url(url)
|
||||
.build();
|
||||
|
||||
try (Response response = RuneLiteAPI.RLP_CLIENT.newCall(request).execute())
|
||||
try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute())
|
||||
{
|
||||
if (!response.isSuccessful())
|
||||
{
|
||||
@@ -411,7 +411,7 @@ public class ChatClient
|
||||
|
||||
public boolean submitHost(int world, String location, House house) throws IOException
|
||||
{
|
||||
HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder()
|
||||
HttpUrl url = RuneLiteAPI.getOpenOSRSApiBase().newBuilder()
|
||||
.addPathSegment("chat")
|
||||
.addPathSegment("hosts")
|
||||
.addQueryParameter("world", Integer.toString(world))
|
||||
@@ -431,7 +431,7 @@ public class ChatClient
|
||||
.url(url)
|
||||
.build();
|
||||
|
||||
try (Response response = RuneLiteAPI.RLP_CLIENT.newCall(request).execute())
|
||||
try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute())
|
||||
{
|
||||
return response.isSuccessful();
|
||||
}
|
||||
@@ -439,7 +439,7 @@ public class ChatClient
|
||||
|
||||
public boolean removeHost(int world, String location, House house) throws IOException
|
||||
{
|
||||
HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder()
|
||||
HttpUrl url = RuneLiteAPI.getOpenOSRSApiBase().newBuilder()
|
||||
.addPathSegment("chat")
|
||||
.addPathSegment("hosts")
|
||||
.addQueryParameter("world", Integer.toString(world))
|
||||
@@ -460,7 +460,7 @@ public class ChatClient
|
||||
.url(url)
|
||||
.build();
|
||||
|
||||
try (Response response = RuneLiteAPI.RLP_CLIENT.newCall(request).execute())
|
||||
try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute())
|
||||
{
|
||||
return response.isSuccessful();
|
||||
}
|
||||
|
||||
@@ -24,16 +24,15 @@
|
||||
*/
|
||||
package net.runelite.http.api.item;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import io.reactivex.Observable;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.inject.Inject;
|
||||
import net.runelite.http.api.RuneLiteAPI;
|
||||
@@ -190,7 +189,7 @@ public class ItemClient
|
||||
});
|
||||
}
|
||||
|
||||
public Observable<ItemPrice[]> getPrices()
|
||||
public Observable<ImmutableMap<Integer, ItemPrice>> getPrices()
|
||||
{
|
||||
HttpUrl.Builder urlBuilder = RuneLiteAPI.getApiBase().newBuilder()
|
||||
.addPathSegment("item")
|
||||
@@ -200,66 +199,64 @@ public class ItemClient
|
||||
|
||||
logger.debug("Built URI: {}", url);
|
||||
|
||||
|
||||
return Observable.defer(() ->
|
||||
return Observable.fromCallable(() ->
|
||||
{
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.build();
|
||||
|
||||
try (Response response = client.newCall(request).execute())
|
||||
try (JsonReader reader = new JsonReader(client.newCall(request).execute().body().charStream()))
|
||||
{
|
||||
if (!response.isSuccessful())
|
||||
ImmutableMap.Builder<Integer, ItemPrice> builder = ImmutableMap.builderWithExpectedSize(3666);
|
||||
reader.beginArray();
|
||||
|
||||
while (reader.hasNext())
|
||||
{
|
||||
logger.warn("Error looking up prices: {}", response);
|
||||
return Observable.just(null);
|
||||
ItemPrice price = RuneLiteAPI.GSON.fromJson(reader, ItemPrice.class);
|
||||
|
||||
builder.put(
|
||||
price.getId(),
|
||||
price
|
||||
);
|
||||
}
|
||||
|
||||
InputStream in = response.body().byteStream();
|
||||
return Observable.just(RuneLiteAPI.GSON.fromJson(new InputStreamReader(in), ItemPrice[].class));
|
||||
}
|
||||
catch (JsonParseException ex)
|
||||
{
|
||||
return Observable.error(ex);
|
||||
reader.endArray();
|
||||
return builder.build();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Observable<Map<Integer, ItemStats>> getStats()
|
||||
public Observable<ImmutableMap<Integer, ItemStats>> getStats()
|
||||
{
|
||||
HttpUrl.Builder urlBuilder = RuneLiteAPI.getStaticBase().newBuilder()
|
||||
HttpUrl url = RuneLiteAPI.getStaticBase()
|
||||
.newBuilder()
|
||||
.addPathSegment("item")
|
||||
// TODO: Change this to stats.min.json later after release is undeployed
|
||||
.addPathSegment("stats.ids.min.json");
|
||||
.addPathSegment("stats.ids.min.json")
|
||||
.build();
|
||||
|
||||
HttpUrl url = urlBuilder.build();
|
||||
|
||||
logger.debug("Built URI: {}", url);
|
||||
|
||||
|
||||
return Observable.defer(() ->
|
||||
logger.debug("Built URI {}", url);
|
||||
return Observable.fromCallable(() ->
|
||||
{
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.build();
|
||||
|
||||
try (Response response = client.newCall(request).execute())
|
||||
try (JsonReader reader = new JsonReader(client.newCall(request).execute().body().charStream()))
|
||||
{
|
||||
if (!response.isSuccessful())
|
||||
// This is the size the items are as I wrote this. the builder gets increased by 1 every time otherwise
|
||||
ImmutableMap.Builder<Integer, ItemStats> builder = ImmutableMap.builderWithExpectedSize(7498);
|
||||
reader.beginObject();
|
||||
|
||||
while (reader.hasNext())
|
||||
{
|
||||
logger.warn("Error looking up item stats: {}", response);
|
||||
return Observable.just(null);
|
||||
builder.put(
|
||||
Integer.parseInt(reader.nextName()),
|
||||
RuneLiteAPI.GSON.fromJson(reader, ItemStats.class)
|
||||
);
|
||||
}
|
||||
|
||||
InputStream in = response.body().byteStream();
|
||||
final Type typeToken = new TypeToken<Map<Integer, ItemStats>>()
|
||||
{
|
||||
}.getType();
|
||||
return Observable.just(RuneLiteAPI.GSON.fromJson(new InputStreamReader(in), typeToken));
|
||||
}
|
||||
catch (JsonParseException ex)
|
||||
{
|
||||
return Observable.error(ex);
|
||||
reader.endObject();
|
||||
return builder.build();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import lombok.Builder;
|
||||
import lombok.Value;
|
||||
|
||||
@Value
|
||||
@Builder
|
||||
@Builder(builderClassName = "Builder")
|
||||
public class ItemEquipmentStats
|
||||
{
|
||||
private int slot;
|
||||
|
||||
@@ -24,12 +24,15 @@
|
||||
*/
|
||||
package net.runelite.http.api.item;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Value;
|
||||
|
||||
@Value
|
||||
@AllArgsConstructor
|
||||
@Builder(builderClassName = "Builder")
|
||||
public class ItemStats
|
||||
{
|
||||
private String name;
|
||||
private boolean quest;
|
||||
private boolean equipable;
|
||||
private double weight;
|
||||
@@ -51,9 +54,9 @@ public class ItemStats
|
||||
{
|
||||
final ItemEquipmentStats equipment = this.equipment != null
|
||||
? this.equipment
|
||||
: new ItemEquipmentStats.ItemEquipmentStatsBuilder().build();
|
||||
: new ItemEquipmentStats.Builder().build();
|
||||
|
||||
newEquipment = new ItemEquipmentStats.ItemEquipmentStatsBuilder()
|
||||
newEquipment = new ItemEquipmentStats.Builder()
|
||||
.slot(equipment.getSlot())
|
||||
.astab(equipment.getAstab() - other.equipment.getAstab())
|
||||
.aslash(equipment.getAslash() - other.equipment.getAslash())
|
||||
@@ -77,7 +80,7 @@ public class ItemStats
|
||||
newEquipment = equipment;
|
||||
}
|
||||
|
||||
return new ItemStats(name, quest, equipable, newWeight, newEquipment);
|
||||
return new ItemStats(quest, equipable, newWeight, newEquipment);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Lucas <https://github.com/lucwousin>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.runelite.http.api.util;
|
||||
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import net.runelite.http.api.item.ItemEquipmentStats;
|
||||
import net.runelite.http.api.item.ItemPrice;
|
||||
import net.runelite.http.api.item.ItemStats;
|
||||
|
||||
/**
|
||||
* A class to put GSON TypeAdapters. These make just as fast the first time you
|
||||
* deserialize something as it would otherwise be after creating these itself.
|
||||
* Kinda funny actually, cause the first time probably matters the most, especially
|
||||
* for jsons that only get deserialized once.
|
||||
*/
|
||||
public class TypeAdapters
|
||||
{
|
||||
public static final TypeAdapter<ItemStats> ITEMSTATS = new TypeAdapter<ItemStats>()
|
||||
{
|
||||
@Deprecated
|
||||
@Override
|
||||
public void write(JsonWriter out, ItemStats value)
|
||||
{
|
||||
throw new UnsupportedOperationException("Not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStats read(JsonReader in) throws IOException
|
||||
{
|
||||
in.beginObject();
|
||||
|
||||
boolean quest = false;
|
||||
boolean equip = false;
|
||||
double weight = 0;
|
||||
ItemEquipmentStats stats = null;
|
||||
while (in.peek() != JsonToken.END_OBJECT)
|
||||
{
|
||||
switch (in.nextName())
|
||||
{
|
||||
case "quest":
|
||||
quest = in.nextBoolean();
|
||||
break;
|
||||
case "equipable":
|
||||
equip = in.nextBoolean();
|
||||
break;
|
||||
case "weight":
|
||||
weight = in.nextDouble();
|
||||
break;
|
||||
case "equipment":
|
||||
stats = EQUIPMENTSTATS.read(in);
|
||||
break;
|
||||
}
|
||||
}
|
||||
in.endObject();
|
||||
|
||||
return new ItemStats(quest, equip, weight, stats);
|
||||
}
|
||||
};
|
||||
|
||||
public static final TypeAdapter<ItemEquipmentStats> EQUIPMENTSTATS = new TypeAdapter<ItemEquipmentStats>()
|
||||
{
|
||||
@Deprecated
|
||||
@Override
|
||||
public void write(JsonWriter out, ItemEquipmentStats value)
|
||||
{
|
||||
throw new UnsupportedOperationException("Not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemEquipmentStats read(JsonReader in) throws IOException
|
||||
{
|
||||
ItemEquipmentStats.Builder builder = ItemEquipmentStats.builder();
|
||||
|
||||
in.beginObject();
|
||||
while (in.peek() != JsonToken.END_OBJECT)
|
||||
{
|
||||
String name = in.nextName();
|
||||
int val = in.nextInt();
|
||||
switch (name)
|
||||
{
|
||||
case "slot":
|
||||
builder.slot(val);
|
||||
break;
|
||||
case "astab":
|
||||
builder.astab(val);
|
||||
break;
|
||||
case "aslash":
|
||||
builder.aslash(val);
|
||||
break;
|
||||
case "acrush":
|
||||
builder.acrush(val);
|
||||
break;
|
||||
case "amagic":
|
||||
builder.amagic(val);
|
||||
break;
|
||||
case "arange":
|
||||
builder.arange(val);
|
||||
break;
|
||||
case "dstab":
|
||||
builder.dstab(val);
|
||||
break;
|
||||
case "dslash":
|
||||
builder.dslash(val);
|
||||
break;
|
||||
case "dcrush":
|
||||
builder.dcrush(val);
|
||||
break;
|
||||
case "dmagic":
|
||||
builder.dmagic(val);
|
||||
break;
|
||||
case "drange":
|
||||
builder.drange(val);
|
||||
break;
|
||||
case "str":
|
||||
builder.str(val);
|
||||
break;
|
||||
case "rstr":
|
||||
builder.rstr(val);
|
||||
break;
|
||||
case "mdmg":
|
||||
builder.mdmg(val);
|
||||
break;
|
||||
case "prayer":
|
||||
builder.prayer(val);
|
||||
break;
|
||||
case "aspeed":
|
||||
builder.aspeed(val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
in.endObject();
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
};
|
||||
|
||||
public static final TypeAdapter<ItemPrice> ITEMPRICE = new TypeAdapter<ItemPrice>()
|
||||
{
|
||||
@Override
|
||||
public void write(JsonWriter out, ItemPrice value)
|
||||
{
|
||||
throw new UnsupportedOperationException("Not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemPrice read(JsonReader in) throws IOException
|
||||
{
|
||||
/*
|
||||
* The ItemPrice json hosted by runelite is 'perfect'
|
||||
* by that I mean every field always exists, even with value 0.
|
||||
* This is why we can skip names and known-0 values
|
||||
*/
|
||||
ItemPrice ret = new ItemPrice();
|
||||
|
||||
in.beginObject();
|
||||
|
||||
// ID
|
||||
in.skipValue();
|
||||
ret.setId(in.nextInt());
|
||||
|
||||
// Name
|
||||
in.skipValue();
|
||||
ret.setName(in.nextString());
|
||||
|
||||
// Price
|
||||
in.skipValue();
|
||||
ret.setPrice(in.nextInt());
|
||||
|
||||
// Time
|
||||
in.skipValue();
|
||||
in.beginObject();
|
||||
|
||||
// Secs
|
||||
in.skipValue();
|
||||
ret.setTime(Instant.ofEpochSecond(in.nextLong()));
|
||||
|
||||
// Nanos
|
||||
in.skipValue();
|
||||
in.skipValue();
|
||||
|
||||
in.endObject();
|
||||
in.endObject();
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -51,7 +51,7 @@ public class XteaClient
|
||||
{
|
||||
String json = RuneLiteAPI.GSON.toJson(xteaRequest);
|
||||
|
||||
HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder()
|
||||
HttpUrl url = RuneLiteAPI.getOpenOSRSApiBase().newBuilder()
|
||||
.addPathSegment("xtea")
|
||||
.build();
|
||||
|
||||
@@ -63,7 +63,7 @@ public class XteaClient
|
||||
.url(url)
|
||||
.build();
|
||||
|
||||
RuneLiteAPI.RLP_CLIENT.newCall(request).enqueue(new Callback()
|
||||
RuneLiteAPI.CLIENT.newCall(request).enqueue(new Callback()
|
||||
{
|
||||
@Override
|
||||
public void onFailure(Call call, IOException e)
|
||||
@@ -91,7 +91,7 @@ public class XteaClient
|
||||
|
||||
public List<XteaKey> get() throws IOException
|
||||
{
|
||||
HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder()
|
||||
HttpUrl url = RuneLiteAPI.getOpenOSRSApiBase().newBuilder()
|
||||
.addPathSegment("xtea")
|
||||
.build();
|
||||
|
||||
@@ -116,7 +116,7 @@ public class XteaClient
|
||||
|
||||
public XteaKey get(int region) throws IOException
|
||||
{
|
||||
HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder()
|
||||
HttpUrl url = RuneLiteAPI.getOpenOSRSApiBase().newBuilder()
|
||||
.addPathSegment("xtea")
|
||||
.addPathSegment(Integer.toString(region))
|
||||
.build();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,6 +375,7 @@ public class RuneLite
|
||||
if (this.client != null)
|
||||
{
|
||||
scheduler.registerObject(modelOutlineRenderer.get());
|
||||
scheduler.registerObject(clientSessionManager);
|
||||
}
|
||||
|
||||
// Close the splash screen
|
||||
|
||||
@@ -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()
|
||||
return Observable.fromCallable(() ->
|
||||
{
|
||||
HttpUrl url = RuneLiteAPI.getopenosrsSessionBase().newBuilder()
|
||||
.build();
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.build();
|
||||
|
||||
RuneLiteAPI.CLIENT.newCall(request).enqueue(new Callback()
|
||||
try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute())
|
||||
{
|
||||
@Override
|
||||
public void onFailure(@NotNull Call call, @NotNull IOException e)
|
||||
{
|
||||
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();
|
||||
|
||||
return Observable.defer(() ->
|
||||
{
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.build();
|
||||
|
||||
RuneLiteAPI.CLIENT.newCall(request).enqueue(new Callback()
|
||||
{
|
||||
@Override
|
||||
public void onFailure(@NotNull Call call, @NotNull IOException e)
|
||||
{
|
||||
manager.error(e);
|
||||
}
|
||||
|
||||
@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();
|
||||
|
||||
return Observable.defer(() ->
|
||||
{
|
||||
Request request = new Request.Builder()
|
||||
.delete()
|
||||
.url(url)
|
||||
.build();
|
||||
|
||||
RuneLiteAPI.CLIENT.newCall(request).execute().close();
|
||||
return Observable.empty();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,14 +92,27 @@ public class SessionManager
|
||||
|
||||
// Check if session is still valid
|
||||
AccountClient accountClient = new AccountClient(session.getUuid());
|
||||
if (!accountClient.sessionCheck())
|
||||
accountClient.sessionCheck()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(b ->
|
||||
{
|
||||
if (!b)
|
||||
{
|
||||
log.debug("Loaded session {} is invalid", session.getUuid());
|
||||
return;
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
}.getType();
|
||||
try (JsonReader reader = new JsonReader(new InputStreamReader(NPCManager.class.getResourceAsStream("/npc_stats.json"), StandardCharsets.UTF_8)))
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,6 +312,8 @@ public class WorldMapPlugin extends Plugin
|
||||
}
|
||||
|
||||
worldMapPointManager.removeIf(TeleportPoint.class::isInstance);
|
||||
// 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 ->
|
||||
{
|
||||
@@ -331,7 +337,8 @@ public class WorldMapPlugin extends Plugin
|
||||
return false;
|
||||
}
|
||||
}).map(TeleportPoint::new)
|
||||
.forEach(worldMapPointManager::add);
|
||||
.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
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user