示例#1
0
        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;