@etothepii/satisfactory-file-parser 0.4.13 → 0.4.15
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/LICENCE.md +1 -1
- package/README.md +64 -28
- package/build/parser/byte/binary-readable.interface.d.ts +0 -3
- package/build/parser/byte/binary-writable.interface.d.ts +20 -0
- package/build/parser/byte/binary-writable.interface.js +2 -0
- package/build/parser/byte/byte-reader.class.d.ts +0 -3
- package/build/parser/byte/byte-reader.class.js +0 -8
- package/build/parser/byte/byte-writer.class.d.ts +6 -3
- package/build/parser/byte/byte-writer.class.js +3 -1
- package/build/parser/satisfactory/blueprint/blueprint-reader.js +8 -8
- package/build/parser/satisfactory/edit/edit-constants.d.ts +2 -0
- package/build/parser/satisfactory/edit/edit-constants.js +82 -158
- package/build/parser/satisfactory/objects/DataFields.js +9 -9
- package/build/parser/satisfactory/objects/SaveObject.d.ts +1 -1
- package/build/parser/satisfactory/objects/SaveObject.js +1 -1
- package/build/parser/satisfactory/objects/property/generic/FloatProperty.js +1 -1
- package/build/parser/satisfactory/objects/property/generic/StructProperty.js +11 -4
- package/build/parser/satisfactory/save/level.class.d.ts +1 -2
- package/build/parser/satisfactory/save/level.class.js +10 -15
- package/build/parser/satisfactory/save/save-reader.js +8 -4
- package/build/parser/satisfactory/save/save.types.d.ts +0 -25
- package/build/parser/satisfactory/structs/util.types.js +8 -8
- package/build/parser/stream/reworked/readable-stream-parser.d.ts +1 -0
- package/build/parser/stream/reworked/readable-stream-parser.js +28 -3
- package/package.json +1 -1
- package/build/parser/satisfactory/objects/ObjectReference.d.ts +0 -10
- package/build/parser/satisfactory/objects/ObjectReference.js +0 -17
- package/build/parser/satisfactory/objects/Property.d.ts +0 -272
- package/build/parser/satisfactory/objects/Property.js +0 -1177
- package/build/parser/satisfactory/objects/ue/FMD5Hash.d.ts +0 -7
- package/build/parser/satisfactory/objects/ue/FMD5Hash.js +0 -19
- package/build/parser/satisfactory/objects/ue/GUID.d.ts +0 -6
- package/build/parser/satisfactory/objects/ue/GUID.js +0 -21
- package/build/parser/satisfactory/save/asynchronous-level.class.d.ts +0 -9
- package/build/parser/satisfactory/save/asynchronous-level.class.js +0 -66
- package/build/parser/stream/byte-stream-reader.class.d.ts +0 -57
- package/build/parser/stream/byte-stream-reader.class.js +0 -241
- package/build/parser/stream/json-stream-state-writer.d.ts +0 -12
- package/build/parser/stream/json-stream-state-writer.js +0 -18
- package/build/parser/stream/json-stream-writable.d.ts +0 -20
- package/build/parser/stream/json-stream-writable.js +0 -83
- package/build/parser/stream/json-stream-writer.d.ts +0 -22
- package/build/parser/stream/json-stream-writer.js +0 -127
- package/build/parser/stream/reworked/stream-parser.d.ts +0 -6
- package/build/parser/stream/reworked/stream-parser.js +0 -31
- package/build/parser/stream/save-stream-json-stringifier.d.ts +0 -6
- package/build/parser/stream/save-stream-json-stringifier.js +0 -35
- package/build/parser/stream/save-stream-reader.class.d.ts +0 -15
- package/build/parser/stream/save-stream-reader.class.js +0 -121
- package/build/parser/stream/save-stream-writer.class.d.ts +0 -25
- package/build/parser/stream/save-stream-writer.class.js +0 -119
- package/build/parser/stream/stream-level.class.d.ts +0 -12
- package/build/parser/stream/stream-level.class.js +0 -103
- package/build/parser/stream/stream-parser.d.ts +0 -40
- package/build/parser/stream/stream-parser.js +0 -225
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.JsonStreamWriter = void 0;
|
|
4
|
-
const json_stream_state_writer_1 = require("./json-stream-state-writer");
|
|
5
|
-
class JsonStreamWriter extends json_stream_state_writer_1.JsonStreamStateWriter {
|
|
6
|
-
constructor(writer) {
|
|
7
|
-
super(async (value) => await writer.write(value), 'BEFORE_START');
|
|
8
|
-
this.writer = writer;
|
|
9
|
-
this.stateMachine = {
|
|
10
|
-
openSave: {
|
|
11
|
-
name: 'Open Save',
|
|
12
|
-
requiresOneOfThemToBeBefore: ['BEFORE_START'],
|
|
13
|
-
do: async () => await this.startObject(),
|
|
14
|
-
assignOnFinish: 'OPENED_SAVE',
|
|
15
|
-
},
|
|
16
|
-
writeHeader: {
|
|
17
|
-
name: 'Write Header',
|
|
18
|
-
requiresOneOfThemToBeBefore: ['OPENED_SAVE'],
|
|
19
|
-
do: async (param) => await this.writeProperty('header', Promise.resolve(JSON.stringify(param))),
|
|
20
|
-
assignOnFinish: 'FINISHED_HEADER',
|
|
21
|
-
},
|
|
22
|
-
writeCompressionInfo: {
|
|
23
|
-
name: 'Write Compression Info',
|
|
24
|
-
requiresOneOfThemToBeBefore: ['FINISHED_HEADER'],
|
|
25
|
-
do: async (param) => await this.writeProperty('compressionInfo', Promise.resolve(JSON.stringify(param))),
|
|
26
|
-
assignOnFinish: 'WROTE_COMPRESSION_INFO',
|
|
27
|
-
},
|
|
28
|
-
openLevels: {
|
|
29
|
-
name: 'Open Levels',
|
|
30
|
-
requiresOneOfThemToBeBefore: ['WROTE_COMPRESSION_INFO'],
|
|
31
|
-
do: async () => await this.startArray(),
|
|
32
|
-
assignOnFinish: 'OPENED_LEVELS',
|
|
33
|
-
},
|
|
34
|
-
openLevel: {
|
|
35
|
-
name: 'Open Level',
|
|
36
|
-
requiresOneOfThemToBeBefore: ['OPENED_LEVELS', 'FINISHED_LEVEL'],
|
|
37
|
-
do: async (param) => {
|
|
38
|
-
await this.writePropertyName(param);
|
|
39
|
-
await this.startObject();
|
|
40
|
-
await this.writeProperty('name', Promise.resolve(param));
|
|
41
|
-
await this.writePropertyName('objects');
|
|
42
|
-
await this.startArray();
|
|
43
|
-
},
|
|
44
|
-
assignOnFinish: 'OPENED_LEVEL',
|
|
45
|
-
},
|
|
46
|
-
writeObject: {
|
|
47
|
-
name: 'Write Object',
|
|
48
|
-
requiresOneOfThemToBeBefore: ['OPENED_LEVEL', 'WROTE_OBJECT'],
|
|
49
|
-
do: async (param) => await this.writeValue(Promise.resolve(JSON.stringify(param))),
|
|
50
|
-
assignOnFinish: 'WROTE_OBJECT',
|
|
51
|
-
},
|
|
52
|
-
switchToCollectables: {
|
|
53
|
-
name: 'Switch To collectables',
|
|
54
|
-
requiresOneOfThemToBeBefore: ['OPENED_LEVEL', 'WROTE_OBJECT'],
|
|
55
|
-
do: async () => {
|
|
56
|
-
await this.endArray();
|
|
57
|
-
await this.writePropertyName('collectables');
|
|
58
|
-
await this.startArray();
|
|
59
|
-
},
|
|
60
|
-
assignOnFinish: 'SWITCH_TO_COLLECTABLES',
|
|
61
|
-
},
|
|
62
|
-
writeCollectable: {
|
|
63
|
-
name: 'Write Collectables',
|
|
64
|
-
requiresOneOfThemToBeBefore: ['SWITCH_TO_COLLECTABLES'],
|
|
65
|
-
do: async (param) => {
|
|
66
|
-
await this.writeValue(Promise.resolve(JSON.stringify(param)));
|
|
67
|
-
},
|
|
68
|
-
assignOnFinish: 'WROTE_COLLECTABLE',
|
|
69
|
-
},
|
|
70
|
-
closeLevel: {
|
|
71
|
-
name: 'Close Level',
|
|
72
|
-
requiresOneOfThemToBeBefore: ['SWITCH_TO_COLLECTABLES', 'WROTE_COLLECTABLE'],
|
|
73
|
-
do: async () => {
|
|
74
|
-
await this.endArray();
|
|
75
|
-
await this.endObject();
|
|
76
|
-
},
|
|
77
|
-
assignOnFinish: 'FINISHED_LEVEL',
|
|
78
|
-
},
|
|
79
|
-
closeLevels: {
|
|
80
|
-
name: 'Close Levels',
|
|
81
|
-
requiresOneOfThemToBeBefore: [],
|
|
82
|
-
do: async () => await this.endArray(),
|
|
83
|
-
assignOnFinish: "FINISHED_LEVELS",
|
|
84
|
-
},
|
|
85
|
-
closeSave: {
|
|
86
|
-
name: 'Close Save',
|
|
87
|
-
requiresOneOfThemToBeBefore: ['FINISHED_LEVELS'],
|
|
88
|
-
do: async () => await this.startObject(),
|
|
89
|
-
assignOnFinish: 'FINISHED_SAVE',
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
async beginSave() {
|
|
94
|
-
await this.useTransition(this.stateMachine.openSave);
|
|
95
|
-
}
|
|
96
|
-
async writeHeader(header) {
|
|
97
|
-
await this.useTransition(this.stateMachine.writeHeader, header);
|
|
98
|
-
}
|
|
99
|
-
async writeCompressionInfo(compressionInfo) {
|
|
100
|
-
await this.useTransition(this.stateMachine.writeCompressionInfo, compressionInfo);
|
|
101
|
-
}
|
|
102
|
-
async openLevels() {
|
|
103
|
-
await this.useTransition(this.stateMachine.openLevels);
|
|
104
|
-
}
|
|
105
|
-
async openLevel() {
|
|
106
|
-
await this.useTransition(this.stateMachine.openLevel);
|
|
107
|
-
}
|
|
108
|
-
async writeObject(object) {
|
|
109
|
-
await this.useTransition(this.stateMachine.writeObject, object);
|
|
110
|
-
}
|
|
111
|
-
async switchToCollectables() {
|
|
112
|
-
await this.useTransition(this.stateMachine.switchToCollectables);
|
|
113
|
-
}
|
|
114
|
-
async writeCollectable(object) {
|
|
115
|
-
await this.useTransition(this.stateMachine.writeCollectable, object);
|
|
116
|
-
}
|
|
117
|
-
async closeLevel() {
|
|
118
|
-
await this.useTransition(this.stateMachine.closeLevel);
|
|
119
|
-
}
|
|
120
|
-
async closeLevels() {
|
|
121
|
-
await this.useTransition(this.stateMachine.closeLevels);
|
|
122
|
-
}
|
|
123
|
-
async endSave() {
|
|
124
|
-
await this.useTransition(this.stateMachine.closeSave);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
exports.JsonStreamWriter = JsonStreamWriter;
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
import { WritableStream } from 'stream/web';
|
|
3
|
-
export declare class StreamParser {
|
|
4
|
-
static ParseSaveFileAsynchronousToOutput(bytes: Uint8Array, outputJson: WritableStream<string>, onDecompressedSaveBody?: (buffer: ArrayBuffer) => void, onProgress?: (progress: number, message?: string) => void): Promise<void>;
|
|
5
|
-
private static readLevelsAsync;
|
|
6
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.StreamParser = void 0;
|
|
4
|
-
const __1 = require("../../..");
|
|
5
|
-
class StreamParser {
|
|
6
|
-
static async ParseSaveFileAsynchronousToOutput(bytes, outputJson, onDecompressedSaveBody = () => { }, onProgress = () => { }) {
|
|
7
|
-
const reader = new __1.SaveReader(bytes.buffer, onProgress);
|
|
8
|
-
const writer = outputJson.getWriter();
|
|
9
|
-
const header = reader.readHeader();
|
|
10
|
-
const save = new __1.SatisfactorySave(header);
|
|
11
|
-
const inflateResult = reader.inflateChunks();
|
|
12
|
-
onDecompressedSaveBody(reader.getBuffer());
|
|
13
|
-
const gridHash = reader.readSaveBodyHash();
|
|
14
|
-
const grids = reader.readGrids();
|
|
15
|
-
await writer.write(`{"header:" ${JSON.stringify(header)}, "compressionInfo": {}, "gridHash": ${JSON.stringify(gridHash)}, "grids": ${JSON.stringify(grids)}, levels: [`);
|
|
16
|
-
await StreamParser.readLevelsAsync(reader, writer, save.header.mapName, save.header.buildVersion);
|
|
17
|
-
await writer.write(`]}`);
|
|
18
|
-
await writer.close();
|
|
19
|
-
}
|
|
20
|
-
static async readLevelsAsync(reader, writer, mapName, buildVersion) {
|
|
21
|
-
const levelCount = reader.readInt32();
|
|
22
|
-
reader.onProgressCallback(reader.getBufferProgress(), `reading pack of ${levelCount} levels.`);
|
|
23
|
-
for (let j = 0; j <= levelCount; j++) {
|
|
24
|
-
let levelName = (j === levelCount) ? '' + mapName : reader.readString();
|
|
25
|
-
if (j % 300 === 0) {
|
|
26
|
-
reader.onProgressCallback(reader.getBufferProgress(), `reading level [${(j + 1)}/${(levelCount + 1)}] ${levelName}`);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
exports.StreamParser = StreamParser;
|
|
@@ -1,6 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
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;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
import { ReadableStreamDefaultReader } from "stream/web";
|
|
3
|
-
import { ChunkCompressionInfo, SatisfactorySaveHeader } from "../..";
|
|
4
|
-
import { ByteStreamReader } from "./byte-stream-reader.class";
|
|
5
|
-
import { SaveStreamWriter } from "./save-stream-writer.class";
|
|
6
|
-
export declare class SaveStreamReader extends ByteStreamReader {
|
|
7
|
-
static readonly EPOCH_TICKS = 621355968000000000n;
|
|
8
|
-
static readonly DEFAULT_SATISFACTORY_CHUNK_HEADER_SIZE = 48;
|
|
9
|
-
compressionInfo: ChunkCompressionInfo;
|
|
10
|
-
constructor(reader: ReadableStreamDefaultReader<Uint8Array>, maxBufferThreshold: number, onCloseCallback?: () => Promise<void>);
|
|
11
|
-
readHeader(): Promise<SatisfactorySaveHeader>;
|
|
12
|
-
readBodyChunk(): Promise<Uint8Array>;
|
|
13
|
-
debugInfo(): string;
|
|
14
|
-
streamLevelsToOutput(writer: SaveStreamWriter, header: SatisfactorySaveHeader): Promise<void>;
|
|
15
|
-
}
|
|
@@ -1,121 +0,0 @@
|
|
|
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.SaveStreamReader = void 0;
|
|
7
|
-
const pako_1 = __importDefault(require("pako"));
|
|
8
|
-
const __1 = require("../..");
|
|
9
|
-
const alignment_enum_1 = require("../byte/alignment.enum");
|
|
10
|
-
const byte_stream_reader_class_1 = require("./byte-stream-reader.class");
|
|
11
|
-
const stream_level_class_1 = require("./stream-level.class");
|
|
12
|
-
class SaveStreamReader extends byte_stream_reader_class_1.ByteStreamReader {
|
|
13
|
-
constructor(reader, maxBufferThreshold, onCloseCallback = async () => { }) {
|
|
14
|
-
super(reader, onCloseCallback, 30000, maxBufferThreshold, alignment_enum_1.Alignment.LITTLE_ENDIAN);
|
|
15
|
-
this.compressionInfo = {
|
|
16
|
-
packageFileTag: 0,
|
|
17
|
-
maxUncompressedChunkContentSize: 0,
|
|
18
|
-
chunkHeaderSize: SaveStreamReader.DEFAULT_SATISFACTORY_CHUNK_HEADER_SIZE
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
async readHeader() {
|
|
22
|
-
const header = {
|
|
23
|
-
saveHeaderType: 0,
|
|
24
|
-
saveVersion: 0,
|
|
25
|
-
buildVersion: 0,
|
|
26
|
-
mapName: "DEFAULT",
|
|
27
|
-
mapOptions: "",
|
|
28
|
-
sessionName: "",
|
|
29
|
-
playDurationSeconds: 0,
|
|
30
|
-
saveDateTime: "0",
|
|
31
|
-
sessionVisibility: 0
|
|
32
|
-
};
|
|
33
|
-
await this.allocate(400);
|
|
34
|
-
console.log(`safely reading header stuff now. ${this.currentByte} ${this.operatingDataView.byteLength} ${this.operatingStreamBuffer.byteLength}`);
|
|
35
|
-
header.saveHeaderType = this.readInt32();
|
|
36
|
-
header.saveVersion = this.readInt32();
|
|
37
|
-
header.buildVersion = this.readInt32();
|
|
38
|
-
header.mapName = this.readString();
|
|
39
|
-
header.mapOptions = this.readString();
|
|
40
|
-
header.sessionName = this.readString();
|
|
41
|
-
header.playDurationSeconds = this.readInt32();
|
|
42
|
-
const rawSaveDateTimeInTicks = this.readLong();
|
|
43
|
-
const unixMilliseconds = (rawSaveDateTimeInTicks - SaveStreamReader.EPOCH_TICKS) / 10000n;
|
|
44
|
-
header.saveDateTime = unixMilliseconds.toString();
|
|
45
|
-
header.sessionVisibility = this.readByte();
|
|
46
|
-
if (header.saveHeaderType >= 7) {
|
|
47
|
-
header.fEditorObjectVersion = this.readInt32();
|
|
48
|
-
}
|
|
49
|
-
if (header.saveHeaderType >= 8) {
|
|
50
|
-
header.rawModMetadataString = this.readString();
|
|
51
|
-
try {
|
|
52
|
-
header.modMetadata = JSON.parse(header.rawModMetadataString);
|
|
53
|
-
}
|
|
54
|
-
catch (error) {
|
|
55
|
-
}
|
|
56
|
-
header.isModdedSave = this.readInt32();
|
|
57
|
-
}
|
|
58
|
-
if (header.saveHeaderType >= 10) {
|
|
59
|
-
header.saveIdentifier = this.readString();
|
|
60
|
-
}
|
|
61
|
-
if (header.saveVersion >= 21) {
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
64
|
-
throw new __1.UnsupportedVersionError("The save version is too old to support encoding currently. Save in newer game version.");
|
|
65
|
-
}
|
|
66
|
-
return header;
|
|
67
|
-
}
|
|
68
|
-
async readBodyChunk() {
|
|
69
|
-
await this.allocate(this.compressionInfo.chunkHeaderSize);
|
|
70
|
-
this.operatingStreamBuffer = this.operatingStreamBuffer.slice(this.currentByte);
|
|
71
|
-
this.operatingDataView = new DataView(this.operatingStreamBuffer.buffer);
|
|
72
|
-
this.currentByte = 0;
|
|
73
|
-
if (this.compressionInfo.packageFileTag <= 0) {
|
|
74
|
-
this.compressionInfo.packageFileTag = this.operatingDataView.getInt32(0, this.alignment === alignment_enum_1.Alignment.LITTLE_ENDIAN);
|
|
75
|
-
}
|
|
76
|
-
if (this.compressionInfo.maxUncompressedChunkContentSize <= 0) {
|
|
77
|
-
this.compressionInfo.maxUncompressedChunkContentSize = this.operatingDataView.getInt32(8, this.alignment === alignment_enum_1.Alignment.LITTLE_ENDIAN);
|
|
78
|
-
}
|
|
79
|
-
const chunkCompressedLength = this.operatingDataView.getInt32(32, this.alignment === alignment_enum_1.Alignment.LITTLE_ENDIAN);
|
|
80
|
-
const chunkUncompressedLength = this.operatingDataView.getInt32(40, this.alignment === alignment_enum_1.Alignment.LITTLE_ENDIAN);
|
|
81
|
-
this.currentByte = this.compressionInfo.chunkHeaderSize;
|
|
82
|
-
await this.allocate(chunkCompressedLength);
|
|
83
|
-
let currentChunk = this.operatingStreamBuffer.slice(this.currentByte, this.currentByte + chunkCompressedLength);
|
|
84
|
-
this.currentByte += chunkCompressedLength;
|
|
85
|
-
this.totalNumberOfBytesRead += chunkUncompressedLength;
|
|
86
|
-
try {
|
|
87
|
-
const uncompressedChunk = pako_1.default.inflate(currentChunk);
|
|
88
|
-
if (uncompressedChunk.byteLength !== chunkUncompressedLength) {
|
|
89
|
-
throw new __1.CorruptSaveError('indicated save body chunk size does not match the inflated result. Save is possibly corrupt.');
|
|
90
|
-
}
|
|
91
|
-
if (this.debug) {
|
|
92
|
-
console.log(`${new Date().toString()}: decompressed a chunk from ${currentChunk.byteLength} to ${uncompressedChunk.byteLength} bytes.`);
|
|
93
|
-
}
|
|
94
|
-
return uncompressedChunk;
|
|
95
|
-
}
|
|
96
|
-
catch (err) {
|
|
97
|
-
throw new __1.CompressionLibraryError("Failed to inflate compressed save data. " + err);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
debugInfo() {
|
|
101
|
-
return `operating buffer size is ${this.operatingStreamBuffer.byteLength}/${this.operatingDataView.byteLength}, at ${this.currentByte} means ${this.getBufferPosition()} pos, with ${this.operatingStreamBuffer.byteLength - this.currentByte} left until end of operating buffer.`;
|
|
102
|
-
}
|
|
103
|
-
async streamLevelsToOutput(writer, header) {
|
|
104
|
-
if (header.saveVersion < 29) {
|
|
105
|
-
throw new __1.UnsupportedVersionError('Support for < U6 is not yet implemented.');
|
|
106
|
-
}
|
|
107
|
-
await this.allocate(100);
|
|
108
|
-
const numSubLevels = this.readInt32();
|
|
109
|
-
for (let j = 0; j <= numSubLevels; j++) {
|
|
110
|
-
let levelName = (j === numSubLevels) ? '' + header.mapName : this.readString();
|
|
111
|
-
if (this.debug) {
|
|
112
|
-
console.log(`${new Date().toString()}: reading level [${(j)}/${numSubLevels}] ${levelName}`);
|
|
113
|
-
}
|
|
114
|
-
await stream_level_class_1.StreamLevel.ReadLevelAsync(this, writer, levelName, header.buildVersion);
|
|
115
|
-
}
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
SaveStreamReader.EPOCH_TICKS = 621355968000000000n;
|
|
120
|
-
SaveStreamReader.DEFAULT_SATISFACTORY_CHUNK_HEADER_SIZE = 48;
|
|
121
|
-
exports.SaveStreamReader = SaveStreamReader;
|
|
@@ -1,25 +0,0 @@
|
|
|
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 formatTracker;
|
|
10
|
-
constructor(writer: WritableStreamDefaultWriter<string>);
|
|
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>;
|
|
24
|
-
close(): Promise<void>;
|
|
25
|
-
}
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SaveStreamWriter = void 0;
|
|
4
|
-
class SaveStreamWriter {
|
|
5
|
-
constructor(writer) {
|
|
6
|
-
this.writer = writer;
|
|
7
|
-
this.mode = 'BEFORE_START';
|
|
8
|
-
this.formatTracker = {
|
|
9
|
-
levels: []
|
|
10
|
-
};
|
|
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
|
-
}
|
|
115
|
-
async close() {
|
|
116
|
-
return this.writer.close();
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
exports.SaveStreamWriter = SaveStreamWriter;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { BinaryReadable } from "../byte/binary-readable.interface";
|
|
2
|
-
import { SaveComponentHeader } from "../satisfactory/objects/SaveComponent";
|
|
3
|
-
import { SaveEntityHeader } from "../satisfactory/objects/SaveEntity";
|
|
4
|
-
import { SaveStreamReader } from "./save-stream-reader.class";
|
|
5
|
-
import { SaveStreamWriter } from "./save-stream-writer.class";
|
|
6
|
-
export declare class StreamLevel {
|
|
7
|
-
name: string;
|
|
8
|
-
constructor(name: string);
|
|
9
|
-
static ReadLevelAsync(reader: SaveStreamReader, writer: SaveStreamWriter, levelName: string, buildVersion: number): Promise<void>;
|
|
10
|
-
static ReadObjectHeaders(reader: BinaryReadable): (SaveEntityHeader | SaveComponentHeader)[];
|
|
11
|
-
static StreamObjectContentsAsync(reader: SaveStreamReader, writer: SaveStreamWriter, headerList: (SaveEntityHeader | SaveComponentHeader)[], buildVersion: number): Promise<void>;
|
|
12
|
-
}
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.StreamLevel = void 0;
|
|
4
|
-
const __1 = require("../..");
|
|
5
|
-
const SaveComponent_1 = require("../satisfactory/objects/SaveComponent");
|
|
6
|
-
const SaveEntity_1 = require("../satisfactory/objects/SaveEntity");
|
|
7
|
-
class StreamLevel {
|
|
8
|
-
constructor(name) {
|
|
9
|
-
this.name = name;
|
|
10
|
-
}
|
|
11
|
-
static async ReadLevelAsync(reader, writer, levelName, buildVersion) {
|
|
12
|
-
const binaryLength = reader.readInt32();
|
|
13
|
-
await reader.allocate(binaryLength);
|
|
14
|
-
const objectHeaders = StreamLevel.ReadObjectHeaders(reader);
|
|
15
|
-
const collectables = __1.Level.ReadCollectablesList(reader);
|
|
16
|
-
await writer.openLevel(levelName);
|
|
17
|
-
await StreamLevel.StreamObjectContentsAsync(reader, writer, objectHeaders, buildVersion);
|
|
18
|
-
await writer.switchInLevelToCollectables();
|
|
19
|
-
await writer.writeCollectables(...collectables);
|
|
20
|
-
await writer.endLevel();
|
|
21
|
-
__1.Level.ReadCollectablesList(reader);
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
static ReadObjectHeaders(reader) {
|
|
25
|
-
let countObjectHeaders = reader.readInt32();
|
|
26
|
-
const headers = [];
|
|
27
|
-
for (let i = 0; i < countObjectHeaders; i++) {
|
|
28
|
-
let objectType = reader.readInt32();
|
|
29
|
-
switch (objectType) {
|
|
30
|
-
case 1:
|
|
31
|
-
headers.push({
|
|
32
|
-
typePath: reader.readString(),
|
|
33
|
-
rootObject: reader.readString(),
|
|
34
|
-
instanceName: reader.readString(),
|
|
35
|
-
needTransform: reader.readInt32() == 1,
|
|
36
|
-
transform: (0, __1.ParseTransform)(reader),
|
|
37
|
-
wasPlacedInLevel: reader.readInt32() == 1
|
|
38
|
-
});
|
|
39
|
-
break;
|
|
40
|
-
case 0:
|
|
41
|
-
headers.push({
|
|
42
|
-
typePath: reader.readString(),
|
|
43
|
-
rootObject: reader.readString(),
|
|
44
|
-
instanceName: reader.readString(),
|
|
45
|
-
parentEntityName: reader.readString()
|
|
46
|
-
});
|
|
47
|
-
break;
|
|
48
|
-
default:
|
|
49
|
-
console.log('Unknown object type', objectType);
|
|
50
|
-
break;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return headers;
|
|
54
|
-
}
|
|
55
|
-
static async StreamObjectContentsAsync(reader, writer, headerList, buildVersion) {
|
|
56
|
-
const binarySize = reader.readInt32();
|
|
57
|
-
const posBefore = reader.getBufferPosition();
|
|
58
|
-
await reader.allocate(Math.min(binarySize, 300 * 1000 * 1000));
|
|
59
|
-
const countEntities = reader.readInt32();
|
|
60
|
-
if (countEntities !== headerList.length) {
|
|
61
|
-
throw new Error(`possibly corrupt. entity content count ${countEntities} does not object count of ${headerList.length}`);
|
|
62
|
-
}
|
|
63
|
-
let bufferedObjects = [];
|
|
64
|
-
for (let i = 0; i < countEntities; i++) {
|
|
65
|
-
if ((i + 1) % 10000 === 0) {
|
|
66
|
-
await writer.writeObjects(...bufferedObjects);
|
|
67
|
-
bufferedObjects = [];
|
|
68
|
-
}
|
|
69
|
-
const len = reader.readInt32();
|
|
70
|
-
if (reader.getAmountAllocatedLeft() <= len) {
|
|
71
|
-
const allocateAmount = Math.min(binarySize - (reader.getBufferPosition() - posBefore) + 4, 300 * 1000 * 1000);
|
|
72
|
-
await reader.allocate(allocateAmount);
|
|
73
|
-
}
|
|
74
|
-
const before = reader.getBufferPosition();
|
|
75
|
-
const obj = headerList.shift();
|
|
76
|
-
if (!obj) {
|
|
77
|
-
throw new Error();
|
|
78
|
-
}
|
|
79
|
-
const isComponent = obj.parentEntityName !== undefined;
|
|
80
|
-
if (!isComponent) {
|
|
81
|
-
const entity = new SaveEntity_1.SaveEntity(obj.typePath, obj.rootObject, obj.instanceName, '', obj.needTransform);
|
|
82
|
-
SaveEntity_1.SaveEntity.ParseData(entity, len, reader, buildVersion, obj.typePath);
|
|
83
|
-
bufferedObjects.push(entity);
|
|
84
|
-
}
|
|
85
|
-
else if (isComponent) {
|
|
86
|
-
const component = new SaveComponent_1.SaveComponent(obj.typePath, obj.rootObject, obj.instanceName, obj.parentEntityName);
|
|
87
|
-
SaveComponent_1.SaveComponent.ParseData(component, len, reader, buildVersion, obj.typePath);
|
|
88
|
-
bufferedObjects.push(component);
|
|
89
|
-
}
|
|
90
|
-
const after = reader.getBufferPosition();
|
|
91
|
-
if (after - before !== len) {
|
|
92
|
-
console.warn('entity may be corrupt.', i);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
await writer.writeObjects(...bufferedObjects);
|
|
96
|
-
bufferedObjects = [];
|
|
97
|
-
const posAfter = reader.getBufferPosition();
|
|
98
|
-
if (posAfter - posBefore !== binarySize) {
|
|
99
|
-
console.warn('save seems corrupt.', this.name);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
exports.StreamLevel = StreamLevel;
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
import { Readable } from "stream";
|
|
3
|
-
import { Alignment } from "../byte/alignment.enum";
|
|
4
|
-
export declare class StreamParserReader {
|
|
5
|
-
minBufferSize: number;
|
|
6
|
-
private buffer;
|
|
7
|
-
view: DataView;
|
|
8
|
-
private hasInputStreamEnded;
|
|
9
|
-
currentByte: number;
|
|
10
|
-
alignment: Alignment;
|
|
11
|
-
private inputBuffer;
|
|
12
|
-
private input;
|
|
13
|
-
hasDataToRead: boolean;
|
|
14
|
-
private onInputDataAvailableCallback;
|
|
15
|
-
constructor(minBufferSize: number);
|
|
16
|
-
getAmountLeftToRead: () => number;
|
|
17
|
-
parseLogic: () => Promise<void>;
|
|
18
|
-
private allocate;
|
|
19
|
-
private waitForAmountLeftToRead;
|
|
20
|
-
private wait;
|
|
21
|
-
private shiftBufferIntoOperatingDataView;
|
|
22
|
-
private readTilBufferFullOrInputEmpty;
|
|
23
|
-
startReading(input: Readable): void;
|
|
24
|
-
skipBytes(byteLength?: number): void;
|
|
25
|
-
readByte(): number;
|
|
26
|
-
readBytes(count: number): Uint8Array;
|
|
27
|
-
readHex(hexLength: number): string;
|
|
28
|
-
readInt8(): number;
|
|
29
|
-
readUint8(): number;
|
|
30
|
-
readInt16(): number;
|
|
31
|
-
readUint16(): number;
|
|
32
|
-
readInt32(): number;
|
|
33
|
-
readUint32(): number;
|
|
34
|
-
readLong(): bigint;
|
|
35
|
-
readInt64(): bigint;
|
|
36
|
-
readUint64(): bigint;
|
|
37
|
-
readFloat32(): number;
|
|
38
|
-
readDouble(): number;
|
|
39
|
-
readString(): string;
|
|
40
|
-
}
|