unreal.js
Version:
A pak reader for games like VALORANT & Fortnite written in Node.JS
157 lines (156 loc) • 8.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.UStaticMesh = void 0;
const UStaticMesh_Properties_1 = require("./UStaticMesh_Properties");
const FStripDataFlags_1 = require("../../objects/engine/FStripDataFlags");
const Guid_1 = require("../../objects/core/misc/Guid");
const FVector_1 = require("../../objects/core/math/FVector");
const FBoxSphereBounds_1 = require("../../objects/core/math/FBoxSphereBounds");
const UnrealArray_1 = require("../../../util/UnrealArray");
const FStaticMaterial_1 = require("../objects/meshes/FStaticMaterial");
const Versions_1 = require("../../versions/Versions");
const Exceptions_1 = require("../../../exceptions/Exceptions");
const index_1 = require("../../../index");
const FRenderingObjectVersion_1 = require("../../versions/FRenderingObjectVersion");
const FStaticMeshLODResources_1 = require("../objects/meshes/FStaticMeshLODResources");
const FDistanceFieldVolumeData_1 = require("../../objects/engine/FDistanceFieldVolumeData");
const FEditorObjectVersion_1 = require("../../versions/FEditorObjectVersion");
class UStaticMesh extends UStaticMesh_Properties_1.UStaticMesh_Properties {
constructor() {
super(...arguments);
this.stripFlags = null;
this.bodySetup = null;
this.navCollision = null; // UNavCollision
this.lightingGuid = null;
this.sockets = null;
this.lods = new Array();
this.bounds = new FBoxSphereBounds_1.FBoxSphereBounds(new FVector_1.FVector(), new FVector_1.FVector(), 0);
this.lodsShareStaticLighting = false;
this.screenSize = new UnrealArray_1.UnrealArray(8, () => 0);
this.staticMaterials = Array();
this.materials = new Array();
}
deserialize(Ar, validPos) {
super.deserialize(Ar, validPos);
this.stripFlags = new FStripDataFlags_1.FStripDataFlags(Ar);
const cooked = Ar.readBoolean();
this.bodySetup = Ar.readObject();
this.navCollision = Ar.ver >= Versions_1.VER_UE4_STATIC_MESH_STORE_NAV_COLLISION ? Ar.readObject() : null;
if (!this.stripFlags.isEditorDataStripped) {
}
this.lightingGuid = new Guid_1.FGuid(Ar);
const socketLength = Ar.readInt32();
this.sockets = new Array(socketLength);
for (let i = 0; i < socketLength; ++i) {
this.sockets[i] = Ar.readObject();
}
if (!this.stripFlags.isEditorDataStripped)
// TODO https://github.com/gildor2/UEViewer/blob/master/Unreal/UnMesh4.cpp#L2382
throw new Exceptions_1.ParserException("Static Mesh with Editor Data not implemented yet");
// this if block doesn't always make sense to me:
// https://github.com/FabianFG/JFortniteParse/blob/85c07b3d8b4e89e8d5a97a55ba621ee2ec9a459b/src/main/kotlin/me/fungames/jfortniteparse/ue4/assets/exports/UStaticMesh.kt#L64
// within the if block which is used if cooked == true there are multiple extra checks of the cooked variable
// even tho it is never reassigned and it is marked as non changeable ('val')
// i guess this is an issue so therefore im skipping some checks
// serialize FStaticMeshRenderData
if (cooked) {
if (Ar.versions.get("StaticMesh.KeepMobileMinLODSettingOnDesktop")) {
// The serialization of this variable is cvar-dependent in UE4, so there's no clear way to understand
// if it should be serialize in our code or not.
Ar.readInt32(); // MinMobileLODIdx
}
/*if (!cooked) { ^ read above
Ar.readTArray { Ar.readInt32() } // WedgeMap
Ar.readTArray { Ar.readInt32() } // MaterialIndexToImportIndex
}*/
const lodsLength = Ar.readInt32();
this.lods = new Array(lodsLength);
for (let i = 0; i < lodsLength; ++i) {
this.lods[i] = new FStaticMeshLODResources_1.FStaticMeshLODResources(Ar);
}
if (Ar.game >= index_1.Game.GAME_UE4(23))
Ar.readUInt8(); // NumInlinedLODs
// {...} ^ read above
if (Ar.ver >= Versions_1.VER_UE4_RENAME_CROUCHMOVESCHARACTERDOWN) {
let stripped = false;
if (Ar.ver >= Versions_1.VER_UE4_RENAME_WIDGET_VISIBILITY) {
const stripFlags2 = new FStripDataFlags_1.FStripDataFlags(Ar);
stripped = stripFlags2.isDataStrippedForServer;
if (Ar.game >= index_1.Game.GAME_UE4(21)) {
// 4.21 uses additional strip flag for distance field
stripped = Boolean(Number(stripped) | Number(stripFlags2.isClassDataStripped(1)));
}
}
if (!stripped) {
// serialize FDistanceFieldVolumeData for each LOD
for (let i = 0; i < lodsLength; ++i) {
const hasDistanceDataField = Ar.readBoolean();
if (hasDistanceDataField)
new FDistanceFieldVolumeData_1.FDistanceFieldVolumeData(Ar); // VolumeData
}
}
}
this.bounds = new FBoxSphereBounds_1.FBoxSphereBounds(Ar);
// Note: bLODsShareStaticLighting field exists in all engine versions except UE4.15.
if (Ar.versions.get("StaticMesh.HasLODsShareStaticLighting"))
this.lodsShareStaticLighting = Ar.readBoolean();
if (Ar.game < index_1.Game.GAME_UE4(14))
Ar.readBoolean(); // bReducedBySimplygon
if (FRenderingObjectVersion_1.FRenderingObjectVersion.get(Ar) < FRenderingObjectVersion_1.EFRenderingObjectVersion.TextureStreamingMeshUVChannelData) {
// StreamingTextureFactors
// StreamingTextureFactor for each UV set
for (let i = 0; i < UStaticMesh.MAX_STATIC_UV_SETS_UE4; ++i)
Ar.readFloat32();
Ar.readFloat32(); // MaxStreamingTextureFactor
}
// {...} ^ read above
// ScreenSize for each LOD
const maxNumLods = Ar.game >= index_1.Game.GAME_UE4(9) ? UStaticMesh.MAX_STATIC_LODS_UE4 : 4;
for (let i = 0; i < maxNumLods; ++i) {
if (Ar.game >= index_1.Game.GAME_UE4(20))
Ar.readBoolean(); // bFloatCooked
this.screenSize[i] = Ar.readFloat32();
}
} // end of FStaticMeshRenderData
if (cooked && Ar.game >= index_1.Game.GAME_UE4(20)) {
const hasOccluderData = Ar.readBoolean();
if (hasOccluderData) {
const _length1 = Ar.readInt32();
for (let i = 0; i < _length1; ++i)
new FVector_1.FVector(Ar); // Vertices
const _length2 = Ar.readInt32();
for (let i = 0; i < _length2; ++i)
Ar.readUInt16(); // Indices
}
}
if (Ar.game >= index_1.Game.GAME_UE4(14)) {
// Serialize following data to obtain material references for UE4.14+.
// Don't bother serializing anything beyond this point in earlier versions.
// Note: really, UE4 uses VER_UE4_SPEEDTREE_STATICMESH
const hasSpeedTreeWind = Ar.readBoolean();
if (hasSpeedTreeWind) {
// TODO - FSpeedTreeWind serialization
// Ignore remaining data
}
else {
if (FEditorObjectVersion_1.FEditorObjectVersion.get(Ar) >= FEditorObjectVersion_1.EFEditorObjectVersion.RefactorMeshEditorMaterials) {
// UE4.14+ - "Materials" are deprecated, added StaticMaterials
const staticMaterialsLength = Ar.readInt32();
this.staticMaterials = new Array(staticMaterialsLength);
for (let i = 0; i < staticMaterialsLength; ++i)
this.staticMaterials[i] = new FStaticMaterial_1.FStaticMaterial(Ar);
}
}
}
this.materials = this.staticMaterials.map(it => it.materialInterface).filter(it => it != null);
// Drop remaining SpeedTree data
if (validPos > 0)
Ar.pos = validPos;
}
serialize(Ar) {
throw new Exceptions_1.ParserException("Serializing UStaticMesh not supported");
}
}
exports.UStaticMesh = UStaticMesh;
UStaticMesh.MAX_STATIC_UV_SETS_UE4 = 8;
UStaticMesh.MAX_STATIC_LODS_UE4 = 8;