@etothepii/satisfactory-file-parser 0.0.15 → 0.0.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 +49 -11
- package/build/index.d.ts +10 -8
- package/build/index.js +10 -12
- package/build/parser/byte/byte-reader.class.d.ts +1 -38
- package/build/parser/byte/byte-reader.class.js +0 -11
- package/build/parser/byte/byte-writer.class.d.ts +1 -38
- package/build/parser/byte/byte-writer.class.js +0 -10
- package/build/parser/file.types.d.ts +9 -0
- package/build/parser/file.types.js +2 -0
- package/build/parser/parser.d.ts +12 -40
- package/build/parser/parser.js +51 -47
- package/build/parser/satisfactory/blueprint/blueprint-reader.d.ts +18 -0
- package/build/parser/satisfactory/blueprint/blueprint-reader.js +124 -0
- package/build/parser/satisfactory/blueprint/blueprint-writer.d.ts +15 -0
- package/build/parser/satisfactory/blueprint/blueprint-writer.js +63 -0
- package/build/parser/satisfactory/blueprint/blueprint.types.d.ts +20 -0
- package/build/parser/satisfactory/blueprint/blueprint.types.js +2 -0
- package/build/parser/satisfactory/objects/DataFields.d.ts +1 -1
- package/build/parser/satisfactory/objects/DataFields.js +0 -25
- package/build/parser/satisfactory/objects/Property.d.ts +1 -1
- package/build/parser/satisfactory/objects/Property.js +10 -159
- package/build/parser/satisfactory/save/level.class.d.ts +21 -0
- package/build/parser/satisfactory/save/level.class.js +138 -0
- package/build/parser/satisfactory/save/satisfactory-save.d.ts +11 -0
- package/build/parser/satisfactory/save/satisfactory-save.js +11 -0
- package/build/parser/satisfactory/save/save-reader.d.ts +44 -0
- package/build/parser/satisfactory/save/save-reader.js +233 -0
- package/build/parser/satisfactory/save/save-writer.d.ts +12 -0
- package/build/parser/satisfactory/save/save-writer.js +112 -0
- package/build/parser/satisfactory/save/save.types.d.ts +49 -0
- package/build/parser/satisfactory/save/save.types.js +2 -0
- package/package.json +6 -2
|
@@ -12,7 +12,6 @@ class AbstractProperty {
|
|
|
12
12
|
}
|
|
13
13
|
exports.AbstractProperty = AbstractProperty;
|
|
14
14
|
class AbstractBaseProperty extends AbstractProperty {
|
|
15
|
-
// overhead like Guid is not calculated into property size
|
|
16
15
|
constructor(type, ueType, index) {
|
|
17
16
|
super(type, index && index !== 0 ? index : undefined);
|
|
18
17
|
this.ueType = ueType;
|
|
@@ -32,7 +31,7 @@ const ParseGUID = (reader) => {
|
|
|
32
31
|
let guid;
|
|
33
32
|
if (hasGuid) {
|
|
34
33
|
throw new Error('Unexpected!');
|
|
35
|
-
guid = reader.readBytes(16);
|
|
34
|
+
guid = reader.readBytes(16);
|
|
36
35
|
}
|
|
37
36
|
return guid;
|
|
38
37
|
};
|
|
@@ -378,7 +377,6 @@ class TextProperty extends BasicProperty {
|
|
|
378
377
|
this.value = value;
|
|
379
378
|
}
|
|
380
379
|
static Parse(reader, ueType, index = 0) {
|
|
381
|
-
//let name = reader.readString();
|
|
382
380
|
const guidInfo = (0, exports.ParseGUID)(reader);
|
|
383
381
|
const value = TextProperty.ParseValue(reader);
|
|
384
382
|
return new TextProperty(value, ueType, guidInfo, index);
|
|
@@ -389,15 +387,12 @@ class TextProperty extends BasicProperty {
|
|
|
389
387
|
historyType: reader.readByte()
|
|
390
388
|
};
|
|
391
389
|
switch (prop.historyType) {
|
|
392
|
-
// HISTORYTYPE_BASE
|
|
393
390
|
case 0:
|
|
394
391
|
prop.namespace = reader.readString();
|
|
395
392
|
prop.key = reader.readString();
|
|
396
393
|
prop.value = reader.readString();
|
|
397
394
|
break;
|
|
398
|
-
// HISTORYTYPE_NAMEDFORMAT
|
|
399
395
|
case 1:
|
|
400
|
-
// HISTORYTYPE_ARGUMENTFORMAT
|
|
401
396
|
case 3:
|
|
402
397
|
prop.sourceFmt = TextProperty.ParseValue(reader);
|
|
403
398
|
const argumentsCount = reader.readInt32();
|
|
@@ -416,22 +411,15 @@ class TextProperty extends BasicProperty {
|
|
|
416
411
|
prop.arguments.push(currentArgumentsData);
|
|
417
412
|
}
|
|
418
413
|
break;
|
|
419
|
-
// see https://github.com/EpicGames/UnrealEngine/blob/4.25/Engine/Source/Runtime/Core/Private/Internationalization/TextHistory.cpp#L2268
|
|
420
|
-
// HISTORYTYPE_TRANSFORM
|
|
421
414
|
case 10:
|
|
422
415
|
prop.sourceText = TextProperty.ParseValue(reader);
|
|
423
416
|
prop.transformType = reader.readByte();
|
|
424
417
|
break;
|
|
425
|
-
// HISTORYTYPE_NONE
|
|
426
418
|
case 255:
|
|
427
|
-
// See: https://github.com/EpicGames/UnrealEngine/blob/4.25/Engine/Source/Runtime/Core/Private/Internationalization/Text.cpp#L894
|
|
428
|
-
// TODO: do i need that? check with goz3rr
|
|
429
|
-
//if (this.header!.buildVersion >= 140822) {
|
|
430
419
|
prop.hasCultureInvariantString = reader.readInt32() === 1;
|
|
431
420
|
if (prop.hasCultureInvariantString) {
|
|
432
421
|
prop.value = reader.readString();
|
|
433
422
|
}
|
|
434
|
-
//}
|
|
435
423
|
break;
|
|
436
424
|
default:
|
|
437
425
|
throw new Error('Unimplemented historyType `' + prop.historyType);
|
|
@@ -449,15 +437,12 @@ class TextProperty extends BasicProperty {
|
|
|
449
437
|
writer.writeInt32(value.flags);
|
|
450
438
|
writer.writeByte(value.historyType);
|
|
451
439
|
switch (value.historyType) {
|
|
452
|
-
// HISTORYTYPE_BASE
|
|
453
440
|
case 0:
|
|
454
441
|
writer.writeString(value.namespace);
|
|
455
442
|
writer.writeString(value.key);
|
|
456
443
|
writer.writeString(value.value);
|
|
457
444
|
break;
|
|
458
|
-
// HISTORYTYPE_NAMEDFORMAT
|
|
459
445
|
case 1:
|
|
460
|
-
// HISTORYTYPE_ARGUMENTFORMAT
|
|
461
446
|
case 3:
|
|
462
447
|
TextProperty.SerializeValue(writer, value.sourceFmt);
|
|
463
448
|
writer.writeInt32(value.arguments.length);
|
|
@@ -474,22 +459,15 @@ class TextProperty extends BasicProperty {
|
|
|
474
459
|
}
|
|
475
460
|
}
|
|
476
461
|
break;
|
|
477
|
-
// see https://github.com/EpicGames/UnrealEngine/blob/4.25/Engine/Source/Runtime/Core/Private/Internationalization/TextHistory.cpp#L2268
|
|
478
|
-
// HISTORYTYPE_TRANSFORM
|
|
479
462
|
case 10:
|
|
480
463
|
TextProperty.SerializeValue(writer, value.sourceText);
|
|
481
464
|
writer.writeByte(value.transformType);
|
|
482
465
|
break;
|
|
483
|
-
// HISTORYTYPE_NONE
|
|
484
466
|
case 255:
|
|
485
|
-
// See: https://github.com/EpicGames/UnrealEngine/blob/4.25/Engine/Source/Runtime/Core/Private/Internationalization/Text.cpp#L894
|
|
486
|
-
// TODO: do i need that? check with goz3rr
|
|
487
|
-
//if (this.header!.buildVersion >= 140822) {
|
|
488
467
|
writer.writeInt32(value.hasCultureInvariantString ? 1 : 0);
|
|
489
468
|
if (value.hasCultureInvariantString) {
|
|
490
469
|
writer.writeString(value.value);
|
|
491
470
|
}
|
|
492
|
-
//}
|
|
493
471
|
break;
|
|
494
472
|
default:
|
|
495
473
|
throw new Error('Unimplemented historyType `' + value.historyType);
|
|
@@ -578,7 +556,6 @@ class StructProperty extends AbstractBaseProperty {
|
|
|
578
556
|
unk3: reader.readString(),
|
|
579
557
|
properties: [],
|
|
580
558
|
};
|
|
581
|
-
//TODO - what is this? currentProperty.value.properties.push(reader.readProperty());
|
|
582
559
|
break;
|
|
583
560
|
case 'FluidBox':
|
|
584
561
|
value = {
|
|
@@ -591,7 +568,6 @@ class StructProperty extends AbstractBaseProperty {
|
|
|
591
568
|
case 'DateTime':
|
|
592
569
|
value = reader.readLong().toString();
|
|
593
570
|
break;
|
|
594
|
-
// MODS
|
|
595
571
|
case 'FINNetworkTrace':
|
|
596
572
|
value = (0, exports.ReadFINNetworkTrace)(reader);
|
|
597
573
|
break;
|
|
@@ -600,14 +576,13 @@ class StructProperty extends AbstractBaseProperty {
|
|
|
600
576
|
values: (0, exports.ReadFINLuaProcessorStateStorage)(reader, size)
|
|
601
577
|
};
|
|
602
578
|
break;
|
|
603
|
-
case 'FICFrameRange':
|
|
579
|
+
case 'FICFrameRange':
|
|
604
580
|
value = {
|
|
605
581
|
begin: reader.readLong().toString(),
|
|
606
582
|
end: reader.readLong().toString(),
|
|
607
583
|
};
|
|
608
584
|
break;
|
|
609
585
|
default:
|
|
610
|
-
//TODO: use buildversion
|
|
611
586
|
value = (0, exports.ParseDynamicStructData)(reader, 0, subtype);
|
|
612
587
|
}
|
|
613
588
|
return value;
|
|
@@ -673,7 +648,6 @@ class StructProperty extends AbstractBaseProperty {
|
|
|
673
648
|
writer.writeString(value.itemName);
|
|
674
649
|
writer.writeString(value.unk2);
|
|
675
650
|
writer.writeString(value.unk3);
|
|
676
|
-
//TODO - how to write properties?
|
|
677
651
|
break;
|
|
678
652
|
case 'FluidBox':
|
|
679
653
|
value = value;
|
|
@@ -687,7 +661,6 @@ class StructProperty extends AbstractBaseProperty {
|
|
|
687
661
|
value = value;
|
|
688
662
|
writer.writeInt64(BigInt(value));
|
|
689
663
|
break;
|
|
690
|
-
// MODS
|
|
691
664
|
case 'FINNetworkTrace':
|
|
692
665
|
value = value;
|
|
693
666
|
(0, exports.SerializeFINNetworkTrace)(writer, value);
|
|
@@ -696,13 +669,12 @@ class StructProperty extends AbstractBaseProperty {
|
|
|
696
669
|
value = value;
|
|
697
670
|
(0, exports.SerializeFINLuaProcessorStateStorage)(writer, value.values);
|
|
698
671
|
break;
|
|
699
|
-
case 'FICFrameRange':
|
|
672
|
+
case 'FICFrameRange':
|
|
700
673
|
value = value;
|
|
701
674
|
writer.writeInt64(BigInt(value.begin));
|
|
702
675
|
writer.writeInt64(BigInt(value.end));
|
|
703
676
|
break;
|
|
704
677
|
default:
|
|
705
|
-
//TODO: use buildversion
|
|
706
678
|
value = value;
|
|
707
679
|
(0, exports.SerializeDynamicStructData)(writer, 0, value);
|
|
708
680
|
}
|
|
@@ -718,7 +690,7 @@ class ArrayProperty extends BasicProperty {
|
|
|
718
690
|
}
|
|
719
691
|
static Parse(reader, ueType, index, propertyName) {
|
|
720
692
|
const subtype = reader.readString();
|
|
721
|
-
reader.skipBytes();
|
|
693
|
+
reader.skipBytes();
|
|
722
694
|
let property;
|
|
723
695
|
const elementCount = reader.readInt32();
|
|
724
696
|
switch (subtype) {
|
|
@@ -754,10 +726,10 @@ class ArrayProperty extends BasicProperty {
|
|
|
754
726
|
property = new ArrayProperty(subtype, new Array(elementCount).fill(0).map(e => ObjectProperty.ReadValue(reader)), ueType, index);
|
|
755
727
|
break;
|
|
756
728
|
case "StructProperty":
|
|
757
|
-
const name = reader.readString();
|
|
758
|
-
const type = reader.readString();
|
|
759
|
-
const binarySize = reader.readInt32();
|
|
760
|
-
const allIndex = reader.readInt32();
|
|
729
|
+
const name = reader.readString();
|
|
730
|
+
const type = reader.readString();
|
|
731
|
+
const binarySize = reader.readInt32();
|
|
732
|
+
const allIndex = reader.readInt32();
|
|
761
733
|
const allStructType = reader.readString();
|
|
762
734
|
const allGuid = reader.readInt32();
|
|
763
735
|
const allUnk1 = reader.readInt32();
|
|
@@ -780,11 +752,6 @@ class ArrayProperty extends BasicProperty {
|
|
|
780
752
|
const before = reader.getBufferPosition();
|
|
781
753
|
const maArr = new Array(elementCount).fill(0).map(e => {
|
|
782
754
|
const struct = new StructProperty(allStructType, type, allIndex, allGuid);
|
|
783
|
-
// we do NOT assign individual unk's here. Since they are only serialized always on ArrayProperty's Level once for all elements.
|
|
784
|
-
//struct.unk1 = allUnk1;
|
|
785
|
-
//struct.unk2 = allUnk2;
|
|
786
|
-
//struct.unk3 = allUnk3;
|
|
787
|
-
//struct.unk4 = allUnk4;
|
|
788
755
|
struct.value = StructProperty.ParseValue(reader, allStructType, binarySize);
|
|
789
756
|
return struct;
|
|
790
757
|
});
|
|
@@ -792,7 +759,6 @@ class ArrayProperty extends BasicProperty {
|
|
|
792
759
|
if (readBytees !== binarySize) {
|
|
793
760
|
throw new Error('possibly corrupt in array of struct.');
|
|
794
761
|
}
|
|
795
|
-
// Array Properties with struct values have some more properties.
|
|
796
762
|
property = new ArrayProperty(subtype, maArr, ueType, index, innerStructValueFields);
|
|
797
763
|
break;
|
|
798
764
|
default:
|
|
@@ -871,8 +837,8 @@ class SetProperty extends BasicProperty {
|
|
|
871
837
|
}
|
|
872
838
|
static Parse(reader, ueType, index, propertyName) {
|
|
873
839
|
const subtype = reader.readString();
|
|
874
|
-
reader.skipBytes(1);
|
|
875
|
-
reader.skipBytes(4);
|
|
840
|
+
reader.skipBytes(1);
|
|
841
|
+
reader.skipBytes(4);
|
|
876
842
|
const elementCount = reader.readInt32();
|
|
877
843
|
let property;
|
|
878
844
|
switch (subtype) {
|
|
@@ -900,7 +866,6 @@ class SetProperty extends BasicProperty {
|
|
|
900
866
|
}
|
|
901
867
|
static Serialize(writer, property) {
|
|
902
868
|
writer.writeString(property.subtype);
|
|
903
|
-
//TODO: what is that
|
|
904
869
|
writer.writeByte(0);
|
|
905
870
|
writer.writeInt32(0);
|
|
906
871
|
writer.writeInt32(property.values.length);
|
|
@@ -915,7 +880,6 @@ class SetProperty extends BasicProperty {
|
|
|
915
880
|
property.values.forEach(v => StrProperty.SerializeValue(writer, v));
|
|
916
881
|
break;
|
|
917
882
|
case "StructProperty":
|
|
918
|
-
//TODO: this would only work for mRemovalLocations. Get a way to check for propertyname at least.
|
|
919
883
|
property.values.forEach(v => (0, util_types_1.SerializeVec3)(writer, v));
|
|
920
884
|
break;
|
|
921
885
|
default:
|
|
@@ -940,119 +904,7 @@ class MapProperty extends BasicProperty {
|
|
|
940
904
|
const property = new MapProperty(reader.readString(), reader.readString(), ueType, index);
|
|
941
905
|
reader.skipBytes(1);
|
|
942
906
|
property.modeType = reader.readInt32();
|
|
943
|
-
//property.remainingData = reader.readBytes(size - (reader.getBufferPosition() - start));
|
|
944
907
|
property.remainingData = Array.from(reader.readBytes(size - 4));
|
|
945
|
-
// TODO
|
|
946
|
-
/*
|
|
947
|
-
|
|
948
|
-
if (property.modeType === 2) {
|
|
949
|
-
property.modeUnk2 = reader.readString();
|
|
950
|
-
property.modeUnk3 = reader.readString();
|
|
951
|
-
} else if (property.modeType === 3) {
|
|
952
|
-
property.modeUnk1 = reader.readHex(9);
|
|
953
|
-
property.modeUnk2 = reader.readString();
|
|
954
|
-
property.modeUnk3 = reader.readString();
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
let elementCount = reader.readInt32();
|
|
958
|
-
for (let i = 0; i < elementCount; i++) {
|
|
959
|
-
let key: number | string | ObjectReferenceV2 | vec3 | any[] | boolean;
|
|
960
|
-
let value: number | string | ObjectReferenceV2 | any[] | boolean;
|
|
961
|
-
|
|
962
|
-
switch (property.keyType) {
|
|
963
|
-
case 'IntProperty':
|
|
964
|
-
key = Int32Property.ReadValue(reader);
|
|
965
|
-
break;
|
|
966
|
-
case 'Int64Property':
|
|
967
|
-
key = Int64Property.ReadValue(reader);
|
|
968
|
-
break;
|
|
969
|
-
case 'NameProperty':
|
|
970
|
-
case 'StrProperty':
|
|
971
|
-
key = StrProperty.ReadValue(reader);
|
|
972
|
-
break;
|
|
973
|
-
case 'ObjectProperty':
|
|
974
|
-
key = ObjectProperty.ReadValue(reader);
|
|
975
|
-
break;
|
|
976
|
-
case 'EnumProperty':
|
|
977
|
-
key = EnumProperty.ReadValue(reader);
|
|
978
|
-
break;
|
|
979
|
-
case 'StructProperty':
|
|
980
|
-
if (propertyName === 'Destroyed_Foliage_Transform' || parentType === '/BuildGunUtilities/BGU_Subsystem.BGU_Subsystem_C') // Mod: Universal Destroyer/Factory Statistics
|
|
981
|
-
{
|
|
982
|
-
key = ParseVec3(reader);
|
|
983
|
-
break;
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
key = [];
|
|
987
|
-
while (true) {
|
|
988
|
-
let singleValueProperty = DataFieldsV2.ParseProperty(reader, buildVersion, propertyName);
|
|
989
|
-
if (singleValueProperty === null) {
|
|
990
|
-
break;
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
key.push(singleValueProperty);
|
|
994
|
-
}
|
|
995
|
-
break;
|
|
996
|
-
default:
|
|
997
|
-
throw new Error(`not implemented type ${property.keyType}`);
|
|
998
|
-
}
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
switch (property.valueType) {
|
|
1002
|
-
case 'ByteProperty':
|
|
1003
|
-
if (property.keyType === 'StrProperty') {
|
|
1004
|
-
value = reader.readString();
|
|
1005
|
-
}
|
|
1006
|
-
else {
|
|
1007
|
-
value = reader.readByte();
|
|
1008
|
-
}
|
|
1009
|
-
break;
|
|
1010
|
-
case 'BoolProperty':
|
|
1011
|
-
value = BoolProperty.ReadValue(reader);
|
|
1012
|
-
break;
|
|
1013
|
-
case 'IntProperty':
|
|
1014
|
-
value = Int32Property.ReadValue(reader);
|
|
1015
|
-
break;
|
|
1016
|
-
case 'FloatProperty':
|
|
1017
|
-
value = FloatProperty.ReadValue(reader);
|
|
1018
|
-
break;
|
|
1019
|
-
case 'StrProperty':
|
|
1020
|
-
value = StrProperty.ReadValue(reader);
|
|
1021
|
-
break;
|
|
1022
|
-
case 'ObjectProperty':
|
|
1023
|
-
value = ObjectProperty.ReadValue(reader);
|
|
1024
|
-
break;
|
|
1025
|
-
case 'StructProperty':
|
|
1026
|
-
// TODO: what is this
|
|
1027
|
-
/*
|
|
1028
|
-
if (parentType === 'LBBalancerData') {
|
|
1029
|
-
mapPropertySubProperties.mNormalIndex = this.readInt32();
|
|
1030
|
-
mapPropertySubProperties.mOverflowIndex = this.readInt32();
|
|
1031
|
-
mapPropertySubProperties.mFilterIndex = this.readInt32();
|
|
1032
|
-
}
|
|
1033
|
-
else { }
|
|
1034
|
-
*/
|
|
1035
|
-
/*
|
|
1036
|
-
|
|
1037
|
-
value = [];
|
|
1038
|
-
while (true) {
|
|
1039
|
-
let singleValueProperty = DataFieldsV2.ParseProperty(reader, buildVersion, propertyName);
|
|
1040
|
-
if (singleValueProperty === null) {
|
|
1041
|
-
break;
|
|
1042
|
-
}
|
|
1043
|
-
|
|
1044
|
-
value.push(singleValueProperty);
|
|
1045
|
-
}
|
|
1046
|
-
break;
|
|
1047
|
-
default:
|
|
1048
|
-
throw new Error(`not implemented type ${property.valueType}`);
|
|
1049
|
-
}
|
|
1050
|
-
|
|
1051
|
-
property.values.push({
|
|
1052
|
-
key, value
|
|
1053
|
-
});
|
|
1054
|
-
}
|
|
1055
|
-
*/
|
|
1056
908
|
return property;
|
|
1057
909
|
}
|
|
1058
910
|
static CalcOverhead(property) {
|
|
@@ -1064,7 +916,6 @@ property.values.push({
|
|
|
1064
916
|
writer.writeByte(0);
|
|
1065
917
|
writer.writeInt32(property.modeType);
|
|
1066
918
|
writer.writeBytesArray(property.remainingData);
|
|
1067
|
-
//TODO: do the actual serialization.
|
|
1068
919
|
}
|
|
1069
920
|
}
|
|
1070
921
|
exports.MapProperty = MapProperty;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ByteReader } from "../../byte/byte-reader.class";
|
|
2
|
+
import { ByteWriter } from "../../byte/byte-writer.class";
|
|
3
|
+
import { ObjectReference } from "../objects/ObjectReference";
|
|
4
|
+
import { SaveComponent } from "../objects/SaveComponent";
|
|
5
|
+
import { SaveEntity } from "../objects/SaveEntity";
|
|
6
|
+
import { SaveObject } from "../objects/SaveObject";
|
|
7
|
+
import { SaveReader } from "./save-reader";
|
|
8
|
+
export declare class Level {
|
|
9
|
+
name: string;
|
|
10
|
+
objects: (SaveEntity | SaveComponent)[];
|
|
11
|
+
collectables: ObjectReference[];
|
|
12
|
+
constructor(name: string);
|
|
13
|
+
static SerializeObjectHeaders(writer: ByteWriter, objects: (SaveEntity | SaveComponent)[]): void;
|
|
14
|
+
static WriteLevel(writer: ByteWriter, level: Level, buildVersion: number): void;
|
|
15
|
+
static SerializeObjectContents(writer: ByteWriter, objects: (SaveEntity | SaveComponent)[], buildVersion: number): void;
|
|
16
|
+
static ReadObjectHeaders(reader: ByteReader, objectsList: SaveObject[], onProgressCallback: (progress: number, msg?: string) => void): void;
|
|
17
|
+
static ReadObjectContents(reader: ByteReader, objectsList: SaveObject[], buildVersion: number, onProgressCallback: (progress: number, msg?: string) => void): void;
|
|
18
|
+
static ReadLevel(reader: SaveReader, levelName: string, buildVersion: number): Level;
|
|
19
|
+
static SerializeCollectablesList(writer: ByteWriter, collectables: ObjectReference[]): void;
|
|
20
|
+
static ReadCollectablesList(reader: SaveReader): ObjectReference[];
|
|
21
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Level = void 0;
|
|
4
|
+
const ObjectReference_1 = require("../objects/ObjectReference");
|
|
5
|
+
const SaveComponent_1 = require("../objects/SaveComponent");
|
|
6
|
+
const SaveEntity_1 = require("../objects/SaveEntity");
|
|
7
|
+
class Level {
|
|
8
|
+
constructor(name) {
|
|
9
|
+
this.name = name;
|
|
10
|
+
this.objects = [];
|
|
11
|
+
this.collectables = [];
|
|
12
|
+
}
|
|
13
|
+
static SerializeObjectHeaders(writer, objects) {
|
|
14
|
+
writer.writeInt32(objects.length);
|
|
15
|
+
for (const obj of objects) {
|
|
16
|
+
switch (obj.type) {
|
|
17
|
+
case 'SaveEntity':
|
|
18
|
+
writer.writeInt32(SaveEntity_1.SaveEntity.TypeID);
|
|
19
|
+
SaveEntity_1.SaveEntity.SerializeHeader(writer, obj);
|
|
20
|
+
break;
|
|
21
|
+
case 'SaveComponent':
|
|
22
|
+
writer.writeInt32(SaveComponent_1.SaveComponent.TypeID);
|
|
23
|
+
SaveComponent_1.SaveComponent.SerializeHeader(writer, obj);
|
|
24
|
+
break;
|
|
25
|
+
default:
|
|
26
|
+
console.log('Unknown object type', obj);
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
static WriteLevel(writer, level, buildVersion) {
|
|
32
|
+
const lenIndicatorHeaderAndCollectableSize = writer.getBufferPosition();
|
|
33
|
+
writer.writeInt32(0);
|
|
34
|
+
Level.SerializeObjectHeaders(writer, level.objects);
|
|
35
|
+
Level.SerializeCollectablesList(writer, level.collectables);
|
|
36
|
+
writer.writeBinarySizeFromPosition(lenIndicatorHeaderAndCollectableSize, lenIndicatorHeaderAndCollectableSize + 4);
|
|
37
|
+
Level.SerializeObjectContents(writer, level.objects, buildVersion);
|
|
38
|
+
Level.SerializeCollectablesList(writer, level.collectables);
|
|
39
|
+
}
|
|
40
|
+
static SerializeObjectContents(writer, objects, buildVersion) {
|
|
41
|
+
const lenIndicatorEntities = writer.getBufferPosition();
|
|
42
|
+
writer.writeInt32(0);
|
|
43
|
+
writer.writeInt32(objects.length);
|
|
44
|
+
for (const obj of objects) {
|
|
45
|
+
const lenReplacementPosition = writer.getBufferPosition();
|
|
46
|
+
writer.writeInt32(0);
|
|
47
|
+
if ((0, SaveEntity_1.isSaveEntity)(obj)) {
|
|
48
|
+
SaveEntity_1.SaveEntity.SerializeData(writer, obj, buildVersion);
|
|
49
|
+
}
|
|
50
|
+
else if ((0, SaveComponent_1.isSaveComponent)(obj)) {
|
|
51
|
+
SaveComponent_1.SaveComponent.SerializeData(writer, obj, buildVersion);
|
|
52
|
+
}
|
|
53
|
+
writer.writeBinarySizeFromPosition(lenReplacementPosition, lenReplacementPosition + 4);
|
|
54
|
+
}
|
|
55
|
+
writer.writeBinarySizeFromPosition(lenIndicatorEntities, lenIndicatorEntities + 4);
|
|
56
|
+
}
|
|
57
|
+
static ReadObjectHeaders(reader, objectsList, onProgressCallback) {
|
|
58
|
+
let countObjectHeaders = reader.readInt32();
|
|
59
|
+
for (let i = 0; i < countObjectHeaders; i++) {
|
|
60
|
+
if (i % 1000 === 0) {
|
|
61
|
+
onProgressCallback(reader.getBufferProgress());
|
|
62
|
+
}
|
|
63
|
+
let objectType = reader.readInt32();
|
|
64
|
+
switch (objectType) {
|
|
65
|
+
case SaveEntity_1.SaveEntity.TypeID:
|
|
66
|
+
let object = new SaveEntity_1.SaveEntity('', '', '', '');
|
|
67
|
+
SaveEntity_1.SaveEntity.ParseHeader(reader, object);
|
|
68
|
+
objectsList.push(object);
|
|
69
|
+
break;
|
|
70
|
+
case SaveComponent_1.SaveComponent.TypeID:
|
|
71
|
+
let component = new SaveComponent_1.SaveComponent('', '', '', '');
|
|
72
|
+
SaveComponent_1.SaveComponent.ParseHeader(reader, component);
|
|
73
|
+
objectsList.push(component);
|
|
74
|
+
break;
|
|
75
|
+
default:
|
|
76
|
+
console.log('Unknown object type', objectType);
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
static ReadObjectContents(reader, objectsList, buildVersion, onProgressCallback) {
|
|
82
|
+
const binarySize = reader.readInt32();
|
|
83
|
+
const posBefore = reader.getBufferPosition();
|
|
84
|
+
const countEntities = reader.readInt32();
|
|
85
|
+
if (countEntities !== objectsList.length) {
|
|
86
|
+
throw new Error(`possibly corrupt. entity content count ${countEntities} does not object count of ${objectsList.length}`);
|
|
87
|
+
}
|
|
88
|
+
for (let i = 0; i < countEntities; i++) {
|
|
89
|
+
if (i % 1000 === 0) {
|
|
90
|
+
onProgressCallback(reader.getBufferProgress());
|
|
91
|
+
}
|
|
92
|
+
const len = reader.readInt32();
|
|
93
|
+
const before = reader.getBufferPosition();
|
|
94
|
+
const obj = objectsList[i];
|
|
95
|
+
if ((0, SaveEntity_1.isSaveEntity)(obj)) {
|
|
96
|
+
SaveEntity_1.SaveEntity.ParseData(obj, len, reader, buildVersion);
|
|
97
|
+
}
|
|
98
|
+
else if ((0, SaveComponent_1.isSaveComponent)(obj)) {
|
|
99
|
+
SaveComponent_1.SaveComponent.ParseData(obj, len, reader, buildVersion);
|
|
100
|
+
}
|
|
101
|
+
const after = reader.getBufferPosition();
|
|
102
|
+
if (after - before !== len) {
|
|
103
|
+
console.warn('entity may be corrupt', this.name, i);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const posAfter = reader.getBufferPosition();
|
|
107
|
+
if (posAfter - posBefore !== binarySize) {
|
|
108
|
+
console.warn('save seems corrupt.', this.name);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
static ReadLevel(reader, levelName, buildVersion) {
|
|
112
|
+
const level = new Level(levelName);
|
|
113
|
+
reader.readInt32();
|
|
114
|
+
Level.ReadObjectHeaders(reader, level.objects, reader.onProgressCallback);
|
|
115
|
+
reader.onProgressCallback(reader.getBufferProgress());
|
|
116
|
+
level.collectables = Level.ReadCollectablesList(reader);
|
|
117
|
+
Level.ReadObjectContents(reader, level.objects, buildVersion, reader.onProgressCallback);
|
|
118
|
+
reader.onProgressCallback(reader.getBufferProgress());
|
|
119
|
+
Level.ReadCollectablesList(reader);
|
|
120
|
+
return level;
|
|
121
|
+
}
|
|
122
|
+
static SerializeCollectablesList(writer, collectables) {
|
|
123
|
+
writer.writeInt32(collectables.length);
|
|
124
|
+
for (const collectable of collectables) {
|
|
125
|
+
ObjectReference_1.ObjectReference.Serialize(writer, collectable);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
static ReadCollectablesList(reader) {
|
|
129
|
+
let countCollected = reader.readInt32();
|
|
130
|
+
const collected = [];
|
|
131
|
+
for (let i = 0; i < countCollected; i++) {
|
|
132
|
+
const collectable = ObjectReference_1.ObjectReference.Parse(reader);
|
|
133
|
+
collected.push(collectable);
|
|
134
|
+
}
|
|
135
|
+
return collected;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
exports.Level = Level;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ChunkCompressionInfo } from "../../file.types";
|
|
2
|
+
import { ObjectReference } from "../objects/ObjectReference";
|
|
3
|
+
import { Level } from "./level.class";
|
|
4
|
+
import { SatisfactorySaveHeader } from "./save.types";
|
|
5
|
+
export declare class SatisfactorySave {
|
|
6
|
+
header: SatisfactorySaveHeader;
|
|
7
|
+
levels: Level[];
|
|
8
|
+
trailingCollectedObjects: ObjectReference[];
|
|
9
|
+
compressionInfo?: ChunkCompressionInfo;
|
|
10
|
+
constructor(header: SatisfactorySaveHeader);
|
|
11
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SatisfactorySave = void 0;
|
|
4
|
+
class SatisfactorySave {
|
|
5
|
+
constructor(header) {
|
|
6
|
+
this.levels = [];
|
|
7
|
+
this.trailingCollectedObjects = [];
|
|
8
|
+
this.header = header;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
exports.SatisfactorySave = SatisfactorySave;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { ByteReader } from "../../byte/byte-reader.class";
|
|
2
|
+
import { ChunkCompressionInfo } from "../../file.types";
|
|
3
|
+
import { ObjectReference } from "../objects/ObjectReference";
|
|
4
|
+
import { SaveComponent } from "../objects/SaveComponent";
|
|
5
|
+
import { SaveEntity } from "../objects/SaveEntity";
|
|
6
|
+
import { SaveObject } from "../objects/SaveObject";
|
|
7
|
+
import { Level } from "./level.class";
|
|
8
|
+
import { SatisfactorySaveHeader } from "./save.types";
|
|
9
|
+
export type EntityPathFilter = {
|
|
10
|
+
behavior: 'whitelist' | 'blacklist';
|
|
11
|
+
list: string[];
|
|
12
|
+
};
|
|
13
|
+
export type SaveProjectionConfig = {
|
|
14
|
+
entityPathFilter: EntityPathFilter;
|
|
15
|
+
includeComponents: boolean;
|
|
16
|
+
};
|
|
17
|
+
export declare const projectionFilterApplies: (config: SaveProjectionConfig, object: SaveComponent | SaveEntity) => boolean;
|
|
18
|
+
export declare class SaveReader extends ByteReader {
|
|
19
|
+
onProgressCallback: (progress: number, msg?: string) => void;
|
|
20
|
+
header: SatisfactorySaveHeader | undefined;
|
|
21
|
+
levels: Level[];
|
|
22
|
+
trailingCollectedObjects: ObjectReference[];
|
|
23
|
+
compressionInfo: ChunkCompressionInfo;
|
|
24
|
+
static readonly EPOCH_TICKS = 621355968000000000n;
|
|
25
|
+
constructor(fileBuffer: ArrayBuffer, onProgressCallback?: (progress: number, msg?: string) => void);
|
|
26
|
+
readHeader(): SatisfactorySaveHeader;
|
|
27
|
+
inflateChunks(): {
|
|
28
|
+
concatenatedChunkLength: number;
|
|
29
|
+
numChunks: number;
|
|
30
|
+
};
|
|
31
|
+
readLevels(): Level[];
|
|
32
|
+
}
|
|
33
|
+
export declare class Conveyor {
|
|
34
|
+
static getConveyorBeltRegex(): RegExp;
|
|
35
|
+
static getConveyorLiftRegex(): RegExp;
|
|
36
|
+
static isAConveyorBelt(obj: SaveObject): boolean;
|
|
37
|
+
static isAConveyorLift(obj: SaveObject): boolean;
|
|
38
|
+
static get availableConnections(): string[];
|
|
39
|
+
static get availableConveyorBelts(): string[];
|
|
40
|
+
static get availableConveyorLifts(): string[];
|
|
41
|
+
static isConveyor(currentObject: any): boolean;
|
|
42
|
+
static isConveyorBelt(currentObject: any): boolean;
|
|
43
|
+
static isConveyorLift(currentObject: any): boolean;
|
|
44
|
+
}
|