// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #if UE_ENABLE_INCLUDE_ORDER_DEPRECATED_IN_5_7 #include "CoreMinimal.h" #include "UObject/WeakObjectPtr.h" #endif // UE_ENABLE_INCLUDE_ORDER_DEPRECATED_IN_5_7 #include "BindableProperty.h" #include "Containers/Ticker.h" #include "IRewindDebugger.h" #include "IRewindDebuggerTrackCreator.h" #include "RewindDebuggerTrack.h" namespace TraceServices { class IAnalysisSession; } class FMenuBuilder; class IGameplayProvider; class SDockTab; class SWidget; class USkeletalMeshComponent; struct FObjectInfo; /** * Singleton class that handles the logic for the Rewind Debugger: * - Playback/Scrubbing state * - Start/Stop recording * - Keeping track of the current Debug Target object, and outputting a list of its sub objects/elements for the UI */ class FRewindDebugger : public IRewindDebugger { public: FRewindDebugger(); virtual ~FRewindDebugger(); //~ IRewindDebugger interface virtual double CurrentTraceTime() const override { return TraceTime.Get(); } virtual double GetScrubTime() const override { return CurrentScrubTime; } virtual const TRange& GetCurrentTraceRange() const override { return CurrentTraceRange; } virtual const TRange& GetCurrentViewRange() const override { return CurrentViewRange; } virtual const TraceServices::IAnalysisSession* GetAnalysisSession() const override; virtual uint64 GetTargetActorId() const override; virtual bool GetTargetActorPosition(FVector& OutPosition) const override; virtual UWorld* GetWorldToVisualize() const override; virtual bool IsRecording() const override; virtual bool IsPIESimulating() const override { return bPIESimulating; } virtual bool IsTraceFileLoaded() const override; virtual double GetRecordingDuration() const override { return RecordingDuration.Get(); } virtual TSharedPtr GetSelectedObject() const override; virtual TSharedPtr GetSelectedTrack() const override; virtual TArray>& GetDebuggedObjects() override; virtual bool IsObjectCurrentlyDebugged(uint64 ObjectId) const override; virtual bool ShouldDisplayWorld(uint64 WorldId) override { return DisplayWorldId == WorldId; } void OnConnection(); void GetTargetObjectIds(TArray& OutTargetObjectIds) const; TArray>& GetTracks() { return DebugTracks; } /** create singleton instance */ static void Initialize(); /** destroy singleton instance */ static void Shutdown(); /** get singleton instance */ static FRewindDebugger* Instance() { return static_cast(InternalInstance); } /** Start a new Recording: Start tracing Object + Animation data, increment the current recording index, and reset the recording elapsed time to 0 */ void StartRecording() const; void OnClearRecording(); void OnRecordingStarted(); void OnRecordingStopped(); bool CanStartRecording() const { return !IsRecording() && bPIESimulating; } bool CanOpenTrace() const; void OpenTrace(const FString& FilePath); void OpenTrace(); void AttachToSession(); bool CanClearTrace() const; void ClearTrace(); bool CanSaveTrace() const; void SaveTrace(FString FileName); void SaveTrace(); bool ShouldAutoRecordOnPIE() const; void SetShouldAutoRecordOnPIE(bool InValue); bool ShouldAutoEject() const; void SetShouldAutoEject(bool InValue); /** Stop recording: Stop tracing Object + Animation Data. */ void StopRecording(); bool CanStopRecording() const { return IsRecording(); } //~ VCR controls bool CanPause() const; void Pause(); bool CanPlay() const; void Play(); bool IsPlaying() const; bool CanPlayReverse() const; void PlayReverse(); void ScrubToStart(); void ScrubToEnd(); void Step(int32 InNumberOfFrames); void StepForward(); void StepBackward(); bool CanScrub() const; void ScrubToTime(double ScrubTime, bool bIsScrubbing); /** Tick function: While recording, update recording duration. While paused, and we have recorded data, update skinned mesh poses for the current frame, and handle playback. */ void Tick(float DeltaTime); /** update the list of tracks for the currently selected debug target */ void RefreshDebugTracks(); void SetCurrentViewRange(const TRange& Range); DECLARE_DELEGATE(FOnTrackListChanged) void SetTrackListChangedDelegate(const FOnTrackListChanged& InTrackListChangedDelegate); void TrackDoubleClicked(TSharedPtr InSelectedTrack); void TrackSelectionChanged(TSharedPtr InSelectedTrack); TSharedPtr BuildTrackContextMenu() const; void UpdateDetailsPanel(TSharedRef DetailsTab); static void RegisterTrackContextMenu(); static void MakeOtherWorldsMenu(class UToolMenu* Menu); void SetDisplayWorld(uint64 WorldId); static void MakeWorldsMenu(class UToolMenu* Menu); static void RegisterToolBar(); DECLARE_DELEGATE_OneParam(FOnTrackCursor, bool) void SetTrackCursorDelegate(const FOnTrackCursor& InTrackCursorDelegate); TBindableProperty* GetTraceTimeProperty() { return &TraceTime; } TBindableProperty* GetRecordingDurationProperty() { return &RecordingDuration; } TBindableProperty* GetDebugTargetActorProperty() { return &SelectedObjectName; } virtual void OpenDetailsPanel() override; void SetIsDetailsPanelOpen(bool bIsOpen) { bIsDetailsPanelOpen = bIsOpen; } virtual const FObjectInfo* FindOwningActorInfo(const IGameplayProvider* GameplayProvider, uint64 ObjectId) const override; TArrayView GetTrackTypes() { return TrackTypes; }; private: static void RefreshDebuggedObjects(TArray>& InTracks, TArray>& OutObjects); void OnPIEStarted(bool bSimulating); void OnPIEPaused(bool bSimulating); void OnPIEResumed(bool bSimulating); void OnPIEStopped(bool bSimulating); void OnPIESingleStepped(bool bSimulating); void SetCurrentScrubTime(double Time); TBindableProperty TraceTime; TBindableProperty RecordingDuration; TBindableProperty SelectedObjectName; enum class EControlState : int8 { Play, PlayReverse, Pause }; EControlState ControlState = EControlState::Pause; FOnTrackListChanged TrackListChangedDelegate; FOnTrackCursor TrackCursorDelegate; bool bQueueStartRecording = false; bool bTraceJustConnected = false; bool bPIEStarted = false; bool bPIESimulating = false; bool bRecording = false; double PreviousTraceTime = -1; double CurrentScrubTime = 0; TRange CurrentViewRange{ 0, 10 }; TRange CurrentTraceRange{ 0, 0 }; uint16 RecordingIndex = 0; struct FScrubTimeInformation { /** Profiling/Tracing time */ double ProfileTime = 0; /** Scrub Frame Index */ int64 FrameIndex = 0; }; FScrubTimeInformation ScrubTimeInformation; FScrubTimeInformation LowerBoundViewTimeInformation; FScrubTimeInformation UpperBoundViewTimeInformation; static void GetScrubTimeInformation(double InDebugTime, FScrubTimeInformation& InOutTimeInformation, uint16 InRecordingIndex, const TraceServices::IAnalysisSession* AnalysisSession); TArray> DebuggedObjects; mutable TSharedPtr SelectedObject; TArray> DebugTracks; TSharedPtr SelectedTrack; TArray CandidateIds; mutable class IUnrealInsightsModule* UnrealInsightsModule = nullptr; FTSTicker::FDelegateHandle TickerHandle; bool bTargetActorPositionValid = false; FVector TargetActorPosition; uint64 TargetActorMeshId = 0; uint64 TargetActorIdForMesh = 0; TArray TrackTypes; bool bIsDetailsPanelOpen = true; uint64 DisplayWorldId = 0; bool bDisplayWorldIdValid = false; };