@etothepii/satisfactory-file-parser
Version:
A file parser for satisfactory files. Includes save files and blueprint files.
163 lines (162 loc) • 7.9 kB
JavaScript
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;
;