3
0

MultiplayerDebugHierarchyReporter.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "MultiplayerDebugHierarchyReporter.h"
  9. #include <Atom/RPI.Public/ViewportContext.h>
  10. #include <Atom/RPI.Public/ViewportContextBus.h>
  11. #include <AzFramework/Entity/EntityDebugDisplayBus.h>
  12. #include <AzFramework/Visibility/IVisibilitySystem.h>
  13. #include <Multiplayer/Components/NetBindComponent.h>
  14. #include <Multiplayer/Components/NetworkHierarchyChildComponent.h>
  15. #if defined(IMGUI_ENABLED)
  16. #include <imgui/imgui.h>
  17. #endif
  18. namespace Multiplayer
  19. {
  20. MultiplayerDebugHierarchyReporter::MultiplayerDebugHierarchyReporter()
  21. : m_updateDebugOverlay([this]() { UpdateDebugOverlay(); }, AZ::Name("UpdateHierarchyDebug"))
  22. {
  23. CollectHierarchyRoots();
  24. AZ::EntitySystemBus::Handler::BusConnect();
  25. m_updateDebugOverlay.Enqueue(AZ::Time::ZeroTimeMs, true);
  26. }
  27. MultiplayerDebugHierarchyReporter::~MultiplayerDebugHierarchyReporter()
  28. {
  29. AZ::EntitySystemBus::Handler::BusDisconnect();
  30. }
  31. // --------------------------------------------------------------------------------------------
  32. void MultiplayerDebugHierarchyReporter::OnImGuiUpdate()
  33. {
  34. #if defined(IMGUI_ENABLED)
  35. ImGui::Text("Hierarchies");
  36. ImGui::Separator();
  37. for (const auto& root : m_hierarchyRoots)
  38. {
  39. if (const auto* rootComponent = root.second.m_rootComponent)
  40. {
  41. if (rootComponent->IsHierarchicalRoot())
  42. {
  43. const AZStd::vector<AZ::Entity*>& hierarchicalChildren = rootComponent->GetHierarchicalEntities();
  44. if (ImGui::TreeNode(rootComponent->GetEntity()->GetName().c_str(),
  45. "[%s] %4zu members",
  46. rootComponent->GetEntity()->GetName().c_str(),
  47. hierarchicalChildren.size()))
  48. {
  49. ImGui::Separator();
  50. ImGui::Columns(4, "hierarchy_columns");
  51. ImGui::Text("EntityId");
  52. ImGui::NextColumn();
  53. ImGui::Text("NetEntityId");
  54. ImGui::NextColumn();
  55. ImGui::Text("Entity Name");
  56. ImGui::NextColumn();
  57. ImGui::Text("Role");
  58. ImGui::NextColumn();
  59. ImGui::Separator();
  60. ImGui::Columns(4, "hierarchy child info");
  61. bool firstEntity = true;
  62. for (const AZ::Entity* entity : hierarchicalChildren)
  63. {
  64. ImGui::Text("%s", entity->GetId().ToString().c_str());
  65. ImGui::NextColumn();
  66. ImGui::Text("%llu", static_cast<AZ::u64>(GetMultiplayer()->GetNetworkEntityManager()->GetNetEntityIdById(entity->GetId())));
  67. ImGui::NextColumn();
  68. ImGui::Text("%s", entity->GetName().c_str());
  69. ImGui::NextColumn();
  70. if (firstEntity)
  71. {
  72. ImGui::Text("Root node");
  73. }
  74. else if (entity->FindComponent<NetworkHierarchyRootComponent>())
  75. {
  76. ImGui::Text("Inner root node");
  77. }
  78. else if (entity->FindComponent<NetworkHierarchyChildComponent>())
  79. {
  80. ImGui::Text("Child node");
  81. }
  82. ImGui::NextColumn();
  83. firstEntity = false;
  84. }
  85. ImGui::Columns(1);
  86. ImGui::TreePop();
  87. }
  88. }
  89. }
  90. }
  91. ImGui::Separator();
  92. if (ImGui::InputFloat("Awareness Radius", &m_awarenessRadius))
  93. {
  94. CollectHierarchyRoots();
  95. }
  96. if (ImGui::Button("Refresh"))
  97. {
  98. CollectHierarchyRoots();
  99. }
  100. #endif
  101. }
  102. void MultiplayerDebugHierarchyReporter::UpdateDebugOverlay()
  103. {
  104. if (!m_hierarchyRoots.empty())
  105. {
  106. if (m_debugDisplay == nullptr)
  107. {
  108. AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus;
  109. AzFramework::DebugDisplayRequestBus::Bind(debugDisplayBus, AzFramework::g_defaultSceneEntityDebugDisplayId);
  110. m_debugDisplay = AzFramework::DebugDisplayRequestBus::FindFirstHandler(debugDisplayBus);
  111. }
  112. const AZ::u32 stateBefore = m_debugDisplay->GetState();
  113. m_debugDisplay->SetColor(AZ::Colors::White);
  114. for (const auto& root : m_hierarchyRoots)
  115. {
  116. if (const auto* rootComponent = root.second.m_rootComponent)
  117. {
  118. if (rootComponent->IsHierarchicalRoot())
  119. {
  120. const AZStd::vector<AZ::Entity*>& hierarchicalChildren = rootComponent->GetHierarchicalEntities();
  121. azsnprintf(m_statusBuffer, AZ_ARRAY_SIZE(m_statusBuffer), "Hierarchy [%s] %u members", rootComponent->GetEntity()->GetName().c_str(),
  122. aznumeric_cast<AZ::u32>(hierarchicalChildren.size()));
  123. AZ::Vector3 entityPosition = rootComponent->GetEntity()->GetTransform()->GetWorldTranslation();
  124. constexpr bool centerText = true;
  125. m_debugDisplay->DrawTextLabel(entityPosition, 1.0f, m_statusBuffer, centerText, 0, 0);
  126. }
  127. }
  128. }
  129. m_debugDisplay->SetState(stateBefore);
  130. }
  131. }
  132. void MultiplayerDebugHierarchyReporter::OnEntityActivated(const AZ::EntityId& entityId)
  133. {
  134. if (const AZ::Entity* childEntity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(entityId))
  135. {
  136. if (auto* rootComponent = childEntity->FindComponent<NetworkHierarchyRootComponent>())
  137. {
  138. HierarchyRootInfo info;
  139. info.m_rootComponent = rootComponent;
  140. rootComponent->BindNetworkHierarchyChangedEventHandler(info.m_changedEvent);
  141. rootComponent->BindNetworkHierarchyLeaveEventHandler(info.m_leaveEvent);
  142. m_hierarchyRoots.insert(AZStd::make_pair(rootComponent, info));
  143. }
  144. }
  145. }
  146. void MultiplayerDebugHierarchyReporter::OnEntityDeactivated(const AZ::EntityId& entityId)
  147. {
  148. if (const AZ::Entity* childEntity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(entityId))
  149. {
  150. if (auto* rootComponent = childEntity->FindComponent<NetworkHierarchyRootComponent>())
  151. {
  152. m_hierarchyRoots.erase(rootComponent);
  153. }
  154. }
  155. }
  156. void MultiplayerDebugHierarchyReporter::CollectHierarchyRoots()
  157. {
  158. m_hierarchyRoots.clear();
  159. AZ::Sphere awarenessSphere(AZ::Vector3::CreateZero(), m_awarenessRadius);
  160. const auto viewportContextManager = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get();
  161. if (const auto viewportContext = viewportContextManager->GetDefaultViewportContext())
  162. {
  163. awarenessSphere.SetCenter(viewportContext->GetCameraTransform().GetTranslation());
  164. }
  165. AZStd::vector<AzFramework::VisibilityEntry*> gatheredEntries;
  166. AZ::Interface<AzFramework::IVisibilitySystem>::Get()->GetDefaultVisibilityScene()->Enumerate(awarenessSphere,
  167. [&gatheredEntries](const AzFramework::IVisibilityScene::NodeData& nodeData)
  168. {
  169. gatheredEntries.reserve(gatheredEntries.size() + nodeData.m_entries.size());
  170. for (AzFramework::VisibilityEntry* visEntry : nodeData.m_entries)
  171. {
  172. if (visEntry->m_typeFlags & AzFramework::VisibilityEntry::TypeFlags::TYPE_Entity)
  173. {
  174. gatheredEntries.push_back(visEntry);
  175. }
  176. }
  177. }
  178. );
  179. for (const AzFramework::VisibilityEntry* entry : gatheredEntries)
  180. {
  181. const AZ::Entity* entity = static_cast<AZ::Entity*>(entry->m_userData);
  182. if (auto* rootComponent = entity->FindComponent<NetworkHierarchyRootComponent>())
  183. {
  184. if (awarenessSphere.GetCenter().GetDistanceEstimate(entity->GetTransform()->GetWorldTranslation()) < m_awarenessRadius)
  185. {
  186. HierarchyRootInfo info;
  187. info.m_rootComponent = rootComponent;
  188. rootComponent->BindNetworkHierarchyChangedEventHandler(info.m_changedEvent);
  189. rootComponent->BindNetworkHierarchyLeaveEventHandler(info.m_leaveEvent);
  190. m_hierarchyRoots.insert(AZStd::make_pair(rootComponent, info));
  191. }
  192. }
  193. }
  194. }
  195. }