From 77c23b6c8f59aa1a0ee9026c670be36981f664c7 Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Thu, 7 Oct 2021 08:27:48 -0400 Subject: [PATCH 1/3] Hierarchy imgui debugger, first take Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- .../MultiplayerDebugHierarchyReporter.cpp | 200 ++++++++++++++++++ .../Debug/MultiplayerDebugHierarchyReporter.h | 52 +++++ .../Debug/MultiplayerDebugSystemComponent.cpp | 24 +++ .../Debug/MultiplayerDebugSystemComponent.h | 5 + .../Code/multiplayer_debug_files.cmake | 2 + 5 files changed, 283 insertions(+) create mode 100644 Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.cpp create mode 100644 Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.h diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.cpp new file mode 100644 index 0000000000..32e9a776a4 --- /dev/null +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.cpp @@ -0,0 +1,200 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include "MultiplayerDebugHierarchyReporter.h" + +#include +#include +#include +#include + +#if defined(IMGUI_ENABLED) +#include +#endif + +#pragma optimize("", off) + +namespace Multiplayer +{ + MultiplayerDebugHierarchyReporter::MultiplayerDebugHierarchyReporter() + : m_updateDebugOverlay([this]() { UpdateDebugOverlay(); }, AZ::Name("UpdateHierarchyDebug")) + { + CollectHierarchyRoots(); + + AZ::EntitySystemBus::Handler::BusConnect(); + m_updateDebugOverlay.Enqueue(AZ::TimeMs{ 0 }, true); + } + + MultiplayerDebugHierarchyReporter::~MultiplayerDebugHierarchyReporter() + { + AZ::EntitySystemBus::Handler::BusDisconnect(); + } + + // -------------------------------------------------------------------------------------------- + void MultiplayerDebugHierarchyReporter::OnImGuiUpdate() + { +#if defined(IMGUI_ENABLED) + for (const auto& root : m_hierarchyRoots) + { + if (const auto* rootComponent = root.second.m_rootComponent) + { + if (rootComponent->IsHierarchicalRoot()) + { + const AZStd::vector& hierarchicalChildren = rootComponent->GetHierarchicalEntities(); + + if (ImGui::TreeNode(rootComponent->GetEntity()->GetName().c_str(), + "Hierarchy, Root entity name [%s]: %4zu members", + rootComponent->GetEntity()->GetName().c_str(), + hierarchicalChildren.size())) + { + ImGui::Separator(); + ImGui::Columns(4, "hierarchy_columns"); + ImGui::Text("EntityId"); + ImGui::NextColumn(); + ImGui::Text("NetEntityId"); + ImGui::NextColumn(); + ImGui::Text("Entity Name"); + ImGui::NextColumn(); + ImGui::Text("Role"); + ImGui::NextColumn(); + + ImGui::Separator(); + ImGui::Columns(4, "hierarchy child info"); + + bool firstEntity = true; + for (const AZ::Entity* entity : hierarchicalChildren) + { + ImGui::Text("%s", entity->GetId().ToString().c_str()); + ImGui::NextColumn(); + ImGui::Text("%u", GetMultiplayer()->GetNetworkEntityManager()->GetNetEntityIdById(entity->GetId())); + ImGui::NextColumn(); + ImGui::Text("%s", entity->GetName().c_str()); + ImGui::NextColumn(); + + if (firstEntity) + { + ImGui::Text("Root node"); + } + else if (entity->FindComponent()) + { + ImGui::Text("Inner root node"); + } + else if (entity->FindComponent()) + { + ImGui::Text("Child node"); + } + ImGui::NextColumn(); + + firstEntity = false; + } + + ImGui::Columns(1); + ImGui::TreePop(); + } + } + } + } +#endif + } + + + void MultiplayerDebugHierarchyReporter::UpdateDebugOverlay() + { + if (!m_hierarchyRoots.empty()) + { + if (m_debugDisplay == nullptr) + { + AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus; + AzFramework::DebugDisplayRequestBus::Bind(debugDisplayBus, AzFramework::g_defaultSceneEntityDebugDisplayId); + m_debugDisplay = AzFramework::DebugDisplayRequestBus::FindFirstHandler(debugDisplayBus); + } + + const AZ::u32 stateBefore = m_debugDisplay->GetState(); + m_debugDisplay->SetColor(AZ::Colors::White); + + for (const auto& root : m_hierarchyRoots) + { + if (const auto* rootComponent = root.second.m_rootComponent) + { + if (rootComponent->IsHierarchicalRoot()) + { + const AZStd::vector& hierarchicalChildren = rootComponent->GetHierarchicalEntities(); + + azsprintf(m_statusBuffer, "Hierarchy [%s] %u members", rootComponent->GetEntity()->GetName().c_str(), + aznumeric_cast(hierarchicalChildren.size())); + + AZ::Vector3 entityPosition = rootComponent->GetEntity()->GetTransform()->GetWorldTranslation(); + constexpr bool centerText = true; + m_debugDisplay->DrawTextLabel(entityPosition, 1.0f, m_statusBuffer, centerText, 0, 0); + } + } + } + + m_debugDisplay->SetState(stateBefore); + } + } + + void MultiplayerDebugHierarchyReporter::OnEntityActivated(const AZ::EntityId& entityId) + { + if (const AZ::Entity* childEntity = AZ::Interface::Get()->FindEntity(entityId)) + { + if (auto* rootComponent = childEntity->FindComponent()) + { + HierarchyRootInfo info; + info.m_rootComponent = rootComponent; + rootComponent->BindNetworkHierarchyChangedEventHandler(info.m_changedEvent); + rootComponent->BindNetworkHierarchyLeaveEventHandler(info.m_leaveEvent); + + m_hierarchyRoots.insert(AZStd::make_pair(rootComponent, info)); + } + } + } + + void MultiplayerDebugHierarchyReporter::OnEntityDeactivated(const AZ::EntityId& entityId) + { + if (const AZ::Entity* childEntity = AZ::Interface::Get()->FindEntity(entityId)) + { + if (auto* rootComponent = childEntity->FindComponent()) + { + m_hierarchyRoots.erase(rootComponent); + } + } + } + + void MultiplayerDebugHierarchyReporter::CollectHierarchyRoots() + { + AZStd::vector gatheredEntries; + const AZ::Sphere awarenessSphere = AZ::Sphere(AZ::Vector3::CreateZero(), 1000.f); + AZ::Interface::Get()->GetDefaultVisibilityScene()->Enumerate(awarenessSphere, [&gatheredEntries](const AzFramework::IVisibilityScene::NodeData& nodeData) + { + gatheredEntries.reserve(gatheredEntries.size() + nodeData.m_entries.size()); + for (AzFramework::VisibilityEntry* visEntry : nodeData.m_entries) + { + if (visEntry->m_typeFlags & AzFramework::VisibilityEntry::TypeFlags::TYPE_Entity) + { + gatheredEntries.push_back(visEntry); + } + } + } + ); + + for (const AzFramework::VisibilityEntry* entry : gatheredEntries) + { + const AZ::Entity* entity = static_cast(entry->m_userData); + if (auto* rootComponent = entity->FindComponent()) + { + HierarchyRootInfo info; + info.m_rootComponent = rootComponent; + rootComponent->BindNetworkHierarchyChangedEventHandler(info.m_changedEvent); + rootComponent->BindNetworkHierarchyLeaveEventHandler(info.m_leaveEvent); + + m_hierarchyRoots.insert(AZStd::make_pair(rootComponent, info)); + } + } + } +} diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.h new file mode 100644 index 0000000000..98a131614c --- /dev/null +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include + +namespace Multiplayer +{ + class MultiplayerDebugHierarchyReporter + : public AZ::EntitySystemBus::Handler + { + public: + MultiplayerDebugHierarchyReporter(); + ~MultiplayerDebugHierarchyReporter() override; + + //! main update loop + void OnImGuiUpdate(); + + //! Draws bandwidth text over entities + void UpdateDebugOverlay(); + + //! EntitySystemBus overrides. + void OnEntityActivated(const AZ::EntityId& entityId) override; + void OnEntityDeactivated(const AZ::EntityId& entityId) override; + + private: + AZ::ScheduledEvent m_updateDebugOverlay; + + AzFramework::DebugDisplayRequests* m_debugDisplay = nullptr; + + struct HierarchyRootInfo + { + NetworkHierarchyRootComponent* m_rootComponent = nullptr; + NetworkHierarchyChangedEvent::Handler m_changedEvent; + NetworkHierarchyLeaveEvent::Handler m_leaveEvent; + }; + + AZStd::unordered_map m_hierarchyRoots; + void CollectHierarchyRoots(); + + char m_statusBuffer[100] = {}; + }; +} diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp index 422b2f0cae..b23bc677f0 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp @@ -71,6 +71,7 @@ namespace Multiplayer ImGui::Checkbox("Networking Stats", &m_displayNetworkingStats); ImGui::Checkbox("Multiplayer Stats", &m_displayMultiplayerStats); ImGui::Checkbox("Multiplayer Entity Stats", &m_displayPerEntityStats); + ImGui::Checkbox("Multiplayer Hierarchy Debugger", &m_displayHierarchyDebugger); ImGui::EndMenu(); } } @@ -464,6 +465,29 @@ namespace Multiplayer } } } + + if (m_displayHierarchyDebugger) + { + if (ImGui::Begin("Multiplayer Hierarchy Debugger", &m_displayHierarchyDebugger)) + { + if (m_hierarchyDebugger == nullptr) + { + m_hierarchyDebugger = AZStd::make_unique(); + } + + if (m_hierarchyDebugger) + { + m_hierarchyDebugger->OnImGuiUpdate(); + } + } + } + else + { + if (m_hierarchyDebugger) + { + m_hierarchyDebugger.reset(); + } + } } #endif } diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h index 7b3c852f58..9becf1543c 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h @@ -8,6 +8,8 @@ #pragma once +#include "MultiplayerDebugHierarchyReporter.h" + #include #include #include @@ -62,5 +64,8 @@ namespace Multiplayer bool m_displayPerEntityStats = false; AZStd::unique_ptr m_reporter; + + bool m_displayHierarchyDebugger = false; + AZStd::unique_ptr m_hierarchyDebugger; }; } diff --git a/Gems/Multiplayer/Code/multiplayer_debug_files.cmake b/Gems/Multiplayer/Code/multiplayer_debug_files.cmake index 37a1c91640..1d85dd8149 100644 --- a/Gems/Multiplayer/Code/multiplayer_debug_files.cmake +++ b/Gems/Multiplayer/Code/multiplayer_debug_files.cmake @@ -9,6 +9,8 @@ set(FILES Source/Debug/MultiplayerDebugByteReporter.cpp Source/Debug/MultiplayerDebugByteReporter.h + Source/Debug/MultiplayerDebugHierarchyReporter.cpp + Source/Debug/MultiplayerDebugHierarchyReporter.h Source/Debug/MultiplayerDebugPerEntityReporter.cpp Source/Debug/MultiplayerDebugPerEntityReporter.h Source/Debug/MultiplayerDebugModule.cpp From a114077e726c95fbb21721ce4c7eb4fb2b7145ce Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Thu, 7 Oct 2021 12:53:33 -0400 Subject: [PATCH 2/3] Final touches on the first pass of imgui hierarchy debugger Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- .../MultiplayerDebugHierarchyDebugger.cpp | 198 ++++++++++++++++++ .../Debug/MultiplayerDebugHierarchyDebugger.h | 55 +++++ .../MultiplayerDebugHierarchyReporter.cpp | 45 +++- .../Debug/MultiplayerDebugHierarchyReporter.h | 13 +- 4 files changed, 298 insertions(+), 13 deletions(-) create mode 100644 Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.cpp create mode 100644 Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.h diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.cpp new file mode 100644 index 0000000000..393f67474b --- /dev/null +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.cpp @@ -0,0 +1,198 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include "MultiplayerDebugHierarchyDebugger.h" + +#include +#include +#include +#include + +#if defined(IMGUI_ENABLED) +#include +#endif + +namespace Multiplayer +{ + MultiplayerDebugHierarchyReporter::MultiplayerDebugHierarchyReporter() + : m_updateDebugOverlay([this]() { UpdateDebugOverlay(); }, AZ::Name("UpdateHierarchyDebug")) + { + CollectHierarchyRoots(); + + AZ::EntitySystemBus::Handler::BusConnect(); + m_updateDebugOverlay.Enqueue(AZ::TimeMs{ 0 }, true); + } + + MultiplayerDebugHierarchyReporter::~MultiplayerDebugHierarchyReporter() + { + AZ::EntitySystemBus::Handler::BusDisconnect(); + } + + // -------------------------------------------------------------------------------------------- + void MultiplayerDebugHierarchyReporter::OnImGuiUpdate() + { +#if defined(IMGUI_ENABLED) + for (const auto& root : m_hierarchyRoots) + { + if (const auto* rootComponent = root.second.m_rootComponent) + { + if (rootComponent->IsHierarchicalRoot()) + { + const AZStd::vector& hierarchicalChildren = rootComponent->GetHierarchicalEntities(); + + if (ImGui::TreeNode(rootComponent->GetEntity()->GetName().c_str(), + "Hierarchy, Root entity name [%s]: %4zu members", + rootComponent->GetEntity()->GetName().c_str(), + hierarchicalChildren.size())) + { + ImGui::Separator(); + ImGui::Columns(4, "hierarchy_columns"); + ImGui::Text("EntityId"); + ImGui::NextColumn(); + ImGui::Text("NetEntityId"); + ImGui::NextColumn(); + ImGui::Text("Entity Name"); + ImGui::NextColumn(); + ImGui::Text("Role"); + ImGui::NextColumn(); + + ImGui::Separator(); + ImGui::Columns(4, "hierarchy child info"); + + bool firstEntity = true; + for (const AZ::Entity* entity : hierarchicalChildren) + { + ImGui::Text("%s", entity->GetId().ToString().c_str()); + ImGui::NextColumn(); + ImGui::Text("%u", GetMultiplayer()->GetNetworkEntityManager()->GetNetEntityIdById(entity->GetId())); + ImGui::NextColumn(); + ImGui::Text("%s", entity->GetName().c_str()); + ImGui::NextColumn(); + + if (firstEntity) + { + ImGui::Text("Root node"); + } + else if (entity->FindComponent()) + { + ImGui::Text("Inner root node"); + } + else if (entity->FindComponent()) + { + ImGui::Text("Child node"); + } + ImGui::NextColumn(); + + firstEntity = false; + } + + ImGui::Columns(1); + ImGui::TreePop(); + } + } + } + } +#endif + } + + + void MultiplayerDebugHierarchyReporter::UpdateDebugOverlay() + { + if (!m_hierarchyRoots.empty()) + { + if (m_debugDisplay == nullptr) + { + AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus; + AzFramework::DebugDisplayRequestBus::Bind(debugDisplayBus, AzFramework::g_defaultSceneEntityDebugDisplayId); + m_debugDisplay = AzFramework::DebugDisplayRequestBus::FindFirstHandler(debugDisplayBus); + } + + const AZ::u32 stateBefore = m_debugDisplay->GetState(); + m_debugDisplay->SetColor(AZ::Colors::White); + + for (const auto& root : m_hierarchyRoots) + { + if (const auto* rootComponent = root.second.m_rootComponent) + { + if (rootComponent->IsHierarchicalRoot()) + { + const AZStd::vector& hierarchicalChildren = rootComponent->GetHierarchicalEntities(); + + azsprintf(m_statusBuffer, "Hierarchy [%s] %u members", rootComponent->GetEntity()->GetName().c_str(), + aznumeric_cast(hierarchicalChildren.size())); + + AZ::Vector3 entityPosition = rootComponent->GetEntity()->GetTransform()->GetWorldTranslation(); + constexpr bool centerText = true; + m_debugDisplay->DrawTextLabel(entityPosition, 1.0f, m_statusBuffer, centerText, 0, 0); + } + } + } + + m_debugDisplay->SetState(stateBefore); + } + } + + void MultiplayerDebugHierarchyReporter::OnEntityActivated(const AZ::EntityId& entityId) + { + if (const AZ::Entity* childEntity = AZ::Interface::Get()->FindEntity(entityId)) + { + if (auto* rootComponent = childEntity->FindComponent()) + { + HierarchyRootInfo info; + info.m_rootComponent = rootComponent; + rootComponent->BindNetworkHierarchyChangedEventHandler(info.m_changedEvent); + rootComponent->BindNetworkHierarchyLeaveEventHandler(info.m_leaveEvent); + + m_hierarchyRoots.insert(AZStd::make_pair(rootComponent, info)); + } + } + } + + void MultiplayerDebugHierarchyReporter::OnEntityDeactivated(const AZ::EntityId& entityId) + { + if (const AZ::Entity* childEntity = AZ::Interface::Get()->FindEntity(entityId)) + { + if (auto* rootComponent = childEntity->FindComponent()) + { + m_hierarchyRoots.erase(rootComponent); + } + } + } + + void MultiplayerDebugHierarchyReporter::CollectHierarchyRoots() + { + AZStd::vector gatheredEntries; + const AZ::Sphere awarenessSphere = AZ::Sphere(AZ::Vector3::CreateZero(), 1000.f); + AZ::Interface::Get()->GetDefaultVisibilityScene()->Enumerate(awarenessSphere, [&gatheredEntries](const AzFramework::IVisibilityScene::NodeData& nodeData) + { + gatheredEntries.reserve(gatheredEntries.size() + nodeData.m_entries.size()); + for (AzFramework::VisibilityEntry* visEntry : nodeData.m_entries) + { + if (visEntry->m_typeFlags & AzFramework::VisibilityEntry::TypeFlags::TYPE_Entity) + { + gatheredEntries.push_back(visEntry); + } + } + } + ); + + for (const AzFramework::VisibilityEntry* entry : gatheredEntries) + { + const AZ::Entity* entity = static_cast(entry->m_userData); + if (auto* rootComponent = entity->FindComponent()) + { + HierarchyRootInfo info; + info.m_rootComponent = rootComponent; + rootComponent->BindNetworkHierarchyChangedEventHandler(info.m_changedEvent); + rootComponent->BindNetworkHierarchyLeaveEventHandler(info.m_leaveEvent); + + m_hierarchyRoots.insert(AZStd::make_pair(rootComponent, info)); + } + } + } +} diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.h new file mode 100644 index 0000000000..978664b96b --- /dev/null +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include + +namespace Multiplayer +{ + /** + * \brief Reports hierarchy information in the scene. + */ + class MultiplayerDebugHierarchyReporter + : public AZ::EntitySystemBus::Handler + { + public: + MultiplayerDebugHierarchyReporter(); + ~MultiplayerDebugHierarchyReporter() override; + + //! main update loop + void OnImGuiUpdate(); + + //! Draws hierarchy information over hierarchy root entities + void UpdateDebugOverlay(); + + //! EntitySystemBus overrides. + void OnEntityActivated(const AZ::EntityId& entityId) override; + void OnEntityDeactivated(const AZ::EntityId& entityId) override; + + private: + AZ::ScheduledEvent m_updateDebugOverlay; + + AzFramework::DebugDisplayRequests* m_debugDisplay = nullptr; + + struct HierarchyRootInfo + { + NetworkHierarchyRootComponent* m_rootComponent = nullptr; + NetworkHierarchyChangedEvent::Handler m_changedEvent; + NetworkHierarchyLeaveEvent::Handler m_leaveEvent; + }; + + AZStd::unordered_map m_hierarchyRoots; + void CollectHierarchyRoots(); + + char m_statusBuffer[100] = {}; + }; +} diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.cpp index 32e9a776a4..7c38a340eb 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.cpp @@ -8,6 +8,8 @@ #include "MultiplayerDebugHierarchyReporter.h" +#include +#include #include #include #include @@ -17,8 +19,6 @@ #include #endif -#pragma optimize("", off) - namespace Multiplayer { MultiplayerDebugHierarchyReporter::MultiplayerDebugHierarchyReporter() @@ -39,6 +39,9 @@ namespace Multiplayer void MultiplayerDebugHierarchyReporter::OnImGuiUpdate() { #if defined(IMGUI_ENABLED) + ImGui::Text("Hierarchies"); + ImGui::Separator(); + for (const auto& root : m_hierarchyRoots) { if (const auto* rootComponent = root.second.m_rootComponent) @@ -48,7 +51,7 @@ namespace Multiplayer const AZStd::vector& hierarchicalChildren = rootComponent->GetHierarchicalEntities(); if (ImGui::TreeNode(rootComponent->GetEntity()->GetName().c_str(), - "Hierarchy, Root entity name [%s]: %4zu members", + "[%s] %4zu members", rootComponent->GetEntity()->GetName().c_str(), hierarchicalChildren.size())) { @@ -99,6 +102,16 @@ namespace Multiplayer } } } + + ImGui::Separator(); + if (ImGui::InputFloat("Awareness Radius", &m_awarenessRadius)) + { + CollectHierarchyRoots(); + } + if (ImGui::Button("Refresh")) + { + CollectHierarchyRoots(); + } #endif } @@ -168,9 +181,18 @@ namespace Multiplayer void MultiplayerDebugHierarchyReporter::CollectHierarchyRoots() { + m_hierarchyRoots.clear(); + AZ::Sphere awarenessSphere(AZ::Vector3::CreateZero(), m_awarenessRadius); + + const auto viewportContextManager = AZ::Interface::Get(); + if (const auto viewportContext = viewportContextManager->GetDefaultViewportContext()) + { + awarenessSphere.SetCenter(viewportContext->GetCameraTransform().GetTranslation()); + } + AZStd::vector gatheredEntries; - const AZ::Sphere awarenessSphere = AZ::Sphere(AZ::Vector3::CreateZero(), 1000.f); - AZ::Interface::Get()->GetDefaultVisibilityScene()->Enumerate(awarenessSphere, [&gatheredEntries](const AzFramework::IVisibilityScene::NodeData& nodeData) + AZ::Interface::Get()->GetDefaultVisibilityScene()->Enumerate(awarenessSphere, + [&gatheredEntries](const AzFramework::IVisibilityScene::NodeData& nodeData) { gatheredEntries.reserve(gatheredEntries.size() + nodeData.m_entries.size()); for (AzFramework::VisibilityEntry* visEntry : nodeData.m_entries) @@ -188,12 +210,15 @@ namespace Multiplayer const AZ::Entity* entity = static_cast(entry->m_userData); if (auto* rootComponent = entity->FindComponent()) { - HierarchyRootInfo info; - info.m_rootComponent = rootComponent; - rootComponent->BindNetworkHierarchyChangedEventHandler(info.m_changedEvent); - rootComponent->BindNetworkHierarchyLeaveEventHandler(info.m_leaveEvent); + if (awarenessSphere.GetCenter().GetDistanceEstimate(entity->GetTransform()->GetWorldTranslation()) < m_awarenessRadius) + { + HierarchyRootInfo info; + info.m_rootComponent = rootComponent; + rootComponent->BindNetworkHierarchyChangedEventHandler(info.m_changedEvent); + rootComponent->BindNetworkHierarchyLeaveEventHandler(info.m_leaveEvent); - m_hierarchyRoots.insert(AZStd::make_pair(rootComponent, info)); + m_hierarchyRoots.insert(AZStd::make_pair(rootComponent, info)); + } } } } diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.h index 98a131614c..2ce7e055a0 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.h +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.h @@ -15,6 +15,9 @@ namespace Multiplayer { + /** + * /brief Provides ImGui and debug draw hierarchy information at runtime. + */ class MultiplayerDebugHierarchyReporter : public AZ::EntitySystemBus::Handler { @@ -22,15 +25,17 @@ namespace Multiplayer MultiplayerDebugHierarchyReporter(); ~MultiplayerDebugHierarchyReporter() override; - //! main update loop + //! Main update loop. void OnImGuiUpdate(); - //! Draws bandwidth text over entities + //! Draws hierarchy information over hierarchy root entities. void UpdateDebugOverlay(); //! EntitySystemBus overrides. + //! @{ void OnEntityActivated(const AZ::EntityId& entityId) override; void OnEntityDeactivated(const AZ::EntityId& entityId) override; + //! @} private: AZ::ScheduledEvent m_updateDebugOverlay; @@ -46,7 +51,9 @@ namespace Multiplayer AZStd::unordered_map m_hierarchyRoots; void CollectHierarchyRoots(); - + char m_statusBuffer[100] = {}; + + float m_awarenessRadius = 1000.f; }; } From ecd358a53e76a2d66f538d24975142900d1a0b1a Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Thu, 7 Oct 2021 12:56:44 -0400 Subject: [PATCH 3/3] Cleaning up Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- .../MultiplayerDebugHierarchyDebugger.cpp | 198 ------------------ .../Debug/MultiplayerDebugHierarchyDebugger.h | 55 ----- 2 files changed, 253 deletions(-) delete mode 100644 Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.cpp delete mode 100644 Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.h diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.cpp deleted file mode 100644 index 393f67474b..0000000000 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "MultiplayerDebugHierarchyDebugger.h" - -#include -#include -#include -#include - -#if defined(IMGUI_ENABLED) -#include -#endif - -namespace Multiplayer -{ - MultiplayerDebugHierarchyReporter::MultiplayerDebugHierarchyReporter() - : m_updateDebugOverlay([this]() { UpdateDebugOverlay(); }, AZ::Name("UpdateHierarchyDebug")) - { - CollectHierarchyRoots(); - - AZ::EntitySystemBus::Handler::BusConnect(); - m_updateDebugOverlay.Enqueue(AZ::TimeMs{ 0 }, true); - } - - MultiplayerDebugHierarchyReporter::~MultiplayerDebugHierarchyReporter() - { - AZ::EntitySystemBus::Handler::BusDisconnect(); - } - - // -------------------------------------------------------------------------------------------- - void MultiplayerDebugHierarchyReporter::OnImGuiUpdate() - { -#if defined(IMGUI_ENABLED) - for (const auto& root : m_hierarchyRoots) - { - if (const auto* rootComponent = root.second.m_rootComponent) - { - if (rootComponent->IsHierarchicalRoot()) - { - const AZStd::vector& hierarchicalChildren = rootComponent->GetHierarchicalEntities(); - - if (ImGui::TreeNode(rootComponent->GetEntity()->GetName().c_str(), - "Hierarchy, Root entity name [%s]: %4zu members", - rootComponent->GetEntity()->GetName().c_str(), - hierarchicalChildren.size())) - { - ImGui::Separator(); - ImGui::Columns(4, "hierarchy_columns"); - ImGui::Text("EntityId"); - ImGui::NextColumn(); - ImGui::Text("NetEntityId"); - ImGui::NextColumn(); - ImGui::Text("Entity Name"); - ImGui::NextColumn(); - ImGui::Text("Role"); - ImGui::NextColumn(); - - ImGui::Separator(); - ImGui::Columns(4, "hierarchy child info"); - - bool firstEntity = true; - for (const AZ::Entity* entity : hierarchicalChildren) - { - ImGui::Text("%s", entity->GetId().ToString().c_str()); - ImGui::NextColumn(); - ImGui::Text("%u", GetMultiplayer()->GetNetworkEntityManager()->GetNetEntityIdById(entity->GetId())); - ImGui::NextColumn(); - ImGui::Text("%s", entity->GetName().c_str()); - ImGui::NextColumn(); - - if (firstEntity) - { - ImGui::Text("Root node"); - } - else if (entity->FindComponent()) - { - ImGui::Text("Inner root node"); - } - else if (entity->FindComponent()) - { - ImGui::Text("Child node"); - } - ImGui::NextColumn(); - - firstEntity = false; - } - - ImGui::Columns(1); - ImGui::TreePop(); - } - } - } - } -#endif - } - - - void MultiplayerDebugHierarchyReporter::UpdateDebugOverlay() - { - if (!m_hierarchyRoots.empty()) - { - if (m_debugDisplay == nullptr) - { - AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus; - AzFramework::DebugDisplayRequestBus::Bind(debugDisplayBus, AzFramework::g_defaultSceneEntityDebugDisplayId); - m_debugDisplay = AzFramework::DebugDisplayRequestBus::FindFirstHandler(debugDisplayBus); - } - - const AZ::u32 stateBefore = m_debugDisplay->GetState(); - m_debugDisplay->SetColor(AZ::Colors::White); - - for (const auto& root : m_hierarchyRoots) - { - if (const auto* rootComponent = root.second.m_rootComponent) - { - if (rootComponent->IsHierarchicalRoot()) - { - const AZStd::vector& hierarchicalChildren = rootComponent->GetHierarchicalEntities(); - - azsprintf(m_statusBuffer, "Hierarchy [%s] %u members", rootComponent->GetEntity()->GetName().c_str(), - aznumeric_cast(hierarchicalChildren.size())); - - AZ::Vector3 entityPosition = rootComponent->GetEntity()->GetTransform()->GetWorldTranslation(); - constexpr bool centerText = true; - m_debugDisplay->DrawTextLabel(entityPosition, 1.0f, m_statusBuffer, centerText, 0, 0); - } - } - } - - m_debugDisplay->SetState(stateBefore); - } - } - - void MultiplayerDebugHierarchyReporter::OnEntityActivated(const AZ::EntityId& entityId) - { - if (const AZ::Entity* childEntity = AZ::Interface::Get()->FindEntity(entityId)) - { - if (auto* rootComponent = childEntity->FindComponent()) - { - HierarchyRootInfo info; - info.m_rootComponent = rootComponent; - rootComponent->BindNetworkHierarchyChangedEventHandler(info.m_changedEvent); - rootComponent->BindNetworkHierarchyLeaveEventHandler(info.m_leaveEvent); - - m_hierarchyRoots.insert(AZStd::make_pair(rootComponent, info)); - } - } - } - - void MultiplayerDebugHierarchyReporter::OnEntityDeactivated(const AZ::EntityId& entityId) - { - if (const AZ::Entity* childEntity = AZ::Interface::Get()->FindEntity(entityId)) - { - if (auto* rootComponent = childEntity->FindComponent()) - { - m_hierarchyRoots.erase(rootComponent); - } - } - } - - void MultiplayerDebugHierarchyReporter::CollectHierarchyRoots() - { - AZStd::vector gatheredEntries; - const AZ::Sphere awarenessSphere = AZ::Sphere(AZ::Vector3::CreateZero(), 1000.f); - AZ::Interface::Get()->GetDefaultVisibilityScene()->Enumerate(awarenessSphere, [&gatheredEntries](const AzFramework::IVisibilityScene::NodeData& nodeData) - { - gatheredEntries.reserve(gatheredEntries.size() + nodeData.m_entries.size()); - for (AzFramework::VisibilityEntry* visEntry : nodeData.m_entries) - { - if (visEntry->m_typeFlags & AzFramework::VisibilityEntry::TypeFlags::TYPE_Entity) - { - gatheredEntries.push_back(visEntry); - } - } - } - ); - - for (const AzFramework::VisibilityEntry* entry : gatheredEntries) - { - const AZ::Entity* entity = static_cast(entry->m_userData); - if (auto* rootComponent = entity->FindComponent()) - { - HierarchyRootInfo info; - info.m_rootComponent = rootComponent; - rootComponent->BindNetworkHierarchyChangedEventHandler(info.m_changedEvent); - rootComponent->BindNetworkHierarchyLeaveEventHandler(info.m_leaveEvent); - - m_hierarchyRoots.insert(AZStd::make_pair(rootComponent, info)); - } - } - } -} diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.h deleted file mode 100644 index 978664b96b..0000000000 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include -#include -#include - -namespace Multiplayer -{ - /** - * \brief Reports hierarchy information in the scene. - */ - class MultiplayerDebugHierarchyReporter - : public AZ::EntitySystemBus::Handler - { - public: - MultiplayerDebugHierarchyReporter(); - ~MultiplayerDebugHierarchyReporter() override; - - //! main update loop - void OnImGuiUpdate(); - - //! Draws hierarchy information over hierarchy root entities - void UpdateDebugOverlay(); - - //! EntitySystemBus overrides. - void OnEntityActivated(const AZ::EntityId& entityId) override; - void OnEntityDeactivated(const AZ::EntityId& entityId) override; - - private: - AZ::ScheduledEvent m_updateDebugOverlay; - - AzFramework::DebugDisplayRequests* m_debugDisplay = nullptr; - - struct HierarchyRootInfo - { - NetworkHierarchyRootComponent* m_rootComponent = nullptr; - NetworkHierarchyChangedEvent::Handler m_changedEvent; - NetworkHierarchyLeaveEvent::Handler m_leaveEvent; - }; - - AZStd::unordered_map m_hierarchyRoots; - void CollectHierarchyRoots(); - - char m_statusBuffer[100] = {}; - }; -}