@etothepii/satisfactory-file-parser 0.0.15 → 0.0.17

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.
Files changed (32) hide show
  1. package/README.md +49 -11
  2. package/build/index.d.ts +10 -8
  3. package/build/index.js +10 -12
  4. package/build/parser/byte/byte-reader.class.d.ts +1 -38
  5. package/build/parser/byte/byte-reader.class.js +0 -11
  6. package/build/parser/byte/byte-writer.class.d.ts +1 -38
  7. package/build/parser/byte/byte-writer.class.js +0 -10
  8. package/build/parser/file.types.d.ts +9 -0
  9. package/build/parser/file.types.js +2 -0
  10. package/build/parser/parser.d.ts +12 -40
  11. package/build/parser/parser.js +51 -47
  12. package/build/parser/satisfactory/blueprint/blueprint-reader.d.ts +18 -0
  13. package/build/parser/satisfactory/blueprint/blueprint-reader.js +124 -0
  14. package/build/parser/satisfactory/blueprint/blueprint-writer.d.ts +15 -0
  15. package/build/parser/satisfactory/blueprint/blueprint-writer.js +63 -0
  16. package/build/parser/satisfactory/blueprint/blueprint.types.d.ts +20 -0
  17. package/build/parser/satisfactory/blueprint/blueprint.types.js +2 -0
  18. package/build/parser/satisfactory/objects/DataFields.d.ts +1 -1
  19. package/build/parser/satisfactory/objects/DataFields.js +0 -25
  20. package/build/parser/satisfactory/objects/Property.d.ts +1 -1
  21. package/build/parser/satisfactory/objects/Property.js +10 -159
  22. package/build/parser/satisfactory/save/level.class.d.ts +21 -0
  23. package/build/parser/satisfactory/save/level.class.js +138 -0
  24. package/build/parser/satisfactory/save/satisfactory-save.d.ts +11 -0
  25. package/build/parser/satisfactory/save/satisfactory-save.js +11 -0
  26. package/build/parser/satisfactory/save/save-reader.d.ts +44 -0
  27. package/build/parser/satisfactory/save/save-reader.js +233 -0
  28. package/build/parser/satisfactory/save/save-writer.d.ts +12 -0
  29. package/build/parser/satisfactory/save/save-writer.js +112 -0
  30. package/build/parser/satisfactory/save/save.types.d.ts +49 -0
  31. package/build/parser/satisfactory/save/save.types.js +2 -0
  32. package/package.json +6 -2
package/README.md CHANGED
@@ -19,13 +19,15 @@ If there will be changes, those will come very soon as soon as U8 is out on Expe
19
19
 
20
20
  ## Installation via npm
21
21
  `npm install @etothepii/satisfactory-file-parser`
22
- ## Usage
23
- Usage of the SaveParser is easy. For reading a save file, just pass a Buffer to it.
22
+
23
+ ## Usage of Save Parsing
24
+ Usage of the SaveParser is easy. For reading a save file (`.sav`), just pass a Buffer to the parser with the file content.
24
25
  ```js
25
- import { SaveParser } from "@etothepii/satisfactory-file-parser";
26
+ import * as fs from 'fs';
27
+ import { Parser } from "@etothepii/satisfactory-file-parser";
26
28
 
27
29
  const file = fs.readFileSync('./MySave.sav') as Buffer;
28
- const parsedSave = SaveParser.ParseSaveFile(file);
30
+ const parsedSave = Parser.ParseSaveFile(file);
29
31
  ```
30
32
 
31
33
  Consequently, writing a parsed save file back is just as easy.
@@ -33,21 +35,57 @@ The SaveParser has callbacks to assist in syncing on different occasions during
33
35
  For example, when writing the header or when writing a chunk of the save body.
34
36
  The splitting in individual chunks enables you to more easily stream the binary data to somewhere else.
