diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerStats.h b/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerStats.h index 1299fe174d..98a7b165f8 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerStats.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerStats.h @@ -55,8 +55,8 @@ namespace Multiplayer void RecordEntitySerializeStop(AzNetworking::SerializerMode mode, AZ::EntityId entityId, const char* entityName); void RecordPropertySent(NetComponentId netComponentId, PropertyIndex propertyId, uint32_t totalBytes); void RecordPropertyReceived(NetComponentId netComponentId, PropertyIndex propertyId, uint32_t totalBytes); - void RecordRpcSent(NetComponentId netComponentId, RpcIndex rpcId, uint32_t totalBytes); - void RecordRpcReceived(NetComponentId netComponentId, RpcIndex rpcId, uint32_t totalBytes); + void RecordRpcSent(AZ::EntityId entityId, const char* entityName, NetComponentId netComponentId, RpcIndex rpcId, uint32_t totalBytes); + void RecordRpcReceived(AZ::EntityId entityId, const char* entityName, NetComponentId netComponentId, RpcIndex rpcId, uint32_t totalBytes); void TickStats(AZ::TimeMs metricFrameTimeMs); Metric CalculateComponentPropertyUpdateSentMetrics(NetComponentId netComponentId) const; @@ -67,5 +67,31 @@ namespace Multiplayer Metric CalculateTotalPropertyUpdateRecvMetrics() const; Metric CalculateTotalRpcsSentMetrics() const; Metric CalculateTotalRpcsRecvMetrics() const; + + struct Events + { + AZ::Event m_entitySerializeStart; + AZ::Event m_componentSerializeEnd; + AZ::Event m_entitySerializeStop; + AZ::Event m_propertySent; + AZ::Event m_propertyReceived; + AZ::Event m_rpcSent; + AZ::Event m_rpcReceived; + }; + + Events m_events; + + struct EventHandlers + { + AZ::Event::Handler m_entitySerializeStart; + AZ::Event::Handler m_componentSerializeEnd; + AZ::Event::Handler m_entitySerializeStop; + AZ::Event::Handler m_propertySent; + AZ::Event::Handler m_propertyReceived; + AZ::Event::Handler m_rpcSent; + AZ::Event::Handler m_rpcReceived; + }; + + void ConnectHandlers(EventHandlers& handlers); }; } diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp index 5e912612b7..a29350e43a 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp @@ -14,7 +14,7 @@ #pragma optimize("", off) -namespace MultiplayerDiagnostics +namespace Multiplayer { void MultiplayerDebugByteReporter::ReportBytes(size_t byteSize) { @@ -44,7 +44,7 @@ namespace MultiplayerDiagnostics return 0.0f; } - return (1.0f * m_totalBytes) / m_count; + return aznumeric_cast(m_totalBytes) / aznumeric_cast(m_count); } size_t MultiplayerDebugByteReporter::GetMaxBytes() const @@ -64,26 +64,26 @@ namespace MultiplayerDiagnostics float MultiplayerDebugByteReporter::GetKbitsPerSecond() { - auto now = AZStd::chrono::monotonic_clock::now(); + const auto now = AZStd::chrono::monotonic_clock::now(); // Check the amount of time elapsed and update totals if necessary. // Time here is measured in whole seconds from the epoch, providing synchronization in // reporting intervals across all byte reporters. - AZStd::chrono::seconds nowSeconds = AZStd::chrono::duration_cast(now.time_since_epoch()); - AZStd::chrono::seconds secondsSinceLastUpdate = nowSeconds - + const AZStd::chrono::seconds nowSeconds = AZStd::chrono::duration_cast(now.time_since_epoch()); + const AZStd::chrono::seconds secondsSinceLastUpdate = nowSeconds - AZStd::chrono::duration_cast(m_lastUpdateTime.time_since_epoch()); if (secondsSinceLastUpdate.count()) { // normalize over elapsed milliseconds - const int k_millisecondsPerSecond = 1000; - auto msSinceLastUpdate = AZStd::chrono::duration_cast(now - m_lastUpdateTime); - m_totalBytesLastSecond = k_millisecondsPerSecond * (1.f * m_totalBytesThisSecond / msSinceLastUpdate.count()); + constexpr int k_millisecondsPerSecond = 1000; + const auto msSinceLastUpdate = AZStd::chrono::duration_cast(now - m_lastUpdateTime); + m_totalBytesLastSecond = k_millisecondsPerSecond * aznumeric_cast(m_totalBytesThisSecond) / aznumeric_cast(msSinceLastUpdate.count()); m_totalBytesThisSecond = 0; m_lastUpdateTime = now; } - const float k_bitsPerByte = 8.0f; - const int k_bitsPerKilobit = 1024; + constexpr float k_bitsPerByte = 8.0f; + constexpr int k_bitsPerKilobit = 1024; return k_bitsPerByte * m_totalBytesLastSecond / k_bitsPerKilobit; } @@ -107,19 +107,19 @@ namespace MultiplayerDiagnostics m_aggregateBytes = 0; } - void ComponentReporter::ReportField(const char* fieldName, size_t byteSize) + void MultiplayerDebugComponentReporter::ReportField(const char* fieldName, size_t byteSize) { MultiplayerDebugByteReporter::AggregateBytes(byteSize); m_fieldReports[fieldName].ReportBytes(byteSize); } - void ComponentReporter::ReportFragmentEnd() + void MultiplayerDebugComponentReporter::ReportFragmentEnd() { MultiplayerDebugByteReporter::ReportAggregateBytes(); m_componentDirtyBytes.ReportAggregateBytes(); } - AZStd::vector ComponentReporter::GetFieldReports() + AZStd::vector MultiplayerDebugComponentReporter::GetFieldReports() { AZStd::vector copy; for (auto field = m_fieldReports.begin(); field != m_fieldReports.end(); ++field) @@ -137,7 +137,7 @@ namespace MultiplayerDiagnostics return copy; } - void ComponentReporter::Combine(const ComponentReporter& other) + void MultiplayerDebugComponentReporter::Combine(const MultiplayerDebugComponentReporter& other) { MultiplayerDebugByteReporter::Combine(other); @@ -149,7 +149,7 @@ namespace MultiplayerDiagnostics m_componentDirtyBytes.Combine(other.m_componentDirtyBytes); } - void EntityReporter::ReportField(AZ::u32 index, const char* componentName, + void MultiplayerDebugEntityReporter::ReportField(AZ::u32 index, const char* componentName, const char* fieldName, size_t byteSize) { if (m_currentComponentReport == nullptr) @@ -163,7 +163,7 @@ namespace MultiplayerDiagnostics MultiplayerDebugByteReporter::AggregateBytes(byteSize); } - void EntityReporter::ReportFragmentEnd() + void MultiplayerDebugEntityReporter::ReportFragmentEnd() { if (m_currentComponentReport) { @@ -175,7 +175,7 @@ namespace MultiplayerDiagnostics MultiplayerDebugByteReporter::ReportAggregateBytes(); } - void EntityReporter::Combine(const EntityReporter& other) + void MultiplayerDebugEntityReporter::Combine(const MultiplayerDebugEntityReporter& other) { MultiplayerDebugByteReporter::Combine(other); @@ -188,7 +188,7 @@ namespace MultiplayerDiagnostics m_gdeDirtyBytes.Combine(other.m_gdeDirtyBytes); } - void EntityReporter::Reset() + void MultiplayerDebugEntityReporter::Reset() { MultiplayerDebugByteReporter::Reset(); @@ -196,7 +196,7 @@ namespace MultiplayerDiagnostics m_gdeDirtyBytes.Reset(); } - AZStd::map& EntityReporter::GetComponentReports() + AZStd::map& MultiplayerDebugEntityReporter::GetComponentReports() { return m_componentReports; } diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.h index 3cef9caaac..934c6f3aac 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.h +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.h @@ -13,7 +13,7 @@ #include #include -namespace MultiplayerDiagnostics +namespace Multiplayer { class MultiplayerDebugByteReporter { @@ -48,10 +48,10 @@ namespace MultiplayerDiagnostics AZStd::chrono::monotonic_clock::time_point m_lastUpdateTime; }; - class ComponentReporter : public MultiplayerDebugByteReporter + class MultiplayerDebugComponentReporter : public MultiplayerDebugByteReporter { public: - ComponentReporter() = default; + MultiplayerDebugComponentReporter() = default; void ReportField(const char* fieldName, size_t byteSize); void ReportFragmentEnd(); @@ -61,22 +61,22 @@ namespace MultiplayerDiagnostics AZStd::size_t GetTotalDirtyBits() const { return m_componentDirtyBytes.GetTotalBytes(); } float GetAvgDirtyBits() const { return m_componentDirtyBytes.GetAverageBytes(); } - void Combine(const ComponentReporter& other); + void Combine(const MultiplayerDebugComponentReporter& other); private: AZStd::map m_fieldReports; MultiplayerDebugByteReporter m_componentDirtyBytes; }; - class EntityReporter : public MultiplayerDebugByteReporter + class MultiplayerDebugEntityReporter : public MultiplayerDebugByteReporter { public: - EntityReporter() = default; + MultiplayerDebugEntityReporter() = default; void ReportField(AZ::u32 index, const char* componentName, const char* fieldName, size_t byteSize); void ReportFragmentEnd(); - void Combine(const EntityReporter& other); + void Combine(const MultiplayerDebugEntityReporter& other); void Reset() override; const char* GetEntityName() const { return m_entityName.c_str(); } @@ -86,13 +86,13 @@ namespace MultiplayerDiagnostics m_entityName = entityName; } - AZStd::map& GetComponentReports(); + AZStd::map& GetComponentReports(); AZStd::size_t GetTotalDirtyBits() const { return m_gdeDirtyBytes.GetTotalBytes(); } float GetAvgDirtyBits() const { return m_gdeDirtyBytes.GetAverageBytes(); } private: - ComponentReporter* m_currentComponentReport = nullptr; - AZStd::map m_componentReports; + MultiplayerDebugComponentReporter* m_currentComponentReport = nullptr; + AZStd::map m_componentReports; MultiplayerDebugByteReporter m_gdeDirtyBytes; AZStd::string m_entityName; }; diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityInterface.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityInterface.h deleted file mode 100644 index 4f177affe3..0000000000 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityInterface.h +++ /dev/null @@ -1,29 +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 - -namespace MultiplayerDiagnostics -{ - class MultiplayerIPerEntityStats - { - public: - AZ_RTTI(MultiplayerIPerEntityStats, "{91A1E4F0-8AE6-44B2-89DF-DA34134C408A}"); - - virtual void RecordEntitySerializeStart(AzNetworking::SerializerMode mode, AZ::EntityId entityId, const char* entityName) = 0; - virtual void RecordComponentSerializeEnd(AzNetworking::SerializerMode mode, Multiplayer::NetComponentId netComponentId) = 0; - virtual void RecordEntitySerializeStop(AzNetworking::SerializerMode mode, AZ::EntityId entityId, const char* entityName) = 0; - virtual void RecordPropertySent(Multiplayer::NetComponentId netComponentId, Multiplayer::PropertyIndex propertyId, uint32_t totalBytes) = 0; - virtual void RecordPropertyReceived(Multiplayer::NetComponentId netComponentId, Multiplayer::PropertyIndex propertyId, uint32_t totalBytes) = 0; - virtual void RecordRpcSent(Multiplayer::NetComponentId netComponentId, Multiplayer::RpcIndex rpcId, uint32_t totalBytes) = 0; - virtual void RecordRpcReceived(Multiplayer::NetComponentId netComponentId, Multiplayer::RpcIndex rpcId, uint32_t totalBytes) = 0; - }; -} diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp index 3c5495ec6a..da32bbb666 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp @@ -34,7 +34,7 @@ AZ_CVAR(AZ::Color, net_DebugNetworkEntity_WarningColor, AZ::Colors::Red, nullptr AZ_CVAR(AZ::Color, net_DebugNetworkEntity_BelowWarningColor, AZ::Colors::Grey, nullptr, AZ::ConsoleFunctorFlags::Null, "If true, prints debug text over entities that use a considerable amount of network traffic"); -namespace MultiplayerDiagnostics +namespace Multiplayer { #if defined(IMGUI_ENABLED) static const ImVec4 k_ImGuiTomato = ImVec4(1.0f, 0.4f, 0.3f, 1.0f); @@ -64,12 +64,12 @@ namespace MultiplayerDiagnostics } // -------------------------------------------------------------------------------------------- - void DisplayReplicatedStateReport(AZStd::map& componentReports, float kbpsWarn, float maxWarn) + void DisplayReplicatedStateReport(AZStd::map& componentReports, float kbpsWarn, float maxWarn) { for (auto& componentPair : componentReports) { ImGui::Separator(); - ComponentReporter& componentReport = componentPair.second; + MultiplayerDebugComponentReporter& componentReport = componentPair.second; if (ReplicatedStateTreeNode(componentPair.first, componentReport, k_ImGuiCyan, 1)) { @@ -94,7 +94,7 @@ namespace MultiplayerDiagnostics const float kbitsLastSecond = fieldReport.GetKbitsPerSecond(); const ImVec4* textColor = &k_ImGuiWhite; - if (fieldReport.GetMaxBytes() > maxWarn) + if (aznumeric_cast(fieldReport.GetMaxBytes()) > maxWarn) { textColor = &k_ImGuiKhaki; } @@ -133,6 +133,37 @@ namespace MultiplayerDiagnostics : m_updateDebugOverlay([this]() { UpdateDebugOverlay(); }, AZ::Name("UpdateDebugPerEntityOverlay")) { m_updateDebugOverlay.Enqueue(AZ::TimeMs{ 0 }, true); + + m_eventHandlers.m_entitySerializeStart = decltype(m_eventHandlers.m_entitySerializeStart)([this](AzNetworking::SerializerMode mode, AZ::EntityId entityId, const char* entityName) + { + RecordEntitySerializeStart(mode, entityId, entityName); + }); + m_eventHandlers.m_componentSerializeEnd = decltype(m_eventHandlers.m_componentSerializeEnd)([this](AzNetworking::SerializerMode mode, Multiplayer::NetComponentId netComponentId) + { + RecordComponentSerializeEnd(mode, netComponentId); + }); + m_eventHandlers.m_entitySerializeStop = decltype(m_eventHandlers.m_entitySerializeStop)([this](AzNetworking::SerializerMode mode, AZ::EntityId entityId, const char* entityName) + { + RecordEntitySerializeStop(mode, entityId, entityName); + }); + m_eventHandlers.m_propertySent = decltype(m_eventHandlers.m_propertySent)([this](Multiplayer::NetComponentId netComponentId, Multiplayer::PropertyIndex propertyId, uint32_t totalBytes) + { + RecordPropertySent(netComponentId, propertyId, totalBytes); + }); + m_eventHandlers.m_propertyReceived = decltype(m_eventHandlers.m_propertyReceived)([this](Multiplayer::NetComponentId netComponentId, Multiplayer::PropertyIndex propertyId, uint32_t totalBytes) + { + RecordPropertyReceived(netComponentId, propertyId, totalBytes); + }); + m_eventHandlers.m_rpcSent = decltype(m_eventHandlers.m_rpcSent)([this](AZ::EntityId entityId, const char* entityName, Multiplayer::NetComponentId netComponentId, Multiplayer::RpcIndex rpcId, uint32_t totalBytes) + { + RecordRpcSent(entityId, entityName, netComponentId, rpcId, totalBytes); + }); + m_eventHandlers.m_rpcReceived = decltype(m_eventHandlers.m_rpcReceived)([this](AZ::EntityId entityId, const char* entityName, Multiplayer::NetComponentId netComponentId, Multiplayer::RpcIndex rpcId, uint32_t totalBytes) + { + RecordRpcSent(entityId, entityName, netComponentId, rpcId, totalBytes); + }); + + GetMultiplayer()->GetStats().ConnectHandlers(m_eventHandlers); } MultiplayerDebugPerEntityReporter::~MultiplayerDebugPerEntityReporter() @@ -149,7 +180,7 @@ namespace MultiplayerDiagnostics if (ImGui::CollapsingHeader("Receiving Entities")) { - for (AZStd::pair& entityPair : m_receivingEntityReports) + for (AZStd::pair& entityPair : m_receivingEntityReports) { if (!filter.PassFilter(entityPair.second.GetEntityName())) { @@ -167,7 +198,7 @@ namespace MultiplayerDiagnostics if (ImGui::CollapsingHeader("Sending Entities")) { - for (AZStd::pair& entityPair : m_sendingEntityReports) + for (AZStd::pair& entityPair : m_sendingEntityReports) { const char* name = entityPair.second.GetEntityName(); if (!filter.PassFilter(name)) @@ -255,26 +286,38 @@ namespace MultiplayerDiagnostics } } - void MultiplayerDebugPerEntityReporter::RecordRpcSent(Multiplayer::NetComponentId netComponentId, Multiplayer::RpcIndex rpcId, uint32_t totalBytes) + void MultiplayerDebugPerEntityReporter::RecordRpcSent(AZ::EntityId entityId, const char* entityName, Multiplayer::NetComponentId netComponentId, Multiplayer::RpcIndex rpcId, uint32_t totalBytes) { if (const Multiplayer::MultiplayerComponentRegistry* componentRegistry = Multiplayer::GetMultiplayerComponentRegistry()) { + // MultiplayerDebugByteReporter requires a + RecordEntitySerializeStart(AzNetworking::SerializerMode::ReadFromObject, entityId, entityName); + m_currentSendingEntityReport.ReportField(static_cast(netComponentId), componentRegistry->GetComponentName(netComponentId), componentRegistry->GetComponentRpcName(netComponentId, rpcId), totalBytes); + + RecordComponentSerializeEnd(AzNetworking::SerializerMode::ReadFromObject, netComponentId); + RecordEntitySerializeStop(AzNetworking::SerializerMode::ReadFromObject, entityId, entityName); } } void MultiplayerDebugPerEntityReporter::RecordRpcReceived( + AZ::EntityId entityId, const char* entityName, Multiplayer::NetComponentId netComponentId, Multiplayer::RpcIndex rpcId, uint32_t totalBytes) { if (const Multiplayer::MultiplayerComponentRegistry* componentRegistry = Multiplayer::GetMultiplayerComponentRegistry()) { + RecordEntitySerializeStart(AzNetworking::SerializerMode::WriteToObject, entityId, entityName); + m_currentReceivingEntityReport.ReportField(static_cast(netComponentId), componentRegistry->GetComponentName(netComponentId), componentRegistry->GetComponentRpcName(netComponentId, rpcId), totalBytes); + + RecordComponentSerializeEnd(AzNetworking::SerializerMode::WriteToObject, netComponentId); + RecordEntitySerializeStop(AzNetworking::SerializerMode::WriteToObject, entityId, entityName); } } @@ -284,13 +327,13 @@ namespace MultiplayerDiagnostics { m_networkEntitiesTraffic.clear(); - for (AZStd::pair& entityPair : m_receivingEntityReports) + for (AZStd::pair& entityPair : m_receivingEntityReports) { m_networkEntitiesTraffic[entityPair.first].m_name = entityPair.second.GetEntityName(); m_networkEntitiesTraffic[entityPair.first].m_down = entityPair.second.GetKbitsPerSecond(); } - for (AZStd::pair& entityPair : m_sendingEntityReports) + for (AZStd::pair& entityPair : m_sendingEntityReports) { m_networkEntitiesTraffic[entityPair.first].m_name = entityPair.second.GetEntityName(); m_networkEntitiesTraffic[entityPair.first].m_up = entityPair.second.GetKbitsPerSecond(); diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h index 23192062e3..d6ceaaf04c 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h @@ -10,38 +10,35 @@ #include "MultiplayerDebugByteReporter.h" #include -#include #include #include #include -#include -#include +#include #include -namespace MultiplayerDiagnostics +namespace Multiplayer { /** * \brief GridMate network live analysis tool via ImGui. */ class MultiplayerDebugPerEntityReporter - : public AZ::Interface::Registrar { public: MultiplayerDebugPerEntityReporter(); - ~MultiplayerDebugPerEntityReporter() override; + ~MultiplayerDebugPerEntityReporter(); // main update loop void OnImGuiUpdate(); - //! MultilayerIPerEntityStats + //! Event handlers // @{ - void RecordEntitySerializeStart(AzNetworking::SerializerMode mode, AZ::EntityId entityId, const char* entityName) override; - void RecordComponentSerializeEnd(AzNetworking::SerializerMode mode, Multiplayer::NetComponentId netComponentId) override; - void RecordEntitySerializeStop(AzNetworking::SerializerMode mode, AZ::EntityId entityId, const char* entityName) override; - void RecordPropertySent(Multiplayer::NetComponentId netComponentId, Multiplayer::PropertyIndex propertyId, uint32_t totalBytes) override; - void RecordPropertyReceived(Multiplayer::NetComponentId netComponentId, Multiplayer::PropertyIndex propertyId, uint32_t totalBytes) override; - void RecordRpcSent(Multiplayer::NetComponentId netComponentId, Multiplayer::RpcIndex rpcId, uint32_t totalBytes) override; - void RecordRpcReceived(Multiplayer::NetComponentId netComponentId, Multiplayer::RpcIndex rpcId, uint32_t totalBytes) override; + void RecordEntitySerializeStart(AzNetworking::SerializerMode mode, AZ::EntityId entityId, const char* entityName); + void RecordComponentSerializeEnd(AzNetworking::SerializerMode mode, Multiplayer::NetComponentId netComponentId); + void RecordEntitySerializeStop(AzNetworking::SerializerMode mode, AZ::EntityId entityId, const char* entityName); + void RecordPropertySent(Multiplayer::NetComponentId netComponentId, Multiplayer::PropertyIndex propertyId, uint32_t totalBytes); + void RecordPropertyReceived(Multiplayer::NetComponentId netComponentId, Multiplayer::PropertyIndex propertyId, uint32_t totalBytes); + void RecordRpcSent(AZ::EntityId entityId, const char* entityName, Multiplayer::NetComponentId netComponentId, Multiplayer::RpcIndex rpcId, uint32_t totalBytes); + void RecordRpcReceived(AZ::EntityId entityId, const char* entityName, Multiplayer::NetComponentId netComponentId, Multiplayer::RpcIndex rpcId, uint32_t totalBytes); // }@ void UpdateDebugOverlay(); @@ -49,12 +46,13 @@ namespace MultiplayerDiagnostics private: AZ::ScheduledEvent m_updateDebugOverlay; + Multiplayer::MultiplayerStats::EventHandlers m_eventHandlers; - AZStd::map m_sendingEntityReports{}; - EntityReporter m_currentSendingEntityReport; + AZStd::map m_sendingEntityReports{}; + MultiplayerDebugEntityReporter m_currentSendingEntityReport; - AZStd::map m_receivingEntityReports{}; - EntityReporter m_currentReceivingEntityReport; + AZStd::map m_receivingEntityReports{}; + MultiplayerDebugEntityReporter m_currentReceivingEntityReport; float m_replicatedStateKbpsWarn = 10.f; float m_replicatedStateMaxSizeWarn = 30.f; diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp index 835aae0d72..03d79025f7 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp @@ -55,7 +55,7 @@ namespace Multiplayer void MultiplayerDebugSystemComponent::OnImGuiInitialize() { - m_reporter = AZStd::make_unique(); + m_reporter = AZStd::make_unique(); } #ifdef IMGUI_ENABLED @@ -65,7 +65,7 @@ namespace Multiplayer { ImGui::Checkbox("Networking Stats", &m_displayNetworkingStats); ImGui::Checkbox("Multiplayer Stats", &m_displayMultiplayerStats); - ImGui::Checkbox("Multiplayer Per Entity Stats", &m_displayPerEntityStats); + ImGui::Checkbox("Multiplayer Entity Stats", &m_displayPerEntityStats); ImGui::EndMenu(); } } diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h index 4972ec6bdf..a7f76e075a 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h @@ -53,6 +53,6 @@ namespace Multiplayer bool m_displayMultiplayerStats = false; bool m_displayPerEntityStats = false; - AZStd::unique_ptr m_reporter; + AZStd::unique_ptr m_reporter; }; } diff --git a/Gems/Multiplayer/Code/Source/MultiplayerStats.cpp b/Gems/Multiplayer/Code/Source/MultiplayerStats.cpp index 05be869872..7e56cd34f3 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerStats.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerStats.cpp @@ -6,7 +6,6 @@ * */ -#include #include namespace Multiplayer @@ -32,86 +31,65 @@ namespace Multiplayer void MultiplayerStats::RecordEntitySerializeStart(AzNetworking::SerializerMode mode, AZ::EntityId entityId, const char* entityName) { - if (auto* perEntityStats = AZ::Interface::Get()) - { - perEntityStats->RecordEntitySerializeStart(mode, entityId, entityName); - } + m_events.m_entitySerializeStart.Signal(mode, entityId, entityName); } void MultiplayerStats::RecordComponentSerializeEnd(AzNetworking::SerializerMode mode, NetComponentId netComponentId) { - if (auto* perEntityStats = AZ::Interface::Get()) - { - perEntityStats->RecordComponentSerializeEnd(mode, netComponentId); - } + m_events.m_componentSerializeEnd.Signal(mode, netComponentId); } void MultiplayerStats::RecordEntitySerializeStop(AzNetworking::SerializerMode mode, AZ::EntityId entityId, const char* entityName) { - if (auto* perEntityStats = AZ::Interface::Get()) - { - perEntityStats->RecordEntitySerializeStop(mode, entityId, entityName); - } + m_events.m_entitySerializeStop.Signal(mode, entityId, entityName); } void MultiplayerStats::RecordPropertySent(NetComponentId netComponentId, PropertyIndex propertyId, uint32_t totalBytes) { - if (auto* perEntityStats = AZ::Interface::Get()) - { - perEntityStats->RecordPropertySent(netComponentId, propertyId, totalBytes); - } - const uint16_t netComponentIndex = aznumeric_cast(netComponentId); const uint16_t propertyIndex = aznumeric_cast(propertyId); m_componentStats[netComponentIndex].m_propertyUpdatesSent[propertyIndex].m_totalCalls++; m_componentStats[netComponentIndex].m_propertyUpdatesSent[propertyIndex].m_totalBytes += totalBytes; m_componentStats[netComponentIndex].m_propertyUpdatesSent[propertyIndex].m_callHistory[m_recordMetricIndex]++; m_componentStats[netComponentIndex].m_propertyUpdatesSent[propertyIndex].m_byteHistory[m_recordMetricIndex] += totalBytes; + + m_events.m_propertySent.Signal(netComponentId, propertyId, totalBytes); } void MultiplayerStats::RecordPropertyReceived(NetComponentId netComponentId, PropertyIndex propertyId, uint32_t totalBytes) { - if (auto* perEntityStats = AZ::Interface::Get()) - { - perEntityStats->RecordPropertyReceived(netComponentId, propertyId, totalBytes); - } - const uint16_t netComponentIndex = aznumeric_cast(netComponentId); const uint16_t propertyIndex = aznumeric_cast(propertyId); m_componentStats[netComponentIndex].m_propertyUpdatesRecv[propertyIndex].m_totalCalls++; m_componentStats[netComponentIndex].m_propertyUpdatesRecv[propertyIndex].m_totalBytes += totalBytes; m_componentStats[netComponentIndex].m_propertyUpdatesRecv[propertyIndex].m_callHistory[m_recordMetricIndex]++; m_componentStats[netComponentIndex].m_propertyUpdatesRecv[propertyIndex].m_byteHistory[m_recordMetricIndex] += totalBytes; + + m_events.m_propertyReceived.Signal(netComponentId, propertyId, totalBytes); } - void MultiplayerStats::RecordRpcSent(NetComponentId netComponentId, RpcIndex rpcId, uint32_t totalBytes) + void MultiplayerStats::RecordRpcSent(AZ::EntityId entityId, const char* entityName, NetComponentId netComponentId, RpcIndex rpcId, uint32_t totalBytes) { - if (auto* perEntityStats = AZ::Interface::Get()) - { - perEntityStats->RecordRpcSent(netComponentId, rpcId, totalBytes); - } - const uint16_t netComponentIndex = aznumeric_cast(netComponentId); const uint16_t rpcIndex = aznumeric_cast(rpcId); m_componentStats[netComponentIndex].m_rpcsSent[rpcIndex].m_totalCalls++; m_componentStats[netComponentIndex].m_rpcsSent[rpcIndex].m_totalBytes += totalBytes; m_componentStats[netComponentIndex].m_rpcsSent[rpcIndex].m_callHistory[m_recordMetricIndex]++; m_componentStats[netComponentIndex].m_rpcsSent[rpcIndex].m_byteHistory[m_recordMetricIndex] += totalBytes; + + m_events.m_rpcSent.Signal(entityId, entityName, netComponentId, rpcId, totalBytes); } - void MultiplayerStats::RecordRpcReceived(NetComponentId netComponentId, RpcIndex rpcId, uint32_t totalBytes) + void MultiplayerStats::RecordRpcReceived(AZ::EntityId entityId, const char* entityName, NetComponentId netComponentId, RpcIndex rpcId, uint32_t totalBytes) { - if (auto* perEntityStats = AZ::Interface::Get()) - { - perEntityStats->RecordRpcReceived(netComponentId, rpcId, totalBytes); - } - const uint16_t netComponentIndex = aznumeric_cast(netComponentId); const uint16_t rpcIndex = aznumeric_cast(rpcId); m_componentStats[netComponentIndex].m_rpcsRecv[rpcIndex].m_totalCalls++; m_componentStats[netComponentIndex].m_rpcsRecv[rpcIndex].m_totalBytes += totalBytes; m_componentStats[netComponentIndex].m_rpcsRecv[rpcIndex].m_callHistory[m_recordMetricIndex]++; m_componentStats[netComponentIndex].m_rpcsRecv[rpcIndex].m_byteHistory[m_recordMetricIndex] += totalBytes; + + m_events.m_rpcReceived.Signal(entityId, entityName, netComponentId, rpcId, totalBytes); } void MultiplayerStats::TickStats(AZ::TimeMs metricFrameTimeMs) @@ -231,4 +209,15 @@ namespace Multiplayer } return result; } + + void MultiplayerStats::ConnectHandlers(EventHandlers& handlers) + { + handlers.m_entitySerializeStart.Connect(m_events.m_entitySerializeStart); + handlers.m_componentSerializeEnd.Connect(m_events.m_componentSerializeEnd); + handlers.m_entitySerializeStop.Connect(m_events.m_entitySerializeStop); + handlers.m_propertySent.Connect(m_events.m_propertySent); + handlers.m_propertyReceived.Connect(m_events.m_propertyReceived); + handlers.m_rpcSent.Connect(m_events.m_rpcSent); + handlers.m_rpcReceived.Connect(m_events.m_rpcReceived); + } } diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp index 2afadbe4a4..457ed3eed5 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp @@ -443,12 +443,8 @@ namespace Multiplayer { // Received rpc metrics, log rpc sent, number of bytes, and the componentId/rpcId for bandwidth metrics MultiplayerStats& stats = GetMultiplayer()->GetStats(); - stats.RecordEntitySerializeStart(AzNetworking::SerializerMode::ReadFromObject, - GetEntityHandle().GetEntity()->GetId(), GetEntityHandle().GetEntity()->GetName().c_str()); - stats.RecordRpcSent(entityRpcMessage.GetComponentId(), entityRpcMessage.GetRpcIndex(), entityRpcMessage.GetEstimatedSerializeSize()); - stats.RecordComponentSerializeEnd(AzNetworking::SerializerMode::ReadFromObject, entityRpcMessage.GetComponentId()); - stats.RecordEntitySerializeStop(AzNetworking::SerializerMode::ReadFromObject, - GetEntityHandle().GetEntity()->GetId(), GetEntityHandle().GetEntity()->GetName().c_str()); + stats.RecordRpcSent(GetEntityHandle().GetEntity()->GetId(), GetEntityHandle().GetEntity()->GetName().c_str(), + entityRpcMessage.GetComponentId(), entityRpcMessage.GetRpcIndex(), entityRpcMessage.GetEstimatedSerializeSize()); m_replicationManager.AddDeferredRpcMessage(entityRpcMessage); } @@ -631,7 +627,8 @@ namespace Multiplayer { // Received rpc metrics, log rpc received, time spent, number of bytes, and the componentId/rpcId for bandwidth metrics MultiplayerStats& stats = GetMultiplayer()->GetStats(); - stats.RecordRpcReceived(entityRpcMessage.GetComponentId(), entityRpcMessage.GetRpcIndex(), entityRpcMessage.GetEstimatedSerializeSize()); + stats.RecordRpcReceived(GetEntityHandle().GetEntity()->GetId(), GetEntityHandle().GetEntity()->GetName().c_str(), + entityRpcMessage.GetComponentId(), entityRpcMessage.GetRpcIndex(), entityRpcMessage.GetEstimatedSerializeSize()); if (!m_netBindComponent) { diff --git a/Gems/Multiplayer/Code/multiplayer_debug_files.cmake b/Gems/Multiplayer/Code/multiplayer_debug_files.cmake index d333269a1d..37a1c91640 100644 --- a/Gems/Multiplayer/Code/multiplayer_debug_files.cmake +++ b/Gems/Multiplayer/Code/multiplayer_debug_files.cmake @@ -9,7 +9,6 @@ set(FILES Source/Debug/MultiplayerDebugByteReporter.cpp Source/Debug/MultiplayerDebugByteReporter.h - Source/Debug/MultiplayerDebugPerEntityInterface.h Source/Debug/MultiplayerDebugPerEntityReporter.cpp Source/Debug/MultiplayerDebugPerEntityReporter.h Source/Debug/MultiplayerDebugModule.cpp