| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- /*
- * 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 <Atom/RPI.Public/ViewportContext.h>
- #include <Atom/RPI.Public/ViewportContextBus.h>
- #include <AzFramework/Entity/EntityDebugDisplayBus.h>
- #include <AzFramework/Visibility/IVisibilitySystem.h>
- #include <Multiplayer/Components/NetBindComponent.h>
- #include <Multiplayer/Components/NetworkHierarchyChildComponent.h>
- #if defined(IMGUI_ENABLED)
- #include <imgui/imgui.h>
- #endif
- namespace Multiplayer
- {
- MultiplayerDebugHierarchyReporter::MultiplayerDebugHierarchyReporter()
- : m_updateDebugOverlay([this]() { UpdateDebugOverlay(); }, AZ::Name("UpdateHierarchyDebug"))
- {
- CollectHierarchyRoots();
- AZ::EntitySystemBus::Handler::BusConnect();
- m_updateDebugOverlay.Enqueue(AZ::Time::ZeroTimeMs, true);
- }
- MultiplayerDebugHierarchyReporter::~MultiplayerDebugHierarchyReporter()
- {
- AZ::EntitySystemBus::Handler::BusDisconnect();
- }
- // --------------------------------------------------------------------------------------------
- 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)
- {
- if (rootComponent->IsHierarchicalRoot())
- {
- const AZStd::vector<AZ::Entity*>& hierarchicalChildren = rootComponent->GetHierarchicalEntities();
- if (ImGui::TreeNode(rootComponent->GetEntity()->GetName().c_str(),
- "[%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("%llu", static_cast<AZ::u64>(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<NetworkHierarchyRootComponent>())
- {
- ImGui::Text("Inner root node");
- }
- else if (entity->FindComponent<NetworkHierarchyChildComponent>())
- {
- ImGui::Text("Child node");
- }
- ImGui::NextColumn();
- firstEntity = false;
- }
- ImGui::Columns(1);
- ImGui::TreePop();
- }
- }
- }
- }
- ImGui::Separator();
- if (ImGui::InputFloat("Awareness Radius", &m_awarenessRadius))
- {
- CollectHierarchyRoots();
- }
- if (ImGui::Button("Refresh"))
- {
- CollectHierarchyRoots();
- }
- #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<AZ::Entity*>& hierarchicalChildren = rootComponent->GetHierarchicalEntities();
- azsnprintf(m_statusBuffer, AZ_ARRAY_SIZE(m_statusBuffer), "Hierarchy [%s] %u members", rootComponent->GetEntity()->GetName().c_str(),
- aznumeric_cast<AZ::u32>(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<AZ::ComponentApplicationRequests>::Get()->FindEntity(entityId))
- {
- if (auto* rootComponent = childEntity->FindComponent<NetworkHierarchyRootComponent>())
- {
- 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<AZ::ComponentApplicationRequests>::Get()->FindEntity(entityId))
- {
- if (auto* rootComponent = childEntity->FindComponent<NetworkHierarchyRootComponent>())
- {
- m_hierarchyRoots.erase(rootComponent);
- }
- }
- }
- void MultiplayerDebugHierarchyReporter::CollectHierarchyRoots()
- {
- m_hierarchyRoots.clear();
- AZ::Sphere awarenessSphere(AZ::Vector3::CreateZero(), m_awarenessRadius);
- const auto viewportContextManager = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get();
- if (const auto viewportContext = viewportContextManager->GetDefaultViewportContext())
- {
- awarenessSphere.SetCenter(viewportContext->GetCameraTransform().GetTranslation());
- }
- AZStd::vector<AzFramework::VisibilityEntry*> gatheredEntries;
- AZ::Interface<AzFramework::IVisibilitySystem>::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<AZ::Entity*>(entry->m_userData);
- if (auto* rootComponent = entity->FindComponent<NetworkHierarchyRootComponent>())
- {
- 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));
- }
- }
- }
- }
- }
|