Ejemplo n.º 1
0
        public override void ReadEvent(FArchive archive)
        {
            int startPosition = archive.Position;

            var info = new EventInfo
            {
                Id          = archive.ReadFString(),
                Group       = archive.ReadFString(),
                Metadata    = archive.ReadFString(),
                StartTime   = archive.ReadUInt32(),
                EndTime     = archive.ReadUInt32(),
                SizeInBytes = archive.ReadInt32()
            };

            int infoSize = archive.Position - startPosition;

            using var decryptedReader = (Unreal.Core.BinaryReader)base.DecryptBuffer(archive, info.SizeInBytes);

            _writer.Write(infoSize + decryptedReader.Bytes.Length); //Chunk Size
            _writer.Write(info.Id);
            _writer.Write(info.Group);
            _writer.Write(info.Metadata);
            _writer.Write(info.StartTime);
            _writer.Write(info.EndTime);
            _writer.Write(decryptedReader.Bytes.Length);    //Decrypted size
            _writer.Write(decryptedReader.Bytes.ToArray()); //Decrypted bytes
        }
Ejemplo n.º 2
0
        /// <summary>
        /// see https://github.com/EpicGames/UnrealEngine/blob/70bc980c6361d9a7d23f6d23ffe322a2d6ef16fb/Engine/Source/Runtime/NetworkReplayStreaming/LocalFileNetworkReplayStreaming/Private/LocalFileNetworkReplayStreaming.cpp#L363
        /// </summary>
        /// <param name="archive"></param>
        /// <returns></returns>
        protected override void ReadEvent(FArchive archive)
        {
            var info = new EventInfo
            {
                Id          = archive.ReadFString(),
                Group       = archive.ReadFString(),
                Metadata    = archive.ReadFString(),
                StartTime   = archive.ReadUInt32(),
                EndTime     = archive.ReadUInt32(),
                SizeInBytes = archive.ReadInt32()
            };

            _logger?.LogDebug($"Encountered event {info.Group} ({info.Metadata}) at {info.StartTime} of size {info.SizeInBytes}");

            // Every event seems to start with some unknown int
            if (info.Group == ReplayEventTypes.PLAYER_ELIMINATION)
            {
                var elimination = ParseElimination(archive, info);
                Replay.Eliminations.Add(elimination);
                return;
            }
            else if (info.Metadata == ReplayEventTypes.MATCH_STATS)
            {
                Replay.Stats = ParseMatchStats(archive, info);
                return;
            }
            else if (info.Metadata == ReplayEventTypes.TEAM_STATS)
            {
                Replay.TeamStats = ParseTeamStats(archive, info);
                return;
            }
            else if (info.Metadata == ReplayEventTypes.ENCRYPTION_KEY)
            {
                Replay.GameInformation.PlayerStateEncryptionKey = ParseEncryptionKeyEvent(archive, info);
                return;
            }
            else if (info.Metadata == ReplayEventTypes.CHARACTER_SAMPLE)
            {
                ParseCharacterSample(archive, info);
                return;
            }
            else if (info.Group == ReplayEventTypes.ZONE_UPDATE)
            {
                ParseZoneUpdateEvent(archive, info);
                return;
            }
            else if (info.Group == ReplayEventTypes.BATTLE_BUS)
            {
                ParseBattleBusFlightEvent(archive, info);
                return;
            }
            else if (info.Group == "fortBenchEvent")
            {
                return;
            }

            _logger?.LogWarning($"Unknown event {info.Group} ({info.Metadata}) of size {info.SizeInBytes}");
            // optionally throw?
            throw new UnknownEventException($"Unknown event {info.Group} ({info.Metadata}) of size {info.SizeInBytes}");
        }
