nc-planner/scripts/files.js

119 lines
3.8 KiB
JavaScript

import { awaitEvent, emitEvent, listenTo } from "./events.js";
import { findFullEntry, stripEntryToMinimums } from "./ncpf-utils.js";
import { getPlannerMultiblockSize, getPlannerMultiblockType, loadPlanner, readPlannerTiles } from "./planner.js";
import { getAtlasIndexFromMetadata, getAtlasMetadata } from "./atlas.js";
import { resetSolver } from "./solver.js";
import { registerLoadCallback } from "./main.js";
registerLoadCallback(() => {
listenTo("file:load", () => showOpenFileDialog());
listenTo("file:new", () => {});
listenTo("file:save", () => saveFile("test"));
});
export function showOpenFileDialog() {
const input = document.createElement("input");
input.type = "file";
input.accept = ".ncpf.json";
input.addEventListener("change", async () => {
const data = await new Promise(resolve => {
const reader = new FileReader();
reader.addEventListener("load", () => {
resolve(JSON.parse(reader.result));
});
reader.readAsText(input.files[0]);
});
void loadFile(data);
});
input.click();
}
export async function loadExampleFile(filename) {
const data = await fetch(`./examples/${filename}.ncpf.json`)
.then(data => data.json());
return loadFile(data);
}
export async function loadFile(data) {
console.log(data);
if (!data.designs) throw new Error("invalid file");
if (data.designs.length === 0) throw new Error("no designs");
let design = data.designs[0];
if (data.designs.length > 1) {
const prepChoice = awaitEvent("fileLoad:chooseDesign:choice");
emitEvent("fileLoad:chooseDesign", data);
const res = await prepChoice;
design = data.designs[res.detail];
}
if (!design) throw new Error("no design");
const blocks = data.configuration[design.type].blocks
.map(block => getAtlasIndexFromMetadata(block, design.type, "blocks"));
const designWithAtlas = design.design.map(a => a.map(b => b.map(c => c === -1 ? -1 : blocks[c])));
loadPlanner(design.dimensions, design.type, designWithAtlas);
resetSolver(design);
}
export async function saveFile(name) {
const multiblockType = getPlannerMultiblockType();
const designAsAtlas = readPlannerTiles();
const designBlocksAtlasMap = Object.fromEntries(
[...new Set(designAsAtlas.flat(3))]
.filter(v => v !== -1)
.sort((a, b) => a - b)
.map((ai, di) => [ ai, { ...getAtlasMetadata(ai), designIndex: di } ])
);
const designAsBlocks = designAsAtlas
.map(xPlane => xPlane
.map(yRow => yRow.map(atlasIndex => designBlocksAtlasMap[atlasIndex]))
);
const designAsBlockIndices = designAsBlocks
.map(xPlane => xPlane.map(yRow => yRow.map(b => b?.designIndex ?? -1)));
const designBlocksWithRecipes = designAsBlocks
.map(xPlane => xPlane
.map(yRow => yRow
.map(block => {
if (!block) return;
return findFullEntry("blocks", block, { configurationHint: multiblockType });
})
.filter(b => b && b.modules && "ncpf:block_recipes" in b.modules)
)
.filter(r => r.length > 0)
)
.filter(p => p.length > 0);
console.log("designBlocksWithRecipes", designBlocksWithRecipes)
const minimizedBlocks = Object.entries(designBlocksAtlasMap)
.sort(([a], [b]) => a - b)
.map(([, m]) => stripEntryToMinimums(m));
const data = {
addons: [],
configurations: {
[multiblockType]: {
blocks: minimizedBlocks,
coolant_recipes: [], // FIXME
},
},
designs: [
{
block_recipes: [], // FIXME
coolant_recipe: 0, // FIXME
design: designAsBlockIndices,
dimensions: getPlannerMultiblockSize(),
type: multiblockType,
},
],
version: 1,
};
console.log(designBlocksAtlasMap);
console.log(data);
}