@etothepii/satisfactory-file-parser 0.0.10 → 0.0.11

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.
Files changed (46) hide show
  1. package/build/index.d.ts +11 -0
  2. package/build/index.js +12 -0
  3. package/build/parser/blueprint-reader.d.ts +18 -0
  4. package/build/parser/blueprint-reader.js +128 -0
  5. package/build/parser/blueprint-writer.d.ts +21 -0
  6. package/build/parser/blueprint-writer.js +64 -0
  7. package/build/parser/byte/alignment.enum.d.ts +4 -0
  8. package/build/parser/byte/alignment.enum.js +5 -0
  9. package/build/parser/byte/byte-reader.class.d.ts +38 -0
  10. package/build/parser/byte/byte-reader.class.js +128 -0
  11. package/build/parser/byte/byte-writer.class.d.ts +38 -0
  12. package/build/parser/byte/byte-writer.class.js +146 -0
  13. package/build/parser/error/parser.error.d.ts +12 -0
  14. package/build/parser/error/parser.error.js +21 -0
  15. package/build/parser/parser.d.ts +44 -0
  16. package/build/parser/parser.js +81 -0
  17. package/build/parser/satisfactory/blueprint/blueprint.d.ts +20 -0
  18. package/build/parser/satisfactory/blueprint/blueprint.js +1 -0
  19. package/build/parser/satisfactory/level.class.d.ts +21 -0
  20. package/build/parser/satisfactory/level.class.js +144 -0
  21. package/build/parser/satisfactory/objects/DataFields.d.ts +13 -0
  22. package/build/parser/satisfactory/objects/DataFields.js +245 -0
  23. package/build/parser/satisfactory/objects/ObjectReference.d.ts +9 -0
  24. package/build/parser/satisfactory/objects/ObjectReference.js +13 -0
  25. package/build/parser/satisfactory/objects/Property.d.ts +270 -0
  26. package/build/parser/satisfactory/objects/Property.js +1119 -0
  27. package/build/parser/satisfactory/objects/SaveComponent.d.ts +16 -0
  28. package/build/parser/satisfactory/objects/SaveComponent.js +27 -0
  29. package/build/parser/satisfactory/objects/SaveEntity.d.ts +25 -0
  30. package/build/parser/satisfactory/objects/SaveEntity.js +66 -0
  31. package/build/parser/satisfactory/objects/SaveObject.d.ts +14 -0
  32. package/build/parser/satisfactory/objects/SaveObject.js +25 -0
  33. package/build/parser/satisfactory/satisfactory-save.d.ts +57 -0
  34. package/build/parser/satisfactory/satisfactory-save.js +7 -0
  35. package/build/parser/satisfactory/static-data.d.ts +7 -0
  36. package/build/parser/satisfactory/static-data.js +1 -0
  37. package/build/parser/satisfactory/structs/util.types.d.ts +40 -0
  38. package/build/parser/satisfactory/structs/util.types.js +75 -0
  39. package/build/parser/save-reader.d.ts +43 -0
  40. package/build/parser/save-reader.js +243 -0
  41. package/build/parser/save-writer.d.ts +22 -0
  42. package/build/parser/save-writer.js +114 -0
  43. package/package.json +4 -3
  44. package/index.d.ts +0 -2356
  45. package/index.js +0 -2364
  46. package/rollup.config.mjs +0 -11
