Implement main game as a mod
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
// 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;
|
||||
}
|
||||
Reference in New Issue
Block a user