90 lines
2.4 KiB
TypeScript
90 lines
2.4 KiB
TypeScript
// registers mods' data, the same way on the server and on clients
|
|
import { BlockRegistry, EverythingRegistry, ItemRegistry } from "./everything_registry.ts";
|
|
import {
|
|
block_from_json,
|
|
BlockJson,
|
|
grid_recipe_from_json,
|
|
GridRecipe,
|
|
item_from_json,
|
|
ItemJson,
|
|
OreJson,
|
|
RecipeJson,
|
|
} from "./mod_data.ts";
|
|
import { register_block_item } from "./utils.ts";
|
|
|
|
// everything a mod's json files hold, merged into one file by the build (build/mods/<id>/<hash>/data.json)
|
|
export interface ModData {
|
|
blocks: BlockJson[];
|
|
items: ItemJson[];
|
|
recipes: RecipeJson[];
|
|
ores: OreJson[];
|
|
}
|
|
|
|
// a mod as the server lists it to clients, in load order. paths are relative to the site root
|
|
export interface ModListing {
|
|
id: string;
|
|
name: string;
|
|
version: string;
|
|
hash: string;
|
|
data: string;
|
|
client?: string;
|
|
worldgen?: string;
|
|
}
|
|
|
|
export class RecipeBook {
|
|
shaped: GridRecipe[] = [];
|
|
furnace = new Map<string, { output: { id: string; count: number }; cook_time: number }>();
|
|
fuel = new Map<string, number>();
|
|
ores: OreJson[] = [];
|
|
}
|
|
|
|
export class ModLoadError extends Error {
|
|
constructor(mod: string, message: string) {
|
|
super(`${mod}: ${message}`);
|
|
this.name = "ModLoadError";
|
|
}
|
|
}
|
|
|
|
// registers every mod's blocks, items and recipes, in the order given (dependencies first)
|
|
export function register_mod_data(mods: { id: string; data: ModData }[]): RecipeBook {
|
|
const recipes = new RecipeBook();
|
|
|
|
for (const { id, data } of mods) {
|
|
const fail = (message: string): never => {
|
|
throw new ModLoadError(id, message);
|
|
};
|
|
try {
|
|
for (const json of data.blocks) {
|
|
const { block, has_item } = block_from_json(json);
|
|
EverythingRegistry.register<BlockRegistry>("blocks", block.id, block);
|
|
if (has_item) {
|
|
register_block_item(block);
|
|
}
|
|
}
|
|
for (const json of data.items) {
|
|
EverythingRegistry.register<ItemRegistry>("items", json.id, item_from_json(json));
|
|
}
|
|
} catch (e) {
|
|
fail((e as Error).message);
|
|
}
|
|
|
|
for (const recipe of data.recipes) {
|
|
switch (recipe.type) {
|
|
case "shaped":
|
|
recipes.shaped.push(grid_recipe_from_json(recipe));
|
|
break;
|
|
case "furnace":
|
|
if (recipes.furnace.has(recipe.input)) fail(`two furnace recipes for ${recipe.input}`);
|
|
recipes.furnace.set(recipe.input, { output: recipe.output, cook_time: recipe.cook_time });
|
|
break;
|
|
case "fuel":
|
|
recipes.fuel.set(recipe.item, recipe.burn_time);
|
|
break;
|
|
}
|
|
}
|
|
recipes.ores.push(...data.ores);
|
|
}
|
|
|
|
return recipes;
|
|
}
|