diff --git a/packages/lib/factorio/export.js b/packages/lib/factorio/export.js index 093e9be3..2e71dd08 100644 --- a/packages/lib/factorio/export.js +++ b/packages/lib/factorio/export.js @@ -90,7 +90,16 @@ async function loadFile(server, modVersions, modPath) { } } - let zip = await loadZip(server, modVersions, mod); + let zip; + try { + zip = await loadZip(server, modVersions, mod); + } catch (err) { + if (err.code === "ENOENT") { + return null; + } + throw err; + } + let file = zip.file(filePath); if (!file) { return null; @@ -310,7 +319,15 @@ async function exportLocale(server, modVersions, modOrder, languageCode) { continue; } - let zip = await loadZip(server, modVersions, mod); + let zip; + try { + zip = await loadZip(server, modVersions, mod); + } catch (err) { + if (err.code === "ENOENT") { + continue; + } + throw err; + } for (let file of zip.file(new RegExp(`locale\\/${languageCode}\\/.*\\.cfg`))) { let content = await file.async("nodebuffer"); mergeLocale(ini.parse(content.toString("utf8"))); @@ -357,6 +374,28 @@ async function exportData(server) { throw new Error("No items got exported"); } + // Some mod authors put leading zeros into the versions of their zip files. + let splitter = /^(.*)_(\d+)\.(\d+)\.(\d+)\.zip?$/; + for (let entry of await fs.readdir(server.writePath("mods"))) { + let match = splitter.exec(entry); + if (!match) { + continue; + } + + let modVersion = `${match[2]}.${match[3]}.${match[4]}`; + let normalizedVersion = + `${Number.parseInt(match[2], 10)}.${Number.parseInt(match[3], 10)}.${Number.parseInt(match[4], 10)}` + ; + + if (modVersion === normalizedVersion) { + continue; + } + + if (modVersions.get(match[1]) === normalizedVersion) { + modVersions.set(match[1], modVersion); + } + } + let { iconSheet, itemData } = await exportItems(server, modVersions, items); let locale = await exportLocale(server, modVersions, modOrder, "en"); diff --git a/packages/lib/factorio/server.js b/packages/lib/factorio/server.js index d61b49c9..5b08447a 100644 --- a/packages/lib/factorio/server.js +++ b/packages/lib/factorio/server.js @@ -605,7 +605,11 @@ class FactorioServer extends events.EventEmitter { let type = line.slice(channelEnd + 1, channelEnd + 2).toString("utf-8"); let content; if (type === "j") { - content = JSON.parse(line.slice(channelEnd + 2).toString("utf-8")); + try { + content = JSON.parse(line.slice(channelEnd + 2).toString("utf-8")); + } catch (err) { + throw new Error(`Malformed JSON to ${channel}: ${line.slice(channelEnd + 2).toString("utf-8")}`); + } } else if (type === "f") { let fileName = line.slice(channelEnd + 2).toString("utf-8"); diff --git a/packages/slave/lua/export/data-final-fixes.lua b/packages/slave/lua/export/data-final-fixes.lua index c4f0e7d3..335ac5c1 100644 --- a/packages/slave/lua/export/data-final-fixes.lua +++ b/packages/slave/lua/export/data-final-fixes.lua @@ -46,11 +46,14 @@ end -- no game.table_to_json here :( local function table_to_json(data) if type(data) == "number" then + if data == math.huge then return "1e500" end -- Inf is not representable in JSON, but 1e500 will overflow to it. + if data == -math.huge then return "-1e500" end + if data ~= data then return "0" end -- NaN is not representable in JSON, treat as 0 instead. return string.format("%.17g", data) elseif type(data) == "string" then data = data:gsub('([\x00-\x1f\\"])', function(match) - return "\\x" .. string.format("%02x", match:byte()) + return "\\u00" .. string.format("%02x", match:byte()) end) return '"' .. data .. '"'