Skip to content

Commit 26862d1

Browse files
committed
fix(data): support Factorio 2.1 prototype dumps
1 parent 3063f3c commit 26862d1

4 files changed

Lines changed: 50 additions & 6 deletions

File tree

app/src/db/import-factorio.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,28 @@ const runImport = (raw: Record<string, unknown>) => {
2727
return new Database(fx.file, { readonly: true });
2828
};
2929

30+
describe("importFactorioDump — recipe categories", () => {
31+
it("imports Factorio 2.1 categories with 2.0 and engine-default fallbacks", () => {
32+
const db = runImport({
33+
recipe: {
34+
soil: { categories: ["soil-extraction"], results: [] },
35+
legacy: { category: "smelting", results: [] },
36+
defaulted: { results: [] },
37+
},
38+
});
39+
const rows = db.prepare(`SELECT name, category FROM recipes ORDER BY name`).all() as {
40+
name: string;
41+
category: string;
42+
}[];
43+
expect(rows).toEqual([
44+
{ name: "defaulted", category: "crafting" },
45+
{ name: "legacy", category: "smelting" },
46+
{ name: "soil", category: "soil-extraction" },
47+
]);
48+
db.close();
49+
});
50+
});
51+
3052
// Fixture values are a real slice of the Py dump (data-raw-dump.json):
3153
// technology.microfilters grants change-recipe-productivity fawogae-spore +0.15
3254
// and navens-spore +0.4; technology.mining-productivity-1 grants

app/src/db/import-factorio.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ const jsonList = (x: unknown): string | null => {
8484
return a.length ? JSON.stringify(a) : null;
8585
};
8686

87+
/** Factorio 2.1 dumps recipe `categories` as a one-element array; 2.0 used the
88+
* singular `category`. Recipes without either field use the engine default. */
89+
const recipeCategory = (r: Record<string, unknown>): string =>
90+
arr<string>(r.categories)[0] ?? (r.category as string | undefined) ?? "crafting";
91+
8792
const TABLES = [
8893
"recipe_ingredients",
8994
"recipe_products",
@@ -262,7 +267,7 @@ export function importFactorioDump(
262267
(mainProduct ? productDisplay[mainProduct] : undefined) ??
263268
null,
264269
kind: "real",
265-
category: r.category ?? "crafting",
270+
category: recipeCategory(r),
266271
energy_required: r.energy_required ?? 0.5,
267272
enabled: r.enabled === false ? 0 : 1,
268273
hidden: r.hidden ? 1 : 0,

app/src/server/dump.server.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ const HELPER_INFO = {
5151
version: "0.1.0",
5252
title: "PyOps dump helper",
5353
author: "PyOps",
54-
factorio_version: "2.0",
54+
factorio_version: "2.1",
5555
description:
5656
"Enables pypostprocessing's planner (YAFC) integration during data dumps so TURD sub-techs and planner-friendly prototypes land in data-raw-dump.json. Enable ONLY while dumping - do not play with this mod active.",
5757
dependencies: ["? pypostprocessing"],
@@ -64,6 +64,18 @@ const HELPER_DATA_LUA = `-- pypostprocessing's data-final-fixes checks this mark
6464
data.data_crawler = "yafc pyops"
6565
`;
6666

67+
const HELPER_DATA_UPDATES_LUA = `-- yafc.lua resets these globals before requiring their prototype modules again.
68+
-- Factorio 2.1 keeps the modules cached, so the second require otherwise leaves
69+
-- the reset tables empty and the planner integration crashes while iterating them.
70+
for name in pairs(package.loaded) do
71+
if string.find(name, "/scripts/digosaurus/digosaurus-prototypes", 1, true)
72+
or string.find(name, "/scripts/biofluid/biofluid-prototypes", 1, true)
73+
or string.find(name, "/prototypes/turd", 1, true) then
74+
package.loaded[name] = nil
75+
end
76+
end
77+
`;
78+
6779
const HELPER_FINAL_FIXES_LUA = `-- pypostprocessing's yafc.lua was written for YAFC's lenient Lua crawler; the
6880
-- real engine validates prototypes. Patch up anything it left incomplete.
6981
-- This mod is dump-only: never play with it enabled.
@@ -226,6 +238,7 @@ export async function writeHelperMod() {
226238
await mkdir(dir, { recursive: true });
227239
await writeFile(join(dir, "info.json"), JSON.stringify(HELPER_INFO, null, 2));
228240
await writeFile(join(dir, "data.lua"), HELPER_DATA_LUA);
241+
await writeFile(join(dir, "data-updates.lua"), HELPER_DATA_UPDATES_LUA);
229242
await writeFile(join(dir, "data-final-fixes.lua"), HELPER_FINAL_FIXES_LUA);
230243
}
231244

docs/data-pipeline.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ orchestrated end-to-end from **Settings › Game data** in the UI
1919
4. **Import** the dump into SQLite (`app/src/db/import-factorio.ts`), then
2020
synthesize the recipes the engine doesn't model as recipes: mining, boiling,
2121
burning, spoiling, planting (agricultural towers), rocket launches, and
22-
per-temperature fluid variants (`app/src/db/synthesize.ts`).
22+
per-temperature fluid variants (`app/src/db/synthesize.ts`). Recipe categories
23+
come from Factorio 2.1's `categories` array, with the singular 2.0 `category`
24+
field retained as an import fallback.
2325
5. **Rebuild the icon atlas** (`buildIconAtlas`, `app/src/server/icon-atlas.ts`):
2426
pack the dumped sprites into content-hash-deduped 4096² sheets + a
2527
`(type, name) → slot` manifest, written to the data dir's `icon-data/`. The app
@@ -100,9 +102,11 @@ and then repairs the fallout so a real `--dump-data` run succeeds: it normalizes
100102
1.x-style `result =` recipes, fills in missing icons and fluid-box volumes, drops
101103
recipes whose result item never got created (and scrubs the now-dangling
102104
`unlock-recipe` tech effects), and rebuilds TURD sub-tech unlock effects that the
103-
integration leaves empty. It's strictly a dump-time tool — `dump.server.ts` enables it,
104-
runs the dumps, and disables it again in a `finally` block so it never lingers for
105-
normal play.
105+
integration leaves empty. On Factorio 2.1 it also evicts the Py modules that the
106+
integration intentionally re-runs after resetting their globals, avoiding stale
107+
`require` cache results. It's strictly a dump-time tool — `dump.server.ts` enables
108+
it, runs the dumps, and disables it again in a `finally` block so it never lingers
109+
for normal play.
106110

107111
## Data model notes
108112

0 commit comments

Comments
 (0)