Merge remote-tracking branch 'runelite/master'
This commit is contained in:
@@ -27,9 +27,12 @@ package net.runelite.client;
|
||||
import ch.qos.logback.classic.Level;
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
import com.jagex.oldscape.pub.OAuthApi;
|
||||
import com.jagex.oldscape.pub.OtlTokenResponse;
|
||||
import com.openosrs.client.OpenOSRS;
|
||||
import com.openosrs.client.game.PlayerManager;
|
||||
import com.openosrs.client.ui.OpenOSRSSplashScreen;
|
||||
@@ -50,6 +53,7 @@ import java.security.SecureRandom;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
@@ -92,6 +96,8 @@ import net.runelite.http.api.RuneLiteAPI;
|
||||
import net.runelite.http.api.worlds.World;
|
||||
import net.runelite.http.api.worlds.WorldResult;
|
||||
import okhttp3.Cache;
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Callback;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
@@ -120,6 +126,9 @@ public class RuneLite
|
||||
@Inject
|
||||
private net.runelite.client.plugins.PluginManager pluginManager;
|
||||
|
||||
@Inject
|
||||
private OkHttpClient okHttpClient;
|
||||
|
||||
@Inject
|
||||
private ExternalPluginManager externalPluginManager;
|
||||
|
||||
@@ -290,8 +299,8 @@ public class RuneLite
|
||||
|
||||
try
|
||||
{
|
||||
final ClientLoader clientLoader = new ClientLoader(okHttpClient, options.valueOf(updateMode), (String) options.valueOf("jav_config"));
|
||||
final RuntimeConfigLoader runtimeConfigLoader = new RuntimeConfigLoader(okHttpClient);
|
||||
final ClientLoader clientLoader = new ClientLoader(okHttpClient, options.valueOf(updateMode), runtimeConfigLoader, (String) options.valueOf("jav_config"));
|
||||
|
||||
new Thread(() ->
|
||||
{
|
||||
@@ -330,6 +339,7 @@ public class RuneLite
|
||||
log.error("Failure during startup", e);
|
||||
SwingUtilities.invokeLater(() ->
|
||||
new FatalErrorDialog("OpenOSRS has encountered an unexpected error during startup.")
|
||||
.addHelpButtons()
|
||||
.open());
|
||||
}
|
||||
finally
|
||||
@@ -371,6 +381,11 @@ public class RuneLite
|
||||
}
|
||||
|
||||
applet.start();
|
||||
|
||||
if (applet instanceof OAuthApi)
|
||||
{
|
||||
setupJxAuth((OAuthApi) applet);
|
||||
}
|
||||
}
|
||||
|
||||
SplashScreen.stage(.57, null, "Loading configuration");
|
||||
@@ -661,4 +676,83 @@ public class RuneLite
|
||||
System.setProperty(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupJxAuth(OAuthApi oAuthApi)
|
||||
{
|
||||
String accessToken = System.getenv("JX_ACCESS_TOKEN");
|
||||
if (Strings.isNullOrEmpty(accessToken))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
log.info("Initializing OTL token requester with access token");
|
||||
oAuthApi.setOtlTokenRequester(url ->
|
||||
{
|
||||
CompletableFuture<OtlTokenResponse> f = new CompletableFuture<>();
|
||||
okHttpClient.newCall(new Request.Builder()
|
||||
.url(url)
|
||||
.header("Authorization", "Bearer " + accessToken)
|
||||
.get()
|
||||
.build())
|
||||
.enqueue(new Callback()
|
||||
{
|
||||
private void complete(boolean success, String token)
|
||||
{
|
||||
f.complete(new OtlTokenResponse()
|
||||
{
|
||||
@Override
|
||||
public boolean isSuccess()
|
||||
{
|
||||
return success;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToken()
|
||||
{
|
||||
return token;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call call, IOException e)
|
||||
{
|
||||
log.error("HTTP error while performing OTL request", e);
|
||||
complete(false, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Call call, Response response) throws IOException
|
||||
{
|
||||
if (response.code() != 200)
|
||||
{
|
||||
log.error("Non-OK response performing OTL request: {}", response.code());
|
||||
complete(false, null);
|
||||
response.close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.body() == null)
|
||||
{
|
||||
log.error("OK response with empty body from OTL request");
|
||||
complete(false, null);
|
||||
response.close();
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug("Successful OTL response");
|
||||
complete(true, response.body().string());
|
||||
response.close();
|
||||
}
|
||||
});
|
||||
return f;
|
||||
});
|
||||
}
|
||||
catch (LinkageError ex)
|
||||
{
|
||||
log.error("error setting up OTL requester", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ public class RuneLiteProperties
|
||||
private static final String PLUGINHUB_VERSION = "runelite.pluginhub.version";
|
||||
private static final String API_BASE = "runelite.api.base";
|
||||
private static final String RUNELITE_CONFIG = "runelite.config";
|
||||
private static final String OSRS_TWITTER_LINK = "runelite.osrstwitter.link";
|
||||
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
private static final Properties properties = new Properties();
|
||||
@@ -148,4 +149,9 @@ public class RuneLiteProperties
|
||||
{
|
||||
return properties.getProperty(RUNELITE_CONFIG);
|
||||
}
|
||||
|
||||
public static String getOSRSTwitterLink()
|
||||
{
|
||||
return properties.getProperty(OSRS_TWITTER_LINK);
|
||||
}
|
||||
}
|
||||
@@ -24,13 +24,46 @@
|
||||
*/
|
||||
package net.runelite.client;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import javax.swing.SwingUtilities;
|
||||
import lombok.Data;
|
||||
import net.runelite.client.ui.FatalErrorDialog;
|
||||
import net.runelite.client.util.LinkBrowser;
|
||||
|
||||
@Data
|
||||
public class RuntimeConfig
|
||||
{
|
||||
private Map<String, ?> props = Collections.emptyMap();
|
||||
private Map<String, String> sysProps = Collections.emptyMap();
|
||||
|
||||
private String outageMessage;
|
||||
private Map<String, String> outageLinks;
|
||||
|
||||
public boolean showOutageMessage()
|
||||
{
|
||||
if (Strings.isNullOrEmpty(getOutageMessage()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SwingUtilities.invokeLater(() ->
|
||||
{
|
||||
FatalErrorDialog fed = new FatalErrorDialog(getOutageMessage());
|
||||
if (getOutageLinks() != null)
|
||||
{
|
||||
for (Map.Entry<String, String> e : getOutageLinks().entrySet())
|
||||
{
|
||||
fed.addButton(e.getKey(), () -> LinkBrowser.browse(e.getValue()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fed.addButton("OSRS Twitter", () -> LinkBrowser.browse(RuneLiteProperties.getOSRSTwitterLink()));
|
||||
}
|
||||
fed.open();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,10 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.function.Supplier;
|
||||
import javax.annotation.Nullable;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.http.api.RuneLiteAPI;
|
||||
import okhttp3.Call;
|
||||
@@ -41,7 +44,7 @@ import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
@Slf4j
|
||||
class RuntimeConfigLoader implements Supplier<RuntimeConfig>
|
||||
public class RuntimeConfigLoader implements Supplier<RuntimeConfig>
|
||||
{
|
||||
private final OkHttpClient okHttpClient;
|
||||
private final CompletableFuture<RuntimeConfig> configFuture;
|
||||
@@ -66,6 +69,19 @@ class RuntimeConfigLoader implements Supplier<RuntimeConfig>
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public RuntimeConfig tryGet()
|
||||
{
|
||||
try
|
||||
{
|
||||
return configFuture.get(0, TimeUnit.SECONDS);
|
||||
}
|
||||
catch (InterruptedException | ExecutionException | TimeoutException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private CompletableFuture<RuntimeConfig> fetch()
|
||||
{
|
||||
CompletableFuture<RuntimeConfig> future = new CompletableFuture<>();
|
||||
|
||||
@@ -121,7 +121,7 @@ public class ClientThread implements Executor
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
log.warn("Exception in invoke", e);
|
||||
log.error("Exception in invoke", e);
|
||||
}
|
||||
if (remove)
|
||||
{
|
||||
|
||||
@@ -88,6 +88,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Player;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import net.runelite.api.events.AccountHashChanged;
|
||||
import net.runelite.api.events.PlayerChanged;
|
||||
import net.runelite.api.events.UsernameChanged;
|
||||
import net.runelite.api.events.WorldChanged;
|
||||
@@ -115,6 +116,7 @@ public class ConfigManager
|
||||
private static final String RSPROFILE_TYPE = "type";
|
||||
private static final String RSPROFILE_LOGIN_HASH = "loginHash";
|
||||
private static final String RSPROFILE_LOGIN_SALT = "loginSalt";
|
||||
private static final String RSPROFILE_ACCOUNT_HASH = "accountHash";
|
||||
|
||||
private static final DateFormat TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
|
||||
|
||||
@@ -544,17 +546,17 @@ public class ConfigManager
|
||||
displayName = p.getName();
|
||||
}
|
||||
|
||||
String username = client.getUsername();
|
||||
if (Strings.isNullOrEmpty(username))
|
||||
RuneScapeProfile prof = findRSProfile(getRSProfiles(), RuneScapeProfileType.getCurrent(client), displayName, true);
|
||||
if (prof == null)
|
||||
{
|
||||
log.warn("trying to create profile without a set username");
|
||||
log.warn("trying to create a profile while not logged in");
|
||||
return;
|
||||
}
|
||||
|
||||
RuneScapeProfile prof = findRSProfile(getRSProfiles(), username, RuneScapeProfileType.getCurrent(client), displayName, true);
|
||||
rsProfileKey = prof.getKey();
|
||||
this.rsProfileKey = rsProfileKey;
|
||||
|
||||
log.debug("RS profile changed to {}", rsProfileKey);
|
||||
eventBus.post(new RuneScapeProfileChanged());
|
||||
}
|
||||
setConfiguration(groupName, rsProfileKey, key, value);
|
||||
@@ -790,6 +792,10 @@ public class ConfigManager
|
||||
{
|
||||
return Integer.parseInt(str);
|
||||
}
|
||||
if (type == long.class || type == Long.class)
|
||||
{
|
||||
return Long.parseLong(str);
|
||||
}
|
||||
if (type == double.class || type == Double.class)
|
||||
{
|
||||
return Double.parseDouble(str);
|
||||
@@ -1129,10 +1135,12 @@ public class ConfigManager
|
||||
return profileKeys.stream()
|
||||
.map(key ->
|
||||
{
|
||||
Long accid = getConfiguration(RSPROFILE_GROUP, key, RSPROFILE_ACCOUNT_HASH, long.class);
|
||||
RuneScapeProfile prof = new RuneScapeProfile(
|
||||
getConfiguration(RSPROFILE_GROUP, key, RSPROFILE_DISPLAY_NAME),
|
||||
getConfiguration(RSPROFILE_GROUP, key, RSPROFILE_TYPE, RuneScapeProfileType.class),
|
||||
getConfiguration(RSPROFILE_GROUP, key, RSPROFILE_LOGIN_HASH, byte[].class),
|
||||
accid == null ? RuneScapeProfile.ACCOUNT_HASH_INVALID : accid,
|
||||
key
|
||||
);
|
||||
|
||||
@@ -1141,26 +1149,54 @@ public class ConfigManager
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private synchronized RuneScapeProfile findRSProfile(List<RuneScapeProfile> profiles, String username, RuneScapeProfileType type, String displayName, boolean create)
|
||||
private synchronized RuneScapeProfile findRSProfile(List<RuneScapeProfile> profiles, RuneScapeProfileType type, String displayName, boolean create)
|
||||
{
|
||||
byte[] salt = getConfiguration(RSPROFILE_GROUP, RSPROFILE_LOGIN_SALT, byte[].class);
|
||||
if (salt == null)
|
||||
String username = client.getUsername();
|
||||
long accountHash = client.getAccountHash();
|
||||
|
||||
if (accountHash == RuneScapeProfile.ACCOUNT_HASH_INVALID && username == null)
|
||||
{
|
||||
salt = new byte[15];
|
||||
new SecureRandom()
|
||||
.nextBytes(salt);
|
||||
log.info("creating new salt as there is no existing one {}", Base64.getUrlEncoder().encodeToString(salt));
|
||||
setConfiguration(RSPROFILE_GROUP, RSPROFILE_LOGIN_SALT, salt);
|
||||
return null;
|
||||
}
|
||||
|
||||
Hasher h = Hashing.sha512().newHasher();
|
||||
h.putBytes(salt);
|
||||
h.putString(username.toLowerCase(Locale.US), StandardCharsets.UTF_8);
|
||||
byte[] loginHash = h.hash().asBytes();
|
||||
final byte[] loginHash;
|
||||
byte[] salt = null;
|
||||
if (username != null)
|
||||
{
|
||||
salt = getConfiguration(RSPROFILE_GROUP, RSPROFILE_LOGIN_SALT, byte[].class);
|
||||
if (salt == null)
|
||||
{
|
||||
salt = new byte[15];
|
||||
new SecureRandom()
|
||||
.nextBytes(salt);
|
||||
log.info("creating new salt as there is no existing one {}", Base64.getUrlEncoder().encodeToString(salt));
|
||||
setConfiguration(RSPROFILE_GROUP, RSPROFILE_LOGIN_SALT, salt);
|
||||
}
|
||||
|
||||
Set<RuneScapeProfile> matches = profiles.stream()
|
||||
.filter(p -> Arrays.equals(p.getLoginHash(), loginHash) && p.getType() == type)
|
||||
Hasher h = Hashing.sha512().newHasher();
|
||||
h.putBytes(salt);
|
||||
h.putString(username.toLowerCase(Locale.US), StandardCharsets.UTF_8);
|
||||
loginHash = h.hash().asBytes();
|
||||
}
|
||||
else
|
||||
{
|
||||
loginHash = null;
|
||||
}
|
||||
|
||||
Set<RuneScapeProfile> matches = Collections.emptySet();
|
||||
if (accountHash != RuneScapeProfile.ACCOUNT_HASH_INVALID)
|
||||
{
|
||||
matches = profiles.stream()
|
||||
.filter(p -> p.getType() == type && accountHash == p.getAccountHash())
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
if (matches.isEmpty() && loginHash != null)
|
||||
{
|
||||
matches = profiles.stream()
|
||||
.filter(p -> p.getType() == type && Arrays.equals(loginHash, p.getLoginHash()))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
if (matches.size() > 1)
|
||||
{
|
||||
@@ -1169,7 +1205,21 @@ public class ConfigManager
|
||||
|
||||
if (matches.size() >= 1)
|
||||
{
|
||||
return matches.iterator().next();
|
||||
RuneScapeProfile profile = matches.iterator().next();
|
||||
if (profile.getAccountHash() == RuneScapeProfile.ACCOUNT_HASH_INVALID && accountHash != RuneScapeProfile.ACCOUNT_HASH_INVALID)
|
||||
{
|
||||
int upgrades = 0;
|
||||
for (RuneScapeProfile p : profiles)
|
||||
{
|
||||
if (p.getAccountHash() == RuneScapeProfile.ACCOUNT_HASH_INVALID && Arrays.equals(p.getLoginHash(), loginHash))
|
||||
{
|
||||
setConfiguration(RSPROFILE_GROUP, p.getKey(), RSPROFILE_ACCOUNT_HASH, accountHash);
|
||||
upgrades++;
|
||||
}
|
||||
}
|
||||
log.info("Attaching account id to {} profiles", upgrades);
|
||||
}
|
||||
return profile;
|
||||
}
|
||||
|
||||
if (!create)
|
||||
@@ -1179,22 +1229,41 @@ public class ConfigManager
|
||||
|
||||
// generate the new key deterministically so if you "create" the same profile on 2 different clients it doesn't duplicate
|
||||
Set<String> keys = profiles.stream().map(RuneScapeProfile::getKey).collect(Collectors.toSet());
|
||||
byte[] key = Arrays.copyOf(loginHash, 6);
|
||||
byte[] key = accountHash == RuneScapeProfile.ACCOUNT_HASH_INVALID
|
||||
? Arrays.copyOf(loginHash, 6)
|
||||
: new byte[]
|
||||
{
|
||||
(byte) accountHash,
|
||||
(byte) (accountHash >> 8),
|
||||
(byte) (accountHash >> 16),
|
||||
(byte) (accountHash >> 24),
|
||||
(byte) (accountHash >> 32),
|
||||
(byte) (accountHash >> 40),
|
||||
};
|
||||
key[0] += type.ordinal();
|
||||
for (int i = 0; i < 0xFF; i++, key[1]++)
|
||||
{
|
||||
String keyStr = RSPROFILE_GROUP + "." + Base64.getUrlEncoder().encodeToString(key);
|
||||
if (!keys.contains(keyStr))
|
||||
{
|
||||
log.info("creating new profile {} for user {} ({}) salt {}", keyStr, username, type, Base64.getUrlEncoder().encodeToString(salt));
|
||||
log.info("creating new profile {} for username {} account hash {} ({}) salt {}",
|
||||
keyStr, username, accountHash, type,
|
||||
salt == null ? "null" : Base64.getUrlEncoder().encodeToString(salt));
|
||||
|
||||
setConfiguration(RSPROFILE_GROUP, keyStr, RSPROFILE_LOGIN_HASH, loginHash);
|
||||
if (loginHash != null)
|
||||
{
|
||||
setConfiguration(RSPROFILE_GROUP, keyStr, RSPROFILE_LOGIN_HASH, loginHash);
|
||||
}
|
||||
if (accountHash != RuneScapeProfile.ACCOUNT_HASH_INVALID)
|
||||
{
|
||||
setConfiguration(RSPROFILE_GROUP, keyStr, RSPROFILE_ACCOUNT_HASH, accountHash);
|
||||
}
|
||||
setConfiguration(RSPROFILE_GROUP, keyStr, RSPROFILE_TYPE, type);
|
||||
if (displayName != null)
|
||||
{
|
||||
setConfiguration(RSPROFILE_GROUP, keyStr, RSPROFILE_DISPLAY_NAME, displayName);
|
||||
}
|
||||
return new RuneScapeProfile(displayName, type, loginHash, keyStr);
|
||||
return new RuneScapeProfile(displayName, type, loginHash, accountHash, keyStr);
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("too many rs profiles");
|
||||
@@ -1208,7 +1277,7 @@ public class ConfigManager
|
||||
}
|
||||
|
||||
List<RuneScapeProfile> profiles = getRSProfiles();
|
||||
RuneScapeProfile prof = findRSProfile(profiles, client.getUsername(), RuneScapeProfileType.getCurrent(client), null, false);
|
||||
RuneScapeProfile prof = findRSProfile(profiles, RuneScapeProfileType.getCurrent(client), null, false);
|
||||
|
||||
String key = prof == null ? null : prof.getKey();
|
||||
if (Objects.equals(key, rsProfileKey))
|
||||
@@ -1217,6 +1286,7 @@ public class ConfigManager
|
||||
}
|
||||
rsProfileKey = key;
|
||||
|
||||
log.debug("RS profile changed to {}", key);
|
||||
eventBus.post(new RuneScapeProfileChanged());
|
||||
}
|
||||
|
||||
@@ -1226,6 +1296,12 @@ public class ConfigManager
|
||||
updateRSProfile();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
private void onAccountHashChanged(AccountHashChanged ev)
|
||||
{
|
||||
updateRSProfile();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
private void onWorldChanged(WorldChanged ev)
|
||||
{
|
||||
|
||||
@@ -33,9 +33,12 @@ import lombok.Data;
|
||||
@Data
|
||||
public class RuneScapeProfile
|
||||
{
|
||||
public static final int ACCOUNT_HASH_INVALID = -1;
|
||||
|
||||
private final String displayName;
|
||||
private final RuneScapeProfileType type;
|
||||
private final byte[] loginHash;
|
||||
private final long accountHash;
|
||||
|
||||
/**
|
||||
* Profile key used to save configs for this profile to the config store. This will
|
||||
|
||||
@@ -110,10 +110,8 @@ public class ChatCommandsPlugin extends Plugin
|
||||
private static final String TEAM_SIZES = "(?:\\d+(?:\\+|-\\d+)? players|Solo)";
|
||||
private static final Pattern RAIDS_PB_PATTERN = Pattern.compile("<col=ef20ff>Congratulations - your raid is complete!</col><br>Team size: <col=ff0000>" + TEAM_SIZES + "</col> Duration:</col> <col=ff0000>(?<pb>[0-9:]+(?:\\.[0-9]+)?)</col> \\(new personal best\\)</col>");
|
||||
private static final Pattern RAIDS_DURATION_PATTERN = Pattern.compile("<col=ef20ff>Congratulations - your raid is complete!</col><br>Team size: <col=ff0000>" + TEAM_SIZES + "</col> Duration:</col> <col=ff0000>[0-9:.]+</col> Personal best: </col><col=ff0000>(?<pb>[0-9:]+(?:\\.[0-9]+)?)</col>");
|
||||
private static final Pattern TOB_WAVE_PB_PATTERN = Pattern.compile("Theatre of Blood wave completion time: <col=ff0000>(?<pb>[0-9:]+(?:\\.[0-9]+)?)</col> \\(new personal best\\)");
|
||||
private static final Pattern TOB_WAVE_DURATION_PATTERN = Pattern.compile("Theatre of Blood wave completion time: <col=ff0000>[0-9:.]+</col>\\. Personal best: (?<pb>[0-9:]+(?:\\.[0-9]+)?)");
|
||||
private static final Pattern KILL_DURATION_PATTERN = Pattern.compile("(?i)(?:(?:Fight |Lap |Challenge |Corrupted challenge )?duration:|Subdued in) <col=[0-9a-f]{6}>[0-9:.]+</col>\\. Personal best: (?:<col=ff0000>)?(?<pb>[0-9:]+(?:\\.[0-9]+)?)");
|
||||
private static final Pattern NEW_PB_PATTERN = Pattern.compile("(?i)(?:(?:Fight |Lap |Challenge |Corrupted challenge )?duration:|Subdued in) <col=[0-9a-f]{6}>(?<pb>[0-9:]+(?:\\.[0-9]+)?)</col> \\(new personal best\\)");
|
||||
private static final Pattern KILL_DURATION_PATTERN = Pattern.compile("(?i)(?:(?:Fight |Lap |Challenge |Corrupted challenge )?duration:|Subdued in|(?<!total )completion time:) <col=[0-9a-f]{6}>[0-9:.]+</col>\\. Personal best: (?:<col=ff0000>)?(?<pb>[0-9:]+(?:\\.[0-9]+)?)");
|
||||
private static final Pattern NEW_PB_PATTERN = Pattern.compile("(?i)(?:(?:Fight |Lap |Challenge |Corrupted challenge )?duration:|Subdued in|(?<!total )completion time:) <col=[0-9a-f]{6}>(?<pb>[0-9:]+(?:\\.[0-9]+)?)</col> \\(new personal best\\)");
|
||||
private static final Pattern DUEL_ARENA_WINS_PATTERN = Pattern.compile("You (were defeated|won)! You have(?: now)? won ([\\d,]+|one) duels?");
|
||||
private static final Pattern DUEL_ARENA_LOSSES_PATTERN = Pattern.compile("You have(?: now)? lost ([\\d,]+|one) duels?");
|
||||
private static final Pattern ADVENTURE_LOG_TITLE_PATTERN = Pattern.compile("The Exploits of (.+)");
|
||||
@@ -123,6 +121,7 @@ public class ChatCommandsPlugin extends Plugin
|
||||
private static final Pattern HS_KC_FLOOR_PATTERN = Pattern.compile("You have completed Floor (\\d) of the Hallowed Sepulchre! Total completions: <col=ff0000>([0-9,]+)</col>\\.");
|
||||
private static final Pattern HS_KC_GHC_PATTERN = Pattern.compile("You have opened the Grand Hallowed Coffin <col=ff0000>([0-9,]+)</col> times?!");
|
||||
private static final Pattern COLLECTION_LOG_ITEM_PATTERN = Pattern.compile("New item added to your collection log: (.*)");
|
||||
private static final Pattern GUARDIANS_OF_THE_RIFT_PATTERN = Pattern.compile("Amount of Rifts you have closed: <col=ff0000>([0-9,]+)</col>.");
|
||||
|
||||
private static final String TOTAL_LEVEL_COMMAND_STRING = "!total";
|
||||
private static final String PRICE_COMMAND_STRING = "!price";
|
||||
@@ -469,18 +468,6 @@ public class ChatCommandsPlugin extends Plugin
|
||||
matchPb(matcher);
|
||||
}
|
||||
|
||||
matcher = TOB_WAVE_PB_PATTERN.matcher(message);
|
||||
if (matcher.find())
|
||||
{
|
||||
matchPb(matcher);
|
||||
}
|
||||
|
||||
matcher = TOB_WAVE_DURATION_PATTERN.matcher(message);
|
||||
if (matcher.find())
|
||||
{
|
||||
matchPb(matcher);
|
||||
}
|
||||
|
||||
matcher = HS_PB_PATTERN.matcher(message);
|
||||
if (matcher.find())
|
||||
{
|
||||
@@ -538,6 +525,13 @@ public class ChatCommandsPlugin extends Plugin
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
matcher = GUARDIANS_OF_THE_RIFT_PATTERN.matcher(message);
|
||||
if (matcher.find())
|
||||
{
|
||||
int kc = Integer.parseInt(matcher.group(1));
|
||||
setKc("Guardians of the Rift", kc);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -1970,6 +1964,7 @@ public class ChatCommandsPlugin extends Plugin
|
||||
case "tob hm":
|
||||
case "tob hard mode":
|
||||
case "tob hard":
|
||||
case "hmt":
|
||||
return "Theatre of Blood Hard Mode";
|
||||
|
||||
// agility course
|
||||
@@ -2152,6 +2147,11 @@ public class ChatCommandsPlugin extends Plugin
|
||||
case "jad 6":
|
||||
return "TzHaar-Ket-Rak's Sixth Challenge";
|
||||
|
||||
// Guardians of the Rift
|
||||
case "gotr":
|
||||
case "runetodt":
|
||||
return "Guardians of the Rift";
|
||||
|
||||
default:
|
||||
return WordUtils.capitalize(boss);
|
||||
}
|
||||
|
||||
@@ -312,6 +312,7 @@ enum DiscordGameEventType
|
||||
MG_TZHAAR_FIGHT_PITS("Tzhaar Fight Pits", DiscordAreaType.MINIGAMES, 9552),
|
||||
MG_VARROCK_RAT_PITS("Varrock Rat Pits", DiscordAreaType.MINIGAMES, 11599),
|
||||
MG_VOLCANIC_MINE("Volcanic Mine", DiscordAreaType.MINIGAMES, 15263, 15262),
|
||||
MG_GUARDIANS_OF_THE_RIFT("Guardians of the Rift", DiscordAreaType.MINIGAMES, 14484),
|
||||
|
||||
// Raids
|
||||
RAIDS_CHAMBERS_OF_XERIC("Chambers of Xeric", DiscordAreaType.RAIDS, 12889, 13136, 13137, 13138, 13139, 13140, 13141, 13145, 13393, 13394, 13395, 13396, 13397, 13401),
|
||||
|
||||
@@ -185,7 +185,7 @@ public class GrandExchangePlugin extends Plugin
|
||||
private boolean wasFuzzySearch;
|
||||
|
||||
private String machineUuid;
|
||||
private String lastUsername;
|
||||
private long lastAccount;
|
||||
private int tradeSeq;
|
||||
|
||||
/**
|
||||
@@ -298,7 +298,8 @@ public class GrandExchangePlugin extends Plugin
|
||||
clientToolbar.removeNavigation(button);
|
||||
mouseManager.unregisterMouseListener(inputListener);
|
||||
keyManager.unregisterKeyListener(inputListener);
|
||||
lastUsername = machineUuid = null;
|
||||
machineUuid = null;
|
||||
lastAccount = -1L;
|
||||
tradeSeq = 0;
|
||||
}
|
||||
|
||||
@@ -893,13 +894,13 @@ public class GrandExchangePlugin extends Plugin
|
||||
|
||||
private String getMachineUuid()
|
||||
{
|
||||
String username = client.getUsername();
|
||||
if (lastUsername == username)
|
||||
long accountHash = client.getAccountHash();
|
||||
if (lastAccount == accountHash)
|
||||
{
|
||||
return machineUuid;
|
||||
}
|
||||
|
||||
lastUsername = username;
|
||||
lastAccount = accountHash;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -922,7 +923,7 @@ public class GrandExchangePlugin extends Plugin
|
||||
hasher.putBytes(hardwareAddress);
|
||||
}
|
||||
}
|
||||
hasher.putUnencodedChars(username);
|
||||
hasher.putLong(accountHash);
|
||||
machineUuid = hasher.hash().toString();
|
||||
tradeSeq = 0;
|
||||
return machineUuid;
|
||||
|
||||
@@ -263,6 +263,12 @@ public class LootTrackerPlugin extends Plugin
|
||||
private static final String TEMPOROSS_LOOT_STRING = "You found some loot: ";
|
||||
private static final int TEMPOROSS_REGION = 12588;
|
||||
|
||||
// Guardians of the Rift
|
||||
private static final String GUARDIANS_OF_THE_RIFT_EVENT = "Guardians of the Rift";
|
||||
private static final String INTRICATE_POUCH_EVENT = "Intricate pouch";
|
||||
private static final String GUARDIANS_OF_THE_RIFT_LOOT_STRING = "You found some loot: ";
|
||||
private static final int GUARDIANS_OF_THE_RIFT_REGION = 14484;
|
||||
|
||||
// Mahogany Homes
|
||||
private static final String MAHOGANY_CRATE_EVENT = "Supply crate (Mahogany Homes)";
|
||||
|
||||
@@ -480,6 +486,13 @@ public class LootTrackerPlugin extends Plugin
|
||||
|
||||
clientThread.invokeLater(() ->
|
||||
{
|
||||
// convertToLootTrackerRecord requires item compositions to be available to get the item name,
|
||||
// so it can't be run while the client is starting
|
||||
if (client.getGameState().getState() < GameState.LOGIN_SCREEN.getState())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// convertToLootTrackerRecord must be called on client thread
|
||||
List<LootTrackerRecord> records = loots.stream()
|
||||
.map(this::convertToLootTrackerRecord)
|
||||
@@ -489,6 +502,8 @@ public class LootTrackerPlugin extends Plugin
|
||||
panel.clearRecords();
|
||||
panel.addRecords(records);
|
||||
});
|
||||
|
||||
return true;
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -887,6 +902,12 @@ public class LootTrackerPlugin extends Plugin
|
||||
return;
|
||||
}
|
||||
|
||||
if (regionID == GUARDIANS_OF_THE_RIFT_REGION && message.startsWith(GUARDIANS_OF_THE_RIFT_LOOT_STRING))
|
||||
{
|
||||
onInvChange(collectInvItems(LootRecordType.EVENT, GUARDIANS_OF_THE_RIFT_EVENT, client.getBoostedSkillLevel(Skill.RUNECRAFT)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.equals(IMPLING_CATCH_MESSAGE))
|
||||
{
|
||||
onInvChange(collectInvItems(LootRecordType.EVENT, client.getLocalPlayer().getInteracting().getName()));
|
||||
@@ -977,6 +998,9 @@ public class LootTrackerPlugin extends Plugin
|
||||
case ItemID.CASKET_25590:
|
||||
onInvChange(collectInvAndGroundItems(LootRecordType.EVENT, TEMPOROSS_CASKET_EVENT));
|
||||
break;
|
||||
case ItemID.INTRICATE_POUCH:
|
||||
onInvChange(collectInvAndGroundItems(LootRecordType.EVENT, INTRICATE_POUCH_EVENT));
|
||||
break;
|
||||
case ItemID.SIMPLE_LOCKBOX_25647:
|
||||
case ItemID.ELABORATE_LOCKBOX_25649:
|
||||
case ItemID.ORNATE_LOCKBOX_25651:
|
||||
|
||||
@@ -826,4 +826,34 @@ public interface MenuEntrySwapperConfig extends Config
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "swapDepositPool",
|
||||
name = "Deposit Pool - Only Runes",
|
||||
description = "Swap Deposit with Deposit Runes on the Deposit Pool in Guardians of the Rift.",
|
||||
section = objectSection
|
||||
)
|
||||
default boolean swapDepositPool()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
enum UnchargedCellsMode
|
||||
{
|
||||
TAKE,
|
||||
TAKE_1,
|
||||
TAKE_5,
|
||||
TAKE_10
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "swapUnchargedCells",
|
||||
name = "Uncharged Cells",
|
||||
description = "Swap the take option for Uncharged Cells in Guardians of the Rift.",
|
||||
section = objectSection
|
||||
)
|
||||
default UnchargedCellsMode swapUnchargedCells()
|
||||
{
|
||||
return UnchargedCellsMode.TAKE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ import static net.runelite.client.plugins.menuentryswapper.MenuEntrySwapperConfi
|
||||
import static net.runelite.client.plugins.menuentryswapper.MenuEntrySwapperConfig.KaramjaGlovesMode;
|
||||
import static net.runelite.client.plugins.menuentryswapper.MenuEntrySwapperConfig.MorytaniaLegsMode;
|
||||
import static net.runelite.client.plugins.menuentryswapper.MenuEntrySwapperConfig.RadasBlessingMode;
|
||||
import static net.runelite.client.plugins.menuentryswapper.MenuEntrySwapperConfig.UnchargedCellsMode;
|
||||
import net.runelite.client.util.Text;
|
||||
|
||||
@PluginDescriptor(
|
||||
@@ -419,6 +420,12 @@ public class MenuEntrySwapperPlugin extends Plugin
|
||||
|
||||
swap("climb", "climb-up", () -> (shiftModifier() ? config.swapStairsShiftClick() : config.swapStairsLeftClick()) == MenuEntrySwapperConfig.StairsMode.CLIMB_UP);
|
||||
swap("climb", "climb-down", () -> (shiftModifier() ? config.swapStairsShiftClick() : config.swapStairsLeftClick()) == MenuEntrySwapperConfig.StairsMode.CLIMB_DOWN);
|
||||
|
||||
swap("deposit", "deposit-runes", config::swapDepositPool);
|
||||
|
||||
swap("take", "uncharged cells", "take-1", () -> config.swapUnchargedCells() == UnchargedCellsMode.TAKE_1);
|
||||
swap("take", "uncharged cells", "take-5", () -> config.swapUnchargedCells() == UnchargedCellsMode.TAKE_5);
|
||||
swap("take", "uncharged cells", "take-10", () -> config.swapUnchargedCells() == UnchargedCellsMode.TAKE_10);
|
||||
}
|
||||
|
||||
public Swap swap(String option, String swappedOption, Supplier<Boolean> enabled)
|
||||
|
||||
@@ -42,7 +42,7 @@ class NpcAggroAreaNotWorkingOverlay extends OverlayPanel
|
||||
this.plugin = plugin;
|
||||
|
||||
panelComponent.getChildren().add(LineComponent.builder()
|
||||
.left("Unaggressive NPC timers will start working when you teleport far away or enter a dungeon.")
|
||||
.left("Unaggressive NPC timers require calibration. Teleport far away or enter a dungeon, then run until this overlay disappears.")
|
||||
.build());
|
||||
|
||||
setPriority(OverlayPriority.LOW);
|
||||
@@ -53,7 +53,7 @@ class NpcAggroAreaNotWorkingOverlay extends OverlayPanel
|
||||
@Override
|
||||
public Dimension render(Graphics2D graphics)
|
||||
{
|
||||
if (!plugin.isActive() || plugin.getSafeCenters()[1] != null)
|
||||
if (plugin.getSafeCenters()[1] != null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Spudjb <https://github.com/spudjb>
|
||||
* Copyright (c) 2022 Adam <Adam@sigterm.info>
|
||||
* 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.client.plugins.questlist;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import javax.inject.Inject;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.ParamID;
|
||||
import net.runelite.api.ScriptID;
|
||||
import net.runelite.api.SoundEffectID;
|
||||
import net.runelite.api.SpriteID;
|
||||
import net.runelite.api.VarClientInt;
|
||||
import net.runelite.api.Varbits;
|
||||
import net.runelite.api.events.ScriptCallbackEvent;
|
||||
import net.runelite.api.events.ScriptPostFired;
|
||||
import net.runelite.api.events.VarClientIntChanged;
|
||||
import net.runelite.api.events.VarbitChanged;
|
||||
import net.runelite.api.widgets.JavaScriptCallback;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.api.widgets.WidgetInfo;
|
||||
import net.runelite.api.widgets.WidgetPositionMode;
|
||||
import net.runelite.api.widgets.WidgetType;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.game.chatbox.ChatboxPanelManager;
|
||||
import net.runelite.client.game.chatbox.ChatboxTextInput;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginDescriptor;
|
||||
|
||||
@PluginDescriptor(
|
||||
name = "Quest List",
|
||||
description = "Adds a search filter to the quest list"
|
||||
)
|
||||
public class QuestListPlugin extends Plugin
|
||||
{
|
||||
private static final String MENU_OPEN = "Open";
|
||||
private static final String MENU_CLOSE = "Close";
|
||||
private static final String MENU_SEARCH = "Search";
|
||||
|
||||
@Inject
|
||||
private Client client;
|
||||
|
||||
@Inject
|
||||
private ChatboxPanelManager chatboxPanelManager;
|
||||
|
||||
@Inject
|
||||
private ClientThread clientThread;
|
||||
|
||||
private ChatboxTextInput searchInput;
|
||||
private Widget questSearchButton;
|
||||
|
||||
@Override
|
||||
protected void startUp()
|
||||
{
|
||||
clientThread.invoke(this::addQuestButtons);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shutDown()
|
||||
{
|
||||
Widget header = client.getWidget(WidgetInfo.QUESTLIST_BOX);
|
||||
if (header != null)
|
||||
{
|
||||
header.deleteAllChildren();
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onScriptPostFired(ScriptPostFired event)
|
||||
{
|
||||
if (event.getScriptId() == ScriptID.QUESTLIST_INIT)
|
||||
{
|
||||
addQuestButtons();
|
||||
}
|
||||
}
|
||||
|
||||
private void addQuestButtons()
|
||||
{
|
||||
Widget header = client.getWidget(WidgetInfo.QUESTLIST_BOX);
|
||||
if (header != null)
|
||||
{
|
||||
header.deleteAllChildren();
|
||||
|
||||
questSearchButton = header.createChild(-1, WidgetType.GRAPHIC);
|
||||
questSearchButton.setSpriteId(SpriteID.GE_SEARCH);
|
||||
questSearchButton.setOriginalWidth(18);
|
||||
questSearchButton.setOriginalHeight(17);
|
||||
questSearchButton.setXPositionMode(WidgetPositionMode.ABSOLUTE_RIGHT);
|
||||
questSearchButton.setOriginalX(5);
|
||||
questSearchButton.setOriginalY(0);
|
||||
questSearchButton.setHasListener(true);
|
||||
questSearchButton.setAction(1, MENU_OPEN);
|
||||
questSearchButton.setOnOpListener((JavaScriptCallback) e -> openSearch());
|
||||
questSearchButton.setName(MENU_SEARCH);
|
||||
questSearchButton.revalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onVarbitChanged(VarbitChanged varbitChanged)
|
||||
{
|
||||
if (isChatboxOpen() && !isOnQuestTab())
|
||||
{
|
||||
chatboxPanelManager.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onVarClientIntChanged(VarClientIntChanged varClientIntChanged)
|
||||
{
|
||||
if (varClientIntChanged.getIndex() == VarClientInt.INVENTORY_TAB.getIndex())
|
||||
{
|
||||
if (isChatboxOpen() && !isOnQuestTab())
|
||||
{
|
||||
chatboxPanelManager.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onScriptCallbackEvent(ScriptCallbackEvent scriptCallbackEvent)
|
||||
{
|
||||
if (!"questFilter".equals(scriptCallbackEvent.getEventName()) || !isChatboxOpen())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final String filter = searchInput.getValue();
|
||||
if (Strings.isNullOrEmpty(filter))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final int[] intStack = client.getIntStack();
|
||||
final int intStackSize = client.getIntStackSize();
|
||||
|
||||
final int questStruct = intStack[intStackSize - 1];
|
||||
final String questName = client.getStructComposition(questStruct)
|
||||
.getStringValue(ParamID.QUEST_NAME);
|
||||
|
||||
intStack[intStackSize - 2] = questName.toLowerCase().contains(filter.toLowerCase()) ? 0 : 1;
|
||||
}
|
||||
|
||||
private boolean isOnQuestTab()
|
||||
{
|
||||
return client.getVar(Varbits.QUEST_TAB) == 0 && client.getVar(VarClientInt.INVENTORY_TAB) == 2;
|
||||
}
|
||||
|
||||
private boolean isChatboxOpen()
|
||||
{
|
||||
return searchInput != null && chatboxPanelManager.getCurrentInput() == searchInput;
|
||||
}
|
||||
|
||||
private void closeSearch()
|
||||
{
|
||||
chatboxPanelManager.close();
|
||||
redrawQuests();
|
||||
client.playSoundEffect(SoundEffectID.UI_BOOP);
|
||||
}
|
||||
|
||||
private void openSearch()
|
||||
{
|
||||
client.playSoundEffect(SoundEffectID.UI_BOOP);
|
||||
questSearchButton.setAction(1, MENU_CLOSE);
|
||||
questSearchButton.setOnOpListener((JavaScriptCallback) e -> closeSearch());
|
||||
searchInput = chatboxPanelManager.openTextInput("Search quest list")
|
||||
.onChanged(s -> redrawQuests())
|
||||
.onDone(s -> false)
|
||||
.onClose(() ->
|
||||
{
|
||||
redrawQuests();
|
||||
questSearchButton.setOnOpListener((JavaScriptCallback) e -> openSearch());
|
||||
questSearchButton.setAction(1, MENU_OPEN);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
private void redrawQuests()
|
||||
{
|
||||
Widget w = client.getWidget(WidgetInfo.QUESTLIST_CONTAINER);
|
||||
if (w == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Object[] onVarTransmitListener = w.getOnVarTransmitListener();
|
||||
if (onVarTransmitListener == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
clientThread.invokeLater(() ->
|
||||
client.runScript(onVarTransmitListener));
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,6 @@ import java.awt.image.BufferedImage;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import javax.inject.Inject;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Setter;
|
||||
@@ -123,7 +122,7 @@ public class XpTrackerPlugin extends Plugin
|
||||
@VisibleForTesting
|
||||
private XpPanel xpPanel;
|
||||
private XpWorldType lastWorldType;
|
||||
private String lastUsername;
|
||||
private long lastAccount;
|
||||
private long lastTickMillis = 0;
|
||||
private boolean fetchXp; // fetch lastXp for the online xp tracker
|
||||
private long lastXp = 0;
|
||||
@@ -162,6 +161,7 @@ public class XpTrackerPlugin extends Plugin
|
||||
// Initialize the tracker & last xp if already logged in
|
||||
fetchXp = true;
|
||||
initializeTracker = true;
|
||||
lastAccount = -1L;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -182,15 +182,15 @@ public class XpTrackerPlugin extends Plugin
|
||||
// Check that the username changed or the world type changed.
|
||||
XpWorldType type = worldSetToType(client.getWorldType());
|
||||
|
||||
if (!Objects.equals(client.getUsername(), lastUsername) || lastWorldType != type)
|
||||
if (client.getAccountHash() != lastAccount || lastWorldType != type)
|
||||
{
|
||||
// Reset
|
||||
log.debug("World change: {} -> {}, {} -> {}",
|
||||
lastUsername, client.getUsername(),
|
||||
lastAccount, client.getAccountHash(),
|
||||
firstNonNull(lastWorldType, "<unknown>"),
|
||||
firstNonNull(type, "<unknown>"));
|
||||
|
||||
lastUsername = client.getUsername();
|
||||
lastAccount = client.getAccountHash();
|
||||
// xp is not available until after login is finished, so fetch it on the next gametick
|
||||
fetchXp = true;
|
||||
lastWorldType = type;
|
||||
|
||||
@@ -29,7 +29,6 @@ package net.runelite.client.plugins.xpupdater;
|
||||
import com.google.inject.Provides;
|
||||
import java.io.IOException;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Objects;
|
||||
import javax.inject.Inject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
@@ -74,7 +73,7 @@ public class XpUpdaterPlugin extends Plugin
|
||||
@Inject
|
||||
private OkHttpClient okHttpClient;
|
||||
|
||||
private String lastUsername;
|
||||
private long lastAccount;
|
||||
private boolean fetchXp;
|
||||
private long lastXp;
|
||||
|
||||
@@ -88,6 +87,7 @@ public class XpUpdaterPlugin extends Plugin
|
||||
protected void startUp()
|
||||
{
|
||||
fetchXp = true;
|
||||
lastAccount = -1L;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
@@ -96,9 +96,9 @@ public class XpUpdaterPlugin extends Plugin
|
||||
GameState state = gameStateChanged.getGameState();
|
||||
if (state == GameState.LOGGED_IN)
|
||||
{
|
||||
if (!Objects.equals(client.getUsername(), lastUsername))
|
||||
if (lastAccount != client.getAccountHash())
|
||||
{
|
||||
lastUsername = client.getUsername();
|
||||
lastAccount = client.getAccountHash();
|
||||
fetchXp = true;
|
||||
}
|
||||
}
|
||||
@@ -114,8 +114,8 @@ public class XpUpdaterPlugin extends Plugin
|
||||
// Don't submit update unless xp threshold is reached
|
||||
if (Math.abs(totalXp - lastXp) > XP_THRESHOLD)
|
||||
{
|
||||
log.debug("Submitting update for {}", local.getName());
|
||||
update(local.getName());
|
||||
log.debug("Submitting update for {} accountHash {}", local.getName(), lastAccount);
|
||||
update(lastAccount, local.getName());
|
||||
lastXp = totalXp;
|
||||
}
|
||||
}
|
||||
@@ -131,12 +131,12 @@ public class XpUpdaterPlugin extends Plugin
|
||||
}
|
||||
}
|
||||
|
||||
private void update(String username)
|
||||
private void update(long accountHash, String username)
|
||||
{
|
||||
EnumSet<WorldType> worldTypes = client.getWorldType();
|
||||
username = username.replace(" ", "_");
|
||||
updateCml(username, worldTypes);
|
||||
updateTempleosrs(username, worldTypes);
|
||||
updateTempleosrs(accountHash, username, worldTypes);
|
||||
updateWom(username, worldTypes);
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ public class XpUpdaterPlugin extends Plugin
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTempleosrs(String username, EnumSet<WorldType> worldTypes)
|
||||
private void updateTempleosrs(long accountHash, String username, EnumSet<WorldType> worldTypes)
|
||||
{
|
||||
if (config.templeosrs()
|
||||
&& !worldTypes.contains(WorldType.SEASONAL)
|
||||
@@ -178,6 +178,7 @@ public class XpUpdaterPlugin extends Plugin
|
||||
.addPathSegment("php")
|
||||
.addPathSegment("add_datapoint.php")
|
||||
.addQueryParameter("player", username)
|
||||
.addQueryParameter("accountHash", Long.toString(accountHash))
|
||||
.build();
|
||||
|
||||
Request request = new Request.Builder()
|
||||
|
||||
@@ -60,6 +60,8 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.client.RuneLite;
|
||||
import net.runelite.client.RuneLiteProperties;
|
||||
import net.runelite.client.RuntimeConfig;
|
||||
import net.runelite.client.RuntimeConfigLoader;
|
||||
import static net.runelite.client.rs.ClientUpdateCheckMode.AUTO;
|
||||
import static net.runelite.client.rs.ClientUpdateCheckMode.NONE;
|
||||
import static net.runelite.client.rs.ClientUpdateCheckMode.VANILLA;
|
||||
@@ -74,7 +76,7 @@ import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
@Slf4j
|
||||
@SuppressWarnings("deprecation")
|
||||
@SuppressWarnings({"deprecation", "removal"})
|
||||
public class ClientLoader implements Supplier<Applet>
|
||||
{
|
||||
private static final String INJECTED_CLIENT_NAME = "/injected-client.oprs";
|
||||
@@ -87,16 +89,18 @@ public class ClientLoader implements Supplier<Applet>
|
||||
private final ClientConfigLoader clientConfigLoader;
|
||||
private ClientUpdateCheckMode updateCheckMode;
|
||||
private final WorldSupplier worldSupplier;
|
||||
private final RuntimeConfigLoader runtimeConfigLoader;
|
||||
private final String javConfigUrl;
|
||||
|
||||
private Object client;
|
||||
|
||||
public ClientLoader(OkHttpClient okHttpClient, ClientUpdateCheckMode updateCheckMode, String javConfigUrl)
|
||||
public ClientLoader(OkHttpClient okHttpClient, ClientUpdateCheckMode updateCheckMode, RuntimeConfigLoader runtimeConfigLoader, String javConfigUrl)
|
||||
{
|
||||
this.okHttpClient = okHttpClient;
|
||||
this.clientConfigLoader = new ClientConfigLoader(okHttpClient);
|
||||
this.updateCheckMode = updateCheckMode;
|
||||
this.worldSupplier = new WorldSupplier(okHttpClient);
|
||||
this.runtimeConfigLoader = runtimeConfigLoader;
|
||||
this.javConfigUrl = javConfigUrl;
|
||||
}
|
||||
|
||||
@@ -183,12 +187,19 @@ public class ClientLoader implements Supplier<Applet>
|
||||
|
||||
return rs;
|
||||
}
|
||||
catch (OutageException e)
|
||||
{
|
||||
return e;
|
||||
}
|
||||
catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException
|
||||
| VerificationException | SecurityException e)
|
||||
{
|
||||
log.error("Error loading RS!", e);
|
||||
|
||||
SwingUtilities.invokeLater(() -> FatalErrorDialog.showNetErrorWindow("loading the client", e));
|
||||
if (!checkOutages())
|
||||
{
|
||||
SwingUtilities.invokeLater(() -> FatalErrorDialog.showNetErrorWindow("loading the client", e));
|
||||
}
|
||||
return e;
|
||||
}
|
||||
}
|
||||
@@ -213,6 +224,10 @@ public class ClientLoader implements Supplier<Applet>
|
||||
catch (IOException e)
|
||||
{
|
||||
log.info("Failed to get jav_config from host \"{}\" ({})", url.host(), e.getMessage());
|
||||
if (checkOutages())
|
||||
{
|
||||
throw new OutageException(e);
|
||||
}
|
||||
|
||||
if (!javConfigUrl.equals(RuneLiteProperties.getJavConfig()))
|
||||
{
|
||||
@@ -301,6 +316,11 @@ public class ClientLoader implements Supplier<Applet>
|
||||
}
|
||||
vanilla.position(0);
|
||||
|
||||
if (!vanillaCacheIsInvalid && "false".equals(System.getProperty("runelite.updateVanilla")))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Start downloading the vanilla client
|
||||
HttpUrl url;
|
||||
if (config.isFallback())
|
||||
@@ -412,6 +432,10 @@ public class ClientLoader implements Supplier<Applet>
|
||||
catch (IOException e)
|
||||
{
|
||||
log.warn("Failed to download gamepack from \"{}\"", url, e);
|
||||
if (checkOutages())
|
||||
{
|
||||
throw new OutageException(e);
|
||||
}
|
||||
|
||||
// With fallback config do 1 attempt (there are no additional urls to try)
|
||||
if (!javConfigUrl.equals(RuneLiteProperties.getJavConfig()) || config.isFallback() || attempt >= NUM_ATTEMPTS)
|
||||
@@ -438,6 +462,7 @@ public class ClientLoader implements Supplier<Applet>
|
||||
SwingUtilities.invokeLater(() ->
|
||||
new FatalErrorDialog("The client-patch is missing from the classpath. If you are building " +
|
||||
"the client you need to re-run maven")
|
||||
.addHelpButtons()
|
||||
.addBuildingGuide()
|
||||
.open());
|
||||
throw new NullPointerException();
|
||||
@@ -605,7 +630,7 @@ public class ClientLoader implements Supplier<Applet>
|
||||
Class<?> clientClass = classLoader.loadClass(initialClass);
|
||||
|
||||
Applet rs = (Applet) clientClass.newInstance();
|
||||
rs.setStub(new RSAppletStub(config));
|
||||
rs.setStub(new RSAppletStub(config, runtimeConfigLoader));
|
||||
|
||||
if (rs instanceof Client)
|
||||
{
|
||||
@@ -658,4 +683,22 @@ public class ClientLoader implements Supplier<Applet>
|
||||
verifyJarEntry(je, chains);
|
||||
}
|
||||
}
|
||||
|
||||
private static class OutageException extends RuntimeException
|
||||
{
|
||||
private OutageException(Throwable cause)
|
||||
{
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkOutages()
|
||||
{
|
||||
RuntimeConfig rtc = runtimeConfigLoader.tryGet();
|
||||
if (rtc != null)
|
||||
{
|
||||
return rtc.showOutageMessage();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,16 +25,28 @@
|
||||
*/
|
||||
package net.runelite.client.rs;
|
||||
|
||||
import java.applet.Applet;
|
||||
import java.applet.AppletContext;
|
||||
import java.applet.AppletStub;
|
||||
import java.applet.AudioClip;
|
||||
import java.awt.Image;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import javax.swing.SwingUtilities;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.runelite.client.RuntimeConfig;
|
||||
import net.runelite.client.RuntimeConfigLoader;
|
||||
import net.runelite.client.ui.FatalErrorDialog;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
class RSAppletStub implements AppletStub
|
||||
{
|
||||
private final RSConfig config;
|
||||
private final RuntimeConfigLoader runtimeConfigLoader;
|
||||
|
||||
@Override
|
||||
public boolean isActive()
|
||||
@@ -70,7 +82,89 @@ class RSAppletStub implements AppletStub
|
||||
@Override
|
||||
public AppletContext getAppletContext()
|
||||
{
|
||||
return null;
|
||||
return new AppletContext()
|
||||
{
|
||||
@Override
|
||||
public AudioClip getAudioClip(URL url)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getImage(URL url)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Applet getApplet(String name)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<Applet> getApplets()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showDocument(URL url)
|
||||
{
|
||||
if (url.getPath().startsWith("/error_game_"))
|
||||
{
|
||||
try
|
||||
{
|
||||
RuntimeConfig rtc = runtimeConfigLoader.get();
|
||||
if (rtc.showOutageMessage())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
}
|
||||
|
||||
String code = url.getPath()
|
||||
.replace("/", "")
|
||||
.replace(".ws", "");
|
||||
|
||||
SwingUtilities.invokeLater(() ->
|
||||
new FatalErrorDialog("OldSchool RuneScape has crashed with the message: " + code + "")
|
||||
.setTitle("OpenOSRS", "OldSchool RuneScape has crashed")
|
||||
.addHelpButtons()
|
||||
.open());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showDocument(URL url, String target)
|
||||
{
|
||||
showDocument(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showStatus(String status)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStream(String key, InputStream stream) throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getStream(String key)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<String> getStreamKeys()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -61,6 +61,7 @@ public class FatalErrorDialog extends JDialog
|
||||
|
||||
private final JPanel rightColumn = new JPanel();
|
||||
private final Font font = new Font(Font.DIALOG, Font.PLAIN, 12);
|
||||
private final JLabel title;
|
||||
|
||||
public FatalErrorDialog(String message)
|
||||
{
|
||||
@@ -114,7 +115,7 @@ public class FatalErrorDialog extends JDialog
|
||||
leftPane.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
leftPane.setLayout(new BorderLayout());
|
||||
|
||||
JLabel title = new JLabel("There was a fatal error starting OpenOSRS");
|
||||
title = new JLabel("There was a fatal error starting OpenOSRS");
|
||||
title.setForeground(Color.WHITE);
|
||||
title.setFont(font.deriveFont(16.f));
|
||||
title.setBorder(new EmptyBorder(10, 10, 10, 10));
|
||||
@@ -137,13 +138,6 @@ public class FatalErrorDialog extends JDialog
|
||||
rightColumn.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
rightColumn.setMaximumSize(new Dimension(200, Integer.MAX_VALUE));
|
||||
|
||||
addButton("Open logs folder", () ->
|
||||
{
|
||||
LinkBrowser.open(RuneLite.LOGS_DIR.toString());
|
||||
});
|
||||
addButton("Get help on Discord", () -> LinkBrowser.browse(RuneLiteProperties.getDiscordInvite()));
|
||||
addButton("Troubleshooting steps", () -> LinkBrowser.browse(RuneLiteProperties.getTroubleshootingLink()));
|
||||
|
||||
pane.add(rightColumn, BorderLayout.EAST);
|
||||
}
|
||||
|
||||
@@ -193,6 +187,20 @@ public class FatalErrorDialog extends JDialog
|
||||
return this;
|
||||
}
|
||||
|
||||
public FatalErrorDialog setTitle(String windowTitle, String header)
|
||||
{
|
||||
super.setTitle(windowTitle);
|
||||
title.setText(header);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FatalErrorDialog addHelpButtons()
|
||||
{
|
||||
return addButton("Open logs folder", () -> LinkBrowser.open(RuneLite.LOGS_DIR.toString()))
|
||||
.addButton("Get help on Discord", () -> LinkBrowser.browse(RuneLiteProperties.getDiscordInvite()))
|
||||
.addButton("Troubleshooting steps", () -> LinkBrowser.browse(RuneLiteProperties.getTroubleshootingLink()));
|
||||
}
|
||||
|
||||
public FatalErrorDialog addBuildingGuide()
|
||||
{
|
||||
return addButton("Building guide", () -> LinkBrowser.browse(RuneLiteProperties.getBuildingLink()));
|
||||
@@ -205,6 +213,7 @@ public class FatalErrorDialog extends JDialog
|
||||
new FatalErrorDialog("OpenOSRS was unable to verify the security of its connection to the internet while " +
|
||||
action + ". You may have a misbehaving antivirus, internet service provider, a proxy, or an incomplete" +
|
||||
" java installation.")
|
||||
.addHelpButtons()
|
||||
.open();
|
||||
return;
|
||||
}
|
||||
@@ -213,6 +222,7 @@ public class FatalErrorDialog extends JDialog
|
||||
{
|
||||
new FatalErrorDialog("OpenOSRS is unable to connect to a required server while " + action + ". " +
|
||||
"Please check your internet connection")
|
||||
.addHelpButtons()
|
||||
.open();
|
||||
return;
|
||||
}
|
||||
@@ -222,11 +232,14 @@ public class FatalErrorDialog extends JDialog
|
||||
new FatalErrorDialog("OpenOSRS is unable to resolve the address of a required server while " + action + ". " +
|
||||
"Your DNS resolver may be misconfigured, pointing to an inaccurate resolver, or your internet connection may " +
|
||||
"be down. ")
|
||||
.addHelpButtons()
|
||||
.addButton("Change your DNS resolver", () -> LinkBrowser.browse(RuneLiteProperties.getDNSChangeLink()))
|
||||
.open();
|
||||
return;
|
||||
}
|
||||
|
||||
new FatalErrorDialog("OpenOSRS encountered a fatal error while " + action + ".").open();
|
||||
new FatalErrorDialog("RuneLite encountered a fatal error while " + action + ".")
|
||||
.addHelpButtons()
|
||||
.open();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,4 +18,5 @@ runelite.api.base=https://api.runelite.net/runelite-@project.version@
|
||||
runelite.session=https://session.openosrs.dev
|
||||
runelite.static.base=https://static.runelite.net
|
||||
runelite.ws=https://api.runelite.net/ws
|
||||
runelite.config=https://static.runelite.net/config.json
|
||||
runelite.config=https://static.runelite.net/config.json
|
||||
runelite.osrstwitter.link=https://twitter.com/OldSchoolRS
|
||||
1
runelite-client/src/main/scripts/QuestFilter.hash
Normal file
1
runelite-client/src/main/scripts/QuestFilter.hash
Normal file
@@ -0,0 +1 @@
|
||||
3FA5FFC8DB18A42971CED41A9BC7CEA407A0EC98061D56B2822F66CD910E4BAF
|
||||
129
runelite-client/src/main/scripts/QuestFilter.rs2asm
Normal file
129
runelite-client/src/main/scripts/QuestFilter.rs2asm
Normal file
@@ -0,0 +1,129 @@
|
||||
.id 3238
|
||||
.int_stack_count 4
|
||||
.string_stack_count 0
|
||||
.int_var_count 5 ; +1 for filter result
|
||||
.string_var_count 0
|
||||
iconst -1 ; set to 1 to hide, 0 to show
|
||||
iload 0 ; quest struct
|
||||
sconst "questFilter"
|
||||
runelite_callback
|
||||
pop_int ; quest struct
|
||||
istore 4 ; save result
|
||||
; compare with -1
|
||||
iload 4 ; load result
|
||||
iconst -1
|
||||
if_icmpeq continue
|
||||
; return value
|
||||
iload 4
|
||||
return
|
||||
|
||||
continue:
|
||||
iload 0
|
||||
iconst 611
|
||||
struct_param
|
||||
iconst 1
|
||||
if_icmpeq LABEL6
|
||||
jump LABEL12
|
||||
LABEL6:
|
||||
invoke 4025
|
||||
iconst 1
|
||||
if_icmpeq LABEL10
|
||||
jump LABEL12
|
||||
LABEL10:
|
||||
iconst 1
|
||||
return
|
||||
LABEL12:
|
||||
iload 0
|
||||
iconst 611
|
||||
struct_param
|
||||
iconst 0
|
||||
if_icmpeq LABEL18
|
||||
jump LABEL24
|
||||
LABEL18:
|
||||
get_varbit 13774
|
||||
iconst 1
|
||||
if_icmpeq LABEL22
|
||||
jump LABEL24
|
||||
LABEL22:
|
||||
iconst 1
|
||||
return
|
||||
LABEL24:
|
||||
iload 1
|
||||
iconst 0
|
||||
if_icmpeq LABEL28
|
||||
jump LABEL34
|
||||
LABEL28:
|
||||
get_varbit 13775
|
||||
iconst 1
|
||||
if_icmpeq LABEL32
|
||||
jump LABEL34
|
||||
LABEL32:
|
||||
iconst 1
|
||||
return
|
||||
LABEL34:
|
||||
iload 1
|
||||
iconst 1
|
||||
if_icmpeq LABEL38
|
||||
jump LABEL44
|
||||
LABEL38:
|
||||
get_varbit 13776
|
||||
iconst 1
|
||||
if_icmpeq LABEL42
|
||||
jump LABEL44
|
||||
LABEL42:
|
||||
iconst 1
|
||||
return
|
||||
LABEL44:
|
||||
iload 1
|
||||
iconst 2
|
||||
if_icmpeq LABEL48
|
||||
jump LABEL54
|
||||
LABEL48:
|
||||
get_varbit 13777
|
||||
iconst 1
|
||||
if_icmpeq LABEL52
|
||||
jump LABEL54
|
||||
LABEL52:
|
||||
iconst 1
|
||||
return
|
||||
LABEL54:
|
||||
iload 1
|
||||
iconst 1
|
||||
if_icmpeq LABEL58
|
||||
jump LABEL68
|
||||
LABEL58:
|
||||
get_varbit 13778
|
||||
iconst 2
|
||||
if_icmpeq LABEL62
|
||||
jump LABEL68
|
||||
LABEL62:
|
||||
iload 2
|
||||
iconst 0
|
||||
if_icmpeq LABEL66
|
||||
jump LABEL68
|
||||
LABEL66:
|
||||
iconst 1
|
||||
return
|
||||
LABEL68:
|
||||
iload 1
|
||||
iconst 1
|
||||
if_icmpeq LABEL72
|
||||
jump LABEL82
|
||||
LABEL72:
|
||||
get_varbit 13779
|
||||
iconst 2
|
||||
if_icmpeq LABEL76
|
||||
jump LABEL82
|
||||
LABEL76:
|
||||
iload 3
|
||||
iconst 0
|
||||
if_icmpeq LABEL80
|
||||
jump LABEL82
|
||||
LABEL80:
|
||||
iconst 1
|
||||
return
|
||||
LABEL82:
|
||||
iconst 0
|
||||
return
|
||||
iconst -1
|
||||
return
|
||||
@@ -165,11 +165,16 @@ public class ChatCommandsPluginTest
|
||||
public void testTheatreOfBlood()
|
||||
{
|
||||
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "",
|
||||
"Wave 'The Final Challenge' (Normal Mode) complete!<br>Duration: <col=ff0000>2:42.0</col><br>Theatre of Blood wave completion time: <col=ff0000>17:00.20</col> (new personal best)", null, 0);
|
||||
"Wave 'The Final Challenge' (Normal Mode) complete!<br>" +
|
||||
"Duration: <col=ff0000>2:42.0</col><br>" +
|
||||
"Theatre of Blood completion time: <col=ff0000>17:00.20</col> (new personal best)", null, 0);
|
||||
chatCommandsPlugin.onChatMessage(chatMessage);
|
||||
|
||||
ChatMessage chatMessageEvent = new ChatMessage(null, GAMEMESSAGE, "", "Your completed Theatre of Blood count is: <col=ff0000>73</col>.", null, 0);
|
||||
chatCommandsPlugin.onChatMessage(chatMessageEvent);
|
||||
chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Theatre of Blood total completion time: <col=ff0000>24:40.20</col>. Personal best: 20:45.00", null, 0);
|
||||
chatCommandsPlugin.onChatMessage(chatMessage);
|
||||
|
||||
chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Your completed Theatre of Blood count is: <col=ff0000>73</col>.", null, 0);
|
||||
chatCommandsPlugin.onChatMessage(chatMessage);
|
||||
|
||||
verify(configManager).setRSProfileConfiguration("killcount", "theatre of blood", 73);
|
||||
verify(configManager).setRSProfileConfiguration("personalbest", "theatre of blood", 17 * 60 + .2);
|
||||
@@ -179,11 +184,16 @@ public class ChatCommandsPluginTest
|
||||
public void testTheatreOfBloodNoPb()
|
||||
{
|
||||
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "",
|
||||
"Wave 'The Final Challenge' (Normal Mode) complete!<br>Duration: <col=ff0000>2:42</col><br>Theatre of Blood wave completion time: <col=ff0000>17:00</col>. Personal best: 13:52.80", null, 0);
|
||||
"Wave 'The Final Challenge' (Normal Mode) complete!<br>" +
|
||||
"Duration: <col=ff0000>2:42</col><br>" +
|
||||
"Theatre of Blood completion time: <col=ff0000>17:00</col>. Personal best: 13:52.80", null, 0);
|
||||
chatCommandsPlugin.onChatMessage(chatMessage);
|
||||
|
||||
ChatMessage chatMessageEvent = new ChatMessage(null, GAMEMESSAGE, "", "Your completed Theatre of Blood count is: <col=ff0000>73</col>.", null, 0);
|
||||
chatCommandsPlugin.onChatMessage(chatMessageEvent);
|
||||
chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Theatre of Blood total completion time: <col=ff0000>24:40.20</col>. Personal best: 20:45.00", null, 0);
|
||||
chatCommandsPlugin.onChatMessage(chatMessage);
|
||||
|
||||
chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Your completed Theatre of Blood count is: <col=ff0000>73</col>.", null, 0);
|
||||
chatCommandsPlugin.onChatMessage(chatMessage);
|
||||
|
||||
verify(configManager).setRSProfileConfiguration("killcount", "theatre of blood", 73);
|
||||
verify(configManager).setRSProfileConfiguration("personalbest", "theatre of blood", 13 * 60 + 52.8);
|
||||
@@ -193,11 +203,16 @@ public class ChatCommandsPluginTest
|
||||
public void testTheatreOfBloodEntryMode()
|
||||
{
|
||||
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "",
|
||||
"Wave 'The Final Challenge' (Entry Mode) complete!<br>Duration: <col=ff0000>2:42</col><br>Theatre of Blood wave completion time: <col=ff0000>17:00</col> (new personal best)", null, 0);
|
||||
"Wave 'The Final Challenge' (Entry Mode) complete!<br>" +
|
||||
"Duration: <col=ff0000>2:42</col><br>" +
|
||||
"Theatre of Blood completion time: <col=ff0000>17:00</col> (new personal best)", null, 0);
|
||||
chatCommandsPlugin.onChatMessage(chatMessage);
|
||||
|
||||
ChatMessage chatMessageEvent = new ChatMessage(null, GAMEMESSAGE, "", "Your completed Theatre of Blood: Entry Mode count is: <col=ff0000>73</col>.", null, 0);
|
||||
chatCommandsPlugin.onChatMessage(chatMessageEvent);
|
||||
chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Theatre of Blood total completion time: <col=ff0000>24:40.20</col>. Personal best: 20:45.00", null, 0);
|
||||
chatCommandsPlugin.onChatMessage(chatMessage);
|
||||
|
||||
chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Your completed Theatre of Blood: Entry Mode count is: <col=ff0000>73</col>.", null, 0);
|
||||
chatCommandsPlugin.onChatMessage(chatMessage);
|
||||
|
||||
verify(configManager).setRSProfileConfiguration("killcount", "theatre of blood entry mode", 73);
|
||||
verify(configManager).setRSProfileConfiguration("personalbest", "theatre of blood entry mode", 17 * 60.);
|
||||
@@ -1074,4 +1089,13 @@ public class ChatCommandsPluginTest
|
||||
verify(configManager).setRSProfileConfiguration("personalbest", "tempoross", 234.0);
|
||||
verify(configManager).setRSProfileConfiguration("personalbest", "chambers of xeric", 1360.0); // the lowest time
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGuardiansOfTheRift()
|
||||
{
|
||||
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Amount of Rifts you have closed: <col=ff0000>7</col>.", null, 0);
|
||||
chatCommandsPlugin.onChatMessage(chatMessage);
|
||||
|
||||
verify(configManager).setRSProfileConfiguration("killcount", "guardians of the rift", 7);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ public class FarmingTrackerTest
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testEmptyNotification()
|
||||
{
|
||||
RuneScapeProfile runeScapeProfile = new RuneScapeProfile("Adam", RuneScapeProfileType.STANDARD, null, null);
|
||||
RuneScapeProfile runeScapeProfile = new RuneScapeProfile("Adam", RuneScapeProfileType.STANDARD, null, -1, null);
|
||||
|
||||
PatchPrediction patchPrediction = new PatchPrediction(Produce.EMPTY_COMPOST_BIN, CropState.EMPTY, 0L, 0, 0);
|
||||
FarmingRegion region = new FarmingRegion("Ardougne", 10548, false,
|
||||
@@ -113,7 +113,7 @@ public class FarmingTrackerTest
|
||||
@Test
|
||||
public void testHarvestableNotification()
|
||||
{
|
||||
RuneScapeProfile runeScapeProfile = new RuneScapeProfile("Adam", RuneScapeProfileType.STANDARD, null, null);
|
||||
RuneScapeProfile runeScapeProfile = new RuneScapeProfile("Adam", RuneScapeProfileType.STANDARD, null, -1, null);
|
||||
|
||||
PatchPrediction patchPrediction = new PatchPrediction(Produce.RANARR, CropState.HARVESTABLE, 0L, 0, 0);
|
||||
FarmingRegion region = new FarmingRegion("Ardougne", 10548, false,
|
||||
|
||||
Reference in New Issue
Block a user