Ejemplo n.º 3
0
        public override void ReadCheckpoint(FArchive archive)
        {
            int startPosition = archive.Position;

            var info = new CheckpointInfo
            {
                Id          = archive.ReadFString(),
                Group       = archive.ReadFString(),
                Metadata    = archive.ReadFString(),
                StartTime   = archive.ReadUInt32(),
                EndTime     = archive.ReadUInt32(),
                SizeInBytes = archive.ReadInt32()
            };

            int infoSize = archive.Position - startPosition;

            using var decrypted     = (Unreal.Core.BinaryReader)DecryptBuffer(archive, info.SizeInBytes);
            using var binaryArchive = (Unreal.Core.BinaryReader)Decompress(decrypted, decrypted.Bytes.Length);

            _writer.Write(infoSize + binaryArchive.Bytes.Length); //Chunk Size
            _writer.Write(info.Id);
            _writer.Write(info.Group);
            _writer.Write(info.Metadata);
            _writer.Write(info.StartTime);
            _writer.Write(info.EndTime);
            _writer.Write(binaryArchive.Bytes.Length);    //Decompressed checkpoint length
            _writer.Write(binaryArchive.Bytes.ToArray()); //Decompressed checkpoint
        }
Ejemplo n.º 4
0
 public FURL(FArchive Ar)
 {
     Protocol = Ar.ReadFString();
     Host     = Ar.ReadFString();
     Map      = Ar.ReadFString();
     Portal   = Ar.ReadFString();
     Op       = Ar.ReadArray(Ar.ReadFString);
     Port     = Ar.Read <int>();
     Valid    = Ar.ReadBoolean();
 }
        public FNiagaraDataInterfaceGPUParamInfo(FArchive Ar)
        {
            DataInterfaceHLSLSymbol = Ar.ReadFString();
            DIClassName             = Ar.ReadFString();

            if (FNiagaraCustomVersion.Get(Ar) >= FNiagaraCustomVersion.Type.AddGeneratedFunctionsToGPUParamInfo)
            {
                GeneratedFunctions = Ar.ReadArray(() => new FNiagaraDataInterfaceGeneratedFunction(Ar));
            }
        }
Ejemplo n.º 6
0
     public AssetObjectProperty(FArchive Ar, ReadType type)
     {
         Value = type switch
         {
             ReadType.ZERO => string.Empty,
             _ => Ar.ReadFString()
         };
     }
 }
        protected virtual PlayerElimination ParseElimination(FArchive archive, EventInfo info)
        {
            try
            {
                var elim = new PlayerElimination
                {
                    Info = info,
                };

                if (archive.EngineNetworkVersion >= EngineNetworkVersionHistory.HISTORY_FAST_ARRAY_DELTA_STRUCT && Major >= 9)
                {
                    archive.SkipBytes(85);
                    elim.Eliminated = ParsePlayer(archive);
                    elim.Eliminator = ParsePlayer(archive);
                }
                else
                {
                    if (Major <= 4 && Minor < 2)
                    {
                        archive.SkipBytes(12);
                    }
                    else if (Major == 4 && Minor <= 2)
                    {
                        archive.SkipBytes(40);
                    }
                    else
                    {
                        archive.SkipBytes(45);
                    }
                    elim.Eliminated = archive.ReadFString();
                    elim.Eliminator = archive.ReadFString();
                }

                elim.GunType = archive.ReadByte();
                elim.Knocked = archive.ReadUInt32AsBoolean();
                elim.Time    = info?.StartTime.MillisecondsToTimeStamp();
                return(elim);
            }
            catch (Exception ex)
            {
                _logger?.LogError($"Error while parsing PlayerElimination at timestamp {info.StartTime}");
                throw new PlayerEliminationException($"Error while parsing PlayerElimination at timestamp {info.StartTime}", ex);
            }
        }
Ejemplo n.º 8
0
        public FTextKey(FArchive Ar, ELocResVersion versionNum)
        {
            StrHash = 0;
            if (versionNum >= ELocResVersion.Optimized_CRC32)
            {
                StrHash = Ar.Read <uint>();
            }

            Str = Ar.ReadFString();
        }
Ejemplo n.º 9
0
        public FNameEntrySerialized(FArchive Ar)
        {
            Name = Ar.ReadFString();
#if NAME_HASHES
            NonCasePreservingHash = Ar.Read <ushort>();
            CasePreservingHash    = Ar.Read <ushort>();
#else
            Ar.Position += 4;
#endif
        }
