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 }
/// <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}"); }
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 }
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)); } }
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); } }
public FTextKey(FArchive Ar, ELocResVersion versionNum) { StrHash = 0; if (versionNum >= ELocResVersion.Optimized_CRC32) { StrHash = Ar.Read <uint>(); } Str = Ar.ReadFString(); }
public FNameEntrySerialized(FArchive Ar) { Name = Ar.ReadFString(); #if NAME_HASHES NonCasePreservingHash = Ar.Read <ushort>(); CasePreservingHash = Ar.Read <ushort>(); #else Ar.Position += 4; #endif }
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 } }
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); } }
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; } }
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; } }
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(); }
public FEngineVersion(FArchive Ar) : base(Ar) { _branch = Ar.ReadFString(); }
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>(); }
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; }