@etothepii/satisfactory-file-parser 0.0.30 → 0.0.32
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 +20 -20
- package/README.md +112 -112
- package/build/index.d.ts +23 -0
- package/build/index.js +65 -0
- package/build/parser/byte/alignment.enum.d.ts +4 -0
- package/build/parser/byte/alignment.enum.js +18 -0
- package/build/parser/byte/binary-operable.interface.d.ts +6 -0
- package/build/parser/byte/binary-operable.interface.js +12 -0
- package/build/parser/byte/binary-readable.interface.d.ts +22 -0
- package/build/parser/byte/binary-readable.interface.js +12 -0
- package/build/parser/byte/byte-reader.class.d.ts +36 -0
- package/build/parser/byte/byte-reader.class.js +139 -0
- package/build/parser/byte/byte-writer.class.d.ts +33 -0
- package/build/parser/byte/byte-writer.class.js +149 -0
- package/build/parser/error/parser.error.d.ts +18 -0
- package/build/parser/error/parser.error.js +50 -0
- package/build/parser/file.types.d.ts +9 -0
- package/build/parser/file.types.js +12 -0
- package/build/parser/parser.d.ts +25 -0
- package/build/parser/parser.js +196 -0
- package/build/parser/satisfactory/blueprint/blueprint-reader.d.ts +19 -0
- package/build/parser/satisfactory/blueprint/blueprint-reader.js +134 -0
- package/build/parser/satisfactory/blueprint/blueprint-writer.d.ts +15 -0
- package/build/parser/satisfactory/blueprint/blueprint-writer.js +73 -0
- package/build/parser/satisfactory/blueprint/blueprint.types.d.ts +20 -0
- package/build/parser/satisfactory/blueprint/blueprint.types.js +12 -0
- package/build/parser/satisfactory/objects/DataFields.d.ts +41 -0
- package/build/parser/satisfactory/objects/DataFields.js +317 -0
- package/build/parser/satisfactory/objects/ObjectReference.d.ts +9 -0
- package/build/parser/satisfactory/objects/ObjectReference.js +27 -0
- package/build/parser/satisfactory/objects/Property.d.ts +270 -0
- package/build/parser/satisfactory/objects/Property.js +1012 -0
- package/build/parser/satisfactory/objects/SaveComponent.d.ts +19 -0
- package/build/parser/satisfactory/objects/SaveComponent.js +41 -0
- package/build/parser/satisfactory/objects/SaveEntity.d.ts +30 -0
- package/build/parser/satisfactory/objects/SaveEntity.js +80 -0
- package/build/parser/satisfactory/objects/SaveObject.d.ts +19 -0
- package/build/parser/satisfactory/objects/SaveObject.js +39 -0
- package/build/parser/satisfactory/save/asynchronous-level.class.d.ts +9 -0
- package/build/parser/satisfactory/save/asynchronous-level.class.js +76 -0
- package/build/parser/satisfactory/save/level.class.d.ts +21 -0
- package/build/parser/satisfactory/save/level.class.js +149 -0
- package/build/parser/satisfactory/save/satisfactory-save.d.ts +11 -0
- package/build/parser/satisfactory/save/satisfactory-save.js +21 -0
- package/build/parser/satisfactory/save/save-reader.d.ts +35 -0
- package/build/parser/satisfactory/save/save-reader.js +188 -0
- package/build/parser/satisfactory/save/save-writer.d.ts +12 -0
- package/build/parser/satisfactory/save/save-writer.js +122 -0
- package/build/parser/satisfactory/save/save.types.d.ts +49 -0
- package/build/parser/satisfactory/save/save.types.js +12 -0
- package/build/parser/satisfactory/structs/util.types.d.ts +40 -0
- package/build/parser/satisfactory/structs/util.types.js +105 -0
- package/build/parser/stream/byte-stream-reader.class.d.ts +57 -0
- package/build/parser/stream/byte-stream-reader.class.js +251 -0
- package/build/parser/stream/json-stream-state-writer.d.ts +12 -0
- package/build/parser/stream/json-stream-state-writer.js +28 -0
- package/build/parser/stream/json-stream-writable.d.ts +20 -0
- package/build/parser/stream/json-stream-writable.js +93 -0
- package/build/parser/stream/json-stream-writer.d.ts +22 -0
- package/build/parser/stream/json-stream-writer.js +137 -0
- package/build/parser/stream/save-stream-json-stringifier.d.ts +6 -0
- package/build/parser/stream/save-stream-json-stringifier.js +43 -0
- package/build/parser/stream/save-stream-reader.class.d.ts +15 -0
- package/build/parser/stream/save-stream-reader.class.js +131 -0
- package/build/parser/stream/save-stream-writer.class.d.ts +22 -0
- package/build/parser/stream/save-stream-writer.class.js +115 -0
- package/build/parser/stream/stream-level.class.d.ts +12 -0
- package/build/parser/stream/stream-level.class.js +113 -0
- package/package.json +5 -3
- package/dist/index.d.ts +0 -610
- package/dist/index.js +0 -1
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
2
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
3
|
+
};
|
|
4
|
+
(function (factory) {
|
|
5
|
+
if (typeof module === "object" && typeof module.exports === "object") {
|
|
6
|
+
var v = factory(require, exports);
|
|
7
|
+
if (v !== undefined) module.exports = v;
|
|
8
|
+
}
|
|
9
|
+
else if (typeof define === "function" && define.amd) {
|
|
10
|
+
define(["require", "exports", "pako", "../../byte/alignment.enum", "../../byte/byte-reader.class", "../../error/parser.error", "../objects/SaveComponent", "../objects/SaveEntity", "./asynchronous-level.class", "./level.class"], factory);
|
|
11
|
+
}
|
|
12
|
+
})(function (require, exports) {
|
|
13
|
+
"use strict";
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.SaveReader = exports.DEFAULT_SATISFACTORY_CHUNK_HEADER_SIZE = exports.projectionFilterApplies = void 0;
|
|
16
|
+
const pako_1 = __importDefault(require("pako"));
|
|
17
|
+
const alignment_enum_1 = require("../../byte/alignment.enum");
|
|
18
|
+
const byte_reader_class_1 = require("../../byte/byte-reader.class");
|
|
19
|
+
const parser_error_1 = require("../../error/parser.error");
|
|
20
|
+
const SaveComponent_1 = require("../objects/SaveComponent");
|
|
21
|
+
const SaveEntity_1 = require("../objects/SaveEntity");
|
|
22
|
+
const asynchronous_level_class_1 = require("./asynchronous-level.class");
|
|
23
|
+
const level_class_1 = require("./level.class");
|
|
24
|
+
const projectionFilterApplies = (config, object) => {
|
|
25
|
+
let cond1 = false;
|
|
26
|
+
if ((0, SaveEntity_1.isSaveEntity)(object) || (config.includeComponents && (0, SaveComponent_1.isSaveComponent)(object))) {
|
|
27
|
+
cond1 = true;
|
|
28
|
+
}
|
|
29
|
+
let cond2 = true;
|
|
30
|
+
if ((0, SaveEntity_1.isSaveEntity)(object)) {
|
|
31
|
+
cond2 = false;
|
|
32
|
+
if (config.entityPathFilter.behavior === 'whitelist') {
|
|
33
|
+
cond2 = config.entityPathFilter.list.find(en => object.typePath.startsWith(en)) !== undefined;
|
|
34
|
+
}
|
|
35
|
+
else if (config.entityPathFilter.behavior === 'blacklist') {
|
|
36
|
+
cond2 = config.entityPathFilter.list.find(en => object.typePath.startsWith(en)) === undefined;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return cond1 && cond2;
|
|
40
|
+
};
|
|
41
|
+
exports.projectionFilterApplies = projectionFilterApplies;
|
|
42
|
+
exports.DEFAULT_SATISFACTORY_CHUNK_HEADER_SIZE = 48;
|
|
43
|
+
class SaveReader extends byte_reader_class_1.ByteReader {
|
|
44
|
+
constructor(fileBuffer, onProgressCallback = () => { }) {
|
|
45
|
+
super(fileBuffer, alignment_enum_1.Alignment.LITTLE_ENDIAN);
|
|
46
|
+
this.onProgressCallback = onProgressCallback;
|
|
47
|
+
this.levels = [];
|
|
48
|
+
this.trailingCollectedObjects = [];
|
|
49
|
+
this.compressionInfo = {
|
|
50
|
+
packageFileTag: 0,
|
|
51
|
+
maxChunkContentSize: 0,
|
|
52
|
+
chunkHeaderSize: exports.DEFAULT_SATISFACTORY_CHUNK_HEADER_SIZE
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
readHeader() {
|
|
56
|
+
this.header = {
|
|
57
|
+
saveHeaderType: 0,
|
|
58
|
+
saveVersion: 0,
|
|
59
|
+
buildVersion: 0,
|
|
60
|
+
mapName: "DEFAULT",
|
|
61
|
+
mapOptions: "",
|
|
62
|
+
sessionName: "",
|
|
63
|
+
playDurationSeconds: 0,
|
|
64
|
+
saveDateTime: "0",
|
|
65
|
+
sessionVisibility: 0
|
|
66
|
+
};
|
|
67
|
+
this.header.saveHeaderType = this.readInt32();
|
|
68
|
+
this.header.saveVersion = this.readInt32();
|
|
69
|
+
this.header.buildVersion = this.readInt32();
|
|
70
|
+
this.header.mapName = this.readString();
|
|
71
|
+
this.header.mapOptions = this.readString();
|
|
72
|
+
this.header.sessionName = this.readString();
|
|
73
|
+
this.header.playDurationSeconds = this.readInt32();
|
|
74
|
+
const rawSaveDateTimeInTicks = this.readLong();
|
|
75
|
+
const unixMilliseconds = (rawSaveDateTimeInTicks - SaveReader.EPOCH_TICKS) / 10000n;
|
|
76
|
+
this.header.saveDateTime = unixMilliseconds.toString();
|
|
77
|
+
this.header.sessionVisibility = this.readByte();
|
|
78
|
+
if (this.header.saveHeaderType >= 7) {
|
|
79
|
+
this.header.fEditorObjectVersion = this.readInt32();
|
|
80
|
+
}
|
|
81
|
+
if (this.header.saveHeaderType >= 8) {
|
|
82
|
+
this.header.rawModMetadataString = this.readString();
|
|
83
|
+
try {
|
|
84
|
+
this.header.modMetadata = JSON.parse(this.header.rawModMetadataString);
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
}
|
|
88
|
+
this.header.isModdedSave = this.readInt32();
|
|
89
|
+
}
|
|
90
|
+
if (this.header.saveHeaderType >= 10) {
|
|
91
|
+
this.header.saveIdentifier = this.readString();
|
|
92
|
+
}
|
|
93
|
+
if (this.header.saveVersion >= 21) {
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
throw new parser_error_1.UnsupportedVersionError("The save version is too old to support encoding currently. Save in newer game version.");
|
|
97
|
+
}
|
|
98
|
+
return this.header;
|
|
99
|
+
}
|
|
100
|
+
inflateChunks() {
|
|
101
|
+
this.fileBuffer = this.fileBuffer.slice(this.currentByte);
|
|
102
|
+
this.handledByte = 0;
|
|
103
|
+
this.currentByte = 0;
|
|
104
|
+
this.maxByte = this.fileBuffer.byteLength;
|
|
105
|
+
let currentChunks = [];
|
|
106
|
+
let totalUncompressedBodySize = 0;
|
|
107
|
+
while (this.handledByte < this.maxByte) {
|
|
108
|
+
let chunkHeader = new DataView(this.fileBuffer.slice(0, this.compressionInfo.chunkHeaderSize));
|
|
109
|
+
this.currentByte = this.compressionInfo.chunkHeaderSize;
|
|
110
|
+
this.handledByte += this.compressionInfo.chunkHeaderSize;
|
|
111
|
+
if (this.compressionInfo.packageFileTag <= 0) {
|
|
112
|
+
this.compressionInfo.packageFileTag = chunkHeader.getInt32(0, this.alignment === alignment_enum_1.Alignment.LITTLE_ENDIAN);
|
|
113
|
+
}
|
|
114
|
+
if (this.compressionInfo.maxChunkContentSize <= 0) {
|
|
115
|
+
this.compressionInfo.maxChunkContentSize = chunkHeader.getInt32(8, this.alignment === alignment_enum_1.Alignment.LITTLE_ENDIAN);
|
|
116
|
+
}
|
|
117
|
+
const chunkCompressedLength = chunkHeader.getInt32(32, this.alignment === alignment_enum_1.Alignment.LITTLE_ENDIAN);
|
|
118
|
+
const chunkUncompressedLength = chunkHeader.getInt32(40, this.alignment === alignment_enum_1.Alignment.LITTLE_ENDIAN);
|
|
119
|
+
totalUncompressedBodySize += chunkUncompressedLength;
|
|
120
|
+
const currentChunkSize = chunkCompressedLength;
|
|
121
|
+
let currentChunk = this.fileBuffer.slice(this.currentByte, this.currentByte + currentChunkSize);
|
|
122
|
+
this.handledByte += currentChunkSize;
|
|
123
|
+
this.currentByte += currentChunkSize;
|
|
124
|
+
this.fileBuffer = this.fileBuffer.slice(this.currentByte);
|
|
125
|
+
this.currentByte = 0;
|
|
126
|
+
try {
|
|
127
|
+
let currentInflatedChunk = null;
|
|
128
|
+
currentInflatedChunk = pako_1.default.inflate(currentChunk);
|
|
129
|
+
currentChunks.push(currentInflatedChunk);
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
throw new parser_error_1.CompressionLibraryError("Failed to inflate compressed save data. " + err);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
let newChunkLength = currentChunks.map(cc => cc.length).reduce((prev, cur) => prev + cur);
|
|
136
|
+
const bigWholeChunk = new Uint8Array(newChunkLength);
|
|
137
|
+
let currentLength = 0;
|
|
138
|
+
for (let i = 0; i < currentChunks.length; i++) {
|
|
139
|
+
bigWholeChunk.set(currentChunks[i], currentLength);
|
|
140
|
+
currentLength += currentChunks[i].length;
|
|
141
|
+
}
|
|
142
|
+
this.currentByte = 0;
|
|
143
|
+
this.maxByte = bigWholeChunk.buffer.byteLength;
|
|
144
|
+
this.bufferView = new DataView(bigWholeChunk.buffer);
|
|
145
|
+
const dataLength = this.readInt32();
|
|
146
|
+
if (totalUncompressedBodySize !== dataLength + 4) {
|
|
147
|
+
throw new parser_error_1.CorruptSaveError(`Possibly corrupt. Indicated size of total save body (${dataLength}) does not match the uncompressed real size of ${totalUncompressedBodySize}.`);
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
concatenatedChunkLength: newChunkLength,
|
|
151
|
+
numChunks: currentChunks.length
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
readLevels() {
|
|
155
|
+
if (!this.header) {
|
|
156
|
+
throw new parser_error_1.ParserError('ParserError', 'Header must be set before objects can be read.');
|
|
157
|
+
}
|
|
158
|
+
if (this.header.saveVersion < 29) {
|
|
159
|
+
throw new parser_error_1.UnsupportedVersionError('Support for < U6 is not yet implemented.');
|
|
160
|
+
}
|
|
161
|
+
const numSubLevels = this.readInt32();
|
|
162
|
+
this.levels = new Array(numSubLevels + 1);
|
|
163
|
+
for (let j = 0; j <= numSubLevels; j++) {
|
|
164
|
+
let levelName = (j === numSubLevels) ? '' + this.header.mapName : this.readString();
|
|
165
|
+
this.onProgressCallback(this.getBufferProgress(), `reading level [${(j + 1)}/${(numSubLevels + 1)}] ${levelName}`);
|
|
166
|
+
this.levels[j] = level_class_1.Level.ReadLevel(this, levelName, this.header.buildVersion);
|
|
167
|
+
}
|
|
168
|
+
if (this.getBufferPosition() < this.bufferView.byteLength) {
|
|
169
|
+
this.trailingCollectedObjects = level_class_1.Level.ReadCollectablesList(this);
|
|
170
|
+
}
|
|
171
|
+
return this.levels;
|
|
172
|
+
}
|
|
173
|
+
async readLevelsAsynchronously(writer) {
|
|
174
|
+
const numSubLevels = this.readInt32();
|
|
175
|
+
this.levels = new Array(numSubLevels + 1);
|
|
176
|
+
await writer.openLevels();
|
|
177
|
+
for (let j = 0; j <= numSubLevels; j++) {
|
|
178
|
+
let levelName = (j === numSubLevels) ? '' + this.header.mapName : this.readString();
|
|
179
|
+
this.onProgressCallback(this.getBufferProgress(), `reading level [${(j + 1)}/${(numSubLevels + 1)}] ${levelName}`);
|
|
180
|
+
this.levels[j] = await asynchronous_level_class_1.AsynchronousLevel.StreamReadLevel(this, levelName, this.header.buildVersion, writer);
|
|
181
|
+
}
|
|
182
|
+
await writer.endLevels();
|
|
183
|
+
return this.levels;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
SaveReader.EPOCH_TICKS = 621355968000000000n;
|
|
187
|
+
exports.SaveReader = SaveReader;
|
|
188
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Alignment } from "../../byte/alignment.enum";
|
|
2
|
+
import { ByteWriter } from "../../byte/byte-writer.class";
|
|
3
|
+
import { ChunkCompressionInfo, ChunkSummary } from "../../file.types";
|
|
4
|
+
import { SatisfactorySave } from "./satisfactory-save";
|
|
5
|
+
import { SatisfactorySaveHeader } from "./save.types";
|
|
6
|
+
export declare class SaveWriter extends ByteWriter {
|
|
7
|
+
constructor();
|
|
8
|
+
static WriteHeader(writer: ByteWriter, header: SatisfactorySaveHeader): void;
|
|
9
|
+
static WriteLevels(writer: ByteWriter, save: SatisfactorySave, buildVersion: number): void;
|
|
10
|
+
static GenerateCompressedChunksFromData(bufferArray: ArrayBuffer, compressionInfo: ChunkCompressionInfo, onBinaryBeforeCompressing: (binary: ArrayBuffer) => void, onChunk: (chunk: Uint8Array) => void, alignment?: Alignment): ChunkSummary[];
|
|
11
|
+
generateChunks(compressionInfo: ChunkCompressionInfo, posAfterHeader: number, onBinaryBeforeCompressing: (binary: ArrayBuffer) => void, onHeader: (header: Uint8Array) => void, onChunk: (chunk: Uint8Array) => void): ChunkSummary[];
|
|
12
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
2
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
3
|
+
};
|
|
4
|
+
(function (factory) {
|
|
5
|
+
if (typeof module === "object" && typeof module.exports === "object") {
|
|
6
|
+
var v = factory(require, exports);
|
|
7
|
+
if (v !== undefined) module.exports = v;
|
|
8
|
+
}
|
|
9
|
+
else if (typeof define === "function" && define.amd) {
|
|
10
|
+
define(["require", "exports", "pako", "../../byte/alignment.enum", "../../byte/byte-writer.class", "../../error/parser.error", "./level.class"], factory);
|
|
11
|
+
}
|
|
12
|
+
})(function (require, exports) {
|
|
13
|
+
"use strict";
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.SaveWriter = void 0;
|
|
16
|
+
const pako_1 = __importDefault(require("pako"));
|
|
17
|
+
const alignment_enum_1 = require("../../byte/alignment.enum");
|
|
18
|
+
const byte_writer_class_1 = require("../../byte/byte-writer.class");
|
|
19
|
+
const parser_error_1 = require("../../error/parser.error");
|
|
20
|
+
const level_class_1 = require("./level.class");
|
|
21
|
+
class SaveWriter extends byte_writer_class_1.ByteWriter {
|
|
22
|
+
constructor() {
|
|
23
|
+
super(alignment_enum_1.Alignment.LITTLE_ENDIAN);
|
|
24
|
+
}
|
|
25
|
+
static WriteHeader(writer, header) {
|
|
26
|
+
writer.writeInt32(header.saveHeaderType);
|
|
27
|
+
writer.writeInt32(header.saveVersion);
|
|
28
|
+
writer.writeInt32(header.buildVersion);
|
|
29
|
+
writer.writeString(header.mapName);
|
|
30
|
+
writer.writeString(header.mapOptions);
|
|
31
|
+
writer.writeString(header.sessionName);
|
|
32
|
+
writer.writeInt32(header.playDurationSeconds);
|
|
33
|
+
writer.writeInt64(BigInt(header.saveDateTime));
|
|
34
|
+
writer.writeByte(header.sessionVisibility);
|
|
35
|
+
if (header.saveHeaderType >= 7) {
|
|
36
|
+
writer.writeInt32(header.fEditorObjectVersion);
|
|
37
|
+
}
|
|
38
|
+
if (header.saveHeaderType >= 8) {
|
|
39
|
+
if (header.modMetadata) {
|
|
40
|
+
writer.writeString(JSON.stringify(header.modMetadata));
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
writer.writeString(header.rawModMetadataString);
|
|
44
|
+
}
|
|
45
|
+
writer.writeInt32(header.isModdedSave);
|
|
46
|
+
}
|
|
47
|
+
if (header.saveHeaderType >= 10) {
|
|
48
|
+
writer.writeString(header.saveIdentifier);
|
|
49
|
+
}
|
|
50
|
+
if (header.saveVersion >= 21) {
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
throw new parser_error_1.UnsupportedVersionError("The save version is too old to be supported currently.");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
static WriteLevels(writer, save, buildVersion) {
|
|
57
|
+
writer.writeInt32(save.levels.length - 1);
|
|
58
|
+
for (const level of save.levels) {
|
|
59
|
+
if (level.name !== save.header.mapName) {
|
|
60
|
+
writer.writeString(level.name);
|
|
61
|
+
}
|
|
62
|
+
level_class_1.Level.WriteLevel(writer, level, buildVersion);
|
|
63
|
+
}
|
|
64
|
+
level_class_1.Level.SerializeCollectablesList(writer, save.trailingCollectedObjects);
|
|
65
|
+
}
|
|
66
|
+
static GenerateCompressedChunksFromData(bufferArray, compressionInfo, onBinaryBeforeCompressing, onChunk, alignment = alignment_enum_1.Alignment.LITTLE_ENDIAN) {
|
|
67
|
+
const errors = [];
|
|
68
|
+
const totalUncompressedSize = bufferArray.byteLength;
|
|
69
|
+
const saveBody = new Uint8Array(bufferArray.byteLength + 4);
|
|
70
|
+
saveBody.set(new Uint8Array(bufferArray), 4);
|
|
71
|
+
const miniView = new DataView(saveBody.buffer);
|
|
72
|
+
miniView.setInt32(0, totalUncompressedSize, alignment === alignment_enum_1.Alignment.LITTLE_ENDIAN);
|
|
73
|
+
onBinaryBeforeCompressing(saveBody.buffer);
|
|
74
|
+
let handledByte = 0;
|
|
75
|
+
const chunkSummary = [];
|
|
76
|
+
while (handledByte < saveBody.byteLength) {
|
|
77
|
+
const uncompressedContentSize = Math.min(compressionInfo.maxChunkContentSize, saveBody.byteLength - handledByte);
|
|
78
|
+
const uncompressedChunk = saveBody.buffer.slice(handledByte, handledByte + uncompressedContentSize);
|
|
79
|
+
let compressedChunk = new Uint8Array(0);
|
|
80
|
+
try {
|
|
81
|
+
compressedChunk = pako_1.default.deflate(uncompressedChunk);
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
throw new parser_error_1.CompressionLibraryError("Could not compress save data. " + err);
|
|
85
|
+
}
|
|
86
|
+
const chunk = new Uint8Array(compressionInfo.chunkHeaderSize + compressedChunk.byteLength);
|
|
87
|
+
chunk.set(compressedChunk, compressionInfo.chunkHeaderSize);
|
|
88
|
+
const view = new DataView(chunk.buffer);
|
|
89
|
+
view.setInt32(0, compressionInfo.packageFileTag, alignment === alignment_enum_1.Alignment.LITTLE_ENDIAN);
|
|
90
|
+
view.setInt32(4, 0, alignment === alignment_enum_1.Alignment.LITTLE_ENDIAN);
|
|
91
|
+
view.setInt32(8, compressionInfo.maxChunkContentSize, alignment === alignment_enum_1.Alignment.LITTLE_ENDIAN);
|
|
92
|
+
view.setInt32(12, 0, alignment === alignment_enum_1.Alignment.LITTLE_ENDIAN);
|
|
93
|
+
view.setInt32(16, compressedChunk.byteLength, alignment === alignment_enum_1.Alignment.LITTLE_ENDIAN);
|
|
94
|
+
view.setInt32(20, 0, alignment === alignment_enum_1.Alignment.LITTLE_ENDIAN);
|
|
95
|
+
view.setInt32(24, uncompressedContentSize, alignment === alignment_enum_1.Alignment.LITTLE_ENDIAN);
|
|
96
|
+
view.setInt32(28, 0, alignment === alignment_enum_1.Alignment.LITTLE_ENDIAN);
|
|
97
|
+
view.setInt32(32, compressedChunk.byteLength, alignment === alignment_enum_1.Alignment.LITTLE_ENDIAN);
|
|
98
|
+
view.setInt32(36, 0, alignment === alignment_enum_1.Alignment.LITTLE_ENDIAN);
|
|
99
|
+
view.setInt32(40, uncompressedContentSize, alignment === alignment_enum_1.Alignment.LITTLE_ENDIAN);
|
|
100
|
+
view.setInt32(44, 0, alignment === alignment_enum_1.Alignment.LITTLE_ENDIAN);
|
|
101
|
+
onChunk(chunk);
|
|
102
|
+
chunkSummary.push({
|
|
103
|
+
uncompressedSize: uncompressedContentSize + compressionInfo.chunkHeaderSize,
|
|
104
|
+
compressedSize: compressedChunk.byteLength + compressionInfo.chunkHeaderSize
|
|
105
|
+
});
|
|
106
|
+
handledByte += uncompressedContentSize;
|
|
107
|
+
}
|
|
108
|
+
return chunkSummary;
|
|
109
|
+
}
|
|
110
|
+
generateChunks(compressionInfo, posAfterHeader, onBinaryBeforeCompressing, onHeader, onChunk) {
|
|
111
|
+
if (posAfterHeader <= 0) {
|
|
112
|
+
throw new parser_error_1.ParserError('ParserError', 'Seems like this buffer has no header. Please write the header first before you can generate chunks.');
|
|
113
|
+
}
|
|
114
|
+
const header = new Uint8Array(this.bufferArray.slice(0, posAfterHeader));
|
|
115
|
+
onHeader(header);
|
|
116
|
+
this.bufferArray = this.bufferArray.slice(posAfterHeader);
|
|
117
|
+
const chunkSummary = SaveWriter.GenerateCompressedChunksFromData(this.bufferArray, compressionInfo, onBinaryBeforeCompressing, onChunk, this.alignment);
|
|
118
|
+
return chunkSummary;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
exports.SaveWriter = SaveWriter;
|
|
122
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export interface ModData {
|
|
2
|
+
Reference: string;
|
|
3
|
+
Name: string;
|
|
4
|
+
Version: string;
|
|
5
|
+
}
|
|
6
|
+
export interface SatisfactoryModMetadata {
|
|
7
|
+
Mods: ModData[];
|
|
8
|
+
}
|
|
9
|
+
export interface SatisfactorySaveHeader {
|
|
10
|
+
saveHeaderType: number;
|
|
11
|
+
saveVersion: number;
|
|
12
|
+
buildVersion: number;
|
|
13
|
+
mapName: string;
|
|
14
|
+
mapOptions: string;
|
|
15
|
+
sessionName: string;
|
|
16
|
+
playDurationSeconds: number;
|
|
17
|
+
saveDateTime: string;
|
|
18
|
+
sessionVisibility: number;
|
|
19
|
+
rawModMetadataString?: string;
|
|
20
|
+
modMetadata?: SatisfactoryModMetadata;
|
|
21
|
+
isModdedSave?: number;
|
|
22
|
+
saveIdentifier?: string;
|
|
23
|
+
fEditorObjectVersion?: number;
|
|
24
|
+
}
|
|
25
|
+
export type ResourceNodeEntry = {
|
|
26
|
+
purity: string;
|
|
27
|
+
pathName: string;
|
|
28
|
+
position: {
|
|
29
|
+
x: number;
|
|
30
|
+
y: number;
|
|
31
|
+
z: number;
|
|
32
|
+
};
|
|
33
|
+
type: string;
|
|
34
|
+
};
|
|
35
|
+
export type CollectibleEntry = {
|
|
36
|
+
pathName: string;
|
|
37
|
+
position: {
|
|
38
|
+
x: number;
|
|
39
|
+
y: number;
|
|
40
|
+
z: number;
|
|
41
|
+
};
|
|
42
|
+
type: string;
|
|
43
|
+
};
|
|
44
|
+
export type StaticData = {
|
|
45
|
+
collectibles: CollectibleEntry[];
|
|
46
|
+
artifacts: CollectibleEntry[];
|
|
47
|
+
slugs: CollectibleEntry[];
|
|
48
|
+
resourceNodes: ResourceNodeEntry[];
|
|
49
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
(function (factory) {
|
|
2
|
+
if (typeof module === "object" && typeof module.exports === "object") {
|
|
3
|
+
var v = factory(require, exports);
|
|
4
|
+
if (v !== undefined) module.exports = v;
|
|
5
|
+
}
|
|
6
|
+
else if (typeof define === "function" && define.amd) {
|
|
7
|
+
define(["require", "exports"], factory);
|
|
8
|
+
}
|
|
9
|
+
})(function (require, exports) {
|
|
10
|
+
"use strict";
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { BinaryReadable } from "../../byte/binary-readable.interface";
|
|
2
|
+
import { ByteWriter } from "../../byte/byte-writer.class";
|
|
3
|
+
export type col4 = {
|
|
4
|
+
r: number;
|
|
5
|
+
g: number;
|
|
6
|
+
b: number;
|
|
7
|
+
a: number;
|
|
8
|
+
};
|
|
9
|
+
export declare const SerializeCol4RGBA: (writer: ByteWriter, value: col4) => void;
|
|
10
|
+
export declare const ParseCol4RGBA: (reader: BinaryReadable) => col4;
|
|
11
|
+
export declare const SerializeCol4BGRA: (writer: ByteWriter, value: col4) => void;
|
|
12
|
+
export declare const ParseCol4BGRA: (reader: BinaryReadable) => col4;
|
|
13
|
+
export type vec4 = vec3 & {
|
|
14
|
+
w: number;
|
|
15
|
+
};
|
|
16
|
+
export declare const ParseVec4: (reader: BinaryReadable) => vec4;
|
|
17
|
+
export declare const SerializeVec4: (writer: ByteWriter, vec: vec4) => void;
|
|
18
|
+
export declare const sub: (other: vec3, vec: vec3) => vec3;
|
|
19
|
+
export declare const add: (vec: vec3, other: vec3) => vec3;
|
|
20
|
+
export declare const length: (vec: vec3) => number;
|
|
21
|
+
export declare const mult: (vec: vec3, scale: number) => vec3;
|
|
22
|
+
export declare const norm: (vec: vec3) => vec3;
|
|
23
|
+
export type vec3 = vec2 & {
|
|
24
|
+
z: number;
|
|
25
|
+
};
|
|
26
|
+
export declare const ParseVec3: (reader: BinaryReadable) => vec3;
|
|
27
|
+
export declare const SerializeVec3: (writer: ByteWriter, vec: vec3) => void;
|
|
28
|
+
export type vec2 = {
|
|
29
|
+
x: number;
|
|
30
|
+
y: number;
|
|
31
|
+
};
|
|
32
|
+
export declare const ParseVec2: (reader: BinaryReadable) => vec2;
|
|
33
|
+
export declare const SerializeVec2: (writer: ByteWriter, vec: vec2) => void;
|
|
34
|
+
export type Transform = {
|
|
35
|
+
rotation: vec4;
|
|
36
|
+
translation: vec3;
|
|
37
|
+
scale3d: vec3;
|
|
38
|
+
};
|
|
39
|
+
export declare const ParseTransform: (reader: BinaryReadable) => Transform;
|
|
40
|
+
export declare const SerializeTransform: (writer: ByteWriter, transform: Transform) => void;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
(function (factory) {
|
|
2
|
+
if (typeof module === "object" && typeof module.exports === "object") {
|
|
3
|
+
var v = factory(require, exports);
|
|
4
|
+
if (v !== undefined) module.exports = v;
|
|
5
|
+
}
|
|
6
|
+
else if (typeof define === "function" && define.amd) {
|
|
7
|
+
define(["require", "exports"], factory);
|
|
8
|
+
}
|
|
9
|
+
})(function (require, exports) {
|
|
10
|
+
"use strict";
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.SerializeTransform = exports.ParseTransform = exports.SerializeVec2 = exports.ParseVec2 = exports.SerializeVec3 = exports.ParseVec3 = exports.norm = exports.mult = exports.length = exports.add = exports.sub = exports.SerializeVec4 = exports.ParseVec4 = exports.ParseCol4BGRA = exports.SerializeCol4BGRA = exports.ParseCol4RGBA = exports.SerializeCol4RGBA = void 0;
|
|
13
|
+
const SerializeCol4RGBA = (writer, value) => {
|
|
14
|
+
writer.writeFloat(value.r);
|
|
15
|
+
writer.writeFloat(value.g);
|
|
16
|
+
writer.writeFloat(value.b);
|
|
17
|
+
writer.writeFloat(value.a);
|
|
18
|
+
};
|
|
19
|
+
exports.SerializeCol4RGBA = SerializeCol4RGBA;
|
|
20
|
+
const ParseCol4RGBA = (reader) => {
|
|
21
|
+
return {
|
|
22
|
+
r: reader.readFloat32(),
|
|
23
|
+
g: reader.readFloat32(),
|
|
24
|
+
b: reader.readFloat32(),
|
|
25
|
+
a: reader.readFloat32(),
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
exports.ParseCol4RGBA = ParseCol4RGBA;
|
|
29
|
+
const SerializeCol4BGRA = (writer, value) => {
|
|
30
|
+
writer.writeByte(value.b);
|
|
31
|
+
writer.writeByte(value.g);
|
|
32
|
+
writer.writeByte(value.r);
|
|
33
|
+
writer.writeByte(value.a);
|
|
34
|
+
};
|
|
35
|
+
exports.SerializeCol4BGRA = SerializeCol4BGRA;
|
|
36
|
+
const ParseCol4BGRA = (reader) => {
|
|
37
|
+
return {
|
|
38
|
+
b: reader.readByte(),
|
|
39
|
+
g: reader.readByte(),
|
|
40
|
+
r: reader.readByte(),
|
|
41
|
+
a: reader.readByte(),
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
exports.ParseCol4BGRA = ParseCol4BGRA;
|
|
45
|
+
const ParseVec4 = (reader) => {
|
|
46
|
+
return {
|
|
47
|
+
...((0, exports.ParseVec3)(reader)),
|
|
48
|
+
w: reader.readFloat32()
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
exports.ParseVec4 = ParseVec4;
|
|
52
|
+
const SerializeVec4 = (writer, vec) => {
|
|
53
|
+
(0, exports.SerializeVec3)(writer, vec);
|
|
54
|
+
writer.writeFloat(vec.w);
|
|
55
|
+
};
|
|
56
|
+
exports.SerializeVec4 = SerializeVec4;
|
|
57
|
+
const sub = (other, vec) => ({ x: other.x - vec.x, y: other.y - vec.y, z: other.z - vec.z });
|
|
58
|
+
exports.sub = sub;
|
|
59
|
+
const add = (vec, other) => ({ x: vec.x + other.x, y: vec.y + other.y, z: vec.z + other.z });
|
|
60
|
+
exports.add = add;
|
|
61
|
+
const length = (vec) => Math.sqrt(vec.x ** 2 + vec.y ** 2 + vec.z ** 2);
|
|
62
|
+
exports.length = length;
|
|
63
|
+
const mult = (vec, scale) => ({ x: vec.x * scale, y: vec.y * scale, z: vec.z * scale });
|
|
64
|
+
exports.mult = mult;
|
|
65
|
+
const norm = (vec) => (0, exports.mult)(vec, 1. / (0, exports.length)(vec));
|
|
66
|
+
exports.norm = norm;
|
|
67
|
+
const ParseVec3 = (reader) => {
|
|
68
|
+
return {
|
|
69
|
+
...((0, exports.ParseVec2)(reader)),
|
|
70
|
+
z: reader.readFloat32()
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
exports.ParseVec3 = ParseVec3;
|
|
74
|
+
const SerializeVec3 = (writer, vec) => {
|
|
75
|
+
(0, exports.SerializeVec2)(writer, vec);
|
|
76
|
+
writer.writeFloat(vec.z);
|
|
77
|
+
};
|
|
78
|
+
exports.SerializeVec3 = SerializeVec3;
|
|
79
|
+
const ParseVec2 = (reader) => {
|
|
80
|
+
return {
|
|
81
|
+
x: reader.readFloat32(),
|
|
82
|
+
y: reader.readFloat32(),
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
exports.ParseVec2 = ParseVec2;
|
|
86
|
+
const SerializeVec2 = (writer, vec) => {
|
|
87
|
+
writer.writeFloat(vec.x);
|
|
88
|
+
writer.writeFloat(vec.y);
|
|
89
|
+
};
|
|
90
|
+
exports.SerializeVec2 = SerializeVec2;
|
|
91
|
+
const ParseTransform = (reader) => {
|
|
92
|
+
return {
|
|
93
|
+
rotation: (0, exports.ParseVec4)(reader),
|
|
94
|
+
translation: (0, exports.ParseVec3)(reader),
|
|
95
|
+
scale3d: (0, exports.ParseVec3)(reader),
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
exports.ParseTransform = ParseTransform;
|
|
99
|
+
const SerializeTransform = (writer, transform) => {
|
|
100
|
+
(0, exports.SerializeVec4)(writer, transform.rotation);
|
|
101
|
+
(0, exports.SerializeVec3)(writer, transform.translation);
|
|
102
|
+
(0, exports.SerializeVec3)(writer, transform.scale3d);
|
|
103
|
+
};
|
|
104
|
+
exports.SerializeTransform = SerializeTransform;
|
|
105
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { ReadableStreamDefaultReader } from "stream/web";
|
|
3
|
+
import { Alignment } from "../byte/alignment.enum";
|
|
4
|
+
import { BinaryReadable } from "../byte/binary-readable.interface";
|
|
5
|
+
export interface StreamBinaryReadable extends BinaryReadable {
|
|
6
|
+
pause: () => void;
|
|
7
|
+
resume: () => void;
|
|
8
|
+
hasInput: () => boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare abstract class ByteStreamReader implements StreamBinaryReadable {
|
|
11
|
+
private reader;
|
|
12
|
+
onCloseCallback: () => Promise<void>;
|
|
13
|
+
private timeout;
|
|
14
|
+
maxBufferThreshold: number;
|
|
15
|
+
alignment: Alignment;
|
|
16
|
+
protected operatingStreamBuffer: Uint8Array;
|
|
17
|
+
protected operatingDataView: DataView;
|
|
18
|
+
protected callbackAfterRead: undefined | (() => void);
|
|
19
|
+
protected currentByte: number;
|
|
20
|
+
protected inputStreamIsDone: boolean;
|
|
21
|
+
protected paused: boolean;
|
|
22
|
+
debug: boolean;
|
|
23
|
+
protected closedAlready: boolean;
|
|
24
|
+
protected neededNextAmountOfBytes: number;
|
|
25
|
+
private readLoopHandle;
|
|
26
|
+
private waitingTimeoutHandle;
|
|
27
|
+
protected totalNumberOfBytesRead: number;
|
|
28
|
+
protected trailingBufferSize: number;
|
|
29
|
+
constructor(reader: ReadableStreamDefaultReader<Uint8Array>, onCloseCallback: () => Promise<void>, timeout?: number, maxBufferThreshold?: number, alignment?: Alignment);
|
|
30
|
+
pause(): void;
|
|
31
|
+
resume(): void;
|
|
32
|
+
hasInput(): boolean;
|
|
33
|
+
close(): Promise<void>;
|
|
34
|
+
protected continuousRead: () => Promise<void>;
|
|
35
|
+
allocate(count: number): Promise<void>;
|
|
36
|
+
private waitUntilNumBytesAvailable;
|
|
37
|
+
skipBytes(byteLength?: number): void;
|
|
38
|
+
readByte(): number;
|
|
39
|
+
readBytes(count: number): Uint8Array;
|
|
40
|
+
readHex(hexLength: number): string;
|
|
41
|
+
readInt8(): number;
|
|
42
|
+
readUint8(): number;
|
|
43
|
+
readInt16(): number;
|
|
44
|
+
readUint16(): number;
|
|
45
|
+
readInt32(): number;
|
|
46
|
+
readUint32(): number;
|
|
47
|
+
readLong(): bigint;
|
|
48
|
+
readInt64(): bigint;
|
|
49
|
+
readUint64(): bigint;
|
|
50
|
+
readFloat32(): number;
|
|
51
|
+
readDouble(): number;
|
|
52
|
+
readString(): string;
|
|
53
|
+
getBufferPosition(): number;
|
|
54
|
+
getBufferProgress(): number;
|
|
55
|
+
getBufferLength(): number;
|
|
56
|
+
getAmountAllocatedLeft(): number;
|
|
57
|
+
}
|