clientloader: use fallback config if gamepack fails to load

This commit is contained in:
Adam
2020-03-25 12:55:20 -04:00
parent 71e4b5d9ad
commit 544414a8cf
2 changed files with 62 additions and 33 deletions

View File

@@ -49,12 +49,13 @@ import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory; import java.security.cert.CertificateFactory;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Map;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.jar.JarEntry; import java.util.jar.JarEntry;
import java.util.jar.JarFile; import java.util.jar.JarFile;
import java.util.jar.JarInputStream; import java.util.jar.JarInputStream;
import javax.annotation.Nonnull;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client; import net.runelite.api.Client;
@@ -66,9 +67,9 @@ import static net.runelite.client.rs.ClientUpdateCheckMode.VANILLA;
import net.runelite.client.ui.FatalErrorDialog; import net.runelite.client.ui.FatalErrorDialog;
import net.runelite.client.ui.SplashScreen; import net.runelite.client.ui.SplashScreen;
import net.runelite.client.util.CountingInputStream; import net.runelite.client.util.CountingInputStream;
import net.runelite.client.util.VerificationException;
import net.runelite.http.api.RuneLiteAPI; import net.runelite.http.api.RuneLiteAPI;
import net.runelite.http.api.worlds.World; import net.runelite.http.api.worlds.World;
import net.runelite.client.util.VerificationException;
import okhttp3.HttpUrl; import okhttp3.HttpUrl;
import okhttp3.Request; import okhttp3.Request;
import okhttp3.Response; import okhttp3.Response;
@@ -86,7 +87,6 @@ public class ClientLoader implements Supplier<Applet>
private Object client = null; private Object client = null;
private WorldSupplier worldSupplier = new WorldSupplier(); private WorldSupplier worldSupplier = new WorldSupplier();
private RSConfig config;
public ClientLoader(ClientUpdateCheckMode updateCheckMode) public ClientLoader(ClientUpdateCheckMode updateCheckMode)
{ {
@@ -118,7 +118,7 @@ public class ClientLoader implements Supplier<Applet>
try try
{ {
SplashScreen.stage(0, null, "Fetching applet viewer config"); SplashScreen.stage(0, null, "Fetching applet viewer config");
downloadConfig(); RSConfig config = downloadConfig();
SplashScreen.stage(.05, null, "Waiting for other clients to start"); SplashScreen.stage(.05, null, "Waiting for other clients to start");
@@ -129,7 +129,24 @@ public class ClientLoader implements Supplier<Applet>
FileLock flock = lockfile.lock()) FileLock flock = lockfile.lock())
{ {
SplashScreen.stage(.05, null, "Downloading Old School RuneScape"); SplashScreen.stage(.05, null, "Downloading Old School RuneScape");
updateVanilla(); try
{
updateVanilla(config);
}
catch (IOException ex)
{
// try again with the fallback config and gamepack
if (!config.isFallback())
{
log.warn("Unable to download game client, attempting to use fallback config", ex);
config = downloadFallbackConfig();
updateVanilla(config);
}
else
{
throw ex;
}
}
if (updateCheckMode == AUTO) if (updateCheckMode == AUTO)
{ {
@@ -146,7 +163,7 @@ public class ClientLoader implements Supplier<Applet>
SplashScreen.stage(.465, "Starting", "Starting Old School RuneScape"); SplashScreen.stage(.465, "Starting", "Starting Old School RuneScape");
Applet rs = loadClient(classLoader); Applet rs = loadClient(config, classLoader);
SplashScreen.stage(.5, null, "Starting core classes"); SplashScreen.stage(.5, null, "Starting core classes");
@@ -162,7 +179,7 @@ public class ClientLoader implements Supplier<Applet>
} }
} }
private void downloadConfig() throws IOException private RSConfig downloadConfig() throws IOException
{ {
HttpUrl url = HttpUrl.parse(RuneLiteProperties.getJavConfig()); HttpUrl url = HttpUrl.parse(RuneLiteProperties.getJavConfig());
IOException err = null; IOException err = null;
@@ -170,14 +187,14 @@ public class ClientLoader implements Supplier<Applet>
{ {
try try
{ {
config = ClientConfigLoader.fetch(url); RSConfig config = ClientConfigLoader.fetch(url);
if (Strings.isNullOrEmpty(config.getCodeBase()) || Strings.isNullOrEmpty(config.getInitialJar()) || Strings.isNullOrEmpty(config.getInitialClass())) if (Strings.isNullOrEmpty(config.getCodeBase()) || Strings.isNullOrEmpty(config.getInitialJar()) || Strings.isNullOrEmpty(config.getInitialClass()))
{ {
throw new IOException("Invalid or missing jav_config"); throw new IOException("Invalid or missing jav_config");
} }
return; return config;
} }
catch (IOException e) catch (IOException e)
{ {
@@ -192,35 +209,42 @@ public class ClientLoader implements Supplier<Applet>
try try
{ {
RSConfig backupConfig = ClientConfigLoader.fetch(HttpUrl.parse(RuneLiteProperties.getJavConfigBackup())); return downloadFallbackConfig();
if (Strings.isNullOrEmpty(backupConfig.getCodeBase()) || Strings.isNullOrEmpty(backupConfig.getInitialJar()) || Strings.isNullOrEmpty(backupConfig.getInitialClass()))
{
throw new IOException("Invalid or missing jav_config");
}
if (Strings.isNullOrEmpty(backupConfig.getRuneLiteGamepack()) || Strings.isNullOrEmpty(backupConfig.getRuneLiteWorldParam()))
{
throw new IOException("Backup config does not have RuneLite gamepack url");
}
// Randomize the codebase
World world = worldSupplier.get();
backupConfig.setCodebase("http://" + world.getAddress() + "/");
// Update the world applet parameter
Map<String, String> appletProperties = backupConfig.getAppletProperties();
appletProperties.put(backupConfig.getRuneLiteWorldParam(), Integer.toString(world.getId()));
config = backupConfig;
} }
catch (IOException ex) catch (IOException ex)
{ {
log.debug("error downloading backup config", ex);
throw err; // use error from Jagex's servers throw err; // use error from Jagex's servers
} }
} }
private void updateVanilla() throws IOException, VerificationException @Nonnull
private RSConfig downloadFallbackConfig() throws IOException
{
RSConfig backupConfig = ClientConfigLoader.fetch(HttpUrl.parse(RuneLiteProperties.getJavConfigBackup()));
if (Strings.isNullOrEmpty(backupConfig.getCodeBase()) || Strings.isNullOrEmpty(backupConfig.getInitialJar()) || Strings.isNullOrEmpty(backupConfig.getInitialClass()))
{
throw new IOException("Invalid or missing jav_config");
}
if (Strings.isNullOrEmpty(backupConfig.getRuneLiteGamepack()) || Strings.isNullOrEmpty(backupConfig.getRuneLiteWorldParam()))
{
throw new IOException("Backup config does not have RuneLite gamepack url");
}
// Randomize the codebase
World world = worldSupplier.get();
backupConfig.setCodebase("http://" + world.getAddress() + "/");
// Update the world applet parameter
Map<String, String> appletProperties = backupConfig.getAppletProperties();
appletProperties.put(backupConfig.getRuneLiteWorldParam(), Integer.toString(world.getId()));
return backupConfig;
}
private void updateVanilla(RSConfig config) throws IOException, VerificationException
{ {
Certificate[] jagexCertificateChain = getJagexCertificateChain(); Certificate[] jagexCertificateChain = getJagexCertificateChain();
@@ -256,7 +280,7 @@ public class ClientLoader implements Supplier<Applet>
// Start downloading the vanilla client // Start downloading the vanilla client
HttpUrl url; HttpUrl url;
if (config.getRuneLiteGamepack() != null) if (config.isFallback())
{ {
// If we are using the backup config, use our own gamepack and ignore the codebase // If we are using the backup config, use our own gamepack and ignore the codebase
url = HttpUrl.parse(config.getRuneLiteGamepack()); url = HttpUrl.parse(config.getRuneLiteGamepack());
@@ -503,7 +527,7 @@ public class ClientLoader implements Supplier<Applet>
} }
} }
private Applet loadClient(ClassLoader classLoader) throws ClassNotFoundException, IllegalAccessException, InstantiationException private Applet loadClient(RSConfig config, ClassLoader classLoader) throws ClassNotFoundException, IllegalAccessException, InstantiationException
{ {
String initialClass = config.getInitialClass(); String initialClass = config.getInitialClass();
Class<?> clientClass = classLoader.loadClass(initialClass); Class<?> clientClass = classLoader.loadClass(initialClass);

View File

@@ -55,6 +55,11 @@ class RSConfig
return classLoaderProperties.get("initial_class").replace(".class", ""); return classLoaderProperties.get("initial_class").replace(".class", "");
} }
boolean isFallback()
{
return getRuneLiteGamepack() != null;
}
String getRuneLiteGamepack() String getRuneLiteGamepack()
{ {
return classLoaderProperties.get("runelite.gamepack"); return classLoaderProperties.get("runelite.gamepack");