factorio-save-parser 1.0.8 → 1.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -93,6 +93,7 @@ function parseLevelInitData(data) {
93
93
  major,
94
94
  minor,
95
95
  patch,
96
+ asString: `${major}.${minor}.${patch}`,
96
97
  };
97
98
  }
98
99
  // Single Unused byte
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../out/errors.js","../out/parser.js"],"sourcesContent":["export class InvalidArgumentError extends Error {\n constructor(message) {\n super(message);\n this.name = 'InvalidArgumentError';\n Object.setPrototypeOf(this, InvalidArgumentError.prototype);\n }\n}\nexport class InvalidSaveFileError extends Error {\n constructor(message) {\n super(message);\n this.name = 'InvalidSaveFileError';\n Object.setPrototypeOf(this, InvalidSaveFileError.prototype);\n }\n}\n//# sourceMappingURL=errors.js.map","import path from 'node:path';\nimport { compare as compareVersions } from 'compare-versions';\nimport unzipper from 'unzipper';\nimport { InvalidArgumentError, InvalidSaveFileError } from './errors';\n// Written with the help of the information on https://forums.factorio.com/viewtopic.php?t=47014\nexport function parseLevelInitData(data) {\n let bytesOffset = 0;\n function readUint8() {\n // console.log(`readUint8() at offset ${bytesOffset.toString(16)}`);\n const value = data.getUint8(bytesOffset);\n bytesOffset += 1;\n return value;\n }\n function readUint16() {\n // console.log(`readUint16() at offset ${bytesOffset.toString(16)}`);\n const value = data.getUint16(bytesOffset, true);\n bytesOffset += 2;\n return value;\n }\n function readUint32() {\n // console.log(`readUint32() at offset ${bytesOffset.toString(16)}`);\n const value = data.getUint32(bytesOffset, true);\n bytesOffset += 4;\n return value;\n }\n function readBoolean() {\n return readUint8() !== 0;\n }\n function readVersion() {\n const major = readUint16();\n const minor = readUint16();\n const patch = readUint16();\n const build = readUint16();\n return {\n major,\n minor,\n patch,\n build,\n // 4-number versions officially supported by compare-versions\n asString: `${major}.${minor}.${patch}.${build}`,\n };\n }\n // Read Factorio Version\n const factorioVersion = readVersion();\n function readOptimizedUint(bitSize) {\n /* console.log('readOptimizedUint()', {\n bitSize,\n }); */\n if (compareVersions(factorioVersion.asString, '0.14.14', '>')) {\n const value = readUint8();\n if (value !== 0xff) {\n return value;\n }\n }\n switch (bitSize) {\n case 16:\n return readUint16();\n case 32:\n return readUint32();\n default:\n throw new Error(`Invalid bit size: ${bitSize}`);\n }\n }\n // has_empty_indicator=false\n function readString() {\n const length = readOptimizedUint(32);\n const bufferSlice = data.buffer.slice(bytesOffset, bytesOffset + length);\n bytesOffset += length;\n return new TextDecoder().decode(bufferSlice);\n }\n function readVersion48() {\n const major = readOptimizedUint(16);\n const minor = readOptimizedUint(16);\n const patch = readOptimizedUint(16);\n return {\n major,\n minor,\n patch,\n };\n }\n // Single Unused byte\n readBoolean();\n // Read fields\n const name = readString();\n const campaign = readString();\n const baseMod = readString();\n const difficulty = readUint8();\n const finished = readBoolean();\n const playerWon = readBoolean();\n const nextLevel = readString();\n const canContinue = readBoolean();\n const finishedButContinuing = readBoolean();\n const savingReplay = readBoolean();\n const allowNonAdminDebugOptions = readBoolean();\n const loadedFrom = readVersion48();\n const loadedFromBuild = factorioVersion.major >= 2 ? readUint32() : readUint16();\n const allowedCommands = readBoolean();\n // 2.0 has a new header with 4 extra bytes here\n if (factorioVersion.major >= 2) {\n readUint8();\n readUint8();\n readUint8();\n readUint8();\n }\n const numMods = readOptimizedUint(32);\n const mods = [];\n for (let i = 0; i < numMods; i++) {\n mods.push({\n name: readString(),\n version: readVersion48(),\n crc: readUint32(),\n });\n }\n return {\n factorioVersion,\n name,\n campaign,\n baseMod,\n difficulty,\n finished,\n playerWon,\n nextLevel,\n canContinue,\n finishedButContinuing,\n savingReplay,\n allowNonAdminDebugOptions,\n loadedFrom,\n loadedFromBuild,\n allowedCommands,\n mods,\n };\n}\nexport async function parseSaveFile(filepath) {\n let centralDirectory;\n let levelInitDatName = '';\n try {\n const normalizedPath = path.normalize(filepath);\n const resolvedPath = path.resolve(normalizedPath);\n const fileExtension = path.extname(filepath);\n const filename = path.basename(filepath).replace(fileExtension, '');\n // if zip file is called _autosave1.zip, make levelInitDatName contain _autosave1\n levelInitDatName = `${filename}/level-init.dat`;\n // if file does not end with .zip, it's likely not valid\n if (fileExtension !== '.zip') {\n throw new InvalidArgumentError('File path is not a zip file.');\n }\n centralDirectory = await unzipper.Open.file(resolvedPath);\n }\n catch (e) {\n // eslint-disable-next-line no-console\n console.error(e);\n return undefined;\n }\n const file = centralDirectory.files.find(f => f.path === levelInitDatName);\n if (!file) {\n throw new InvalidSaveFileError('File does not appear to be a save file');\n }\n const levelInitDatContent = await file?.buffer();\n if (levelInitDatContent === null) {\n throw new InvalidSaveFileError('Unable to find level-init.dat in save file');\n }\n const binaryData = new DataView(levelInitDatContent.buffer);\n return parseLevelInitData(binaryData);\n}\n//# sourceMappingURL=parser.js.map"],"names":["compareVersions"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../out/errors.js","../out/parser.js"],"sourcesContent":["export class InvalidArgumentError extends Error {\n constructor(message) {\n super(message);\n this.name = 'InvalidArgumentError';\n Object.setPrototypeOf(this, InvalidArgumentError.prototype);\n }\n}\nexport class InvalidSaveFileError extends Error {\n constructor(message) {\n super(message);\n this.name = 'InvalidSaveFileError';\n Object.setPrototypeOf(this, InvalidSaveFileError.prototype);\n }\n}\n//# sourceMappingURL=errors.js.map","import path from 'node:path';\nimport { compare as compareVersions } from 'compare-versions';\nimport unzipper from 'unzipper';\nimport { InvalidArgumentError, InvalidSaveFileError } from './errors';\n// Written with the help of the information on https://forums.factorio.com/viewtopic.php?t=47014\nexport function parseLevelInitData(data) {\n let bytesOffset = 0;\n function readUint8() {\n // console.log(`readUint8() at offset ${bytesOffset.toString(16)}`);\n const value = data.getUint8(bytesOffset);\n bytesOffset += 1;\n return value;\n }\n function readUint16() {\n // console.log(`readUint16() at offset ${bytesOffset.toString(16)}`);\n const value = data.getUint16(bytesOffset, true);\n bytesOffset += 2;\n return value;\n }\n function readUint32() {\n // console.log(`readUint32() at offset ${bytesOffset.toString(16)}`);\n const value = data.getUint32(bytesOffset, true);\n bytesOffset += 4;\n return value;\n }\n function readBoolean() {\n return readUint8() !== 0;\n }\n function readVersion() {\n const major = readUint16();\n const minor = readUint16();\n const patch = readUint16();\n const build = readUint16();\n return {\n major,\n minor,\n patch,\n build,\n // 4-number versions officially supported by compare-versions\n asString: `${major}.${minor}.${patch}.${build}`,\n };\n }\n // Read Factorio Version\n const factorioVersion = readVersion();\n function readOptimizedUint(bitSize) {\n /* console.log('readOptimizedUint()', {\n bitSize,\n }); */\n if (compareVersions(factorioVersion.asString, '0.14.14', '>')) {\n const value = readUint8();\n if (value !== 0xff) {\n return value;\n }\n }\n switch (bitSize) {\n case 16:\n return readUint16();\n case 32:\n return readUint32();\n default:\n throw new Error(`Invalid bit size: ${bitSize}`);\n }\n }\n // has_empty_indicator=false\n function readString() {\n const length = readOptimizedUint(32);\n const bufferSlice = data.buffer.slice(bytesOffset, bytesOffset + length);\n bytesOffset += length;\n return new TextDecoder().decode(bufferSlice);\n }\n function readVersion48() {\n const major = readOptimizedUint(16);\n const minor = readOptimizedUint(16);\n const patch = readOptimizedUint(16);\n return {\n major,\n minor,\n patch,\n asString: `${major}.${minor}.${patch}`,\n };\n }\n // Single Unused byte\n readBoolean();\n // Read fields\n const name = readString();\n const campaign = readString();\n const baseMod = readString();\n const difficulty = readUint8();\n const finished = readBoolean();\n const playerWon = readBoolean();\n const nextLevel = readString();\n const canContinue = readBoolean();\n const finishedButContinuing = readBoolean();\n const savingReplay = readBoolean();\n const allowNonAdminDebugOptions = readBoolean();\n const loadedFrom = readVersion48();\n const loadedFromBuild = factorioVersion.major >= 2 ? readUint32() : readUint16();\n const allowedCommands = readBoolean();\n // 2.0 has a new header with 4 extra bytes here\n if (factorioVersion.major >= 2) {\n readUint8();\n readUint8();\n readUint8();\n readUint8();\n }\n const numMods = readOptimizedUint(32);\n const mods = [];\n for (let i = 0; i < numMods; i++) {\n mods.push({\n name: readString(),\n version: readVersion48(),\n crc: readUint32(),\n });\n }\n return {\n factorioVersion,\n name,\n campaign,\n baseMod,\n difficulty,\n finished,\n playerWon,\n nextLevel,\n canContinue,\n finishedButContinuing,\n savingReplay,\n allowNonAdminDebugOptions,\n loadedFrom,\n loadedFromBuild,\n allowedCommands,\n mods,\n };\n}\nexport async function parseSaveFile(filepath) {\n let centralDirectory;\n let levelInitDatName = '';\n try {\n const normalizedPath = path.normalize(filepath);\n const resolvedPath = path.resolve(normalizedPath);\n const fileExtension = path.extname(filepath);\n const filename = path.basename(filepath).replace(fileExtension, '');\n // if zip file is called _autosave1.zip, make levelInitDatName contain _autosave1\n levelInitDatName = `${filename}/level-init.dat`;\n // if file does not end with .zip, it's likely not valid\n if (fileExtension !== '.zip') {\n throw new InvalidArgumentError('File path is not a zip file.');\n }\n centralDirectory = await unzipper.Open.file(resolvedPath);\n }\n catch (e) {\n // eslint-disable-next-line no-console\n console.error(e);\n return undefined;\n }\n const file = centralDirectory.files.find(f => f.path === levelInitDatName);\n if (!file) {\n throw new InvalidSaveFileError('File does not appear to be a save file');\n }\n const levelInitDatContent = await file?.buffer();\n if (levelInitDatContent === null) {\n throw new InvalidSaveFileError('Unable to find level-init.dat in save file');\n }\n const binaryData = new DataView(levelInitDatContent.buffer);\n return parseLevelInitData(binaryData);\n}\n//# sourceMappingURL=parser.js.map"],"names":["compareVersions"],"mappings":"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"}
package/dist/es/index.mjs CHANGED
@@ -91,6 +91,7 @@ function parseLevelInitData(data) {
91
91
  major,
92
92
  minor,
93
93
  patch,
94
+ asString: `${major}.${minor}.${patch}`,
94
95
  };
