@etothepii/satisfactory-file-parser 0.1.24 → 0.1.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/index.d.ts +1 -0
- package/build/index.js +25 -58
- package/build/parser/byte/alignment.enum.js +2 -5
- package/build/parser/byte/binary-operable.interface.js +1 -2
- package/build/parser/byte/binary-readable.interface.js +1 -2
- package/build/parser/byte/byte-reader.class.js +10 -14
- package/build/parser/byte/byte-writer.class.js +10 -13
- package/build/parser/error/parser.error.js +6 -15
- package/build/parser/file.types.js +2 -5
- package/build/parser/parser.d.ts +1 -1
- package/build/parser/parser.js +24 -27
- package/build/parser/satisfactory/blueprint/blueprint-reader.js +28 -36
- package/build/parser/satisfactory/blueprint/blueprint-writer.js +20 -25
- package/build/parser/satisfactory/blueprint/blueprint.types.js +1 -2
- package/build/parser/satisfactory/objects/DataFields.js +79 -83
- package/build/parser/satisfactory/objects/GUIDInfo.js +5 -8
- package/build/parser/satisfactory/objects/ObjectReference.js +2 -5
- package/build/parser/satisfactory/objects/Property.js +91 -120
- package/build/parser/satisfactory/objects/SaveComponent.js +7 -11
- package/build/parser/satisfactory/objects/SaveEntity.js +13 -17
- package/build/parser/satisfactory/objects/SaveObject.js +4 -8
- package/build/parser/satisfactory/objects/ue/GUID.js +2 -5
- package/build/parser/satisfactory/objects/ue/MD5Hash.js +2 -5
- package/build/parser/satisfactory/save/asynchronous-level.class.js +12 -16
- package/build/parser/satisfactory/save/level.class.js +26 -30
- package/build/parser/satisfactory/save/satisfactory-save.d.ts +2 -1
- package/build/parser/satisfactory/save/satisfactory-save.js +3 -6
- package/build/parser/satisfactory/save/save-reader.js +31 -34
- package/build/parser/satisfactory/save/save-writer.js +34 -40
- package/build/parser/satisfactory/save/save.types.js +1 -2
- package/build/parser/satisfactory/structs/util.types.js +37 -63
- package/build/parser/stream/byte-stream-reader.class.js +17 -21
- package/build/parser/stream/json-stream-state-writer.js +2 -6
- package/build/parser/stream/json-stream-writable.js +1 -5
- package/build/parser/stream/json-stream-writer.js +2 -6
- package/build/parser/stream/reworked/readable-stream-parser.d.ts +12 -0
- package/build/parser/stream/reworked/readable-stream-parser.js +201 -0
- package/build/parser/stream/reworked/stream-parser.d.ts +3 -1
- package/build/parser/stream/reworked/stream-parser.js +86 -11
- package/build/parser/stream/save-stream-json-stringifier.js +3 -7
- package/build/parser/stream/save-stream-reader.class.js +18 -24
- package/build/parser/stream/save-stream-writer.class.d.ts +15 -13
- package/build/parser/stream/save-stream-writer.class.js +71 -108
- package/build/parser/stream/stream-level.class.js +11 -15
- package/build/parser/stream/stream-parser.js +11 -15
- package/package.json +4 -2
- package/build/parser/satisfactory/objects/ue/FMD5Hash.d.ts +0 -7
- package/build/parser/satisfactory/objects/ue/FMD5Hash.js +0 -19
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.SaveComponent = exports.isSaveComponent = void 0;
|
|
4
|
-
const SaveObject_1 = require("./SaveObject");
|
|
5
|
-
const isSaveComponent = (obj) => {
|
|
1
|
+
import { SaveObject } from "./SaveObject";
|
|
2
|
+
export const isSaveComponent = (obj) => {
|
|
6
3
|
return obj.type === 'SaveComponent';
|
|
7
4
|
};
|
|
8
|
-
|
|
9
|
-
class SaveComponent extends SaveObject_1.SaveObject {
|
|
5
|
+
class SaveComponent extends SaveObject {
|
|
10
6
|
constructor(typePath, rootObject, instanceName, parentEntityName = '') {
|
|
11
7
|
super(typePath, rootObject, instanceName);
|
|
12
8
|
this.typePath = typePath;
|
|
@@ -16,16 +12,16 @@ class SaveComponent extends SaveObject_1.SaveObject {
|
|
|
16
12
|
this.type = 'SaveComponent';
|
|
17
13
|
}
|
|
18
14
|
static ParseHeader(reader, obj) {
|
|
19
|
-
|
|
15
|
+
SaveObject.ParseHeader(reader, obj);
|
|
20
16
|
obj.parentEntityName = reader.readString();
|
|
21
17
|
}
|
|
22
18
|
static SerializeHeader(writer, component) {
|
|
23
|
-
|
|
19
|
+
SaveObject.SerializeHeader(writer, component);
|
|
24
20
|
writer.writeString(component.parentEntityName);
|
|
25
21
|
}
|
|
26
22
|
static ParseData(component, length, reader, buildVersion, typePath) {
|
|
27
|
-
|
|
23
|
+
SaveObject.ParseData(component, length, reader, buildVersion, typePath);
|
|
28
24
|
}
|
|
29
25
|
}
|
|
30
26
|
SaveComponent.TypeID = 0;
|
|
31
|
-
|
|
27
|
+
export { SaveComponent };
|
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
const ObjectReference_1 = require("./ObjectReference");
|
|
6
|
-
const SaveObject_1 = require("./SaveObject");
|
|
7
|
-
const isSaveEntity = (obj) => {
|
|
1
|
+
import { ParseTransform, SerializeTransform } from "../structs/util.types";
|
|
2
|
+
import { ObjectReference } from "./ObjectReference";
|
|
3
|
+
import { SaveObject } from "./SaveObject";
|
|
4
|
+
export const isSaveEntity = (obj) => {
|
|
8
5
|
return obj.type === 'SaveEntity';
|
|
9
6
|
};
|
|
10
|
-
|
|
11
|
-
class SaveEntity extends SaveObject_1.SaveObject {
|
|
7
|
+
class SaveEntity extends SaveObject {
|
|
12
8
|
constructor(typePath, rootObject, instanceName, parentEntityName = '', needsTransform = false) {
|
|
13
9
|
super(typePath, rootObject, instanceName);
|
|
14
10
|
this.typePath = typePath;
|
|
@@ -28,9 +24,9 @@ class SaveEntity extends SaveObject_1.SaveObject {
|
|
|
28
24
|
this.components = [];
|
|
29
25
|
}
|
|
30
26
|
static ParseHeader(reader, obj) {
|
|
31
|
-
|
|
27
|
+
SaveObject.ParseHeader(reader, obj);
|
|
32
28
|
obj.needTransform = reader.readInt32() == 1;
|
|
33
|
-
obj.transform =
|
|
29
|
+
obj.transform = ParseTransform(reader);
|
|
34
30
|
obj.wasPlacedInLevel = reader.readInt32() == 1;
|
|
35
31
|
}
|
|
36
32
|
static ParseData(entity, length, reader, buildVersion, typePath) {
|
|
@@ -39,16 +35,16 @@ class SaveEntity extends SaveObject_1.SaveObject {
|
|
|
39
35
|
entity.parentObjectName = reader.readString();
|
|
40
36
|
var componentCount = reader.readInt32();
|
|
41
37
|
for (let i = 0; i < componentCount; i++) {
|
|
42
|
-
var componentRef =
|
|
38
|
+
var componentRef = ObjectReference.read(reader);
|
|
43
39
|
entity.components.push(componentRef);
|
|
44
40
|
}
|
|
45
41
|
const remainingSize = length - (reader.getBufferPosition() - afterSizeIndicator);
|
|
46
|
-
return
|
|
42
|
+
return SaveObject.ParseData(entity, remainingSize, reader, buildVersion, typePath);
|
|
47
43
|
}
|
|
48
44
|
static SerializeHeader(writer, entity) {
|
|
49
|
-
|
|
45
|
+
SaveObject.SerializeHeader(writer, entity);
|
|
50
46
|
writer.writeInt32(entity.needTransform ? 1 : 0);
|
|
51
|
-
|
|
47
|
+
SerializeTransform(writer, entity.transform);
|
|
52
48
|
writer.writeInt32(entity.wasPlacedInLevel ? 1 : 0);
|
|
53
49
|
}
|
|
54
50
|
static SerializeData(writer, entity, buildVersion) {
|
|
@@ -59,8 +55,8 @@ class SaveEntity extends SaveObject_1.SaveObject {
|
|
|
59
55
|
writer.writeString(com.levelName);
|
|
60
56
|
writer.writeString(com.pathName);
|
|
61
57
|
}
|
|
62
|
-
|
|
58
|
+
SaveObject.SerializeData(writer, entity, buildVersion);
|
|
63
59
|
}
|
|
64
60
|
}
|
|
65
61
|
SaveEntity.TypeID = 1;
|
|
66
|
-
|
|
62
|
+
export { SaveEntity };
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.SaveObject = void 0;
|
|
4
|
-
const DataFields_1 = require("./DataFields");
|
|
5
|
-
class SaveObject {
|
|
1
|
+
import { DataFields } from "./DataFields";
|
|
2
|
+
export class SaveObject {
|
|
6
3
|
constructor(typePath, rootObject, instanceName) {
|
|
7
4
|
this.typePath = typePath;
|
|
8
5
|
this.rootObject = rootObject;
|
|
@@ -24,10 +21,9 @@ class SaveObject {
|
|
|
24
21
|
writer.writeString(obj.instanceName);
|
|
25
22
|
}
|
|
26
23
|
static ParseData(obj, length, reader, buildVersion, typePath) {
|
|
27
|
-
|
|
24
|
+
DataFields.ParseProperties(obj, length, reader, buildVersion, typePath);
|
|
28
25
|
}
|
|
29
26
|
static SerializeData(writer, obj, buildVersion) {
|
|
30
|
-
|
|
27
|
+
DataFields.Serialize(obj, writer, buildVersion, obj.typePath);
|
|
31
28
|
}
|
|
32
29
|
}
|
|
33
|
-
exports.SaveObject = SaveObject;
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.GUID = void 0;
|
|
4
|
-
var GUID;
|
|
1
|
+
export var GUID;
|
|
5
2
|
(function (GUID) {
|
|
6
3
|
GUID.read = (reader) => {
|
|
7
4
|
return [
|
|
@@ -17,5 +14,5 @@ var GUID;
|
|
|
17
14
|
writer.writeUint32(guid[2]);
|
|
18
15
|
writer.writeUint32(guid[3]);
|
|
19
16
|
};
|
|
20
|
-
})(GUID
|
|
17
|
+
})(GUID || (GUID = {}));
|
|
21
18
|
;
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.MD5Hash = void 0;
|
|
4
|
-
var MD5Hash;
|
|
1
|
+
export var MD5Hash;
|
|
5
2
|
(function (MD5Hash) {
|
|
6
3
|
MD5Hash.read = (reader) => {
|
|
7
4
|
const md5Hash = { isValid: false };
|
|
@@ -17,5 +14,5 @@ var MD5Hash;
|
|
|
17
14
|
writer.writeBytesArray(md5Hash.hash);
|
|
18
15
|
}
|
|
19
16
|
};
|
|
20
|
-
})(MD5Hash
|
|
17
|
+
})(MD5Hash || (MD5Hash = {}));
|
|
21
18
|
;
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const SaveEntity_1 = require("../objects/SaveEntity");
|
|
6
|
-
const level_class_1 = require("./level.class");
|
|
7
|
-
class AsynchronousLevel {
|
|
1
|
+
import { isSaveComponent, SaveComponent } from "../objects/SaveComponent";
|
|
2
|
+
import { isSaveEntity, SaveEntity } from "../objects/SaveEntity";
|
|
3
|
+
import { Level } from "./level.class";
|
|
4
|
+
export class AsynchronousLevel {
|
|
8
5
|
static async StreamReadObjectContents(reader, objectsList, buildVersion, writer, onProgressCallback) {
|
|
9
6
|
const binarySize = reader.readInt32();
|
|
10
7
|
const posBefore = reader.getBufferPosition();
|
|
@@ -27,11 +24,11 @@ class AsynchronousLevel {
|
|
|
27
24
|
await reader.allocate(Math.max(before - binarySize, 300 * 1000 * 1000));
|
|
28
25
|
}
|
|
29
26
|
const obj = objectsList[i];
|
|
30
|
-
if (
|
|
31
|
-
|
|
27
|
+
if (isSaveEntity(obj)) {
|
|
28
|
+
SaveEntity.ParseData(obj, len, reader, buildVersion, obj.typePath);
|
|
32
29
|
}
|
|
33
|
-
else if (
|
|
34
|
-
|
|
30
|
+
else if (isSaveComponent(obj)) {
|
|
31
|
+
SaveComponent.ParseData(obj, len, reader, buildVersion, obj.typePath);
|
|
35
32
|
}
|
|
36
33
|
dynamicObjectBatch.push(obj);
|
|
37
34
|
const after = reader.getBufferPosition();
|
|
@@ -46,21 +43,20 @@ class AsynchronousLevel {
|
|
|
46
43
|
}
|
|
47
44
|
}
|
|
48
45
|
static async StreamReadLevel(reader, levelName, buildVersion, writer) {
|
|
49
|
-
const level = new
|
|
46
|
+
const level = new Level(levelName);
|
|
50
47
|
const binaryLength = reader.readInt32();
|
|
51
48
|
await reader.allocate(binaryLength);
|
|
52
49
|
await writer.openLevel(levelName);
|
|
53
|
-
|
|
50
|
+
Level.ReadObjectHeaders(reader, level.objects, reader.onProgressCallback);
|
|
54
51
|
reader.onProgressCallback(reader.getBufferProgress());
|
|
55
|
-
level.collectables =
|
|
52
|
+
level.collectables = Level.ReadCollectablesList(reader, undefined);
|
|
56
53
|
console.log(`before object contents buffer pos ${reader.getBufferPosition()}`);
|
|
57
54
|
await AsynchronousLevel.StreamReadObjectContents(reader, level.objects, buildVersion, writer, reader.onProgressCallback);
|
|
58
55
|
await writer.switchInLevelToCollectables();
|
|
59
56
|
await writer.writeCollectables(...level.collectables);
|
|
60
57
|
reader.onProgressCallback(reader.getBufferProgress());
|
|
61
|
-
|
|
58
|
+
Level.ReadCollectablesList(reader, undefined);
|
|
62
59
|
await writer.endLevel();
|
|
63
60
|
return level;
|
|
64
61
|
}
|
|
65
62
|
}
|
|
66
|
-
exports.AsynchronousLevel = AsynchronousLevel;
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const SaveComponent_1 = require("../objects/SaveComponent");
|
|
6
|
-
const SaveEntity_1 = require("../objects/SaveEntity");
|
|
7
|
-
class Level {
|
|
1
|
+
import { ObjectReference } from "../objects/ObjectReference";
|
|
2
|
+
import { SaveComponent, isSaveComponent } from "../objects/SaveComponent";
|
|
3
|
+
import { SaveEntity, isSaveEntity } from "../objects/SaveEntity";
|
|
4
|
+
export class Level {
|
|
8
5
|
constructor(name) {
|
|
9
6
|
this.name = name;
|
|
10
7
|
this.objects = [];
|
|
@@ -16,12 +13,12 @@ class Level {
|
|
|
16
13
|
for (const obj of objects) {
|
|
17
14
|
switch (obj.type) {
|
|
18
15
|
case 'SaveEntity':
|
|
19
|
-
writer.writeInt32(
|
|
20
|
-
|
|
16
|
+
writer.writeInt32(SaveEntity.TypeID);
|
|
17
|
+
SaveEntity.SerializeHeader(writer, obj);
|
|
21
18
|
break;
|
|
22
19
|
case 'SaveComponent':
|
|
23
|
-
writer.writeInt32(
|
|
24
|
-
|
|
20
|
+
writer.writeInt32(SaveComponent.TypeID);
|
|
21
|
+
SaveComponent.SerializeHeader(writer, obj);
|
|
25
22
|
break;
|
|
26
23
|
default:
|
|
27
24
|
console.log('Unknown object type', obj);
|
|
@@ -49,11 +46,11 @@ class Level {
|
|
|
49
46
|
writer.writeInt32(obj.unknownType2);
|
|
50
47
|
const lenReplacementPosition = writer.getBufferPosition();
|
|
51
48
|
writer.writeInt32(0);
|
|
52
|
-
if (
|
|
53
|
-
|
|
49
|
+
if (isSaveEntity(obj)) {
|
|
50
|
+
SaveEntity.SerializeData(writer, obj, buildVersion);
|
|
54
51
|
}
|
|
55
|
-
else if (
|
|
56
|
-
|
|
52
|
+
else if (isSaveComponent(obj)) {
|
|
53
|
+
SaveComponent.SerializeData(writer, obj, buildVersion);
|
|
57
54
|
}
|
|
58
55
|
writer.writeBinarySizeFromPosition(lenReplacementPosition, lenReplacementPosition + 4);
|
|
59
56
|
}
|
|
@@ -67,14 +64,14 @@ class Level {
|
|
|
67
64
|
}
|
|
68
65
|
let objectType = reader.readInt32();
|
|
69
66
|
switch (objectType) {
|
|
70
|
-
case
|
|
71
|
-
let object = new
|
|
72
|
-
|
|
67
|
+
case SaveEntity.TypeID:
|
|
68
|
+
let object = new SaveEntity('', '', '', '');
|
|
69
|
+
SaveEntity.ParseHeader(reader, object);
|
|
73
70
|
objectsList.push(object);
|
|
74
71
|
break;
|
|
75
|
-
case
|
|
76
|
-
let component = new
|
|
77
|
-
|
|
72
|
+
case SaveComponent.TypeID:
|
|
73
|
+
let component = new SaveComponent('', '', '', '');
|
|
74
|
+
SaveComponent.ParseHeader(reader, component);
|
|
78
75
|
objectsList.push(component);
|
|
79
76
|
break;
|
|
80
77
|
default:
|
|
@@ -89,19 +86,19 @@ class Level {
|
|
|
89
86
|
throw new Error(`possibly corrupt. entity content count ${countEntities} does not equal object count of ${objectsList.length}`);
|
|
90
87
|
}
|
|
91
88
|
for (let i = 0; i < countEntities; i++) {
|
|
92
|
-
if (i %
|
|
93
|
-
onProgressCallback(reader.getBufferProgress());
|
|
89
|
+
if (countEntities >= 10000 && i % 10000 === 0) {
|
|
90
|
+
onProgressCallback(reader.getBufferProgress(), `read object count [${(i + 1)}/${(countEntities + 1)}] in level ${levelName}`);
|
|
94
91
|
}
|
|
95
92
|
const obj = objectsList[i];
|
|
96
93
|
obj.saveOrBlueprintIndicator = reader.readInt32();
|
|
97
94
|
obj.unknownType2 = reader.readInt32();
|
|
98
95
|
const binarySize = reader.readInt32();
|
|
99
96
|
const before = reader.getBufferPosition();
|
|
100
|
-
if (
|
|
101
|
-
|
|
97
|
+
if (isSaveEntity(obj)) {
|
|
98
|
+
SaveEntity.ParseData(obj, binarySize, reader, buildVersion, obj.typePath);
|
|
102
99
|
}
|
|
103
|
-
else if (
|
|
104
|
-
|
|
100
|
+
else if (isSaveComponent(obj)) {
|
|
101
|
+
SaveComponent.ParseData(obj, binarySize, reader, buildVersion, obj.typePath);
|
|
105
102
|
}
|
|
106
103
|
const after = reader.getBufferPosition();
|
|
107
104
|
if (after - before !== binarySize) {
|
|
@@ -141,7 +138,7 @@ class Level {
|
|
|
141
138
|
static SerializeCollectablesList(writer, collectables) {
|
|
142
139
|
writer.writeInt32(collectables.length);
|
|
143
140
|
for (const collectable of collectables) {
|
|
144
|
-
|
|
141
|
+
ObjectReference.write(writer, collectable);
|
|
145
142
|
}
|
|
146
143
|
}
|
|
147
144
|
static ReadCollectablesList(reader, printSmthWhenItsCollectables) {
|
|
@@ -149,7 +146,7 @@ class Level {
|
|
|
149
146
|
let countSmthing = reader.readInt32();
|
|
150
147
|
if (countSmthing > 0) {
|
|
151
148
|
for (let i = 0; i < countSmthing; i++) {
|
|
152
|
-
const collectable =
|
|
149
|
+
const collectable = ObjectReference.read(reader);
|
|
153
150
|
collected.push(collectable);
|
|
154
151
|
}
|
|
155
152
|
if (process.env.NODE_ENV === 'debug' && countSmthing > 0) {
|
|
@@ -159,4 +156,3 @@ class Level {
|
|
|
159
156
|
return collected;
|
|
160
157
|
}
|
|
161
158
|
}
|
|
162
|
-
exports.Level = Level;
|
|
@@ -4,11 +4,12 @@ import { Level } from "./level.class";
|
|
|
4
4
|
import { ByteArray4, Grids } from "./save-reader";
|
|
5
5
|
import { SatisfactorySaveHeader } from "./save.types";
|
|
6
6
|
export declare class SatisfactorySave {
|
|
7
|
+
name: string;
|
|
7
8
|
header: SatisfactorySaveHeader;
|
|
8
9
|
gridHash: ByteArray4;
|
|
9
10
|
grids: Grids;
|
|
10
11
|
levels: Level[];
|
|
11
12
|
trailingCollectedObjects: ObjectReference[];
|
|
12
13
|
compressionInfo?: ChunkCompressionInfo;
|
|
13
|
-
constructor(header: SatisfactorySaveHeader);
|
|
14
|
+
constructor(name: string, header: SatisfactorySaveHeader);
|
|
14
15
|
}
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.SatisfactorySave = void 0;
|
|
4
|
-
class SatisfactorySave {
|
|
5
|
-
constructor(header) {
|
|
1
|
+
export class SatisfactorySave {
|
|
2
|
+
constructor(name, header) {
|
|
6
3
|
this.gridHash = [0, 0, 0, 0];
|
|
7
4
|
this.grids = {};
|
|
8
5
|
this.levels = [];
|
|
9
6
|
this.trailingCollectedObjects = [];
|
|
7
|
+
this.name = name;
|
|
10
8
|
this.header = header;
|
|
11
9
|
}
|
|
12
10
|
}
|
|
13
|
-
exports.SatisfactorySave = SatisfactorySave;
|
|
@@ -1,27 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
const parser_error_1 = require("../../error/parser.error");
|
|
11
|
-
const MD5Hash_1 = require("../objects/ue/MD5Hash");
|
|
12
|
-
const asynchronous_level_class_1 = require("./asynchronous-level.class");
|
|
13
|
-
const level_class_1 = require("./level.class");
|
|
14
|
-
exports.DEFAULT_SATISFACTORY_CHUNK_HEADER_SIZE = 49;
|
|
15
|
-
class SaveReader extends byte_reader_class_1.ByteReader {
|
|
1
|
+
import Pako from "pako";
|
|
2
|
+
import { Alignment } from "../../byte/alignment.enum";
|
|
3
|
+
import { ByteReader } from "../../byte/byte-reader.class";
|
|
4
|
+
import { CompressionLibraryError, CorruptSaveError, ParserError, UnsupportedVersionError } from "../../error/parser.error";
|
|
5
|
+
import { MD5Hash } from '../objects/ue/MD5Hash';
|
|
6
|
+
import { AsynchronousLevel } from "./asynchronous-level.class";
|
|
7
|
+
import { Level } from "./level.class";
|
|
8
|
+
export const DEFAULT_SATISFACTORY_CHUNK_HEADER_SIZE = 49;
|
|
9
|
+
class SaveReader extends ByteReader {
|
|
16
10
|
constructor(fileBuffer, onProgressCallback = () => { }) {
|
|
17
|
-
super(fileBuffer,
|
|
11
|
+
super(fileBuffer, Alignment.LITTLE_ENDIAN);
|
|
18
12
|
this.onProgressCallback = onProgressCallback;
|
|
19
13
|
this.levels = [];
|
|
20
14
|
this.trailingCollectedObjects = [];
|
|
21
15
|
this.compressionInfo = {
|
|
22
16
|
packageFileTag: 0,
|
|
23
17
|
maxUncompressedChunkContentSize: 0,
|
|
24
|
-
chunkHeaderSize:
|
|
18
|
+
chunkHeaderSize: DEFAULT_SATISFACTORY_CHUNK_HEADER_SIZE
|
|
25
19
|
};
|
|
26
20
|
this.readSaveBodyHash = () => {
|
|
27
21
|
const unk = this.readInt32();
|
|
@@ -98,7 +92,7 @@ class SaveReader extends byte_reader_class_1.ByteReader {
|
|
|
98
92
|
this.header.partitionEnabledFlag = this.readInt32() === 1;
|
|
99
93
|
}
|
|
100
94
|
if (this.header.saveHeaderType >= 12) {
|
|
101
|
-
this.header.consistencyHashBytes =
|
|
95
|
+
this.header.consistencyHashBytes = MD5Hash.read(this);
|
|
102
96
|
}
|
|
103
97
|
if (this.header.saveHeaderType >= 13) {
|
|
104
98
|
this.header.creativeModeEnabled = this.readInt32() == 1;
|
|
@@ -106,7 +100,7 @@ class SaveReader extends byte_reader_class_1.ByteReader {
|
|
|
106
100
|
if (this.header.saveVersion >= 21) {
|
|
107
101
|
}
|
|
108
102
|
else {
|
|
109
|
-
throw new
|
|
103
|
+
throw new UnsupportedVersionError("The save version is too old to support encoding currently. Save in newer game version.");
|
|
110
104
|
}
|
|
111
105
|
return this.header;
|
|
112
106
|
}
|
|
@@ -122,13 +116,13 @@ class SaveReader extends byte_reader_class_1.ByteReader {
|
|
|
122
116
|
this.currentByte = this.compressionInfo.chunkHeaderSize;
|
|
123
117
|
this.handledByte += this.compressionInfo.chunkHeaderSize;
|
|
124
118
|
if (this.compressionInfo.packageFileTag <= 0) {
|
|
125
|
-
this.compressionInfo.packageFileTag = chunkHeader.getUint32(0, this.alignment ===
|
|
119
|
+
this.compressionInfo.packageFileTag = chunkHeader.getUint32(0, this.alignment === Alignment.LITTLE_ENDIAN);
|
|
126
120
|
}
|
|
127
121
|
if (this.compressionInfo.maxUncompressedChunkContentSize <= 0) {
|
|
128
|
-
this.compressionInfo.maxUncompressedChunkContentSize = chunkHeader.getInt32(8, this.alignment ===
|
|
122
|
+
this.compressionInfo.maxUncompressedChunkContentSize = chunkHeader.getInt32(8, this.alignment === Alignment.LITTLE_ENDIAN);
|
|
129
123
|
}
|
|
130
|
-
const chunkCompressedLength = chunkHeader.getInt32(33, this.alignment ===
|
|
131
|
-
const chunkUncompressedLength = chunkHeader.getInt32(25, this.alignment ===
|
|
124
|
+
const chunkCompressedLength = chunkHeader.getInt32(33, this.alignment === Alignment.LITTLE_ENDIAN);
|
|
125
|
+
const chunkUncompressedLength = chunkHeader.getInt32(25, this.alignment === Alignment.LITTLE_ENDIAN);
|
|
132
126
|
totalUncompressedBodySize += chunkUncompressedLength;
|
|
133
127
|
const currentChunkSize = chunkCompressedLength;
|
|
134
128
|
let currentChunk = this.fileBuffer.slice(this.currentByte, this.currentByte + currentChunkSize);
|
|
@@ -138,11 +132,11 @@ class SaveReader extends byte_reader_class_1.ByteReader {
|
|
|
138
132
|
this.currentByte = 0;
|
|
139
133
|
try {
|
|
140
134
|
let currentInflatedChunk = null;
|
|
141
|
-
currentInflatedChunk =
|
|
135
|
+
currentInflatedChunk = Pako.inflate(currentChunk);
|
|
142
136
|
currentChunks.push(currentInflatedChunk);
|
|
143
137
|
}
|
|
144
138
|
catch (err) {
|
|
145
|
-
throw new
|
|
139
|
+
throw new CompressionLibraryError("Failed to inflate compressed save data. " + err);
|
|
146
140
|
}
|
|
147
141
|
}
|
|
148
142
|
let newChunkLength = currentChunks.map(cc => cc.length).reduce((prev, cur) => prev + cur);
|
|
@@ -157,7 +151,7 @@ class SaveReader extends byte_reader_class_1.ByteReader {
|
|
|
157
151
|
this.bufferView = new DataView(bigWholeChunk.buffer);
|
|
158
152
|
const dataLength = this.readInt32();
|
|
159
153
|
if (totalUncompressedBodySize !== dataLength + 8) {
|
|
160
|
-
throw new
|
|
154
|
+
throw new CorruptSaveError(`Possibly corrupt. Indicated size of total save body (${dataLength + 8}) does not match the uncompressed real size of ${totalUncompressedBodySize}.`);
|
|
161
155
|
}
|
|
162
156
|
return {
|
|
163
157
|
concatenatedChunkLength: newChunkLength,
|
|
@@ -166,23 +160,26 @@ class SaveReader extends byte_reader_class_1.ByteReader {
|
|
|
166
160
|
}
|
|
167
161
|
readLevels() {
|
|
168
162
|
if (!this.header) {
|
|
169
|
-
throw new
|
|
163
|
+
throw new ParserError('ParserError', 'Header must be set before objects can be read.');
|
|
170
164
|
}
|
|
171
165
|
if (this.header.saveVersion < 29) {
|
|
172
|
-
throw new
|
|
166
|
+
throw new UnsupportedVersionError('Game Version < U6 is not supported.');
|
|
173
167
|
}
|
|
174
168
|
if (this.header.saveHeaderType < 13) {
|
|
175
|
-
throw new
|
|
169
|
+
throw new UnsupportedVersionError('Game Version < U8 is not supported in this package version. Consider downgrading to the latest package version supporting it, which is 0.0.34');
|
|
176
170
|
}
|
|
177
171
|
const levels = [];
|
|
178
172
|
const levelCount = this.readInt32();
|
|
179
173
|
this.onProgressCallback(this.getBufferProgress(), `reading pack of ${levelCount} levels.`);
|
|
180
174
|
for (let i = 0; i < levelCount; i++) {
|
|
181
175
|
let levelSingleName = this.readString();
|
|
182
|
-
|
|
176
|
+
if (i % 500 === 0) {
|
|
177
|
+
this.onProgressCallback(this.getBufferProgress(), `reading level [${(i + 1)}/${(levelCount + 1)}] ${levelSingleName}`);
|
|
178
|
+
}
|
|
179
|
+
levels.push(Level.ReadLevel(this, levelSingleName, this.header.buildVersion));
|
|
183
180
|
}
|
|
184
|
-
levels.push(
|
|
185
|
-
const trailingStuffToIgnore =
|
|
181
|
+
levels.push(Level.ReadLevel(this, this.header.mapName, this.header.buildVersion));
|
|
182
|
+
const trailingStuffToIgnore = Level.ReadCollectablesList(this, 'collectables 6!');
|
|
186
183
|
this.onProgressCallback(this.getBufferProgress(), 'finished parsing.');
|
|
187
184
|
return levels;
|
|
188
185
|
}
|
|
@@ -193,7 +190,7 @@ class SaveReader extends byte_reader_class_1.ByteReader {
|
|
|
193
190
|
for (let j = 0; j <= numSubLevels; j++) {
|
|
194
191
|
let levelName = (j === numSubLevels) ? '' + this.header.mapName : this.readString();
|
|
195
192
|
this.onProgressCallback(this.getBufferProgress(), `reading level [${(j + 1)}/${(numSubLevels + 1)}] ${levelName}`);
|
|
196
|
-
this.levels[j] = await
|
|
193
|
+
this.levels[j] = await AsynchronousLevel.StreamReadLevel(this, levelName, this.header.buildVersion, writer);
|
|
197
194
|
}
|
|
198
195
|
await writer.endLevels();
|
|
199
196
|
return this.levels;
|
|
@@ -211,4 +208,4 @@ SaveReader.getRoughSaveVersion = (saveVersion, headerTypeVersion) => {
|
|
|
211
208
|
return '<U6';
|
|
212
209
|
}
|
|
213
210
|
};
|
|
214
|
-
|
|
211
|
+
export { SaveReader };
|