Add SPLServer support to loader
All checks were successful
/ Build BaseBand Loader (push) Successful in 1m55s
All checks were successful
/ Build BaseBand Loader (push) Successful in 1m55s
This commit is contained in:
parent
be2750c4dd
commit
c3f6505a8f
2 changed files with 155 additions and 84 deletions
|
@ -30,8 +30,10 @@ import oshi.hardware.Processor;
|
|||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.Socket;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
@ -42,6 +44,7 @@ import java.util.HashMap;
|
|||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
@Mod(modid = "baseband")
|
||||
|
@ -85,6 +88,18 @@ public class Loader implements Util {
|
|||
preOptions = new TCN();
|
||||
}
|
||||
preOptions.setIfAbsent("timeout", 5);
|
||||
TCN branches;
|
||||
try {
|
||||
branches = JSON.read(new StreamReader(new URL("https://download.baseband.com.de/branches").openStream()).readAllAsString());
|
||||
} catch (Exception e) {
|
||||
exit();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!GitHash.GIT_HASH.equals("[dev]") && !GitHash.GIT_HASH.equals(branches.getSub("loader").getString("commit"))) {
|
||||
splUpdate();
|
||||
return;
|
||||
}
|
||||
|
||||
TCN options = new ClientBoot("BaseBand", preOptions.getInteger("timeout") * 1000, preOptions)
|
||||
.label("Start Minecraft:")
|
||||
|
@ -222,9 +237,18 @@ public class Loader implements Util {
|
|||
.option("Set timeout: 5s", x1 -> x1.data.set("timeout", 5))
|
||||
.option("Set timeout: 10s", x1 -> x1.data.set("timeout", 10))
|
||||
.option("Back", ClientBoot::back))
|
||||
.option("Set branch", x -> x.newScreen()
|
||||
.option("release (Broadway)", x1 -> x1.back().data.set("branch", "release"))
|
||||
.option("main (Iceland)", x1 -> x1.back().data.set("branch", "main")))
|
||||
.option("Set branch", x -> {
|
||||
ClientBoot screen = x.newScreen();
|
||||
for (String entry : branches.map.keys()) {
|
||||
if(entry.equals("loader"))
|
||||
continue;
|
||||
|
||||
screen.option(entry + " (" + branches.getSub(entry).getString("name") + ")", x1 -> x1.back().data.set("branch", entry));
|
||||
}
|
||||
})
|
||||
.option("Server mode", x -> x.newScreen()
|
||||
.option("SPL", x1 -> x1.back().data.set("server", "spl"))
|
||||
.option("Java", x1 -> x1.back().data.set("server", "java")))
|
||||
.option("Persist changes", x -> {
|
||||
try(FileOutputStream fos = new FileOutputStream("baseband_launch.json")) {
|
||||
fos.write(JSON.writeReadable(x.data).getBytes(StandardCharsets.UTF_8));
|
||||
|
@ -235,101 +259,145 @@ public class Loader implements Util {
|
|||
.spacer()
|
||||
.option("Exit Minecraft", x -> exit(0))
|
||||
.show();
|
||||
options.setIfAbsent("server", "java");
|
||||
options.setIfAbsent("branch", "release");
|
||||
options.setIfAbsent("ip", "baseband.com.de");
|
||||
options.setIfAbsent("disabled-modules", new TCNArray());
|
||||
|
||||
try(Socket client = new Socket(options.getString("ip"), 40000)) {
|
||||
client.setSoTimeout(5000);
|
||||
client.getOutputStream().write(0);
|
||||
TypedInputStream inputStream = new TypedInputStream(client.getInputStream());
|
||||
TypedOutputStream outputStream = new TypedOutputStream(client.getOutputStream());
|
||||
if(options.getString("server").equals("java")) {
|
||||
try (Socket client = new Socket(options.getString("ip"), 40000)) {
|
||||
client.setSoTimeout(5000);
|
||||
client.getOutputStream().write(0);
|
||||
TypedInputStream inputStream = new TypedInputStream(client.getInputStream());
|
||||
TypedOutputStream outputStream = new TypedOutputStream(client.getOutputStream());
|
||||
|
||||
RSAKey rsaKey = new RSAKey(inputStream.readString()); //get publickey
|
||||
Key key = new Key();
|
||||
outputStream.writeString(rsaKey.rsaEnc(key.toString().getBytes(StandardCharsets.ISO_8859_1)));
|
||||
outputStream.writeString(key.encryptString(Tools.mapToString(getData(options).toMap())));
|
||||
RSAKey rsaKey = new RSAKey(inputStream.readString()); //get publickey
|
||||
Key key = new Key();
|
||||
outputStream.writeString(rsaKey.rsaEnc(key.toString().getBytes(StandardCharsets.ISO_8859_1)));
|
||||
outputStream.writeString(key.encryptString(Tools.mapToString(getData(options).toMap())));
|
||||
|
||||
Response status = Response.values()[inputStream.readInt()];
|
||||
Response status = Response.values()[inputStream.readInt()];
|
||||
|
||||
if(status == Response.OUTDATED) {
|
||||
LOGGER.info("BaseBand is downloading a significant update.");
|
||||
RawKey rk = new RawKey(key.toBytes());
|
||||
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(HTTPUtils.decodeUTF8(Loader.class.getProtectionDomain().getCodeSource().getLocation().getFile())));
|
||||
int n = inputStream.readInt();
|
||||
for (int i = 0; i < n; i++) {
|
||||
out.putNextEntry(new ZipEntry(rk.decryptString(inputStream.readString())));
|
||||
out.write(rk.decryptBytes(inputStream.readByteArray()));
|
||||
out.closeEntry();
|
||||
}
|
||||
out.close();
|
||||
LOGGER.info("BaseBand has downloaded a significant update. Minecraft will exit.");
|
||||
JOptionPane.showMessageDialog(null, "BaseBand has downloaded a significant update. Please restart Minecraft.");
|
||||
exit(0);
|
||||
} else if(status == Response.OK) {
|
||||
LOGGER.info(status.name);
|
||||
try {
|
||||
TCN clientData = TCN.readMap(Tools.stringToMap(key.decryptString(inputStream.readString())));
|
||||
|
||||
for (TLMap.Entry<String, Object> entry : options.map.entries()) {
|
||||
if(entry.val instanceof TCNArray && clientData.get(entry.key) != null) {
|
||||
clientData.getArray(entry.key).addAll((TCNArray) entry.val);
|
||||
}
|
||||
else {
|
||||
clientData.setIfAbsent(entry.key, entry.val);
|
||||
}
|
||||
}
|
||||
|
||||
HashMap<String, byte[]> data = new HashMap<>();
|
||||
SimpleLock downloadUpdated = new SimpleLock();
|
||||
SimpleLock continueDownload = new SimpleLock();
|
||||
AtomicInteger bytes = new AtomicInteger();
|
||||
new Thread(() -> {
|
||||
long lastUpdate = System.currentTimeMillis();
|
||||
while (classLoader == null) {
|
||||
downloadUpdated.waitHere(2000);
|
||||
if(downloadUpdated.isLocked()) {
|
||||
LOGGER.warn("No new BaseBand chunk has been downloaded in 2 seconds. Consider restarting your game.");
|
||||
}
|
||||
else if(System.currentTimeMillis() - lastUpdate >= 500) {
|
||||
//LOGGER.info("Downloading at {}KB/s...", (int) ((bytes.get() / 1024f) * (System.currentTimeMillis() - lastUpdate) / 1000f));
|
||||
lastUpdate = System.currentTimeMillis();
|
||||
bytes.set(0);
|
||||
}
|
||||
downloadUpdated.lock();
|
||||
continueDownload.unlock();
|
||||
}
|
||||
}, "Download guard").start();
|
||||
if (status == Response.OUTDATED) {
|
||||
LOGGER.info("BaseBand is downloading a significant update.");
|
||||
RawKey rk = new RawKey(key.toBytes());
|
||||
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(HTTPUtils.decodeUTF8(Loader.class.getProtectionDomain().getCodeSource().getLocation().getFile())));
|
||||
int n = inputStream.readInt();
|
||||
for (int i = 0; i < n; i++) {
|
||||
String name = inputStream.readString();
|
||||
byte[] classBytes = inputStream.readByteArray();
|
||||
data.put(rk.decryptString(name), rk.decryptBytes(classBytes));
|
||||
bytes.getAndAdd(classBytes.length);
|
||||
continueDownload.lock();
|
||||
downloadUpdated.unlock();
|
||||
continueDownload.waitHere();
|
||||
out.putNextEntry(new ZipEntry(rk.decryptString(inputStream.readString())));
|
||||
out.write(rk.decryptBytes(inputStream.readByteArray()));
|
||||
out.closeEntry();
|
||||
}
|
||||
LOGGER.info("BaseBand downloaded: {} chunks.", data.size());
|
||||
LOGGER.info("Booting BaseBand {} @ {}", clientData.getString("build-name"), new String(data.get("commit")).trim());
|
||||
classLoader = new CustomClassLoader(data);
|
||||
downloadUpdated.unlock();
|
||||
classLoader.inject();
|
||||
classLoader.informClient(clientData);
|
||||
} catch (Exception e) {
|
||||
LOGGER.fatal("BaseBand failed to (down)load.");
|
||||
e.printStackTrace();
|
||||
out.close();
|
||||
LOGGER.info("BaseBand has downloaded a significant update. Minecraft will exit.");
|
||||
JOptionPane.showMessageDialog(null, "BaseBand has downloaded a significant update. Please restart Minecraft.");
|
||||
exit(0);
|
||||
} else if (status == Response.OK) {
|
||||
LOGGER.info(status.name);
|
||||
try {
|
||||
TCN clientData = TCN.readMap(Tools.stringToMap(key.decryptString(inputStream.readString())));
|
||||
|
||||
for (TLMap.Entry<String, Object> entry : options.map.entries()) {
|
||||
if (entry.val instanceof TCNArray && clientData.get(entry.key) != null) {
|
||||
clientData.getArray(entry.key).addAll((TCNArray) entry.val);
|
||||
} else {
|
||||
clientData.setIfAbsent(entry.key, entry.val);
|
||||
}
|
||||
}
|
||||
|
||||
HashMap<String, byte[]> data = new HashMap<>();
|
||||
SimpleLock downloadUpdated = new SimpleLock();
|
||||
SimpleLock continueDownload = new SimpleLock();
|
||||
AtomicInteger bytes = new AtomicInteger();
|
||||
new Thread(() -> {
|
||||
long lastUpdate = System.currentTimeMillis();
|
||||
while (classLoader == null) {
|
||||
downloadUpdated.waitHere(2000);
|
||||
if (downloadUpdated.isLocked()) {
|
||||
LOGGER.warn("No new BaseBand chunk has been downloaded in 2 seconds. Consider restarting your game.");
|
||||
} else if (System.currentTimeMillis() - lastUpdate >= 500) {
|
||||
//LOGGER.info("Downloading at {}KB/s...", (int) ((bytes.get() / 1024f) * (System.currentTimeMillis() - lastUpdate) / 1000f));
|
||||
lastUpdate = System.currentTimeMillis();
|
||||
bytes.set(0);
|
||||
}
|
||||
downloadUpdated.lock();
|
||||
continueDownload.unlock();
|
||||
}
|
||||
}, "Download guard").start();
|
||||
RawKey rk = new RawKey(key.toBytes());
|
||||
int n = inputStream.readInt();
|
||||
for (int i = 0; i < n; i++) {
|
||||
String name = inputStream.readString();
|
||||
byte[] classBytes = inputStream.readByteArray();
|
||||
data.put(rk.decryptString(name), rk.decryptBytes(classBytes));
|
||||
bytes.getAndAdd(classBytes.length);
|
||||
continueDownload.lock();
|
||||
downloadUpdated.unlock();
|
||||
continueDownload.waitHere();
|
||||
}
|
||||
LOGGER.info("BaseBand downloaded: {} chunks.", data.size());
|
||||
LOGGER.info("Booting BaseBand {} @ {}", clientData.getString("build-name"), new String(data.get("commit")).trim());
|
||||
classLoader = new CustomClassLoader(data);
|
||||
downloadUpdated.unlock();
|
||||
classLoader.inject();
|
||||
classLoader.informClient(clientData);
|
||||
} catch (Exception e) {
|
||||
LOGGER.fatal("BaseBand failed to (down)load.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
LOGGER.error(status.name);
|
||||
exit();
|
||||
}
|
||||
} else {
|
||||
LOGGER.error(status.name);
|
||||
} catch (Exception e) {
|
||||
LOGGER.fatal("Failed to connect to Server-side.");
|
||||
LOGGER.fatal(e.getMessage());
|
||||
exit();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.fatal("Failed to connect to Server-side.");
|
||||
LOGGER.fatal(e.getMessage());
|
||||
exit();
|
||||
}
|
||||
|
||||
if(options.getString("server").equals("spl")) {
|
||||
if(options.getBoolean("redownload")) {
|
||||
splUpdate();
|
||||
}
|
||||
|
||||
options.set("build-name", branches.getSub(options.getString("branch")).getString("name"));
|
||||
HashMap<String, byte[]> data = downloadFromSPL("https://download.baseband.com.de/download/client/" + options.getString("branch"));
|
||||
LOGGER.info("BaseBand downloaded: {} chunks.", data.size());
|
||||
LOGGER.info("Booting BaseBand {} @ {}", options.getString("build-name"), new String(data.get("commit")).trim());
|
||||
classLoader = new CustomClassLoader(data);
|
||||
classLoader.inject();
|
||||
classLoader.informClient(options);
|
||||
}
|
||||
}
|
||||
|
||||
private static void splUpdate() {
|
||||
LOGGER.info("BaseBand is downloading a significant update...");
|
||||
CustomClassLoader loaderReloader = new CustomClassLoader(downloadFromSPL("https://download.baseband.com.de/download/loader"));
|
||||
loaderReloader.inject();
|
||||
LOGGER.info("BaseBand has downloaded a significant update. Applying...");
|
||||
try {
|
||||
loaderReloader.loadClass(Tweaker.class.getName()).getMethod("load").invoke(null);
|
||||
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException |
|
||||
ClassNotFoundException e) {
|
||||
JOptionPane.showMessageDialog(null, "BaseBand has downloaded a significant update. Please restart Minecraft.");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
private static HashMap<String, byte[]> downloadFromSPL(String url) {
|
||||
HashMap<String, byte[]> data = new HashMap<>();
|
||||
try (ZipInputStream jar = new ZipInputStream(new URL(url).openStream())) {
|
||||
ZipEntry entry;
|
||||
while ((entry = jar.getNextEntry()) != null) {
|
||||
byte[] bytes = new StreamReader(jar).readAllAsBytes();
|
||||
data.put(entry.getName(), bytes);
|
||||
jar.closeEntry();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public static void loaded(Class<?> baseBandClass) {
|
||||
|
|
|
@ -26,6 +26,9 @@ public class Tweaker implements ITweaker, IFMLLoadingPlugin {
|
|||
public static void loaded(Class<?> baseBandClass) {
|
||||
Loader.loaded(baseBandClass);
|
||||
}
|
||||
public static void load() {
|
||||
Loader.run();
|
||||
}
|
||||
|
||||
private final MixinTweaker wrapped;
|
||||
|
||||
|
@ -40,7 +43,7 @@ public class Tweaker implements ITweaker, IFMLLoadingPlugin {
|
|||
|
||||
@Override
|
||||
public void injectIntoClassLoader(LaunchClassLoader launchClassLoader) {
|
||||
Loader.run();
|
||||
load();
|
||||
wrapped.injectIntoClassLoader(launchClassLoader);
|
||||
|
||||
Mixins.addConfiguration("mixins.baseband.json");
|
||||
|
|
Loading…
Add table
Reference in a new issue