// Copyright Epic Games, Inc. All Rights Reserved. #include "SNetworkingProfilerWindow.h" #include "EditorStyleSet.h" #include "Framework/Commands/UICommandList.h" #include "Framework/Docking/WorkspaceItem.h" #include "Framework/MultiBox/MultiBoxBuilder.h" #include "SlateOptMacros.h" #include "Widgets/Docking/SDockTab.h" #include "Widgets/Images/SImage.h" #include "Widgets/Layout/SBorder.h" #include "Widgets/Layout/SBox.h" #include "Widgets/Layout/SSpacer.h" #include "Widgets/Notifications/SNotificationList.h" #include "Widgets/SBoxPanel.h" #include "Widgets/Text/STextBlock.h" #if WITH_EDITOR #include "EngineAnalytics.h" #include "Runtime/Analytics/Analytics/Public/AnalyticsEventAttribute.h" #include "Runtime/Analytics/Analytics/Public/Interfaces/IAnalyticsProvider.h" #endif // WITH_EDITOR // Insights #include "Insights/Common/InsightsMenuBuilder.h" #include "Insights/InsightsManager.h" #include "Insights/InsightsStyle.h" #include "Insights/NetworkingProfiler/NetworkingProfilerManager.h" #include "Insights/NetworkingProfiler/Widgets/SNetStatsView.h" #include "Insights/NetworkingProfiler/Widgets/SNetworkingProfilerToolbar.h" #include "Insights/NetworkingProfiler/Widgets/SPacketContentView.h" #include "Insights/NetworkingProfiler/Widgets/SPacketView.h" #include "Insights/Version.h" #include "Insights/Widgets/SInsightsSettings.h" //////////////////////////////////////////////////////////////////////////////////////////////////// #define LOCTEXT_NAMESPACE "SNetworkingProfilerWindow" //////////////////////////////////////////////////////////////////////////////////////////////////// const FName FNetworkingProfilerTabs::ToolbarID(TEXT("Toolbar")); const FName FNetworkingProfilerTabs::PacketViewID(TEXT("PacketView")); const FName FNetworkingProfilerTabs::PacketContentViewID(TEXT("PacketContent")); const FName FNetworkingProfilerTabs::NetStatsViewID(TEXT("NetStats")); //////////////////////////////////////////////////////////////////////////////////////////////////// SNetworkingProfilerWindow::SNetworkingProfilerWindow() : AvailableGameInstances(), SelectedGameInstance(nullptr), AvailableConnections(), SelectedConnection(nullptr), AvailableConnectionModes(), SelectedConnectionMode(nullptr), DurationActive(0.0f) { } //////////////////////////////////////////////////////////////////////////////////////////////////// SNetworkingProfilerWindow::~SNetworkingProfilerWindow() { if (NetStatsView) { HideTab(FNetworkingProfilerTabs::NetStatsViewID); check(NetStatsView == nullptr); } if (PacketContentView) { HideTab(FNetworkingProfilerTabs::PacketContentViewID); check(PacketContentView == nullptr); } if (PacketView) { HideTab(FNetworkingProfilerTabs::PacketViewID); check(PacketView == nullptr); } HideTab(FNetworkingProfilerTabs::ToolbarID); #if WITH_EDITOR if (DurationActive > 0.0f && FEngineAnalytics::IsAvailable()) { FEngineAnalytics::GetProvider().RecordEvent(TEXT("Insights.Usage.NetworkingProfiler"), FAnalyticsEventAttribute(TEXT("Duration"), DurationActive)); } #endif // WITH_EDITOR } //////////////////////////////////////////////////////////////////////////////////////////////////// void SNetworkingProfilerWindow::Reset() { if (PacketView) { PacketView->Reset(); } if (PacketContentView) { PacketContentView->Reset(); } if (NetStatsView) { NetStatsView->Reset(); } AvailableGameInstances.Reset(); SelectedGameInstance.Reset(); AvailableConnections.Reset(); SelectedConnection.Reset(); AvailableConnectionModes.Reset(); SelectedConnectionMode.Reset(); SelectedPacketStartIndex = 0; SelectedPacketEndIndex = 0; SelectionStartPosition = 0; SelectionEndPosition = 0; } //////////////////////////////////////////////////////////////////////////////////////////////////// BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION //////////////////////////////////////////////////////////////////////////////////////////////////// TSharedRef SNetworkingProfilerWindow::SpawnTab_Toolbar(const FSpawnTabArgs& Args) { const TSharedRef DockTab = SNew(SDockTab) .ShouldAutosize(true) .TabRole(ETabRole::PanelTab) [SNew(SNetworkingProfilerToolbar, SharedThis(this))]; DockTab->SetOnTabClosed(SDockTab::FOnTabClosedCallback::CreateRaw(this, &SNetworkingProfilerWindow::OnToolbarTabClosed)); return DockTab; } //////////////////////////////////////////////////////////////////////////////////////////////////// void SNetworkingProfilerWindow::OnToolbarTabClosed(TSharedRef TabBeingClosed) { } //////////////////////////////////////////////////////////////////////////////////////////////////// TSharedRef SNetworkingProfilerWindow::SpawnTab_PacketView(const FSpawnTabArgs& Args) { const TSharedRef DockTab = SNew(SDockTab) .ShouldAutosize(false) .TabRole(ETabRole::PanelTab) [SAssignNew(PacketView, SPacketView, SharedThis(this))]; DockTab->SetOnTabClosed(SDockTab::FOnTabClosedCallback::CreateRaw(this, &SNetworkingProfilerWindow::OnPacketViewTabClosed)); return DockTab; } //////////////////////////////////////////////////////////////////////////////////////////////////// void SNetworkingProfilerWindow::OnPacketViewTabClosed(TSharedRef TabBeingClosed) { PacketView = nullptr; } //////////////////////////////////////////////////////////////////////////////////////////////////// TSharedRef SNetworkingProfilerWindow::SpawnTab_PacketContentView(const FSpawnTabArgs& Args) { const TSharedRef DockTab = SNew(SDockTab) .ShouldAutosize(false) .TabRole(ETabRole::PanelTab) [SAssignNew(PacketContentView, SPacketContentView, SharedThis(this))]; DockTab->SetOnTabClosed(SDockTab::FOnTabClosedCallback::CreateRaw(this, &SNetworkingProfilerWindow::OnPacketContentViewTabClosed)); return DockTab; } //////////////////////////////////////////////////////////////////////////////////////////////////// void SNetworkingProfilerWindow::OnPacketContentViewTabClosed(TSharedRef TabBeingClosed) { PacketContentView = nullptr; } //////////////////////////////////////////////////////////////////////////////////////////////////// TSharedRef SNetworkingProfilerWindow::SpawnTab_NetStatsView(const FSpawnTabArgs& Args) { const TSharedRef DockTab = SNew(SDockTab) .ShouldAutosize(false) .TabRole(ETabRole::PanelTab) [SAssignNew(NetStatsView, SNetStatsView, SharedThis(this))]; DockTab->SetOnTabClosed(SDockTab::FOnTabClosedCallback::CreateRaw(this, &SNetworkingProfilerWindow::OnNetStatsViewTabClosed)); return DockTab; } //////////////////////////////////////////////////////////////////////////////////////////////////// void SNetworkingProfilerWindow::OnNetStatsViewTabClosed(TSharedRef TabBeingClosed) { NetStatsView = nullptr; } //////////////////////////////////////////////////////////////////////////////////////////////////// void SNetworkingProfilerWindow::Construct(const FArguments& InArgs, const TSharedRef& ConstructUnderMajorTab, const TSharedPtr& ConstructUnderWindow) { CommandList = MakeShared(); // Create & initialize tab manager. TabManager = FGlobalTabmanager::Get()->NewTabManager(ConstructUnderMajorTab); TSharedRef AppMenuGroup = TabManager->AddLocalWorkspaceMenuCategory(LOCTEXT("NetworkingProfilerMenuGroupName", "Networking Insights")); TabManager->RegisterTabSpawner(FNetworkingProfilerTabs::ToolbarID, FOnSpawnTab::CreateRaw(this, &SNetworkingProfilerWindow::SpawnTab_Toolbar)) .SetDisplayName(LOCTEXT("DeviceToolbarTabTitle", "Toolbar")) .SetIcon(FSlateIcon(FInsightsStyle::GetStyleSetName(), "Toolbar.Icon.Small")) .SetGroup(AppMenuGroup); TabManager->RegisterTabSpawner(FNetworkingProfilerTabs::PacketViewID, FOnSpawnTab::CreateRaw(this, &SNetworkingProfilerWindow::SpawnTab_PacketView)) .SetDisplayName(LOCTEXT("NetworkingProfiler.PacketViewTabTitle", "Packet View")) .SetIcon(FSlateIcon(FInsightsStyle::GetStyleSetName(), "PacketView.Icon.Small")) .SetGroup(AppMenuGroup); TabManager->RegisterTabSpawner(FNetworkingProfilerTabs::PacketContentViewID, FOnSpawnTab::CreateRaw(this, &SNetworkingProfilerWindow::SpawnTab_PacketContentView)) .SetDisplayName(LOCTEXT("NetworkingProfiler.PacketContentViewTabTitle", "Packet Content")) .SetIcon(FSlateIcon(FInsightsStyle::GetStyleSetName(), "PacketContentView.Icon.Small")) .SetGroup(AppMenuGroup); TabManager->RegisterTabSpawner(FNetworkingProfilerTabs::NetStatsViewID, FOnSpawnTab::CreateRaw(this, &SNetworkingProfilerWindow::SpawnTab_NetStatsView)) .SetDisplayName(LOCTEXT("NetworkingProfiler.NetStatsViewTabTitle", "Net Stats")) .SetIcon(FSlateIcon(FInsightsStyle::GetStyleSetName(), "NetStatsView.Icon.Small")) .SetGroup(AppMenuGroup); TSharedPtr NetworkingProfilerManager = FNetworkingProfilerManager::Get(); ensure(NetworkingProfilerManager.IsValid()); // Create tab layout. const TSharedRef Layout = FTabManager::NewLayout("InsightsNetworkingProfilerLayout_v1.0") ->AddArea( FTabManager::NewPrimaryArea() ->SetOrientation(Orient_Vertical) ->Split( FTabManager::NewStack() ->AddTab(FNetworkingProfilerTabs::ToolbarID, ETabState::OpenedTab) ->SetHideTabWell(true)) ->Split( FTabManager::NewSplitter() ->SetOrientation(Orient_Horizontal) ->SetSizeCoefficient(1.0f) ->Split( FTabManager::NewSplitter() ->SetOrientation(Orient_Vertical) ->SetSizeCoefficient(0.65f) ->Split( FTabManager::NewStack() ->SetSizeCoefficient(0.35f) ->SetHideTabWell(true) ->AddTab(FNetworkingProfilerTabs::PacketViewID, ETabState::OpenedTab)) ->Split( FTabManager::NewStack() ->SetSizeCoefficient(0.65f) ->SetHideTabWell(true) ->AddTab(FNetworkingProfilerTabs::PacketContentViewID, ETabState::OpenedTab))) ->Split( FTabManager::NewStack() ->SetSizeCoefficient(0.35f) ->AddTab(FNetworkingProfilerTabs::NetStatsViewID, ETabState::OpenedTab) //->SetForegroundTab(FNetworkingProfilerTabs::NetStatsViewID) ))); // Create & initialize main menu. FMenuBarBuilder MenuBarBuilder = FMenuBarBuilder(TSharedPtr()); MenuBarBuilder.AddPullDownMenu( LOCTEXT("MenuLabel", "Menu"), FText::GetEmpty(), FNewMenuDelegate::CreateStatic(&SNetworkingProfilerWindow::FillMenu, TabManager), FName(TEXT("Menu"))); ChildSlot [SNew(SOverlay) // Version + SOverlay::Slot() .HAlign(HAlign_Right) .VAlign(VAlign_Top) .Padding(0.0f, -16.0f, 0.0f, 0.0f) [SNew(STextBlock) .Clipping(EWidgetClipping::ClipToBoundsWithoutIntersecting) .Text(LOCTEXT("UnrealInsightsVersion", UNREAL_INSIGHTS_VERSION_STRING_EX)) .ColorAndOpacity(FLinearColor(0.15f, 0.15f, 0.15f, 1.0f))] // Overlay slot for the main window area + SOverlay::Slot() .HAlign(HAlign_Fill) .VAlign(VAlign_Fill) [SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() [MenuBarBuilder.MakeWidget()] + SVerticalBox::Slot() .FillHeight(1.0f) [TabManager->RestoreFrom(Layout, ConstructUnderWindow).ToSharedRef()]] // Session hint overlay + SOverlay::Slot() .HAlign(HAlign_Center) .VAlign(VAlign_Center) [SNew(SBorder) .Visibility(this, &SNetworkingProfilerWindow::IsSessionOverlayVisible) .BorderImage(FEditorStyle::GetBrush("NotificationList.ItemBackground")) .Padding(8.0f) [SNew(STextBlock) .Text(LOCTEXT("SelectTraceOverlayText", "Please select a trace."))]]]; // Tell tab-manager about the global menu bar. TabManager->SetMenuMultiBox(MenuBarBuilder.GetMultiBox()); BindCommands(); } //////////////////////////////////////////////////////////////////////////////////////////////////// END_SLATE_FUNCTION_BUILD_OPTIMIZATION //////////////////////////////////////////////////////////////////////////////////////////////////// void SNetworkingProfilerWindow::BindCommands() { Map_TogglePacketViewVisibility(); Map_TogglePacketContentViewVisibility(); Map_ToggleNetStatsViewVisibility(); CommandList->MapAction(FInsightsCommands::Get().ToggleDebugInfo, FInsightsManager::GetActionManager().ToggleDebugInfo_Custom()); } //////////////////////////////////////////////////////////////////////////////////////////////////// // Toggle Commands //////////////////////////////////////////////////////////////////////////////////////////////////// #define IMPLEMENT_TOGGLE_COMMAND(CmdName, IsEnabled, SetEnabled) \ \ void SNetworkingProfilerWindow::Map_##CmdName()\ {\ CommandList->MapAction(FNetworkingProfilerManager::GetCommands().CmdName, CmdName##_Custom());\ }\ \ const FUIAction SNetworkingProfilerWindow::CmdName##_Custom() \ {\ FUIAction UIAction;\ UIAction.ExecuteAction = FExecuteAction::CreateRaw(this, &SNetworkingProfilerWindow::CmdName##_Execute);\ UIAction.CanExecuteAction = FCanExecuteAction::CreateRaw(this, &SNetworkingProfilerWindow::CmdName##_CanExecute);\ UIAction.GetActionCheckState = FGetActionCheckState::CreateRaw(this, &SNetworkingProfilerWindow::CmdName##_GetCheckState);\ return UIAction;\ }\ \ void SNetworkingProfilerWindow::CmdName##_Execute()\ {\ SetEnabled(!IsEnabled());\ }\ \ bool SNetworkingProfilerWindow::CmdName##_CanExecute() const\ {\ return FInsightsManager::Get()->GetSession().IsValid();\ }\ \ ECheckBoxState SNetworkingProfilerWindow::CmdName##_GetCheckState() const\ {\ return IsEnabled() ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;\ } IMPLEMENT_TOGGLE_COMMAND(TogglePacketViewVisibility, IsPacketViewVisible, ShowOrHidePacketView) IMPLEMENT_TOGGLE_COMMAND(TogglePacketContentViewVisibility, IsPacketContentViewVisible, ShowOrHidePacketContentView) IMPLEMENT_TOGGLE_COMMAND(ToggleNetStatsViewVisibility, IsNetStatsViewVisible, ShowOrHideNetStatsView) #undef IMPLEMENT_TOGGLE_COMMAND //////////////////////////////////////////////////////////////////////////////////////////////////// void SNetworkingProfilerWindow::FillMenu(FMenuBuilder& MenuBuilder, const TSharedPtr TabManager) { if (!TabManager.IsValid()) { return; } FInsightsManager::Get()->GetInsightsMenuBuilder()->PopulateMenu(MenuBuilder); TabManager->PopulateLocalTabSpawnerMenu(MenuBuilder); } //////////////////////////////////////////////////////////////////////////////////////////////////// void SNetworkingProfilerWindow::ShowTab(const FName& TabID) { if (TabManager->HasTabSpawner(TabID)) { TabManager->TryInvokeTab(TabID); } } //////////////////////////////////////////////////////////////////////////////////////////////////// void SNetworkingProfilerWindow::HideTab(const FName& TabID) { TSharedPtr Tab = TabManager->FindExistingLiveTab(TabID); if (Tab.IsValid()) { Tab->RequestCloseTab(); } } //////////////////////////////////////////////////////////////////////////////////////////////////// EVisibility SNetworkingProfilerWindow::IsSessionOverlayVisible() const { if (FInsightsManager::Get()->GetSession().IsValid()) { return EVisibility::Hidden; } else { return EVisibility::Visible; } } //////////////////////////////////////////////////////////////////////////////////////////////////// bool SNetworkingProfilerWindow::IsProfilerEnabled() const { return FInsightsManager::Get()->GetSession().IsValid(); } //////////////////////////////////////////////////////////////////////////////////////////////////// EActiveTimerReturnType SNetworkingProfilerWindow::UpdateActiveDuration(double InCurrentTime, float InDeltaTime) { DurationActive += InDeltaTime; // The profiler window will explicitly unregister this active timer when the mouse leaves. return EActiveTimerReturnType::Continue; } //////////////////////////////////////////////////////////////////////////////////////////////////// void SNetworkingProfilerWindow::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) { TSharedPtr Session = FInsightsManager::Get()->GetSession(); uint32 GameInstanceCount = 0; if (Session.IsValid()) { Trace::FAnalysisSessionReadScope SessionReadScope(*Session.Get()); const Trace::INetProfilerProvider& NetProfilerProvider = Trace::ReadNetProfilerProvider(*Session.Get()); GameInstanceCount = NetProfilerProvider.GetGameInstanceCount(); } if (GameInstanceCount != AvailableGameInstances.Num()) { UpdateAvailableGameInstances(); } uint32 ConnectionCount = 0; if (Session.IsValid() && SelectedGameInstance.IsValid()) { Trace::FAnalysisSessionReadScope SessionReadScope(*Session.Get()); const Trace::INetProfilerProvider& NetProfilerProvider = Trace::ReadNetProfilerProvider(*Session.Get()); ConnectionCount = NetProfilerProvider.GetConnectionCount(SelectedGameInstance->GetIndex()); } if (ConnectionCount != AvailableConnections.Num()) { UpdateAvailableConnections(); } } //////////////////////////////////////////////////////////////////////////////////////////////////// void SNetworkingProfilerWindow::UpdateAvailableGameInstances() { AvailableGameInstances.Reset(); TSharedPtr Session = FInsightsManager::Get()->GetSession(); if (Session.IsValid()) { Trace::FAnalysisSessionReadScope SessionReadScope(*Session.Get()); const Trace::INetProfilerProvider& NetProfilerProvider = Trace::ReadNetProfilerProvider(*Session.Get()); NetProfilerProvider.ReadGameInstances([this](const Trace::FNetProfilerGameInstance& GameInstance) { AvailableGameInstances.Add(MakeShared(GameInstance)); }); } if (GameInstanceComboBox.IsValid()) { GameInstanceComboBox->SetSelectedItem(AvailableGameInstances.Num() > 0 ? AvailableGameInstances[0] : nullptr); } UpdateAvailableConnections(); } //////////////////////////////////////////////////////////////////////////////////////////////////// void SNetworkingProfilerWindow::UpdateAvailableConnections() { AvailableConnections.Reset(); TSharedPtr Session = FInsightsManager::Get()->GetSession(); if (Session.IsValid() && SelectedGameInstance.IsValid()) { Trace::FAnalysisSessionReadScope SessionReadScope(*Session.Get()); const Trace::INetProfilerProvider& NetProfilerProvider = Trace::ReadNetProfilerProvider(*Session.Get()); NetProfilerProvider.ReadConnections(SelectedGameInstance->GetIndex(), [this](const Trace::FNetProfilerConnection& Connection) { AvailableConnections.Add(MakeShared(Connection)); }); } if (ConnectionComboBox.IsValid()) { ConnectionComboBox->SetSelectedItem(AvailableConnections.Num() > 0 ? AvailableConnections[0] : nullptr); } UpdateAvailableConnectionModes(); } //////////////////////////////////////////////////////////////////////////////////////////////////// void SNetworkingProfilerWindow::UpdateAvailableConnectionModes() { AvailableConnectionModes.Reset(); if (SelectedConnection.IsValid()) { if (SelectedConnection->Connection.bHasIncomingData) { AvailableConnectionModes.Add(MakeShared(Trace::ENetProfilerConnectionMode::Incoming)); } if (SelectedConnection->Connection.bHasOutgoingData) { AvailableConnectionModes.Add(MakeShared(Trace::ENetProfilerConnectionMode::Outgoing)); } } if (ConnectionModeComboBox.IsValid()) { ConnectionModeComboBox->SetSelectedItem(AvailableConnectionModes.Num() > 0 ? AvailableConnectionModes[0] : nullptr); } } //////////////////////////////////////////////////////////////////////////////////////////////////// void SNetworkingProfilerWindow::OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { SCompoundWidget::OnMouseEnter(MyGeometry, MouseEvent); if (!ActiveTimerHandle.IsValid()) { ActiveTimerHandle = RegisterActiveTimer(0.f, FWidgetActiveTimerDelegate::CreateSP(this, &SNetworkingProfilerWindow::UpdateActiveDuration)); } } //////////////////////////////////////////////////////////////////////////////////////////////////// void SNetworkingProfilerWindow::OnMouseLeave(const FPointerEvent& MouseEvent) { SCompoundWidget::OnMouseLeave(MouseEvent); auto PinnedActiveTimerHandle = ActiveTimerHandle.Pin(); if (PinnedActiveTimerHandle.IsValid()) { UnRegisterActiveTimer(PinnedActiveTimerHandle.ToSharedRef()); } } //////////////////////////////////////////////////////////////////////////////////////////////////// FReply SNetworkingProfilerWindow::OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) { return GetCommandList()->ProcessCommandBindings(InKeyEvent) ? FReply::Handled() : FReply::Unhandled(); } //////////////////////////////////////////////////////////////////////////////////////////////////// FReply SNetworkingProfilerWindow::OnDragOver(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) { TSharedPtr DragDropOp = DragDropEvent.GetOperationAs(); if (DragDropOp.IsValid()) { if (DragDropOp->HasFiles()) { const TArray& Files = DragDropOp->GetFiles(); if (Files.Num() == 1) { const FString DraggedFileExtension = FPaths::GetExtension(Files[0], true); if (DraggedFileExtension == TEXT(".utrace")) { return FReply::Handled(); } } } } return SCompoundWidget::OnDragOver(MyGeometry, DragDropEvent); } //////////////////////////////////////////////////////////////////////////////////////////////////// FReply SNetworkingProfilerWindow::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) { TSharedPtr DragDropOp = DragDropEvent.GetOperationAs(); if (DragDropOp.IsValid()) { if (DragDropOp->HasFiles()) { // For now, only allow a single file. const TArray& Files = DragDropOp->GetFiles(); if (Files.Num() == 1) { const FString DraggedFileExtension = FPaths::GetExtension(Files[0], true); if (DraggedFileExtension == TEXT(".utrace")) { // Enqueue load operation. FInsightsManager::Get()->LoadTraceFile(Files[0]); return FReply::Handled(); } } } } return SCompoundWidget::OnDrop(MyGeometry, DragDropEvent); } //////////////////////////////////////////////////////////////////////////////////////////////////// FText SNetworkingProfilerWindow::FGameInstanceItem::GetText() const { return FText::Format(LOCTEXT("GameInstanceItemFmt", "Game Instance {0}"), FText::AsNumber(GetIndex())); } //////////////////////////////////////////////////////////////////////////////////////////////////// FText SNetworkingProfilerWindow::FGameInstanceItem::GetTooltipText() const { return GetText(); } //////////////////////////////////////////////////////////////////////////////////////////////////// FText SNetworkingProfilerWindow::FConnectionItem::GetText() const { if (!Connection.Name) { return FText::Format(LOCTEXT("ConnectionItemFmt1", "Connection {0}"), FText::AsNumber(GetIndex())); } else { return FText::Format(LOCTEXT("ConnectionItemFmt2", "Connection {0} ({1})"), FText::AsNumber(GetIndex()), FText::FromString(Connection.Name)); } } //////////////////////////////////////////////////////////////////////////////////////////////////// FText SNetworkingProfilerWindow::FConnectionItem::GetTooltipText() const { return GetText(); } //////////////////////////////////////////////////////////////////////////////////////////////////// FText SNetworkingProfilerWindow::FConnectionModeItem::GetText() const { switch (Mode) { case Trace::ENetProfilerConnectionMode::Outgoing: return LOCTEXT("ConnectionMode_Outgoing", "Outgoing"); case Trace::ENetProfilerConnectionMode::Incoming: return LOCTEXT("ConnectionMode_Incoming", "Incoming"); default: return LOCTEXT("ConnectionMode_Unknown", "Unknown"); } } //////////////////////////////////////////////////////////////////////////////////////////////////// FText SNetworkingProfilerWindow::FConnectionModeItem::GetTooltipText() const { return GetText(); } //////////////////////////////////////////////////////////////////////////////////////////////////// BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION TSharedRef SNetworkingProfilerWindow::CreateGameInstanceComboBox() { GameInstanceComboBox = SNew(SComboBox>) .ToolTipText(this, &SNetworkingProfilerWindow::GameInstance_GetSelectedTooltipText) .OptionsSource(&AvailableGameInstances) .OnSelectionChanged(this, &SNetworkingProfilerWindow::GameInstance_OnSelectionChanged) .OnGenerateWidget(this, &SNetworkingProfilerWindow::GameInstance_OnGenerateWidget) [SNew(STextBlock) .Text(this, &SNetworkingProfilerWindow::GameInstance_GetSelectedText)]; return GameInstanceComboBox.ToSharedRef(); } END_SLATE_FUNCTION_BUILD_OPTIMIZATION //////////////////////////////////////////////////////////////////////////////////////////////////// BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION TSharedRef SNetworkingProfilerWindow::GameInstance_OnGenerateWidget(TSharedPtr InGameInstance) const { return SNew(STextBlock) .Text(InGameInstance->GetText()) .ToolTipText(InGameInstance->GetTooltipText()); } END_SLATE_FUNCTION_BUILD_OPTIMIZATION //////////////////////////////////////////////////////////////////////////////////////////////////// void SNetworkingProfilerWindow::GameInstance_OnSelectionChanged(TSharedPtr NewGameInstance, ESelectInfo::Type SelectInfo) { const bool bSameValue = (!SelectedGameInstance.IsValid() && !NewGameInstance.IsValid()) || (SelectedGameInstance.IsValid() && NewGameInstance.IsValid() && SelectedGameInstance->GetIndex() == NewGameInstance->GetIndex()); SelectedGameInstance = NewGameInstance; if (!bSameValue) { UpdateAvailableConnections(); if (PacketView.IsValid()) { PacketView->SetConnection(GetSelectedGameInstanceIndex(), GetSelectedConnectionIndex(), GetSelectedConnectionMode()); } UpdateAggregatedNetStats(); } } //////////////////////////////////////////////////////////////////////////////////////////////////// FText SNetworkingProfilerWindow::GameInstance_GetSelectedText() const { return SelectedGameInstance.IsValid() ? SelectedGameInstance->GetText() : LOCTEXT("NoGameInstanceText", "Game Instance N/A"); } //////////////////////////////////////////////////////////////////////////////////////////////////// FText SNetworkingProfilerWindow::GameInstance_GetSelectedTooltipText() const { return SelectedGameInstance.IsValid() ? SelectedGameInstance->GetTooltipText() : FText(); } //////////////////////////////////////////////////////////////////////////////////////////////////// BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION TSharedRef SNetworkingProfilerWindow::CreateConnectionComboBox() { ConnectionComboBox = SNew(SComboBox>) .ToolTipText(this, &SNetworkingProfilerWindow::Connection_GetSelectedTooltipText) .OptionsSource(&AvailableConnections) .OnSelectionChanged(this, &SNetworkingProfilerWindow::Connection_OnSelectionChanged) .OnGenerateWidget(this, &SNetworkingProfilerWindow::Connection_OnGenerateWidget) [SNew(STextBlock) .Text(this, &SNetworkingProfilerWindow::Connection_GetSelectedText)]; return ConnectionComboBox.ToSharedRef(); } END_SLATE_FUNCTION_BUILD_OPTIMIZATION //////////////////////////////////////////////////////////////////////////////////////////////////// BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION TSharedRef SNetworkingProfilerWindow::Connection_OnGenerateWidget(TSharedPtr InConnection) const { return SNew(STextBlock) .Text(InConnection->GetText()) .ToolTipText(InConnection->GetTooltipText()); } END_SLATE_FUNCTION_BUILD_OPTIMIZATION //////////////////////////////////////////////////////////////////////////////////////////////////// void SNetworkingProfilerWindow::Connection_OnSelectionChanged(TSharedPtr NewConnection, ESelectInfo::Type SelectInfo) { const bool bSameValue = (!SelectedConnection.IsValid() && !NewConnection.IsValid()) || (SelectedConnection.IsValid() && NewConnection.IsValid() && SelectedConnection->GetIndex() == NewConnection->GetIndex()); SelectedConnection = NewConnection; if (!bSameValue) { UpdateAvailableConnectionModes(); if (PacketView.IsValid()) { PacketView->SetConnection(GetSelectedGameInstanceIndex(), GetSelectedConnectionIndex(), GetSelectedConnectionMode()); } UpdateAggregatedNetStats(); } } //////////////////////////////////////////////////////////////////////////////////////////////////// FText SNetworkingProfilerWindow::Connection_GetSelectedText() const { return SelectedConnection.IsValid() ? SelectedConnection->GetText() : LOCTEXT("NoConnectionText", "Connection N/A"); } //////////////////////////////////////////////////////////////////////////////////////////////////// FText SNetworkingProfilerWindow::Connection_GetSelectedTooltipText() const { return SelectedConnection.IsValid() ? SelectedConnection->GetTooltipText() : FText(); } //////////////////////////////////////////////////////////////////////////////////////////////////// BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION TSharedRef SNetworkingProfilerWindow::CreateConnectionModeComboBox() { ConnectionModeComboBox = SNew(SComboBox>) .ToolTipText(this, &SNetworkingProfilerWindow::ConnectionMode_GetSelectedTooltipText) .OptionsSource(&AvailableConnectionModes) .OnSelectionChanged(this, &SNetworkingProfilerWindow::ConnectionMode_OnSelectionChanged) .OnGenerateWidget(this, &SNetworkingProfilerWindow::ConnectionMode_OnGenerateWidget) [SNew(STextBlock) .Text(this, &SNetworkingProfilerWindow::ConnectionMode_GetSelectedText)]; return ConnectionModeComboBox.ToSharedRef(); } END_SLATE_FUNCTION_BUILD_OPTIMIZATION //////////////////////////////////////////////////////////////////////////////////////////////////// BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION TSharedRef SNetworkingProfilerWindow::ConnectionMode_OnGenerateWidget(TSharedPtr InConnectionMode) const { return SNew(STextBlock) .Text(InConnectionMode->GetText()) .ToolTipText(InConnectionMode->GetTooltipText()); } END_SLATE_FUNCTION_BUILD_OPTIMIZATION //////////////////////////////////////////////////////////////////////////////////////////////////// void SNetworkingProfilerWindow::ConnectionMode_OnSelectionChanged(TSharedPtr NewConnectionMode, ESelectInfo::Type SelectInfo) { const bool bSameValue = (!SelectedConnectionMode.IsValid() && !NewConnectionMode.IsValid()) || (SelectedConnectionMode.IsValid() && NewConnectionMode.IsValid() && SelectedConnectionMode->Mode == NewConnectionMode->Mode); SelectedConnectionMode = NewConnectionMode; if (!bSameValue) { if (PacketView.IsValid()) { PacketView->SetConnection(GetSelectedGameInstanceIndex(), GetSelectedConnectionIndex(), GetSelectedConnectionMode()); } UpdateAggregatedNetStats(); } } //////////////////////////////////////////////////////////////////////////////////////////////////// FText SNetworkingProfilerWindow::ConnectionMode_GetSelectedText() const { return SelectedConnectionMode.IsValid() ? SelectedConnectionMode->GetText() : LOCTEXT("NoConnectionModeText", "N/A"); } //////////////////////////////////////////////////////////////////////////////////////////////////// FText SNetworkingProfilerWindow::ConnectionMode_GetSelectedTooltipText() const { return SelectedConnectionMode.IsValid() ? SelectedConnectionMode->GetTooltipText() : FText(); } //////////////////////////////////////////////////////////////////////////////////////////////////// void SNetworkingProfilerWindow::SetSelectedPacket(uint32 StartIndex, uint32 EndIndex, uint32 SinglePacketBitSize) { if (StartIndex != SelectedPacketStartIndex || EndIndex != SelectedPacketEndIndex) { SelectedPacketStartIndex = StartIndex; SelectedPacketEndIndex = EndIndex; UpdateAggregatedNetStats(); if (PacketContentView.IsValid()) { if (SelectedPacketEndIndex == SelectedPacketStartIndex + 1 && // only one packet selected SelectedGameInstance.IsValid() && SelectedConnection.IsValid() && SelectedConnectionMode.IsValid()) { PacketContentView->SetPacket(SelectedGameInstance->GetIndex(), SelectedConnection->GetIndex(), SelectedConnectionMode->Mode, SelectedPacketStartIndex, SinglePacketBitSize); } else { PacketContentView->ResetPacket(); } } } } //////////////////////////////////////////////////////////////////////////////////////////////////// void SNetworkingProfilerWindow::SetSelectedBitRange(uint32 StartPos, uint32 EndPos) { if (StartPos != SelectionStartPosition || EndPos != SelectionEndPosition) { SelectionStartPosition = StartPos; SelectionEndPosition = EndPos; UpdateAggregatedNetStats(); } } //////////////////////////////////////////////////////////////////////////////////////////////////// void SNetworkingProfilerWindow::SetSelectedEventTypeIndex(const uint32 InEventTypeIndex) { if (InEventTypeIndex != SelectedEventTypeIndex) { SelectedEventTypeIndex = InEventTypeIndex; if (SelectedEventTypeIndex != InvalidEventTypeIndex) { if (NetStatsView) { const uint64 NodeId = static_cast(SelectedEventTypeIndex); NetStatsView->SelectNetEventNode(NodeId); } } } } //////////////////////////////////////////////////////////////////////////////////////////////////// void SNetworkingProfilerWindow::UpdateAggregatedNetStats() { if (NetStatsView) { if (SelectedGameInstance.IsValid() && SelectedConnection.IsValid() && SelectedConnectionMode.IsValid() && (SelectedPacketStartIndex < SelectedPacketEndIndex) && (SelectedPacketStartIndex + 1 != SelectedPacketEndIndex || SelectionStartPosition < SelectionEndPosition)) { NetStatsView->UpdateStats(SelectedGameInstance->GetIndex(), SelectedConnection->GetIndex(), SelectedConnectionMode->Mode, SelectedPacketStartIndex, SelectedPacketEndIndex, SelectionStartPosition, SelectionEndPosition); } else { NetStatsView->ResetStats(); } } } //////////////////////////////////////////////////////////////////////////////////////////////////// #undef LOCTEXT_NAMESPACE