UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
ReplayHelper.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreMinimal.h"
10#include "Net/ReplayResult.h"
11#include "ReplayTypes.h"
13
15class UNetConnection;
16
17class FReplayHelper;
18
20{
21 friend class FReplayHelper;
22
23private:
24 void InitResultHandler(FReplayHelper* InReplayHelper);
25
26 virtual UE::Net::EHandleNetResult HandleNetResult(UE::Net::FNetResult&& InResult) override;
27
28private:
29 FReplayHelper* ReplayHelper = nullptr;
30};
31
33{
34 friend class UDemoNetDriver;
35 friend class UDemoNetConnection;
38
39public:
42
43 /* Do not copy or move this helper instance */
45 FReplayHelper(const FReplayHelper&) = delete;
48
49 /* For collection of GC references */
50 void Serialize(FArchive& Ar);
51
52private:
53
55
56 void SetPlaybackNetworkVersions(FArchive& Ar);
57 void SetPlaybackNetworkVersions(UNetConnection* Connection);
58
59 FReplayCustomVersion::Type GetPlaybackReplayVersion() const;
60
61 void StartRecording(UNetConnection* Connection);
62 void StopReplay();
63
64 void OnStartRecordingComplete(const FStartStreamingResult& Result);
65
66 void WriteNetworkDemoHeader(UNetConnection* Connection);
67 bool ReadPlaybackDemoHeader(FString& Error);
68
69 static void FlushNetChecked(UNetConnection& NetConnection);
70 static void WritePacket(FArchive& Ar, uint8* Data, int32 Count);
71
72 void OnSeamlessTravelStart(UWorld* InWorld, const FString& LevelName, UNetConnection* Connection);
73
74 APlayerController* CreateSpectatorController(UNetConnection* Connection);
75
76 bool HasLevelStreamingFixes() const
77 {
78 return bHasLevelStreamingFixes;
79 }
80
81 bool HasDeltaCheckpoints() const
82 {
83 return bHasDeltaCheckpoints;
84 }
85
86 bool HasGameSpecificFrameData() const
87 {
88 return bHasGameSpecificFrameData;
89 }
90
91 FGuid GetPlaybackGuid() const
92 {
93 return PlaybackDemoHeader.Guid;
94 }
95
96 void AddNewLevel(const FString& NewLevelName);
97
98 void TickRecording(float DeltaSeconds, UNetConnection* Connection);
99
100 void SaveCheckpoint(UNetConnection* Connection);
101 void TickCheckpoint(UNetConnection* Connection);
102 bool ShouldSaveCheckpoint() const;
103
105 float GetCheckpointSaveMaxMSPerFrame() const;
106
108 FOnReplayRecordError OnReplayRecordError;
109
111 FOnReplayPlaybackError OnReplayPlaybackError;
112
113 static float GetClampedDeltaSeconds(UWorld* World, const float DeltaSeconds);
114
115 uint32 GetDemoCurrentTimeInMS() const { return (uint32)((double)DemoCurrentTime * 1000); }
116 uint32 GetLastCheckpointTimeInMS() const { return (uint32)((double)LastCheckpointTime * 1000); }
117
118 void ResetState();
119
120 void AddOrUpdateEvent(const FString& Name, const FString& Group, const FString& Meta, const TArray<uint8>& Data);
121
122 void SetAnalyticsProvider(TSharedPtr<IAnalyticsProvider> InProvider);
123
124 void RequestCheckpoint();
125
126 void RemoveActorFromCheckpoint(UNetConnection* Connection, AActor* Actor);
127
128 void NotifyActorDestroyed(UNetConnection* Connection, AActor* Actor);
129
130private:
131 // Hooks used to determine when levels are streamed in, streamed out, or if there's a map change.
132 void OnLevelAddedToWorld(ULevel* Level, UWorld* World);
133 void OnLevelRemovedFromWorld(ULevel* Level, UWorld* World);
134
135 void RecordFrame(float DeltaSeconds, UNetConnection* Connection);
136
137 void WriteDemoFrame(UNetConnection* Connection, FArchive& Ar, TArray<FQueuedDemoPacket>& QueuedPackets, float FrameTime, EWriteDemoFrameFlags Flags);
138 bool ReadDemoFrame(UNetConnection* Connection, FArchive& Ar, TArray<FPlaybackPacket>& InPlaybackPackets, const bool bForLevelFastForward, const FArchivePos MaxArchiveReadPos, float* OutTime);
139
140 // Possible values returned by ReadPacket.
141 enum class EReadPacketState
142 {
143 Success, // A packet was read successfully and there may be more in the frame archive.
144 End, // No more data is present in the archive.
145 Error, // An error occurred while reading.
146 };
147
148 enum class EReadPacketMode
149 {
150 Default, // Read the packet normally
151 SkipData // Skip packet data.
152 };
153
165 static const EReadPacketState ReadPacket(FArchive& Archive, TArray<uint8>& OutBuffer, const EReadPacketMode Mode);
166
167 void CacheNetGuids(UNetConnection* Connection);
168
169 bool SerializeGuidCache(UNetConnection* Connection, const FRepActorsCheckpointParams& Params, FArchive* CheckpointArchive);
170 bool SerializeDeletedStartupActors(UNetConnection* Connection, const FRepActorsCheckpointParams& Params, FArchive* CheckpointArchive);
171 bool SerializeDeltaDynamicDestroyed(UNetConnection* Connection, const FRepActorsCheckpointParams& Params, FArchive* CheckpointArchive);
172 bool SerializeDeltaClosedChannels(UNetConnection* Connection, const FRepActorsCheckpointParams& Params, FArchive* CheckpointArchive);
173
184 bool ReplicateCheckpointActor(AActor* ToReplicate, UNetConnection* Connection, class FRepActorsCheckpointParams& Params);
185
186 bool ReplicateActor(AActor* Actor, UNetConnection* Connection, bool bMustReplicate);
187
189
190 struct FExternalDataWrapper
191 {
192 FNetworkGUID NetGUID;
195 };
196
197 TMap<TWeakObjectPtr<UObject>, FExternalDataWrapper, FDefaultSetAllocator, TWeakObjectPtrMapKeyFuncs<TWeakObjectPtr<UObject>, FExternalDataWrapper>> ExternalDataMap;
198
199 void SaveExternalData(UNetConnection* Connection, FArchive& Ar);
200 void LoadExternalData(FArchive& Ar, const float TimeSeconds);
201
202 bool SetExternalDataForObject(UNetConnection* Connection, UObject* OwningObject, const uint8* Src, const int32 NumBits);
203
204 void ResetDeltaCheckpointTracking(UNetConnection* Connection);
205
206 // Cached replay URL
207 FURL DemoURL;
208
209 FString ActiveReplayName;
210
212
214
215 // List of levels used in the current replay
216 TArray<FLevelNameAndTime> LevelNamesAndTimes;
217
219 int32 CurrentLevelIndex;
220
222 int32 DemoFrameNum;
223
225 float DemoCurrentTime;
226
228 float DemoTotalTime;
229
230 // Last time a checkpoint was saved
231 double LastCheckpointTime;
232
233 // Time of the last frame we've read (in seconds).
234 float LatestReadFrameTime;
235
236 bool bWasStartRecordingSuccessful;
237 bool bIsWaitingForStream;
238 bool bIsLoadingCheckpoint;
239
240 // Whether or not the Streaming Level Fixes are enabled for capture or playback.
241 bool bHasLevelStreamingFixes;
242
243 // Checkpoints are delta compressed
244 bool bHasDeltaCheckpoints;
245
246 // Allow appending per frame game specific data
247 bool bHasGameSpecificFrameData;
248
249 // If true, will skip recording, but leaves the replay open so that recording can be resumed again.
250 bool bPauseRecording;
251
252 bool bRecordMapChanges;
253
254 float CheckpointSaveMaxMSPerFrame;
255
256 // This header is valid during playback (so we know what version to pass into serializers, etc)
257 FNetworkDemoHeader PlaybackDemoHeader;
258
259 enum class ECheckpointSaveState
260 {
261 Idle,
262 ProcessCheckpointActors,
263 SerializeDeletedStartupActors,
264 SerializeDeltaDynamicDestroyed,
265 SerializeDeltaClosedChannels,
266 CacheNetGuids,
267 SerializeGuidCache,
268 SerializeNetFieldExportGroupMap,
269 SerializeDemoFrameFromQueuedDemoPackets,
270 Finalize,
271 };
272
273 struct FCheckpointStepHelper
274 {
275 FCheckpointStepHelper() = delete;
276 FCheckpointStepHelper(ECheckpointSaveState InCheckpointState, const double InCheckpointStartTime, int32* InCurrentIndex, int32 InTotalCount)
277 : CheckpointState(InCheckpointState)
278 , CheckpointStartTime(InCheckpointStartTime)
279 , CurrentIndex(InCurrentIndex)
280 , TotalCount(InTotalCount)
281 {
283 StartTime = FPlatformTime::Seconds();
284 }
285
286 ~FCheckpointStepHelper()
287 {
288 const double EndTime = FPlatformTime::Seconds();
289 const double TotalTimeInMS = (EndTime - CheckpointStartTime) * 1000.0;
290 const double StepTimeInMS = (EndTime - StartTime) * 1000.0;
291
292 const TCHAR* StateStr = TEXT("Unknown");
293
294 switch (CheckpointState)
295 {
296 case ECheckpointSaveState::ProcessCheckpointActors:
297 StateStr = TEXT("ProcessCheckpointActors");
298 break;
299 case ECheckpointSaveState::SerializeDeletedStartupActors:
300 StateStr = TEXT("SerializeDeletedStartupActors");
301 break;
302 case ECheckpointSaveState::SerializeDeltaDynamicDestroyed:
303 StateStr = TEXT("SerializeDeltaDynamicDestroyed");
304 break;
305 case ECheckpointSaveState::SerializeDeltaClosedChannels:
306 StateStr = TEXT("SerializeDeltaClosedChannels");
307 break;
308 case ECheckpointSaveState::SerializeGuidCache:
309 StateStr = TEXT("SerializeGuidCache");
310 break;
311 default:
312 ensureMsgf(false, TEXT("FCheckpointStepHelper: Unsupported checkpoint state: %d"), CheckpointState);
313 break;
314 }
315
316 UE_LOG(LogDemo, Verbose, TEXT("Checkpoint. %s: %i/%i, took %.2fms (Total this frame: %.2fms)"), StateStr, *CurrentIndex, TotalCount, StepTimeInMS, TotalTimeInMS);
317 }
318
319 private:
320 ECheckpointSaveState CheckpointState;
321 double StartTime = 0.0;
322 double CheckpointStartTime = 0.0;
323 int32* CurrentIndex = nullptr;
324 int32 TotalCount = 0;
325 };
326
328 struct FPendingCheckPointActor
329 {
331 int32 LevelIndex;
332 };
333
334 struct FNetGuidCacheItem
335 {
336 FNetworkGUID NetGuid;
337 FNetGuidCacheObject NetGuidCacheObject;
338 };
339
341 struct FCheckpointSaveStateContext
342 {
343 FCheckpointSaveStateContext()
344 : CheckpointSaveState(ECheckpointSaveState::Idle)
345 , TotalCheckpointSaveTimeSeconds(0.0)
346 , TotalCheckpointReplicationTimeSeconds(0.0)
347 , bWriteCheckpointOffset(false)
348 , TotalCheckpointSaveFrames(0)
349 , TotalCheckpointActors(0)
350 , CheckpointOffset(0)
351 , GuidCacheSize(0)
352 , NextAmortizedItem(0)
353 , NumNetGuidsForRecording(0)
354 , NetGuidsCountPos(0)
355 {}
356
357 ECheckpointSaveState CheckpointSaveState; // Current state of checkpoint SaveState
358 FPackageMapAckState CheckpointAckState; // Current ack state of packagemap for the current checkpoint being saved
359 TArray<FPendingCheckPointActor> PendingCheckpointActors; // Actors to be serialized by pending checkpoint
361 double TotalCheckpointSaveTimeSeconds; // Total time it took to save checkpoint including the finaling part across all frames
362 double TotalCheckpointReplicationTimeSeconds; // Total time it took to write all replicated objects across all frames
363 bool bWriteCheckpointOffset;
364 int32 TotalCheckpointSaveFrames; // Total number of frames used to save a checkpoint
365 int32 TotalCheckpointActors;
366 FArchivePos CheckpointOffset;
367 uint32 GuidCacheSize;
368
369 FDeltaCheckpointData DeltaCheckpointData;
370 TArray<FNetworkGUID> DeltaChannelCloseKeys;
371
372 TArray<FNetGuidCacheItem> NetGuidCacheSnapshot;
373 int32 NextAmortizedItem;
374 int32 NumNetGuidsForRecording;
375 FArchivePos NetGuidsCountPos;
376
377 TArray<FString> CheckpointDeletedNetStartupActors;
378
379 TMap<FName, uint32> NameTableMap;
380
381 void CountBytes(FArchive& Ar) const;
382 };
383
384 FCheckpointSaveStateContext CheckpointSaveContext;
385
386 FDeltaCheckpointData RecordingDeltaCheckpointData;
387
388 TArray<TUniquePtr<FDeltaCheckpointData>> PlaybackDeltaCheckpointData;
389
394 TSet<TWeakObjectPtr<UObject>> UniqueStreamingLevels;
395
400 TSet<TWeakObjectPtr<UObject>> NewStreamingLevelsThisFrame;
401
402 TArray<FQueuedDemoPacket> QueuedDemoPackets;
403 TArray<FQueuedDemoPacket> QueuedCheckpointPackets;
404
416 struct FLevelStatus
417 {
418 FLevelStatus(const FString& LevelPackageName) :
419 LevelName(LevelPackageName),
420 LevelIndex(INDEX_NONE),
421 bIsReady(false),
422 bHasBeenSeen(false)
423 {
424 }
425
426 // Level name.
427 FString LevelName;
428
429 // Level index (in AllLevelStatuses).
430 int32 LevelIndex;
431
432 // Whether or not the level is ready to receive streaming data.
433 bool bIsReady;
434
435 // Whether or not we've seen replicated data for the level. Only set during playback.
436 bool bHasBeenSeen;
437
438 void CountBytes(FArchive& Ar) const
439 {
440 LevelName.CountBytes(Ar);
441 }
442 };
443
444 // Tracks all available level statuses.
445 // When Recording, this will be in order of replication, and all statuses will be assumed Seen and Visible (even if unmarked).
446 // During Playback, there's no guaranteed order. Levels will be added either when they are added to the world, or when we handle the first
447 // frame containing replicated data.
448 // Use SeenLevelStatuses and LevelStatusesByName for querying.
449 TArray<FLevelStatus> AllLevelStatuses;
450
451 // Since Arrays are dynamically allocated, we can't just hold onto pointers.
452 // If we tried, the underlying memory could be moved without us knowing.
453 // Therefore, we track the Index into the array which should be independent of allocation.
454
455 // Index of level status (in AllLevelStatuses list).
456 TMap<FString, int32> LevelStatusesByName;
457
458 // Maintain a quick lookup for loaded levels directly to LevelStatus
459 TMap<const ULevel*, int32> LevelStatusIndexByLevel;
460
461 // Map of ULevel GetFName to weak object pointer to the level
462 // Populated during playback, not using NetworkRemapPath because it is never serialized
463 TMap<FName, TWeakObjectPtr<ULevel>> WeakLevelsByName;
464
465 void ResetLevelMap();
466 void ClearLevelMap();
467
468 // List of seen level statuses indices (in AllLevelStatuses).
469 TArray<int32> SeenLevelStatuses;
470
471 // Only used during recording.
472 uint32 NumLevelsAddedThisFrame;
473
474 // Levels that are currently pending for fast forward.
475 // Using raw pointers, because we manually keep when levels are added and removed.
476 TSet<class ULevel*> LevelsPendingFastForward;
477
478 bool bPendingCheckpointRequest;
479
480 UE::Net::FNetResultManager ResultManager;
481
482 static FString GetLevelPackageName(const ULevel& InLevel);
483
484 void ResetLevelStatuses();
485 void ClearLevelStreamingState()
486 {
487 AllLevelStatuses.Empty();
488 LevelStatusesByName.Empty();
489 SeenLevelStatuses.Empty();
490 LevelsPendingFastForward.Empty();
491 NumLevelsAddedThisFrame = 0;
492 LevelStatusIndexByLevel.Reset();
493 }
494
495 FLevelStatus& FindOrAddLevelStatus(const ULevel& Level)
496 {
497 // see if we can find it in the cache
498 int32* LevelStatusIndex = LevelStatusIndexByLevel.Find(&Level);
499
501 {
502 return AllLevelStatuses[*LevelStatusIndex];
503 }
504
505 FLevelStatus& LevelStatus = FindOrAddLevelStatus(GetLevelPackageName(Level));
506 LevelStatusIndexByLevel.Add(&Level, LevelStatus.LevelIndex);
507
508 return LevelStatus;
509 }
510
511 FLevelStatus& FindOrAddLevelStatus(const FString& LevelPackageName)
512 {
513 return FindOrAddLevelStatus(FString(LevelPackageName));
514 }
515
516 FLevelStatus& FindOrAddLevelStatus(FString&& LevelPackageName)
517 {
518 if (int32* LevelStatusIndex = LevelStatusesByName.Find(LevelPackageName))
519 {
520 return AllLevelStatuses[*LevelStatusIndex];
521 }
522
523 const int32 Index = AllLevelStatuses.Emplace(LevelPackageName);
524 AllLevelStatuses[Index].LevelIndex = Index;
525
526 LevelStatusesByName.Add(MoveTemp(LevelPackageName), Index);
527 NumLevelsAddedThisFrame++;
528
529 return AllLevelStatuses[Index];
530 }
531
532 FLevelStatus& GetLevelStatus(const int32 SeenLevelIndex)
533 {
534 return AllLevelStatuses[SeenLevelStatuses[SeenLevelIndex - 1]];
535 }
536
537 FLevelStatus& GetLevelStatus(const FString& LevelPackageName)
538 {
539 return AllLevelStatuses[LevelStatusesByName[LevelPackageName]];
540 }
541
543 TMap<FNetworkGUID, FReplayExternalDataArray> ExternalDataToObjectMap;
544
547
549 TArray<FString> RecordingDeletedNetStartupActors;
550
552 TSet<FString> PlaybackDeletedNetStartupActors;
553
554 TSharedPtr<IAnalyticsProvider> AnalyticsProvider;
555
556 void ReadDeletedStartupActors(UNetConnection* Connection, FArchive& Ar, TSet<FString>& DeletedStartupActors);
557
558 ECheckpointSaveState GetCheckpointSaveState() const { return CheckpointSaveContext.CheckpointSaveState; }
559
560 void ProcessCheckpointActors(UNetConnection* Connection, TArrayView<FPendingCheckPointActor> PendingActors, int32& NextIndex, FRepActorsCheckpointParams& Params);
561
562 void NotifyReplayError(UE::Net::TNetResult<EReplayResult>&& Result);
563
564 bool bRecording;
565
566 static constexpr int32 MAX_DEMO_READ_WRITE_BUFFER = 1024 * 2;
567 static constexpr int32 MAX_DEMO_STRING_SERIALIZATION_SIZE = 16 * 1024 * 1024;
568};
#define check(expr)
Definition AssertionMacros.h:314
#define ensureMsgf( InExpression, InFormat,...)
Definition AssertionMacros.h:465
@ INDEX_NONE
Definition CoreMiscDefines.h:150
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::TCHAR TCHAR
Either ANSICHAR or WIDECHAR, depending on whether the platform supports wide characters or the requir...
Definition Platform.h:1135
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
#define DECLARE_DELEGATE_OneParam(DelegateName, Param1Type)
Definition DelegateCombinations.h:48
void Init()
Definition LockFreeList.h:4
#define UE_LOG(CategoryName, Verbosity, Format,...)
Definition LogMacros.h:270
EWriteDemoFrameFlags
Definition ReplayTypes.h:43
int64 FArchivePos
Definition ReplayTypes.h:232
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTemp(T &&Obj) noexcept
Definition UnrealTemplate.h:520
uint8_t uint8
Definition binka_ue_file_header.h:8
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition Actor.h:257
Definition PlayerController.h:261
Definition Archive.h:1208
Definition ContainerAllocationPolicies.h:1660
Definition PackageMapClient.h:121
Definition NetworkGuid.h:12
Definition PackageMapClient.h:447
Definition ReplayTypes.h:250
Definition ReplayHelper.h:33
FReplayHelper(FReplayHelper &&)=delete
FReplayHelper()
Definition ReplayHelper.cpp:36
FReplayHelper & operator=(FReplayHelper &&)=delete
~FReplayHelper()
Definition ReplayHelper.cpp:58
FReplayHelper(const FReplayHelper &)=delete
FReplayHelper & operator=(const FReplayHelper &)=delete
Definition ReplayHelper.h:20
Definition ArrayView.h:139
Definition Array.h:670
UE_FORCEINLINE_HINT SizeType Emplace(ArgsType &&... Args)
Definition Array.h:2561
void Empty(SizeType Slack=0)
Definition Array.h:2273
Definition UnrealString.h.inl:34
Definition SharedPointer.h:692
Definition DemoNetConnection.h:20
Definition DemoNetDriver.h:154
Definition NetResultManager.h:118
Definition NetResultManager.h:48
Definition Level.h:423
Definition NetConnection.h:284
Definition Object.h:95
Definition ReplayNetConnection.h:13
Definition World.h:918
GeometryCollection::Facades::FMuscleActivationData Data
Definition MuscleActivationConstraints.h:15
const Type Default
Definition AIController.h:54
@ Success
Definition EnvQueryTypes.h:177
@ NumBits
Definition MeshPassProcessor.h:87
@ Actor
Definition TokenizedMessage.h:38
@ Error
Definition PathFollowingComponent.h:145
@ Idle
Definition PathFollowingComponent.h:39
@ End
Definition GeoEnum.h:101
EHandleNetResult
Definition NetResultManager.h:26
@ false
Definition radaudio_common.h:23
U16 Index
Definition radfft.cpp:71
static double Seconds()
Definition AndroidPlatformTime.h:20
Definition ReplayTypes.h:235
Definition Guid.h:109
Definition ReplayTypes.h:178
FGuid Guid
Definition ReplayTypes.h:195
Type
Definition ReplayTypes.h:126
Definition NetworkReplayStreaming.h:228
Definition EngineBaseTypes.h:799
Definition WeakObjectPtrTemplates.h:415
Definition WeakObjectPtrTemplates.h:25
Definition NetResult.h:64
Definition NetResult.h:330