@etothepii/satisfactory-file-parser 0.4.15 → 0.4.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -10
- package/build/index.d.ts +2 -2
- package/build/index.js +3 -5
- package/build/parser/parser.d.ts +0 -1
- package/build/parser/parser.js +0 -17
- package/build/parser/satisfactory/objects/property/generic/StructProperty.d.ts +2 -5
- package/build/parser/satisfactory/objects/property/generic/StructProperty.js +23 -14
- package/build/parser/satisfactory/save/level.class.d.ts +0 -3
- package/build/parser/satisfactory/save/level.class.js +1 -55
- package/build/parser/satisfactory/save/satisfactory-save.d.ts +0 -2
- package/build/parser/satisfactory/save/satisfactory-save.js +0 -1
- package/build/parser/satisfactory/save/save-reader.d.ts +0 -1
- package/build/parser/satisfactory/save/save-reader.js +2 -32
- package/build/parser/stream/reworked/readable-stream-parser.js +6 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ Game Version Files of U5 and below are NOT supported.
|
|
|
18
18
|
| <= U5 | ❌ |
|
|
19
19
|
| U6 + U7 | ✅ 0.0.1 - 0.0.34 |
|
|
20
20
|
| U8 | ✅ 0.1.20 - 0.3.7 |
|
|
21
|
-
| U1.0 | ✅ >= 0.4.
|
|
21
|
+
| U1.0 | ✅ >= 0.4.16 |
|
|
22
22
|
|
|
23
23
|
# Installation via npm
|
|
24
24
|
`npm install @etothepii/satisfactory-file-parser`
|
|
@@ -86,14 +86,19 @@ fs.writeFileSync('./MyModifiedSave.sav', Buffer.concat([fileHeader!, ...bodyChun
|
|
|
86
86
|
```
|
|
87
87
|
|
|
88
88
|
|
|
89
|
-
##
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
import * as fs from 'fs';
|
|
93
|
-
import { Parser } from "@etothepii/satisfactory-file-parser";
|
|
89
|
+
## Inspecting Save Objects
|
|
90
|
+
Once you have the complete parsing done, the JSON is a `SatisfactorySave` object.
|
|
91
|
+
You can for example loop through players and print their cached names and positions.
|
|
94
92
|
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
```js
|
|
94
|
+
import { isSaveEntity, SatisfactorySave, SaveEntity, StrProperty } from '@etothepii/satisfactory-file-parser';
|
|
95
|
+
|
|
96
|
+
const objects = save.levels.flatMap(level => level.objects);
|
|
97
|
+
const players = objects.filter(obj => isSaveEntity(obj) && obj.typePath === '/Game/FactoryGame/Character/Player/Char_Player.Char_Player_C') as SaveEntity[];
|
|
98
|
+
for (const player of players) {
|
|
99
|
+
const name = (player.properties.mCachedPlayerName as StrProperty).value;
|
|
100
|
+
console.log(name, player.transform.translation);
|
|
101
|
+
}
|
|
97
102
|
```
|
|
98
103
|
|
|
99
104
|
|
|
@@ -138,6 +143,16 @@ So far this was just a private hobby project. But i figure some people actually
|
|
|
138
143
|
If you find a bug or have feedback about the parser, you can just hit me up on the satisfactory discord `etothepii`.
|
|
139
144
|
|
|
140
145
|
# Changelog
|
|
146
|
+
### [0.4.17] (2024-10-05)
|
|
147
|
+
#### updated README
|
|
148
|
+
#### bugfix
|
|
149
|
+
* `ClientIdentityInfo` field names and structure got changed, since the meaning is now more clear.
|
|
150
|
+
* removed trailing object list from satisfactory save object.
|
|
151
|
+
* deleted entities references get serialized again, just based on collectables list.
|
|
152
|
+
|
|
153
|
+
### [0.4.16] (2024-10-03)
|
|
154
|
+
#### bugfix
|
|
155
|
+
* exporting `isSaveEntity` and `isSaveComponent` again.
|
|
141
156
|
|
|
142
157
|
### [0.4.15] (2024-10-02)
|
|
143
158
|
#### updated README
|
|
@@ -146,8 +161,7 @@ If you find a bug or have feedback about the parser, you can just hit me up on t
|
|
|
146
161
|
### [0.4.14] (2024-10-02)
|
|
147
162
|
#### updated README
|
|
148
163
|
* updated the code examples with more context
|
|
149
|
-
|
|
150
|
-
### Internal renamings (won't affect you if you stick to the code examples)
|
|
164
|
+
#### Internal renamings (won't affect you if you stick to the code examples)
|
|
151
165
|
* improved the interface for abstract parser classes
|
|
152
166
|
* extended some error log messages
|
|
153
167
|
* added an additional check when parsing struct property InventoryItem, since ported saves often have a few more bytes.
|
package/build/index.d.ts
CHANGED
|
@@ -21,8 +21,8 @@ export * from './parser/satisfactory/objects/property/generic/Uint32Property';
|
|
|
21
21
|
export * from './parser/satisfactory/objects/property/generic/Uint64Property';
|
|
22
22
|
export * from './parser/satisfactory/objects/property/generic/Uint8Property';
|
|
23
23
|
export * from './parser/satisfactory/objects/property/special/SpecialAnyProperty';
|
|
24
|
-
export
|
|
25
|
-
export
|
|
24
|
+
export * from './parser/satisfactory/objects/SaveComponent';
|
|
25
|
+
export * from './parser/satisfactory/objects/SaveEntity';
|
|
26
26
|
export * from './parser/satisfactory/objects/ue/MD5Hash';
|
|
27
27
|
export * from './parser/satisfactory/objects/values/GUID';
|
|
28
28
|
export * from './parser/satisfactory/objects/values/ObjectReference';
|
package/build/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.ReadableStreamParser = exports.Parser = exports.SaveStreamWriter = exports.SaveStreamJsonStringifier = exports.SaveWriter = exports.SaveReader = exports.BlueprintWriter = exports.BlueprintConfigWriter = exports.BlueprintReader = exports.BlueprintConfigReader = exports.ByteWriter = exports.ByteReader = exports.SatisfactorySave = exports.Level = exports.
|
|
17
|
+
exports.ReadableStreamParser = exports.Parser = exports.SaveStreamWriter = exports.SaveStreamJsonStringifier = exports.SaveWriter = exports.SaveReader = exports.BlueprintWriter = exports.BlueprintConfigWriter = exports.BlueprintReader = exports.BlueprintConfigReader = exports.ByteWriter = exports.ByteReader = exports.SatisfactorySave = exports.Level = exports.DataFields = void 0;
|
|
18
18
|
__exportStar(require("./parser/satisfactory/blueprint/blueprint.types"), exports);
|
|
19
19
|
var DataFields_1 = require("./parser/satisfactory/objects/DataFields");
|
|
20
20
|
Object.defineProperty(exports, "DataFields", { enumerable: true, get: function () { return DataFields_1.DataFields; } });
|
|
@@ -39,10 +39,8 @@ __exportStar(require("./parser/satisfactory/objects/property/generic/Uint32Prope
|
|
|
39
39
|
__exportStar(require("./parser/satisfactory/objects/property/generic/Uint64Property"), exports);
|
|
40
40
|
__exportStar(require("./parser/satisfactory/objects/property/generic/Uint8Property"), exports);
|
|
41
41
|
__exportStar(require("./parser/satisfactory/objects/property/special/SpecialAnyProperty"), exports);
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
var SaveEntity_1 = require("./parser/satisfactory/objects/SaveEntity");
|
|
45
|
-
Object.defineProperty(exports, "SaveEntity", { enumerable: true, get: function () { return SaveEntity_1.SaveEntity; } });
|
|
42
|
+
__exportStar(require("./parser/satisfactory/objects/SaveComponent"), exports);
|
|
43
|
+
__exportStar(require("./parser/satisfactory/objects/SaveEntity"), exports);
|
|
46
44
|
__exportStar(require("./parser/satisfactory/objects/ue/MD5Hash"), exports);
|
|
47
45
|
__exportStar(require("./parser/satisfactory/objects/values/GUID"), exports);
|
|
48
46
|
__exportStar(require("./parser/satisfactory/objects/values/ObjectReference"), exports);
|
package/build/parser/parser.d.ts
CHANGED
|
@@ -3,7 +3,6 @@ import { Blueprint } from "./satisfactory/blueprint/blueprint.types";
|
|
|
3
3
|
import { SatisfactorySave } from "./satisfactory/save/satisfactory-save";
|
|
4
4
|
export declare class Parser {
|
|
5
5
|
static WriteSave(save: SatisfactorySave, onBinaryBeforeCompressing: (buffer: ArrayBuffer) => void, onHeader: (header: Uint8Array) => void, onChunk: (chunk: Uint8Array) => void): ChunkSummary[];
|
|
6
|
-
static ParseSaveFile(name: string, file: Buffer, onDecompressedSaveBody?: (buffer: ArrayBuffer) => void, onProgress?: (progress: number, message?: string) => void): SatisfactorySave;
|
|
7
6
|
static WriteBlueprintFiles(blueprint: Blueprint, onMainFileBinaryBeforeCompressing?: (binary: ArrayBuffer) => void, onMainFileHeader?: (header: Uint8Array) => void, onMainFileChunk?: (chunk: Uint8Array) => void): {
|
|
8
7
|
mainFileChunkSummary: ChunkSummary[];
|
|
9
8
|
configFileBinary: ArrayBuffer;
|
package/build/parser/parser.js
CHANGED
|
@@ -3,8 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.Parser = void 0;
|
|
4
4
|
const blueprint_reader_1 = require("./satisfactory/blueprint/blueprint-reader");
|
|
5
5
|
const blueprint_writer_1 = require("./satisfactory/blueprint/blueprint-writer");
|
|
6
|
-
const satisfactory_save_1 = require("./satisfactory/save/satisfactory-save");
|
|
7
|
-
const save_reader_1 = require("./satisfactory/save/save-reader");
|
|
8
6
|
const save_writer_1 = require("./satisfactory/save/save-writer");
|
|
9
7
|
class Parser {
|
|
10
8
|
static WriteSave(save, onBinaryBeforeCompressing, onHeader, onChunk) {
|
|
@@ -18,21 +16,6 @@ class Parser {
|
|
|
18
16
|
const chunkSummary = writer.generateChunks(save.compressionInfo, posAfterHeader, onBinaryBeforeCompressing, onHeader, onChunk);
|
|
19
17
|
return chunkSummary;
|
|
20
18
|
}
|
|
21
|
-
static ParseSaveFile(name, file, onDecompressedSaveBody = () => { }, onProgress = () => { }) {
|
|
22
|
-
const reader = new save_reader_1.SaveReader(new Uint8Array(file).buffer, onProgress);
|
|
23
|
-
const header = reader.readHeader();
|
|
24
|
-
const save = new satisfactory_save_1.SatisfactorySave(name, header);
|
|
25
|
-
const inflateResult = reader.inflateChunks();
|
|
26
|
-
onDecompressedSaveBody(reader.getBuffer());
|
|
27
|
-
const gridHash = reader.readSaveBodyHash();
|
|
28
|
-
save.gridHash = gridHash;
|
|
29
|
-
const grids = reader.readGrids();
|
|
30
|
-
save.grids = grids;
|
|
31
|
-
save.levels = reader.readLevels();
|
|
32
|
-
save.compressionInfo = reader.compressionInfo;
|
|
33
|
-
save.trailingCollectedObjects = reader.trailingCollectedObjects;
|
|
34
|
-
return save;
|
|
35
|
-
}
|
|
36
19
|
static WriteBlueprintFiles(blueprint, onMainFileBinaryBeforeCompressing = () => { }, onMainFileHeader = () => { }, onMainFileChunk = () => { }) {
|
|
37
20
|
const blueprintWriter = new blueprint_writer_1.BlueprintWriter();
|
|
38
21
|
blueprint_writer_1.BlueprintWriter.SerializeHeader(blueprintWriter, blueprint.header);
|
|
@@ -39,11 +39,8 @@ export type DynamicStructPropertyValue = {
|
|
|
39
39
|
properties: PropertiesMap;
|
|
40
40
|
};
|
|
41
41
|
export type ClientIdentityInfo = {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
clientUnk2: number;
|
|
45
|
-
clientHashSize: number;
|
|
46
|
-
someClientHash: number[];
|
|
42
|
+
offlineId: string;
|
|
43
|
+
accountIds: Record<number, number[]>;
|
|
47
44
|
};
|
|
48
45
|
export type GENERIC_STRUCT_PROPERTY_VALUE = BasicMultipleStructPropertyValue | BasicStructPropertyValue | BoxStructPropertyValue | RailroadTrackPositionStructPropertyValue | InventoryItemStructPropertyValue | FICFrameRangeStructPropertyValue | ClientIdentityInfo | DynamicStructPropertyValue | col4 | vec3 | vec4 | string;
|
|
49
46
|
export declare class StructProperty extends AbstractBaseProperty {
|
|
@@ -35,7 +35,7 @@ class StructProperty extends BasicProperty_1.AbstractBaseProperty {
|
|
|
35
35
|
struct.value = StructProperty.ParseValue(reader, struct.subtype, size);
|
|
36
36
|
const readBytes = reader.getBufferPosition() - before;
|
|
37
37
|
if (readBytes !== size) {
|
|
38
|
-
if (size - readBytes === 4
|
|
38
|
+
if (size - readBytes === 4) {
|
|
39
39
|
reader.skipBytes(size - readBytes);
|
|
40
40
|
}
|
|
41
41
|
else {
|
|
@@ -64,7 +64,7 @@ class StructProperty extends BasicProperty_1.AbstractBaseProperty {
|
|
|
64
64
|
value = (size === 16) ? util_types_1.vec4.ParseF(reader) : util_types_1.vec4.Parse(reader);
|
|
65
65
|
break;
|
|
66
66
|
case 'Box':
|
|
67
|
-
value = (size === 25) ? {
|
|
67
|
+
value = ((size === 25) ? {
|
|
68
68
|
min: util_types_1.vec3.ParseF(reader),
|
|
69
69
|
max: util_types_1.vec3.ParseF(reader),
|
|
70
70
|
isValid: reader.readByte() >= 1
|
|
@@ -72,7 +72,7 @@ class StructProperty extends BasicProperty_1.AbstractBaseProperty {
|
|
|
72
72
|
min: util_types_1.vec3.Parse(reader),
|
|
73
73
|
max: util_types_1.vec3.Parse(reader),
|
|
74
74
|
isValid: reader.readByte() >= 1
|
|
75
|
-
};
|
|
75
|
+
});
|
|
76
76
|
break;
|
|
77
77
|
case 'RailroadTrackPosition':
|
|
78
78
|
value = {
|
|
@@ -89,12 +89,19 @@ class StructProperty extends BasicProperty_1.AbstractBaseProperty {
|
|
|
89
89
|
value = reader.readString();
|
|
90
90
|
break;
|
|
91
91
|
case 'ClientIdentityInfo':
|
|
92
|
-
const
|
|
93
|
-
const
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
92
|
+
const offlineId = reader.readString();
|
|
93
|
+
const numAccountIds = reader.readInt32();
|
|
94
|
+
const accountIds = {};
|
|
95
|
+
for (let i = 0; i < numAccountIds; i++) {
|
|
96
|
+
const platformFlagMaybe = reader.readByte();
|
|
97
|
+
const idSize = reader.readInt32();
|
|
98
|
+
const accountId = Array.from(reader.readBytes(idSize));
|
|
99
|
+
accountIds[platformFlagMaybe] = accountId;
|
|
100
|
+
}
|
|
101
|
+
value = {
|
|
102
|
+
offlineId,
|
|
103
|
+
accountIds
|
|
104
|
+
};
|
|
98
105
|
break;
|
|
99
106
|
case 'InventoryItem':
|
|
100
107
|
const before = reader.getBufferPosition();
|
|
@@ -209,11 +216,13 @@ class StructProperty extends BasicProperty_1.AbstractBaseProperty {
|
|
|
209
216
|
break;
|
|
210
217
|
case 'ClientIdentityInfo':
|
|
211
218
|
value = value;
|
|
212
|
-
writer.writeString(value.
|
|
213
|
-
writer.writeInt32(value.
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
219
|
+
writer.writeString(value.offlineId);
|
|
220
|
+
writer.writeInt32(Object.values(value.accountIds).length);
|
|
221
|
+
for (const [platformFlagMaybe, accountId] of Object.entries(value.accountIds)) {
|
|
222
|
+
writer.writeByte(Number(platformFlagMaybe));
|
|
223
|
+
writer.writeInt32(accountId.length);
|
|
224
|
+
writer.writeBytesArray(accountId);
|
|
225
|
+
}
|
|
217
226
|
break;
|
|
218
227
|
case 'InventoryItem':
|
|
219
228
|
value = value;
|
|
@@ -4,7 +4,6 @@ import { SaveComponent } from "../objects/SaveComponent";
|
|
|
4
4
|
import { SaveEntity } from "../objects/SaveEntity";
|
|
5
5
|
import { SaveObject } from "../objects/SaveObject";
|
|
6
6
|
import { ObjectReference } from "../objects/values/ObjectReference";
|
|
7
|
-
import { SaveReader } from "./save-reader";
|
|
8
7
|
export declare class Level {
|
|
9
8
|
name: string;
|
|
10
9
|
objects: (SaveEntity | SaveComponent)[];
|
|
@@ -14,8 +13,6 @@ export declare class Level {
|
|
|
14
13
|
static WriteLevel(writer: ByteWriter, level: Level, buildVersion: number): void;
|
|
15
14
|
static SerializeObjectContents(writer: ByteWriter, objects: (SaveEntity | SaveComponent)[], buildVersion: number, levelName: string): void;
|
|
16
15
|
static ReadObjectHeaders(reader: BinaryReadable, objectsList: SaveObject[], onProgressCallback: (progress: number, msg?: string) => void): void;
|
|
17
|
-
static ReadObjectContents(levelName: string, reader: BinaryReadable, objectsList: SaveObject[], buildVersion: number, onProgressCallback: (progress: number, msg?: string) => void): Promise<void>;
|
|
18
|
-
static ReadLevel(reader: SaveReader, levelName: string, buildVersion: number): Level;
|
|
19
16
|
static SerializeCollectablesList(writer: ByteWriter, collectables: ObjectReference[]): void;
|
|
20
17
|
static ReadCollectablesList(reader: BinaryReadable): ObjectReference[];
|
|
21
18
|
}
|
|
@@ -33,6 +33,7 @@ class Level {
|
|
|
33
33
|
writer.writeInt32(0);
|
|
34
34
|
writer.writeInt32(0);
|
|
35
35
|
Level.SerializeObjectHeaders(writer, level.objects);
|
|
36
|
+
Level.SerializeCollectablesList(writer, level.collectables);
|
|
36
37
|
writer.writeBinarySizeFromPosition(lenIndicatorHeaderAndDestroyedEntitiesSize, lenIndicatorHeaderAndDestroyedEntitiesSize + 8);
|
|
37
38
|
Level.SerializeObjectContents(writer, level.objects, buildVersion, level.name);
|
|
38
39
|
Level.SerializeCollectablesList(writer, level.collectables);
|
|
@@ -81,61 +82,6 @@ class Level {
|
|
|
81
82
|
}
|
|
82
83
|
}
|
|
83
84
|
}
|
|
84
|
-
static async ReadObjectContents(levelName, reader, objectsList, buildVersion, onProgressCallback) {
|
|
85
|
-
const countEntities = reader.readInt32();
|
|
86
|
-
if (countEntities !== objectsList.length) {
|
|
87
|
-
throw new Error(`possibly corrupt. entity content count ${countEntities} does not equal object count of ${objectsList.length}`);
|
|
88
|
-
}
|
|
89
|
-
for (let i = 0; i < countEntities; i++) {
|
|
90
|
-
if (countEntities >= 10000 && i % 10000 === 0) {
|
|
91
|
-
onProgressCallback(reader.getBufferProgress(), `read object count [${(i + 1)}/${(countEntities + 1)}] in level ${levelName}`);
|
|
92
|
-
}
|
|
93
|
-
const obj = objectsList[i];
|
|
94
|
-
obj.objectVersion = reader.readInt32();
|
|
95
|
-
obj.unknownType2 = reader.readInt32();
|
|
96
|
-
const binarySize = reader.readInt32();
|
|
97
|
-
const before = reader.getBufferPosition();
|
|
98
|
-
if ((0, SaveEntity_1.isSaveEntity)(obj)) {
|
|
99
|
-
SaveEntity_1.SaveEntity.ParseData(obj, binarySize, reader, buildVersion, obj.typePath);
|
|
100
|
-
}
|
|
101
|
-
else if ((0, SaveComponent_1.isSaveComponent)(obj)) {
|
|
102
|
-
SaveComponent_1.SaveComponent.ParseData(obj, binarySize, reader, buildVersion, obj.typePath);
|
|
103
|
-
}
|
|
104
|
-
const after = reader.getBufferPosition();
|
|
105
|
-
if (after - before !== binarySize) {
|
|
106
|
-
console.warn('entity may be corrupt', obj.instanceName);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
static ReadLevel(reader, levelName, buildVersion) {
|
|
111
|
-
const level = new Level(levelName);
|
|
112
|
-
const headersBinLen = reader.readInt32();
|
|
113
|
-
const unk = reader.readInt32();
|
|
114
|
-
const posBeforeHeaders = reader.getBufferPosition();
|
|
115
|
-
Level.ReadObjectHeaders(reader, level.objects, reader.onProgressCallback);
|
|
116
|
-
let remainingSize = headersBinLen - (reader.getBufferPosition() - posBeforeHeaders);
|
|
117
|
-
if (remainingSize > 0) {
|
|
118
|
-
const doubledCollectablesIgnored = Level.ReadCollectablesList(reader);
|
|
119
|
-
}
|
|
120
|
-
else {
|
|
121
|
-
}
|
|
122
|
-
remainingSize = headersBinLen - (reader.getBufferPosition() - posBeforeHeaders);
|
|
123
|
-
if (remainingSize !== 0) {
|
|
124
|
-
console.warn('remaining size not 0. Save may be corrupt.', remainingSize, levelName);
|
|
125
|
-
}
|
|
126
|
-
const objectContentsBinLen = reader.readInt32();
|
|
127
|
-
const unk2 = reader.readInt32();
|
|
128
|
-
reader.onProgressCallback(reader.getBufferProgress());
|
|
129
|
-
const posBeforeContents = reader.getBufferPosition();
|
|
130
|
-
Level.ReadObjectContents(levelName, reader, level.objects, buildVersion, reader.onProgressCallback);
|
|
131
|
-
const posAfterContents = reader.getBufferPosition();
|
|
132
|
-
if (posAfterContents - posBeforeContents !== objectContentsBinLen) {
|
|
133
|
-
console.warn('save seems corrupt.', this.name);
|
|
134
|
-
}
|
|
135
|
-
reader.onProgressCallback(reader.getBufferProgress());
|
|
136
|
-
level.collectables = Level.ReadCollectablesList(reader);
|
|
137
|
-
return level;
|
|
138
|
-
}
|
|
139
85
|
static SerializeCollectablesList(writer, collectables) {
|
|
140
86
|
writer.writeInt32(collectables.length);
|
|
141
87
|
for (const collectable of collectables) {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { ChunkCompressionInfo } from "../../file.types";
|
|
2
|
-
import { ObjectReference } from "../objects/values/ObjectReference";
|
|
3
2
|
import { Level } from "./level.class";
|
|
4
3
|
import { ByteArray4, Grids } from "./save-reader";
|
|
5
4
|
import { SatisfactorySaveHeader } from "./save.types";
|
|
@@ -9,7 +8,6 @@ export declare class SatisfactorySave {
|
|
|
9
8
|
gridHash: ByteArray4;
|
|
10
9
|
grids: Grids;
|
|
11
10
|
levels: Level[];
|
|
12
|
-
trailingCollectedObjects: ObjectReference[];
|
|
13
11
|
compressionInfo?: ChunkCompressionInfo;
|
|
14
12
|
constructor(name: string, header: SatisfactorySaveHeader);
|
|
15
13
|
}
|
|
@@ -9,7 +9,6 @@ const alignment_enum_1 = require("../../byte/alignment.enum");
|
|
|
9
9
|
const byte_reader_class_1 = require("../../byte/byte-reader.class");
|
|
10
10
|
const parser_error_1 = require("../../error/parser.error");
|
|
11
11
|
const MD5Hash_1 = require("../objects/ue/MD5Hash");
|
|
12
|
-
const level_class_1 = require("./level.class");
|
|
13
12
|
exports.DEFAULT_SATISFACTORY_CHUNK_HEADER_SIZE = 49;
|
|
14
13
|
class SaveReader extends byte_reader_class_1.ByteReader {
|
|
15
14
|
constructor(fileBuffer, onProgressCallback = () => { }) {
|
|
@@ -23,10 +22,10 @@ class SaveReader extends byte_reader_class_1.ByteReader {
|
|
|
23
22
|
chunkHeaderSize: exports.DEFAULT_SATISFACTORY_CHUNK_HEADER_SIZE
|
|
24
23
|
};
|
|
25
24
|
this.readSaveBodyHash = () => {
|
|
26
|
-
|
|
25
|
+
this.readInt32();
|
|
27
26
|
const cannotBeLevelCountWhatIsIt = this.readInt32();
|
|
28
27
|
const noneString = this.readString();
|
|
29
|
-
|
|
28
|
+
this.readInt32();
|
|
30
29
|
const gridValidationHash = Array.from(this.readBytes(4));
|
|
31
30
|
const unk3 = this.readInt32();
|
|
32
31
|
const noneString2 = this.readString();
|
|
@@ -163,35 +162,6 @@ class SaveReader extends byte_reader_class_1.ByteReader {
|
|
|
163
162
|
numChunks: currentChunks.length
|
|
164
163
|
};
|
|
165
164
|
}
|
|
166
|
-
readLevels() {
|
|
167
|
-
if (!this.header) {
|
|
168
|
-
throw new parser_error_1.ParserError('ParserError', 'Header must be set before objects can be read.');
|
|
169
|
-
}
|
|
170
|
-
const roughSaveVersion = SaveReader.getRoughSaveVersion(this.header.saveVersion, this.header.saveHeaderType);
|
|
171
|
-
if (roughSaveVersion === '<U6') {
|
|
172
|
-
throw new parser_error_1.UnsupportedVersionError('Game Version < U6 is not supported.');
|
|
173
|
-
}
|
|
174
|
-
else if (roughSaveVersion === 'U6/U7') {
|
|
175
|
-
throw new parser_error_1.UnsupportedVersionError('Game Version U6/U7 is not supported in this package version. Consider downgrading to the latest package version supporting it, which is 0.0.34');
|
|
176
|
-
}
|
|
177
|
-
else if (roughSaveVersion === 'U8') {
|
|
178
|
-
throw new parser_error_1.UnsupportedVersionError('Game Version U8 is not supported in this package version. Consider downgrading to the latest package version supporting it, which is 0.3.7');
|
|
179
|
-
}
|
|
180
|
-
const levels = [];
|
|
181
|
-
const levelCount = this.readInt32();
|
|
182
|
-
this.onProgressCallback(this.getBufferProgress(), `reading pack of ${levelCount} levels.`);
|
|
183
|
-
for (let i = 0; i < levelCount; i++) {
|
|
184
|
-
let levelSingleName = this.readString();
|
|
185
|
-
if (i % 500 === 0) {
|
|
186
|
-
this.onProgressCallback(this.getBufferProgress(), `reading level [${(i + 1)}/${(levelCount + 1)}] ${levelSingleName}`);
|
|
187
|
-
}
|
|
188
|
-
levels.push(level_class_1.Level.ReadLevel(this, levelSingleName, this.header.buildVersion));
|
|
189
|
-
}
|
|
190
|
-
levels.push(level_class_1.Level.ReadLevel(this, this.header.mapName, this.header.buildVersion));
|
|
191
|
-
const trailingStuffToIgnore = level_class_1.Level.ReadCollectablesList(this);
|
|
192
|
-
this.onProgressCallback(this.getBufferProgress(), 'finished parsing.');
|
|
193
|
-
return levels;
|
|
194
|
-
}
|
|
195
165
|
}
|
|
196
166
|
exports.SaveReader = SaveReader;
|
|
197
167
|
SaveReader.EPOCH_TICKS = 621355968000000000n;
|
|
@@ -72,6 +72,12 @@ class ReadableStreamParser {
|
|
|
72
72
|
const objectCountToRead = Math.min(countObjectHeaders - totalReadObjectsInLevel, batchingSizeOfObjects);
|
|
73
73
|
const objects = _a.ReadNObjectHeaders(reader, objectCountToRead);
|
|
74
74
|
afterHeadersOfBatch = reader.getBufferPosition();
|
|
75
|
+
if (countObjectHeaders === totalReadObjectsInLevel + objects.length) {
|
|
76
|
+
const bytesLeft = afterAllHeaders - reader.getBufferPosition();
|
|
77
|
+
if (bytesLeft > 0) {
|
|
78
|
+
_a.ReadDestroyedEntityReferences(reader);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
75
81
|
if (totalReadObjectsInLevel === 0) {
|
|
76
82
|
reader.skipBytes(afterAllHeaders - reader.getBufferPosition());
|
|
77
83
|
const objectContentsBinLen = reader.readInt32();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@etothepii/satisfactory-file-parser",
|
|
3
3
|
"author": "etothepii",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.17",
|
|
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",
|