Ejemplo n.º 10
0
        public FNameEntrySerialized(FArchive Ar)
        {
            var bHasNameHashes = Ar.Ver >= EUnrealEngineObjectUE4Version.NAME_HASHES_SERIALIZED;

            Name = Ar.ReadFString();
            if (bHasNameHashes)
            {
#if NAME_HASHES
                NonCasePreservingHash = Ar.Read <ushort>();
                CasePreservingHash    = Ar.Read <ushort>();
#else
                Ar.Position += 4;
#endif
            }
        }
Ejemplo n.º 11
0
        public FFortCreativeVkPalette(FArchive Ar)
        {
            var dummy = Ar.Read <int>();

            var linkCodeMapNum = Ar.Read <int>();

            if (linkCodeMapNum > 0)
            {
                throw new NotImplementedException();
            }
            LinkCodeMap = new Dictionary <string, FFortCreativeVkPalette_ProjectInfo>(linkCodeMapNum);
            for (int i = 0; i < linkCodeMapNum; i++)
            {
                LinkCodeMap[Ar.ReadFString()] = new FFortCreativeVkPalette_ProjectInfo(Ar);
            }
        }
Ejemplo n.º 12
0
        protected virtual void ParsePlayer(FArchive archive, PlayerEliminationInfo info)
        {
            info.PlayerType = archive.ReadByteAsEnum <PlayerTypes>();

            switch (info.PlayerType)
            {
            case PlayerTypes.Bot:

                break;

            case PlayerTypes.NamedBot:
                info.Id = archive.ReadFString();
                break;

            case PlayerTypes.Player:
                info.Id = archive.ReadGUID(archive.ReadByte());
                break;
            }
        }
Ejemplo n.º 13
0
 public FPackageFileSummary(FArchive Ar)
 {
     Tag = Ar.Read <uint>();
     LegacyFileVersion      = Ar.Read <int>();
     LegacyUE3Version       = Ar.Read <int>();
     FileVersionUE4         = Ar.Read <int>();
     FileVersionLicenseUE4  = Ar.Read <int>();
     CustomContainerVersion = Ar.ReadArray <FCustomVersion>();
     TotalHeaderSize        = Ar.Read <int>();
     FolderName             = Ar.ReadFString();
     PackageFlags           = Ar.Read <PackageFlags>();
     NameCount  = Ar.Read <int>();
     NameOffset = Ar.Read <int>();
     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>();
     SoftPackageReferencesCount  = Ar.Read <int>();
     SoftPackageReferencesOffset = Ar.Read <int>();
     SearchableNamesOffset       = Ar.Read <int>();
     ThumbnailTableOffset        = Ar.Read <int>();
     if (Ar.Game == EGame.GAME_VALORANT)
     {
         Ar.Position += 8;
     }
     Guid                        = Ar.Read <FGuid>();
     Generations                 = Ar.ReadArray <FGenerationInfo>();
     SavedByEngineVersion        = new FEngineVersion(Ar);
     CompatibleWithEngineVersion = new FEngineVersion(Ar);
     CompressionFlags            = Ar.Read <uint>();
     CompressedChunks            = Ar.ReadArray <FCompressedChunk>();
     PackageSource               = Ar.Read <uint>();
     AdditionalPackagesToCook    = Ar.ReadArray(Ar.ReadFString);
     AssetRegistryDataOffset     = Ar.Read <int>();
     BulkDataStartOffset         = Ar.Read <int>();
     WorldTileInfoDataOffset     = Ar.Read <int>();
     ChunkIds                    = Ar.ReadArray <int>();
     PreloadDependencyCount      = Ar.Read <int>();
     PreloadDependencyOffset     = Ar.Read <int>();
 }
        protected virtual string ParsePlayer(FArchive archive)
        {
            // TODO player type enum
            var botIndicator = archive.ReadByte();

            if (botIndicator == 0x03)
            {
                return("Bot");
            }
            else if (botIndicator == 0x10)
            {
                return(archive.ReadFString());
            }

            // 0x11
            var size = archive.ReadByte();

            return(archive.ReadGUID(size));
        }
        public PlayerNameData(FArchive archive)
        {
            Handle      = archive.ReadByte();
            Unknown1    = archive.ReadByte();
            IsPlayer    = archive.ReadBoolean();
            EncodedName = archive.ReadFString();

            string decodedName = String.Empty;

            if (IsPlayer)
            {
                for (int i = 0; i < EncodedName.Length; i++)
                {
                    int shift = (EncodedName.Length % 4 * 3 % 8 + 1 + i) * 3 % 8;
                    decodedName += (char)(EncodedName[i] + shift);
                }

                DecodedName = decodedName;
            }
            else
            {
                DecodedName = EncodedName;
            }
        }
