Allow the server to send ClientDiff

This commit is contained in:
Melledy
2025-11-15 04:29:55 -08:00
parent 33babe3405
commit 5f98c8ce80
8 changed files with 111 additions and 18 deletions

1
.gitignore vendored
View File

@@ -71,6 +71,7 @@ tmp/
# Extra # Extra
Nebula Handbook.txt Nebula Handbook.txt
config.json config.json
patchlist.json
*.mv *.mv
*.exe *.exe
*.p12 *.p12

View File

@@ -24,6 +24,7 @@ public class Config {
public String resourceDir = "./resources"; public String resourceDir = "./resources";
public String dataDir = "./data"; public String dataDir = "./data";
public String patchListPath = "./patchlist.json";
@Getter @Getter
public static class DatabaseInfo { public static class DatabaseInfo {

View File

@@ -3,7 +3,7 @@ package emu.nebula;
import java.time.ZoneId; import java.time.ZoneId;
public class GameConstants { public class GameConstants {
public static final int DATA_VERSION = 40; public static final int DATA_VERSION = 46;
public static final String VERSION = "1.0.0." + DATA_VERSION; public static final String VERSION = "1.0.0." + DATA_VERSION;
public static final ZoneId UTC_ZONE = ZoneId.of("UTC"); public static final ZoneId UTC_ZONE = ZoneId.of("UTC");

View File

@@ -11,6 +11,11 @@ public class ReloadCommand implements CommandHandler {
@Override @Override
public void execute(CommandArgs args) { public void execute(CommandArgs args) {
Nebula.loadConfig(); Nebula.loadConfig();
if (Nebula.getHttpServer() != null) {
Nebula.getHttpServer().loadPatchList();
}
args.sendMessage("Reloaded the server config"); args.sendMessage("Reloaded the server config");
} }

View File

@@ -1,5 +1,8 @@
package emu.nebula.server; package emu.nebula.server;
import java.io.File;
import java.io.FileReader;
import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer; import org.eclipse.jetty.server.SecureRequestCustomizer;
@@ -7,9 +10,12 @@ import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.ssl.SslContextFactory;
import emu.nebula.Config.HttpServerConfig; import emu.nebula.Config.HttpServerConfig;
import emu.nebula.GameConstants;
import emu.nebula.Nebula; import emu.nebula.Nebula;
import emu.nebula.Nebula.ServerType; import emu.nebula.Nebula.ServerType;
import emu.nebula.proto.Pb.ClientDiff;
import emu.nebula.server.routes.*; import emu.nebula.server.routes.*;
import emu.nebula.util.JsonUtils;
import io.javalin.Javalin; import io.javalin.Javalin;
import io.javalin.http.ContentType; import io.javalin.http.ContentType;
import io.javalin.http.Context; import io.javalin.http.Context;
@@ -21,10 +27,15 @@ public class HttpServer {
private ServerType type; private ServerType type;
private boolean started; private boolean started;
// Cached client diff
private PatchList patchlist;
private byte[] diff;
public HttpServer(ServerType type) { public HttpServer(ServerType type) {
this.app = Javalin.create(); this.app = Javalin.create();
this.type = type; this.type = type;
this.loadPatchList();
this.addRoutes(); this.addRoutes();
} }
@@ -49,6 +60,39 @@ public class HttpServer {
return sslContextFactory; return sslContextFactory;
} }
// Patch list
public long getDataVersion() {
return getPatchlist() != null ? getPatchlist().getVersion() : GameConstants.DATA_VERSION;
}
public synchronized void loadPatchList() {
// Clear
this.patchlist = null;
this.diff = null;
// Get file
File file = new File(Nebula.getConfig().getPatchListPath());
if (!file.exists()) {
this.diff = ClientDiff.newInstance().toByteArray();
return;
}
// Load
try (FileReader reader = new FileReader(file)) {
this.patchlist = JsonUtils.loadToClass(reader, PatchList.class);
this.diff = patchlist.toProto().toByteArray();
} catch (Exception e) {
this.patchlist = null;
this.diff = ClientDiff.newInstance().toByteArray();
}
if (this.patchlist != null) {
Nebula.getLogger().info("Loaded patchlist version " + patchlist.getVersion());
}
}
// Start server // Start server
public void start() { public void start() {
@@ -107,7 +151,7 @@ public class HttpServer {
// https://nova-static.stellasora.global/ // https://nova-static.stellasora.global/
getApp().get("/meta/serverlist.html", new MetaServerlistHandler(this)); getApp().get("/meta/serverlist.html", new MetaServerlistHandler(this));
getApp().get("/meta/win.html", new MetaWinHandler()); getApp().get("/meta/win.html", new MetaWinHandler(this));
} }
private void addGameServerRoutes() { private void addGameServerRoutes() {

View File

@@ -0,0 +1,39 @@
package emu.nebula.server;
import java.util.List;
import emu.nebula.proto.Pb.ClientDiff;
import emu.nebula.proto.Pb.FileDiff;
import lombok.Getter;
@Getter
public class PatchList {
public long version;
public List<PatchListFile> files;
@Getter
public static class PatchListFile {
public String name;
public String hash;
public long version;
public String additionalPath;
}
// Proto
public ClientDiff toProto() {
var proto = ClientDiff.newInstance();
for (var file : files) {
var diff = FileDiff.newInstance()
.setFileName(file.getName())
.setHash(file.getHash())
.setVersion(this.getVersion())
.setAdditionalPath(file.getAdditionalPath());
proto.addDiff(diff);
}
return proto;
}
}

View File

@@ -2,7 +2,6 @@ package emu.nebula.server.routes;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import emu.nebula.GameConstants;
import emu.nebula.proto.Pb.ServerAgent; import emu.nebula.proto.Pb.ServerAgent;
import emu.nebula.proto.Pb.ServerListMeta; import emu.nebula.proto.Pb.ServerListMeta;
import emu.nebula.server.HttpServer; import emu.nebula.server.HttpServer;
@@ -24,7 +23,7 @@ public class MetaServerlistHandler implements Handler {
// Create server list // Create server list
this.list = ServerListMeta.newInstance() this.list = ServerListMeta.newInstance()
.setVersion(GameConstants.DATA_VERSION) .setVersion(server.getDataVersion())
.setReportEndpoint(server.getServerConfig().getDisplayAddress() + "/report"); .setReportEndpoint(server.getServerConfig().getDisplayAddress() + "/report");
var agent = ServerAgent.newInstance() var agent = ServerAgent.newInstance()

View File

@@ -2,8 +2,9 @@ package emu.nebula.server.routes;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import emu.nebula.proto.Pb.ClientDiff; import emu.nebula.server.HttpServer;
import emu.nebula.util.AeadHelper; import emu.nebula.util.AeadHelper;
import emu.nebula.util.Utils;
import io.javalin.http.ContentType; import io.javalin.http.ContentType;
import io.javalin.http.Context; import io.javalin.http.Context;
import io.javalin.http.Handler; import io.javalin.http.Handler;
@@ -12,24 +13,27 @@ import lombok.Getter;
@Getter(AccessLevel.PRIVATE) @Getter(AccessLevel.PRIVATE)
public class MetaWinHandler implements Handler { public class MetaWinHandler implements Handler {
private ClientDiff list; private HttpServer server;
private byte[] proto;
public MetaWinHandler() { public MetaWinHandler(HttpServer server) {
// Create client diff this.server = server;
this.list = ClientDiff.newInstance();
// TODO load from json or something
// Cache proto
this.proto = list.toByteArray();
} }
@Override @Override
public void handle(@NotNull Context ctx) throws Exception { public void handle(@NotNull Context ctx) throws Exception {
// Result // Get diff
var diffBytes = this.getServer().getDiff();
// Sanity check
if (diffBytes == null) {
ctx.contentType(ContentType.APPLICATION_OCTET_STREAM);
ctx.result(Utils.EMPTY_BYTE_ARRAY);
return;
}
// Encrypt patch list
ctx.contentType(ContentType.APPLICATION_OCTET_STREAM); ctx.contentType(ContentType.APPLICATION_OCTET_STREAM);
ctx.result(AeadHelper.encryptCBC(this.getProto())); ctx.result(AeadHelper.encryptCBC(diffBytes));
} }
} }