Implement main game as a mod

This commit is contained in:
2026-09-24 23:49:34 -03:00
parent bb42dd662e
commit 6458bc0440
131 changed files with 1810 additions and 786 deletions
+27 -2
View File
@@ -1,9 +1,11 @@
import { serveDir } from "@std/http/file-server";
import { GameToHost, HostToGame } from "./game/host_protocol.ts";
import type { ServerModIndex } from "../build.ts";
const PORT = Number(Deno.env.get("PORT") ?? 8000);
const WORLD_FILE = Deno.env.get("WORLD_FILE") ?? "world.json";
const STATIC_ROOT = "build";
const STATIC_ROOT = Deno.env.get("BUILD_DIR") ?? "build";
const SERVER_MODS_DIR = Deno.env.get("SERVER_MODS_DIR") ?? "server_mods";
const MAX_MESSAGE_SIZE = 4096;
const SHUTDOWN_TIMEOUT_MS = 5000;
@@ -43,6 +45,10 @@ game.onmessage = (event: MessageEvent<GameToHost>) => {
case "ready":
console.log(`World ${WORLD_FILE} ready, seed ${message.seed}`);
break;
case "failed":
console.error(`Couldn't start the game: ${message.error}`);
Deno.exit(1);
break;
case "send": {
const socket = sockets.get(message.conn);
if (socket?.readyState === WebSocket.OPEN) {
@@ -63,13 +69,32 @@ game.onmessage = (event: MessageEvent<GameToHost>) => {
}
};
// what deno task build made. no index means the build failed or never ran, and the game never runs without its mods
function read_mods(): Extract<HostToGame, { type: "init" }>["mods"] {
let index: ServerModIndex;
try {
index = JSON.parse(Deno.readTextFileSync(`${SERVER_MODS_DIR}/index.json`));
} catch {
console.error(`No ${SERVER_MODS_DIR}/index.json, run deno task build first (it also reports mod errors)`);
Deno.exit(1);
}
return index.mods.map(({ listing, server }) => ({
listing,
data: JSON.parse(Deno.readTextFileSync(`${STATIC_ROOT}/${listing.data}`)),
server_code: server ? Deno.readTextFileSync(server) : undefined,
worldgen_code: listing.worldgen ? Deno.readTextFileSync(`${STATIC_ROOT}/${listing.worldgen}`) : undefined,
}));
}
game.onerror = (event) => {
console.error("Game server crashed:", event.message);
Deno.exit(1);
};
const mods = read_mods();
console.log(`Mods: ${mods.map((mod) => `${mod.listing.id} ${mod.listing.version}`).join(", ") || "none"}`);
const save = read_world();
post({ type: "init", save, default_seed: Deno.env.get("SEED") ?? crypto.randomUUID() });
post({ type: "init", save, default_seed: Deno.env.get("SEED") ?? crypto.randomUUID(), mods });
function handle_socket(socket: WebSocket) {
const conn = next_conn++;