Ejemplo n.º 16
0
        protected virtual PlayerElimination ParseElimination(FArchive archive, EventInfo info)
        {
            try
            {
                var elim = new PlayerElimination
                {
                    Info = info,
                };

                if (archive.EngineNetworkVersion >= EngineNetworkVersionHistory.HISTORY_FAST_ARRAY_DELTA_STRUCT && Major >= 9)
                {
                    archive.SkipBytes(9);

                    elim.EliminatedInfo = new PlayerEliminationInfo
                    {
                        Unknown1 = new FVector(archive.ReadSingle(), archive.ReadSingle(), archive.ReadSingle()),
                        Location = new FVector(archive.ReadSingle(), archive.ReadSingle(), archive.ReadSingle()),
                        Unknown2 = new FVector(archive.ReadSingle(), archive.ReadSingle(), archive.ReadSingle()),
                    };

                    archive.ReadSingle(); //?

                    elim.EliminatorInfo = new PlayerEliminationInfo
                    {
                        Unknown1 = new FVector(archive.ReadSingle(), archive.ReadSingle(), archive.ReadSingle()),
                        Location = new FVector(archive.ReadSingle(), archive.ReadSingle(), archive.ReadSingle()),
                        Unknown2 = new FVector(archive.ReadSingle(), archive.ReadSingle(), archive.ReadSingle()),
                    };

                    ParsePlayer(archive, elim.EliminatedInfo);
                    ParsePlayer(archive, elim.EliminatorInfo);
                }
                else
                {
                    if (Major <= 4 && Minor < 2)
                    {
                        archive.SkipBytes(12);
                    }
                    else if (Major == 4 && Minor <= 2)
                    {
                        archive.SkipBytes(40);
                    }
                    else
                    {
                        archive.SkipBytes(45);
                    }

                    elim.EliminatedInfo = new PlayerEliminationInfo
                    {
                        Id = archive.ReadFString()
                    };

                    elim.EliminatorInfo = new PlayerEliminationInfo
                    {
                        Id = archive.ReadFString()
                    };
                }

                elim.GunType   = archive.ReadByte();
                elim.Knocked   = archive.ReadUInt32AsBoolean();
                elim.Timestamp = info.StartTime;

                return(elim);
            }
            catch (Exception ex)
            {
                _logger?.LogError($"Error while parsing PlayerElimination at timestamp {info.StartTime}");
                throw new PlayerEliminationException($"Error while parsing PlayerElimination at timestamp {info.StartTime}", ex);
            }
        }
 public FLevelSequenceLegacyObjectReference(FArchive Ar)
 {
     ObjectId   = Ar.Read <FGuid>();
     ObjectPath = Ar.ReadFString();
 }
Ejemplo n.º 18
0
 public FEngineVersion(FArchive Ar) : base(Ar)
 {
     _branch = Ar.ReadFString();
 }
