UNPKG

unreal.js

Version:

A pak reader for games like VALORANT & Fortnite written in Node.JS

278 lines (277 loc) 8.58 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.serializeProperties = exports.deserializeVersionedTaggedProperties = exports.UObject = void 0; const FPropertyTag_1 = require("../objects/FPropertyTag"); const Guid_1 = require("../../objects/core/misc/Guid"); const Package_1 = require("../Package"); const FName_1 = require("../../objects/uobject/FName"); const Exceptions_1 = require("../../../exceptions/Exceptions"); const UnversionedPropertySerialization_1 = require("../../objects/uobject/serialization/UnversionedPropertySerialization"); const lodash_1 = require("lodash"); const EObjectFlags_1 = require("../../objects/uobject/EObjectFlags"); /** * UE4 Asset Object * @implements {IPropertyHolder} */ class UObject { /** * Creates an instance * @param {?Array<FPropertyTag>} properties Properties to assign * @constructor * @public */ constructor(properties = []) { /** * Object name * @type {string} * @public */ this.name = ""; /** * Outer object of object * @type {UObject} * @public */ this.outer = null; /** * Object class * @type {any} * @public */ this.clazz = null; /** * Template of object * @type {Lazy<UObject>} * @public */ this.template = null; /** * Object properties * @type {Array<FPropertyTag>} * @public */ this.properties = []; /** * Object GUID * @type {FGuid} * @public */ this.objectGuid = null; /** * Object flags * @type {number} * @public */ this.flags = 0; this.properties = properties; } /** * Package that owns this object * @type {Package} * @public */ get owner() { let current = this.outer; let next = current?.outer; while (next != null) { current = next; next = current.outer; } return current; } /** * Type of export * @type {string} * @public */ get exportType() { return this.clazz?.name || UObject.name; } /** * Sets a property * @param {string} name Name of property * @param {any} value Value of property * @returns {void} * @public */ set(name, value) { if (this.getOrNull(name)) return this.properties.find(it => it.name.text === name)?.setTagTypeValue(value); } /** * Gets a property (safe) * @param {string} name Name of property to find * @param {any} dflt Default value to return * @returns {any} Result * @public */ getOrDefault(name, dflt) { const value = this.getOrNull(name); return value || dflt; } /** * Gets a property (safe) * @param {string} name Name of property to find * @returns {?any} Result or null * @public */ getOrNull(name) { return this.properties.find(it => it.name.text === name)?.getTagTypeValue(); } /** * Gets a property * @param {string} name Name of property to find * @returns {any} Result * @throws {Error} If property doesn't exist * @public */ get(name) { const val = this.getOrNull(name); if (!val) throw new Error(`${name} must be not-null`); return val; } /** * Deserializes properties * @param {FAssetArchive} Ar Reader to use * @param {number} validPos Valid position of Reader * @returns {void} * @public */ deserialize(Ar, validPos) { this.properties = []; if (Object.getPrototypeOf(this)?.constructor?.name !== "UClass") { if (Ar.useUnversionedPropertySerialization) { if (this.clazz == null) throw new Exceptions_1.ParserException("Found unversioned properties but object does not have a class.", Ar); UnversionedPropertySerialization_1.deserializeUnversionedProperties(this.properties, this.clazz, Ar); } else { deserializeVersionedTaggedProperties(this.properties, Ar); } } if ((EObjectFlags_1.EObjectFlags.RF_ClassDefaultObject & this.flags) === 0 && Ar.readBoolean()) this.objectGuid = new Guid_1.FGuid(Ar); } /** * Serializes this * @param {FAssetArchiveWriter} Ar Writer to use * @returns {void} * @public */ serialize(Ar) { serializeProperties(Ar, this.properties); Ar.writeBoolean(!!this.objectGuid); this.objectGuid?.serialize(Ar); } /** * Turns this object into json * @param {Locres} locres Locres to use * @returns {any} Json * @public */ toJson(locres = null) { const ob = {}; for (const property of this.properties) { const tagValue = property.prop; if (!tagValue) return; ob[lodash_1.camelCase(property.name.text)] = tagValue.toJsonValue(locres); } return ob; } /** * Clears flags * @param {number} newFlags New flags to set * @returns {void} * @public */ clearFlags(newFlags) { this.flags = this.flags & newFlags; } /** * Checks if this has provided flags * @param {number} flagsToCheck Flags to check for * @returns {boolean} Whether if flags matched or not * @public */ hasAnyFlags(flagsToCheck) { return (this.flags & flagsToCheck) !== 0; } getFullName0(stopOuter = null, includeClassPackage = false) { return this.getFullName1("", stopOuter, includeClassPackage); } getFullName1(resultString, stopOuter = null, includeClassPackage = false) { if (includeClassPackage) { resultString += this.clazz?.getPathName() || "???"; } else { resultString += this.clazz?.name || "???"; } resultString += " "; return this.getPathName1(resultString, stopOuter); } getPathName0(stopOuter = null) { return this.getPathName1("", stopOuter); } getPathName1(resultString, stopOuter = null) { if (this != stopOuter) { const objOuter = this.outer; if (objOuter != null && objOuter != stopOuter) { objOuter.getPathName1(resultString, stopOuter); // SUBOBJECT_DELIMITER_CHAR is used to indicate that this object's outer is not a UPackage if (objOuter.outer instanceof Package_1.Package) { resultString += ":"; } else { resultString += "."; } } resultString += this.name; } else { resultString += "None"; } return resultString; } /** * Turns this into string * @returns {string} * @public */ toString() { return this.name; } } exports.UObject = UObject; /** * Deserializes versioned tagged properties * @param {Array<FPropertyTag>} properties Array to assign properties to * @param {FAssetArchive} Ar Reader to use * @returns {void} * @export */ function deserializeVersionedTaggedProperties(properties, Ar) { while (true) { const tag = new FPropertyTag_1.FPropertyTag(Ar, true); if (tag.name.isNone()) break; properties.push(tag); } } exports.deserializeVersionedTaggedProperties = deserializeVersionedTaggedProperties; /** * Serializes properties * @param {FAssetArchiveWriter} Ar Writer to use * @param {Array<FPropertyTag>} properties Array with properties to serialize * @returns {void} * @export */ function serializeProperties(Ar, properties) { properties.forEach((it) => it.serialize(Ar, true)); const nameMap = FName_1.FName.getByNameMap("None", Ar.nameMap); if (!nameMap) throw new Exceptions_1.ParserException("NameMap must contain \"None\"", Ar); Ar.writeFName(nameMap); } exports.serializeProperties = serializeProperties;