You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
- replaced node details view by embedding property values in the tree view - node exported text (e.g. Task, Conditions, etc) is no longer imported in struct or object to avoid problems with missing types or property types with specific requirements (e.g. Object base property needs to find the specified value). Goal is to always be able to inspect key/value pairs. - improved hierarchy of event to improve readibility - started adding some custom row widgets for the different event types - reworked the toolbar to regroup the different concepts (Simulation controls, Trace recording, Trace analyzing) #rnx #rb mikko.mononen [CL 26854347 by Yoan StAmant in 5.3 branch]
334 lines
14 KiB
C++
334 lines
14 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#if WITH_STATETREE_DEBUGGER
|
|
|
|
#include "IStateTreeTraceProvider.h"
|
|
#include "StateTree.h"
|
|
#include "StateTreeDebuggerTypes.h"
|
|
#include "StateTreeTypes.h"
|
|
#include "Tickable.h"
|
|
#include "TraceServices/Model/AnalysisSession.h"
|
|
#include "TraceServices/Model/Diagnostics.h"
|
|
#include "TraceServices/Model/Frames.h"
|
|
|
|
enum class EStateTreeBreakpointType : uint8;
|
|
|
|
namespace UE::Trace
|
|
{
|
|
class FStoreClient;
|
|
}
|
|
|
|
class IStateTreeModule;
|
|
class UStateTreeState;
|
|
class UStateTree;
|
|
|
|
DECLARE_DELEGATE_OneParam(FOnStateTreeDebuggerScrubStateChanged, const UE::StateTreeDebugger::FScrubState& ScrubState);
|
|
DECLARE_DELEGATE_TwoParams(FOnStateTreeDebuggerBreakpointHit, FStateTreeInstanceDebugId InstanceId, const FStateTreeDebuggerBreakpoint Breakpoint);
|
|
DECLARE_DELEGATE_OneParam(FOnStateTreeDebuggerActiveStatesChanges, TConstArrayView<FStateTreeStateHandle> ActiveStates);
|
|
DECLARE_DELEGATE_OneParam(FOnStateTreeDebuggerNewInstance, FStateTreeInstanceDebugId InstanceId);
|
|
DECLARE_DELEGATE(FOnStateTreeDebuggerNewSession);
|
|
DECLARE_DELEGATE(FOnStateTreeDebuggerDebuggedInstanceSet);
|
|
|
|
struct STATETREEMODULE_API FStateTreeDebugger : FTickableGameObject
|
|
{
|
|
struct FTraceDescriptor
|
|
{
|
|
FTraceDescriptor() = default;
|
|
FTraceDescriptor(const FString& Name, const uint32 Id) : Name(Name), TraceId(Id) {}
|
|
|
|
bool operator==(const FTraceDescriptor& Other) const { return Other.TraceId == TraceId; }
|
|
bool operator!=(const FTraceDescriptor& Other) const { return !(Other == *this); }
|
|
bool IsValid() const { return TraceId != INDEX_NONE; }
|
|
|
|
FString Name;
|
|
uint32 TraceId = INDEX_NONE;
|
|
|
|
TraceServices::FSessionInfo SessionInfo;
|
|
};
|
|
|
|
struct FHitBreakpoint
|
|
{
|
|
bool IsSet() const { return Index != INDEX_NONE; }
|
|
void Reset()
|
|
{
|
|
InstanceId = FStateTreeInstanceDebugId::Invalid;
|
|
Time = 0;
|
|
Index = INDEX_NONE;
|
|
}
|
|
|
|
/** Indicates the instance for which the breakpoint has been hit */
|
|
FStateTreeInstanceDebugId InstanceId = FStateTreeInstanceDebugId::Invalid;
|
|
|
|
/**
|
|
* Store the time at which the breakpoint was hit since we might have process more events before
|
|
* sending the notifications.
|
|
*/
|
|
double Time = 0;
|
|
|
|
/** Indicates the index of the breakpoint that has been hit */
|
|
int32 Index = INDEX_NONE;
|
|
};
|
|
|
|
FStateTreeDebugger();
|
|
virtual ~FStateTreeDebugger() override;
|
|
|
|
const UStateTree* GetAsset() const { return StateTreeAsset.Get(); }
|
|
void SetAsset(const UStateTree* InStateTreeAsset) { StateTreeAsset = InStateTreeAsset; }
|
|
|
|
/** Forces a single refresh to latest state. Useful when simulation is paused. */
|
|
void SyncToCurrentSessionDuration();
|
|
|
|
bool CanStepBackToPreviousStateWithEvents() const;
|
|
void StepBackToPreviousStateWithEvents();
|
|
|
|
bool CanStepForwardToNextStateWithEvents() const;
|
|
void StepForwardToNextStateWithEvents();
|
|
|
|
bool CanStepBackToPreviousStateChange() const;
|
|
void StepBackToPreviousStateChange();
|
|
|
|
bool CanStepForwardToNextStateChange() const;
|
|
void StepForwardToNextStateChange();
|
|
|
|
bool IsActiveInstance(double Time, FStateTreeInstanceDebugId InstanceId) const;
|
|
FText GetInstanceName(FStateTreeInstanceDebugId InstanceId) const;
|
|
FText GetInstanceDescription(FStateTreeInstanceDebugId InstanceId) const;
|
|
void SelectInstance(const FStateTreeInstanceDebugId InstanceId);
|
|
void ClearSelection() { SelectInstance({}); }
|
|
FStateTreeInstanceDebugId GetSelectedInstanceId() const { return SelectedInstanceId; }
|
|
const UE::StateTreeDebugger::FInstanceDescriptor* GetInstanceDescriptor(const FStateTreeInstanceDebugId InstanceId) const ;
|
|
const UE::StateTreeDebugger::FInstanceDescriptor* GetSelectedInstanceDescriptor() const { return GetInstanceDescriptor(SelectedInstanceId); }
|
|
|
|
bool HasStateBreakpoint(FStateTreeStateHandle StateHandle, EStateTreeBreakpointType BreakpointType) const;
|
|
bool HasTaskBreakpoint(FStateTreeIndex16 Index, EStateTreeBreakpointType BreakpointType) const;
|
|
bool HasTransitionBreakpoint(FStateTreeIndex16 Index, EStateTreeBreakpointType BreakpointType) const;
|
|
void SetStateBreakpoint(FStateTreeStateHandle StateHandle, EStateTreeBreakpointType BreakpointType);
|
|
void SetTransitionBreakpoint(FStateTreeIndex16 SubIndex, EStateTreeBreakpointType BreakpointType);
|
|
void SetTaskBreakpoint(FStateTreeIndex16 NodeIndex, EStateTreeBreakpointType BreakpointType);
|
|
void ClearBreakpoint(FStateTreeIndex16 NodeIndex, EStateTreeBreakpointType BreakpointType);
|
|
void ClearAllBreakpoints();
|
|
int32 NumBreakpoints() const { return Breakpoints.Num(); }
|
|
bool HasHitBreakpoint() const { return HitBreakpoint.IsSet(); }
|
|
|
|
static FText DescribeTrace(const FTraceDescriptor& TraceDescriptor);
|
|
static FText DescribeInstance(const UE::StateTreeDebugger::FInstanceDescriptor& StateTreeInstanceDesc);
|
|
|
|
/**
|
|
* Finds and returns the event collection associated to a given instance Id.
|
|
* An invalid empty collection is returned if not found (IsValid needs to be called).
|
|
* @param InstanceId Id of the instance for which the event collection is returned.
|
|
* @return Event collection associated to the provided Id or an invalid one if not found.
|
|
*/
|
|
const UE::StateTreeDebugger::FInstanceEventCollection& GetEventCollection(FStateTreeInstanceDebugId InstanceId) const;
|
|
|
|
/** Clears events from all instances. */
|
|
void ResetEventCollections();
|
|
|
|
/** Returns the recording duration in world recorded time. */
|
|
double GetRecordingDuration() const { return RecordingDuration; }
|
|
|
|
/** Returns the duration of the analysis session. This is not related to the world simulation time. */
|
|
double GetAnalysisDuration() const { return AnalysisDuration; }
|
|
|
|
/** Returns the time (based on the recording duration) associated to the selected frame. */
|
|
double GetScrubTime() const { return ScrubState.GetScrubTime(); }
|
|
void SetScrubTime(double ScrubTime);
|
|
|
|
void GetLiveTraces(TArray<FTraceDescriptor>& OutTraceDescriptors) const;
|
|
|
|
/**
|
|
* Queue a request to auto start an analysis session on the next available live trace.
|
|
* This will replace the current analysis session if any.
|
|
* @return True if connection was successfully requested or was able to use active trace, false otherwise.
|
|
*/
|
|
bool RequestAnalysisOfEditorSession();
|
|
bool IsAnalyzingEditorSession() const
|
|
{
|
|
return AnalysisTransitionType == EAnalysisTransitionType::NoneToEditor
|
|
|| AnalysisTransitionType == EAnalysisTransitionType::EditorToEditor
|
|
|| AnalysisTransitionType == EAnalysisTransitionType::SelectedToEditor;
|
|
}
|
|
|
|
bool WasAnalyzingEditorSession() const
|
|
{
|
|
return AnalysisTransitionType == EAnalysisTransitionType::EditorToSelected
|
|
|| AnalysisTransitionType == EAnalysisTransitionType::EditorToEditor;
|
|
}
|
|
|
|
bool IsAnalysisSessionActive() const { return GetAnalysisSession() != nullptr; }
|
|
bool IsAnalysisSessionPaused() const { return bSessionAnalysisPaused; }
|
|
const TraceServices::IAnalysisSession* GetAnalysisSession() const;
|
|
|
|
/**
|
|
* Tries to start an analysis for a given trace descriptor.
|
|
* On success this method will execute the OnNewSession delegate.
|
|
* @param TraceDescriptor Descriptor of the trace that needs to be analyzed
|
|
* @return True if analysis was successfully started, false otherwise.
|
|
*/
|
|
bool RequestSessionAnalysis(const FTraceDescriptor& TraceDescriptor);
|
|
void PauseSessionAnalysis() { bSessionAnalysisPaused = true; }
|
|
void ResumeSessionAnalysis()
|
|
{
|
|
bSessionAnalysisPaused = false;
|
|
HitBreakpoint.Reset();
|
|
}
|
|
void StopSessionAnalysis();
|
|
FTraceDescriptor GetSelectedTraceDescriptor() const { return ActiveSessionTraceDescriptor; }
|
|
FText GetSelectedTraceDescription() const;
|
|
|
|
FOnStateTreeDebuggerNewSession OnNewSession;
|
|
FOnStateTreeDebuggerNewInstance OnNewInstance;
|
|
FOnStateTreeDebuggerDebuggedInstanceSet OnSelectedInstanceCleared;
|
|
FOnStateTreeDebuggerScrubStateChanged OnScrubStateChanged;
|
|
FOnStateTreeDebuggerBreakpointHit OnBreakpointHit;
|
|
FOnStateTreeDebuggerActiveStatesChanges OnActiveStatesChanged;
|
|
|
|
protected:
|
|
virtual void Tick(float DeltaTime) override;
|
|
virtual bool IsTickable() const override { return true; }
|
|
virtual bool IsTickableWhenPaused() const override { return true; }
|
|
virtual bool IsTickableInEditor() const override { return true; }
|
|
virtual TStatId GetStatId() const override { RETURN_QUICK_DECLARE_CYCLE_STAT(FStateTreeDebugger, STATGROUP_Tickables); }
|
|
|
|
private:
|
|
enum class EAnalysisSourceType : uint8
|
|
{
|
|
// Analysis selected from available sessions
|
|
SelectedSession,
|
|
|
|
// Analysis automatically started from Editor new recording
|
|
EditorSession
|
|
};
|
|
|
|
enum class EAnalysisTransitionType : uint8
|
|
{
|
|
Unset,
|
|
NoneToSelected,
|
|
NoneToEditor,
|
|
EditorToSelected,
|
|
EditorToEditor,
|
|
SelectedToSelected,
|
|
SelectedToEditor,
|
|
};
|
|
|
|
void UpdateAnalysisTransitionType(EAnalysisSourceType SourceType);
|
|
|
|
void ReadTrace(double ScrubTime);
|
|
void ReadTrace(uint64 FrameIndex);
|
|
void ReadTrace(
|
|
const TraceServices::IAnalysisSession& Session,
|
|
const TraceServices::IFrameProvider& FrameProvider,
|
|
const TraceServices::FFrame& Frame
|
|
);
|
|
|
|
/**
|
|
* Tests event for given instance id against breakpoints.
|
|
* @param InstanceId Id of the statetree instance that produces the event.
|
|
* @param Event The event received from the instance.
|
|
* @return True if a breakpoint has been it, false otherwise.
|
|
*/
|
|
bool EvaluateBreakpoints(FStateTreeInstanceDebugId InstanceId, const FStateTreeTraceEventVariantType& Event);
|
|
|
|
void SendNotifications();
|
|
|
|
void SetActiveStates(const TConstArrayView<FStateTreeStateHandle> NewActiveStates);
|
|
|
|
/**
|
|
* Looks for a new live traces to start an analysis session.
|
|
* On failure, if 'RetryPollingDuration is > 0', will retry connecting every frame for 'RetryPollingDuration' seconds
|
|
* @param RetryPollingDuration - On failure, how many seconds to retry connecting during FStateTreeDebugger::Tick
|
|
* @return True if the analysis was successfully started; false otherwise.
|
|
*/
|
|
bool TryStartNewLiveSessionAnalysis(float RetryPollingDuration);
|
|
|
|
bool StartSessionAnalysis(const FTraceDescriptor& TraceDescriptor);
|
|
|
|
void SetScrubStateCollectionIndex(int32 EventCollectionIndex);
|
|
|
|
/**
|
|
* Recompute index of the span that contains the active states change event and update the active states.
|
|
* This method handles unselected instances in which case it will reset the active states and set the span index to INDEX_NONE
|
|
* */
|
|
void RefreshActiveStates();
|
|
|
|
UE::Trace::FStoreClient* GetStoreClient() const;
|
|
void GetSessionInstances(TArray<UE::StateTreeDebugger::FInstanceDescriptor>& OutInstances) const;
|
|
void UpdateInstances();
|
|
|
|
bool ProcessEvent(const FStateTreeInstanceDebugId InstanceId, const TraceServices::FFrame& Frame, const FStateTreeTraceEventVariantType& Event);
|
|
void AddEvents(double StartTime, double EndTime, const TraceServices::IFrameProvider& FrameProvider, const IStateTreeTraceProvider& StateTreeTraceProvider);
|
|
void UpdateMetadata(FTraceDescriptor& TraceDescriptor) const;
|
|
|
|
/** Module used to access the store client and analysis sessions .*/
|
|
IStateTreeModule& StateTreeModule;
|
|
|
|
/** The StateTree asset associated to this debugger. All instances will be using this asset. */
|
|
TWeakObjectPtr<const UStateTree> StateTreeAsset;
|
|
|
|
/** The trace analysis session. */
|
|
TSharedPtr<const TraceServices::IAnalysisSession> AnalysisSession;
|
|
|
|
/** Descriptor of the currently selected session */
|
|
FTraceDescriptor ActiveSessionTraceDescriptor;
|
|
|
|
/** Descriptors for all instances of the StateTree asset that have traces in the analysis session and still active. */
|
|
TArray<UE::StateTreeDebugger::FInstanceDescriptor> InstanceDescs;
|
|
|
|
/** Processed events for each instance. */
|
|
TArray<UE::StateTreeDebugger::FInstanceEventCollection> EventCollections;
|
|
|
|
/** Specific instance selected for more details */
|
|
FStateTreeInstanceDebugId SelectedInstanceId;
|
|
|
|
/** List of breakpoints set. This is per asset and not specific to an instance. */
|
|
TArray<FStateTreeDebuggerBreakpoint> Breakpoints;
|
|
|
|
/** List of currently active states in the selected instance */
|
|
TArray<FStateTreeStateHandle> ActiveStates;
|
|
|
|
/**
|
|
* When auto-connecting on next live session it is possible that a few frames are required for the tracing session to be accessible and connected to.
|
|
* This is to keep track of the previous last live session id so we can detect when the new one is available.
|
|
*/
|
|
int32 LastLiveSessionId = INDEX_NONE;
|
|
|
|
/**
|
|
* When auto-connecting on next live session it is possible that a few frames are required for the tracing session to be accessible and connected to.
|
|
* This is to keep track of the time window where we will retry.
|
|
*/
|
|
float RetryLoadNextLiveSessionTimer = 0.0f;
|
|
|
|
/** Recording duration of the analysis session in world recorded time. */
|
|
double RecordingDuration = 0;
|
|
|
|
/** Duration of the analysis session. This is not related to the world simulation time. */
|
|
double AnalysisDuration = 0;
|
|
|
|
/** Last time in the recording that we use to fetch events and we will use for the next read. */
|
|
double LastTraceReadTime = 0;
|
|
|
|
/** Combined information regarding current scrub time (e.g. frame index, event collection index, etc.) */
|
|
UE::StateTreeDebugger::FScrubState ScrubState;
|
|
|
|
/** Information stored when a breakpoint is hit while processing events and used to send notifications. */
|
|
FHitBreakpoint HitBreakpoint;
|
|
|
|
/** List of new instances discovered by processing event in the analysis session. */
|
|
TArray<FStateTreeInstanceDebugId> NewInstances;
|
|
|
|
/**
|
|
* Indicates that the debugger no longer process new events from the analysis session until it gets resumed.
|
|
* This can be an external explicit request or after hitting a breakpoint.
|
|
*/
|
|
bool bSessionAnalysisPaused = false;
|
|
|
|
/**
|
|
* Indicates the last transition type between two consecutive analyses to manage track cleanup properly.
|
|
*/
|
|
EAnalysisTransitionType AnalysisTransitionType = EAnalysisTransitionType::Unset;
|
|
};
|
|
|
|
#endif // WITH_STATETREE_DEBUGGER
|