Ejemplo n.º 19
0
        public WwiseReader(FArchive Ar)
        {
            IdToString         = new Dictionary <uint, string>();
            WwiseEncodedMedias = new Dictionary <string, byte[]>();
            while (Ar.Position < Ar.Length)
            {
                var sectionIdentifier = Ar.Read <ESectionIdentifier>();
                var sectionLength     = Ar.Read <int>();
                var position          = Ar.Position;

                switch (sectionIdentifier)
                {
                case ESectionIdentifier.AKPK:
                    if (!Ar.ReadBoolean())
                    {
                        throw new ParserException(Ar, $"'{Ar.Name}' has unsupported endianness.");
                    }

                    Ar.Position += 16;
                    Folders      = Ar.ReadArray(() => new AkFolder(Ar));
                    foreach (var folder in Folders)
                    {
                        folder.PopulateName(Ar);
                    }
                    foreach (var folder in Folders)
                    {
                        folder.Entries = new AkEntry[Ar.Read <uint>()];
                        for (var i = 0; i < folder.Entries.Length; i++)
                        {
                            var entry = new AkEntry(Ar);
                            entry.Path = Folders[entry.FolderId].Name;

                            var savePos = Ar.Position;
                            Ar.Position       = entry.Offset;
                            entry.IsSoundBank = Ar.Read <ESectionIdentifier>() == ESectionIdentifier.BKHD;
                            Ar.Position      -= 4;
                            entry.Data        = Ar.ReadBytes(entry.Size);
                            Ar.Position       = savePos;

                            folder.Entries[i] = entry;
                        }
                    }
                    break;

                case ESectionIdentifier.BKHD:
                    Header = Ar.Read <BankHeader>();
                    break;

                case ESectionIdentifier.INIT:
                    Initialization = Ar.ReadArray(() =>
                    {
                        Ar.Position += 4;
                        return(Ar.ReadFString());
                    });
                    break;

                case ESectionIdentifier.DIDX:
                    WemIndexes = Ar.ReadArray(sectionLength / 12, Ar.Read <DataIndex>);
                    break;

                case ESectionIdentifier.DATA:
                    if (WemIndexes == null)
                    {
                        break;
                    }
                    WemSounds = new byte[WemIndexes.Length][];
                    for (var i = 0; i < WemSounds.Length; i++)
                    {
                        Ar.Position  = position + WemIndexes[i].Offset;
                        WemSounds[i] = Ar.ReadBytes(WemIndexes[i].Length);
                        WwiseEncodedMedias[WemIndexes[i].Id.ToString()] = WemSounds[i];
                    }
                    break;

                case ESectionIdentifier.HIRC:
                    Hierarchy = Ar.ReadArray(() => new Hierarchy(Ar));
                    break;

                case ESectionIdentifier.RIFF:
                    // read byte[sectionLength] it's simply a wem file
                    break;

                case ESectionIdentifier.STID:
                    Ar.Position += 4;
                    var count = Ar.Read <int>();
                    for (var i = 0; i < count; i++)
                    {
                        IdToString[Ar.Read <uint>()] = Ar.ReadString();
                    }
                    break;

                case ESectionIdentifier.STMG:
                    break;

                case ESectionIdentifier.ENVS:
                    break;

                case ESectionIdentifier.FXPR:
                    break;

                case ESectionIdentifier.PLAT:
                    Platform = Ar.ReadFString();
                    break;

                default:
#if DEBUG
                    Log.Warning($"Unknown section {sectionIdentifier:X} at {position - sizeof(uint) - sizeof(uint)}");
#endif
                    break;
                }

                if (Ar.Position != position + sectionLength)
                {
                    var shouldBe = position + sectionLength;
#if DEBUG
                    Log.Warning($"Didn't read 0x{sectionIdentifier:X} correctly (at {Ar.Position}, should be {shouldBe})");
#endif
                    Ar.Position = shouldBe;
                }
            }


            if (Folders != null)
            {
                foreach (var folder in Folders)
                {
                    foreach (var entry in folder.Entries)
                    {
                        if (entry.IsSoundBank || entry.Data == null)
                        {
                            continue;
                        }
                        WwiseEncodedMedias[IdToString.TryGetValue(entry.NameHash, out var k) ? k : $"{entry.Path.ToUpper()}_{entry.NameHash}"] = entry.Data;
        public string KeyString; // Deprecated

        public FMaterialLayersFunctions(FArchive Ar)
        {
            KeyString = Ar.ReadFString();
        }
 public FTextLocalizationResourceString(FArchive Ar)
 {
     String   = Ar.ReadFString();
     RefCount = Ar.Read <int>();
 }
Ejemplo n.º 22
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;
            }