@etothepii/satisfactory-file-parser 0.0.15 → 0.0.16

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 (31) hide show
  1. package/build/index.d.ts +10 -8
  2. package/build/index.js +10 -12
  3. package/build/parser/byte/byte-reader.class.d.ts +1 -38
  4. package/build/parser/byte/byte-reader.class.js +0 -11
  5. package/build/parser/byte/byte-writer.class.d.ts +1 -38
  6. package/build/parser/byte/byte-writer.class.js +0 -10
  7. package/build/parser/file.types.d.ts +9 -0
  8. package/build/parser/file.types.js +2 -0
  9. package/build/parser/parser.d.ts +12 -40
  10. package/build/parser/parser.js +51 -47
  11. package/build/parser/satisfactory/blueprint/blueprint-reader.d.ts +18 -0
  12. package/build/parser/satisfactory/blueprint/blueprint-reader.js +124 -0
  13. package/build/parser/satisfactory/blueprint/blueprint-writer.d.ts +15 -0
  14. package/build/parser/satisfactory/blueprint/blueprint-writer.js +63 -0
  15. package/build/parser/satisfactory/blueprint/blueprint.types.d.ts +20 -0
  16. package/build/parser/satisfactory/blueprint/blueprint.types.js +2 -0
  17. package/build/parser/satisfactory/objects/DataFields.d.ts +1 -1
  18. package/build/parser/satisfactory/objects/DataFields.js +0 -25
  19. package/build/parser/satisfactory/objects/Property.d.ts +1 -1
  20. package/build/parser/satisfactory/objects/Property.js +10 -159
  21. package/build/parser/satisfactory/save/level.class.d.ts +21 -0
  22. package/build/parser/satisfactory/save/level.class.js +138 -0
  23. package/build/parser/satisfactory/save/satisfactory-save.d.ts +11 -0
  24. package/build/parser/satisfactory/save/satisfactory-save.js +11 -0
  25. package/build/parser/satisfactory/save/save-reader.d.ts +44 -0
  26. package/build/parser/satisfactory/save/save-reader.js +233 -0
  27. package/build/parser/satisfactory/save/save-writer.d.ts +12 -0
  28. package/build/parser/satisfactory/save/save-writer.js +112 -0
  29. package/build/parser/satisfactory/save/save.types.d.ts +49 -0
  30. package/build/parser/satisfactory/save/save.types.js +2 -0
  31. package/package.json +6 -2
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
+ }
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.BlueprintConfigReader = exports.BlueprintReader = void 0;
7
+ const pako_1 = __importDefault(require("pako"));
8
+ const alignment_enum_1 = require("../../byte/alignment.enum");
9
+ const byte_reader_class_1 = require("../../byte/byte-reader.class");
10
+ const parser_error_1 = require("../../error/parser.error");
11
+ const level_class_1 = require("../save/level.class");
12
+ const util_types_1 = require("../structs/util.types");
13
+ class BlueprintReader extends byte_reader_class_1.ByteReader {
14
+ constructor(bluePrintBuffer) {
15
+ super(bluePrintBuffer, alignment_enum_1.Alignment.LITTLE_ENDIAN);
16
+ this.compressionInfo = {
17
+ packageFileTag: 0,
18
+ maxChunkContentSize: 0,
19
+ chunkHeaderSize: 48
20
+ };
21
+ }
22
+ static ReadHeader(reader) {
23
+ const unk = reader.readBytes(3 * 4);
24
+ const positionThingOrWhat = (0, util_types_1.ParseVec3)(reader);
25
+ let itemTypeCount = reader.readInt32();
26
+ const itemCosts = new Array(itemTypeCount).fill(['', 0]);
27
+ for (let i = 0; i < itemTypeCount; i++) {
28
+ let indexOrWhat = reader.readInt32();
29
+ let itemPathName = reader.readString();
30
+ let itemCount = reader.readInt32();
31
+ itemCosts[i] = [itemPathName, itemCount];
32
+ }
33
+ let recipeCount = reader.readInt32();
34
+ const recipeRefs = new Array(recipeCount).fill('');
35
+ for (let i = 0; i < recipeCount; i++) {
36
+ let indexOrWhat = reader.readInt32();
37
+ const recipeName = reader.readString();
38
+ recipeRefs[i] = recipeName;
39
+ }
40
+ return {
41
+ recipeReferences: recipeRefs,
42
+ itemCosts
43
+ };
44
+ }
45
+ inflateChunks() {
46
+ this.fileBuffer = this.fileBuffer.slice(this.currentByte);
47
+ this.handledByte = 0;
48
+ this.currentByte = 0;
49
+ this.maxByte = this.fileBuffer.byteLength;
50
+ let currentChunks = [];
51
+ let totalUncompressedBodySize = 0;
52
+ while (this.handledByte < this.maxByte) {
53
+ let chunkHeader = new DataView(this.fileBuffer.slice(0, this.compressionInfo.chunkHeaderSize));
54
+ this.currentByte = this.compressionInfo.chunkHeaderSize;
55
+ this.handledByte += this.compressionInfo.chunkHeaderSize;
56
+ if (this.compressionInfo.packageFileTag <= 0) {
57
+ this.compressionInfo.packageFileTag = chunkHeader.getUint32(0, this.alignment === alignment_enum_1.Alignment.LITTLE_ENDIAN);
58
+ }
59
+ if (this.compressionInfo.maxChunkContentSize <= 0) {
60
+ this.compressionInfo.maxChunkContentSize = chunkHeader.getInt32(8, this.alignment === alignment_enum_1.Alignment.LITTLE_ENDIAN);
61
+ }
62
+ const chunkCompressedLength = chunkHeader.getInt32(32, this.alignment === alignment_enum_1.Alignment.LITTLE_ENDIAN);
63
+ const chunkUncompressedLength = chunkHeader.getInt32(40, this.alignment === alignment_enum_1.Alignment.LITTLE_ENDIAN);
64
+ totalUncompressedBodySize += chunkUncompressedLength;
65
+ const currentChunkSize = chunkCompressedLength;
66
+ let currentChunk = this.fileBuffer.slice(this.currentByte, this.currentByte + currentChunkSize);
67
+ this.handledByte += currentChunkSize;
68
+ this.currentByte += currentChunkSize;
69
+ this.fileBuffer = this.fileBuffer.slice(this.currentByte);
70
+ this.currentByte = 0;
71
+ try {
72
+ let currentInflatedChunk = null;
73
+ currentInflatedChunk = pako_1.default.inflate(currentChunk);
74
+ currentChunks.push(currentInflatedChunk);
75
+ }
76
+ catch (err) {
77
+ throw new parser_error_1.ParserError('ParserError', 'An error occurred while calling pako inflate.' + err);
78
+ }
79
+ }
80
+ let newChunkLength = currentChunks.map(cc => cc.length).reduce((prev, cur) => prev + cur);
81
+ const bigWholeChunk = new Uint8Array(newChunkLength);
82
+ let currentLength = 0;
83
+ for (let i = 0; i < currentChunks.length; i++) {
84
+ bigWholeChunk.set(currentChunks[i], currentLength);
85
+ currentLength += currentChunks[i].length;
86
+ }
87
+ this.currentByte = 0;
88
+ this.maxByte = bigWholeChunk.buffer.byteLength;
89
+ this.bufferView = new DataView(bigWholeChunk.buffer);
90
+ return {
91
+ newChunkLength,
92
+ numChunks: currentChunks.length,
93
+ inflatedData: bigWholeChunk
94
+ };
95
+ }
96
+ static ParseObjects(reader) {
97
+ const totalBodyRestSize = reader.readInt32();
98
+ const objectHeadersBinarySize = reader.readInt32();
99
+ let objects = [];
100
+ level_class_1.Level.ReadObjectHeaders(reader, objects, () => { });
101
+ level_class_1.Level.ReadObjectContents(reader, objects, 0, () => { });
102
+ return objects;
103
+ }
104
+ }
105
+ exports.BlueprintReader = BlueprintReader;
106
+ class BlueprintConfigReader extends byte_reader_class_1.ByteReader {
107
+ constructor(bluePrintConfigBuffer) {
108
+ super(bluePrintConfigBuffer, alignment_enum_1.Alignment.LITTLE_ENDIAN);
109
+ this.bluePrintConfigBuffer = bluePrintConfigBuffer;
110
+ this.parse = () => BlueprintConfigReader.ParseConfig(this);
111
+ }
112
+ static ParseConfig(reader) {
113
+ const unk = reader.readInt32();
114
+ const description = reader.readString();
115
+ const unk3 = reader.readInt32();
116
+ const colorMaybe = (0, util_types_1.ParseCol4RGBA)(reader);
117
+ return {
118
+ description,
119
+ color: colorMaybe,
120
+ iconID: unk3
121
+ };
122
+ }
123
+ }
124
+ exports.BlueprintConfigReader = BlueprintConfigReader;
@@ -0,0 +1,15 @@
1
+ import { ByteWriter } from "../../byte/byte-writer.class";
2
+ import { ChunkCompressionInfo, ChunkSummary } 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 BlueprintWriter extends ByteWriter {
7
+ constructor();
8
+ static SerializeHeader(writer: ByteWriter, header: BlueprintHeader): void;
9
+ generateChunks(compressionInfo: ChunkCompressionInfo, posAfterHeader: number, onBinaryBeforeCompressing: (binary: ArrayBuffer) => void, onHeader: (header: Uint8Array) => void, onChunk: (chunk: Uint8Array) => void): ChunkSummary[];
10
+ static SerializeObjects(writer: ByteWriter, objects: (SaveEntity | SaveComponent)[]): void;
11
+ }
12
+ export declare class BlueprintConfigWriter extends ByteWriter {
13
+ constructor();
14
+ static SerializeConfig(writer: ByteWriter, config: BlueprintConfig): void;
15
+ }