internal FPackageFileSummary(FArchive Ar) { Tag = Ar.Read <uint>(); /* * The package file version number when this package was saved. * * Lower 16 bits stores the UE3 engine version * Upper 16 bits stores the UE4/licensee version * For newer packages this is -7 * -2 indicates presence of enum-based custom versions * -3 indicates guid-based custom versions * -4 indicates removal of the UE3 version. Packages saved with this ID cannot be loaded in older engine versions * -5 indicates the replacement of writing out the "UE3 version" so older versions of engine can gracefully fail to open newer packages * -6 indicates optimizations to how custom versions are being serialized * -7 indicates the texture allocation info has been removed from the summary * -8 indicates that the UE5 version has been added to the summary */ const int CurrentLegacyFileVersion = -8; var legacyFileVersion = CurrentLegacyFileVersion; if (Tag == PACKAGE_FILE_TAG_ONE) // SOD2, "one" { Ar.Game = EGame.GAME_StateOfDecay2; Ar.Ver = Ar.Game.GetVersion(); legacyFileVersion = Ar.Read <int>(); // seems to be always int.MinValue bUnversioned = true; FileVersionUE = Ar.Ver; CustomVersionContainer = Array.Empty <FCustomVersion>(); FolderName = "None"; PackageFlags = EPackageFlags.PKG_FilterEditorOnly; goto afterPackageFlags; } if (Tag != PACKAGE_FILE_TAG && Tag != PACKAGE_FILE_TAG_SWAPPED) { throw new ParserException($"Invalid uasset magic: 0x{Tag:X8} != 0x{PACKAGE_FILE_TAG:X8}"); } // The package has been stored in a separate endianness than the linker expected so we need to force // endian conversion. Latent handling allows the PC version to retrieve information about cooked packages. if (Tag == PACKAGE_FILE_TAG_SWAPPED) { // Set proper tag. //Tag = PACKAGE_FILE_TAG; // Toggle forced byte swapping. throw new ParserException("Byte swapping for packages not supported"); } legacyFileVersion = Ar.Read <int>(); if (legacyFileVersion < 0) // means we have modern version numbers { if (legacyFileVersion < CurrentLegacyFileVersion) { // we can't safely load more than this because the legacy version code differs in ways we can not predict. // Make sure that the linker will fail to load with it. FileVersionUE.Reset(); FileVersionLicenseeUE = 0; throw new ParserException("Can't load legacy UE3 file"); } if (legacyFileVersion != -4) { var legacyUE3Version = Ar.Read <int>(); } FileVersionUE.FileVersionUE4 = Ar.Read <int>(); if (legacyFileVersion <= -8) { FileVersionUE.FileVersionUE5 = Ar.Read <int>(); } FileVersionLicenseeUE = Ar.Read <EUnrealEngineObjectLicenseeUEVersion>(); CustomVersionContainer = legacyFileVersion <= -2 ? Ar.ReadArray <FCustomVersion>() : Array.Empty <FCustomVersion>(); if (Ar.Versions.CustomVersions == null && CustomVersionContainer.Length > 0) { Ar.Versions.CustomVersions = CustomVersionContainer.ToList(); } if (FileVersionUE.FileVersionUE4 == 0 && FileVersionUE.FileVersionUE5 == 0 && FileVersionLicenseeUE == 0) { // this file is unversioned, remember that, then use current versions bUnversioned = true; FileVersionUE = Ar.Ver; FileVersionLicenseeUE = EUnrealEngineObjectLicenseeUEVersion.VER_LIC_AUTOMATIC_VERSION; } else { bUnversioned = false; // Only apply the version if an explicit version is not set if (!Ar.Versions.bExplicitVer) { Ar.Ver = FileVersionUE; } } } else { // This is probably an old UE3 file, make sure that the linker will fail to load with it. throw new ParserException("Can't load legacy UE3 file"); } TotalHeaderSize = Ar.Read <int>(); FolderName = Ar.ReadFString(); PackageFlags = Ar.Read <EPackageFlags>(); /*if (PackageFlags.HasFlag(EPackageFlags.PKG_FilterEditorOnly)) * { * TODO Ar.SetFilterEditorOnly(true); * }*/ afterPackageFlags: NameCount = Ar.Read <int>(); NameOffset = Ar.Read <int>(); if (!PackageFlags.HasFlag(EPackageFlags.PKG_FilterEditorOnly)) { if (FileVersionUE >= EUnrealEngineObjectUE4Version.ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID) { LocalizationId = Ar.ReadFString(); } } if (FileVersionUE >= EUnrealEngineObjectUE4Version.SERIALIZE_TEXT_IN_PACKAGES) { GatherableTextDataCount = Ar.Read <int>(); GatherableTextDataOffset = Ar.Read <int>(); } ExportCount = Ar.Read <int>(); ExportOffset = Ar.Read <int>(); ImportCount = Ar.Read <int>(); ImportOffset = Ar.Read <int>(); DependsOffset = Ar.Read <int>(); if (FileVersionUE < EUnrealEngineObjectUE4Version.OLDEST_LOADABLE_PACKAGE || FileVersionUE > EUnrealEngineObjectUE4Version.AUTOMATIC_VERSION) { Generations = Array.Empty <FGenerationInfo>(); ChunkIds = Array.Empty <int>(); return; // we can't safely load more than this because the below was different in older files. } if (FileVersionUE >= EUnrealEngineObjectUE4Version.ADD_STRING_ASSET_REFERENCES_MAP) { SoftPackageReferencesCount = Ar.Read <int>(); SoftPackageReferencesOffset = Ar.Read <int>(); } if (FileVersionUE >= EUnrealEngineObjectUE4Version.ADDED_SEARCHABLE_NAMES) { SearchableNamesOffset = Ar.Read <int>(); } ThumbnailTableOffset = Ar.Read <int>(); if (Ar.Game == EGame.GAME_Valorant) { Ar.Position += 8; } Guid = Ar.Read <FGuid>(); if (!PackageFlags.HasFlag(EPackageFlags.PKG_FilterEditorOnly)) { if (FileVersionUE >= EUnrealEngineObjectUE4Version.ADDED_PACKAGE_OWNER) { PersistentGuid = Ar.Read <FGuid>(); } else { // By assigning the current package guid, we maintain a stable persistent guid, so we can reference this package even if it wasn't resaved. PersistentGuid = Guid; } // The owner persistent guid was added in VER_UE4_ADDED_PACKAGE_OWNER but removed in the next version VER_UE4_NON_OUTER_PACKAGE_IMPORT if (FileVersionUE >= EUnrealEngineObjectUE4Version.ADDED_PACKAGE_OWNER && FileVersionUE < EUnrealEngineObjectUE4Version.NON_OUTER_PACKAGE_IMPORT) { var ownerPersistentGuid = Ar.Read <FGuid>(); } } Generations = Ar.ReadArray <FGenerationInfo>(); if (FileVersionUE >= EUnrealEngineObjectUE4Version.ENGINE_VERSION_OBJECT) { SavedByEngineVersion = new FEngineVersion(Ar); FixCorruptEngineVersion(FileVersionUE, SavedByEngineVersion); } else { var engineChangelist = Ar.Read <int>(); if (engineChangelist != 0) { SavedByEngineVersion = new FEngineVersion(4, 0, 0, (uint)engineChangelist, string.Empty); } } if (FileVersionUE >= EUnrealEngineObjectUE4Version.PACKAGE_SUMMARY_HAS_COMPATIBLE_ENGINE_VERSION) { CompatibleWithEngineVersion = new FEngineVersion(Ar); FixCorruptEngineVersion(FileVersionUE, CompatibleWithEngineVersion); } else { CompatibleWithEngineVersion = SavedByEngineVersion; }
internal FPackageFileSummary(FAssetArchive Ar) { Tag = Ar.Read <uint>(); if (Tag == PACKAGE_FILE_TAG_ONE) // SOD2, "one" { Ar.Game = EGame.GAME_SOD2; Ar.Ver = Ar.Game.GetVersion(); var legacyFileVersion = Ar.Read <int>(); // seems to be always int.MinValue bUnversioned = true; FileVersionUE4 = (EUnrealEngineObjectUE4Version)Ar.Ver; CustomVersionContainer = Array.Empty <FCustomVersion>(); FolderName = "None"; PackageFlags = EPackageFlags.PKG_FilterEditorOnly; goto afterPackageFlags; } if (Tag != PACKAGE_FILE_TAG && Tag != PACKAGE_FILE_TAG_SWAPPED) { throw new ParserException($"Invalid uasset magic: 0x{Tag:X8} != 0x{PACKAGE_FILE_TAG:X8}"); } // The package has been stored in a separate endianness than the linker expected so we need to force // endian conversion. Latent handling allows the PC version to retrieve information about cooked packages. if (Tag == PACKAGE_FILE_TAG_SWAPPED) { // Set proper tag. //Tag = PACKAGE_FILE_TAG; // Toggle forced byte swapping. throw new ParserException("Byte swapping for packages not supported"); } /* * The package file version number when this package was saved. * * Lower 16 bits stores the UE3 engine version * Upper 16 bits stores the UE4/licensee version * For newer packages this is -7 * -2 indicates presence of enum-based custom versions * -3 indicates guid-based custom versions * -4 indicates removal of the UE3 version. Packages saved with this ID cannot be loaded in older engine versions * -5 indicates the replacement of writing out the "UE3 version" so older versions of engine can gracefully fail to open newer packages * -6 indicates optimizations to how custom versions are being serialized * -7 indicates the texture allocation info has been removed from the summary */ const int CurrentLegacyFileVersion = -7; LegacyFileVersion = Ar.Read <int>(); if (LegacyFileVersion < 0) // means we have modern version numbers { if (LegacyFileVersion < CurrentLegacyFileVersion) { // we can't safely load more than this because the legacy version code differs in ways we can not predict. // Make sure that the linker will fail to load with it. throw new ParserException("Can't load legacy UE3 file"); } LegacyUE3Version = LegacyFileVersion != -4 ? Ar.Read <LegacyUE3Version>() : 0; FileVersionUE4 = Ar.Read <EUnrealEngineObjectUE4Version>(); FileVersionLicenseUE4 = Ar.Read <EUnrealEngineObjectLicenseeUE4Version>(); CustomVersionContainer = LegacyFileVersion <= -2 ? Ar.ReadArray <FCustomVersion>() : Array.Empty <FCustomVersion>(); if (Ar.Versions.CustomVersions == null && CustomVersionContainer.Length > 0) { Ar.Versions.CustomVersions = CustomVersionContainer.ToList(); } if (FileVersionUE4 == 0 && FileVersionLicenseUE4 == 0) { // this file is unversioned, remember that, then use current versions bUnversioned = true; // set the versions to latest here, etc. FileVersionUE4 = (EUnrealEngineObjectUE4Version)Ar.Ver; FileVersionLicenseUE4 = EUnrealEngineObjectLicenseeUE4Version.VER_LIC_AUTOMATIC_VERSION; } else { bUnversioned = false; // Only apply the version if an explicit version is not set if (Ar.Ver == UE4Version.VER_UE4_DETERMINE_BY_GAME) { Ar.Ver = (UE4Version)FileVersionUE4; } } } else { // This is probably an old UE3 file, make sure that the linker will fail to load with it. throw new ParserException("Can't load legacy UE3 file"); } TotalHeaderSize = Ar.Read <int>(); FolderName = Ar.ReadFString(); PackageFlags = Ar.Read <EPackageFlags>(); afterPackageFlags: NameCount = Ar.Read <int>(); NameOffset = Ar.Read <int>(); LocalizationId = !PackageFlags.HasFlag(EPackageFlags.PKG_FilterEditorOnly) && FileVersionUE4 >= VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID?Ar.ReadFString() : null; if (FileVersionUE4 >= VER_UE4_SERIALIZE_TEXT_IN_PACKAGES) { GatherableTextDataCount = Ar.Read <int>(); GatherableTextDataOffset = Ar.Read <int>(); } else { GatherableTextDataCount = GatherableTextDataOffset = 0; } ExportCount = Ar.Read <int>(); ExportOffset = Ar.Read <int>(); ImportCount = Ar.Read <int>(); ImportOffset = Ar.Read <int>(); DependsOffset = Ar.Read <int>(); if (FileVersionUE4 is < VER_UE4_OLDEST_LOADABLE_PACKAGE or > VER_UE4_AUTOMATIC_VERSION) { SoftPackageReferencesCount = 0; SoftPackageReferencesOffset = 0; SearchableNamesOffset = 0; ThumbnailTableOffset = 0; Guid = default; Generations = Array.Empty <FGenerationInfo>(); SavedByEngineVersion = default; CompatibleWithEngineVersion = default; CompressionFlags = COMPRESS_None; PackageSource = 0; AssetRegistryDataOffset = 0; WorldTileInfoDataOffset = 0; ChunkIds = Array.Empty <int>(); AdditionalPackagesToCook = Array.Empty <string>(); CompressedChunks = Array.Empty <FCompressedChunk>(); PreloadDependencyCount = 0; PreloadDependencyOffset = 0; return; // we can't safely load more than this because the below was different in older files. } if (FileVersionUE4 >= VER_UE4_ADD_STRING_ASSET_REFERENCES_MAP) { SoftPackageReferencesCount = Ar.Read <int>(); SoftPackageReferencesOffset = Ar.Read <int>(); } else { SoftPackageReferencesCount = SoftPackageReferencesOffset = 0; } SearchableNamesOffset = FileVersionUE4 >= VER_UE4_ADDED_SEARCHABLE_NAMES?Ar.Read <int>() : 0; ThumbnailTableOffset = Ar.Read <int>(); if (Ar.Game == EGame.GAME_VALORANT) { Ar.Position += 8; } Guid = Ar.Read <FGuid>(); Generations = Ar.ReadArray <FGenerationInfo>(); if (FileVersionUE4 >= VER_UE4_ENGINE_VERSION_OBJECT) { SavedByEngineVersion = new FEngineVersion(Ar); if (FileVersionUE4 < VER_UE4_CORRECT_LICENSEE_FLAG && SavedByEngineVersion.Major == 4 && SavedByEngineVersion.Minor == 26 && SavedByEngineVersion.Patch == 0 && SavedByEngineVersion.Changelist >= 12740027 && SavedByEngineVersion.IsLicenseeVersion()) { SavedByEngineVersion.Set(4, 26, 0, SavedByEngineVersion.Changelist, SavedByEngineVersion.Branch); } } else { var engineChangelist = Ar.Read <int>(); SavedByEngineVersion = engineChangelist == 0 ? null : new FEngineVersion(4, 0, 0, (uint)engineChangelist, string.Empty); } CompatibleWithEngineVersion = FileVersionUE4 >= VER_UE4_PACKAGE_SUMMARY_HAS_COMPATIBLE_ENGINE_VERSION ? new FEngineVersion(Ar) : SavedByEngineVersion;