294 lines
13 KiB
C++
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
|