35
37
  ```js
36
- import { SaveParser } from "@etothepii/satisfactory-file-parser";
38
+ import * as fs from 'fs';
39
+ import { Parser } from "@etothepii/satisfactory-file-parser";
37
40
 
38
- let header, bodyChunks;
39
- SaveParser.WriteSave(save, binaryBeforeCompressed => {}, header => {
41
+ let header, bodyChunks = [];
42
+ Parser.WriteSave(save, binaryBeforeCompressed => {
43
+ console.log('on binary data before being compressed.');
44
+ }, header => {
40
45
  console.log('on save header.');
41
46
  header = header;
42
47
  }, chunk => {
43
48
  console.log('on save body chunk.');
44
49
  bodyChunks.push(chunk);
45
- }, summary => {
46
- console.log('finished writing chunks.');
50
+ });
51
+
52
+ // write complete sav file back to disk
53
+ fs.writeFileSync('./MyModifiedSave.sav', Buffer.concat([header, ...bodyChunks]));
54
+ ```
55
+
56
+ ## Usage of Blueprint Parsing
57
+ Blueprint parsing works very similiar. Note, that blueprints consist of 2 files. The `.sbp` main file and the config file `.sbpcfg`.
58
+
59
+ ```js
60
+ import * as fs from 'fs';
61
+ import { Parser } from "@etothepii/satisfactory-file-parser";
47
62
 
48
- // write complete sav file back to disk
49
- fs.writeFileSync('./MyModifiedSave.sav', Buffer.concat([header, ...bodyChunks]));
63
+ const mainFile = fs.readFileSync('./MyBlueprint.sbp') as Buffer;
64
+ const configFile = fs.readFileSync('./MyBlueprint.sbpcfg') as Buffer;
65
+ const parsedBlueprint = Parser.ParseBlueprintFiles('MyBlueprint', mainFile, configFile);
66
+ ```
67
+
68
+ Consequently, writing a blueprint into binary data works the same way with getting callbacks in the same style as the save parsing.
69
+ ```js
70
+ import * as fs from 'fs';
71
+ import { Parser } from "@etothepii/satisfactory-file-parser";
72
+
73
+ let mainFileHeader, mainFileBodyChunks = [];
74
+ const summary = Parser.WriteBlueprintFiles(blueprint, mainFileBinaryBeforeCompressed => {
75
+ console.log('on main file binary data before being compressed.');
76
+ }, header => {
77
+ console.log('on main file blueprint header.');
78
+ mainFileHeader = header;
79
+ }, chunk => {
80
+ console.log('on main file blueprint body chunk.');
81
+ mainFileBodyChunks.push(chunk);
50
82
  });
83
+
84
+ // write complete .sbp file back to disk
85
+ fs.writeFileSync('./MyModifiedBlueprint.sbp', Buffer.concat([mainFileHeader, ...mainFileBodyChunks]));
86
+
87
+ // write .sbpcfg file back to disk, we get that data from the result of WriteBlueprint
88
+ fs.writeFileSync('./MyModifiedSave.sbpcfg', Buffer.from(summary.configFileBinary));
51
89
  ```
52
90
 
53
91
  ## License
package/build/index.d.ts CHANGED
@@ -1,15 +1,17 @@
1
- export { Level } from './parser/satisfactory/level.class';
1
+ export type * from './parser/satisfactory/blueprint/blueprint.types';
2
2
  export { DataFields } from './parser/satisfactory/objects/DataFields';
3
3
  export { ObjectReference } from './parser/satisfactory/objects/ObjectReference';
4
4
  export * from './parser/satisfactory/objects/Property';
5
5
  export { SaveComponent } from './parser/satisfactory/objects/SaveComponent';
6
6
  export { SaveEntity } from './parser/satisfactory/objects/SaveEntity';
7
- export type * from './parser/satisfactory/satisfactory-save';
8
- export { StaticData } from './parser/satisfactory/static-data';
9
- export { BlueprintConfigReader, BlueprintReader } from './parser/blueprint-reader';
10
- export { BlueprintConfigWriter, BlueprintWriter } from './parser/blueprint-writer';
7
+ export { Level } from './parser/satisfactory/save/level.class';
8
+ export { SatisfactorySave } from './parser/satisfactory/save/satisfactory-save';
9
+ export type * from './parser/satisfactory/save/save.types';
10
+ export { BlueprintConfigReader, BlueprintReader } from './parser/satisfactory/blueprint/blueprint-reader';
11
+ export { BlueprintConfigWriter, BlueprintWriter } from './parser/satisfactory/blueprint/blueprint-writer';
12
+ export { SaveReader } from './parser/satisfactory/save/save-reader';
13
+ export { SaveWriter } from './parser/satisfactory/save/save-writer';
11
14
  export type * from './parser/satisfactory/structs/util.types';
12
- export { SaveReader } from './parser/save-reader';
13
- export { SaveWriter } from './parser/save-writer';
14
15
  export { CompressionLibraryError, CorruptSaveError, ParserError, UnsupportedVersionError } from './parser/error/parser.error';