95
96
  }
96
97
  // Single Unused byte
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../out/errors.js","../out/parser.js"],"sourcesContent":["export class InvalidArgumentError extends Error {\n constructor(message) {\n super(message);\n this.name = 'InvalidArgumentError';\n Object.setPrototypeOf(this, InvalidArgumentError.prototype);\n }\n}\nexport class InvalidSaveFileError extends Error {\n constructor(message) {\n super(message);\n this.name = 'InvalidSaveFileError';\n Object.setPrototypeOf(this, InvalidSaveFileError.prototype);\n }\n}\n//# sourceMappingURL=errors.js.map","import path from 'node:path';\nimport { compare as compareVersions } from 'compare-versions';\nimport unzipper from 'unzipper';\nimport { InvalidArgumentError, InvalidSaveFileError } from './errors';\n// Written with the help of the information on https://forums.factorio.com/viewtopic.php?t=47014\nexport function parseLevelInitData(data) {\n let bytesOffset = 0;\n function readUint8() {\n // console.log(`readUint8() at offset ${bytesOffset.toString(16)}`);\n const value = data.getUint8(bytesOffset);\n bytesOffset += 1;\n return value;\n }\n function readUint16() {\n // console.log(`readUint16() at offset ${bytesOffset.toString(16)}`);\n const value = data.getUint16(bytesOffset, true);\n bytesOffset += 2;\n return value;\n }\n function readUint32() {\n // console.log(`readUint32() at offset ${bytesOffset.toString(16)}`);\n const value = data.getUint32(bytesOffset, true);\n bytesOffset += 4;\n return value;\n }\n function readBoolean() {\n return readUint8() !== 0;\n }\n function readVersion() {\n const major = readUint16();\n const minor = readUint16();\n const patch = readUint16();\n const build = readUint16();\n return {\n major,\n minor,\n patch,\n build,\n // 4-number versions officially supported by compare-versions\n asString: `${major}.${minor}.${patch}.${build}`,\n };\n }\n // Read Factorio Version\n const factorioVersion = readVersion();\n function readOptimizedUint(bitSize) {\n /* console.log('readOptimizedUint()', {\n bitSize,\n }); */\n if (compareVersions(factorioVersion.asString, '0.14.14', '>')) {\n const value = readUint8();\n if (value !== 0xff) {\n return value;\n }\n }\n switch (bitSize) {\n case 16:\n return readUint16();\n case 32:\n return readUint32();\n default:\n throw new Error(`Invalid bit size: ${bitSize}`);\n }\n }\n // has_empty_indicator=false\n function readString() {\n const length = readOptimizedUint(32);\n const bufferSlice = data.buffer.slice(bytesOffset, bytesOffset + length);\n bytesOffset += length;\n return new TextDecoder().decode(bufferSlice);\n }\n function readVersion48() {\n const major = readOptimizedUint(16);\n const minor = readOptimizedUint(16);\n const patch = readOptimizedUint(16);\n return {\n major,\n minor,\n patch,\n };\n }\n // Single Unused byte\n readBoolean();\n // Read fields\n const name = readString();\n const campaign = readString();\n const baseMod = readString();\n const difficulty = readUint8();\n const finished = readBoolean();\n const playerWon = readBoolean();\n const nextLevel = readString();\n const canContinue = readBoolean();\n const finishedButContinuing = readBoolean();\n const savingReplay = readBoolean();\n const allowNonAdminDebugOptions = readBoolean();\n const loadedFrom = readVersion48();\n const loadedFromBuild = factorioVersion.major >= 2 ? readUint32() : readUint16();\n const allowedCommands = readBoolean();\n // 2.0 has a new header with 4 extra bytes here\n if (factorioVersion.major >= 2) {\n readUint8();\n readUint8();\n readUint8();\n readUint8();\n }\n const numMods = readOptimizedUint(32);\n const mods = [];\n for (let i = 0; i < numMods; i++) {\n mods.push({\n name: readString(),\n version: readVersion48(),\n crc: readUint32(),\n });\n }\n return {\n factorioVersion,\n name,\n campaign,\n baseMod,\n difficulty,\n finished,\n playerWon,\n nextLevel,\n canContinue,\n finishedButContinuing,\n savingReplay,\n allowNonAdminDebugOptions,\n loadedFrom,\n loadedFromBuild,\n allowedCommands,\n mods,\n };\n}\nexport async function parseSaveFile(filepath) {\n let centralDirectory;\n let levelInitDatName = '';\n try {\n const normalizedPath = path.normalize(filepath);\n const resolvedPath = path.resolve(normalizedPath);\n const fileExtension = path.extname(filepath);\n const filename = path.basename(filepath).replace(fileExtension, '');\n // if zip file is called _autosave1.zip, make levelInitDatName contain _autosave1\n levelInitDatName = `${filename}/level-init.dat`;\n // if file does not end with .zip, it's likely not valid\n if (fileExtension !== '.zip') {\n throw new InvalidArgumentError('File path is not a zip file.');\n }\n centralDirectory = await unzipper.Open.file(resolvedPath);\n }\n catch (e) {\n // eslint-disable-next-line no-console\n console.error(e);\n return undefined;\n }\n const file = centralDirectory.files.find(f => f.path === levelInitDatName);\n if (!file) {\n throw new InvalidSaveFileError('File does not appear to be a save file');\n }\n const levelInitDatContent = await file?.buffer();\n if (levelInitDatContent === null) {\n throw new InvalidSaveFileError('Unable to find level-init.dat in save file');\n }\n const binaryData = new DataView(levelInitDatContent.buffer);\n return parseLevelInitData(binaryData);\n}\n//# sourceMappingURL=parser.js.map"],"names":["compareVersions"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../out/errors.js","../out/parser.js"],"sourcesContent":["export class InvalidArgumentError extends Error {\n constructor(message) {\n super(message);\n this.name = 'InvalidArgumentError';\n Object.setPrototypeOf(this, InvalidArgumentError.prototype);\n }\n}\nexport class InvalidSaveFileError extends Error {\n constructor(message) {\n super(message);\n this.name = 'InvalidSaveFileError';\n Object.setPrototypeOf(this, InvalidSaveFileError.prototype);\n }\n}\n//# sourceMappingURL=errors.js.map","import path from 'node:path';\nimport { compare as compareVersions } from 'compare-versions';\nimport unzipper from 'unzipper';\nimport { InvalidArgumentError, InvalidSaveFileError } from './errors';\n// Written with the help of the information on https://forums.factorio.com/viewtopic.php?t=47014\nexport function parseLevelInitData(data) {\n let bytesOffset = 0;\n function readUint8() {\n // console.log(`readUint8() at offset ${bytesOffset.toString(16)}`);\n const value = data.getUint8(bytesOffset);\n bytesOffset += 1;\n return value;\n }\n function readUint16() {\n // console.log(`readUint16() at offset ${bytesOffset.toString(16)}`);\n const value = data.getUint16(bytesOffset, true);\n bytesOffset += 2;\n return value;\n }\n function readUint32() {\n // console.log(`readUint32() at offset ${bytesOffset.toString(16)}`);\n const value = data.getUint32(bytesOffset, true);\n bytesOffset += 4;\n return value;\n }\n function readBoolean() {\n return readUint8() !== 0;\n }\n function readVersion() {\n const major = readUint16();\n const minor = readUint16();\n const patch = readUint16();\n const build = readUint16();\n return {\n major,\n minor,\n patch,\n build,\n // 4-number versions officially supported by compare-versions\n asString: `${major}.${minor}.${patch}.${build}`,\n };\n }\n // Read Factorio Version\n const factorioVersion = readVersion();\n function readOptimizedUint(bitSize) {\n /* console.log('readOptimizedUint()', {\n bitSize,\n }); */\n if (compareVersions(factorioVersion.asString, '0.14.14', '>')) {\n const value = readUint8();\n if (value !== 0xff) {\n return value;\n }\n }\n switch (bitSize) {\n case 16:\n return readUint16();\n case 32:\n return readUint32();\n default:\n throw new Error(`Invalid bit size: ${bitSize}`);\n }\n }\n // has_empty_indicator=false\n function readString() {\n const length = readOptimizedUint(32);\n const bufferSlice = data.buffer.slice(bytesOffset, bytesOffset + length);\n bytesOffset += length;\n return new TextDecoder().decode(bufferSlice);\n }\n function readVersion48() {\n const major = readOptimizedUint(16);\n const minor = readOptimizedUint(16);\n const patch = readOptimizedUint(16);\n return {\n major,\n minor,\n patch,\n asString: `${major}.${minor}.${patch}`,\n };\n }\n // Single Unused byte\n readBoolean();\n // Read fields\n const name = readString();\n const campaign = readString();\n const baseMod = readString();\n const difficulty = readUint8();\n const finished = readBoolean();\n const playerWon = readBoolean();\n const nextLevel = readString();\n const canContinue = readBoolean();\n const finishedButContinuing = readBoolean();\n const savingReplay = readBoolean();\n const allowNonAdminDebugOptions = readBoolean();\n const loadedFrom = readVersion48();\n const loadedFromBuild = factorioVersion.major >= 2 ? readUint32() : readUint16();\n const allowedCommands = readBoolean();\n // 2.0 has a new header with 4 extra bytes here\n if (factorioVersion.major >= 2) {\n readUint8();\n readUint8();\n readUint8();\n readUint8();\n }\n const numMods = readOptimizedUint(32);\n const mods = [];\n for (let i = 0; i < numMods; i++) {\n mods.push({\n name: readString(),\n version: readVersion48(),\n crc: readUint32(),\n });\n }\n return {\n factorioVersion,\n name,\n campaign,\n baseMod,\n difficulty,\n finished,\n playerWon,\n nextLevel,\n canContinue,\n finishedButContinuing,\n savingReplay,\n allowNonAdminDebugOptions,\n loadedFrom,\n loadedFromBuild,\n allowedCommands,\n mods,\n };\n}\nexport async function parseSaveFile(filepath) {\n let centralDirectory;\n let levelInitDatName = '';\n try {\n const normalizedPath = path.normalize(filepath);\n const resolvedPath = path.resolve(normalizedPath);\n const fileExtension = path.extname(filepath);\n const filename = path.basename(filepath).replace(fileExtension, '');\n // if zip file is called _autosave1.zip, make levelInitDatName contain _autosave1\n levelInitDatName = `${filename}/level-init.dat`;\n // if file does not end with .zip, it's likely not valid\n if (fileExtension !== '.zip') {\n throw new InvalidArgumentError('File path is not a zip file.');\n }\n centralDirectory = await unzipper.Open.file(resolvedPath);\n }\n catch (e) {\n // eslint-disable-next-line no-console\n console.error(e);\n return undefined;\n }\n const file = centralDirectory.files.find(f => f.path === levelInitDatName);\n if (!file) {\n throw new InvalidSaveFileError('File does not appear to be a save file');\n }\n const levelInitDatContent = await file?.buffer();\n if (levelInitDatContent === null) {\n throw new InvalidSaveFileError('Unable to find level-init.dat in save file');\n }\n const binaryData = new DataView(levelInitDatContent.buffer);\n return parseLevelInitData(binaryData);\n}\n//# sourceMappingURL=parser.js.map"],"names":["compareVersions"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -7,6 +7,7 @@ declare interface Version48 {
7
7
  major: number;
8
8
  minor: number;
9
9
  patch: number;
10
+ asString: string;
10
11
  }
11
12
  declare interface Version {
12
13
  major: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "factorio-save-parser",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
4
4
  "license": "AGPL-3.0",
5
5
  "author": "CommanderRedYT",
6
6
  "keywords": [