def __init__(self, reader: BinaryStream):
        StripFlags = FStripDataFlags(
            reader, Versions.VER_UE4_STATIC_SKELETAL_MESH_SERIALIZATION_FIX)
        self.NumTexCoords = reader.readInt32()
        self.Strides = reader.readInt32() if reader.game < GAME_UE4(19) else -1

        self.NumVertices = reader.readInt32()
        self.UseFullPrecisionUVs = reader.readBool()
        self.UseHighPrecisionTangentBasis = reader.readBool(
        ) if reader.game >= GAME_UE4(12) else False

        if not StripFlags.isDataStrippedForServer():
            if reader.game < GAME_UE4(19):
                self.UV = reader.readTArray_W_Arg(
                    FStaticMeshUVItem().read, reader,
                    self.UseHighPrecisionTangentBasis, self.NumTexCoords,
                    self.UseFullPrecisionUVs)
            else:
                # reader.readBulkTArray()
                itemSize = reader.readInt32()
                itemCount = reader.readInt32()

                if itemCount != self.NumVertices:
                    raise ParserException(
                        f"{itemCount=} != {self.NumVertices=}")

                pos = reader.tell()
                self.UV = [
                    FStaticMeshUVItem().construct(
                        FStaticMeshUVItem().serialize_tangents(
                            reader, self.UseHighPrecisionTangentBasis), [])
                    for _ in range(self.NumVertices)
                ]

                if reader.tell() - pos != itemSize * itemCount:
                    raise ParserException(
                        f"Read incorrect amount of tangent bytes, at {reader.tell()}, should be: {pos + itemSize * itemCount} behind: {pos + (itemSize * itemCount) - pos}"
                    )

                itemSize = reader.readInt32()
                itemCount = reader.readInt32()
                if itemCount != self.NumVertices * self.NumTexCoords:
                    raise ParserException(
                        f"{itemCount=} != NumVertices * NumTexCoords = {self.NumVertices * self.NumTexCoords}"
                    )

                pos = reader.tell()
                for i in range(self.NumVertices):
                    self.UV[i].UV = FStaticMeshUVItem().serialize_texcoords(
                        reader, self.NumTexCoords, self.UseFullPrecisionUVs)

                if reader.tell() - pos != itemSize * itemCount:
                    raise ParserException(
                        f"Read incorrect amount of Texture Coordinate bytes, at {reader.tell()}, should be: {pos + itemSize * itemCount} behind: {pos + (itemSize * itemCount) - pos}"
                    )
        else:
            self.UV = []
Example #2
0
 def readBulkTArray(self, func, *args) -> list:
     elementSize = self.readInt32()
     savePos = self.tell()
     array = self.readTArray(func, *args)
     if self.tell() != savePos + 4 + len(array) * elementSize:
         raise ParserException(
             f"RawArray item size mismatch: expected {elementSize}, serialized {(self.tell() - savePos) / len(array)}"
         )
     return array
Example #3
0
    def deserializeUnVersioned(self, type=None):
        reader = self.reader
        properties = {}
        pos = reader.tell()
        Header = FUnversionedHeader(reader)
        if not Header.hasValues():
            return properties

        Schema = self.reader.getmappings().get_schema(type or self.type)
        if Schema is None:
            raise ParserException(f"Missing prop mappings for type {type or self.type}")
        tags = []
        num = 1
        if Header.HasNonZeroValues:
            iterator = FIterator(Header)
            while not iterator.bDone:
                current = iterator.Current

                propmappings = Schema.TryGetProp(iterator._schemaIt)
                if propmappings is None:
                    logger.error("Missing Mappings for index {} cannot proceed with serilization".format(iterator._schemaIt))
                    return properties
                    # raise ParserException("Missing Mappings for index {}".format(iterator._schemaIt))
                Tag = FPropertyTag(None, propmappings)
                tags.append(Tag)

                if iterator.IsNonZero:
                    try:
                        pos = reader.tell()
                        obj = BaseProperty.ReadAsObject(
                        self.reader, Tag, Tag.Type, ReadType.NORMAL)
                        logger.debug(f"{pos} -> {reader.tell()} : {Tag.Name}")
                    except Exception as e:
                        logger.debug(f"Failed to read values for {Tag.Name.string}, {e}")
                        obj = None

                    self.addProp(Tag, obj, num, properties)
                    if obj is None:
                        break

                else: # Zero prop
                    try:
                        pos = reader.tell()
                        obj = BaseProperty.ReadAsObject(
                        self.reader, Tag, Tag.Type, ReadType.ZERO)
                        logger.debug(f"{pos} -> {reader.tell()} : {Tag.Name}")
                    except Exception as e:
                        logger.debug(f"Failed to read values for {Tag.Name.string}, {e}")
                        obj = None

                    self.addProp(Tag, obj, num, properties)

                if current.IsLast:
                    break
                iterator.MoveNext()
        return properties
