86 lines
3.2 KiB
TypeScript
86 lines
3.2 KiB
TypeScript
// deno task export-bworld
|
|
// writes the base game's blocks, items and recipes into mods/bworld as json, from what the game registers now.
|
|
// the game still loads the typescript definitions until the mod loader exists (phase 1 in MODS.md),
|
|
// so run this again after changing them. tests/bworld_mod_test.ts fails when the two drift apart
|
|
import "$/common/blocks/mod.ts";
|
|
import "$/common/items/mod.ts";
|
|
import { BlockRegistry, EverythingRegistry, ItemRegistry } from "$/common/everything_registry.ts";
|
|
import { block_to_json, grid_recipe_to_json, item_to_json, RecipeJson } from "$/common/mod_data.ts";
|
|
import { CRAFTING_RECIPES } from "$/server/game/crafting.ts";
|
|
import { FUEL_VALUES, FURNACE_RECIPES } from "$/server/game/blocks.ts";
|
|
|
|
const MOD_DIR = "mods/bworld";
|
|
const DATA_FOLDERS = ["blocks", "items", "recipes"];
|
|
|
|
function name_of(id: string) {
|
|
return id.split(":")[1];
|
|
}
|
|
|
|
// everything the base game registers, as the json files mods/bworld should contain
|
|
export function bworld_data_files(): { path: string; content: unknown }[] {
|
|
const files: { path: string; content: unknown }[] = [];
|
|
const add = (folder: string, name: string, key: string, content: unknown) =>
|
|
files.push({ path: `${folder}/${name}.json`, content: { format_version: 1, [key]: content } });
|
|
|
|
const items = new Map(EverythingRegistry.entries<ItemRegistry>("items"));
|
|
|
|
for (const [id, block] of EverythingRegistry.entries<BlockRegistry>("blocks")) {
|
|
const has_item = items.get(id)?.block_id === id;
|
|
add("blocks", name_of(id), "block", block_to_json(block, has_item));
|
|
}
|
|
|
|
for (const [id, item] of items) {
|
|
// block items come from their block's "item" field
|
|
if (item.block_id === undefined) {
|
|
add("items", name_of(id), "item", item_to_json(id, item));
|
|
}
|
|
}
|
|
|
|
for (const recipe of CRAFTING_RECIPES) {
|
|
add("recipes", `crafting_${name_of(recipe.result.id)}`, "recipe", grid_recipe_to_json(recipe));
|
|
}
|
|
for (const recipe of FURNACE_RECIPES) {
|
|
add(
|
|
"recipes",
|
|
`smelting_${name_of(recipe.input)}`,
|
|
"recipe",
|
|
{
|
|
type: "furnace",
|
|
input: recipe.input,
|
|
output: { id: recipe.output.type_id, count: recipe.output.amount },
|
|
cook_time: recipe.cook_time,
|
|
} satisfies RecipeJson,
|
|
);
|
|
}
|
|
for (const [item, burn_time] of Object.entries(FUEL_VALUES)) {
|
|
add("recipes", `fuel_${name_of(item)}`, "recipe", { type: "fuel", item, burn_time } satisfies RecipeJson);
|
|
}
|
|
|
|
return files;
|
|
}
|
|
|
|
if (import.meta.main) {
|
|
for (const folder of DATA_FOLDERS) {
|
|
try {
|
|
Deno.removeSync(`${MOD_DIR}/${folder}`, { recursive: true });
|
|
} catch (e) {
|
|
if (!(e instanceof Deno.errors.NotFound)) throw e;
|
|
}
|
|
Deno.mkdirSync(`${MOD_DIR}/${folder}`, { recursive: true });
|
|
}
|
|
|
|
const files = bworld_data_files();
|
|
for (const { path, content } of files) {
|
|
Deno.writeTextFileSync(`${MOD_DIR}/${path}`, JSON.stringify(content, null, "\t") + "\n");
|
|
}
|
|
|
|
// match the repo's formatting so reruns don't show up as changes
|
|
await new Deno.Command(Deno.execPath(), { args: ["fmt", "--quiet", ...DATA_FOLDERS.map((f) => `${MOD_DIR}/${f}`)] })
|
|
.output();
|
|
|
|
const count = (folder: string) => files.filter((f) => f.path.startsWith(`${folder}/`)).length;
|
|
console.log(
|
|
`Wrote ${count("blocks")} blocks, ${count("items")} items and ${count("recipes")} recipes to ${MOD_DIR}`,
|
|
);
|
|
}
|