UNPKG

@etothepii/satisfactory-file-parser

Version:

A file parser for satisfactory files. Includes save files and blueprint files.

163 lines (162 loc) 7.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Level = void 0; const ObjectReference_1 = require("../objects/ObjectReference"); const SaveComponent_1 = require("../objects/SaveComponent"); const SaveEntity_1 = require("../objects/SaveEntity"); class Level { constructor(name) { this.name = name; this.objects = []; this.collectables = []; this.remainingStuffAfterHeaders = new Uint8Array(); } static SerializeObjectHeaders(writer, objects) { writer.writeInt32(objects.length); for (const obj of objects) { switch (obj.type) { case 'SaveEntity': writer.writeInt32(SaveEntity_1.SaveEntity.TypeID); SaveEntity_1.SaveEntity.SerializeHeader(writer, obj); break; case 'SaveComponent': writer.writeInt32(SaveComponent_1.SaveComponent.TypeID); SaveComponent_1.SaveComponent.SerializeHeader(writer, obj); break; default: console.log('Unknown object type', obj); break; } } } static WriteLevel(writer, level, buildVersion) { const lenIndicatorHeaderAndCollectableSize = writer.getBufferPosition(); writer.writeInt32(0); writer.writeInt32(0); Level.SerializeObjectHeaders(writer, level.objects); Level.SerializeCollectablesList(writer, level.collectables); writer.writeBinarySizeFromPosition(lenIndicatorHeaderAndCollectableSize, lenIndicatorHeaderAndCollectableSize + 8); Level.SerializeObjectContents(writer, level.objects, buildVersion, level.name); Level.SerializeCollectablesList(writer, level.collectables); } static SerializeObjectContents(writer, objects, buildVersion, levelName) { const lenIndicatorEntities = writer.getBufferPosition(); writer.writeInt32(0); writer.writeInt32(0); writer.writeInt32(objects.length); for (const obj of objects) { writer.writeInt32(obj.saveOrBlueprintIndicator); writer.writeInt32(obj.unknownType2); const lenReplacementPosition = writer.getBufferPosition(); writer.writeInt32(0); if ((0, SaveEntity_1.isSaveEntity)(obj)) { SaveEntity_1.SaveEntity.SerializeData(writer, obj, buildVersion); } else if ((0, SaveComponent_1.isSaveComponent)(obj)) { SaveComponent_1.SaveComponent.SerializeData(writer, obj, buildVersion); } writer.writeBinarySizeFromPosition(lenReplacementPosition, lenReplacementPosition + 4); } writer.writeBinarySizeFromPosition(lenIndicatorEntities, lenIndicatorEntities + 8); } static ReadObjectHeaders(reader, objectsList, onProgressCallback) { let countObjectHeaders = reader.readInt32(); for (let i = 0; i < countObjectHeaders; i++) { if (i % 1000 === 0) { onProgressCallback(reader.getBufferProgress()); } let objectType = reader.readInt32(); switch (objectType) { case SaveEntity_1.SaveEntity.TypeID: let object = new SaveEntity_1.SaveEntity('', '', '', ''); SaveEntity_1.SaveEntity.ParseHeader(reader, object); objectsList.push(object); break; case SaveComponent_1.SaveComponent.TypeID: let component = new SaveComponent_1.SaveComponent('', '', '', ''); SaveComponent_1.SaveComponent.ParseHeader(reader, component); objectsList.push(component); break; default: console.log('Unknown object type', objectType); break; } } } static async ReadObjectContents(levelName, reader, objectsList, buildVersion, onProgressCallback) { const countEntities = reader.readInt32(); if (countEntities !== objectsList.length) { throw new Error(`possibly corrupt. entity content count ${countEntities} does not equal object count of ${objectsList.length}`); } for (let i = 0; i < countEntities; i++) { if (countEntities >= 10000 && i % 10000 === 0) { onProgressCallback(reader.getBufferProgress(), `read object count [${(i + 1)}/${(countEntities + 1)}] in level ${levelName}`); } const obj = objectsList[i]; obj.saveOrBlueprintIndicator = reader.readInt32(); obj.unknownType2 = reader.readInt32(); const binarySize = reader.readInt32(); const before = reader.getBufferPosition(); if ((0, SaveEntity_1.isSaveEntity)(obj)) { SaveEntity_1.SaveEntity.ParseData(obj, binarySize, reader, buildVersion, obj.typePath); } else if ((0, SaveComponent_1.isSaveComponent)(obj)) { SaveComponent_1.SaveComponent.ParseData(obj, binarySize, reader, buildVersion, obj.typePath); } const after = reader.getBufferPosition(); if (after - before !== binarySize) { console.warn('entity may be corrupt', obj.instanceName); } } } static ReadLevel(reader, levelName, buildVersion) { const level = new Level(levelName); const headersBinLen = reader.readInt32(); const unk = reader.readInt32(); const posBeforeHeaders = reader.getBufferPosition(); Level.ReadObjectHeaders(reader, level.objects, reader.onProgressCallback); let remainingSize = headersBinLen - (reader.getBufferPosition() - posBeforeHeaders); if (remainingSize > 0) { const doubledCollectablesIgnored = Level.ReadCollectablesList(reader, 'collectables at the header section! ' + levelName); } else { } remainingSize = headersBinLen - (reader.getBufferPosition() - posBeforeHeaders); if (remainingSize !== 0) { console.warn('remaining size not 0. Save may be corrupt.', remainingSize, levelName); } const objectContentsBinLen = reader.readInt32(); const unk2 = reader.readInt32(); reader.onProgressCallback(reader.getBufferProgress()); const posBeforeContents = reader.getBufferPosition(); Level.ReadObjectContents(levelName, reader, level.objects, buildVersion, reader.onProgressCallback); const posAfterContents = reader.getBufferPosition(); if (posAfterContents - posBeforeContents !== objectContentsBinLen) { console.warn('save seems corrupt.', this.name); } reader.onProgressCallback(reader.getBufferProgress()); level.collectables = Level.ReadCollectablesList(reader, 'collectables 2! ' + levelName); return level; } static SerializeCollectablesList(writer, collectables) { writer.writeInt32(collectables.length); for (const collectable of collectables) { ObjectReference_1.ObjectReference.write(writer, collectable); } } static ReadCollectablesList(reader, printSmthWhenItsCollectables) { const collected = []; let countSmthing = reader.readInt32(); if (countSmthing > 0) { for (let i = 0; i < countSmthing; i++) { const collectable = ObjectReference_1.ObjectReference.read(reader); collected.push(collectable); } if (process.env.NODE_ENV === 'debug' && countSmthing > 0) { console.log(printSmthWhenItsCollectables, countSmthing, collected.map(coll => coll.pathName).join(', ')); } } return collected; } } exports.Level = Level;