Example #4
0
 def getmappings(self):
     if hasattr(self, "mappings"):
         return self.mappings
     raise ParserException("mappings are not attached")
Example #5
0
 def readBytes(self, length):
     if self.size == self.position:
         raise ParserException("Cannot read beyond end of stream")
     return self.base_stream.read(length)
Example #6
0
    def __init__(self, reader: BinaryStream) -> None:
        Tag = reader.readUInt32()
        if Tag != PACKAGE_FILE_TAG and Tag != PACKAGE_FILE_TAG_SWAPPED:
            raise InvalidMagic("Not a UE package")

        if Tag == PACKAGE_FILE_TAG_SWAPPED:
            raise NotImplementedError(
                "Byte swapping for packages is not implemented")

        LegacyFileVersion = reader.readInt32()
        if LegacyFileVersion < 0:
            if LegacyFileVersion < -7:
                raise ParserException("Can not load UE3 packages.")
            if LegacyFileVersion != -4:
                reader.readInt32()  # VersionUE3

            version = reader.readInt32()
            self.FileVersionUE4 = EUnrealEngineObjectUE4Version(
                version)  # version

            self.FileVersionLicenseeUE4 = EUnrealEngineObjectLicenseeUE4Version(
                reader.readInt32())  # Licensee Version
            if LegacyFileVersion <= -2:
                self.CustomVersionContainer = FCustomVersionContainer(reader)

            if self.FileVersionUE4.value != 0 and self.FileVersionLicenseeUE4.value != 0:
                self.bUnversioned = True
        else:
            raise ParserException("Can not load UE3 packages.")

        self.TotalHeaderSize = reader.readInt32()
        self.FolderName = reader.readFString()

        self.PackageFlags = reader.readUInt32()
        with suppress(ValueError):
            self.PackageFlags = EPackageFlags(self.PackageFlags)

        self.NameCount = reader.readInt32()
        self.NameOffset = reader.readInt32()

        if self.FileVersionUE4.value >= EUnrealEngineObjectUE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID.value:
            self.LocalizationId = reader.readFString()

        if self.FileVersionUE4.value >= EUnrealEngineObjectUE4Version.VER_UE4_SERIALIZE_TEXT_IN_PACKAGES.value or self.FileVersionUE4.value == 0:
            self.GatherableTextDataCount = reader.readInt32()
            self.GatherableTextDataOffset = reader.readInt32()

        self.ExportCount = reader.readInt32()
        self.ExportOffset = reader.readInt32()
        self.ImportCount = reader.readInt32()
        self.ImportOffset = reader.readInt32()
        self.DependsOffset = reader.readInt32()
        if self.FileVersionUE4.value >= EUnrealEngineObjectUE4Version.VER_UE4_ADD_STRING_ASSET_REFERENCES_MAP.value or self.FileVersionUE4.value == 0:
            self.SoftPackageReferencesCount = reader.readInt32()
            self.SoftPackageReferencesOffset = reader.readInt32()

        if self.FileVersionUE4.value >= EUnrealEngineObjectUE4Version.VER_UE4_ADDED_SEARCHABLE_NAMES.value or self.FileVersionUE4.value == 0:
            self.SearchableNamesOffset = reader.readInt32()

        self.ThumbnailTableOffset = reader.readInt32()
        self.Guid = FGuid(reader)

        if reader.game == EUEVersion.GAME_VALORANT:
            reader.readInt64()  # valorant

        self.GenerationCount = reader.readInt32()
        self.Generations = []
        if self.GenerationCount > 0:
            for _ in range(self.GenerationCount):
                self.Generations.append(FGenerationInfo(reader))

        if self.FileVersionUE4.value >= EUnrealEngineObjectUE4Version.VER_UE4_ENGINE_VERSION_OBJECT.value or self.FileVersionUE4.value == 0:
            self.SavedByEngineVersion = FEngineVersion(reader)

        if self.GetFileVersionUE4(
        ).value >= EUnrealEngineObjectUE4Version.VER_UE4_PACKAGE_SUMMARY_HAS_COMPATIBLE_ENGINE_VERSION.value or self.FileVersionUE4.value == 0:
            self.CompatibleWithEngineVersion = FEngineVersion(reader)

        self.CompressionFlags = ECompressionFlags(reader.readUInt32())
        if self.CompressionFlags.name != "COMPRESS_None":
            raise ParserException(
                f"Incompatible compression flags {self.CompressionFlags.name}")

        self.CompressedChunks: List[FCompressedChunk] = reader.readTArray(
            FCompressedChunk)
        if len(self.CompressedChunks) != 0:  # "CompressedChunks"
            raise ParserException("Package level compression is enabled")

        self.PackageSource = reader.readUInt32()
        self.AdditionalPackagesToCook = reader.readTArray(
            reader.readFString)  # AdditionalPackagesToCook

        if LegacyFileVersion > -7:
            if reader.readInt32() != 0:  # "NumTextureAllocations"
                raise ParserException("Can't load legacy UE3 file")

        # if reader.Ver >= VER_UE4_ASSET_REGISTRY_TAGS
        self.AssetRegistryDataOffset = reader.readInt32()

        self.BulkDataStartOffset = reader.readInt64()
        self.WorldTileInfoDataOffset = reader.readInt32()
        self.ChunkIDs = reader.readTArray(reader.readInt32)
        self.PreloadDependencyCount = reader.readInt32()
        self.PreloadDependencyOffset = reader.readInt32()
