/// <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 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 }
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 override void ReadReplayData(FArchive archive) { int startPosition = archive.Position; var info = new ReplayDataInfo(); if (archive.ReplayVersion >= ReplayVersionHistory.HISTORY_STREAM_CHUNK_TIMES) { info.Start = archive.ReadUInt32(); info.End = archive.ReadUInt32(); info.Length = archive.ReadUInt32(); } else { info.Length = archive.ReadUInt32(); } int memorySizeInBytes = (int)info.Length; if (archive.ReplayVersion >= ReplayVersionHistory.HISTORY_ENCRYPTION) { memorySizeInBytes = archive.ReadInt32(); } int infoSize = archive.Position - startPosition; using var decryptedReader = DecryptBuffer(archive, (int)info.Length); using var binaryArchive = (Unreal.Core.BinaryReader)Decompress(decryptedReader, memorySizeInBytes); //Chunk size _writer.Write(infoSize + binaryArchive.Bytes.Length); if (archive.ReplayVersion >= ReplayVersionHistory.HISTORY_STREAM_CHUNK_TIMES) { _writer.Write(info.Start); _writer.Write(info.End); _writer.Write(binaryArchive.Bytes.Length); } else { _writer.Write(binaryArchive.Bytes.Length); } if (archive.ReplayVersion >= ReplayVersionHistory.HISTORY_ENCRYPTION) { _writer.Write(binaryArchive.Bytes.Length); } _writer.Write(binaryArchive.Bytes.ToArray()); }
public override void ReadReplayChunks(FArchive archive) { while (!archive.AtEnd()) { var chunkType = archive.ReadUInt32AsEnum <ReplayChunkType>(); _writer.Write((uint)chunkType); var chunkSize = archive.ReadInt32(); var offset = archive.Position; //Console.WriteLine($"Chunk {chunkType}. Size: {chunkSize}. Offset: {offset}"); if (chunkType == ReplayChunkType.Checkpoint) { ReadCheckpoint(archive); } else if (chunkType == ReplayChunkType.Event) { ReadEvent(archive); } else if (chunkType == ReplayChunkType.ReplayData) { ReadReplayData(archive); } else if (chunkType == ReplayChunkType.Header) { //Copy over bytes _writer.Write(chunkSize); _writer.Write(archive.ReadBytes(chunkSize)); _writer.Flush(); } if (archive.Position != offset + chunkSize) { //_logger?.LogWarning($"Chunk ({chunkType}) at offset {offset} not correctly read..."); archive.Seek(offset + chunkSize, SeekOrigin.Begin); } } }