79 lines
3.0 KiB
TypeScript
79 lines
3.0 KiB
TypeScript
import { resolve, toFileUrl } from "@std/path";
|
|
import { EverythingRegistry } from "$/common/everything_registry.ts";
|
|
import { load_and_check, load_order } from "$/tools/check_mods.ts";
|
|
import type { ServerModSource } from "$/server/game/load_mods.ts";
|
|
import { GameServer } from "$/server/game/game_server.ts";
|
|
import { start_game } from "$/server/game/load_mods.ts";
|
|
import { PROTOCOL_VERSION } from "$/common/protocol.ts";
|
|
|
|
// mods straight from their source folders, skipping the build: scripts are imported as typescript
|
|
export function mod_sources(mods_dir: string): ServerModSource[] {
|
|
const mods = load_and_check(mods_dir);
|
|
const errors = mods.flatMap((mod) => mod.report.errors.map((e) => `${mod.id}: ${e}`));
|
|
if (errors.length) throw new Error(errors.join("\n"));
|
|
return load_order(mods).map((mod) => {
|
|
const scripts = (mod.manifest?.scripts ?? {}) as Record<string, string>;
|
|
const url = (path?: string) => path ? toFileUrl(resolve(mod.dir, path)).href : undefined;
|
|
return {
|
|
listing: {
|
|
id: mod.id,
|
|
name: String(mod.manifest?.name),
|
|
version: String(mod.manifest?.version),
|
|
hash: "source",
|
|
data: `mods/${mod.id}/source/data.json`,
|
|
sha256: { data: "" },
|
|
},
|
|
data: {
|
|
blocks: mod.blocks.map((b) => b.json),
|
|
items: mod.items.map((i) => i.json),
|
|
recipes: mod.recipes.map((r) => r.json),
|
|
ores: mod.ores.map((o) => o.json),
|
|
},
|
|
server_url: url(scripts.server),
|
|
worldgen_url: url(scripts.worldgen),
|
|
};
|
|
});
|
|
}
|
|
|
|
// a game with an in memory host that remembers what it sent to each connection
|
|
export async function test_game(mods_dir: string, save?: string, seed = "test-seed") {
|
|
EverythingRegistry.clear();
|
|
const outbox = new Map<number, unknown[]>();
|
|
const closed = new Set<number>();
|
|
const host = {
|
|
send: (conn: number, data: string) => {
|
|
if (!outbox.has(conn)) outbox.set(conn, []);
|
|
outbox.get(conn)!.push(JSON.parse(data));
|
|
},
|
|
close(conn: number) {
|
|
closed.add(conn);
|
|
},
|
|
};
|
|
const atlas = { png: "atlas.png", json: "atlas.json", sha256: { png: "", json: "" } };
|
|
const game: GameServer = await start_game(host, save, seed, atlas, mod_sources(mods_dir));
|
|
// deno-lint-ignore no-explicit-any
|
|
const take = (conn: number): any[] => {
|
|
const messages = outbox.get(conn) ?? [];
|
|
outbox.set(conn, []);
|
|
return messages;
|
|
};
|
|
const send = (conn: number, message: unknown) => game.on_message(conn, JSON.stringify(message));
|
|
// the whole handshake: hello, welcome, ready, join. returns join
|
|
const join = (conn: number, name: string) => {
|
|
game.on_connect(conn);
|
|
send(conn, { type: "hello", name, protocol: PROTOCOL_VERSION });
|
|
send(conn, { type: "ready" });
|
|
return take(conn).find((m) => m.type === "join");
|
|
};
|
|
return { game, take, send, join, closed };
|
|
}
|
|
|
|
export function copy_dir(from: string, to: string) {
|
|
if (Deno.statSync(from).isDirectory) {
|
|
Deno.mkdirSync(to, { recursive: true });
|
|
for (const entry of Deno.readDirSync(from)) copy_dir(`${from}/${entry.name}`, `${to}/${entry.name}`);
|
|
} else {
|
|
Deno.copyFileSync(from, to);
|
|
}
|
|
}
|