// Copyright Epic Games, Inc. All Rights Reserved. #include "AnimInstanceHelpers.h" #include "Modules/ModuleManager.h" #include "ObjectTrace.h" #include "IGameplayProvider.h" #include "Animation/AnimBlueprint.h" #include "Animation/AnimBlueprintGeneratedClass.h" #include "Editor.h" #include "EdGraph/EdGraph.h" #include "RewindDebuggerAnimation.h" #include "Subsystems/AssetEditorSubsystem.h" #include "IAnimationBlueprintEditor.h" #include "RewindDebuggerModule.h" #include "Insights/IUnrealInsightsModule.h" #include "ToolMenus.h" #define LOCTEXT_NAMESPACE "SRewindDebuggerAnimBPTools" static bool OpenAnimBlueprintAndAttachDebugger(const TraceServices::IAnalysisSession* Session, uint64 ObjectId) { TraceServices::FAnalysisSessionReadScope SessionReadScope(*Session); if (const IGameplayProvider* GameplayProvider = Session->ReadProvider("GameplayProvider")) { if (const FObjectInfo* ObjectInfo = GameplayProvider->FindObjectInfo(ObjectId)) { if (const FClassInfo* ClassInfo = GameplayProvider->FindClassInfo(ObjectInfo->ClassId)) { if (UAnimBlueprintGeneratedClass* InstanceClass = TSoftObjectPtr(FSoftObjectPath(ClassInfo->PathName)).LoadSynchronous()) { if(UAnimBlueprint* AnimBlueprint = Cast(InstanceClass->ClassGeneratedBy)) { GEditor->GetEditorSubsystem()->OpenEditorForAsset(AnimBlueprint); UObject* SelectedInstance = nullptr; #if OBJECT_TRACE_ENABLED SelectedInstance = FObjectTrace::GetObjectFromId(ObjectId); #endif if (SelectedInstance == nullptr) { if (FRewindDebuggerAnimation* RewindDebuggerAnimation = FRewindDebuggerAnimation::GetInstance()) { SelectedInstance = RewindDebuggerAnimation->GetDebugAnimInstance(ObjectId); } } if(SelectedInstance) { AnimBlueprint->SetObjectBeingDebugged(SelectedInstance); } if(IAnimationBlueprintEditor* AnimBlueprintEditor = static_cast(GEditor->GetEditorSubsystem()->FindEditorForAsset(AnimBlueprint, true))) { // navigate the opened editor to the AnimGraph if (AnimBlueprint->FunctionGraphs.Num() > 0) { AnimBlueprintEditor->JumpToHyperlink(AnimBlueprint->FunctionGraphs[0]); } } return true; } } } } } return false; } bool FAnimInstanceDoubleClickHandler::HandleDoubleClick(IRewindDebugger* RewindDebugger) { TSharedPtr SelectedObject = RewindDebugger->GetSelectedObject(); if (SelectedObject.IsValid()) { return OpenAnimBlueprintAndAttachDebugger(RewindDebugger->GetAnalysisSession(), SelectedObject->GetUObjectId()); } return false; } FName FAnimInstanceDoubleClickHandler::GetTargetTypeName() const { static const FName ObjectTypeName = "AnimInstance"; return ObjectTypeName; } void FAnimInstanceMenu::Register() { #if OBJECT_TRACE_ENABLED UToolMenu* Menu = UToolMenus::Get()->FindMenu(FRewindDebuggerModule::TrackContextMenuName); FToolMenuSection& Section = Menu->FindOrAddSection("Blueprint"); Section.AddDynamicEntry("DebugAnimInstanceEntry", FNewToolMenuSectionDelegate::CreateLambda([](FToolMenuSection& InSection) { URewindDebuggerTrackContextMenuContext* Context = InSection.FindContext(); if (Context && Context->SelectedObject.IsValid() && Context->TypeHierarchy.Contains("AnimInstance")) { InSection.AddMenuEntry(NAME_None, LOCTEXT("Open AnimBP", "Open/Debug AnimGraph"), LOCTEXT("Open AnimBP ToolTip", "Open this Animation Blueprint and attach the debugger to this instance"), FSlateIcon(), FExecuteAction::CreateLambda([ObjectId = Context->SelectedObject->GetUObjectId()]() { const IUnrealInsightsModule& UnrealInsightsModule = FModuleManager::LoadModuleChecked("TraceInsights"); const TSharedPtr Session = UnrealInsightsModule.GetAnalysisSession(); OpenAnimBlueprintAndAttachDebugger(Session.Get(), ObjectId); })); } })); #endif } #undef LOCTEXT_NAMESPACE