15
- export { SaveParser } from './parser/parser';
16
+ export type * from './parser/file.types';
17
+ export { Parser } from './parser/parser';
package/build/index.js CHANGED
@@ -14,10 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.SaveParser = exports.UnsupportedVersionError = exports.ParserError = exports.CorruptSaveError = exports.CompressionLibraryError = exports.SaveWriter = exports.SaveReader = exports.BlueprintWriter = exports.BlueprintConfigWriter = exports.BlueprintReader = exports.BlueprintConfigReader = exports.SaveEntity = exports.SaveComponent = exports.ObjectReference = exports.DataFields = exports.Level = void 0;
18
- // types & classes for convenience
19
- var level_class_1 = require("./parser/satisfactory/level.class");
20
- Object.defineProperty(exports, "Level", { enumerable: true, get: function () { return level_class_1.Level; } });
17
+ exports.Parser = exports.UnsupportedVersionError = exports.ParserError = exports.CorruptSaveError = exports.CompressionLibraryError = exports.SaveWriter = exports.SaveReader = exports.BlueprintWriter = exports.BlueprintConfigWriter = exports.BlueprintReader = exports.BlueprintConfigReader = exports.SatisfactorySave = exports.Level = exports.SaveEntity = exports.SaveComponent = exports.ObjectReference = exports.DataFields = void 0;
21
18
  var DataFields_1 = require("./parser/satisfactory/objects/DataFields");
22
19
  Object.defineProperty(exports, "DataFields", { enumerable: true, get: function () { return DataFields_1.DataFields; } });
23
20
  var ObjectReference_1 = require("./parser/satisfactory/objects/ObjectReference");
@@ -27,23 +24,24 @@ var SaveComponent_1 = require("./parser/satisfactory/objects/SaveComponent");
27
24
  Object.defineProperty(exports, "SaveComponent", { enumerable: true, get: function () { return SaveComponent_1.SaveComponent; } });
28
25
  var SaveEntity_1 = require("./parser/satisfactory/objects/SaveEntity");
29
26
  Object.defineProperty(exports, "SaveEntity", { enumerable: true, get: function () { return SaveEntity_1.SaveEntity; } });
30
- // should better be removed in a future update to prevent shenanigans.
31
- var blueprint_reader_1 = require("./parser/blueprint-reader");
27
+ var level_class_1 = require("./parser/satisfactory/save/level.class");
28
+ Object.defineProperty(exports, "Level", { enumerable: true, get: function () { return level_class_1.Level; } });
29
+ var satisfactory_save_1 = require("./parser/satisfactory/save/satisfactory-save");
30
+ Object.defineProperty(exports, "SatisfactorySave", { enumerable: true, get: function () { return satisfactory_save_1.SatisfactorySave; } });
31
+ var blueprint_reader_1 = require("./parser/satisfactory/blueprint/blueprint-reader");
32
32
  Object.defineProperty(exports, "BlueprintConfigReader", { enumerable: true, get: function () { return blueprint_reader_1.BlueprintConfigReader; } });
33
33
  Object.defineProperty(exports, "BlueprintReader", { enumerable: true, get: function () { return blueprint_reader_1.BlueprintReader; } });
34
- var blueprint_writer_1 = require("./parser/blueprint-writer");
34
+ var blueprint_writer_1 = require("./parser/satisfactory/blueprint/blueprint-writer");
35
35
  Object.defineProperty(exports, "BlueprintConfigWriter", { enumerable: true, get: function () { return blueprint_writer_1.BlueprintConfigWriter; } });
36
36
  Object.defineProperty(exports, "BlueprintWriter", { enumerable: true, get: function () { return blueprint_writer_1.BlueprintWriter; } });
37
- var save_reader_1 = require("./parser/save-reader");
37
+ var save_reader_1 = require("./parser/satisfactory/save/save-reader");
38
38
  Object.defineProperty(exports, "SaveReader", { enumerable: true, get: function () { return save_reader_1.SaveReader; } });
39
- var save_writer_1 = require("./parser/save-writer");
39
+ var save_writer_1 = require("./parser/satisfactory/save/save-writer");
40
40
  Object.defineProperty(exports, "SaveWriter", { enumerable: true, get: function () { return save_writer_1.SaveWriter; } });
41
- // errors
42
41
  var parser_error_1 = require("./parser/error/parser.error");
