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 = []
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
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
def getmappings(self): if hasattr(self, "mappings"): return self.mappings raise ParserException("mappings are not attached")
def readBytes(self, length): if self.size == self.position: raise ParserException("Cannot read beyond end of stream") return self.base_stream.read(length)
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()
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}" )
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)