@etothepii/satisfactory-file-parser 0.1.29 → 0.2.1
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.
- package/build/index.d.ts +3 -2
- package/build/index.js +3 -2
- package/build/parser/satisfactory/blueprint/blueprint-reader.js +1 -1
- package/build/parser/satisfactory/edit/edit-constants.d.ts +376 -0
- package/build/parser/satisfactory/edit/edit-constants.js +525 -0
- package/build/parser/satisfactory/objects/ue/FMD5Hash.d.ts +7 -0
- package/build/parser/satisfactory/objects/ue/FMD5Hash.js +19 -0
- package/build/parser/satisfactory/save/save-reader.d.ts +0 -2
- package/build/parser/satisfactory/save/save-reader.js +0 -13
- package/build/parser/satisfactory/save/save.types.d.ts +2 -0
- package/build/parser/satisfactory/structs/util.types.d.ts +2 -0
- package/build/parser/satisfactory/structs/util.types.js +15 -1
- package/build/parser/stream/reworked/readable-stream-parser.js +3 -3
- package/build/parser/stream/reworked/save-stream-json-stringifier.d.ts +6 -0
- package/build/parser/stream/reworked/save-stream-json-stringifier.js +35 -0
- package/build/parser/stream/reworked/save-stream-writer.class.d.ts +27 -0
- package/build/parser/stream/reworked/save-stream-writer.class.js +86 -0
- package/build/parser/stream/reworked/stream-parser.d.ts +1 -3
- package/build/parser/stream/reworked/stream-parser.js +5 -83
- package/build/parser/stream/save-stream-writer.class.d.ts +13 -15
- package/build/parser/stream/save-stream-writer.class.js +103 -70
- package/package.json +1 -1
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
var _a;
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
exports.ReadableStreamParser = void 0;
|
|
5
|
-
const
|
|
6
|
-
const save_reader_1 = require("../../satisfactory/save/save-reader");
|
|
5
|
+
const web_1 = require("node:stream/web");
|
|
7
6
|
const SaveComponent_1 = require("../../satisfactory/objects/SaveComponent");
|
|
8
7
|
const SaveEntity_1 = require("../../satisfactory/objects/SaveEntity");
|
|
9
8
|
const level_class_1 = require("../../satisfactory/save/level.class");
|
|
10
|
-
const
|
|
9
|
+
const satisfactory_save_1 = require("../../satisfactory/save/satisfactory-save");
|
|
10
|
+
const save_reader_1 = require("../../satisfactory/save/save-reader");
|
|
11
11
|
const DEFAULT_BYTE_HIGHWATERMARK = 1024 * 1024 * 200;
|
|
12
12
|
const createStringLengthQueuingStrategy = (highWaterMark = DEFAULT_BYTE_HIGHWATERMARK / 4) => ({
|
|
13
13
|
highWaterMark,
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { WritableStream } from "stream/web";
|
|
3
|
+
import { SatisfactorySave } from "../../..";
|
|
4
|
+
export declare class SaveStreamJsonStringifier {
|
|
5
|
+
static StreamStringifySave(save: SatisfactorySave, output: WritableStream<string>): Promise<void>;
|
|
6
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SaveStreamJsonStringifier = void 0;
|
|
4
|
+
const save_stream_writer_class_1 = require("./save-stream-writer.class");
|
|
5
|
+
class SaveStreamJsonStringifier {
|
|
6
|
+
static async StreamStringifySave(save, output) {
|
|
7
|
+
const writer = new save_stream_writer_class_1.SaveStreamWriter(output.getWriter());
|
|
8
|
+
await writer.beginSave();
|
|
9
|
+
await writer.writeHeader(save.header);
|
|
10
|
+
if (save.compressionInfo) {
|
|
11
|
+
await writer.writeCompressionInfo(save.compressionInfo);
|
|
12
|
+
}
|
|
13
|
+
await writer.writeGridHash(save.gridHash);
|
|
14
|
+
await writer.writeGrids(save.grids);
|
|
15
|
+
await writer.openLevels();
|
|
16
|
+
const objectBatchSize = 10000;
|
|
17
|
+
for (const level of save.levels) {
|
|
18
|
+
await writer.openLevel(level.name);
|
|
19
|
+
let i = 0;
|
|
20
|
+
for (i; i < level.objects.length; i += objectBatchSize) {
|
|
21
|
+
await writer.writeObjects(...level.objects.slice(i, Math.min(i + objectBatchSize, level.objects.length)));
|
|
22
|
+
}
|
|
23
|
+
await writer.switchInLevelToCollectables();
|
|
24
|
+
i = 0;
|
|
25
|
+
for (i; i < level.collectables.length; i += objectBatchSize) {
|
|
26
|
+
await writer.writeCollectables(...level.collectables.slice(i, Math.min(i + objectBatchSize, level.collectables.length)));
|
|
27
|
+
}
|
|
28
|
+
await writer.endLevel();
|
|
29
|
+
}
|
|
30
|
+
await writer.endLevels();
|
|
31
|
+
await writer.endSave();
|
|
32
|
+
await writer.close();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.SaveStreamJsonStringifier = SaveStreamJsonStringifier;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { WritableStreamDefaultWriter } from "stream/web";
|
|
3
|
+
import { ChunkCompressionInfo, ObjectReference, SatisfactorySaveHeader } from "../../..";
|
|
4
|
+
import { SaveObject } from "../../satisfactory/objects/SaveObject";
|
|
5
|
+
import { ByteArray4, Grids } from '../../satisfactory/save/save-reader';
|
|
6
|
+
export declare class SaveStreamWriter {
|
|
7
|
+
private writer;
|
|
8
|
+
private mode;
|
|
9
|
+
private tracker;
|
|
10
|
+
private formatTracker;
|
|
11
|
+
constructor(writer: WritableStreamDefaultWriter<string>);
|
|
12
|
+
private createExecutionFunction;
|
|
13
|
+
beginSave: () => Promise<void>;
|
|
14
|
+
writeHeader: (header: SatisfactorySaveHeader) => Promise<void>;
|
|
15
|
+
writeCompressionInfo: (compressionInfo: ChunkCompressionInfo) => Promise<void>;
|
|
16
|
+
writeGridHash: (gridHash: ByteArray4) => Promise<void>;
|
|
17
|
+
writeGrids: (grids: Grids) => Promise<void>;
|
|
18
|
+
openLevels: () => Promise<void>;
|
|
19
|
+
openLevel: (levelName: string) => Promise<void>;
|
|
20
|
+
writeObjects: (...objects: SaveObject[]) => Promise<void>;
|
|
21
|
+
switchInLevelToCollectables: (...objects: SaveObject[]) => Promise<void>;
|
|
22
|
+
writeCollectables: (...collectables: ObjectReference[]) => Promise<void>;
|
|
23
|
+
endLevel: () => Promise<void>;
|
|
24
|
+
endLevels: () => Promise<void>;
|
|
25
|
+
endSave: () => Promise<void>;
|
|
26
|
+
close(): Promise<void>;
|
|
27
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SaveStreamWriter = void 0;
|
|
4
|
+
class ModeStateTracker {
|
|
5
|
+
constructor(mode) {
|
|
6
|
+
this.mode = mode;
|
|
7
|
+
}
|
|
8
|
+
checkIsComingFrom(...allowedPredecessors) {
|
|
9
|
+
if (!allowedPredecessors.includes(this.mode)) {
|
|
10
|
+
throw new Error(`Wrong order of commands. mode is ${this.mode}. but only ${allowedPredecessors.join(', ')} is/are allowed.`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
advance(newMode) {
|
|
14
|
+
this.mode = newMode;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
class SaveStreamWriter {
|
|
18
|
+
constructor(writer) {
|
|
19
|
+
this.writer = writer;
|
|
20
|
+
this.createExecutionFunction = async (allowedInputModes, fn, targetMode) => {
|
|
21
|
+
this.tracker.checkIsComingFrom(...allowedInputModes);
|
|
22
|
+
await fn();
|
|
23
|
+
this.tracker.advance(targetMode);
|
|
24
|
+
};
|
|
25
|
+
this.beginSave = () => this.createExecutionFunction(['BEFORE_START'], async () => {
|
|
26
|
+
await this.writer.write('{');
|
|
27
|
+
}, 'OPENED_SAVE');
|
|
28
|
+
this.writeHeader = (header) => this.createExecutionFunction(['OPENED_SAVE'], async () => {
|
|
29
|
+
await this.writer.write(`"header": ${JSON.stringify(header)}`);
|
|
30
|
+
}, 'FINISHED_HEADER');
|
|
31
|
+
this.writeCompressionInfo = (compressionInfo) => this.createExecutionFunction(['FINISHED_HEADER'], async () => {
|
|
32
|
+
await this.writer.write(`, "compressionInfo": ${JSON.stringify(compressionInfo)}`);
|
|
33
|
+
}, 'WROTE_COMPRESSION_INFO');
|
|
34
|
+
this.writeGridHash = (gridHash) => this.createExecutionFunction(['WROTE_COMPRESSION_INFO'], async () => {
|
|
35
|
+
await this.writer.write(`, "gridHash": ${JSON.stringify(gridHash)}`);
|
|
36
|
+
}, 'WROTE_GRID_HASH');
|
|
37
|
+
this.writeGrids = (grids) => this.createExecutionFunction(['WROTE_GRID_HASH'], async () => {
|
|
38
|
+
await this.writer.write(`, "grids": ${JSON.stringify(grids)}`);
|
|
39
|
+
}, 'WROTE_GRIDS');
|
|
40
|
+
this.openLevels = () => this.createExecutionFunction(['WROTE_GRIDS'], async () => {
|
|
41
|
+
await this.writer.write(`, "levels": [`);
|
|
42
|
+
}, 'OPENED_LEVELS');
|
|
43
|
+
this.openLevel = (levelName) => this.createExecutionFunction(['OPENED_LEVELS', 'FINISHED_LEVEL'], async () => {
|
|
44
|
+
this.formatTracker.levels.push({
|
|
45
|
+
objectCount: 0, collectablesCount: 0
|
|
46
|
+
});
|
|
47
|
+
const prefix = this.formatTracker.levels.length > 1 ? ', ' : '';
|
|
48
|
+
await this.writer.write(`${prefix}{"name": "${levelName}", "objects": [`);
|
|
49
|
+
}, 'OPENED_LEVEL');
|
|
50
|
+
this.writeObjects = (...objects) => this.createExecutionFunction(['OPENED_LEVEL', 'WROTE_OBJECT'], async () => {
|
|
51
|
+
const stringified = objects.map(saveObj => JSON.stringify(saveObj));
|
|
52
|
+
for (const obj of stringified) {
|
|
53
|
+
await this.writer.write(`${this.formatTracker.levels.at(-1).objectCount >= 1 ? ', ' : ''}${obj}`);
|
|
54
|
+
this.formatTracker.levels.at(-1).objectCount++;
|
|
55
|
+
}
|
|
56
|
+
}, 'WROTE_OBJECT');
|
|
57
|
+
this.switchInLevelToCollectables = (...objects) => this.createExecutionFunction(['OPENED_LEVEL', 'WROTE_OBJECT'], async () => {
|
|
58
|
+
await this.writer.write(`], "collectables": [`);
|
|
59
|
+
}, 'SWITCH_TO_COLLECTABLES');
|
|
60
|
+
this.writeCollectables = (...collectables) => this.createExecutionFunction(['SWITCH_TO_COLLECTABLES', 'WROTE_COLLECTABLE'], async () => {
|
|
61
|
+
const stringified = collectables.map(coll => JSON.stringify(coll));
|
|
62
|
+
for (const obj of stringified) {
|
|
63
|
+
await this.writer.write(`${this.formatTracker.levels.at(-1).collectablesCount >= 1 ? ', ' : ''}${obj}`);
|
|
64
|
+
this.formatTracker.levels.at(-1).collectablesCount++;
|
|
65
|
+
}
|
|
66
|
+
}, 'WROTE_COLLECTABLE');
|
|
67
|
+
this.endLevel = () => this.createExecutionFunction(['SWITCH_TO_COLLECTABLES', 'WROTE_COLLECTABLE'], async () => {
|
|
68
|
+
await this.writer.write(`]}`);
|
|
69
|
+
}, 'FINISHED_LEVEL');
|
|
70
|
+
this.endLevels = () => this.createExecutionFunction(['OPENED_LEVELS', 'FINISHED_LEVEL'], async () => {
|
|
71
|
+
await this.writer.write(`]`);
|
|
72
|
+
}, 'FINISHED_LEVELS');
|
|
73
|
+
this.endSave = () => this.createExecutionFunction(['FINISHED_LEVELS'], async () => {
|
|
74
|
+
await this.writer.write('}');
|
|
75
|
+
}, 'FINISHED_SAVE');
|
|
76
|
+
this.mode = 'BEFORE_START';
|
|
77
|
+
this.tracker = new ModeStateTracker(this.mode);
|
|
78
|
+
this.formatTracker = {
|
|
79
|
+
levels: []
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
async close() {
|
|
83
|
+
return this.writer.close();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
exports.SaveStreamWriter = SaveStreamWriter;
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { WritableStream } from 'stream/web';
|
|
3
3
|
export declare class StreamParser {
|
|
4
|
-
static
|
|
4
|
+
static ParseSaveFileAsynchronousToOutput(bytes: Uint8Array, outputJson: WritableStream<string>, onDecompressedSaveBody?: (buffer: ArrayBuffer) => void, onProgress?: (progress: number, message?: string) => void): Promise<void>;
|
|
5
5
|
private static readLevelsAsync;
|
|
6
|
-
private static ReadNObjectHeaders;
|
|
7
|
-
private static ReadNObjects;
|
|
8
6
|
}
|
|
@@ -2,108 +2,30 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.StreamParser = void 0;
|
|
4
4
|
const __1 = require("../../..");
|
|
5
|
-
const SaveComponent_1 = require("../../satisfactory/objects/SaveComponent");
|
|
6
|
-
const SaveEntity_1 = require("../../satisfactory/objects/SaveEntity");
|
|
7
5
|
class StreamParser {
|
|
8
|
-
static async
|
|
6
|
+
static async ParseSaveFileAsynchronousToOutput(bytes, outputJson, onDecompressedSaveBody = () => { }, onProgress = () => { }) {
|
|
9
7
|
const reader = new __1.SaveReader(bytes.buffer, onProgress);
|
|
10
8
|
const writer = outputJson.getWriter();
|
|
11
9
|
const header = reader.readHeader();
|
|
12
|
-
const save = new __1.SatisfactorySave(
|
|
10
|
+
const save = new __1.SatisfactorySave(header);
|
|
13
11
|
const inflateResult = reader.inflateChunks();
|
|
14
12
|
onDecompressedSaveBody(reader.getBuffer());
|
|
15
13
|
const gridHash = reader.readSaveBodyHash();
|
|
16
14
|
const grids = reader.readGrids();
|
|
17
|
-
await writer.write(`{"header"
|
|
15
|
+
await writer.write(`{"header:" ${JSON.stringify(header)}, "compressionInfo": {}, "gridHash": ${JSON.stringify(gridHash)}, "grids": ${JSON.stringify(grids)}, levels: [`);
|
|
18
16
|
await StreamParser.readLevelsAsync(reader, writer, save.header.mapName, save.header.buildVersion);
|
|
19
17
|
await writer.write(`]}`);
|
|
20
|
-
await writer.ready;
|
|
21
18
|
await writer.close();
|
|
22
19
|
}
|
|
23
20
|
static async readLevelsAsync(reader, writer, mapName, buildVersion) {
|
|
24
21
|
const levelCount = reader.readInt32();
|
|
25
|
-
reader.onProgressCallback(reader.getBufferProgress(), `reading pack of ${levelCount
|
|
26
|
-
const batchingSizeOfObjects = 1000;
|
|
22
|
+
reader.onProgressCallback(reader.getBufferProgress(), `reading pack of ${levelCount} levels.`);
|
|
27
23
|
for (let j = 0; j <= levelCount; j++) {
|
|
28
24
|
let levelName = (j === levelCount) ? '' + mapName : reader.readString();
|
|
29
|
-
if (j %
|
|
25
|
+
if (j % 300 === 0) {
|
|
30
26
|
reader.onProgressCallback(reader.getBufferProgress(), `reading level [${(j + 1)}/${(levelCount + 1)}] ${levelName}`);
|
|
31
27
|
}
|
|
32
|
-
await writer.write(`${j > 0 ? ', ' : ''}{"name": "${levelName}", "objects": [`);
|
|
33
|
-
const headersBinLen = reader.readInt32();
|
|
34
|
-
const unk = reader.readInt32();
|
|
35
|
-
const posBeforeHeaders = reader.getBufferPosition();
|
|
36
|
-
const afterAllHeaders = posBeforeHeaders + headersBinLen;
|
|
37
|
-
let countObjectHeaders = reader.readInt32();
|
|
38
|
-
let totalReadObjects = 0;
|
|
39
|
-
let afterHeadersOfBatch = reader.getBufferPosition();
|
|
40
|
-
let afterObjectsOfBatch = -1;
|
|
41
|
-
do {
|
|
42
|
-
reader.skipBytes(afterHeadersOfBatch - reader.getBufferPosition());
|
|
43
|
-
const objectCountToRead = Math.min(countObjectHeaders - totalReadObjects, batchingSizeOfObjects);
|
|
44
|
-
const objects = StreamParser.ReadNObjectHeaders(reader, objectCountToRead);
|
|
45
|
-
afterHeadersOfBatch = reader.getBufferPosition();
|
|
46
|
-
if (totalReadObjects === 0) {
|
|
47
|
-
reader.skipBytes(afterAllHeaders - reader.getBufferPosition());
|
|
48
|
-
const objectContentsBinLen = reader.readInt32();
|
|
49
|
-
const unk2 = reader.readInt32();
|
|
50
|
-
const posBeforeContents = reader.getBufferPosition();
|
|
51
|
-
const countEntities = reader.readInt32();
|
|
52
|
-
afterObjectsOfBatch = reader.getBufferPosition();
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
reader.skipBytes(afterObjectsOfBatch - reader.getBufferPosition());
|
|
56
|
-
}
|
|
57
|
-
StreamParser.ReadNObjects(reader, objectCountToRead, objects, buildVersion);
|
|
58
|
-
afterObjectsOfBatch = reader.getBufferPosition();
|
|
59
|
-
totalReadObjects += objectCountToRead;
|
|
60
|
-
if (countObjectHeaders > 10000 && totalReadObjects % 10000 === 0) {
|
|
61
|
-
reader.onProgressCallback(reader.getBufferProgress(), `read object count [${(totalReadObjects + 1)}/${(countObjectHeaders + 1)}] in level ${levelName}`);
|
|
62
|
-
}
|
|
63
|
-
await writer.write(`${objects.map(obj => JSON.stringify(obj)).join(', ')}`);
|
|
64
|
-
} while (totalReadObjects < countObjectHeaders);
|
|
65
|
-
await writer.write('], "collectables": [');
|
|
66
|
-
const collectables = __1.Level.ReadCollectablesList(reader);
|
|
67
|
-
await writer.write(`${collectables.map(obj => JSON.stringify(obj)).join(', ')}`);
|
|
68
|
-
await writer.write(']');
|
|
69
|
-
await writer.write('}');
|
|
70
28
|
}
|
|
71
29
|
}
|
|
72
30
|
}
|
|
73
|
-
StreamParser.ReadNObjectHeaders = (reader, count) => {
|
|
74
|
-
let objects = [];
|
|
75
|
-
let objectsRead = 0;
|
|
76
|
-
for (; objectsRead < count; objectsRead++) {
|
|
77
|
-
let obj;
|
|
78
|
-
let objectType = reader.readInt32();
|
|
79
|
-
switch (objectType) {
|
|
80
|
-
case __1.SaveEntity.TypeID:
|
|
81
|
-
obj = new __1.SaveEntity('', '', '', '');
|
|
82
|
-
__1.SaveEntity.ParseHeader(reader, obj);
|
|
83
|
-
break;
|
|
84
|
-
case __1.SaveComponent.TypeID:
|
|
85
|
-
obj = new __1.SaveComponent('', '', '', '');
|
|
86
|
-
__1.SaveComponent.ParseHeader(reader, obj);
|
|
87
|
-
break;
|
|
88
|
-
default:
|
|
89
|
-
throw new Error('Unknown object type' + objectType);
|
|
90
|
-
}
|
|
91
|
-
objects.push(obj);
|
|
92
|
-
}
|
|
93
|
-
return objects;
|
|
94
|
-
};
|
|
95
|
-
StreamParser.ReadNObjects = (reader, count, objects, buildVersion) => {
|
|
96
|
-
for (let i = 0; i < count; i++) {
|
|
97
|
-
objects[i].saveOrBlueprintIndicator = reader.readInt32();
|
|
98
|
-
objects[i].unknownType2 = reader.readInt32();
|
|
99
|
-
const binarySize = reader.readInt32();
|
|
100
|
-
const before = reader.getBufferPosition();
|
|
101
|
-
if ((0, SaveEntity_1.isSaveEntity)(objects[i])) {
|
|
102
|
-
__1.SaveEntity.ParseData(objects[i], binarySize, reader, buildVersion, objects[i].typePath);
|
|
103
|
-
}
|
|
104
|
-
else if ((0, SaveComponent_1.isSaveComponent)(objects[i])) {
|
|
105
|
-
__1.SaveComponent.ParseData(objects[i], binarySize, reader, buildVersion, objects[i].typePath);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
31
|
exports.StreamParser = StreamParser;
|
|
@@ -6,22 +6,20 @@ import { ByteArray4, Grids } from '../satisfactory/save/save-reader';
|
|
|
6
6
|
export declare class SaveStreamWriter {
|
|
7
7
|
private writer;
|
|
8
8
|
private mode;
|
|
9
|
-
private tracker;
|
|
10
9
|
private formatTracker;
|
|
11
10
|
constructor(writer: WritableStreamDefaultWriter<string>);
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
endSave: () => Promise<void>;
|
|
11
|
+
beginSave(): Promise<void>;
|
|
12
|
+
writeHeader(header: SatisfactorySaveHeader): Promise<void>;
|
|
13
|
+
writeCompressionInfo(compressionInfo: ChunkCompressionInfo): Promise<void>;
|
|
14
|
+
writeGridHash(gridHash: ByteArray4): Promise<void>;
|
|
15
|
+
writeGrids(grids: Grids): Promise<void>;
|
|
16
|
+
openLevels(): Promise<void>;
|
|
17
|
+
openLevel(levelName: string): Promise<void>;
|
|
18
|
+
writeObjects(...objects: SaveObject[]): Promise<void>;
|
|
19
|
+
switchInLevelToCollectables(): Promise<void>;
|
|
20
|
+
writeCollectables(...collectables: ObjectReference[]): Promise<void>;
|
|
21
|
+
endLevel(): Promise<void>;
|
|
22
|
+
endLevels(): Promise<void>;
|
|
23
|
+
endSave(): Promise<void>;
|
|
26
24
|
close(): Promise<void>;
|
|
27
25
|
}
|
|
@@ -1,84 +1,117 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SaveStreamWriter = void 0;
|
|
4
|
-
class ModeStateTracker {
|
|
5
|
-
constructor(mode) {
|
|
6
|
-
this.mode = mode;
|
|
7
|
-
}
|
|
8
|
-
checkIsComingFrom(...allowedPredecessors) {
|
|
9
|
-
if (!allowedPredecessors.includes(this.mode)) {
|
|
10
|
-
throw new Error(`Wrong order of commands. mode is ${this.mode}. but only ${allowedPredecessors.join(', ')} is/are allowed.`);
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
advance(newMode) {
|
|
14
|
-
this.mode = newMode;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
4
|
class SaveStreamWriter {
|
|
18
5
|
constructor(writer) {
|
|
19
6
|
this.writer = writer;
|
|
20
|
-
this.createExecutionFunction = async (allowedInputModes, fn, targetMode) => {
|
|
21
|
-
this.tracker.checkIsComingFrom(...allowedInputModes);
|
|
22
|
-
await fn();
|
|
23
|
-
this.tracker.advance(targetMode);
|
|
24
|
-
};
|
|
25
|
-
this.beginSave = () => this.createExecutionFunction(['BEFORE_START'], async () => {
|
|
26
|
-
await this.writer.write('{');
|
|
27
|
-
}, 'OPENED_SAVE');
|
|
28
|
-
this.writeHeader = (header) => this.createExecutionFunction(['OPENED_SAVE'], async () => {
|
|
29
|
-
await this.writer.write(`"header": ${JSON.stringify(header)}`);
|
|
30
|
-
}, 'FINISHED_HEADER');
|
|
31
|
-
this.writeCompressionInfo = (compressionInfo) => this.createExecutionFunction(['FINISHED_HEADER'], async () => {
|
|
32
|
-
await this.writer.write(`, "compressionInfo": ${JSON.stringify(compressionInfo)}`);
|
|
33
|
-
}, 'WROTE_COMPRESSION_INFO');
|
|
34
|
-
this.writeGridHash = (gridHash) => this.createExecutionFunction(['WROTE_COMPRESSION_INFO'], async () => {
|
|
35
|
-
await this.writer.write(`, "gridHash": ${JSON.stringify(gridHash)}`);
|
|
36
|
-
}, 'WROTE_GRID_HASH');
|
|
37
|
-
this.writeGrids = (grids) => this.createExecutionFunction(['WROTE_GRID_HASH'], async () => {
|
|
38
|
-
await this.writer.write(`, "grids": ${JSON.stringify(grids)}`);
|
|
39
|
-
}, 'WROTE_GRIDS');
|
|
40
|
-
this.openLevels = () => this.createExecutionFunction(['WROTE_GRIDS'], async () => {
|
|
41
|
-
await this.writer.write(`, "levels": [`);
|
|
42
|
-
}, 'OPENED_LEVELS');
|
|
43
|
-
this.openLevel = (levelName) => this.createExecutionFunction(['OPENED_LEVELS', 'FINISHED_LEVEL'], async () => {
|
|
44
|
-
this.formatTracker.levels.push({
|
|
45
|
-
objectCount: 0, collectablesCount: 0
|
|
46
|
-
});
|
|
47
|
-
const prefix = this.formatTracker.levels.length > 1 ? ', ' : '';
|
|
48
|
-
await this.writer.write(`${prefix}{"name": "${levelName}", "objects": [`);
|
|
49
|
-
}, 'OPENED_LEVEL');
|
|
50
|
-
this.writeObjects = (...objects) => this.createExecutionFunction(['OPENED_LEVEL', 'WROTE_OBJECT'], async () => {
|
|
51
|
-
const stringified = objects.map(saveObj => JSON.stringify(saveObj));
|
|
52
|
-
for (const obj of stringified) {
|
|
53
|
-
await this.writer.write(`${this.formatTracker.levels.at(-1).objectCount >= 1 ? ', ' : ''}${obj}`);
|
|
54
|
-
this.formatTracker.levels.at(-1).objectCount++;
|
|
55
|
-
}
|
|
56
|
-
}, 'WROTE_OBJECT');
|
|
57
|
-
this.switchInLevelToCollectables = (...objects) => this.createExecutionFunction(['OPENED_LEVEL', 'WROTE_OBJECT'], async () => {
|
|
58
|
-
await this.writer.write(`], "collectables": [`);
|
|
59
|
-
}, 'SWITCH_TO_COLLECTABLES');
|
|
60
|
-
this.writeCollectables = (...collectables) => this.createExecutionFunction(['SWITCH_TO_COLLECTABLES', 'WROTE_COLLECTABLE'], async () => {
|
|
61
|
-
const stringified = collectables.map(coll => JSON.stringify(coll));
|
|
62
|
-
for (const obj of stringified) {
|
|
63
|
-
await this.writer.write(`${this.formatTracker.levels.at(-1).collectablesCount >= 1 ? ', ' : ''}${obj}`);
|
|
64
|
-
this.formatTracker.levels.at(-1).collectablesCount++;
|
|
65
|
-
}
|
|
66
|
-
}, 'WROTE_COLLECTABLE');
|
|
67
|
-
this.endLevel = () => this.createExecutionFunction(['SWITCH_TO_COLLECTABLES', 'WROTE_COLLECTABLE'], async () => {
|
|
68
|
-
await this.writer.write(`]}`);
|
|
69
|
-
}, 'FINISHED_LEVEL');
|
|
70
|
-
this.endLevels = () => this.createExecutionFunction(['OPENED_LEVELS', 'FINISHED_LEVEL'], async () => {
|
|
71
|
-
await this.writer.write(`]`);
|
|
72
|
-
}, 'FINISHED_LEVELS');
|
|
73
|
-
this.endSave = () => this.createExecutionFunction(['FINISHED_LEVELS'], async () => {
|
|
74
|
-
await this.writer.write('}');
|
|
75
|
-
}, 'FINISHED_SAVE');
|
|
76
7
|
this.mode = 'BEFORE_START';
|
|
77
|
-
this.tracker = new ModeStateTracker(this.mode);
|
|
78
8
|
this.formatTracker = {
|
|
79
9
|
levels: []
|
|
80
10
|
};
|
|
81
11
|
}
|
|
12
|
+
async beginSave() {
|
|
13
|
+
if (this.mode !== 'BEFORE_START') {
|
|
14
|
+
throw new Error(`Wrong order of commands. Already opened save. mode is ${this.mode}.`);
|
|
15
|
+
}
|
|
16
|
+
await this.writer.write('{');
|
|
17
|
+
this.mode = 'OPENED_SAVE';
|
|
18
|
+
}
|
|
19
|
+
async writeHeader(header) {
|
|
20
|
+
if (this.mode !== 'OPENED_SAVE') {
|
|
21
|
+
throw new Error(`Wrong order of commands. Header has to come after save open. mode is ${this.mode}.`);
|
|
22
|
+
}
|
|
23
|
+
await this.writer.write(`"header": ${JSON.stringify(header)}`);
|
|
24
|
+
this.mode = 'FINISHED_HEADER';
|
|
25
|
+
}
|
|
26
|
+
async writeCompressionInfo(compressionInfo) {
|
|
27
|
+
if (this.mode !== 'FINISHED_HEADER') {
|
|
28
|
+
throw new Error(`Wrong order of commands. Compression info has to come after header. mode is ${this.mode}.`);
|
|
29
|
+
}
|
|
30
|
+
await this.writer.write(`, "compressionInfo": ${JSON.stringify(compressionInfo)}`);
|
|
31
|
+
this.mode = 'WROTE_COMPRESSION_INFO';
|
|
32
|
+
}
|
|
33
|
+
async writeGridHash(gridHash) {
|
|
34
|
+
if (this.mode !== 'WROTE_COMPRESSION_INFO') {
|
|
35
|
+
throw new Error(`Wrong order of commands. Save hbody hash has to come after compression info. mode is ${this.mode}.`);
|
|
36
|
+
}
|
|
37
|
+
await this.writer.write(`, "gridHash": ${JSON.stringify(gridHash)}`);
|
|
38
|
+
this.mode = 'WROTE_GRID_HASH';
|
|
39
|
+
}
|
|
40
|
+
async writeGrids(grids) {
|
|
41
|
+
if (this.mode !== 'WROTE_GRID_HASH') {
|
|
42
|
+
throw new Error(`Wrong order of commands. Grids have to come after save body hash info. mode is ${this.mode}.`);
|
|
43
|
+
}
|
|
44
|
+
await this.writer.write(`, "grids": ${JSON.stringify(grids)}`);
|
|
45
|
+
this.mode = 'WROTE_GRIDS';
|
|
46
|
+
}
|
|
47
|
+
async openLevels() {
|
|
48
|
+
if (this.mode !== 'WROTE_GRIDS') {
|
|
49
|
+
throw new Error(`Wrong order of commands. Levels have to come after grids info. mode is ${this.mode}.`);
|
|
50
|
+
}
|
|
51
|
+
await this.writer.write(`, "levels": [`);
|
|
52
|
+
this.mode = 'OPENED_LEVELS';
|
|
53
|
+
}
|
|
54
|
+
async openLevel(levelName) {
|
|
55
|
+
if (this.mode !== 'OPENED_LEVELS' && this.mode !== 'FINISHED_LEVEL') {
|
|
56
|
+
throw new Error(`Wrong order of commands. Single level can only come after opening levels array or after finishing single level. mode is ${this.mode}.`);
|
|
57
|
+
}
|
|
58
|
+
this.formatTracker.levels.push({
|
|
59
|
+
objectCount: 0, collectablesCount: 0
|
|
60
|
+
});
|
|
61
|
+
const prefix = this.formatTracker.levels.length > 1 ? ', ' : '';
|
|
62
|
+
await this.writer.write(`${prefix}{"name": "${levelName}", "objects": [`);
|
|
63
|
+
this.mode = 'OPENED_LEVEL';
|
|
64
|
+
}
|
|
65
|
+
async writeObjects(...objects) {
|
|
66
|
+
if (this.mode !== 'OPENED_LEVEL' && this.mode !== 'WROTE_OBJECT') {
|
|
67
|
+
throw new Error(`Wrong order of commands. An object can not be written into the level if it was not opened or other objects were not written. mode is ${this.mode}.`);
|
|
68
|
+
}
|
|
69
|
+
const stringified = objects.map(saveObj => JSON.stringify(saveObj));
|
|
70
|
+
for (const obj of stringified) {
|
|
71
|
+
await this.writer.write(`${this.formatTracker.levels.at(-1).objectCount >= 1 ? ', ' : ''}${obj}`);
|
|
72
|
+
this.formatTracker.levels.at(-1).objectCount++;
|
|
73
|
+
}
|
|
74
|
+
this.mode = 'WROTE_OBJECT';
|
|
75
|
+
}
|
|
76
|
+
async switchInLevelToCollectables() {
|
|
77
|
+
if (this.mode !== 'OPENED_LEVEL' && this.mode !== 'WROTE_OBJECT') {
|
|
78
|
+
throw new Error(`Wrong order of commands. The level structure can not be switched to collectables if the level was not opened recently or has not written objects. mode is ${this.mode}.`);
|
|
79
|
+
}
|
|
80
|
+
await this.writer.write(`], "collectables": [`);
|
|
81
|
+
this.mode = 'SWITCH_TO_COLLECTABLES';
|
|
82
|
+
}
|
|
83
|
+
async writeCollectables(...collectables) {
|
|
84
|
+
if (this.mode !== 'SWITCH_TO_COLLECTABLES' && this.mode !== 'WROTE_COLLECTABLE') {
|
|
85
|
+
throw new Error(`Wrong order of commands. A collectable can not be written into the level if we did not switch to collectables or other collectables were not written. mode is ${this.mode}.`);
|
|
86
|
+
}
|
|
87
|
+
const stringified = collectables.map(coll => JSON.stringify(coll));
|
|
88
|
+
for (const obj of stringified) {
|
|
89
|
+
await this.writer.write(`${this.formatTracker.levels.at(-1).collectablesCount >= 1 ? ', ' : ''}${obj}`);
|
|
90
|
+
this.formatTracker.levels.at(-1).collectablesCount++;
|
|
91
|
+
}
|
|
92
|
+
this.mode = 'WROTE_COLLECTABLE';
|
|
93
|
+
}
|
|
94
|
+
async endLevel() {
|
|
95
|
+
if (this.mode !== 'SWITCH_TO_COLLECTABLES' && this.mode !== 'WROTE_COLLECTABLE') {
|
|
96
|
+
throw new Error(`Wrong order of commands. Single level can not be closed if a switch to collectibles or writing of collectible did not happen. mode is ${this.mode}.`);
|
|
97
|
+
}
|
|
98
|
+
await this.writer.write(`]}`);
|
|
99
|
+
this.mode = 'FINISHED_LEVEL';
|
|
100
|
+
}
|
|
101
|
+
async endLevels() {
|
|
102
|
+
if (this.mode !== 'OPENED_LEVELS' && this.mode !== 'FINISHED_LEVEL') {
|
|
103
|
+
throw new Error(`Wrong order of commands. Levels can only be closed after opening levels array or after finishing single level. mode is ${this.mode}.`);
|
|
104
|
+
}
|
|
105
|
+
await this.writer.write(`]`);
|
|
106
|
+
this.mode = 'FINISHED_LEVELS';
|
|
107
|
+
}
|
|
108
|
+
async endSave() {
|
|
109
|
+
if (this.mode !== 'FINISHED_LEVELS') {
|
|
110
|
+
throw new Error(`Wrong order of commands. Save has to end after levels. mode is ${this.mode}.`);
|
|
111
|
+
}
|
|
112
|
+
await this.writer.write('}');
|
|
113
|
+
this.mode = 'FINISHED_SAVE';
|
|
114
|
+
}
|
|
82
115
|
async close() {
|
|
83
116
|
return this.writer.close();
|
|
84
117
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@etothepii/satisfactory-file-parser",
|
|
3
3
|
"author": "etothepii",
|
|
4
|
-
"version": "0.1
|
|
4
|
+
"version": "0.2.1",
|
|
5
5
|
"description": "A file parser for satisfactory files. Includes save files and blueprint files.",
|
|
6
6
|
"types": "./build/index.d.ts",
|
|
7
7
|
"main": "./build/index.js",
|