Files
UnrealEngineUWP/Engine/Plugins/Runtime/StateTree/Source/StateTreeModule/Private/Debugger/StateTreeTraceAnalyzer.cpp
Yoan StAmant f74ec561de [StateTreeDebuggger] Frame details view update:
- 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]
2023-08-04 14:23:12 -04:00

193 lines
7.7 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#if WITH_STATETREE_DEBUGGER
#include "Debugger/StateTreeTraceAnalyzer.h"
#include "Debugger/StateTreeDebugger.h"
#include "Debugger/StateTreeTraceProvider.h"
#include "Debugger/StateTreeTraceTypes.h"
#include "Serialization/MemoryReader.h"
#include "TraceServices/Model/AnalysisSession.h"
FStateTreeTraceAnalyzer::FStateTreeTraceAnalyzer(TraceServices::IAnalysisSession& InSession, FStateTreeTraceProvider& InProvider)
: Session(InSession)
, Provider(InProvider)
{
}
void FStateTreeTraceAnalyzer::OnAnalysisBegin(const FOnAnalysisContext& Context)
{
auto& Builder = Context.InterfaceBuilder;
Builder.RouteEvent(RouteId_WorldTimestamp, "StateTreeDebugger", "WorldTimestampEvent");
Builder.RouteEvent(RouteId_Instance, "StateTreeDebugger", "InstanceEvent");
Builder.RouteEvent(RouteId_Phase, "StateTreeDebugger", "PhaseEvent");
Builder.RouteEvent(RouteId_LogMessage, "StateTreeDebugger", "LogEvent");
Builder.RouteEvent(RouteId_State, "StateTreeDebugger", "StateEvent");
Builder.RouteEvent(RouteId_Task, "StateTreeDebugger", "TaskEvent");
Builder.RouteEvent(RouteId_Transition, "StateTreeDebugger", "TransitionEvent");
Builder.RouteEvent(RouteId_Condition, "StateTreeDebugger", "ConditionEvent");
Builder.RouteEvent(RouteId_ActiveStates, "StateTreeDebugger", "ActiveStatesEvent");
}
bool FStateTreeTraceAnalyzer::OnEvent(const uint16 RouteId, EStyle Style, const FOnEventContext& Context)
{
LLM_SCOPE_BYNAME(TEXT("Insights/FStateTreeAnalyzer"));
TraceServices::FAnalysisSessionEditScope _(Session);
const auto& EventData = Context.EventData;
switch (RouteId)
{
case RouteId_WorldTimestamp:
{
WorldTime = EventData.GetValue<double>("WorldTime");
break;
}
case RouteId_Instance:
{
FString ObjectName, ObjectPathName;
EventData.GetString("TreeName", ObjectName);
EventData.GetString("TreePath", ObjectPathName);
const FTopLevelAssetPath Path((FName)ObjectPathName, (FName)ObjectName);
TWeakObjectPtr<const UStateTree> WeakStateTree;
{
// This might not work when using a debugger on a client but should be fine in Editor as long as
// we are not trying to find the object during GC. We might not currently be in the game thread.
// @todo STDBG: eventually errors should be reported in the UI
FGCScopeGuard Guard;
WeakStateTree = FindObject<UStateTree>(Path);
}
if (const UStateTree* StateTree = WeakStateTree.Get())
{
const uint32 CompiledDataHash = EventData.GetValue<uint32>("CompiledDataHash");
if (StateTree->LastCompiledEditorDataHash == CompiledDataHash)
{
FString InstanceName;
EventData.GetString("InstanceName", InstanceName);
Provider.AppendInstanceEvent(StateTree,
FStateTreeInstanceDebugId(EventData.GetValue<uint32>("InstanceId"), EventData.GetValue<uint32>("InstanceSerial")),
*InstanceName,
Context.EventTime.AsSeconds(EventData.GetValue<uint64>("Cycle")),
WorldTime,
EventData.GetValue<EStateTreeTraceEventType>("EventType"));
}
else
{
UE_LOG(LogStateTree, Warning, TEXT("Traces are not using the same StateTree asset version as the current asset."));
}
}
else
{
UE_LOG(LogStateTree, Warning, TEXT("Unable to find StateTree asset: %s : %s"), *ObjectPathName, *ObjectName);
}
break;
}
case RouteId_Phase:
{
const FStateTreeTracePhaseEvent Event(WorldTime,
EventData.GetValue<EStateTreeUpdatePhase>("Phase"),
EventData.GetValue<EStateTreeTraceEventType>("EventType"),
FStateTreeStateHandle(EventData.GetValue<uint16>("StateIndex")));
Provider.AppendEvent(FStateTreeInstanceDebugId(EventData.GetValue<uint32>("InstanceId"), EventData.GetValue<uint32>("InstanceSerial")),
Context.EventTime.AsSeconds(EventData.GetValue<uint64>("Cycle")),
FStateTreeTraceEventVariantType(TInPlaceType<FStateTreeTracePhaseEvent>(), Event));
break;
}
case RouteId_LogMessage:
{
FString Message;
EventData.GetString("Message", Message);
const FStateTreeTraceLogEvent Event(WorldTime, Message);
Provider.AppendEvent(FStateTreeInstanceDebugId(EventData.GetValue<uint32>("InstanceId"), EventData.GetValue<uint32>("InstanceSerial")),
Context.EventTime.AsSeconds(EventData.GetValue<uint64>("Cycle")),
FStateTreeTraceEventVariantType(TInPlaceType<FStateTreeTraceLogEvent>(), Event));
break;
}
case RouteId_State:
{
const FStateTreeTraceStateEvent Event(WorldTime,
FStateTreeIndex16(EventData.GetValue<uint16>("StateIndex")),
EventData.GetValue<EStateTreeTraceEventType>("EventType"),
EventData.GetValue<EStateTreeStateSelectionBehavior>("SelectionBehavior"));
Provider.AppendEvent(FStateTreeInstanceDebugId(EventData.GetValue<uint32>("InstanceId"), EventData.GetValue<uint32>("InstanceSerial")),
Context.EventTime.AsSeconds(EventData.GetValue<uint64>("Cycle")),
FStateTreeTraceEventVariantType(TInPlaceType<FStateTreeTraceStateEvent>(), Event));
break;
}
case RouteId_Task:
{
FString TypePath, DataAsText;
FMemoryReaderView Archive(EventData.GetArrayView<uint8>("DataView"));
Archive << TypePath;
Archive << DataAsText;
const FStateTreeTraceTaskEvent Event(WorldTime,
FStateTreeIndex16(EventData.GetValue<uint16>("NodeIndex")),
EventData.GetValue<EStateTreeTraceEventType>("EventType"),
EventData.GetValue<EStateTreeRunStatus>("Status"),
TypePath, DataAsText);
Provider.AppendEvent(FStateTreeInstanceDebugId(EventData.GetValue<uint32>("InstanceId"), EventData.GetValue<uint32>("InstanceSerial")),
Context.EventTime.AsSeconds(EventData.GetValue<uint64>("Cycle")),
FStateTreeTraceEventVariantType(TInPlaceType<FStateTreeTraceTaskEvent>(), Event));
break;
}
case RouteId_Condition:
{
FString TypePath, DataAsText;
FMemoryReaderView Archive(EventData.GetArrayView<uint8>("DataView"));
Archive << TypePath;
Archive << DataAsText;
const FStateTreeTraceConditionEvent Event(WorldTime,
FStateTreeIndex16(EventData.GetValue<uint16>("NodeIndex")),
EventData.GetValue<EStateTreeTraceEventType>("EventType"),
TypePath, DataAsText);
Provider.AppendEvent(FStateTreeInstanceDebugId(EventData.GetValue<uint32>("InstanceId"), EventData.GetValue<uint32>("InstanceSerial")),
Context.EventTime.AsSeconds(EventData.GetValue<uint64>("Cycle")),
FStateTreeTraceEventVariantType(TInPlaceType<FStateTreeTraceConditionEvent>(), Event));
break;
}
case RouteId_Transition:
{
const FStateTreeTraceTransitionEvent Event(WorldTime,
FStateTreeTransitionSource(
EventData.GetValue<EStateTreeTransitionSourceType>("SourceType"),
FStateTreeIndex16(EventData.GetValue<uint16>("TransitionIndex")),
FStateTreeStateHandle(EventData.GetValue<uint16>("TargetStateIndex")),
EventData.GetValue<EStateTreeTransitionPriority>("Priority")
),
EventData.GetValue<EStateTreeTraceEventType>("EventType"));
Provider.AppendEvent(FStateTreeInstanceDebugId(EventData.GetValue<uint32>("InstanceId"), EventData.GetValue<uint32>("InstanceSerial")),
Context.EventTime.AsSeconds(EventData.GetValue<uint64>("Cycle")),
FStateTreeTraceEventVariantType(TInPlaceType<FStateTreeTraceTransitionEvent>(), Event));
break;
}
case RouteId_ActiveStates:
{
FStateTreeTraceActiveStatesEvent Event(WorldTime);
Event.ActiveStates = EventData.GetArrayView<uint16>("ActiveStates");
Provider.AppendEvent(FStateTreeInstanceDebugId(EventData.GetValue<uint32>("InstanceId"), EventData.GetValue<uint32>("InstanceSerial")),
Context.EventTime.AsSeconds(EventData.GetValue<uint64>("Cycle")),
FStateTreeTraceEventVariantType(TInPlaceType<FStateTreeTraceActiveStatesEvent>(), Event));
break;
}
default:
ensureMsgf(false, TEXT("Unhandle route id: %s"), RouteId);
}
return true;
}
#endif // WITH_STATETREE_DEBUGGER