Example #7
0
    def __init__(self,
                 uasset: BinaryStream,
                 uexp: BinaryStream = None,
                 ubulk: BinaryStream = None,
                 provider: "Provider" = None) -> None:
        self.reader = uasset
        self.reader.set_ar_version(provider.GameInfo.UEVersion)
        self.reader.provider = provider
        self.reader.PackageReader = self

        self.PackageFileSummary = FPackageFileSummary(self.reader)
        self.Summary = self.PackageFileSummary
        pos = self.reader.tell()
        self.NameMap = self.SerializeNameMap()
        self.reader.NameMap = self.NameMap

        self.ImportMap = self.SerializeImportMap()
        self.ExportMap = self.SerializeExportMap()

        filever = self.PackageFileSummary.FileVersionUE4
        if filever > 0:
            self.reader.version = filever

        self.reader.ubulk_stream = ubulk

        if uexp is not None:
            self.reader.change_stream(uexp)
        elif self.PackageFileSummary.FileVersionUE4.value == 0:  # Cooked
            return
        else:  # not cooked
            self.reader.seek(pos, 0)
            self.reader.change_stream(self.reader.read())

        for Export in self.ExportMap:
            if Export.ClassIndex.IsNull:
                ExportType = self.reader.readFName()
            elif Export.ClassIndex.IsExport:
                ExportType = self.ExportMap[
                    Export.ClassIndex.AsExport].SuperIndex.Resource.ObjectName
            elif Export.ClassIndex.IsImport:
                ExportType = self.ImportMap[
                    Export.ClassIndex.AsImport].ObjectName
            else:
                raise ParserException("failed to get export type")
            Export.name = ExportType

            self.reader.seek(
                Export.SerialOffset - self.PackageFileSummary.TotalHeaderSize,
                0)

            self.reader.bulk_offset = Export.SerialSize + self.PackageFileSummary.TotalHeaderSize  # ?

            pos = self.reader.base_stream.tell()
            ExportData = Registry().get_export_reader(ExportType.string,
                                                      Export, self.reader)
            ExportData.deserialize(pos + Export.SerialSize)
            Export.exportObject = ExportData

            # export event
            trigger = provider.Triggers.get(ExportType.string, False)
            if trigger:
                trigger(Export)

            position = self.reader.base_stream.tell()
            if position != pos + Export.SerialSize:
                logger.debug(
                    f"Didn't read ExportType {ExportType.string} properly, at {position}, should be: {pos + Export.SerialSize} behind: {pos + Export.SerialSize - position}"
                )