43
42
  Object.defineProperty(exports, "CompressionLibraryError", { enumerable: true, get: function () { return parser_error_1.CompressionLibraryError; } });
44
43
  Object.defineProperty(exports, "CorruptSaveError", { enumerable: true, get: function () { return parser_error_1.CorruptSaveError; } });
45
44
  Object.defineProperty(exports, "ParserError", { enumerable: true, get: function () { return parser_error_1.ParserError; } });
46
45
  Object.defineProperty(exports, "UnsupportedVersionError", { enumerable: true, get: function () { return parser_error_1.UnsupportedVersionError; } });
47
- // facade
48
46
  var parser_1 = require("./parser/parser");
49
- Object.defineProperty(exports, "SaveParser", { enumerable: true, get: function () { return parser_1.SaveParser; } });
47
+ Object.defineProperty(exports, "Parser", { enumerable: true, get: function () { return parser_1.Parser; } });
@@ -1,38 +1 @@
1
- import { Alignment } from "./alignment.enum";
2
- export declare abstract class ByteReader {
3
- protected bufferView: DataView;
4
- protected fileBuffer: ArrayBuffer;
5
- protected alignment: Alignment;
6
- protected currentByte: number;
7
- protected handledByte: number;
8
- protected maxByte: number;
9
- protected lastStrRead: number;
10
- constructor(fileBuffer: ArrayBuffer, alignment: Alignment);
11
- /**
12
- * Resets the reader on the given arraybuffer to start from the beginning.
13
- * @param newFileBuffer the new array buffer to be read.
14
- */
15
- reset(newFileBuffer: ArrayBuffer): void;
16
- skipBytes(byteLength?: number): void;
17
- readByte(): number;
18
- readBytes(count: number): Uint8Array;
19
- readHex(hexLength: number): string;
20
- readInt8(): number;
21
- readUint8(): number;
22
- readUint16(): number;
23
- readInt32(): number;
24
- readUint32(): number;
25
- readLong(): bigint;
26
- readFloat(): number;
27
- readDouble(): number;
28
- protected getStringInfo(): {
29
- payload: string;
30
- counter: number;
31
- };
32
- getBufferPosition: () => number;
33
- getBufferSlice: (begin: number, end: number | undefined) => ArrayBuffer;
34
- getBufferProgress: () => number;
35
- getBufferLength: () => number;
36
- getBuffer: () => ArrayBuffer;
37
- readString(): string;
38
- }
1
+ export {};
@@ -16,10 +16,6 @@ class ByteReader {
16
16
  this.alignment = alignment;
17
17
  this.reset(fileBuffer);
18
18
  }
