Files
bworld/server/game/load_mods.ts
T
2026-09-24 23:49:34 -03:00

60 lines
1.9 KiB
TypeScript

// starts a game server with its mods: registers their data, then imports worldgen and server scripts.
// the worker loads built mods, tests can load mods straight from their source folders
import { register_mod_data } from "$/common/mod_loader.ts";
import type { ModData, ModListing } from "$/common/mod_loader.ts";
import { load_worldgen } from "$/common/worldgen_loader.ts";
import { add_base_item_hooks } from "./blocks.ts";
import { GameHost, GameServer } from "./game_server.ts";
import { ModRuntime } from "./mod_runtime.ts";
export interface ServerModSource {
listing: ModListing;
data: ModData;
// importable urls of the scripts: data: urls in the worker, file urls in tests
server_url?: string;
worldgen_url?: string;
}
export async function start_game(
host: GameHost,
save: string | undefined,
default_seed: string,
mods: ServerModSource[],
): Promise<GameServer> {
const recipes = register_mod_data(mods.map((mod) => ({ id: mod.listing.id, data: mod.data })));
add_base_item_hooks();
const worldgen_scripts = mods.flatMap((mod) =>
mod.worldgen_url ? [{ mod: mod.listing.id, url: mod.worldgen_url }] : []
);
const worldgen = await load_worldgen(worldgen_scripts, recipes.ores);
const runtime = new ModRuntime();
const game = new GameServer(host, save, default_seed, {
listings: mods.map((mod) => mod.listing),
recipes,
worldgen,
runtime,
});
await runtime.load_scripts(
game,
mods.flatMap((mod) =>
mod.server_url ? [{ mod: mod.listing.id, version: mod.listing.version, url: mod.server_url }] : []
),
);
runtime.finish_setup();
runtime.after.server_start.emit({});
return game;
}
export function data_url(code: string) {
const bytes = new TextEncoder().encode(code);
let binary = "";
for (let i = 0; i < bytes.length; i += 0x8000) {
binary += String.fromCharCode(...bytes.subarray(i, i + 0x8000));
}
return `data:application/javascript;base64,${btoa(binary)}`;
}