Improve networking
This commit is contained in:
+26
-15
@@ -8,6 +8,7 @@ import type { OreJson } from "$/common/mod_data.ts";
|
||||
import { AIR_ID } from "$/common/protocol.ts";
|
||||
import { Position } from "$/common/components/position.ts";
|
||||
import type { ClientWorld } from "./client_world.ts";
|
||||
import { code_url, fetch_verified } from "./handshake.ts";
|
||||
|
||||
// what the chunk workers need to generate the same world as the server
|
||||
export const worldgen_mods: { scripts: { mod: string; url: string }[]; ores: OreJson[] } = { scripts: [], ores: [] };
|
||||
@@ -19,26 +20,36 @@ export function set_mods_world(client_world: ClientWorld) {
|
||||
world = client_world;
|
||||
}
|
||||
|
||||
export async function load_client_mods(listings: ModListing[]) {
|
||||
const site = new URL("/", location.href);
|
||||
|
||||
const datas = await Promise.all(listings.map(async (listing) => {
|
||||
const response = await fetch(new URL(listing.data, site));
|
||||
if (!response.ok) {
|
||||
throw new ModLoadError(listing.id, `couldn't download its data (${response.status})`);
|
||||
}
|
||||
return { id: listing.id, data: await response.json() as ModData };
|
||||
// downloads every mod's files and checks them against the hashes the server listed, then registers the data and
|
||||
// runs the client scripts. everything a mod runs is imported from the checked bytes, never fetched twice
|
||||
export async function load_client_mods(listings: ModListing[], base: URL) {
|
||||
const downloads = await Promise.all(listings.map(async (listing) => {
|
||||
const get = async (path: string | undefined, sha256: string | undefined, what: string) => {
|
||||
if (!path) return undefined;
|
||||
try {
|
||||
return await fetch_verified(new URL(path, base), sha256 ?? "", what);
|
||||
} catch (e) {
|
||||
throw new ModLoadError(listing.id, (e as Error).message);
|
||||
}
|
||||
};
|
||||
const [data, client, worldgen] = await Promise.all([
|
||||
get(listing.data, listing.sha256.data, "its data"),
|
||||
get(listing.client, listing.sha256.client, "its client script"),
|
||||
get(listing.worldgen, listing.sha256.worldgen, "its worldgen script"),
|
||||
]);
|
||||
return { listing, data: JSON.parse(new TextDecoder().decode(data)) as ModData, client, worldgen };
|
||||
}));
|
||||
const recipes = register_mod_data(datas);
|
||||
|
||||
const recipes = register_mod_data(downloads.map(({ listing, data }) => ({ id: listing.id, data })));
|
||||
|
||||
worldgen_mods.ores = recipes.ores;
|
||||
worldgen_mods.scripts = listings.flatMap((listing) =>
|
||||
listing.worldgen ? [{ mod: listing.id, url: new URL(listing.worldgen, site).href }] : []
|
||||
worldgen_mods.scripts = downloads.flatMap(({ listing, worldgen }) =>
|
||||
worldgen ? [{ mod: listing.id, url: code_url(worldgen) }] : []
|
||||
);
|
||||
|
||||
for (const listing of listings) {
|
||||
if (!listing.client) continue;
|
||||
const module = await import(new URL(listing.client, site).href);
|
||||
for (const { listing, client } of downloads) {
|
||||
if (!client) continue;
|
||||
const module = await import(code_url(client));
|
||||
if (typeof module.setup !== "function") {
|
||||
throw new ModLoadError(listing.id, "the client script doesn't export a setup function");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user