19
- /**
20
- * Resets the reader on the given arraybuffer to start from the beginning.
21
- * @param newFileBuffer the new array buffer to be read.
22
- */
23
19
  reset(newFileBuffer) {
24
20
  this.fileBuffer = newFileBuffer;
25
21
  this.bufferView = new DataView(newFileBuffer, 0, Math.min(102400, this.fileBuffer.byteLength));
@@ -27,14 +23,10 @@ class ByteReader {
27
23
  this.currentByte = 0;
28
24
  this.handledByte = 0;
29
25
  }
30
- /*
31
- * Byte Manipulation
32
- */
33
26
  skipBytes(byteLength = 1) {
34
27
  this.currentByte += byteLength;
35
28
  }
36
29
  readByte() {
37
- // TODO can i not just readByte() ??
38
30
  return parseInt(this.bufferView.getUint8(this.currentByte++).toString());
39
31
  }
40
32
  readBytes(count) {
@@ -105,18 +97,15 @@ class ByteReader {
105
97
  if (strLength === 0) {
106
98
  return '';
107
99
  }
108
- // Range error!
109
100
  if (strLength > (this.bufferView.buffer.byteLength - this.currentByte)) {
110
101
  let errorMessage = `Cannot read string of length ${strLength} at position ${this.currentByte} as it exceeds the end at ${this.bufferView.buffer.byteLength}`;
111
102
  throw new Error(errorMessage);
112
103
  }
113
- // it uses UTF16 if text is non-ascii, even if it would fit into UTF8.
114
104
  if (strLength < 0) {
115
105
  const string = new Array(-strLength - 1).fill('').map(c => String.fromCharCode(this.readUint16()));
116
106
  this.currentByte += 2;
117
107
  return string.join('');
118
108
  }
119
- //default UTF-8
120
109
  try {
121
110
  const string = new Array(strLength - 1).fill('').map(c => String.fromCharCode(this.readUint8()));
122
111
  this.currentByte += 1;
@@ -1,38 +1 @@
1
- import { Alignment } from "./alignment.enum";
2
- export declare abstract class ByteWriter {
3
- protected alignment: Alignment;
4
- protected bufferArray: ArrayBuffer;
5
- protected bufferView: DataView;
6
- protected currentByte: number;
7
- constructor(alignment: Alignment, bufferSize?: number);
8
- skipBytes(count?: number): void;
9
- jumpTo(pos: number): void;
10
- writeByte(value: number): void;
11
- writeBytesArray(bytes: number[]): void;
12
- writeBytes(bytes: Uint8Array): void;
13
- writeInt8(value: number): void;
14
- writeUint8(value: number): void;
15
- writeInt16(value: number): void;
16
- writeUint16(value: number): void;
17
- writeInt32(value: number): void;
18
- writeUint32(value: number): void;
19
- writeInt64(value: bigint): void;
20
- writeUint64(value: bigint): void;
21
- writeFloat(value: number): void;
22
- writeDouble(value: number): void;
23
- writeString(value: string): void;
24
- static IsASCIICompatible: (value: string) => boolean;
25
- getBufferPosition: () => number;
26
- getBufferSlice: (start: number, end?: number) => ArrayBuffer;
27
- writeBinarySizeFromPosition(lenIndicatorPos: number, start: number): void;
28
- /**
29
- * automatically extends the current buffer if the given space exceeds the available rest capacity of the current buffer.
30
- * @param countNeededBytes the needed space
31
- * @param factor how big the appended buffer should be in comparison to the current one. Values >= 1 make sense.
32
- */
33
- protected extendBufferIfNeeded(countNeededBytes: number, factor?: number): void;
34
- protected truncateBuffer(): void;
35
- endWriting(): ArrayBuffer;
36
- static ToInt32(num: number): Uint8Array;
37
- static AppendBuffer(buffer1: ArrayBuffer, buffer2: ArrayBuffer): ArrayBuffer;
38
- }
1
+ export {};
@@ -11,9 +11,6 @@ class ByteWriter {
11
11
  this.bufferView = new DataView(this.bufferArray);
12
12
  this.currentByte = 0;
13
13
  }
14
- /*
15
- * Byte Manipulation
16
- */
17
14
  skipBytes(count = 1) {
18
15
  this.extendBufferIfNeeded(count);
19
16
  this.currentByte += count;
@@ -87,7 +84,6 @@ class ByteWriter {
87
84
  this.writeInt32(0);
88
85
  return;
89
86
  }
90
- // if it's safe to use ASCII, use UTF8.
91
87
  if (ByteWriter.IsASCIICompatible(value)) {
92
88
  this.writeInt32(value.length + 1);
93
89
  for (let i = 0; i < value.length; i++) {
@@ -95,7 +91,6 @@ class ByteWriter {
95
91
  }
96
92
  this.writeUint8(0);
97
93
  }
98
- // write UTF16
99
94
  else {
100
95
  this.writeInt32(-value.length - 1);
101
96
  for (let i = 0; i < value.length; i++) {
@@ -111,11 +106,6 @@ class ByteWriter {
111
106
  this.writeInt32(writtenBytes);
112
107
  this.jumpTo(after);
113
108
  }
114
- /**
115
- * automatically extends the current buffer if the given space exceeds the available rest capacity of the current buffer.
116
- * @param countNeededBytes the needed space
117
- * @param factor how big the appended buffer should be in comparison to the current one. Values >= 1 make sense.
118
- */
119
109
  extendBufferIfNeeded(countNeededBytes, factor = 1.5) {
120
110
  if (this.currentByte + countNeededBytes > this.bufferView.byteLength) {
121
111
  this.bufferArray = ByteWriter.AppendBuffer(this.bufferArray, new ArrayBuffer(factor * this.bufferArray.byteLength));
@@ -0,0 +1,9 @@
1
+ export type ChunkCompressionInfo = {
2
+ chunkHeaderSize: number;
3
+ packageFileTag: number;
4
+ maxChunkContentSize: number;
5
+ };
6
+ export type ChunkSummary = {
7
+ uncompressedSize: number;
8
+ compressedSize: number;
9
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,44 +1,16 @@
1
1
  /// <reference types="node" />
2
- import { SatisfactorySave } from "./satisfactory/satisfactory-save";
3
- import { SaveProjectionConfig } from "./save-reader";
4
- export declare class SaveParser {
5
- /**
6
- * serializes a save file into binary and reports back on individual callbacks.
7
- * @param save the save file to serialize into binary.
8
- * @param onBinaryBeforeCompressing gets called on the binary save body before it is compressed.
9
- * @param onHeader gets called on the binary save header, which is always uncompressed.
10
- * @param onChunk gets called when a chunk of the compressed save body was generated. Often, files' save bodies consist of multiple chunks.
11
- * @param onFinish gets called when all chunks have been generated. A summary of the chunk sizes and count is reported.
12
- */
13
- static WriteSave(save: SatisfactorySave, onBinaryBeforeCompressing: (buffer: ArrayBuffer) => void, onHeader: (header: Uint8Array) => void, onChunk: (chunk: Uint8Array) => void, onFinish: (summary: {
14
- errors: string[];
15
- chunkSummary: {
16
- uncompressedSize: number;
17
- compressedSize: number;
18
- }[];
19
- }) => void): void;
20
- /**
21
- * parses a save object from a binary buffer and reports back on decompressing the save body in a callback.
22
- * @param file the binary content to be parsed.
23
- * @param additionalData additional static data that is not contained in save files. For example, power slugs and resource nodes.
24
- * @param onSaveDecompressed gets called when the entire binary save body has been decompressed.
25
- * @returns a brief summary
26
- */
27
- static ParseSaveFile(file: Buffer, onSaveDecompressed?: (buffer: ArrayBuffer) => void, onProgress?: (progress: number, message?: string) => void): SatisfactorySave;
28
- /**
29
- * Does Projection on a Save Object in order to reduce it's complexity.
30
- * @param save the save object in question.
31
- * @param config the projection config to apply.
32
- * @returns a save object that has been projected / modified. Do not try to serialize it into an actual save tho! Since information has been transformed.
33
- */
2
+ import { ChunkSummary } from "./file.types";
3
+ import { Blueprint } from "./satisfactory/blueprint/blueprint.types";
4
+ import { SatisfactorySave } from "./satisfactory/save/satisfactory-save";
5
+ import { SaveProjectionConfig } from "./satisfactory/save/save-reader";
6
+ export declare class Parser {
7
+ static WriteSave(save: SatisfactorySave, onBinaryBeforeCompressing: (buffer: ArrayBuffer) => void, onHeader: (header: Uint8Array) => void, onChunk: (chunk: Uint8Array) => void): ChunkSummary[];
8
+ static ParseSaveFile(file: Buffer, onDecompressedSaveBody?: (buffer: ArrayBuffer) => void, onProgress?: (progress: number, message?: string) => void): SatisfactorySave;
9
+ static WriteBlueprintFiles(blueprint: Blueprint, onMainFileBinaryBeforeCompressing?: (binary: ArrayBuffer) => void, onMainFileHeader?: (header: Uint8Array) => void, onMainFileChunk?: (chunk: Uint8Array) => void): {
10
+ mainFileChunkSummary: ChunkSummary[];
11
+ configFileBinary: ArrayBuffer;
12
+ };
13
+ static ParseBlueprintFiles(name: string, blueprintFile: Buffer, blueprintConfigFile: Buffer, onDecompressedBlueprintBody?: (buffer: ArrayBuffer) => void): Blueprint;
34
14
  static ProjectSave(save: SatisfactorySave, config: SaveProjectionConfig): SatisfactorySave;
35
- /**
36
- * It JSON.stringifies any parsed content safely. The original JSON.stringify() has some flaws that get in the way, so it is custom wrapped. The original has some problems:
37
- * 1. it cannot stringify bigints. So we help out by converting it into a string.
38
- * 2. It cannot distinguish between 0 and -0. But a float32 is encoded in a uint8Array for 0 to be [0,0,0,0] (0x00000000) and -0 to be [0,0,0,128] (0x00000080) in little endian.
39
- * @param obj
40
- * @param indent
41
- * @returns a string that is safely stringified.
42
- */
43
15
  static JSONStringifyModified: (obj: any, indent?: number) => string;
44
16
  }
@@ -1,56 +1,68 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SaveParser = void 0;
4
- const level_class_1 = require("./satisfactory/level.class");
5
- const satisfactory_save_1 = require("./satisfactory/satisfactory-save");
6
- const save_reader_1 = require("./save-reader");
7
- const save_writer_1 = require("./save-writer");
8
- class SaveParser {
9
- /**
10
- * serializes a save file into binary and reports back on individual callbacks.
11
- * @param save the save file to serialize into binary.
12
- * @param onBinaryBeforeCompressing gets called on the binary save body before it is compressed.
13
- * @param onHeader gets called on the binary save header, which is always uncompressed.
14
- * @param onChunk gets called when a chunk of the compressed save body was generated. Often, files' save bodies consist of multiple chunks.
15
- * @param onFinish gets called when all chunks have been generated. A summary of the chunk sizes and count is reported.
16
- */
17
- static WriteSave(save, onBinaryBeforeCompressing, onHeader, onChunk, onFinish) {
3
+ exports.Parser = void 0;
4
+ const blueprint_reader_1 = require("./satisfactory/blueprint/blueprint-reader");
5
+ const blueprint_writer_1 = require("./satisfactory/blueprint/blueprint-writer");
6
+ const level_class_1 = require("./satisfactory/save/level.class");
7
+ const satisfactory_save_1 = require("./satisfactory/save/satisfactory-save");
8
+ const save_reader_1 = require("./satisfactory/save/save-reader");
9
+ const save_writer_1 = require("./satisfactory/save/save-writer");
10
+ class Parser {
11
+ static WriteSave(save, onBinaryBeforeCompressing, onHeader, onChunk) {
18
12
  const writer = new save_writer_1.SaveWriter();
19
13
  save_writer_1.SaveWriter.WriteHeader(writer, save.header);
20
14
  const posAfterHeader = writer.getBufferPosition();
21
15
  save_writer_1.SaveWriter.WriteLevels(writer, save, save.header.buildVersion);
22
16
  writer.endWriting();
23
- writer.generateChunks(save.compressionInfo, posAfterHeader, onBinaryBeforeCompressing, onHeader, onChunk, onFinish);
17
+ const chunkSummary = writer.generateChunks(save.compressionInfo, posAfterHeader, onBinaryBeforeCompressing, onHeader, onChunk);
18
+ return chunkSummary;
24
19
  }
25
- /**
26
- * parses a save object from a binary buffer and reports back on decompressing the save body in a callback.
27
- * @param file the binary content to be parsed.
28
- * @param additionalData additional static data that is not contained in save files. For example, power slugs and resource nodes.
29
- * @param onSaveDecompressed gets called when the entire binary save body has been decompressed.
30
- * @returns a brief summary
31
- */
32
- static ParseSaveFile(file, onSaveDecompressed = () => { }, onProgress = () => { }) {
33
- const reader = new save_reader_1.SaveReader(file.buffer, onProgress);
34
- // read header
20
+ static ParseSaveFile(file, onDecompressedSaveBody = () => { }, onProgress = () => { }) {
21
+ const reader = new save_reader_1.SaveReader(new Uint8Array(file).buffer, onProgress);
35
22
  const header = reader.readHeader();
36
23
  const save = new satisfactory_save_1.SatisfactorySave(header);
37
- // inflate chunks
38
24
  const inflateResult = reader.inflateChunks();
39
- // call callback on decompressed save body
40
- onSaveDecompressed(reader.getBuffer());
41
- // parse levels
25
+ onDecompressedSaveBody(reader.getBuffer());
42
26
  const levelParseResult = reader.readLevels();
43
27
  save.levels = reader.levels;
44
28
  save.compressionInfo = reader.compressionInfo;
45
29
  save.trailingCollectedObjects = reader.trailingCollectedObjects;
46
30
  return save;
47
31
  }
48
- /**
49
- * Does Projection on a Save Object in order to reduce it's complexity.
50
- * @param save the save object in question.
51
- * @param config the projection config to apply.
52
- * @returns a save object that has been projected / modified. Do not try to serialize it into an actual save tho! Since information has been transformed.
53
- */
32
+ static WriteBlueprintFiles(blueprint, onMainFileBinaryBeforeCompressing = () => { }, onMainFileHeader = () => { }, onMainFileChunk = () => { }) {
33
+ const blueprintWriter = new blueprint_writer_1.BlueprintWriter();
34
+ blueprint_writer_1.BlueprintWriter.SerializeHeader(blueprintWriter, blueprint.header);
35
+ const saveBodyPos = blueprintWriter.getBufferPosition();
36
+ blueprint_writer_1.BlueprintWriter.SerializeObjects(blueprintWriter, blueprint.objects);
37
+ blueprintWriter.endWriting();
38
+ let binaryChunks = [];
39
+ let binaryHeader;
40
+ const mainFileChunkSummary = blueprintWriter.generateChunks(blueprint.compressionInfo, saveBodyPos, onMainFileBinaryBeforeCompressing, onMainFileHeader, onMainFileChunk);
41
+ const configWriter = new blueprint_writer_1.BlueprintConfigWriter();
42
+ blueprint_writer_1.BlueprintConfigWriter.SerializeConfig(configWriter, blueprint.config);
43
+ const configFileBinary = configWriter.endWriting();
44
+ return {
45
+ mainFileChunkSummary,
46
+ configFileBinary
47
+ };
48
+ }
49
+ static ParseBlueprintFiles(name, blueprintFile, blueprintConfigFile, onDecompressedBlueprintBody = () => { }) {
50
+ const blueprintConfigReader = new blueprint_reader_1.BlueprintConfigReader(new Uint8Array(blueprintConfigFile).buffer);
51
+ const config = blueprint_reader_1.BlueprintConfigReader.ParseConfig(blueprintConfigReader);
52
+ const blueprintReader = new blueprint_reader_1.BlueprintReader(new Uint8Array(blueprintFile).buffer);
53
+ const header = blueprint_reader_1.BlueprintReader.ReadHeader(blueprintReader);
54
+ const inflateResult = blueprintReader.inflateChunks();
55
+ onDecompressedBlueprintBody(inflateResult.inflatedData);
56
+ const blueprintObjects = blueprint_reader_1.BlueprintReader.ParseObjects(blueprintReader);
57
+ const blueprint = {
58
+ name,
59
+ compressionInfo: blueprintReader.compressionInfo,
60
+ header: header,
61
+ config,
62
+ objects: blueprintObjects
63
+ };
64
+ return blueprint;
65
+ }
54
66
  static ProjectSave(save, config) {
55
67
  return {
56
68
  header: save.header,
@@ -64,21 +76,13 @@ class SaveParser {
64
76
  };
65
77
  }
66
78
  }
67
- /**
68
- * It JSON.stringifies any parsed content safely. The original JSON.stringify() has some flaws that get in the way, so it is custom wrapped. The original has some problems:
69
- * 1. it cannot stringify bigints. So we help out by converting it into a string.
70
- * 2. It cannot distinguish between 0 and -0. But a float32 is encoded in a uint8Array for 0 to be [0,0,0,0] (0x00000000) and -0 to be [0,0,0,128] (0x00000080) in little endian.
71
- * @param obj
72
- * @param indent
73
- * @returns a string that is safely stringified.
74
- */
75
- SaveParser.JSONStringifyModified = (obj, indent = 0) => JSON.stringify(obj, (key, value) => {
79
+ Parser.JSONStringifyModified = (obj, indent = 0) => JSON.stringify(obj, (key, value) => {
76
80
  if (typeof value === 'bigint') {
77
81
  return value.toString();
78
82
  }
79
- else if (value === 0 && 1 / value < 0) { // -0
83
+ else if (value === 0 && 1 / value < 0) {
80
84
  return '-0';
81
85
  }
82
86
  return value;
83
87
  }, indent);
84
- exports.SaveParser = SaveParser;
88
+ exports.Parser = Parser;
@@ -0,0 +1,18 @@
1
+ import { ByteReader } from "../../byte/byte-reader.class";
2
+ import { ChunkCompressionInfo } from "../../file.types";
3
+ import { SaveComponent } from "../objects/SaveComponent";
4
+ import { SaveEntity } from "../objects/SaveEntity";
5
+ import { BlueprintConfig, BlueprintHeader } from "./blueprint.types";
6
+ export declare class BlueprintReader extends ByteReader {
7
+ compressionInfo: ChunkCompressionInfo;
8
+ constructor(bluePrintBuffer: ArrayBuffer);
9
+ static ReadHeader(reader: ByteReader): BlueprintHeader;
10
+ inflateChunks(): any;
11
+ static ParseObjects(reader: ByteReader): (SaveEntity | SaveComponent)[];
12
+ }
13
+ export declare class BlueprintConfigReader extends ByteReader {
14
+ bluePrintConfigBuffer: ArrayBuffer;
15
+ constructor(bluePrintConfigBuffer: ArrayBuffer);
16
+ parse: () => BlueprintConfig;
17
+ static ParseConfig(reader: ByteReader): BlueprintConfig;
18
+ }