// 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 { 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)}`; }