Example #8
0
    def deserialize(self, validpos) -> None:
        super().deserialize(validpos)
        reader = self.reader

        self.StripData = FStripDataFlags(reader)
        bCooked = reader.readBool()
        self.BodySetup = reader.readObject()

        if reader.version >= Versions.VER_UE4_STATIC_MESH_STORE_NAV_COLLISION:
            self.NavCollision = reader.readObject()

        if not self.StripData.isEditorDataStripped():
            if reader.version < Versions.VER_UE4_DEPRECATED_STATIC_MESH_THUMBNAIL_PROPERTIES_REMOVED:
                FRotator(reader)  # dummyThumbnailAngle
                reader.readFloat()  # dummyThumbnailDistance
            highResSourceMeshName = reader.readString(
            )  # highResSourceMeshName
            highResSourceMeshCRC = reader.readUInt32()  #

        self.LightingGuid = FGuid(reader)

        self.Sockets = reader.readTArray(reader.readObject)

        if not self.StripData.isEditorDataStripped:
            raise ParserException("Mesh with editor data not supported")

        # FStaticMeshRenderData
        if bCooked:
            if not bCooked:  # how possible
                pass  # https://github.com/FabianFG/JFortniteParse/blob/558fb2b96985aad5b90c96c8f28950021cf801a0/src/main/kotlin/me/fungames/jfortniteparse/ue4/assets/exports/UStaticMesh.kt#L59
            # if unversioned MinMobileLODIdx int32
            self.LODs = reader.readTArray_W_Arg(FStaticMeshLODResources,
                                                reader)  #TODO fix this

            if reader.game >= GAME_UE4(23):
                NumInlinedLODs = reader.readUInt8()

            if bCooked:
                if reader.version >= Versions.VER_UE4_RENAME_CROUCHMOVESCHARACTERDOWN:
                    isStripped = False
                    if reader.version >= Versions.VER_UE4_RENAME_WIDGET_VISIBILITY:
                        stripflag = FStripDataFlags(reader)
                        isStripped = stripflag.isDataStrippedForServer()
                        if reader.game >= GAME_UE4(21):
                            # 4.21 uses additional strip flag for distance field
                            distanceFieldDataStripFlag = 1
                            isStripped = isStripped | stripflag.isClassDataStripped(
                                distanceFieldDataStripFlag)  # ?
                    if not isStripped:
                        # serialize FDistanceFieldVolumeData for each LOD
                        for _ in range(len(self.LODs) - 1):  # wut why
                            hasDistanceDataField = reader.readBool()
                            if hasDistanceDataField:
                                FDistanceFieldVolumeData(reader)  # VolumeData

            self.Bounds = FBoxSphereBounds(reader)

            if reader.game != GAME_UE4(15):
                self.LODsShareStaticLighting = reader.readBool()

            if reader.game < GAME_UE4(15):
                reader.readBool()  # bReducedBySimplygon

            if FRenderingObjectVersion().get(
                    reader
            ) < FRenderingObjectVersion.TextureStreamingMeshUVChannelData:
                for _ in range(
                        MAX_STATIC_UV_SETS_UE4):  # StreamingTextureFactors
                    reader.readFloat(
                    )  # StreamingTextureFactor for each UV set
                reader.readFloat()  # MaxStreamingTextureFactor

            if bCooked:
                maxNumLods = MAX_STATIC_LODS_UE4 if reader.game >= GAME_UE4(
                    9) else 4
                for x in range(maxNumLods):
                    if reader.game >= GAME_UE4(20):
                        reader.readBool()  # bFloatCooked
                    self.ScreenSize.append(reader.readFloat())
        # End of FStaticMeshRenderData

        if bCooked and reader.game >= GAME_UE4(20):
            hasOccluderData = reader.readBool()
            if hasOccluderData:
                reader.readTArray(FVector, reader)  # Vertices
                reader.readTArray(reader.readUInt16)  # Indics

        if reader.game >= GAME_UE4(14):
            hasSpeedTreeWind = reader.readBool()
            if hasSpeedTreeWind:
                pass  # ignore
            else:
                if FEditorObjectVersion().get(
                        reader
                ) >= FEditorObjectVersion.RefactorMeshEditorMaterials:
                    # UE4.14+ - "Materials" are deprecated, added StaticMaterials
                    self.StaticMaterials = reader.readTArray_W_Arg(
                        FStaticMaterial, reader)

        if len(self.Materials) == 0 and len(self.StaticMaterials) > 0:
            material: FStaticMaterial
            for material in self.StaticMaterials:
                self.Materials.append(material.MaterialInterface)