2023-03-14 13:35:46 -04:00
|
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
|
|
|
|
|
#if WITH_STATETREE_DEBUGGER
|
|
|
|
|
|
|
|
|
|
#include "Debugger/StateTreeTraceProvider.h"
|
|
|
|
|
#include "StateTreeTypes.h"
|
|
|
|
|
#include "Debugger/StateTreeDebugger.h"
|
|
|
|
|
|
|
|
|
|
FName FStateTreeTraceProvider::ProviderName("StateTreeDebuggerProvider");
|
|
|
|
|
|
|
|
|
|
#define LOCTEXT_NAMESPACE "StateTreeDebuggerProvider"
|
|
|
|
|
|
|
|
|
|
FStateTreeTraceProvider::FStateTreeTraceProvider(TraceServices::IAnalysisSession& InSession)
|
|
|
|
|
: Session(InSession)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FStateTreeTraceProvider::ReadTimelines(const FStateTreeInstanceDebugId InstanceId, const TFunctionRef<void(const FStateTreeInstanceDebugId ProcessedInstanceId, const FEventsTimeline&)> Callback) const
|
|
|
|
|
{
|
|
|
|
|
Session.ReadAccessCheck();
|
|
|
|
|
|
|
|
|
|
// Read specific timeline if specified
|
|
|
|
|
if (InstanceId.IsValid())
|
|
|
|
|
{
|
|
|
|
|
const uint32* IndexPtr = InstanceIdToDebuggerEntryTimelines.Find(InstanceId);
|
|
|
|
|
if (IndexPtr != nullptr && EventsTimelines.IsValidIndex(*IndexPtr))
|
|
|
|
|
{
|
|
|
|
|
Callback(InstanceId, *EventsTimelines[*IndexPtr]);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for(auto It = InstanceIdToDebuggerEntryTimelines.CreateConstIterator(); It; ++It)
|
|
|
|
|
{
|
|
|
|
|
if (EventsTimelines.IsValidIndex(It.Value()))
|
|
|
|
|
{
|
|
|
|
|
Callback(It.Key(), *EventsTimelines[It.Value()]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-26 11:59:58 -04:00
|
|
|
return EventsTimelines.Num() > 0;
|
2023-03-14 13:35:46 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-09 12:57:56 -04:00
|
|
|
bool FStateTreeTraceProvider::ReadTimelines(const UStateTree& StateTree, TFunctionRef<void(const FStateTreeInstanceDebugId ProcessedInstanceId, const FEventsTimeline&)> Callback) const
|
|
|
|
|
{
|
|
|
|
|
Session.ReadAccessCheck();
|
|
|
|
|
|
|
|
|
|
for (auto It = InstanceIdToDebuggerEntryTimelines.CreateConstIterator(); It; ++It)
|
|
|
|
|
{
|
|
|
|
|
check(EventsTimelines.IsValidIndex(It.Value()));
|
|
|
|
|
check(Descriptors.Num() == EventsTimelines.Num());
|
|
|
|
|
|
|
|
|
|
if (Descriptors[It.Value()].StateTree == &StateTree)
|
|
|
|
|
{
|
|
|
|
|
Callback(Descriptors[It.Value()].Id, *EventsTimelines[It.Value()]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return EventsTimelines.Num() > 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FStateTreeTraceProvider::AppendEvent(const FStateTreeInstanceDebugId InInstanceId, const double InTime, const FStateTreeTraceEventVariantType& InEvent)
|
2023-03-14 13:35:46 -04:00
|
|
|
{
|
|
|
|
|
Session.WriteAccessCheck();
|
|
|
|
|
|
2023-05-29 10:13:21 -04:00
|
|
|
// It is currently possible to receive events from an instance without receiving event `EStateTreeTraceEventType::Push` first
|
2023-05-26 11:59:58 -04:00
|
|
|
// (i.e. traces were activated after the statetree instance execution was started).
|
|
|
|
|
// We plan to buffer the Instance events (Started/Stopped) to address this but for now we ignore events related to that instance.
|
|
|
|
|
if (const uint32* IndexPtr = InstanceIdToDebuggerEntryTimelines.Find(InInstanceId))
|
2023-03-14 13:35:46 -04:00
|
|
|
{
|
2023-05-09 12:57:56 -04:00
|
|
|
EventsTimelines[*IndexPtr]->AppendEvent(InTime, InEvent);
|
2023-03-14 13:35:46 -04:00
|
|
|
}
|
2023-05-09 12:57:56 -04:00
|
|
|
|
2023-03-14 13:35:46 -04:00
|
|
|
Session.UpdateDurationSeconds(InTime);
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-09 12:57:56 -04:00
|
|
|
void FStateTreeTraceProvider::AppendInstanceEvent(
|
2023-03-14 13:35:46 -04:00
|
|
|
const UStateTree* InStateTree,
|
|
|
|
|
const FStateTreeInstanceDebugId InInstanceId,
|
|
|
|
|
const TCHAR* InInstanceName,
|
2023-05-09 12:57:56 -04:00
|
|
|
const double InTime,
|
2023-05-26 11:59:58 -04:00
|
|
|
const double InWorldRecordingTime,
|
2023-05-29 10:13:21 -04:00
|
|
|
const EStateTreeTraceEventType InEventType)
|
2023-03-14 13:35:46 -04:00
|
|
|
{
|
2023-05-29 10:13:21 -04:00
|
|
|
if (InEventType == EStateTreeTraceEventType::Push)
|
2023-03-14 13:35:46 -04:00
|
|
|
{
|
2023-05-26 11:59:58 -04:00
|
|
|
Descriptors.Emplace(InStateTree, InInstanceId, InInstanceName, TRange<double>(InWorldRecordingTime, std::numeric_limits<double>::max()));
|
2023-05-09 12:57:56 -04:00
|
|
|
|
|
|
|
|
check(InstanceIdToDebuggerEntryTimelines.Find(InInstanceId) == nullptr);
|
|
|
|
|
InstanceIdToDebuggerEntryTimelines.Add(InInstanceId, EventsTimelines.Num());
|
|
|
|
|
|
|
|
|
|
EventsTimelines.Emplace(MakeShared<TraceServices::TPointTimeline<FStateTreeTraceEventVariantType>>(Session.GetLinearAllocator()));
|
2023-03-14 13:35:46 -04:00
|
|
|
}
|
2023-05-29 10:13:21 -04:00
|
|
|
else if (InEventType == EStateTreeTraceEventType::Pop)
|
2023-03-14 13:35:46 -04:00
|
|
|
{
|
2023-05-26 11:59:58 -04:00
|
|
|
// Process only if timeline can be found. See details in AppendEvent comment.
|
|
|
|
|
if (const uint32* Index = InstanceIdToDebuggerEntryTimelines.Find(InInstanceId))
|
2023-05-09 12:57:56 -04:00
|
|
|
{
|
|
|
|
|
check(Descriptors.IsValidIndex(*Index));
|
2023-05-26 11:59:58 -04:00
|
|
|
Descriptors[*Index].Lifetime.SetUpperBound(InWorldRecordingTime);
|
2023-05-09 12:57:56 -04:00
|
|
|
}
|
2023-03-14 13:35:46 -04:00
|
|
|
}
|
2023-05-09 12:57:56 -04:00
|
|
|
|
|
|
|
|
Session.UpdateDurationSeconds(InTime);
|
2023-03-14 13:35:46 -04:00
|
|
|
}
|
|
|
|
|
|
2023-05-09 12:57:56 -04:00
|
|
|
void FStateTreeTraceProvider::GetInstances(TArray<UE::StateTreeDebugger::FInstanceDescriptor>& OutInstances) const
|
2023-03-14 13:35:46 -04:00
|
|
|
{
|
2023-05-09 12:57:56 -04:00
|
|
|
OutInstances = Descriptors;
|
2023-03-14 13:35:46 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef LOCTEXT_NAMESPACE
|
|
|
|
|
|
|
|
|
|
#endif // WITH_STATETREE_DEBUGGER
|