Files
UnrealEngine/Engine/Plugins/Animation/GameplayInsights/Source/RewindDebugger/Private/RewindDebuggerModule.cpp
2025-05-18 13:04:45 +08:00

294 lines
13 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "RewindDebuggerModule.h"
#include "AnimInstanceHelpers.h"
#include "BlueprintDoubleClickHandler.h"
#include "Engine/Selection.h"
#include "Features/IModularFeatures.h"
#include "Framework/Docking/LayoutExtender.h"
#include "IAnimationBlueprintEditorModule.h"
#include "Kismet2/DebuggerCommands.h"
#include "LevelEditor.h"
#include "Modules/ModuleManager.h"
#include "PropertyTraceMenu.h"
#include "RewindDebugger.h"
#include "RewindDebuggerCommands.h"
#include "RewindDebuggerStyle.h"
#include "SRewindDebugger.h"
#include "ToolMenus.h"
#include "Widgets/Docking/SDockTab.h"
#include "WorkspaceMenuStructure.h"
#include "WorkspaceMenuStructureModule.h"
#define LOCTEXT_NAMESPACE "RewindDebuggerModule"
const FName FRewindDebuggerModule::MainTabName("RewindDebugger2");
const FName FRewindDebuggerModule::DetailsTabName("RewindDebuggerDetails2");
const FName FRewindDebuggerModule::MainMenuName("RewindDebugger.MainMenu");
const FName FRewindDebuggerModule::TrackContextMenuName("RewindDebugger.TrackContextMenu");
TSharedRef<SDockTab> FRewindDebuggerModule::SpawnRewindDebuggerDetailsTab(const FSpawnTabArgs& SpawnTabArgs)
{
if (FRewindDebugger::Instance() == nullptr)
{
FRewindDebugger::Initialize();
}
FRewindDebugger* RewindDebugger = FRewindDebugger::Instance();
RewindDebugger->SetIsDetailsPanelOpen(true);
TSharedRef<SDockTab> MajorTab = SNew(SDockTab)
.TabRole(ETabRole::PanelTab);
MajorTab->SetOnTabClosed(SDockTab::FOnTabClosedCallback::CreateLambda( [](TSharedRef<SDockTab>) { FRewindDebugger::Instance()->SetIsDetailsPanelOpen(false); }));
RewindDebugger->UpdateDetailsPanel(MajorTab);
return MajorTab;
}
TSharedRef<SDockTab> FRewindDebuggerModule::SpawnRewindDebuggerTab(const FSpawnTabArgs& SpawnTabArgs)
{
if (FRewindDebugger::Instance() == nullptr)
{
FRewindDebugger::Initialize();
}
const TSharedRef<SDockTab> MajorTab = SNew(SDockTab)
.TabRole(ETabRole::PanelTab)
.OnTabClosed_Lambda([this](TSharedRef<SDockTab>)
{
// clear reference to widget so it will be destroyed
RewindDebuggerWidget = nullptr;
});
TSharedPtr<FUICommandList> CommandList = MakeShared<FUICommandList>();
const FRewindDebuggerCommands& Commands = FRewindDebuggerCommands::Get();
FRewindDebugger* DebuggerInstance = FRewindDebugger::Instance();
CommandList->MapAction(Commands.Play,
FExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::Play),
FCanExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::CanPlay),
FIsActionChecked(),
FIsActionButtonVisible());
CommandList->MapAction(Commands.Pause,
FExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::Pause),
FCanExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::CanPause),
FIsActionChecked(),
FIsActionButtonVisible());
CommandList->MapAction(Commands.PauseOrPlay,
FExecuteAction::CreateLambda([DebuggerInstance]()
{
if (DebuggerInstance->CanPause())
{
DebuggerInstance->Pause();
}
else if (DebuggerInstance->CanPlay())
{
DebuggerInstance->Play();
}
}),
FCanExecuteAction::CreateLambda([DebuggerInstance]()
{
return DebuggerInstance->CanPause() || DebuggerInstance->CanPlay();
}),
FIsActionChecked(),
FIsActionButtonVisible());
CommandList->MapAction(Commands.ReversePlay,
FExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::PlayReverse),
FCanExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::CanPlayReverse),
FIsActionChecked(),
FIsActionButtonVisible());
CommandList->MapAction(Commands.PreviousFrame,
FExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::StepBackward),
FCanExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::CanScrub),
FIsActionChecked(),
FIsActionButtonVisible());
CommandList->MapAction(Commands.FirstFrame,
FExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::ScrubToStart),
FCanExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::CanScrub),
FIsActionChecked(),
FIsActionButtonVisible());
CommandList->MapAction(Commands.LastFrame,
FExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::ScrubToEnd),
FCanExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::CanScrub),
FIsActionChecked(),
FIsActionButtonVisible());
CommandList->MapAction(Commands.NextFrame,
FExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::StepForward),
FCanExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::CanScrub),
FIsActionChecked(),
FIsActionButtonVisible());
CommandList->MapAction(Commands.StartRecording,
FExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::StartRecording),
FCanExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::CanStartRecording),
FIsActionChecked(),
FIsActionButtonVisible::CreateLambda([]() { return !FRewindDebugger::Instance()->IsRecording();}));
CommandList->MapAction(Commands.StopRecording,
FExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::StopRecording),
FCanExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::CanStopRecording),
FIsActionChecked(),
FIsActionButtonVisible::CreateRaw(DebuggerInstance, &FRewindDebugger::CanStopRecording));
CommandList->MapAction(Commands.AutoEject,
FExecuteAction::CreateLambda([DebuggerInstance]() { DebuggerInstance->SetShouldAutoEject(!DebuggerInstance->ShouldAutoEject()); }),
FCanExecuteAction(),
FCanExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::ShouldAutoEject),
FIsActionButtonVisible());
CommandList->MapAction(Commands.AutoRecord,
FExecuteAction::CreateLambda([DebuggerInstance]() { DebuggerInstance->SetShouldAutoRecordOnPIE(!DebuggerInstance->ShouldAutoRecordOnPIE()); }),
FCanExecuteAction(),
FCanExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::ShouldAutoRecordOnPIE),
FIsActionButtonVisible());
CommandList->MapAction(Commands.OpenTrace,
FExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::OpenTrace),
FCanExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::CanOpenTrace),
FIsActionChecked(),
FIsActionButtonVisible());
CommandList->MapAction(Commands.AttachToSession,
FExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::AttachToSession),
FCanExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::CanOpenTrace),
FIsActionChecked(),
FIsActionButtonVisible());
CommandList->MapAction(Commands.SaveTrace,
FExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::SaveTrace),
FCanExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::CanSaveTrace),
FIsActionChecked(),
FIsActionButtonVisible());
CommandList->MapAction(Commands.ClearTrace,
FExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::ClearTrace),
FCanExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::CanClearTrace),
FIsActionChecked(),
FIsActionButtonVisible());
// Register PIE Rewind Debugger Commands
if (GEditor != nullptr)
{
check(FPlayWorldCommands::GlobalPlayWorldActions.IsValid());
FPlayWorldCommands::GlobalPlayWorldActions->MapAction(Commands.StartRecording,
FExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::StartRecording),
FCanExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::CanStartRecording),
FIsActionChecked(),
FIsActionButtonVisible::CreateLambda([]() { return !FRewindDebugger::Instance()->IsRecording();}));
FPlayWorldCommands::GlobalPlayWorldActions->MapAction(Commands.StopRecording,
FExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::StopRecording),
FCanExecuteAction::CreateRaw(DebuggerInstance, &FRewindDebugger::CanStopRecording),
FIsActionChecked(),
FIsActionButtonVisible::CreateRaw(DebuggerInstance, &FRewindDebugger::CanStopRecording));
}
RewindDebuggerWidget = SNew(SRewindDebugger, CommandList.ToSharedRef(), MajorTab, SpawnTabArgs.GetOwnerWindow())
.DebuggedObjectName({ DebuggerInstance->GetDebugTargetActorProperty(), URewindDebuggerSettings::Get().DebugTargetActor})
.RecordingDuration(DebuggerInstance->GetRecordingDurationProperty())
.Tracks(&DebuggerInstance->GetTracks())
.TraceTime(DebuggerInstance->GetTraceTimeProperty())
.OnScrubPositionChanged_Raw(DebuggerInstance,&FRewindDebugger::ScrubToTime)
.OnViewRangeChanged_Raw(DebuggerInstance,&FRewindDebugger::SetCurrentViewRange)
.OnTrackDoubleClicked_Raw(DebuggerInstance, &FRewindDebugger::TrackDoubleClicked)
.OnTrackSelectionChanged_Raw(DebuggerInstance, &FRewindDebugger::TrackSelectionChanged)
.BuildTrackContextMenu_Raw(DebuggerInstance, &FRewindDebugger::BuildTrackContextMenu)
.TrackTypes_Lambda([]() { return FRewindDebugger::Instance()->GetTrackTypes(); })
.ScrubTime_Lambda([]() { return FRewindDebugger::Instance()->GetScrubTime(); });
DebuggerInstance->SetTrackCursorDelegate(FRewindDebugger::FOnTrackCursor::CreateSP(RewindDebuggerWidget.Get(), &SRewindDebugger::TrackCursor));
DebuggerInstance->SetTrackListChangedDelegate(FRewindDebugger::FOnTrackListChanged::CreateSP(RewindDebuggerWidget.Get(), &SRewindDebugger::RefreshTracks));
MajorTab->SetContent(RewindDebuggerWidget.ToSharedRef());
return MajorTab;
}
static FAnimInstanceDoubleClickHandler AnimInstanceDoubleClickHandler;
static FBlueprintDoubleClickHandler BlueprintDoubleClickHandler;
void FRewindDebuggerModule::StartupModule()
{
UToolMenus::Get()->RegisterMenu(FRewindDebuggerModule::MainMenuName);
UToolMenus::Get()->RegisterMenu(FRewindDebuggerModule::TrackContextMenuName);
FRewindDebuggerStyle::Initialize();
FRewindDebuggerCommands::Register();
FLevelEditorModule& LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>("LevelEditor");
/* LevelEditorTabManagerChangedHandle = */ LevelEditorModule.OnTabManagerChanged().AddLambda([this]()
{
FLevelEditorModule& LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>("LevelEditor");
TSharedPtr<FTabManager> LevelEditorTabManager = LevelEditorModule.GetLevelEditorTabManager();
LevelEditorTabManager->RegisterTabSpawner(
MainTabName, FOnSpawnTab::CreateRaw(this, &FRewindDebuggerModule::SpawnRewindDebuggerTab))
.SetDisplayName(LOCTEXT("TabTitle", "Rewind Debugger"))
.SetIcon(FSlateIcon("RewindDebuggerStyle", "RewindDebugger.RewindIcon"))
.SetTooltipText(LOCTEXT("TooltipText", "Opens Rewind Debugger."))
.SetGroup(WorkspaceMenu::GetMenuStructure().GetDeveloperToolsDebugCategory());
LevelEditorTabManager->RegisterTabSpawner(
DetailsTabName, FOnSpawnTab::CreateStatic(&FRewindDebuggerModule::SpawnRewindDebuggerDetailsTab))
.SetDisplayName(LOCTEXT("DetailsTabTitle", "Rewind Debugger Details"))
.SetIcon(FSlateIcon("RewindDebuggerStyle", "RewindDebugger.RewindDetailsIcon"))
.SetTooltipText(LOCTEXT("DetailsWindowTooltipText", "Opens Rewind Debugger Details Window."))
.SetGroup(WorkspaceMenu::GetMenuStructure().GetDeveloperToolsDebugCategory());
});
/*LevelEditorLayoutExtensionHandle = */ LevelEditorModule.OnRegisterLayoutExtensions().AddLambda(
[this](FLayoutExtender& Extender)
{
Extender.ExtendLayout(FName("LevelEditorSelectionDetails"), ELayoutExtensionPosition::After, FTabManager::FTab(DetailsTabName, ETabState::ClosedTab));
Extender.ExtendLayout(FName("Sequencer"), ELayoutExtensionPosition::After, FTabManager::FTab(MainTabName, ETabState::ClosedTab));
}
);
RewindDebuggerCameraExtension.Initialize();
RewindDebuggerAnimationExtension.Initialize();
IModularFeatures::Get().RegisterModularFeature(IRewindDebuggerExtension::ModularFeatureName, &RewindDebuggerCameraExtension);
IModularFeatures::Get().RegisterModularFeature(IRewindDebuggerExtension::ModularFeatureName, &RewindDebuggerAnimationExtension);
IModularFeatures::Get().RegisterModularFeature(IRewindDebuggerDoubleClickHandler::ModularFeatureName, &AnimInstanceDoubleClickHandler);
IModularFeatures::Get().RegisterModularFeature(IRewindDebuggerDoubleClickHandler::ModularFeatureName, &BlueprintDoubleClickHandler);
FPropertyTraceMenu::Register();
FAnimInstanceMenu::Register();
FRewindDebugger::RegisterTrackContextMenu();
FRewindDebugger::RegisterToolBar();
}
void FRewindDebuggerModule::ShutdownModule()
{
RewindDebuggerAnimationExtension.Shutdown();
IModularFeatures::Get().UnregisterModularFeature(IRewindDebuggerExtension::ModularFeatureName, &RewindDebuggerCameraExtension);
IModularFeatures::Get().UnregisterModularFeature(IRewindDebuggerExtension::ModularFeatureName, &RewindDebuggerAnimationExtension);
IModularFeatures::Get().UnregisterModularFeature(IRewindDebuggerDoubleClickHandler::ModularFeatureName, &AnimInstanceDoubleClickHandler);
IModularFeatures::Get().UnregisterModularFeature(IRewindDebuggerDoubleClickHandler::ModularFeatureName, &BlueprintDoubleClickHandler);
FRewindDebuggerCommands::Unregister();
FRewindDebuggerStyle::Shutdown();
FRewindDebugger::Shutdown();
}
IMPLEMENT_MODULE(FRewindDebuggerModule, RewindDebugger);
#undef LOCTEXT_NAMESPACE