@@ -0,0 +1,16 @@
1
+ import { ByteReader } from "../../byte/byte-reader.class";
2
+ import { ByteWriter } from "../../byte/byte-writer.class";
3
+ import { SaveObject } from "./SaveObject";
4
+ export declare const isSaveComponent: (obj: any) => obj is SaveComponent;
5
+ export declare class SaveComponent extends SaveObject {
6
+ typePath: string;
7
+ rootObject: string;
8
+ instanceName: string;
9
+ parentEntityName: string;
10
+ static readonly TypeID = 0;
11
+ readonly type = "SaveComponent";
12
+ constructor(typePath: string, rootObject: string, instanceName: string, parentEntityName?: string);
13
+ static ParseHeader(reader: ByteReader, obj: SaveComponent): void;
14
+ static SerializeHeader(writer: ByteWriter, component: SaveComponent): void;
15
+ static ParseData(component: SaveComponent, length: number, reader: ByteReader, buildVersion: number): void;
16
+ }
@@ -0,0 +1,27 @@
1
+ import { SaveObject } from "./SaveObject";
2
+ export const isSaveComponent = (obj) => {
3
+ return obj.type === 'SaveComponent';
4
+ };
5
+ class SaveComponent extends SaveObject {
6
+ constructor(typePath, rootObject, instanceName, parentEntityName = '') {
7
+ super(typePath, rootObject, instanceName);
8
+ this.typePath = typePath;
9
+ this.rootObject = rootObject;
10
+ this.instanceName = instanceName;
11
+ this.parentEntityName = parentEntityName;
12
+ this.type = 'SaveComponent';
13
+ }
14
+ static ParseHeader(reader, obj) {
15
+ SaveObject.ParseHeader(reader, obj);
16
+ obj.parentEntityName = reader.readString();
17
+ }
18
+ static SerializeHeader(writer, component) {
19
+ SaveObject.SerializeHeader(writer, component);
20
+ writer.writeString(component.parentEntityName);
21
+ }
22
+ static ParseData(component, length, reader, buildVersion) {
23
+ SaveObject.ParseData(component, length, reader, buildVersion);
24
+ }
25
+ }
26
+ SaveComponent.TypeID = 0;
27
+ export { SaveComponent };
@@ -0,0 +1,25 @@
1
+ import { ByteReader } from "../../byte/byte-reader.class";
2
+ import { ByteWriter } from "../../byte/byte-writer.class";
3
+ import { Transform } from "../structs/util.types";
4
+ import { ObjectReference } from "./ObjectReference";
5
+ import { SaveObject } from "./SaveObject";
6
+ export declare const isSaveEntity: (obj: any) => obj is SaveEntity;
7
+ export declare class SaveEntity extends SaveObject {
8
+ typePath: string;
9
+ rootObject: string;
10
+ instanceName: string;
11
+ parentEntityName: string;
12
+ static readonly TypeID = 1;
13
+ readonly type = "SaveEntity";
14
+ needTransform: boolean;
15
+ transform: Transform;
16
+ wasPlacedInLevel: boolean;
17
+ parentObjectRoot: string;
18
+ parentObjectName: string;
19
+ components: ObjectReference[];
20
+ constructor(typePath: string, rootObject: string, instanceName: string, parentEntityName?: string, needsTransform?: boolean);
21
+ static ParseHeader(reader: ByteReader, obj: SaveEntity): void;
22
+ static ParseData(entity: SaveEntity, length: number, reader: ByteReader, buildVersion: number): void;
23
+ static SerializeHeader(writer: ByteWriter, entity: SaveEntity): void;
24
+ static SerializeData(writer: ByteWriter, entity: SaveEntity, buildVersion: number): void;
25
+ }
@@ -0,0 +1,66 @@
1
+ import { ParseTransform, SerializeTransform } from "../structs/util.types";
2
+ import { ObjectReference } from "./ObjectReference";
3
+ import { SaveObject } from "./SaveObject";
4
+ export const isSaveEntity = (obj) => {
5
+ return obj.type === 'SaveEntity';
6
+ };
7
+ class SaveEntity extends SaveObject {
8
+ constructor(typePath, rootObject, instanceName, parentEntityName = '', needsTransform = false) {
9
+ super(typePath, rootObject, instanceName);
10
+ this.typePath = typePath;
11
+ this.rootObject = rootObject;
12
+ this.instanceName = instanceName;
13
+ this.parentEntityName = parentEntityName;
14
+ this.type = 'SaveEntity';
15
+ this.needTransform = needsTransform;
16
+ this.wasPlacedInLevel = false;
17
+ this.parentObjectRoot = '';
18
+ this.parentObjectName = '';
19
+ this.transform = {
20
+ rotation: { x: 0, y: 0, z: 0, w: 1 },
21
+ translation: { x: 0, y: 0, z: 0 },
22
+ scale3d: { x: 1, y: 1, z: 1 }
23
+ };
24
+ this.components = [];
25
+ }
26
+ static ParseHeader(reader, obj) {
27
+ SaveObject.ParseHeader(reader, obj);
28
+ obj.needTransform = reader.readInt32() == 1;
29
+ obj.transform = ParseTransform(reader);
30
+ obj.wasPlacedInLevel = reader.readInt32() == 1;
31
+ }
32
+ static ParseData(entity, length, reader, buildVersion) {
33
+ var newLen = length - 12;
34
+ entity.parentObjectRoot = reader.readString();
35
+ if (entity.parentObjectRoot.length > 0)
36
+ newLen -= entity.parentObjectRoot.length + 1;
37
+ entity.parentObjectName = reader.readString();
38
+ if (entity.parentObjectName.length > 0)
39
+ newLen -= entity.parentObjectName.length + 1;
40
+ var componentCount = reader.readInt32();
41
+ for (let i = 0; i < componentCount; i++) {
42
+ var componentRef = ObjectReference.Parse(reader);
43
+ entity.components.push(componentRef);
44
+ newLen -= 10 + componentRef.levelName.length + componentRef.pathName.length;
45
+ }
46
+ SaveObject.ParseData(entity, newLen, reader, buildVersion);
47
+ }
48
+ static SerializeHeader(writer, entity) {
49
+ SaveObject.SerializeHeader(writer, entity);
50
+ writer.writeInt32(entity.needTransform ? 1 : 0);
51
+ SerializeTransform(writer, entity.transform);
52
+ writer.writeInt32(entity.wasPlacedInLevel ? 1 : 0);
53
+ }
54
+ static SerializeData(writer, entity, buildVersion) {
55
+ writer.writeString(entity.parentObjectRoot);
56
+ writer.writeString(entity.parentObjectName);
57
+ writer.writeInt32(entity.components.length);
58
+ for (const com of entity.components) {
59
+ writer.writeString(com.levelName);
60
+ writer.writeString(com.pathName);
61
+ }
62
+ SaveObject.SerializeData(writer, entity, buildVersion);
63
+ }
64
+ }
65
+ SaveEntity.TypeID = 1;
66
+ export { SaveEntity };
@@ -0,0 +1,14 @@
1
+ import { ByteReader } from "../../byte/byte-reader.class";
2
+ import { ByteWriter } from "../../byte/byte-writer.class";
3
+ import { DataFields } from "./DataFields";
4
+ export declare abstract class SaveObject {
5
+ typePath: string;
6
+ rootObject: string;
7
+ instanceName: string;
8
+ dataFields: DataFields;
9
+ constructor(typePath: string, rootObject: string, instanceName: string);
10
+ protected static ParseHeader(reader: ByteReader, obj: SaveObject): void;
11
+ protected static SerializeHeader(writer: ByteWriter, obj: SaveObject): void;
12
+ static ParseData(obj: SaveObject, length: number, reader: ByteReader, buildVersion: number): void;
13
+ static SerializeData(writer: any, obj: SaveObject, buildVersion: number): void;
14
+ }
@@ -0,0 +1,25 @@
1
+ import { DataFields } from "./DataFields";
2
+ export class SaveObject {
3
+ constructor(typePath, rootObject, instanceName) {
4
+ this.typePath = typePath;
5
+ this.rootObject = rootObject;
6
+ this.instanceName = instanceName;
7
+ this.dataFields = new DataFields();
8
+ }
9
+ static ParseHeader(reader, obj) {
10
+ obj.typePath = reader.readString();
11
+ obj.rootObject = reader.readString();
12
+ obj.instanceName = reader.readString();
13
+ }
14
+ static SerializeHeader(writer, obj) {
15
+ writer.writeString(obj.typePath);
16
+ writer.writeString(obj.rootObject);
17
+ writer.writeString(obj.instanceName);
18
+ }
19
+ static ParseData(obj, length, reader, buildVersion) {
20
+ obj.dataFields = DataFields.Parse(length, reader, buildVersion);
21
+ }
22
+ static SerializeData(writer, obj, buildVersion) {
23
+ DataFields.Serialize(writer, obj.dataFields, buildVersion);
24
+ }
25
+ }
@@ -0,0 +1,57 @@
1
+ import { Level } from "./level.class";
2
+ import { ObjectReference } from "./objects/ObjectReference";
3
+ export interface ModData {
4
+ Reference: string;
5
+ Name: string;
6
+ Version: string;
7
+ }
8
+ export interface SatisfactoryModMetadata {
9
+ Mods: ModData[];
10
+ }
11
+ export interface SatisfactorySaveHeader {
12
+ saveHeaderType: number;
13
+ saveVersion: number;
14
+ buildVersion: number;
15
+ mapName: string;
16
+ mapOptions: string;
17
+ sessionName: string;
18
+ playDurationSeconds: number;
19
+ saveDateTime: string;
20
+ sessionVisibility: number;
21
+ rawModMetadataString?: string;
22
+ modMetadata?: SatisfactoryModMetadata;
23
+ isModdedSave?: number;
24
+ saveIdentifier?: string;
25
+ fEditorObjectVersion?: number;
26
+ }
27
+ export type ResourceNodeEntry = {
28
+ purity: string;
29
+ pathName: string;
30
+ position: {
31
+ x: number;
32
+ y: number;
33
+ z: number;
34
+ };
35
+ type: string;
36
+ };
37
+ export type CollectibleEntry = {
38
+ pathName: string;
39
+ position: {
40
+ x: number;
41
+ y: number;
42
+ z: number;
43
+ };
44
+ type: string;
45
+ };
46
+ export type ChunkCompressionInfo = {
47
+ chunkHeaderSize: number;
48
+ packageFileTag: number;
49
+ maxChunkContentSize: number;
50
+ };
51
+ export declare class SatisfactorySave {
52
+ header: SatisfactorySaveHeader;
53
+ levels: Level[];
54
+ trailingCollectedObjects: ObjectReference[];
55
+ compressionInfo?: ChunkCompressionInfo;
56
+ constructor(header: SatisfactorySaveHeader);
57
+ }
@@ -0,0 +1,7 @@
1
+ export class SatisfactorySave {
2
+ constructor(header) {
3
+ this.levels = [];
4
+ this.trailingCollectedObjects = [];
5
+ this.header = header;
6
+ }
7
+ }
@@ -0,0 +1,7 @@
1
+ import { CollectibleEntry, ResourceNodeEntry } from "./satisfactory-save";
2
+ export type StaticData = {
3
+ collectibles: CollectibleEntry[];
4
+ artifacts: CollectibleEntry[];
5
+ slugs: CollectibleEntry[];
6
+ resourceNodes: ResourceNodeEntry[];
7
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,40 @@
1
+ import { ByteReader } from "../../byte/byte-reader.class";
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: ByteReader) => col4;
11
+ export declare const SerializeCol4BGRA: (writer: ByteWriter, value: col4) => void;
12
+ export declare const ParseCol4BGRA: (reader: ByteReader) => col4;
13
+ export type vec4 = vec3 & {
14
+ w: number;
15
+ };
16
+ export declare const ParseVec4: (reader: ByteReader) => 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: ByteReader) => 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: ByteReader) => 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: ByteReader) => Transform;
40
+ export declare const SerializeTransform: (writer: ByteWriter, transform: Transform) => void;
@@ -0,0 +1,75 @@
1
+ export const SerializeCol4RGBA = (writer, value) => {
2
+ writer.writeFloat(value.r);
3
+ writer.writeFloat(value.g);
4
+ writer.writeFloat(value.b);
5
+ writer.writeFloat(value.a);
6
+ };
7
+ export const ParseCol4RGBA = (reader) => {
8
+ return {
9
+ r: reader.readFloat(),
10
+ g: reader.readFloat(),
11
+ b: reader.readFloat(),
12
+ a: reader.readFloat(),
13
+ };
14
+ };
15
+ export const SerializeCol4BGRA = (writer, value) => {
16
+ writer.writeByte(value.b);
17
+ writer.writeByte(value.g);
18
+ writer.writeByte(value.r);
19
+ writer.writeByte(value.a);
20
+ };
21
+ export const ParseCol4BGRA = (reader) => {
22
+ return {
23
+ b: reader.readByte(),
24
+ g: reader.readByte(),
25
+ r: reader.readByte(),
26
+ a: reader.readByte(),
27
+ };
28
+ };
29
+ export const ParseVec4 = (reader) => {
30
+ return {
31
+ ...ParseVec3(reader),
32
+ w: reader.readFloat()
33
+ };
34
+ };
35
+ export const SerializeVec4 = (writer, vec) => {
36
+ SerializeVec3(writer, vec);
37
+ writer.writeFloat(vec.w);
38
+ };
39
+ export const sub = (other, vec) => ({ x: other.x - vec.x, y: other.y - vec.y, z: other.z - vec.z });
40
+ export const add = (vec, other) => ({ x: vec.x + other.x, y: vec.y + other.y, z: vec.z + other.z });
41
+ export const length = (vec) => Math.sqrt(vec.x ** 2 + vec.y ** 2 + vec.z ** 2);
42
+ export const mult = (vec, scale) => ({ x: vec.x * scale, y: vec.y * scale, z: vec.z * scale });
43
+ export const norm = (vec) => mult(vec, 1. / length(vec));
44
+ export const ParseVec3 = (reader) => {
45
+ return {
46
+ ...ParseVec2(reader),
47
+ z: reader.readFloat()
48
+ };
49
+ };
50
+ export const SerializeVec3 = (writer, vec) => {
51
+ SerializeVec2(writer, vec);
52
+ writer.writeFloat(vec.z);
53
+ };
54
+ export const ParseVec2 = (reader) => {
55
+ return {
56
+ x: reader.readFloat(),
57
+ y: reader.readFloat(),
58
+ };
59
+ };
60
+ export const SerializeVec2 = (writer, vec) => {
61
+ writer.writeFloat(vec.x);
62
+ writer.writeFloat(vec.y);
63
+ };
64
+ export const ParseTransform = (reader) => {
65
+ return {
66
+ rotation: ParseVec4(reader),
67
+ translation: ParseVec3(reader),
68
+ scale3d: ParseVec3(reader),
69
+ };
70
+ };
71
+ export const SerializeTransform = (writer, transform) => {
72
+ SerializeVec4(writer, transform.rotation);
73
+ SerializeVec3(writer, transform.translation);
74
+ SerializeVec3(writer, transform.scale3d);
75
+ };
@@ -0,0 +1,43 @@
1
+ import { ByteReader } from "./byte/byte-reader.class";
2
+ import { Level } from "./satisfactory/level.class";
3
+ import { ObjectReference } from "./satisfactory/objects/ObjectReference";
4
+ import { SaveComponent } from "./satisfactory/objects/SaveComponent";
5
+ import { SaveEntity } from "./satisfactory/objects/SaveEntity";
6
+ import { SaveObject } from "./satisfactory/objects/SaveObject";
7
+ import { ChunkCompressionInfo, SatisfactorySaveHeader } from "./satisfactory/satisfactory-save";
8
+ export type EntityPathFilter = {
9
+ behavior: 'whitelist' | 'blacklist';
10
+ list: string[];
11
+ };
12
+ export type SaveProjectionConfig = {
13
+ entityPathFilter: EntityPathFilter;
14
+ includeComponents: boolean;
15
+ };
16
+ export declare const projectionFilterApplies: (config: SaveProjectionConfig, object: SaveComponent | SaveEntity) => boolean;
17
+ export declare class SaveReader extends ByteReader {
18
+ onProgressCallback: (progress: number, msg?: string) => void;
19
+ header: SatisfactorySaveHeader | undefined;
20
+ levels: Level[];
21
+ trailingCollectedObjects: ObjectReference[];
22
+ compressionInfo: ChunkCompressionInfo;
23
+ static readonly EPOCH_TICKS = 621355968000000000n;
24
+ constructor(fileBuffer: ArrayBuffer, onProgressCallback?: (progress: number, msg?: string) => void);
25
+ readHeader(): SatisfactorySaveHeader;
26
+ inflateChunks(): {
27
+ concatenatedChunkLength: number;
28
+ numChunks: number;
29
+ };
30
+ readLevels(): Level[];
31
+ }
32
+ export declare class Conveyor {
33
+ static getConveyorBeltRegex(): RegExp;
34
+ static getConveyorLiftRegex(): RegExp;
35
+ static isAConveyorBelt(obj: SaveObject): boolean;
36
+ static isAConveyorLift(obj: SaveObject): boolean;
37
+ static get availableConnections(): string[];
38
+ static get availableConveyorBelts(): string[];
39
+ static get availableConveyorLifts(): string[];
40
+ static isConveyor(currentObject: any): boolean;
41
+ static isConveyorBelt(currentObject: any): boolean;
42
+ static isConveyorLift(currentObject: any): boolean;
43
+ }
@@ -0,0 +1,243 @@
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 { Level } from "./satisfactory/level.class";
6
+ import { isSaveComponent } from "./satisfactory/objects/SaveComponent";
7
+ import { isSaveEntity } from "./satisfactory/objects/SaveEntity";
8
+ export const projectionFilterApplies = (config, object) => {
9
+ let cond1 = false;
10
+ if (isSaveEntity(object) || (config.includeComponents && isSaveComponent(object))) {
11
+ cond1 = true;
12
+ }
13
+ let cond2 = true;
14
+ if (isSaveEntity(object)) {
15
+ cond2 = false;
16
+ if (config.entityPathFilter.behavior === 'whitelist') {
17
+ cond2 = config.entityPathFilter.list.find(en => object.typePath.startsWith(en)) !== undefined;
18
+ }
19
+ else if (config.entityPathFilter.behavior === 'blacklist') {
20
+ cond2 = config.entityPathFilter.list.find(en => object.typePath.startsWith(en)) === undefined;
21
+ }
22
+ }
23
+ return cond1 && cond2;
24
+ };
25
+ class SaveReader extends ByteReader {
26
+ constructor(fileBuffer, onProgressCallback = () => { }) {
27
+ super(fileBuffer, Alignment.LITTLE_ENDIAN);
28
+ this.onProgressCallback = onProgressCallback;
29
+ this.levels = [];
30
+ this.trailingCollectedObjects = [];
31
+ this.compressionInfo = {
32
+ packageFileTag: 0,
33
+ maxChunkContentSize: 0,
34
+ chunkHeaderSize: 48
35
+ };
36
+ }
37
+ readHeader() {
38
+ this.header = {
39
+ saveHeaderType: 0,
40
+ saveVersion: 0,
41
+ buildVersion: 0,
42
+ mapName: "DEFAULT",
43
+ mapOptions: "",
44
+ sessionName: "",
45
+ playDurationSeconds: 0,
46
+ saveDateTime: "0",
47
+ sessionVisibility: 0
48
+ };
49
+ this.header.saveHeaderType = this.readInt32();
50
+ this.header.saveVersion = this.readInt32();
51
+ this.header.buildVersion = this.readInt32();
52
+ this.header.mapName = this.readString();
53
+ this.header.mapOptions = this.readString();
54
+ this.header.sessionName = this.readString();
55
+ this.header.playDurationSeconds = this.readInt32();
56
+ const rawSaveDateTimeInTicks = this.readLong();
57
+ const unixMilliseconds = (rawSaveDateTimeInTicks - SaveReader.EPOCH_TICKS) / 10000n;
58
+ this.header.saveDateTime = unixMilliseconds.toString();
59
+ this.header.sessionVisibility = this.readByte();
60
+ if (this.header.saveHeaderType >= 7) {
61
+ this.header.fEditorObjectVersion = this.readInt32();
62
+ }
63
+ if (this.header.saveHeaderType >= 8) {
64
+ this.header.rawModMetadataString = this.readString();
65
+ try {
66
+ this.header.modMetadata = JSON.parse(this.header.rawModMetadataString);
67
+ }
68
+ catch (error) {
69
+ //
70
+ }
71
+ this.header.isModdedSave = this.readInt32();
72
+ }
73
+ if (this.header.saveHeaderType >= 10) {
74
+ this.header.saveIdentifier = this.readString();
75
+ }
76
+ if (this.header.saveVersion >= 21) {
77
+ // all good, ready to read chunks now.
78
+ }
79
+ else {
80
+ throw new UnsupportedVersionError("The save version is too old to support encoding currently. Save in newer game version.");
81
+ }
82
+ return this.header;
83
+ }
84
+ inflateChunks() {
85
+ // free memory
86
+ this.fileBuffer = this.fileBuffer.slice(this.currentByte);
87
+ this.handledByte = 0;
88
+ this.currentByte = 0;
89
+ this.maxByte = this.fileBuffer.byteLength;
90
+ let currentChunks = [];
91
+ let totalUncompressedBodySize = 0;
92
+ // read while we can handle
93
+ while (this.handledByte < this.maxByte) {
94
+ // Read chunk info size...
95
+ let chunkHeader = new DataView(this.fileBuffer.slice(0, this.compressionInfo.chunkHeaderSize));
96
+ this.currentByte = this.compressionInfo.chunkHeaderSize;
97
+ this.handledByte += this.compressionInfo.chunkHeaderSize;
98
+ if (this.compressionInfo.packageFileTag <= 0) {
99
+ this.compressionInfo.packageFileTag = chunkHeader.getInt32(0, this.alignment === Alignment.LITTLE_ENDIAN);
100
+ }
101
+ if (this.compressionInfo.maxChunkContentSize <= 0) {
102
+ this.compressionInfo.maxChunkContentSize = chunkHeader.getInt32(8, this.alignment === Alignment.LITTLE_ENDIAN);
103
+ }
104
+ const chunkCompressedLength = chunkHeader.getInt32(32, this.alignment === Alignment.LITTLE_ENDIAN);
105
+ const chunkUncompressedLength = chunkHeader.getInt32(40, this.alignment === Alignment.LITTLE_ENDIAN);
106
+ totalUncompressedBodySize += chunkUncompressedLength;
107
+ const currentChunkSize = chunkCompressedLength;
108
+ let currentChunk = this.fileBuffer.slice(this.currentByte, this.currentByte + currentChunkSize);
109
+ this.handledByte += currentChunkSize;
110
+ this.currentByte += currentChunkSize;
111
+ // Free memory from previous chunk...
112
+ this.fileBuffer = this.fileBuffer.slice(this.currentByte);
113
+ this.currentByte = 0;
114
+ // Unzip!
115
+ try {
116
+ // Inflate current chunk
117
+ let currentInflatedChunk = null;
118
+ currentInflatedChunk = Pako.inflate(currentChunk);
119
+ currentChunks.push(currentInflatedChunk);
120
+ }
121
+ catch (err) {
122
+ throw new CompressionLibraryError("Failed to inflate compressed save data. " + err);
123
+ }
124
+ }
125
+ //TODO we can get rid of file buffer here.
126
+ // Create one big chunk out of the little chunks
127
+ let newChunkLength = currentChunks.map(cc => cc.length).reduce((prev, cur) => prev + cur);
128
+ const bigWholeChunk = new Uint8Array(newChunkLength);
129
+ let currentLength = 0;
130
+ for (let i = 0; i < currentChunks.length; i++) {
131
+ bigWholeChunk.set(currentChunks[i], currentLength);
132
+ currentLength += currentChunks[i].length;
133
+ }
134
+ this.currentByte = 0;
135
+ this.maxByte = bigWholeChunk.buffer.byteLength;
136
+ this.bufferView = new DataView(bigWholeChunk.buffer);
137
+ const dataLength = this.readInt32();
138
+ if (totalUncompressedBodySize !== dataLength + 4) {
139
+ throw new CorruptSaveError(`Possibly corrupt. Indicated size of total save body (${dataLength}) does not match the uncompressed real size of ${totalUncompressedBodySize}.`);
140
+ }
141
+ return {
142
+ concatenatedChunkLength: newChunkLength,
143
+ numChunks: currentChunks.length
144
+ };
145
+ }
146
+ readLevels() {
147
+ if (!this.header) {
148
+ throw new ParserError('ParserError', 'Header must be set before objects can be read.');
149
+ }
150
+ if (this.header.saveVersion < 29) {
151
+ throw new UnsupportedVersionError('Support for < U6 is not yet implemented.');
152
+ }
153
+ const numSubLevels = this.readInt32();
154
+ this.levels = new Array(numSubLevels + 1);
155
+ // read levels
156
+ for (let j = 0; j <= numSubLevels; j++) {
157
+ let levelName = (j === numSubLevels) ? '' + this.header.mapName : this.readString();
158
+ this.onProgressCallback(this.getBufferProgress(), `reading level [${(j + 1)}/${(numSubLevels + 1)}] ${levelName}`);
159
+ this.levels[j] = Level.ReadLevel(this, levelName, this.header.buildVersion);
160
+ }
161
+ // in U6/U7 there were more collectibles added that do not belong to a particular level
162
+ if (this.getBufferPosition() < this.bufferView.byteLength) {
163
+ this.trailingCollectedObjects = Level.ReadCollectablesList(this);
164
+ }
165
+ return this.levels;
166
+ }
167
+ }
168
+ // the number of .net ticks at the unix epoch
169
+ SaveReader.EPOCH_TICKS = 621355968000000000n;
170
+ export { SaveReader };
171
+ export class Conveyor {
172
+ static getConveyorBeltRegex() {
173
+ return /\/Game\/FactoryGame\/Buildable\/Factory\/(ConveyorBeltMk[0-9]+)\/Build_(\1)\.Build_(\1)_C/g;
174
+ }
175
+ ;
176
+ static getConveyorLiftRegex() {
177
+ return /\/Game\/FactoryGame\/Buildable\/Factory\/(ConveyorLiftMk[0-9]+)\/Build_(\1)\.Build_(\1)_C/g;
178
+ }
179
+ ;
180
+ static isAConveyorBelt(obj) {
181
+ return obj.typePath.match(this.getConveyorBeltRegex()) !== null;
182
+ }
183
+ static isAConveyorLift(obj) {
184
+ return obj.typePath.match(this.getConveyorLiftRegex()) !== null;
185
+ }
186
+ static get availableConnections() { return ['.ConveyorAny0', '.ConveyorAny1', '.Input0', '.Input1', '.Input2', '.Input3', '.InPut3', '.Input4', '.Input5', '.Input6', '.Output0', '.Output1', '.Output2', '.Output3']; }
187
+ static get availableConveyorBelts() {
188
+ return [
189
+ '/Game/FactoryGame/Buildable/Factory/ConveyorBeltMk1/Build_ConveyorBeltMk1.Build_ConveyorBeltMk1_C',
190
+ '/Game/FactoryGame/Buildable/Factory/ConveyorBeltMk2/Build_ConveyorBeltMk2.Build_ConveyorBeltMk2_C',
191
+ '/Game/FactoryGame/Buildable/Factory/ConveyorBeltMk3/Build_ConveyorBeltMk3.Build_ConveyorBeltMk3_C',
192
+ '/Game/FactoryGame/Buildable/Factory/ConveyorBeltMk4/Build_ConveyorBeltMk4.Build_ConveyorBeltMk4_C',
193
+ '/Game/FactoryGame/Buildable/Factory/ConveyorBeltMk5/Build_ConveyorBeltMk5.Build_ConveyorBeltMk5_C'
194
+ ];
195
+ }
196
+ static get availableConveyorLifts() {
197
+ return [
198
+ '/Game/FactoryGame/Buildable/Factory/ConveyorLiftMk1/Build_ConveyorLiftMk1.Build_ConveyorLiftMk1_C',
199
+ '/Game/FactoryGame/Buildable/Factory/ConveyorLiftMk2/Build_ConveyorLiftMk2.Build_ConveyorLiftMk2_C',
200
+ '/Game/FactoryGame/Buildable/Factory/ConveyorLiftMk3/Build_ConveyorLiftMk3.Build_ConveyorLiftMk3_C',
201
+ '/Game/FactoryGame/Buildable/Factory/ConveyorLiftMk4/Build_ConveyorLiftMk4.Build_ConveyorLiftMk4_C',
202
+ '/Game/FactoryGame/Buildable/Factory/ConveyorLiftMk5/Build_ConveyorLiftMk5.Build_ConveyorLiftMk5_C'
203
+ ];
204
+ }
205
+ /*
206
+ * BELT/LIFT LOOKUP, includes mods to avoid finding them everywhere
207
+ */
208
+ static isConveyor(currentObject) {
209
+ return Conveyor.isConveyorBelt(currentObject) || Conveyor.isConveyorLift(currentObject);
210
+ }
211
+ static isConveyorBelt(currentObject) {
212
+ if (Conveyor.availableConveyorBelts.includes(currentObject.className)) {
213
+ return true;
214
+ }
215
+ // Belts Mod
216
+ if (currentObject.className.startsWith('/Conveyors_Mod/Build_BeltMk')
217
+ || currentObject.className.startsWith('/Game/Conveyors_Mod/Build_BeltMk')
218
+ || currentObject.className.startsWith('/UltraFastLogistics/Buildable/build_conveyorbeltMK')
219
+ || currentObject.className.startsWith('/FlexSplines/Conveyor/Build_Belt')
220
+ || currentObject.className.startsWith('/conveyorbeltmod/Belt/mk')
221
+ || currentObject.className.startsWith('/minerplus/content/buildable/Factory/belt_')
222
+ || currentObject.className.startsWith('/bamfp/content/buildable/Factory/belt_')) {
223
+ return true;
224
+ }
225
+ return false;
226
+ }
227
+ static isConveyorLift(currentObject) {
228
+ if (Conveyor.availableConveyorLifts.includes(currentObject.className)) {
229
+ return true;
230
+ }
231
+ // Lifts Mod
232
+ if (currentObject.className.startsWith('/minerplus/content/buildable/Factory/lift')
233
+ || currentObject.className.startsWith('/bamfp/content/buildable/Factory/lift')
234
+ || currentObject.className.startsWith('/Game/Conveyors_Mod/Build_LiftMk')
235
+ || currentObject.className.startsWith('/Conveyors_Mod/Build_LiftMk')
236
+ || currentObject.className.startsWith('/Game/CoveredConveyor')
237
+ || currentObject.className.startsWith('/CoveredConveyor')
238
+ || currentObject.className.startsWith('/conveyorbeltmod/lift/')) {
239
+ return true;
240
+ }
241
+ return false;
242
+ }
243
+ }