From 46777b537e350ce4b115facebcf25533f81a0da4 Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Mon, 26 Jul 2021 18:01:14 -0400 Subject: [PATCH 01/13] Brought over LY legacy imgui code Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- .../Debug/MultiplayerDebugByteReporter.cpp | 222 ++++++++++ .../Debug/MultiplayerDebugByteReporter.h | 96 +++++ .../MultiplayerDebugPerEntityReporter.cpp | 385 ++++++++++++++++++ .../Debug/MultiplayerDebugPerEntityReporter.h | 90 ++++ .../Debug/MultiplayerDebugSystemComponent.cpp | 11 + .../Debug/MultiplayerDebugSystemComponent.h | 4 + .../Code/multiplayer_debug_files.cmake | 4 + 7 files changed, 812 insertions(+) create mode 100644 Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp create mode 100644 Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.h create mode 100644 Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp create mode 100644 Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp new file mode 100644 index 0000000000..382bc70d9b --- /dev/null +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp @@ -0,0 +1,222 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#include "MultiplayerDebugByteReporter.h" + +#include +#include +#include + +namespace MultiplayerDiagnostics +{ + void MultiplayerDebugByteReporter::ReportBytes(size_t byteSize) + { + m_count++; + m_totalBytes += byteSize; + m_totalBytesThisSecond += byteSize; + m_minBytes = AZStd::min(m_minBytes, byteSize); + m_maxBytes = AZStd::max(m_maxBytes, byteSize); + } + + void MultiplayerDebugByteReporter::AggregateBytes(size_t byteSize) + { + m_aggregateBytes += byteSize; + } + + void MultiplayerDebugByteReporter::ReportAggregateBytes() + { + ReportBytes(m_aggregateBytes); + m_aggregateBytes = 0; + } + + float MultiplayerDebugByteReporter::GetAverageBytes() const + { + if (m_count == 0) + { + AZ_Warning("MultiplayerDebugByteReporter", m_totalBytes == 0, "Attempted to average bytes with a zero count."); + return 0.0f; + } + + return (1.0f * m_totalBytes) / m_count; + } + + size_t MultiplayerDebugByteReporter::GetMaxBytes() const + { + return m_maxBytes; + } + + size_t MultiplayerDebugByteReporter::GetMinBytes() const + { + return m_minBytes; + } + + size_t MultiplayerDebugByteReporter::GetTotalBytes() const + { + return m_totalBytes; + } + + float MultiplayerDebugByteReporter::GetKbitsPerSecond() + { + 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 - + 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()); + m_totalBytesThisSecond = 0; + m_lastUpdateTime = now; + } + + const float k_bitsPerByte = 8.0f; + const int k_bitsPerKilobit = 1024; + return k_bitsPerByte * m_totalBytesLastSecond / k_bitsPerKilobit; + } + + void MultiplayerDebugByteReporter::Combine(const MultiplayerDebugByteReporter& other) + { + m_count += other.m_count; + m_totalBytes += other.m_totalBytes; + m_totalBytesThisSecond += other.m_totalBytesThisSecond; + m_minBytes = AZStd::GetMin(m_minBytes, other.m_minBytes); + m_maxBytes = AZStd::GetMax(m_maxBytes, other.m_maxBytes); + } + + void MultiplayerDebugByteReporter::Reset() + { + m_count = 0; + m_totalBytes = 0; + m_totalBytesThisSecond = 0; + m_totalBytesLastSecond = 0; + m_minBytes = std::numeric_limits::max(); + m_maxBytes = 0; + m_aggregateBytes = 0; + } + + void ComponentReporter::ReportField(const char* fieldName, size_t byteSize) + { + MultiplayerDebugByteReporter::AggregateBytes(byteSize); + m_fieldReports[fieldName].ReportBytes(byteSize); + } + + void ComponentReporter::ReportFragmentEnd() + { + MultiplayerDebugByteReporter::ReportAggregateBytes(); + m_componentDirtyBytes.ReportAggregateBytes(); + } + + AZStd::vector ComponentReporter::GetFieldReports() + { + AZStd::vector copy; + for (auto field = m_fieldReports.begin(); field != m_fieldReports.end(); ++field) + { + copy.emplace_back(field->first, &field->second); + } + + auto sortByFrequency = [](const Report& a, const Report& b) + { + return a.second->GetTotalCount() > b.second->GetTotalCount(); + }; + + AZStd::sort(copy.begin(), copy.end(), sortByFrequency); + + return copy; + } + + void ComponentReporter::Combine(const ComponentReporter& other) + { + MultiplayerDebugByteReporter::Combine(other); + + for (const auto& fieldIter : other.m_fieldReports) + { + m_fieldReports[fieldIter.first].Combine(fieldIter.second); + } + + m_componentDirtyBytes.Combine(other.m_componentDirtyBytes); + } + + void EntityReporter::ReportField(AZ::u32 index, const char* componentName, + const char* fieldName, size_t byteSize) + { + if (m_currentComponentReport == nullptr) + { + std::stringstream component; + component << "[" << std::setw(2) << std::setfill('0') << static_cast(index) << "]" << " " << componentName; + m_currentComponentReport = &m_componentReports[component.str().c_str()]; + } + + m_currentComponentReport->ReportField(fieldName, byteSize); + MultiplayerDebugByteReporter::AggregateBytes(byteSize); + } + + void EntityReporter::ReportDirtyBits(AZ::u32 index, const char* componentName, size_t byteSize) + { + const char* const prefix = "MB::"; + if (strncmp(prefix, componentName, 4) == 0) + { + componentName += strlen(prefix); + } + + if (m_currentComponentReport == nullptr) + { + std::stringstream component; + component << "[" << std::setw(2) << std::setfill('0') << static_cast(index) << "]" << " " << componentName; + m_currentComponentReport = &m_componentReports[component.str().c_str()]; + } + + m_currentComponentReport->ReportDirtyBits(byteSize); + m_gdeDirtyBytes.AggregateBytes(byteSize); + } + + void EntityReporter::ReportFragmentEnd() + { + if (m_currentComponentReport) + { + m_currentComponentReport->ReportFragmentEnd(); + m_currentComponentReport = nullptr; + } + + m_gdeDirtyBytes.ReportAggregateBytes(); + MultiplayerDebugByteReporter::ReportAggregateBytes(); + } + + void EntityReporter::Combine(const EntityReporter& other) + { + MultiplayerDebugByteReporter::Combine(other); + + for (const auto& componentIter : other.m_componentReports) + { + m_componentReports[componentIter.first].Combine(componentIter.second); + } + + m_gdeDirtyBytes.Combine(other.m_gdeDirtyBytes); + } + + void EntityReporter::Reset() + { + MultiplayerDebugByteReporter::Reset(); + + m_componentReports.clear(); + m_gdeDirtyBytes.Reset(); + } + + AZStd::map& EntityReporter::GetComponentReports() + { + return m_componentReports; + } +} diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.h new file mode 100644 index 0000000000..7e6a04569d --- /dev/null +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.h @@ -0,0 +1,96 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#pragma once + +#include +#include +#include +#include + +namespace MultiplayerDiagnostics +{ + class MultiplayerDebugByteReporter + { + public: + MultiplayerDebugByteReporter() { MultiplayerDebugByteReporter::Reset(); } + virtual ~MultiplayerDebugByteReporter() = default; + + void ReportBytes(size_t byteSize); + void AggregateBytes(size_t byteSize); + void ReportAggregateBytes(); + + float GetAverageBytes() const; + size_t GetMaxBytes() const; + size_t GetMinBytes() const; + size_t GetTotalBytes() const; + float GetKbitsPerSecond(); + + void Combine(const MultiplayerDebugByteReporter& other); + virtual void Reset(); + + size_t GetTotalCount() const { return m_count; } + + private: + size_t m_count; + size_t m_totalBytes; + size_t m_totalBytesThisSecond; + float m_totalBytesLastSecond; + size_t m_minBytes; + size_t m_maxBytes; + size_t m_aggregateBytes; + + AZStd::chrono::monotonic_clock::time_point m_lastUpdateTime; + }; + + class ComponentReporter : public MultiplayerDebugByteReporter + { + public: + ComponentReporter() = default; + + void ReportField(const char* fieldName, size_t byteSize); + void ReportDirtyBits(size_t byteSize) { m_componentDirtyBytes.AggregateBytes(byteSize); } + void ReportFragmentEnd(); + + using Report = AZStd::pair; + AZStd::vector GetFieldReports(); + AZStd::size_t GetTotalDirtyBits() const { return m_componentDirtyBytes.GetTotalBytes(); } + float GetAvgDirtyBits() const { return m_componentDirtyBytes.GetAverageBytes(); } + + void Combine(const ComponentReporter& other); + + private: + AZStd::map m_fieldReports; + MultiplayerDebugByteReporter m_componentDirtyBytes; + }; + + class EntityReporter : public MultiplayerDebugByteReporter + { + public: + EntityReporter() = default; + + void ReportField(AZ::u32 index, const char* componentName, const char* fieldName, size_t byteSize); + void ReportDirtyBits(AZ::u32 index, const char* componentName, size_t byteSize); + void ReportFragmentEnd(); + + void Combine(const EntityReporter& other); + void Reset() override; + + 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; + MultiplayerDebugByteReporter m_gdeDirtyBytes; + }; +} diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp new file mode 100644 index 0000000000..e60b800372 --- /dev/null +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp @@ -0,0 +1,385 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#include "MultiplayerDebugPerEntityReporter.h" +#include +#include +#include + +#if defined(IMGUI_ENABLED) +#include +#endif + +namespace MultiplayerDiagnostics +{ +#if defined(IMGUI_ENABLED) + static const ImVec4 k_ImGuiTomato = ImVec4(1.0f, 0.4f, 0.3f, 1.0f); + static const ImVec4 k_ImGuiKhaki = ImVec4(0.9f, 0.8f, 0.5f, 1.0f); + static const ImVec4 k_ImGuiCyan = ImVec4(0.5f, 1.0f, 1.0f, 1.0f); + static const ImVec4 k_ImGuiDusk = ImVec4(0.7f, 0.7f, 1.0f, 1.0f); + static const ImVec4 k_ImGuiWhite = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); + + // -------------------------------------------------------------------------------------------- + template + bool ReplicatedStateTreeNode(const AZStd::string& name, Reporter& report, const ImVec4& color, int depth = 0) + { + const int defaultPadAmount = 55; + const int depthReduction = 3; + ImGui::PushStyleColor(ImGuiCol_Text, color); + + const bool expanded = ImGui::TreeNode(name.c_str(), + "%-*s %7.2f kbps %7.2f B Avg. %4zu B Max %10zu B Payload", + defaultPadAmount - depthReduction * depth, + name.c_str(), + report.GetKbitsPerSecond(), + report.GetAverageBytes(), + report.GetMaxBytes(), + report.GetTotalBytes()); + ImGui::PopStyleColor(); + return expanded; + } + + // -------------------------------------------------------------------------------------------- + void DisplayReplicatedStateReport(AZStd::map& componentReports, float kbpsWarn, float maxWarn) + { + for (auto& componentPair : componentReports) + { + ImGui::Separator(); + ComponentReporter& componentReport = componentPair.second; + + if (ReplicatedStateTreeNode(componentPair.first, componentReport, k_ImGuiCyan, 1)) + { + ImGui::Separator(); + ImGui::Columns(6, "replicated_field_columns"); + ImGui::NextColumn(); + ImGui::Text("kbps"); + ImGui::NextColumn(); + ImGui::Text("Avg. Bytes"); + ImGui::NextColumn(); + ImGui::Text("Min Bytes"); + ImGui::NextColumn(); + ImGui::Text("Max Bytes"); + ImGui::NextColumn(); + ImGui::Text("Total Bytes"); + ImGui::NextColumn(); + + auto fieldReports = componentReport.GetFieldReports(); + for (auto& fieldPair : fieldReports) + { + MultiplayerDebugByteReporter& fieldReport = *fieldPair.second; + const float kbitsLastSecond = fieldReport.GetKbitsPerSecond(); + + const ImVec4* textColor = &k_ImGuiWhite; + if (fieldReport.GetMaxBytes() > maxWarn) + { + textColor = &k_ImGuiKhaki; + } + + if (kbitsLastSecond > kbpsWarn) + { + textColor = &k_ImGuiTomato; + } + + ImGui::PushStyleColor(ImGuiCol_Text, *textColor); + + ImGui::Text("%s", fieldPair.first.c_str()); + ImGui::NextColumn(); + ImGui::Text("%.2f", kbitsLastSecond); + ImGui::NextColumn(); + ImGui::Text("%.2f", fieldReport.GetAverageBytes()); + ImGui::NextColumn(); + ImGui::Text("%zu", fieldReport.GetMinBytes()); + ImGui::NextColumn(); + ImGui::Text("%zu", fieldReport.GetMaxBytes()); + ImGui::NextColumn(); + ImGui::Text("%zu", fieldReport.GetTotalBytes()); + ImGui::NextColumn(); + + ImGui::PopStyleColor(); + } + + ImGui::Columns(1); + ImGui::TreePop(); + } + } + } +#endif + + MultiplayerDebugPerEntityReporter::MultiplayerDebugPerEntityReporter () + { + GridMate::Debug::CarrierDrillerBus::Handler::BusConnect(); + } + + // -------------------------------------------------------------------------------------------- + MultiplayerDebugPerEntityReporter::~MultiplayerDebugPerEntityReporter() + { + GridMate::Debug::ReplicaDrillerBus::Handler::BusDisconnect(); + GridMate::Debug::CarrierDrillerBus::Handler::BusDisconnect(); + } + + void MultiplayerDebugPerEntityReporter::OnReceiveReplicaBegin(GridMate::Replica*, const void*, size_t) + { + m_currentReceivingEntityReport.Reset(); + } + + void MultiplayerDebugPerEntityReporter::OnReceiveReplicaEnd(GridMate::Replica* replica) + { + m_receivingEntityReports[replica->GetDebugName()].Combine(m_currentReceivingEntityReport); + } + + void MultiplayerDebugPerEntityReporter::OnReceiveReplicaChunkEnd(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex) + { + AZ_UNUSED(chunk); + AZ_UNUSED(chunkIndex); + m_currentReceivingEntityReport.ReportFragmentEnd(); + } + + void MultiplayerDebugPerEntityReporter::OnReceiveDataSet(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex, + GridMate::DataSetBase* dataSet, GridMate::PeerId, GridMate::PeerId, const void*, size_t len) + { + m_currentReceivingEntityReport.ReportField(chunkIndex, chunk->GetDescriptor()->GetChunkName(), chunk->GetDescriptor()->GetDataSetName(chunk, dataSet), len); + } + + void MultiplayerDebugPerEntityReporter::OnReceiveRpc (GridMate::ReplicaChunkBase* chunk, + AZ::u32 chunkIndex, + GridMate::Internal::RpcRequest* rpc, + GridMate::PeerId from, + GridMate::PeerId to, + const void* data, + size_t len) + { + AZ_UNUSED( from ); + AZ_UNUSED( to ); + AZ_UNUSED( data ); + + m_currentReceivingEntityReport.ReportField(chunkIndex, chunk->GetDescriptor()->GetChunkName(), chunk->GetDescriptor()->GetRpcName(chunk, rpc->m_rpc), len); + } + + void MultiplayerDebugPerEntityReporter::OnSendReplicaBegin (GridMate::Replica*) + { + m_currentSendingEntityReport.Reset(); + } + + void MultiplayerDebugPerEntityReporter::OnSendReplicaEnd (GridMate::Replica* replica, const void*, size_t) + { + m_sendingEntityReports[replica->GetDebugName()].Combine(m_currentSendingEntityReport); + } + + void MultiplayerDebugPerEntityReporter::OnSendReplicaChunkEnd (GridMate::ReplicaChunkBase* chunk, + AZ::u32 chunkIndex, + const void*, + size_t) + { + AZ_UNUSED(chunk); + AZ_UNUSED(chunkIndex); + m_currentSendingEntityReport.ReportFragmentEnd(); + } + + void MultiplayerDebugPerEntityReporter::OnSendDataSet (GridMate::ReplicaChunkBase* chunk, + AZ::u32 chunkIndex, + GridMate::DataSetBase* dataSet, + GridMate::PeerId, + GridMate::PeerId, + const void*, + size_t len) + { + m_currentSendingEntityReport.ReportField(chunkIndex, chunk->GetDescriptor()->GetChunkName(), chunk->GetDescriptor()->GetDataSetName(chunk, dataSet), len); + } + + void MultiplayerDebugPerEntityReporter::OnSendRpc (GridMate::ReplicaChunkBase* chunk, + AZ::u32 chunkIndex, + GridMate::Internal::RpcRequest* rpc, + GridMate::PeerId, + GridMate::PeerId, + const void*, + size_t len) + { + m_currentSendingEntityReport.ReportField(chunkIndex, chunk->GetDescriptor()->GetChunkName(), chunk->GetDescriptor()->GetRpcName(chunk, rpc->m_rpc), len); + } + + void MultiplayerDebugPerEntityReporter::OnIncomingConnection (GridMate::Carrier*, GridMate::ConnectionID) + { + } + + void MultiplayerDebugPerEntityReporter::OnFailedToConnect (GridMate::Carrier*, + GridMate::ConnectionID, + GridMate::CarrierDisconnectReason) + { + m_lastSecondStats.clear(); + } + + void MultiplayerDebugPerEntityReporter::OnConnectionEstablished (GridMate::Carrier*, GridMate::ConnectionID) + { + } + + void MultiplayerDebugPerEntityReporter::OnDisconnect (GridMate::Carrier*, + GridMate::ConnectionID, + GridMate::CarrierDisconnectReason) + { + /* + * CarrierDrillerBus doesn't provide enough information to correctly keep track of network traffic for all peers. + * This is a work around until that is fixed to at least not over report the bandwidth amount. + */ + m_lastSecondStats.clear(); + } + + void MultiplayerDebugPerEntityReporter::OnDriverError (GridMate::Carrier*, + GridMate::ConnectionID, + const GridMate::DriverError&) + { + m_lastSecondStats.clear(); + } + + void MultiplayerDebugPerEntityReporter::OnSecurityError (GridMate::Carrier*, + GridMate::ConnectionID, + const GridMate::SecurityError&) + { + m_lastSecondStats.clear(); + } + + void MultiplayerDebugPerEntityReporter::OnUpdateStatistics (const GridMate::string& address, + const GridMate::TrafficControl::Statistics&, + const GridMate::TrafficControl::Statistics&, + const GridMate::TrafficControl::Statistics& effectiveLastSecond, + const GridMate::TrafficControl::Statistics&) + { + m_lastSecondStats[address] = effectiveLastSecond; + } + + void MultiplayerDebugPerEntityReporter::OnConnectionStateChanged (GridMate::Carrier*, + GridMate::ConnectionID, + GridMate::Carrier::ConnectionStates) + { + m_lastSecondStats.clear(); + } + + void MultiplayerDebugPerEntityReporter::UpdateTrafficStatistics() + { +#if defined(IMGUI_ENABLED) + AZ::u32 dataReceived = 0, dataSent = 0; + + for (auto& perConnection : m_lastSecondStats) + { + dataReceived += perConnection.second.m_dataReceived; + dataSent += perConnection.second.m_dataSend; + } + + if (dataReceived !=0 || dataSent != 0) + { + ImGui::Text("Total bandwidth: Sent %u kbps Received %u kbps.", dataSent * 8 / 1000, dataReceived * 8 / 1000); + } + else + { + ImGui::Text("Total bandwidth: Sent -- kbps Received -- kbps."); + } +#endif + } + + // -------------------------------------------------------------------------------------------- + void MultiplayerDebugPerEntityReporter::OnImGuiUpdate() + { +#if defined(IMGUI_ENABLED) + if (ImGui::BeginMainMenuBar()) + { + if (ImGui::BeginMenu("GridMate")) + { + if (m_showServerReportWindow) + { + if (ImGui::MenuItem("Hide Multiplayer Analytics Window")) + { + m_showServerReportWindow = false; + } + } + else if (ImGui::MenuItem("Show Multiplayer Analytics Window")) + { + m_showServerReportWindow = true; + } + + ImGui::End(); + } + + ImGui::EndMainMenuBar(); + } + + if (m_showServerReportWindow) + { + if (ImGui::Begin("Multiplayer Analytics", &m_showServerReportWindow)) + { + // General carrier stats + UpdateTrafficStatistics(); + + if (ImGui::Checkbox("Analyze network traffic", &m_isTrackingMessages)) + { + if (m_isTrackingMessages) + { + GridMate::Debug::ReplicaDrillerBus::Handler::BusConnect(); + } + else + { + GridMate::Debug::ReplicaDrillerBus::Handler::BusDisconnect(); + + m_currentReceivingEntityReport.Reset(); + m_receivingEntityReports.clear(); + + m_currentSendingEntityReport.Reset(); + m_sendingEntityReports.clear(); + } + } + + if (m_isTrackingMessages) + { + ImGui::Separator(); + + static ImGuiTextFilter filter; + filter.Draw(); + + if (ImGui::CollapsingHeader("Received replicas per type")) + { + for (auto& entityPair : m_receivingEntityReports) + { + if (!filter.PassFilter(entityPair.first.c_str())) + { + continue; + } + + ImGui::Separator(); + if (ReplicatedStateTreeNode(entityPair.first, entityPair.second, k_ImGuiDusk)) + { + DisplayReplicatedStateReport(entityPair.second.GetComponentReports(), m_replicatedStateKbpsWarn, m_replicatedStateMaxSizeWarn); + ImGui::TreePop(); + } + } + } + + if (ImGui::CollapsingHeader("Sent replicas per type")) + { + for (auto& entityPair : m_sendingEntityReports) + { + if (!filter.PassFilter(entityPair.first.c_str())) + { + continue; + } + + ImGui::Separator(); + if (ReplicatedStateTreeNode(entityPair.first, entityPair.second, k_ImGuiDusk)) + { + DisplayReplicatedStateReport(entityPair.second.GetComponentReports(), m_replicatedStateKbpsWarn, m_replicatedStateMaxSizeWarn); + ImGui::TreePop(); + } + } + } + } + } + ImGui::End(); + } +#endif + } +} diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h new file mode 100644 index 0000000000..96cfadb14d --- /dev/null +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h @@ -0,0 +1,90 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#pragma once +#include +#include "MultiplayerDebugByteReporter.h" +#include + +namespace MultiplayerDiagnostics +{ + /** + * \brief GridMate network live analysis tool via ImGui. + */ + class MultiplayerDebugPerEntityReporter + : public GridMate::Debug::ReplicaDrillerBus::Handler + , public GridMate::Debug::CarrierDrillerBus::Handler + { + public: + MultiplayerDebugPerEntityReporter(); + virtual ~MultiplayerDebugPerEntityReporter(); + + // main update loop + void OnImGuiUpdate(); + + // ReplicaDrillerBus - receive + + void OnReceiveReplicaBegin(GridMate::Replica* replica, const void* data, size_t len) override; + void OnReceiveReplicaEnd(GridMate::Replica* replica) override; + void OnReceiveReplicaChunkEnd(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex) override; + void OnReceiveDataSet(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex, GridMate::DataSetBase* dataSet, GridMate::PeerId from, GridMate::PeerId to, const void* data, size_t len) override; + void OnReceiveRpc(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex, GridMate::Internal::RpcRequest* rpc, GridMate::PeerId from, GridMate::PeerId to, const void* data, size_t len) override; + + // ReplicaDrillerBus - sending + + void OnSendReplicaBegin(GridMate::Replica* replica) override; + void OnSendReplicaEnd(GridMate::Replica* replica, const void* data, size_t len) override; + void OnSendReplicaChunkEnd(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex, const void* data, size_t len) override; + void OnSendDataSet(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex, GridMate::DataSetBase* dataSet, GridMate::PeerId from, GridMate::PeerId to, const void* data, size_t len) override; + void OnSendRpc(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex, GridMate::Internal::RpcRequest* rpc, GridMate::PeerId from, GridMate::PeerId to, const void* data, size_t len) override; + + // CarrierDrillerBus + void OnIncomingConnection (GridMate::Carrier* carrier, GridMate::ConnectionID id) override; + void OnFailedToConnect (GridMate::Carrier* carrier, + GridMate::ConnectionID id, + GridMate::CarrierDisconnectReason reason) override; + void OnConnectionEstablished (GridMate::Carrier* carrier, GridMate::ConnectionID id) override; + void OnDisconnect (GridMate::Carrier* carrier, + GridMate::ConnectionID id, + GridMate::CarrierDisconnectReason reason) override; + void OnDriverError (GridMate::Carrier* carrier, + GridMate::ConnectionID id, + const GridMate::DriverError& error) override; + void OnSecurityError (GridMate::Carrier* carrier, + GridMate::ConnectionID id, + const GridMate::SecurityError& error) override; + void OnUpdateStatistics (const GridMate::string& address, + const GridMate::TrafficControl::Statistics& lastSecond, + const GridMate::TrafficControl::Statistics& lifeTime, + const GridMate::TrafficControl::Statistics& effectiveLastSecond, + const GridMate::TrafficControl::Statistics& effectiveLifeTime) override; + void OnConnectionStateChanged (GridMate::Carrier* carrier, + GridMate::ConnectionID id, + GridMate::Carrier::ConnectionStates newState) override; + + private: + + bool m_showServerReportWindow = false; + bool m_isTrackingMessages = false; + + AZStd::map m_sendingEntityReports{}; + EntityReporter m_currentSendingEntityReport; + + AZStd::map m_receivingEntityReports{}; + EntityReporter m_currentReceivingEntityReport; + + float m_replicatedStateKbpsWarn = 10.f; + float m_replicatedStateMaxSizeWarn = 30.f; + + void UpdateTrafficStatistics(); + AZStd::map m_lastSecondStats; + }; +} diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp index 1611a3213d..b97fa053b2 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp @@ -53,6 +53,11 @@ namespace Multiplayer #endif } + void MultiplayerDebugSystemComponent::OnImGuiInitialize() + { + m_reporter = AZStd::make_unique(); + } + #ifdef IMGUI_ENABLED void MultiplayerDebugSystemComponent::OnImGuiMainMenuUpdate() { @@ -318,6 +323,12 @@ namespace Multiplayer ImGui::End(); } } + + + if (m_reporter) + { + m_reporter->OnImGuiUpdate(); + } } #endif } diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h index 77daaf9b7d..3dbbd06d6f 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h @@ -9,6 +9,7 @@ #pragma once #include +#include #ifdef IMGUI_ENABLED # include @@ -42,6 +43,7 @@ namespace Multiplayer #ifdef IMGUI_ENABLED //! ImGui::ImGuiUpdateListenerBus overrides //! @{ + void OnImGuiInitialize() override; void OnImGuiMainMenuUpdate() override; void OnImGuiUpdate() override; //! @} @@ -49,5 +51,7 @@ namespace Multiplayer private: bool m_displayNetworkingStats = false; bool m_displayMultiplayerStats = false; + + AZStd::unique_ptr m_reporter; }; } diff --git a/Gems/Multiplayer/Code/multiplayer_debug_files.cmake b/Gems/Multiplayer/Code/multiplayer_debug_files.cmake index 62bd632e7e..37a1c91640 100644 --- a/Gems/Multiplayer/Code/multiplayer_debug_files.cmake +++ b/Gems/Multiplayer/Code/multiplayer_debug_files.cmake @@ -7,6 +7,10 @@ # set(FILES + Source/Debug/MultiplayerDebugByteReporter.cpp + Source/Debug/MultiplayerDebugByteReporter.h + Source/Debug/MultiplayerDebugPerEntityReporter.cpp + Source/Debug/MultiplayerDebugPerEntityReporter.h Source/Debug/MultiplayerDebugModule.cpp Source/Debug/MultiplayerDebugModule.h Source/Debug/MultiplayerDebugSystemComponent.cpp From f29fd86a395812f07c28998758365e9e97b68d7f Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Mon, 26 Jul 2021 19:11:28 -0400 Subject: [PATCH 02/13] More converstion in progress Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- .../Components/MultiplayerComponent.h | 21 +- .../Include/Multiplayer/MultiplayerStats.h | 2 + .../Source/Components/NetBindComponent.cpp | 4 + .../Debug/MultiplayerDebugByteReporter.cpp | 17 +- .../MultiplayerDebugPerEntityInterface.h | 26 ++ .../MultiplayerDebugPerEntityReporter.cpp | 292 ++++++++++-------- .../Debug/MultiplayerDebugPerEntityReporter.h | 93 +++--- .../Code/Source/MultiplayerStats.cpp | 27 ++ .../Code/multiplayer_debug_files.cmake | 1 + 9 files changed, 288 insertions(+), 195 deletions(-) create mode 100644 Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityInterface.h diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/Components/MultiplayerComponent.h b/Gems/Multiplayer/Code/Include/Multiplayer/Components/MultiplayerComponent.h index 8526b6c70b..48590e5393 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/Components/MultiplayerComponent.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Components/MultiplayerComponent.h @@ -105,14 +105,15 @@ namespace Multiplayer template inline void SerializeNetworkPropertyHelper ( - AzNetworking::ISerializer& serializer, - bool modifyRecord, - AzNetworking::FixedSizeBitsetView& bitset, - int32_t bitIndex, - TYPE& value, - const char* name, - NetComponentId componentId, - PropertyIndex propertyIndex, + AzNetworking::ISerializer& serializer, + bool modifyRecord, + AzNetworking::FixedSizeBitsetView& bitset, + int32_t bitIndex, + TYPE& value, + const char* name, + AZ::EntityId entityId, + NetComponentId componentId, + PropertyIndex propertyIndex, MultiplayerStats& stats ) { @@ -133,11 +134,11 @@ namespace Multiplayer { if (modifyRecord) { - stats.RecordPropertyReceived(componentId, propertyIndex, updateSize); + stats.RecordPropertyReceived(entityId, componentId, propertyIndex, updateSize); } else { - stats.RecordPropertySent(componentId, propertyIndex, updateSize); + stats.RecordPropertySent(entityId, componentId, propertyIndex, updateSize); } } } diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerStats.h b/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerStats.h index d279355d7c..133cbb7aeb 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerStats.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerStats.h @@ -50,6 +50,8 @@ namespace Multiplayer AZStd::vector m_componentStats; void ReserveComponentStats(NetComponentId netComponentId, uint16_t propertyCount, uint16_t rpcCount); + void RecordEntitySerializeStart(AZ::EntityId entityId, const char* entityName); + void RecordEntitySerializeStop(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); diff --git a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp index e8da34fc7f..74091908e2 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp @@ -447,12 +447,16 @@ namespace Multiplayer bool NetBindComponent::SerializeStateDeltaMessage(ReplicationRecord& replicationRecord, AzNetworking::ISerializer& serializer) { + GetMultiplayer()->GetStats().RecordEntitySerializeStart(GetEntityId(), GetEntity()->GetName().c_str()); + bool success = true; for (auto iter = m_multiplayerSerializationComponentVector.begin(); iter != m_multiplayerSerializationComponentVector.end(); ++iter) { success &= (*iter)->SerializeStateDeltaMessage(replicationRecord, serializer); } + GetMultiplayer()->GetStats().RecordEntitySerializeStop(GetEntityId(), GetEntity()->GetName().c_str()); + return success; } diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp index 382bc70d9b..fd31298ad8 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp @@ -1,14 +1,11 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * 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 "MultiplayerDebugByteReporter.h" #include diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityInterface.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityInterface.h new file mode 100644 index 0000000000..8cd94944b2 --- /dev/null +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityInterface.h @@ -0,0 +1,26 @@ +/* + * 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 MultilayerIPerEntityStats + { + public: + virtual ~MultilayerIPerEntityStats(); + + virtual void RecordEntitySerializeStart(AZ::EntityId entityId, const char* entityName) = 0; + virtual void RecordEntitySerializeStop(AZ::EntityId entityId, const char* entityName) = 0; + virtual void RecordPropertySent(Multiplayer::NetComponentId netComponentId, Multiplayer::PropertyIndex propertyId, uint32_t totalBytes); + virtual void RecordPropertyReceived(Multiplayer::NetComponentId netComponentId, Multiplayer::PropertyIndex propertyId, uint32_t totalBytes); + }; +} diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp index e60b800372..32ed7d5a59 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp @@ -1,18 +1,16 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * 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 "MultiplayerDebugPerEntityReporter.h" #include #include #include +#include #if defined(IMGUI_ENABLED) #include @@ -115,151 +113,151 @@ namespace MultiplayerDiagnostics MultiplayerDebugPerEntityReporter::MultiplayerDebugPerEntityReporter () { - GridMate::Debug::CarrierDrillerBus::Handler::BusConnect(); + //GridMate::Debug::CarrierDrillerBus::Handler::BusConnect(); } // -------------------------------------------------------------------------------------------- MultiplayerDebugPerEntityReporter::~MultiplayerDebugPerEntityReporter() { - GridMate::Debug::ReplicaDrillerBus::Handler::BusDisconnect(); - GridMate::Debug::CarrierDrillerBus::Handler::BusDisconnect(); + /*GridMate::Debug::ReplicaDrillerBus::Handler::BusDisconnect(); + GridMate::Debug::CarrierDrillerBus::Handler::BusDisconnect();*/ } - void MultiplayerDebugPerEntityReporter::OnReceiveReplicaBegin(GridMate::Replica*, const void*, size_t) - { - m_currentReceivingEntityReport.Reset(); - } + //void MultiplayerDebugPerEntityReporter::OnReceiveReplicaBegin(GridMate::Replica*, const void*, size_t) + //{ + // m_currentReceivingEntityReport.Reset(); + //} - void MultiplayerDebugPerEntityReporter::OnReceiveReplicaEnd(GridMate::Replica* replica) - { - m_receivingEntityReports[replica->GetDebugName()].Combine(m_currentReceivingEntityReport); - } + //void MultiplayerDebugPerEntityReporter::OnReceiveReplicaEnd(GridMate::Replica* replica) + //{ + // m_receivingEntityReports[replica->GetDebugName()].Combine(m_currentReceivingEntityReport); + //} - void MultiplayerDebugPerEntityReporter::OnReceiveReplicaChunkEnd(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex) - { - AZ_UNUSED(chunk); - AZ_UNUSED(chunkIndex); - m_currentReceivingEntityReport.ReportFragmentEnd(); - } + //void MultiplayerDebugPerEntityReporter::OnReceiveReplicaChunkEnd(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex) + //{ + // AZ_UNUSED(chunk); + // AZ_UNUSED(chunkIndex); + // m_currentReceivingEntityReport.ReportFragmentEnd(); + //} - void MultiplayerDebugPerEntityReporter::OnReceiveDataSet(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex, - GridMate::DataSetBase* dataSet, GridMate::PeerId, GridMate::PeerId, const void*, size_t len) - { - m_currentReceivingEntityReport.ReportField(chunkIndex, chunk->GetDescriptor()->GetChunkName(), chunk->GetDescriptor()->GetDataSetName(chunk, dataSet), len); - } + //void MultiplayerDebugPerEntityReporter::OnReceiveDataSet(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex, + // GridMate::DataSetBase* dataSet, GridMate::PeerId, GridMate::PeerId, const void*, size_t len) + //{ + // m_currentReceivingEntityReport.ReportField(chunkIndex, chunk->GetDescriptor()->GetChunkName(), chunk->GetDescriptor()->GetDataSetName(chunk, dataSet), len); + //} - void MultiplayerDebugPerEntityReporter::OnReceiveRpc (GridMate::ReplicaChunkBase* chunk, - AZ::u32 chunkIndex, - GridMate::Internal::RpcRequest* rpc, - GridMate::PeerId from, - GridMate::PeerId to, - const void* data, - size_t len) - { - AZ_UNUSED( from ); - AZ_UNUSED( to ); - AZ_UNUSED( data ); + //void MultiplayerDebugPerEntityReporter::OnReceiveRpc (GridMate::ReplicaChunkBase* chunk, + // AZ::u32 chunkIndex, + // GridMate::Internal::RpcRequest* rpc, + // GridMate::PeerId from, + // GridMate::PeerId to, + // const void* data, + // size_t len) + //{ + // AZ_UNUSED( from ); + // AZ_UNUSED( to ); + // AZ_UNUSED( data ); - m_currentReceivingEntityReport.ReportField(chunkIndex, chunk->GetDescriptor()->GetChunkName(), chunk->GetDescriptor()->GetRpcName(chunk, rpc->m_rpc), len); - } + // m_currentReceivingEntityReport.ReportField(chunkIndex, chunk->GetDescriptor()->GetChunkName(), chunk->GetDescriptor()->GetRpcName(chunk, rpc->m_rpc), len); + //} - void MultiplayerDebugPerEntityReporter::OnSendReplicaBegin (GridMate::Replica*) - { - m_currentSendingEntityReport.Reset(); - } + //void MultiplayerDebugPerEntityReporter::OnSendReplicaBegin (GridMate::Replica*) + //{ + // m_currentSendingEntityReport.Reset(); + //} - void MultiplayerDebugPerEntityReporter::OnSendReplicaEnd (GridMate::Replica* replica, const void*, size_t) - { - m_sendingEntityReports[replica->GetDebugName()].Combine(m_currentSendingEntityReport); - } + //void MultiplayerDebugPerEntityReporter::OnSendReplicaEnd (GridMate::Replica* replica, const void*, size_t) + //{ + // m_sendingEntityReports[replica->GetDebugName()].Combine(m_currentSendingEntityReport); + //} - void MultiplayerDebugPerEntityReporter::OnSendReplicaChunkEnd (GridMate::ReplicaChunkBase* chunk, - AZ::u32 chunkIndex, - const void*, - size_t) - { - AZ_UNUSED(chunk); - AZ_UNUSED(chunkIndex); - m_currentSendingEntityReport.ReportFragmentEnd(); - } + //void MultiplayerDebugPerEntityReporter::OnSendReplicaChunkEnd (GridMate::ReplicaChunkBase* chunk, + // AZ::u32 chunkIndex, + // const void*, + // size_t) + //{ + // AZ_UNUSED(chunk); + // AZ_UNUSED(chunkIndex); + // m_currentSendingEntityReport.ReportFragmentEnd(); + //} - void MultiplayerDebugPerEntityReporter::OnSendDataSet (GridMate::ReplicaChunkBase* chunk, - AZ::u32 chunkIndex, - GridMate::DataSetBase* dataSet, - GridMate::PeerId, - GridMate::PeerId, - const void*, - size_t len) - { - m_currentSendingEntityReport.ReportField(chunkIndex, chunk->GetDescriptor()->GetChunkName(), chunk->GetDescriptor()->GetDataSetName(chunk, dataSet), len); - } + //void MultiplayerDebugPerEntityReporter::OnSendDataSet (GridMate::ReplicaChunkBase* chunk, + // AZ::u32 chunkIndex, + // GridMate::DataSetBase* dataSet, + // GridMate::PeerId, + // GridMate::PeerId, + // const void*, + // size_t len) + //{ + // m_currentSendingEntityReport.ReportField(chunkIndex, chunk->GetDescriptor()->GetChunkName(), chunk->GetDescriptor()->GetDataSetName(chunk, dataSet), len); + //} - void MultiplayerDebugPerEntityReporter::OnSendRpc (GridMate::ReplicaChunkBase* chunk, - AZ::u32 chunkIndex, - GridMate::Internal::RpcRequest* rpc, - GridMate::PeerId, - GridMate::PeerId, - const void*, - size_t len) - { - m_currentSendingEntityReport.ReportField(chunkIndex, chunk->GetDescriptor()->GetChunkName(), chunk->GetDescriptor()->GetRpcName(chunk, rpc->m_rpc), len); - } + //void MultiplayerDebugPerEntityReporter::OnSendRpc (GridMate::ReplicaChunkBase* chunk, + // AZ::u32 chunkIndex, + // GridMate::Internal::RpcRequest* rpc, + // GridMate::PeerId, + // GridMate::PeerId, + // const void*, + // size_t len) + //{ + // m_currentSendingEntityReport.ReportField(chunkIndex, chunk->GetDescriptor()->GetChunkName(), chunk->GetDescriptor()->GetRpcName(chunk, rpc->m_rpc), len); + //} - void MultiplayerDebugPerEntityReporter::OnIncomingConnection (GridMate::Carrier*, GridMate::ConnectionID) - { - } + //void MultiplayerDebugPerEntityReporter::OnIncomingConnection (GridMate::Carrier*, GridMate::ConnectionID) + //{ + //} - void MultiplayerDebugPerEntityReporter::OnFailedToConnect (GridMate::Carrier*, - GridMate::ConnectionID, - GridMate::CarrierDisconnectReason) - { - m_lastSecondStats.clear(); - } + //void MultiplayerDebugPerEntityReporter::OnFailedToConnect (GridMate::Carrier*, + // GridMate::ConnectionID, + // GridMate::CarrierDisconnectReason) + //{ + // m_lastSecondStats.clear(); + //} - void MultiplayerDebugPerEntityReporter::OnConnectionEstablished (GridMate::Carrier*, GridMate::ConnectionID) - { - } + //void MultiplayerDebugPerEntityReporter::OnConnectionEstablished (GridMate::Carrier*, GridMate::ConnectionID) + //{ + //} - void MultiplayerDebugPerEntityReporter::OnDisconnect (GridMate::Carrier*, - GridMate::ConnectionID, - GridMate::CarrierDisconnectReason) - { - /* - * CarrierDrillerBus doesn't provide enough information to correctly keep track of network traffic for all peers. - * This is a work around until that is fixed to at least not over report the bandwidth amount. - */ - m_lastSecondStats.clear(); - } + //void MultiplayerDebugPerEntityReporter::OnDisconnect (GridMate::Carrier*, + // GridMate::ConnectionID, + // GridMate::CarrierDisconnectReason) + //{ + // /* + // * CarrierDrillerBus doesn't provide enough information to correctly keep track of network traffic for all peers. + // * This is a work around until that is fixed to at least not over report the bandwidth amount. + // */ + // m_lastSecondStats.clear(); + //} - void MultiplayerDebugPerEntityReporter::OnDriverError (GridMate::Carrier*, - GridMate::ConnectionID, - const GridMate::DriverError&) - { - m_lastSecondStats.clear(); - } + //void MultiplayerDebugPerEntityReporter::OnDriverError (GridMate::Carrier*, + // GridMate::ConnectionID, + // const GridMate::DriverError&) + //{ + // m_lastSecondStats.clear(); + //} - void MultiplayerDebugPerEntityReporter::OnSecurityError (GridMate::Carrier*, - GridMate::ConnectionID, - const GridMate::SecurityError&) - { - m_lastSecondStats.clear(); - } + //void MultiplayerDebugPerEntityReporter::OnSecurityError (GridMate::Carrier*, + // GridMate::ConnectionID, + // const GridMate::SecurityError&) + //{ + // m_lastSecondStats.clear(); + //} - void MultiplayerDebugPerEntityReporter::OnUpdateStatistics (const GridMate::string& address, - const GridMate::TrafficControl::Statistics&, - const GridMate::TrafficControl::Statistics&, - const GridMate::TrafficControl::Statistics& effectiveLastSecond, - const GridMate::TrafficControl::Statistics&) - { - m_lastSecondStats[address] = effectiveLastSecond; - } + //void MultiplayerDebugPerEntityReporter::OnUpdateStatistics (const GridMate::string& address, + // const GridMate::TrafficControl::Statistics&, + // const GridMate::TrafficControl::Statistics&, + // const GridMate::TrafficControl::Statistics& effectiveLastSecond, + // const GridMate::TrafficControl::Statistics&) + //{ + // m_lastSecondStats[address] = effectiveLastSecond; + //} - void MultiplayerDebugPerEntityReporter::OnConnectionStateChanged (GridMate::Carrier*, - GridMate::ConnectionID, - GridMate::Carrier::ConnectionStates) - { - m_lastSecondStats.clear(); - } + //void MultiplayerDebugPerEntityReporter::OnConnectionStateChanged (GridMate::Carrier*, + // GridMate::ConnectionID, + // GridMate::Carrier::ConnectionStates) + //{ + // m_lastSecondStats.clear(); + //} void MultiplayerDebugPerEntityReporter::UpdateTrafficStatistics() { @@ -320,11 +318,11 @@ namespace MultiplayerDiagnostics { if (m_isTrackingMessages) { - GridMate::Debug::ReplicaDrillerBus::Handler::BusConnect(); + //GridMate::Debug::ReplicaDrillerBus::Handler::BusConnect(); } else { - GridMate::Debug::ReplicaDrillerBus::Handler::BusDisconnect(); + //GridMate::Debug::ReplicaDrillerBus::Handler::BusDisconnect(); m_currentReceivingEntityReport.Reset(); m_receivingEntityReports.clear(); @@ -382,4 +380,34 @@ namespace MultiplayerDiagnostics } #endif } + + void MultiplayerDebugPerEntityReporter::RecordEntitySerializeStart(AZ::EntityId entityId, const char* entityName) + { + } + + void MultiplayerDebugPerEntityReporter::RecordEntitySerializeStop(AZ::EntityId entityId, const char* entityName) + { + } + + void MultiplayerDebugPerEntityReporter::RecordPropertySent( + AZ::EntityId entityId, + Multiplayer::NetComponentId netComponentId, + Multiplayer::PropertyIndex propertyId, + uint32_t totalBytes) + { + // TODO + } + + void MultiplayerDebugPerEntityReporter::RecordPropertyReceived( + Multiplayer::NetComponentId netComponentId, + Multiplayer::PropertyIndex propertyId, + uint32_t totalBytes) + { + if (Multiplayer::MultiplayerComponentRegistry* componentRegistry = Multiplayer::GetMultiplayerComponentRegistry()) + { + m_currentReceivingEntityReport.ReportField(static_cast(netComponentId), + componentRegistry->GetComponentName(netComponentId), + componentRegistry->GetComponentPropertyName(netComponentId, propertyId), totalBytes); + } + } } diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h index 96cfadb14d..c89c889813 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h @@ -1,18 +1,20 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * 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 "MultiplayerDebugByteReporter.h" + +#include +#include +#include #include +#include namespace MultiplayerDiagnostics { @@ -20,55 +22,60 @@ namespace MultiplayerDiagnostics * \brief GridMate network live analysis tool via ImGui. */ class MultiplayerDebugPerEntityReporter - : public GridMate::Debug::ReplicaDrillerBus::Handler - , public GridMate::Debug::CarrierDrillerBus::Handler + : public AZ::Interface::Registrar { public: MultiplayerDebugPerEntityReporter(); - virtual ~MultiplayerDebugPerEntityReporter(); + ~MultiplayerDebugPerEntityReporter() override; // main update loop void OnImGuiUpdate(); - // ReplicaDrillerBus - receive + //! MultilayerIPerEntityStats + // @{ + void RecordEntitySerializeStart(AZ::EntityId entityId, const char* entityName); + void RecordEntitySerializeStop(AZ::EntityId entityId, const char* entityName); + 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 OnReceiveReplicaBegin(GridMate::Replica* replica, const void* data, size_t len) override; - void OnReceiveReplicaEnd(GridMate::Replica* replica) override; + /*void OnReceiveReplicaBegin(AZ::EntityId entityId, const void* data, size_t len) override; + void OnReceiveReplicaEnd(AZ::EntityId entityId) override; void OnReceiveReplicaChunkEnd(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex) override; void OnReceiveDataSet(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex, GridMate::DataSetBase* dataSet, GridMate::PeerId from, GridMate::PeerId to, const void* data, size_t len) override; - void OnReceiveRpc(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex, GridMate::Internal::RpcRequest* rpc, GridMate::PeerId from, GridMate::PeerId to, const void* data, size_t len) override; + void OnReceiveRpc(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex, GridMate::Internal::RpcRequest* rpc, GridMate::PeerId from, GridMate::PeerId to, const void* data, size_t len) override;*/ // ReplicaDrillerBus - sending - void OnSendReplicaBegin(GridMate::Replica* replica) override; - void OnSendReplicaEnd(GridMate::Replica* replica, const void* data, size_t len) override; + /*void OnSendReplicaBegin(AZ::EntityId entityId) override; + void OnSendReplicaEnd(AZ::EntityId entityId, const void* data, size_t len) override; void OnSendReplicaChunkEnd(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex, const void* data, size_t len) override; void OnSendDataSet(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex, GridMate::DataSetBase* dataSet, GridMate::PeerId from, GridMate::PeerId to, const void* data, size_t len) override; - void OnSendRpc(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex, GridMate::Internal::RpcRequest* rpc, GridMate::PeerId from, GridMate::PeerId to, const void* data, size_t len) override; + void OnSendRpc(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex, GridMate::Internal::RpcRequest* rpc, GridMate::PeerId from, GridMate::PeerId to, const void* data, size_t len) override;*/ - // CarrierDrillerBus - void OnIncomingConnection (GridMate::Carrier* carrier, GridMate::ConnectionID id) override; - void OnFailedToConnect (GridMate::Carrier* carrier, - GridMate::ConnectionID id, - GridMate::CarrierDisconnectReason reason) override; - void OnConnectionEstablished (GridMate::Carrier* carrier, GridMate::ConnectionID id) override; - void OnDisconnect (GridMate::Carrier* carrier, - GridMate::ConnectionID id, - GridMate::CarrierDisconnectReason reason) override; - void OnDriverError (GridMate::Carrier* carrier, - GridMate::ConnectionID id, - const GridMate::DriverError& error) override; - void OnSecurityError (GridMate::Carrier* carrier, - GridMate::ConnectionID id, - const GridMate::SecurityError& error) override; - void OnUpdateStatistics (const GridMate::string& address, - const GridMate::TrafficControl::Statistics& lastSecond, - const GridMate::TrafficControl::Statistics& lifeTime, - const GridMate::TrafficControl::Statistics& effectiveLastSecond, - const GridMate::TrafficControl::Statistics& effectiveLifeTime) override; - void OnConnectionStateChanged (GridMate::Carrier* carrier, - GridMate::ConnectionID id, - GridMate::Carrier::ConnectionStates newState) override; + //// CarrierDrillerBus + //void OnIncomingConnection (GridMate::Carrier* carrier, GridMate::ConnectionID id) override; + //void OnFailedToConnect (GridMate::Carrier* carrier, + // GridMate::ConnectionID id, + // GridMate::CarrierDisconnectReason reason) override; + //void OnConnectionEstablished (GridMate::Carrier* carrier, GridMate::ConnectionID id) override; + //void OnDisconnect (GridMate::Carrier* carrier, + // GridMate::ConnectionID id, + // GridMate::CarrierDisconnectReason reason) override; + //void OnDriverError (GridMate::Carrier* carrier, + // GridMate::ConnectionID id, + // const GridMate::DriverError& error) override; + //void OnSecurityError (GridMate::Carrier* carrier, + // GridMate::ConnectionID id, + // const GridMate::SecurityError& error) override; + //void OnUpdateStatistics (const GridMate::string& address, + // const GridMate::TrafficControl::Statistics& lastSecond, + // const GridMate::TrafficControl::Statistics& lifeTime, + // const GridMate::TrafficControl::Statistics& effectiveLastSecond, + // const GridMate::TrafficControl::Statistics& effectiveLifeTime) override; + //void OnConnectionStateChanged (GridMate::Carrier* carrier, + // GridMate::ConnectionID id, + // GridMate::Carrier::ConnectionStates newState) override; private: diff --git a/Gems/Multiplayer/Code/Source/MultiplayerStats.cpp b/Gems/Multiplayer/Code/Source/MultiplayerStats.cpp index 6ee9f09cf7..b3236fbf77 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerStats.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerStats.cpp @@ -6,6 +6,7 @@ * */ +#include #include namespace Multiplayer @@ -29,8 +30,29 @@ namespace Multiplayer m_componentStats[netComponentIndex].m_rpcsRecv.resize(rpcCount); } + void MultiplayerStats::RecordEntitySerializeStart(AZ::EntityId entityId, const char* entityName) + { + if (auto* perEntityStats = AZ::Interface::Get()) + { + perEntityStats->RecordEntitySerializeStart(entityId, entityName); + } + } + + void MultiplayerStats::RecordEntitySerializeStop(AZ::EntityId entityId, const char* entityName) + { + if (auto* perEntityStats = AZ::Interface::Get()) + { + perEntityStats->RecordEntitySerializeStop(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++; @@ -41,6 +63,11 @@ namespace Multiplayer 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++; diff --git a/Gems/Multiplayer/Code/multiplayer_debug_files.cmake b/Gems/Multiplayer/Code/multiplayer_debug_files.cmake index 37a1c91640..d333269a1d 100644 --- a/Gems/Multiplayer/Code/multiplayer_debug_files.cmake +++ b/Gems/Multiplayer/Code/multiplayer_debug_files.cmake @@ -9,6 +9,7 @@ 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 From a2f3066fa36d0cb1e817f6a7517f067854e11ba9 Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Mon, 26 Jul 2021 21:59:19 -0400 Subject: [PATCH 03/13] Imgui per entity works Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- Gems/Multiplayer/Code/CMakeLists.txt | 2 +- .../Components/MultiplayerComponent.h | 5 +- .../Include/Multiplayer/MultiplayerStats.h | 5 +- .../Source/Components/NetBindComponent.cpp | 7 +- .../Debug/MultiplayerDebugByteReporter.cpp | 2 + .../Debug/MultiplayerDebugByteReporter.h | 17 +- .../MultiplayerDebugPerEntityInterface.h | 14 +- .../MultiplayerDebugPerEntityReporter.cpp | 337 ++++-------------- .../Debug/MultiplayerDebugPerEntityReporter.h | 57 +-- .../Debug/MultiplayerDebugSystemComponent.cpp | 14 +- .../Debug/MultiplayerDebugSystemComponent.h | 1 + .../Code/Source/MultiplayerStats.cpp | 29 +- .../EntityReplication/EntityReplicator.cpp | 9 +- 13 files changed, 155 insertions(+), 344 deletions(-) diff --git a/Gems/Multiplayer/Code/CMakeLists.txt b/Gems/Multiplayer/Code/CMakeLists.txt index 96527fbfc4..e8b38c8799 100644 --- a/Gems/Multiplayer/Code/CMakeLists.txt +++ b/Gems/Multiplayer/Code/CMakeLists.txt @@ -79,7 +79,7 @@ ly_add_target( # The "Multiplayer" target is used by clients and servers, Debug is used only on clients. ly_create_alias(NAME Multiplayer.Clients NAMESPACE Gem TARGETS Gem::Multiplayer Gem::Multiplayer.Debug) -ly_create_alias(NAME Multiplayer.Servers NAMESPACE Gem TARGETS Gem::Multiplayer) +ly_create_alias(NAME Multiplayer.Servers NAMESPACE Gem TARGETS Gem::Multiplayer Gem::Multiplayer.Debug) if (PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/Components/MultiplayerComponent.h b/Gems/Multiplayer/Code/Include/Multiplayer/Components/MultiplayerComponent.h index 48590e5393..64ceb6e16f 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/Components/MultiplayerComponent.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Components/MultiplayerComponent.h @@ -111,7 +111,6 @@ namespace Multiplayer int32_t bitIndex, TYPE& value, const char* name, - AZ::EntityId entityId, NetComponentId componentId, PropertyIndex propertyIndex, MultiplayerStats& stats @@ -134,11 +133,11 @@ namespace Multiplayer { if (modifyRecord) { - stats.RecordPropertyReceived(entityId, componentId, propertyIndex, updateSize); + stats.RecordPropertyReceived(componentId, propertyIndex, updateSize); } else { - stats.RecordPropertySent(entityId, componentId, propertyIndex, updateSize); + stats.RecordPropertySent(componentId, propertyIndex, updateSize); } } } diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerStats.h b/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerStats.h index 133cbb7aeb..1299fe174d 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerStats.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerStats.h @@ -50,8 +50,9 @@ namespace Multiplayer AZStd::vector m_componentStats; void ReserveComponentStats(NetComponentId netComponentId, uint16_t propertyCount, uint16_t rpcCount); - void RecordEntitySerializeStart(AZ::EntityId entityId, const char* entityName); - void RecordEntitySerializeStop(AZ::EntityId entityId, const char* entityName); + void RecordEntitySerializeStart(AzNetworking::SerializerMode mode, AZ::EntityId entityId, const char* entityName); + void RecordComponentSerializeEnd(AzNetworking::SerializerMode mode, NetComponentId netComponentId); + 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); diff --git a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp index 74091908e2..cfaeaedeff 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp @@ -447,15 +447,18 @@ namespace Multiplayer bool NetBindComponent::SerializeStateDeltaMessage(ReplicationRecord& replicationRecord, AzNetworking::ISerializer& serializer) { - GetMultiplayer()->GetStats().RecordEntitySerializeStart(GetEntityId(), GetEntity()->GetName().c_str()); + auto& stats = GetMultiplayer()->GetStats(); + stats.RecordEntitySerializeStart(serializer.GetSerializerMode(), GetEntityId(), GetEntity()->GetName().c_str()); bool success = true; for (auto iter = m_multiplayerSerializationComponentVector.begin(); iter != m_multiplayerSerializationComponentVector.end(); ++iter) { success &= (*iter)->SerializeStateDeltaMessage(replicationRecord, serializer); + + stats.RecordComponentSerializeEnd(serializer.GetSerializerMode(), (*iter)->GetNetComponentId()); } - GetMultiplayer()->GetStats().RecordEntitySerializeStop(GetEntityId(), GetEntity()->GetName().c_str()); + stats.RecordEntitySerializeStop(serializer.GetSerializerMode(), GetEntityId(), GetEntity()->GetName().c_str()); return success; } diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp index fd31298ad8..2c0a8b5db1 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp @@ -12,6 +12,8 @@ #include #include +#pragma optimize("", off) + namespace MultiplayerDiagnostics { void MultiplayerDebugByteReporter::ReportBytes(size_t byteSize) diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.h index 7e6a04569d..8977c2e6ba 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.h +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.h @@ -1,14 +1,11 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * 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 diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityInterface.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityInterface.h index 8cd94944b2..94bc11dafa 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityInterface.h +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityInterface.h @@ -13,14 +13,16 @@ namespace MultiplayerDiagnostics { - class MultilayerIPerEntityStats + class MultiplayerIPerEntityStats { public: - virtual ~MultilayerIPerEntityStats(); + AZ_RTTI(MultiplayerIPerEntityStats, "{91A1E4F0-8AE6-44B2-89DF-DA34134C408A}"); - virtual void RecordEntitySerializeStart(AZ::EntityId entityId, const char* entityName) = 0; - virtual void RecordEntitySerializeStop(AZ::EntityId entityId, const char* entityName) = 0; - virtual void RecordPropertySent(Multiplayer::NetComponentId netComponentId, Multiplayer::PropertyIndex propertyId, uint32_t totalBytes); - virtual void RecordPropertyReceived(Multiplayer::NetComponentId netComponentId, Multiplayer::PropertyIndex propertyId, uint32_t totalBytes); + 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; }; } diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp index 32ed7d5a59..c839083f63 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp @@ -7,23 +7,22 @@ */ #include "MultiplayerDebugPerEntityReporter.h" -#include -#include -#include #include #if defined(IMGUI_ENABLED) #include #endif +#pragma optimize("", off) + namespace MultiplayerDiagnostics { #if defined(IMGUI_ENABLED) static const ImVec4 k_ImGuiTomato = ImVec4(1.0f, 0.4f, 0.3f, 1.0f); - static const ImVec4 k_ImGuiKhaki = ImVec4(0.9f, 0.8f, 0.5f, 1.0f); - static const ImVec4 k_ImGuiCyan = ImVec4(0.5f, 1.0f, 1.0f, 1.0f); - static const ImVec4 k_ImGuiDusk = ImVec4(0.7f, 0.7f, 1.0f, 1.0f); - static const ImVec4 k_ImGuiWhite = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); + static const ImVec4 k_ImGuiKhaki = ImVec4(0.9f, 0.8f, 0.5f, 1.0f); + static const ImVec4 k_ImGuiCyan = ImVec4(0.5f, 1.0f, 1.0f, 1.0f); + static const ImVec4 k_ImGuiDusk = ImVec4(0.7f, 0.7f, 1.0f, 1.0f); + static const ImVec4 k_ImGuiWhite = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // -------------------------------------------------------------------------------------------- template @@ -111,291 +110,103 @@ namespace MultiplayerDiagnostics } #endif - MultiplayerDebugPerEntityReporter::MultiplayerDebugPerEntityReporter () - { - //GridMate::Debug::CarrierDrillerBus::Handler::BusConnect(); - } - - // -------------------------------------------------------------------------------------------- - MultiplayerDebugPerEntityReporter::~MultiplayerDebugPerEntityReporter() - { - /*GridMate::Debug::ReplicaDrillerBus::Handler::BusDisconnect(); - GridMate::Debug::CarrierDrillerBus::Handler::BusDisconnect();*/ - } - - //void MultiplayerDebugPerEntityReporter::OnReceiveReplicaBegin(GridMate::Replica*, const void*, size_t) - //{ - // m_currentReceivingEntityReport.Reset(); - //} - - //void MultiplayerDebugPerEntityReporter::OnReceiveReplicaEnd(GridMate::Replica* replica) - //{ - // m_receivingEntityReports[replica->GetDebugName()].Combine(m_currentReceivingEntityReport); - //} - - //void MultiplayerDebugPerEntityReporter::OnReceiveReplicaChunkEnd(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex) - //{ - // AZ_UNUSED(chunk); - // AZ_UNUSED(chunkIndex); - // m_currentReceivingEntityReport.ReportFragmentEnd(); - //} - - //void MultiplayerDebugPerEntityReporter::OnReceiveDataSet(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex, - // GridMate::DataSetBase* dataSet, GridMate::PeerId, GridMate::PeerId, const void*, size_t len) - //{ - // m_currentReceivingEntityReport.ReportField(chunkIndex, chunk->GetDescriptor()->GetChunkName(), chunk->GetDescriptor()->GetDataSetName(chunk, dataSet), len); - //} - - //void MultiplayerDebugPerEntityReporter::OnReceiveRpc (GridMate::ReplicaChunkBase* chunk, - // AZ::u32 chunkIndex, - // GridMate::Internal::RpcRequest* rpc, - // GridMate::PeerId from, - // GridMate::PeerId to, - // const void* data, - // size_t len) - //{ - // AZ_UNUSED( from ); - // AZ_UNUSED( to ); - // AZ_UNUSED( data ); - - // m_currentReceivingEntityReport.ReportField(chunkIndex, chunk->GetDescriptor()->GetChunkName(), chunk->GetDescriptor()->GetRpcName(chunk, rpc->m_rpc), len); - //} - - //void MultiplayerDebugPerEntityReporter::OnSendReplicaBegin (GridMate::Replica*) - //{ - // m_currentSendingEntityReport.Reset(); - //} - - //void MultiplayerDebugPerEntityReporter::OnSendReplicaEnd (GridMate::Replica* replica, const void*, size_t) - //{ - // m_sendingEntityReports[replica->GetDebugName()].Combine(m_currentSendingEntityReport); - //} - - //void MultiplayerDebugPerEntityReporter::OnSendReplicaChunkEnd (GridMate::ReplicaChunkBase* chunk, - // AZ::u32 chunkIndex, - // const void*, - // size_t) - //{ - // AZ_UNUSED(chunk); - // AZ_UNUSED(chunkIndex); - // m_currentSendingEntityReport.ReportFragmentEnd(); - //} - - //void MultiplayerDebugPerEntityReporter::OnSendDataSet (GridMate::ReplicaChunkBase* chunk, - // AZ::u32 chunkIndex, - // GridMate::DataSetBase* dataSet, - // GridMate::PeerId, - // GridMate::PeerId, - // const void*, - // size_t len) - //{ - // m_currentSendingEntityReport.ReportField(chunkIndex, chunk->GetDescriptor()->GetChunkName(), chunk->GetDescriptor()->GetDataSetName(chunk, dataSet), len); - //} - - //void MultiplayerDebugPerEntityReporter::OnSendRpc (GridMate::ReplicaChunkBase* chunk, - // AZ::u32 chunkIndex, - // GridMate::Internal::RpcRequest* rpc, - // GridMate::PeerId, - // GridMate::PeerId, - // const void*, - // size_t len) - //{ - // m_currentSendingEntityReport.ReportField(chunkIndex, chunk->GetDescriptor()->GetChunkName(), chunk->GetDescriptor()->GetRpcName(chunk, rpc->m_rpc), len); - //} - - //void MultiplayerDebugPerEntityReporter::OnIncomingConnection (GridMate::Carrier*, GridMate::ConnectionID) - //{ - //} - - //void MultiplayerDebugPerEntityReporter::OnFailedToConnect (GridMate::Carrier*, - // GridMate::ConnectionID, - // GridMate::CarrierDisconnectReason) - //{ - // m_lastSecondStats.clear(); - //} - - //void MultiplayerDebugPerEntityReporter::OnConnectionEstablished (GridMate::Carrier*, GridMate::ConnectionID) - //{ - //} - - //void MultiplayerDebugPerEntityReporter::OnDisconnect (GridMate::Carrier*, - // GridMate::ConnectionID, - // GridMate::CarrierDisconnectReason) - //{ - // /* - // * CarrierDrillerBus doesn't provide enough information to correctly keep track of network traffic for all peers. - // * This is a work around until that is fixed to at least not over report the bandwidth amount. - // */ - // m_lastSecondStats.clear(); - //} - - //void MultiplayerDebugPerEntityReporter::OnDriverError (GridMate::Carrier*, - // GridMate::ConnectionID, - // const GridMate::DriverError&) - //{ - // m_lastSecondStats.clear(); - //} - - //void MultiplayerDebugPerEntityReporter::OnSecurityError (GridMate::Carrier*, - // GridMate::ConnectionID, - // const GridMate::SecurityError&) - //{ - // m_lastSecondStats.clear(); - //} - - //void MultiplayerDebugPerEntityReporter::OnUpdateStatistics (const GridMate::string& address, - // const GridMate::TrafficControl::Statistics&, - // const GridMate::TrafficControl::Statistics&, - // const GridMate::TrafficControl::Statistics& effectiveLastSecond, - // const GridMate::TrafficControl::Statistics&) - //{ - // m_lastSecondStats[address] = effectiveLastSecond; - //} - - //void MultiplayerDebugPerEntityReporter::OnConnectionStateChanged (GridMate::Carrier*, - // GridMate::ConnectionID, - // GridMate::Carrier::ConnectionStates) - //{ - // m_lastSecondStats.clear(); - //} - - void MultiplayerDebugPerEntityReporter::UpdateTrafficStatistics() - { -#if defined(IMGUI_ENABLED) - AZ::u32 dataReceived = 0, dataSent = 0; - - for (auto& perConnection : m_lastSecondStats) - { - dataReceived += perConnection.second.m_dataReceived; - dataSent += perConnection.second.m_dataSend; - } - - if (dataReceived !=0 || dataSent != 0) - { - ImGui::Text("Total bandwidth: Sent %u kbps Received %u kbps.", dataSent * 8 / 1000, dataReceived * 8 / 1000); - } - else - { - ImGui::Text("Total bandwidth: Sent -- kbps Received -- kbps."); - } -#endif - } - // -------------------------------------------------------------------------------------------- void MultiplayerDebugPerEntityReporter::OnImGuiUpdate() { #if defined(IMGUI_ENABLED) - if (ImGui::BeginMainMenuBar()) + static ImGuiTextFilter filter; + filter.Draw(); + + if (ImGui::CollapsingHeader("Receiving Entities")) { - if (ImGui::BeginMenu("GridMate")) + for (auto& entityPair : m_receivingEntityReports) { - if (m_showServerReportWindow) + if (!filter.PassFilter(entityPair.first.c_str())) { - if (ImGui::MenuItem("Hide Multiplayer Analytics Window")) - { - m_showServerReportWindow = false; - } - } - else if (ImGui::MenuItem("Show Multiplayer Analytics Window")) - { - m_showServerReportWindow = true; + continue; } - ImGui::End(); + ImGui::Separator(); + if (ReplicatedStateTreeNode(entityPair.first, entityPair.second, k_ImGuiDusk)) + { + DisplayReplicatedStateReport(entityPair.second.GetComponentReports(), m_replicatedStateKbpsWarn, m_replicatedStateMaxSizeWarn); + ImGui::TreePop(); + } } - - ImGui::EndMainMenuBar(); } - if (m_showServerReportWindow) + if (ImGui::CollapsingHeader("Sending Entities")) { - if (ImGui::Begin("Multiplayer Analytics", &m_showServerReportWindow)) + for (auto& entityPair : m_sendingEntityReports) { - // General carrier stats - UpdateTrafficStatistics(); - - if (ImGui::Checkbox("Analyze network traffic", &m_isTrackingMessages)) + if (!filter.PassFilter(entityPair.first.c_str())) { - if (m_isTrackingMessages) - { - //GridMate::Debug::ReplicaDrillerBus::Handler::BusConnect(); - } - else - { - //GridMate::Debug::ReplicaDrillerBus::Handler::BusDisconnect(); - - m_currentReceivingEntityReport.Reset(); - m_receivingEntityReports.clear(); - - m_currentSendingEntityReport.Reset(); - m_sendingEntityReports.clear(); - } + continue; } - if (m_isTrackingMessages) + ImGui::Separator(); + if (ReplicatedStateTreeNode(entityPair.first, entityPair.second, k_ImGuiDusk)) { - ImGui::Separator(); - - static ImGuiTextFilter filter; - filter.Draw(); - - if (ImGui::CollapsingHeader("Received replicas per type")) - { - for (auto& entityPair : m_receivingEntityReports) - { - if (!filter.PassFilter(entityPair.first.c_str())) - { - continue; - } - - ImGui::Separator(); - if (ReplicatedStateTreeNode(entityPair.first, entityPair.second, k_ImGuiDusk)) - { - DisplayReplicatedStateReport(entityPair.second.GetComponentReports(), m_replicatedStateKbpsWarn, m_replicatedStateMaxSizeWarn); - ImGui::TreePop(); - } - } - } - - if (ImGui::CollapsingHeader("Sent replicas per type")) - { - for (auto& entityPair : m_sendingEntityReports) - { - if (!filter.PassFilter(entityPair.first.c_str())) - { - continue; - } - - ImGui::Separator(); - if (ReplicatedStateTreeNode(entityPair.first, entityPair.second, k_ImGuiDusk)) - { - DisplayReplicatedStateReport(entityPair.second.GetComponentReports(), m_replicatedStateKbpsWarn, m_replicatedStateMaxSizeWarn); - ImGui::TreePop(); - } - } - } + DisplayReplicatedStateReport(entityPair.second.GetComponentReports(), m_replicatedStateKbpsWarn, m_replicatedStateMaxSizeWarn); + ImGui::TreePop(); } } - ImGui::End(); } #endif } - void MultiplayerDebugPerEntityReporter::RecordEntitySerializeStart(AZ::EntityId entityId, const char* entityName) + void MultiplayerDebugPerEntityReporter::RecordEntitySerializeStart(AzNetworking::SerializerMode mode, + [[maybe_unused]] AZ::EntityId entityId, [[maybe_unused]] const char* entityName) { + switch (mode) + { + case AzNetworking::SerializerMode::ReadFromObject: + m_currentSendingEntityReport.Reset(); + break; + case AzNetworking::SerializerMode::WriteToObject: + m_currentReceivingEntityReport.Reset(); + break; + } } - void MultiplayerDebugPerEntityReporter::RecordEntitySerializeStop(AZ::EntityId entityId, const char* entityName) + void MultiplayerDebugPerEntityReporter::RecordComponentSerializeEnd(AzNetworking::SerializerMode mode, [[maybe_unused]] Multiplayer::NetComponentId netComponentId) { + switch (mode) + { + case AzNetworking::SerializerMode::ReadFromObject: + m_currentSendingEntityReport.ReportFragmentEnd(); + break; + case AzNetworking::SerializerMode::WriteToObject: + m_currentReceivingEntityReport.ReportFragmentEnd(); + break; + } + } + + void MultiplayerDebugPerEntityReporter::RecordEntitySerializeStop(AzNetworking::SerializerMode mode, + [[maybe_unused]] AZ::EntityId entityId, const char* entityName) + { + switch (mode) + { + case AzNetworking::SerializerMode::ReadFromObject: + m_sendingEntityReports[entityName].Combine(m_currentSendingEntityReport); + break; + case AzNetworking::SerializerMode::WriteToObject: + m_receivingEntityReports[entityName].Combine(m_currentReceivingEntityReport); + break; + } } void MultiplayerDebugPerEntityReporter::RecordPropertySent( - AZ::EntityId entityId, Multiplayer::NetComponentId netComponentId, Multiplayer::PropertyIndex propertyId, uint32_t totalBytes) { - // TODO + if (const Multiplayer::MultiplayerComponentRegistry* componentRegistry = Multiplayer::GetMultiplayerComponentRegistry()) + { + m_currentSendingEntityReport.ReportField(static_cast(netComponentId), + componentRegistry->GetComponentName(netComponentId), + componentRegistry->GetComponentPropertyName(netComponentId, propertyId), totalBytes); + } } void MultiplayerDebugPerEntityReporter::RecordPropertyReceived( @@ -403,11 +214,21 @@ namespace MultiplayerDiagnostics Multiplayer::PropertyIndex propertyId, uint32_t totalBytes) { - if (Multiplayer::MultiplayerComponentRegistry* componentRegistry = Multiplayer::GetMultiplayerComponentRegistry()) + if (const Multiplayer::MultiplayerComponentRegistry* componentRegistry = Multiplayer::GetMultiplayerComponentRegistry()) { m_currentReceivingEntityReport.ReportField(static_cast(netComponentId), componentRegistry->GetComponentName(netComponentId), componentRegistry->GetComponentPropertyName(netComponentId, propertyId), totalBytes); } } + + void MultiplayerDebugPerEntityReporter::RecordRpcSent(Multiplayer::NetComponentId netComponentId, Multiplayer::RpcIndex rpcId, uint32_t totalBytes) + { + if (const Multiplayer::MultiplayerComponentRegistry* componentRegistry = Multiplayer::GetMultiplayerComponentRegistry()) + { + m_currentSendingEntityReport.ReportField(static_cast(netComponentId), + componentRegistry->GetComponentName(netComponentId), + componentRegistry->GetComponentRpcName(netComponentId, rpcId), totalBytes); + } + } } diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h index c89c889813..121c4131ed 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h @@ -7,7 +7,6 @@ */ #pragma once -#include #include "MultiplayerDebugByteReporter.h" #include @@ -22,66 +21,27 @@ namespace MultiplayerDiagnostics * \brief GridMate network live analysis tool via ImGui. */ class MultiplayerDebugPerEntityReporter - : public AZ::Interface::Registrar + : public AZ::Interface::Registrar { public: - MultiplayerDebugPerEntityReporter(); - ~MultiplayerDebugPerEntityReporter() override; + MultiplayerDebugPerEntityReporter() = default; + ~MultiplayerDebugPerEntityReporter() override = default; // main update loop void OnImGuiUpdate(); //! MultilayerIPerEntityStats // @{ - void RecordEntitySerializeStart(AZ::EntityId entityId, const char* entityName); - void RecordEntitySerializeStop(AZ::EntityId entityId, const char* entityName); + 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 OnReceiveReplicaBegin(AZ::EntityId entityId, const void* data, size_t len) override; - void OnReceiveReplicaEnd(AZ::EntityId entityId) override; - void OnReceiveReplicaChunkEnd(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex) override; - void OnReceiveDataSet(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex, GridMate::DataSetBase* dataSet, GridMate::PeerId from, GridMate::PeerId to, const void* data, size_t len) override; - void OnReceiveRpc(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex, GridMate::Internal::RpcRequest* rpc, GridMate::PeerId from, GridMate::PeerId to, const void* data, size_t len) override;*/ - - // ReplicaDrillerBus - sending - - /*void OnSendReplicaBegin(AZ::EntityId entityId) override; - void OnSendReplicaEnd(AZ::EntityId entityId, const void* data, size_t len) override; - void OnSendReplicaChunkEnd(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex, const void* data, size_t len) override; - void OnSendDataSet(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex, GridMate::DataSetBase* dataSet, GridMate::PeerId from, GridMate::PeerId to, const void* data, size_t len) override; - void OnSendRpc(GridMate::ReplicaChunkBase* chunk, AZ::u32 chunkIndex, GridMate::Internal::RpcRequest* rpc, GridMate::PeerId from, GridMate::PeerId to, const void* data, size_t len) override;*/ - - //// CarrierDrillerBus - //void OnIncomingConnection (GridMate::Carrier* carrier, GridMate::ConnectionID id) override; - //void OnFailedToConnect (GridMate::Carrier* carrier, - // GridMate::ConnectionID id, - // GridMate::CarrierDisconnectReason reason) override; - //void OnConnectionEstablished (GridMate::Carrier* carrier, GridMate::ConnectionID id) override; - //void OnDisconnect (GridMate::Carrier* carrier, - // GridMate::ConnectionID id, - // GridMate::CarrierDisconnectReason reason) override; - //void OnDriverError (GridMate::Carrier* carrier, - // GridMate::ConnectionID id, - // const GridMate::DriverError& error) override; - //void OnSecurityError (GridMate::Carrier* carrier, - // GridMate::ConnectionID id, - // const GridMate::SecurityError& error) override; - //void OnUpdateStatistics (const GridMate::string& address, - // const GridMate::TrafficControl::Statistics& lastSecond, - // const GridMate::TrafficControl::Statistics& lifeTime, - // const GridMate::TrafficControl::Statistics& effectiveLastSecond, - // const GridMate::TrafficControl::Statistics& effectiveLifeTime) override; - //void OnConnectionStateChanged (GridMate::Carrier* carrier, - // GridMate::ConnectionID id, - // GridMate::Carrier::ConnectionStates newState) override; - private: - bool m_showServerReportWindow = false; - bool m_isTrackingMessages = false; - AZStd::map m_sendingEntityReports{}; EntityReporter m_currentSendingEntityReport; @@ -90,8 +50,5 @@ namespace MultiplayerDiagnostics float m_replicatedStateKbpsWarn = 10.f; float m_replicatedStateMaxSizeWarn = 30.f; - - void UpdateTrafficStatistics(); - AZStd::map m_lastSecondStats; }; } diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp index b97fa053b2..73afc45271 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp @@ -13,6 +13,8 @@ #include #include +#pragma optimize("", off) + namespace Multiplayer { void MultiplayerDebugSystemComponent::Reflect(AZ::ReflectContext* context) @@ -65,6 +67,7 @@ namespace Multiplayer { ImGui::Checkbox("Networking Stats", &m_displayNetworkingStats); ImGui::Checkbox("Multiplayer Stats", &m_displayMultiplayerStats); + ImGui::Checkbox("Multiplayer Per Entity Stats", &m_displayPerEntityStats); ImGui::EndMenu(); } } @@ -324,10 +327,15 @@ namespace Multiplayer } } - - if (m_reporter) + if (m_displayPerEntityStats) { - m_reporter->OnImGuiUpdate(); + if (ImGui::Begin("Multiplayer Per Entity Analytics", &m_displayPerEntityStats)) + { + if (m_reporter) + { + m_reporter->OnImGuiUpdate(); + } + } } } #endif diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h index 3dbbd06d6f..4972ec6bdf 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h @@ -51,6 +51,7 @@ namespace Multiplayer private: bool m_displayNetworkingStats = false; bool m_displayMultiplayerStats = false; + bool m_displayPerEntityStats = false; AZStd::unique_ptr m_reporter; }; diff --git a/Gems/Multiplayer/Code/Source/MultiplayerStats.cpp b/Gems/Multiplayer/Code/Source/MultiplayerStats.cpp index b3236fbf77..fd1b6a329d 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerStats.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerStats.cpp @@ -30,25 +30,33 @@ namespace Multiplayer m_componentStats[netComponentIndex].m_rpcsRecv.resize(rpcCount); } - void MultiplayerStats::RecordEntitySerializeStart(AZ::EntityId entityId, const char* entityName) + void MultiplayerStats::RecordEntitySerializeStart(AzNetworking::SerializerMode mode, AZ::EntityId entityId, const char* entityName) { - if (auto* perEntityStats = AZ::Interface::Get()) + if (auto* perEntityStats = AZ::Interface::Get()) { - perEntityStats->RecordEntitySerializeStart(entityId, entityName); + perEntityStats->RecordEntitySerializeStart(mode, entityId, entityName); } } - void MultiplayerStats::RecordEntitySerializeStop(AZ::EntityId entityId, const char* entityName) + void MultiplayerStats::RecordComponentSerializeEnd(AzNetworking::SerializerMode mode, NetComponentId netComponentId) { - if (auto* perEntityStats = AZ::Interface::Get()) + if (auto* perEntityStats = AZ::Interface::Get()) { - perEntityStats->RecordEntitySerializeStop(entityId, entityName); + perEntityStats->RecordComponentSerializeEnd(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); } } void MultiplayerStats::RecordPropertySent(NetComponentId netComponentId, PropertyIndex propertyId, uint32_t totalBytes) { - if (auto* perEntityStats = AZ::Interface::Get()) + if (auto* perEntityStats = AZ::Interface::Get()) { perEntityStats->RecordPropertySent(netComponentId, propertyId, totalBytes); } @@ -63,7 +71,7 @@ namespace Multiplayer void MultiplayerStats::RecordPropertyReceived(NetComponentId netComponentId, PropertyIndex propertyId, uint32_t totalBytes) { - if (auto* perEntityStats = AZ::Interface::Get()) + if (auto* perEntityStats = AZ::Interface::Get()) { perEntityStats->RecordPropertyReceived(netComponentId, propertyId, totalBytes); } @@ -78,6 +86,11 @@ namespace Multiplayer void MultiplayerStats::RecordRpcSent(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++; diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp index 93fd3ea652..2afadbe4a4 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp @@ -30,6 +30,8 @@ #include +#pragma optimize("", off) + namespace Multiplayer { EntityReplicator::EntityReplicator @@ -441,7 +443,12 @@ 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()); m_replicationManager.AddDeferredRpcMessage(entityRpcMessage); } @@ -515,7 +522,7 @@ namespace Multiplayer && (GetRemoteNetworkRole() == NetEntityRole::Server)) { // We are on a server, and we received this message from another server, therefore we should forward this to our autonomous player - // This can occur if we've recently migrated + // This can occur if we've recently migrated result = RpcValidationResult::ForwardToAutonomous; } } From 59f65f265653cc73abeb2db3b94fb8b8bf64a231 Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Mon, 26 Jul 2021 23:45:09 -0400 Subject: [PATCH 04/13] Refactored to store entities by entity ids Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- .../Debug/MultiplayerDebugByteReporter.cpp | 20 +----------------- .../Debug/MultiplayerDebugByteReporter.h | 10 +++++++-- .../MultiplayerDebugPerEntityReporter.cpp | 21 +++++++++++-------- .../Debug/MultiplayerDebugPerEntityReporter.h | 4 ++-- 4 files changed, 23 insertions(+), 32 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp index 2c0a8b5db1..5e912612b7 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp @@ -163,25 +163,6 @@ namespace MultiplayerDiagnostics MultiplayerDebugByteReporter::AggregateBytes(byteSize); } - void EntityReporter::ReportDirtyBits(AZ::u32 index, const char* componentName, size_t byteSize) - { - const char* const prefix = "MB::"; - if (strncmp(prefix, componentName, 4) == 0) - { - componentName += strlen(prefix); - } - - if (m_currentComponentReport == nullptr) - { - std::stringstream component; - component << "[" << std::setw(2) << std::setfill('0') << static_cast(index) << "]" << " " << componentName; - m_currentComponentReport = &m_componentReports[component.str().c_str()]; - } - - m_currentComponentReport->ReportDirtyBits(byteSize); - m_gdeDirtyBytes.AggregateBytes(byteSize); - } - void EntityReporter::ReportFragmentEnd() { if (m_currentComponentReport) @@ -203,6 +184,7 @@ namespace MultiplayerDiagnostics m_componentReports[componentIter.first].Combine(componentIter.second); } + SetEntityName(other.GetEntityName()); m_gdeDirtyBytes.Combine(other.m_gdeDirtyBytes); } diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.h index 8977c2e6ba..3cef9caaac 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.h +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.h @@ -54,7 +54,6 @@ namespace MultiplayerDiagnostics ComponentReporter() = default; void ReportField(const char* fieldName, size_t byteSize); - void ReportDirtyBits(size_t byteSize) { m_componentDirtyBytes.AggregateBytes(byteSize); } void ReportFragmentEnd(); using Report = AZStd::pair; @@ -75,12 +74,18 @@ namespace MultiplayerDiagnostics EntityReporter() = default; void ReportField(AZ::u32 index, const char* componentName, const char* fieldName, size_t byteSize); - void ReportDirtyBits(AZ::u32 index, const char* componentName, size_t byteSize); void ReportFragmentEnd(); void Combine(const EntityReporter& other); void Reset() override; + const char* GetEntityName() const { return m_entityName.c_str(); } + void SetEntityName(const char* entityName) + { + // copying because the entity might go away + m_entityName = entityName; + } + AZStd::map& GetComponentReports(); AZStd::size_t GetTotalDirtyBits() const { return m_gdeDirtyBytes.GetTotalBytes(); } float GetAvgDirtyBits() const { return m_gdeDirtyBytes.GetAverageBytes(); } @@ -89,5 +94,6 @@ namespace MultiplayerDiagnostics ComponentReporter* m_currentComponentReport = nullptr; AZStd::map m_componentReports; MultiplayerDebugByteReporter m_gdeDirtyBytes; + AZStd::string m_entityName; }; } diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp index c839083f63..3517dfa86a 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp @@ -119,15 +119,15 @@ namespace MultiplayerDiagnostics if (ImGui::CollapsingHeader("Receiving Entities")) { - for (auto& entityPair : m_receivingEntityReports) + for (AZStd::pair& entityPair : m_receivingEntityReports) { - if (!filter.PassFilter(entityPair.first.c_str())) + if (!filter.PassFilter(entityPair.second.GetEntityName())) { continue; } ImGui::Separator(); - if (ReplicatedStateTreeNode(entityPair.first, entityPair.second, k_ImGuiDusk)) + if (ReplicatedStateTreeNode(entityPair.second.GetEntityName(), entityPair.second, k_ImGuiDusk)) { DisplayReplicatedStateReport(entityPair.second.GetComponentReports(), m_replicatedStateKbpsWarn, m_replicatedStateMaxSizeWarn); ImGui::TreePop(); @@ -137,15 +137,16 @@ namespace MultiplayerDiagnostics if (ImGui::CollapsingHeader("Sending Entities")) { - for (auto& entityPair : m_sendingEntityReports) + for (AZStd::pair& entityPair : m_sendingEntityReports) { - if (!filter.PassFilter(entityPair.first.c_str())) + const char* name = entityPair.second.GetEntityName(); + if (!filter.PassFilter(name)) { continue; } ImGui::Separator(); - if (ReplicatedStateTreeNode(entityPair.first, entityPair.second, k_ImGuiDusk)) + if (ReplicatedStateTreeNode(name, entityPair.second, k_ImGuiDusk)) { DisplayReplicatedStateReport(entityPair.second.GetComponentReports(), m_replicatedStateKbpsWarn, m_replicatedStateMaxSizeWarn); ImGui::TreePop(); @@ -162,9 +163,11 @@ namespace MultiplayerDiagnostics { case AzNetworking::SerializerMode::ReadFromObject: m_currentSendingEntityReport.Reset(); + m_currentSendingEntityReport.SetEntityName(entityName); break; case AzNetworking::SerializerMode::WriteToObject: m_currentReceivingEntityReport.Reset(); + m_currentReceivingEntityReport.SetEntityName(entityName); break; } } @@ -183,15 +186,15 @@ namespace MultiplayerDiagnostics } void MultiplayerDebugPerEntityReporter::RecordEntitySerializeStop(AzNetworking::SerializerMode mode, - [[maybe_unused]] AZ::EntityId entityId, const char* entityName) + [[maybe_unused]] AZ::EntityId entityId, [[maybe_unused]] const char* entityName) { switch (mode) { case AzNetworking::SerializerMode::ReadFromObject: - m_sendingEntityReports[entityName].Combine(m_currentSendingEntityReport); + m_sendingEntityReports[entityId].Combine(m_currentSendingEntityReport); break; case AzNetworking::SerializerMode::WriteToObject: - m_receivingEntityReports[entityName].Combine(m_currentReceivingEntityReport); + m_receivingEntityReports[entityId].Combine(m_currentReceivingEntityReport); break; } } diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h index 121c4131ed..f34cc2cd35 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h @@ -42,10 +42,10 @@ namespace MultiplayerDiagnostics private: - AZStd::map m_sendingEntityReports{}; + AZStd::map m_sendingEntityReports{}; EntityReporter m_currentSendingEntityReport; - AZStd::map m_receivingEntityReports{}; + AZStd::map m_receivingEntityReports{}; EntityReporter m_currentReceivingEntityReport; float m_replicatedStateKbpsWarn = 10.f; From 8fa3addda3501ee44308f15e5331b1d27d280565 Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Tue, 27 Jul 2021 00:21:40 -0400 Subject: [PATCH 05/13] Added debug overlay for entitie with high network costs Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- .../MultiplayerDebugPerEntityReporter.cpp | 37 +++++++++++++++++++ .../Debug/MultiplayerDebugSystemComponent.cpp | 2 +- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp index 3517dfa86a..30e6feb2f4 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp @@ -7,6 +7,10 @@ */ #include "MultiplayerDebugPerEntityReporter.h" + +#include +#include +#include #include #if defined(IMGUI_ENABLED) @@ -117,6 +121,17 @@ namespace MultiplayerDiagnostics static ImGuiTextFilter filter; filter.Draw(); + char status[100] = {}; + + struct NetworkEntityTraffic + { + const char* m_name = nullptr; + float m_up = 0.f; + float m_down = 0.f; + }; + + AZStd::fixed_unordered_map networkEntitiesTraffic; + if (ImGui::CollapsingHeader("Receiving Entities")) { for (AZStd::pair& entityPair : m_receivingEntityReports) @@ -132,6 +147,9 @@ namespace MultiplayerDiagnostics DisplayReplicatedStateReport(entityPair.second.GetComponentReports(), m_replicatedStateKbpsWarn, m_replicatedStateMaxSizeWarn); ImGui::TreePop(); } + + networkEntitiesTraffic[entityPair.first].m_name = entityPair.second.GetEntityName(); + networkEntitiesTraffic[entityPair.first].m_down = entityPair.second.GetKbitsPerSecond(); } } @@ -151,8 +169,27 @@ namespace MultiplayerDiagnostics DisplayReplicatedStateReport(entityPair.second.GetComponentReports(), m_replicatedStateKbpsWarn, m_replicatedStateMaxSizeWarn); ImGui::TreePop(); } + + networkEntitiesTraffic[entityPair.first].m_name = entityPair.second.GetEntityName(); + networkEntitiesTraffic[entityPair.first].m_up = entityPair.second.GetKbitsPerSecond(); } } + + constexpr float trafficThreshold = 0.1f; + for (AZStd::pair& networkEntity : networkEntitiesTraffic) + { + if (networkEntity.second.m_down < trafficThreshold && networkEntity.second.m_up < trafficThreshold) + { + continue; + } + + azsprintf(status, "%s - %.0f down / %0.f up (kbps)", networkEntity.second.m_name, networkEntity.second.m_down, networkEntity.second.m_up); + AZ::Vector3 entityPosition = AZ::Vector3::CreateZero(); + constexpr bool centerText = true; + AZ::TransformBus::EventResult(entityPosition, networkEntity.first, &AZ::TransformBus::Events::GetWorldTranslation); + AzFramework::DebugDisplayRequestBus::Broadcast(&AzFramework::DebugDisplayRequestBus::Events::DrawTextLabel, + entityPosition, 1.0f, status, centerText, 0, 0); + } #endif } diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp index 73afc45271..44e2f9f6bf 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp @@ -329,7 +329,7 @@ namespace Multiplayer if (m_displayPerEntityStats) { - if (ImGui::Begin("Multiplayer Per Entity Analytics", &m_displayPerEntityStats)) + if (ImGui::Begin("Multiplayer Per Entity Analytics", &m_displayPerEntityStats, ImGuiWindowFlags_None)) { if (m_reporter) { From 5ebb096d1a3420281a002f20a86351b8b7d1a690 Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Tue, 27 Jul 2021 15:49:41 -0400 Subject: [PATCH 06/13] Debug overlay for kpbs per entity works Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- .../MultiplayerDebugPerEntityInterface.h | 1 + .../MultiplayerDebugPerEntityReporter.cpp | 140 +++++++++++++----- .../Debug/MultiplayerDebugPerEntityReporter.h | 25 +++- .../Debug/MultiplayerDebugSystemComponent.cpp | 5 +- .../Code/Source/MultiplayerStats.cpp | 5 + 5 files changed, 138 insertions(+), 38 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityInterface.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityInterface.h index 94bc11dafa..4f177affe3 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityInterface.h +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityInterface.h @@ -24,5 +24,6 @@ namespace MultiplayerDiagnostics 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 30e6feb2f4..3c5495ec6a 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp @@ -19,6 +19,21 @@ #pragma optimize("", off) +AZ_CVAR(bool, net_DebugNetworkEntity_Bandwidth, true, nullptr, AZ::ConsoleFunctorFlags::Null, + "If true, prints debug text over entities that use a considerable amount of network traffic"); + +AZ_CVAR(float, net_DebugNetworkEntity_ShowAboveKbps, 1.f, nullptr, AZ::ConsoleFunctorFlags::Null, + "Prints bandwidth on network entities with higher kpbs than this value"); + +AZ_CVAR(float, net_DebugNetworkEntity_WarnAboveKbps, 10.f, nullptr, AZ::ConsoleFunctorFlags::Null, + "Prints bandwidth on network entities with higher kpbs than this value"); + +AZ_CVAR(AZ::Color, net_DebugNetworkEntity_WarningColor, AZ::Colors::Red, nullptr, AZ::ConsoleFunctorFlags::Null, + "If true, prints debug text over entities that use a considerable amount of network traffic"); + +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 { #if defined(IMGUI_ENABLED) @@ -114,6 +129,17 @@ namespace MultiplayerDiagnostics } #endif + MultiplayerDebugPerEntityReporter::MultiplayerDebugPerEntityReporter() + : m_updateDebugOverlay([this]() { UpdateDebugOverlay(); }, AZ::Name("UpdateDebugPerEntityOverlay")) + { + m_updateDebugOverlay.Enqueue(AZ::TimeMs{ 0 }, true); + } + + MultiplayerDebugPerEntityReporter::~MultiplayerDebugPerEntityReporter() + { + m_updateDebugOverlay.RemoveFromQueue(); + } + // -------------------------------------------------------------------------------------------- void MultiplayerDebugPerEntityReporter::OnImGuiUpdate() { @@ -121,17 +147,6 @@ namespace MultiplayerDiagnostics static ImGuiTextFilter filter; filter.Draw(); - char status[100] = {}; - - struct NetworkEntityTraffic - { - const char* m_name = nullptr; - float m_up = 0.f; - float m_down = 0.f; - }; - - AZStd::fixed_unordered_map networkEntitiesTraffic; - if (ImGui::CollapsingHeader("Receiving Entities")) { for (AZStd::pair& entityPair : m_receivingEntityReports) @@ -147,9 +162,6 @@ namespace MultiplayerDiagnostics DisplayReplicatedStateReport(entityPair.second.GetComponentReports(), m_replicatedStateKbpsWarn, m_replicatedStateMaxSizeWarn); ImGui::TreePop(); } - - networkEntitiesTraffic[entityPair.first].m_name = entityPair.second.GetEntityName(); - networkEntitiesTraffic[entityPair.first].m_down = entityPair.second.GetKbitsPerSecond(); } } @@ -169,27 +181,8 @@ namespace MultiplayerDiagnostics DisplayReplicatedStateReport(entityPair.second.GetComponentReports(), m_replicatedStateKbpsWarn, m_replicatedStateMaxSizeWarn); ImGui::TreePop(); } - - networkEntitiesTraffic[entityPair.first].m_name = entityPair.second.GetEntityName(); - networkEntitiesTraffic[entityPair.first].m_up = entityPair.second.GetKbitsPerSecond(); } } - - constexpr float trafficThreshold = 0.1f; - for (AZStd::pair& networkEntity : networkEntitiesTraffic) - { - if (networkEntity.second.m_down < trafficThreshold && networkEntity.second.m_up < trafficThreshold) - { - continue; - } - - azsprintf(status, "%s - %.0f down / %0.f up (kbps)", networkEntity.second.m_name, networkEntity.second.m_down, networkEntity.second.m_up); - AZ::Vector3 entityPosition = AZ::Vector3::CreateZero(); - constexpr bool centerText = true; - AZ::TransformBus::EventResult(entityPosition, networkEntity.first, &AZ::TransformBus::Events::GetWorldTranslation); - AzFramework::DebugDisplayRequestBus::Broadcast(&AzFramework::DebugDisplayRequestBus::Events::DrawTextLabel, - entityPosition, 1.0f, status, centerText, 0, 0); - } #endif } @@ -271,4 +264,85 @@ namespace MultiplayerDiagnostics componentRegistry->GetComponentRpcName(netComponentId, rpcId), totalBytes); } } + + void MultiplayerDebugPerEntityReporter::RecordRpcReceived( + Multiplayer::NetComponentId netComponentId, + Multiplayer::RpcIndex rpcId, + uint32_t totalBytes) + { + if (const Multiplayer::MultiplayerComponentRegistry* componentRegistry = Multiplayer::GetMultiplayerComponentRegistry()) + { + m_currentReceivingEntityReport.ReportField(static_cast(netComponentId), + componentRegistry->GetComponentName(netComponentId), + componentRegistry->GetComponentRpcName(netComponentId, rpcId), totalBytes); + } + } + + void MultiplayerDebugPerEntityReporter::UpdateDebugOverlay() + { + if (net_DebugNetworkEntity_Bandwidth) + { + m_networkEntitiesTraffic.clear(); + + 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) + { + m_networkEntitiesTraffic[entityPair.first].m_name = entityPair.second.GetEntityName(); + m_networkEntitiesTraffic[entityPair.first].m_up = entityPair.second.GetKbitsPerSecond(); + } + + //get debug display interface for the viewport + 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(); + + for (AZStd::pair& networkEntity : m_networkEntitiesTraffic) + { + if (networkEntity.second.m_down < net_DebugNetworkEntity_ShowAboveKbps && networkEntity.second.m_up < net_DebugNetworkEntity_ShowAboveKbps) + { + continue; + } + + if (networkEntity.second.m_down > net_DebugNetworkEntity_WarnAboveKbps || networkEntity.second.m_up > net_DebugNetworkEntity_WarnAboveKbps) + { + m_debugDisplay->SetColor(net_DebugNetworkEntity_WarningColor); + } + else + { + m_debugDisplay->SetColor(net_DebugNetworkEntity_BelowWarningColor); + } + + if (networkEntity.second.m_down > net_DebugNetworkEntity_ShowAboveKbps && networkEntity.second.m_up > net_DebugNetworkEntity_ShowAboveKbps) + { + azsprintf(m_statusBuffer, "[%s] %.0f down / %0.f up (kbps)", networkEntity.second.m_name, + networkEntity.second.m_down, networkEntity.second.m_up); + } + else if (networkEntity.second.m_down > net_DebugNetworkEntity_ShowAboveKbps) + { + azsprintf(m_statusBuffer, "[%s] %.0f down (kbps)", networkEntity.second.m_name, networkEntity.second.m_down); + } + else + { + azsprintf(m_statusBuffer, "[%s] %.0f up (kbps)", networkEntity.second.m_name, networkEntity.second.m_up); + } + + AZ::Vector3 entityPosition = AZ::Vector3::CreateZero(); + constexpr bool centerText = true; + AZ::TransformBus::EventResult(entityPosition, networkEntity.first, &AZ::TransformBus::Events::GetWorldTranslation); + m_debugDisplay->DrawTextLabel(entityPosition, 1.0f, m_statusBuffer, centerText, 0, 0); + } + + m_debugDisplay->SetState(stateBefore); + } + } } diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h index f34cc2cd35..23192062e3 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h @@ -10,7 +10,10 @@ #include "MultiplayerDebugByteReporter.h" #include +#include +#include #include +#include #include #include #include @@ -24,8 +27,8 @@ namespace MultiplayerDiagnostics : public AZ::Interface::Registrar { public: - MultiplayerDebugPerEntityReporter() = default; - ~MultiplayerDebugPerEntityReporter() override = default; + MultiplayerDebugPerEntityReporter(); + ~MultiplayerDebugPerEntityReporter() override; // main update loop void OnImGuiUpdate(); @@ -38,10 +41,15 @@ namespace MultiplayerDiagnostics 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 UpdateDebugOverlay(); + private: + AZ::ScheduledEvent m_updateDebugOverlay; + AZStd::map m_sendingEntityReports{}; EntityReporter m_currentSendingEntityReport; @@ -50,5 +58,18 @@ namespace MultiplayerDiagnostics float m_replicatedStateKbpsWarn = 10.f; float m_replicatedStateMaxSizeWarn = 30.f; + + char m_statusBuffer[100] = {}; + + struct NetworkEntityTraffic + { + const char* m_name = nullptr; + float m_up = 0.f; + float m_down = 0.f; + }; + + AZStd::fixed_unordered_map m_networkEntitiesTraffic; + + AzFramework::DebugDisplayRequests* m_debugDisplay = nullptr; }; } diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp index 44e2f9f6bf..835aae0d72 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp @@ -13,8 +13,6 @@ #include #include -#pragma optimize("", off) - namespace Multiplayer { void MultiplayerDebugSystemComponent::Reflect(AZ::ReflectContext* context) @@ -329,7 +327,8 @@ namespace Multiplayer if (m_displayPerEntityStats) { - if (ImGui::Begin("Multiplayer Per Entity Analytics", &m_displayPerEntityStats, ImGuiWindowFlags_None)) + //ImGui::SetNextWindowSize({500, 400}); + if (ImGui::Begin("Multiplayer Per Entity Stats", &m_displayPerEntityStats, ImGuiWindowFlags_AlwaysAutoResize)) { if (m_reporter) { diff --git a/Gems/Multiplayer/Code/Source/MultiplayerStats.cpp b/Gems/Multiplayer/Code/Source/MultiplayerStats.cpp index fd1b6a329d..05be869872 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerStats.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerStats.cpp @@ -101,6 +101,11 @@ namespace Multiplayer void MultiplayerStats::RecordRpcReceived(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++; From 462c31b5de49ffe05c1788741278d2865a685ae1 Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Wed, 28 Jul 2021 09:53:44 -0400 Subject: [PATCH 07/13] Refactoring to use AZ::Events Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- .../Include/Multiplayer/MultiplayerStats.h | 30 ++++++++- .../Debug/MultiplayerDebugByteReporter.cpp | 38 ++++++------ .../Debug/MultiplayerDebugByteReporter.h | 20 +++--- .../MultiplayerDebugPerEntityInterface.h | 29 --------- .../MultiplayerDebugPerEntityReporter.cpp | 61 ++++++++++++++++--- .../Debug/MultiplayerDebugPerEntityReporter.h | 34 +++++------ .../Debug/MultiplayerDebugSystemComponent.cpp | 4 +- .../Debug/MultiplayerDebugSystemComponent.h | 2 +- .../Code/Source/MultiplayerStats.cpp | 59 ++++++++---------- .../EntityReplication/EntityReplicator.cpp | 11 ++-- .../Code/multiplayer_debug_files.cmake | 1 - 11 files changed, 156 insertions(+), 133 deletions(-) delete mode 100644 Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityInterface.h 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 From 93a3d3efa07abe909474ee81f981b9df98524c01 Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Mon, 2 Aug 2021 15:57:29 -0400 Subject: [PATCH 08/13] Bandwith overlay works without imgui Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- .../Include/Multiplayer/IMultiplayerDebug.h | 28 ++++ .../Debug/MultiplayerDebugByteReporter.cpp | 4 +- .../MultiplayerDebugPerEntityReporter.cpp | 130 ++++++++---------- .../Debug/MultiplayerDebugPerEntityReporter.h | 3 +- .../Debug/MultiplayerDebugSystemComponent.cpp | 35 ++++- .../Debug/MultiplayerDebugSystemComponent.h | 11 +- Gems/Multiplayer/Code/multiplayer_files.cmake | 1 + 7 files changed, 135 insertions(+), 77 deletions(-) create mode 100644 Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayerDebug.h diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayerDebug.h b/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayerDebug.h new file mode 100644 index 0000000000..384db66317 --- /dev/null +++ b/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayerDebug.h @@ -0,0 +1,28 @@ +/* + * 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 + +namespace Multiplayer +{ + //! @class IMultiplayerDebug + //! @brief IMultiplayerDebug provides access to multiplayer debug overlays + class IMultiplayerDebug + { + public: + AZ_RTTI(IMultiplayerDebug, "{C5EB7F3A-E19F-4921-A604-C9BDC910123C}"); + + virtual ~IMultiplayerDebug() = default; + + //! + virtual void ShowEntityBandwidthDebugOverlay() = 0; + + //! + virtual void HideEntityBandwidthDebugOverlay() = 0; + }; +} diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp index a29350e43a..38a1a27dcd 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp @@ -8,12 +8,10 @@ #include "MultiplayerDebugByteReporter.h" -#include +#include // for std::setfill #include #include -#pragma optimize("", off) - namespace Multiplayer { void MultiplayerDebugByteReporter::ReportBytes(size_t byteSize) diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp index da32bbb666..b0bfe097e1 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp @@ -17,11 +17,6 @@ #include #endif -#pragma optimize("", off) - -AZ_CVAR(bool, net_DebugNetworkEntity_Bandwidth, true, nullptr, AZ::ConsoleFunctorFlags::Null, - "If true, prints debug text over entities that use a considerable amount of network traffic"); - AZ_CVAR(float, net_DebugNetworkEntity_ShowAboveKbps, 1.f, nullptr, AZ::ConsoleFunctorFlags::Null, "Prints bandwidth on network entities with higher kpbs than this value"); @@ -304,8 +299,8 @@ namespace Multiplayer void MultiplayerDebugPerEntityReporter::RecordRpcReceived( AZ::EntityId entityId, const char* entityName, - Multiplayer::NetComponentId netComponentId, - Multiplayer::RpcIndex rpcId, + NetComponentId netComponentId, + RpcIndex rpcId, uint32_t totalBytes) { if (const Multiplayer::MultiplayerComponentRegistry* componentRegistry = Multiplayer::GetMultiplayerComponentRegistry()) @@ -323,69 +318,66 @@ namespace Multiplayer void MultiplayerDebugPerEntityReporter::UpdateDebugOverlay() { - if (net_DebugNetworkEntity_Bandwidth) + m_networkEntitiesTraffic.clear(); + + for (AZStd::pair& entityPair : m_receivingEntityReports) { - m_networkEntitiesTraffic.clear(); - - 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) - { - m_networkEntitiesTraffic[entityPair.first].m_name = entityPair.second.GetEntityName(); - m_networkEntitiesTraffic[entityPair.first].m_up = entityPair.second.GetKbitsPerSecond(); - } - - //get debug display interface for the viewport - 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(); - - for (AZStd::pair& networkEntity : m_networkEntitiesTraffic) - { - if (networkEntity.second.m_down < net_DebugNetworkEntity_ShowAboveKbps && networkEntity.second.m_up < net_DebugNetworkEntity_ShowAboveKbps) - { - continue; - } - - if (networkEntity.second.m_down > net_DebugNetworkEntity_WarnAboveKbps || networkEntity.second.m_up > net_DebugNetworkEntity_WarnAboveKbps) - { - m_debugDisplay->SetColor(net_DebugNetworkEntity_WarningColor); - } - else - { - m_debugDisplay->SetColor(net_DebugNetworkEntity_BelowWarningColor); - } - - if (networkEntity.second.m_down > net_DebugNetworkEntity_ShowAboveKbps && networkEntity.second.m_up > net_DebugNetworkEntity_ShowAboveKbps) - { - azsprintf(m_statusBuffer, "[%s] %.0f down / %0.f up (kbps)", networkEntity.second.m_name, - networkEntity.second.m_down, networkEntity.second.m_up); - } - else if (networkEntity.second.m_down > net_DebugNetworkEntity_ShowAboveKbps) - { - azsprintf(m_statusBuffer, "[%s] %.0f down (kbps)", networkEntity.second.m_name, networkEntity.second.m_down); - } - else - { - azsprintf(m_statusBuffer, "[%s] %.0f up (kbps)", networkEntity.second.m_name, networkEntity.second.m_up); - } - - AZ::Vector3 entityPosition = AZ::Vector3::CreateZero(); - constexpr bool centerText = true; - AZ::TransformBus::EventResult(entityPosition, networkEntity.first, &AZ::TransformBus::Events::GetWorldTranslation); - m_debugDisplay->DrawTextLabel(entityPosition, 1.0f, m_statusBuffer, centerText, 0, 0); - } - - m_debugDisplay->SetState(stateBefore); + m_networkEntitiesTraffic[entityPair.first].m_name = entityPair.second.GetEntityName(); + m_networkEntitiesTraffic[entityPair.first].m_down = entityPair.second.GetKbitsPerSecond(); } + + for (AZStd::pair& entityPair : m_sendingEntityReports) + { + m_networkEntitiesTraffic[entityPair.first].m_name = entityPair.second.GetEntityName(); + m_networkEntitiesTraffic[entityPair.first].m_up = entityPair.second.GetKbitsPerSecond(); + } + + //get debug display interface for the viewport + 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(); + + for (AZStd::pair& networkEntity : m_networkEntitiesTraffic) + { + if (networkEntity.second.m_down < net_DebugNetworkEntity_ShowAboveKbps && networkEntity.second.m_up < net_DebugNetworkEntity_ShowAboveKbps) + { + continue; + } + + if (networkEntity.second.m_down > net_DebugNetworkEntity_WarnAboveKbps || networkEntity.second.m_up > net_DebugNetworkEntity_WarnAboveKbps) + { + m_debugDisplay->SetColor(net_DebugNetworkEntity_WarningColor); + } + else + { + m_debugDisplay->SetColor(net_DebugNetworkEntity_BelowWarningColor); + } + + if (networkEntity.second.m_down > net_DebugNetworkEntity_ShowAboveKbps && networkEntity.second.m_up > net_DebugNetworkEntity_ShowAboveKbps) + { + azsprintf(m_statusBuffer, "[%s] %.0f down / %0.f up (kbps)", networkEntity.second.m_name, + networkEntity.second.m_down, networkEntity.second.m_up); + } + else if (networkEntity.second.m_down > net_DebugNetworkEntity_ShowAboveKbps) + { + azsprintf(m_statusBuffer, "[%s] %.0f down (kbps)", networkEntity.second.m_name, networkEntity.second.m_down); + } + else + { + azsprintf(m_statusBuffer, "[%s] %.0f up (kbps)", networkEntity.second.m_name, networkEntity.second.m_up); + } + + AZ::Vector3 entityPosition = AZ::Vector3::CreateZero(); + constexpr bool centerText = true; + AZ::TransformBus::EventResult(entityPosition, networkEntity.first, &AZ::TransformBus::Events::GetWorldTranslation); + m_debugDisplay->DrawTextLabel(entityPosition, 1.0f, m_statusBuffer, centerText, 0, 0); + } + + m_debugDisplay->SetState(stateBefore); } } diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h index d6ceaaf04c..8a33bc78ee 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h @@ -11,7 +11,6 @@ #include #include -#include #include #include #include @@ -66,7 +65,7 @@ namespace Multiplayer float m_down = 0.f; }; - AZStd::fixed_unordered_map m_networkEntitiesTraffic; + AZStd::unordered_map m_networkEntitiesTraffic; AzFramework::DebugDisplayRequests* m_debugDisplay = nullptr; }; diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp index 03d79025f7..f892ee9724 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp @@ -13,6 +13,11 @@ #include #include +void OnDebugNetworkEntity_ShowBandwidth_Changed(const bool& showBandwidth); + +AZ_CVAR(bool, net_DebugNetworkEntity_ShowBandwidth, false, &OnDebugNetworkEntity_ShowBandwidth_Changed, AZ::ConsoleFunctorFlags::Null, + "If true, prints bandwidth values over entities that use a considerable amount of network traffic"); + namespace Multiplayer { void MultiplayerDebugSystemComponent::Reflect(AZ::ReflectContext* context) @@ -53,11 +58,20 @@ namespace Multiplayer #endif } - void MultiplayerDebugSystemComponent::OnImGuiInitialize() + void MultiplayerDebugSystemComponent::ShowEntityBandwidthDebugOverlay() { m_reporter = AZStd::make_unique(); } + void MultiplayerDebugSystemComponent::HideEntityBandwidthDebugOverlay() + { + m_reporter.reset(); + } + + void MultiplayerDebugSystemComponent::OnImGuiInitialize() + { + } + #ifdef IMGUI_ENABLED void MultiplayerDebugSystemComponent::OnImGuiMainMenuUpdate() { @@ -327,15 +341,32 @@ namespace Multiplayer if (m_displayPerEntityStats) { - //ImGui::SetNextWindowSize({500, 400}); + // This overrides @net_DebugNetworkEntity_ShowBandwidth value if (ImGui::Begin("Multiplayer Per Entity Stats", &m_displayPerEntityStats, ImGuiWindowFlags_AlwaysAutoResize)) { if (m_reporter) { m_reporter->OnImGuiUpdate(); } + else + { + ShowEntityBandwidthDebugOverlay(); + } } } } #endif } + +void OnDebugNetworkEntity_ShowBandwidth_Changed(const bool& showBandwidth) +{ + if (showBandwidth) + { + AZ::Interface::Get()->ShowEntityBandwidthDebugOverlay(); + } + else + { + AZ::Interface::Get()->HideEntityBandwidthDebugOverlay(); + } +} + diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h index a7f76e075a..87b238c79b 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h @@ -9,7 +9,9 @@ #pragma once #include +#include #include +#include #ifdef IMGUI_ENABLED # include @@ -20,6 +22,7 @@ namespace Multiplayer { class MultiplayerDebugSystemComponent final : public AZ::Component + , public AZ::Interface::Registrar #ifdef IMGUI_ENABLED , public ImGui::ImGuiUpdateListenerBus::Handler #endif @@ -30,7 +33,7 @@ namespace Multiplayer static void Reflect(AZ::ReflectContext* context); static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); - static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatbile); + static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); ~MultiplayerDebugSystemComponent() override = default; @@ -40,6 +43,12 @@ namespace Multiplayer void Deactivate() override; //! @} + //! IMultiplayerDebugSystem overrides + //! @{ + void ShowEntityBandwidthDebugOverlay() override; + void HideEntityBandwidthDebugOverlay() override; + //! @} + #ifdef IMGUI_ENABLED //! ImGui::ImGuiUpdateListenerBus overrides //! @{ diff --git a/Gems/Multiplayer/Code/multiplayer_files.cmake b/Gems/Multiplayer/Code/multiplayer_files.cmake index 7392ea6856..0b2adb1530 100644 --- a/Gems/Multiplayer/Code/multiplayer_files.cmake +++ b/Gems/Multiplayer/Code/multiplayer_files.cmake @@ -8,6 +8,7 @@ set(FILES Include/Multiplayer/IMultiplayer.h + Include/Multiplayer/IMultiplayerDebug.h Include/Multiplayer/IMultiplayerTools.h Include/Multiplayer/MultiplayerConstants.h Include/Multiplayer/MultiplayerStats.h From 0620f6dff3267d2a5efda4ee89babd064083c562 Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Mon, 2 Aug 2021 19:06:02 -0400 Subject: [PATCH 09/13] Minor refactoring Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- .../Source/Debug/MultiplayerDebugByteReporter.cpp | 3 --- .../Source/Debug/MultiplayerDebugByteReporter.h | 5 ----- .../Debug/MultiplayerDebugSystemComponent.cpp | 14 +++++++++----- .../Source/Debug/MultiplayerDebugSystemComponent.h | 2 ++ 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp index 38a1a27dcd..361f9d943d 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp @@ -169,7 +169,6 @@ namespace Multiplayer m_currentComponentReport = nullptr; } - m_gdeDirtyBytes.ReportAggregateBytes(); MultiplayerDebugByteReporter::ReportAggregateBytes(); } @@ -183,7 +182,6 @@ namespace Multiplayer } SetEntityName(other.GetEntityName()); - m_gdeDirtyBytes.Combine(other.m_gdeDirtyBytes); } void MultiplayerDebugEntityReporter::Reset() @@ -191,7 +189,6 @@ namespace Multiplayer MultiplayerDebugByteReporter::Reset(); m_componentReports.clear(); - m_gdeDirtyBytes.Reset(); } AZStd::map& MultiplayerDebugEntityReporter::GetComponentReports() diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.h index 934c6f3aac..279f7fb360 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.h +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.h @@ -58,8 +58,6 @@ namespace Multiplayer using Report = AZStd::pair; AZStd::vector GetFieldReports(); - AZStd::size_t GetTotalDirtyBits() const { return m_componentDirtyBytes.GetTotalBytes(); } - float GetAvgDirtyBits() const { return m_componentDirtyBytes.GetAverageBytes(); } void Combine(const MultiplayerDebugComponentReporter& other); @@ -87,13 +85,10 @@ namespace Multiplayer } AZStd::map& GetComponentReports(); - AZStd::size_t GetTotalDirtyBits() const { return m_gdeDirtyBytes.GetTotalBytes(); } - float GetAvgDirtyBits() const { return m_gdeDirtyBytes.GetAverageBytes(); } private: MultiplayerDebugComponentReporter* m_currentComponentReport = nullptr; AZStd::map m_componentReports; - MultiplayerDebugByteReporter m_gdeDirtyBytes; AZStd::string m_entityName; }; } diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp index f892ee9724..0e015fc86d 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp @@ -341,17 +341,21 @@ namespace Multiplayer if (m_displayPerEntityStats) { - // This overrides @net_DebugNetworkEntity_ShowBandwidth value if (ImGui::Begin("Multiplayer Per Entity Stats", &m_displayPerEntityStats, ImGuiWindowFlags_AlwaysAutoResize)) { + if (ImGui::Checkbox("Show Bandwidth over Entities", &m_displayPerEntityBandwidth)) + { + // This overrides @net_DebugNetworkEntity_ShowBandwidth value + if (m_reporter == nullptr) + { + ShowEntityBandwidthDebugOverlay(); + } + } + if (m_reporter) { m_reporter->OnImGuiUpdate(); } - else - { - ShowEntityBandwidthDebugOverlay(); - } } } } diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h index 87b238c79b..9be53cca02 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h @@ -60,7 +60,9 @@ namespace Multiplayer private: bool m_displayNetworkingStats = false; bool m_displayMultiplayerStats = false; + bool m_displayPerEntityStats = false; + bool m_displayPerEntityBandwidth = false; AZStd::unique_ptr m_reporter; }; From 854e5409505c0a80dc015b67d7455125e1e6d156 Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Tue, 3 Aug 2021 12:42:48 -0400 Subject: [PATCH 10/13] Cleanup Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- .../Debug/MultiplayerDebugByteReporter.cpp | 19 +++-- .../Debug/MultiplayerDebugByteReporter.h | 8 +- .../MultiplayerDebugPerEntityReporter.cpp | 76 ++++++++++--------- .../Debug/MultiplayerDebugPerEntityReporter.h | 18 ++--- .../Debug/MultiplayerDebugSystemComponent.cpp | 15 ++-- .../Debug/MultiplayerDebugSystemComponent.h | 4 +- 6 files changed, 74 insertions(+), 66 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp index 361f9d943d..f69291013a 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp @@ -14,6 +14,11 @@ namespace Multiplayer { + MultiplayerDebugByteReporter::MultiplayerDebugByteReporter() + { + MultiplayerDebugByteReporter::Reset(); + } + void MultiplayerDebugByteReporter::ReportBytes(size_t byteSize) { m_count++; @@ -80,9 +85,9 @@ namespace Multiplayer m_lastUpdateTime = now; } - constexpr float k_bitsPerByte = 8.0f; - constexpr int k_bitsPerKilobit = 1024; - return k_bitsPerByte * m_totalBytesLastSecond / k_bitsPerKilobit; + constexpr float bitsPerByte = 8.0f; + constexpr int bitsPerKilobit = 1024; + return bitsPerByte * m_totalBytesLastSecond / bitsPerKilobit; } void MultiplayerDebugByteReporter::Combine(const MultiplayerDebugByteReporter& other) @@ -139,9 +144,9 @@ namespace Multiplayer { MultiplayerDebugByteReporter::Combine(other); - for (const auto& fieldIter : other.m_fieldReports) + for (const auto& fieldIterator : other.m_fieldReports) { - m_fieldReports[fieldIter.first].Combine(fieldIter.second); + m_fieldReports[fieldIterator.first].Combine(fieldIterator.second); } m_componentDirtyBytes.Combine(other.m_componentDirtyBytes); @@ -176,9 +181,9 @@ namespace Multiplayer { MultiplayerDebugByteReporter::Combine(other); - for (const auto& componentIter : other.m_componentReports) + for (const auto& componentIterator : other.m_componentReports) { - m_componentReports[componentIter.first].Combine(componentIter.second); + m_componentReports[componentIterator.first].Combine(componentIterator.second); } SetEntityName(other.GetEntityName()); diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.h index 279f7fb360..8f7513d5d4 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.h +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.h @@ -18,7 +18,7 @@ namespace Multiplayer class MultiplayerDebugByteReporter { public: - MultiplayerDebugByteReporter() { MultiplayerDebugByteReporter::Reset(); } + MultiplayerDebugByteReporter(); virtual ~MultiplayerDebugByteReporter() = default; void ReportBytes(size_t byteSize); @@ -48,7 +48,8 @@ namespace Multiplayer AZStd::chrono::monotonic_clock::time_point m_lastUpdateTime; }; - class MultiplayerDebugComponentReporter : public MultiplayerDebugByteReporter + class MultiplayerDebugComponentReporter final + : public MultiplayerDebugByteReporter { public: MultiplayerDebugComponentReporter() = default; @@ -66,7 +67,8 @@ namespace Multiplayer MultiplayerDebugByteReporter m_componentDirtyBytes; }; - class MultiplayerDebugEntityReporter : public MultiplayerDebugByteReporter + class MultiplayerDebugEntityReporter final + : public MultiplayerDebugByteReporter { public: MultiplayerDebugEntityReporter() = default; diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp index b0bfe097e1..adfef397b6 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.cpp @@ -17,16 +17,16 @@ #include #endif -AZ_CVAR(float, net_DebugNetworkEntity_ShowAboveKbps, 1.f, nullptr, AZ::ConsoleFunctorFlags::Null, +AZ_CVAR(float, net_DebugEntities_ShowAboveKbps, 1.f, nullptr, AZ::ConsoleFunctorFlags::Null, "Prints bandwidth on network entities with higher kpbs than this value"); -AZ_CVAR(float, net_DebugNetworkEntity_WarnAboveKbps, 10.f, nullptr, AZ::ConsoleFunctorFlags::Null, +AZ_CVAR(float, net_DebugEntities_WarnAboveKbps, 10.f, nullptr, AZ::ConsoleFunctorFlags::Null, "Prints bandwidth on network entities with higher kpbs than this value"); -AZ_CVAR(AZ::Color, net_DebugNetworkEntity_WarningColor, AZ::Colors::Red, nullptr, AZ::ConsoleFunctorFlags::Null, +AZ_CVAR(AZ::Color, net_DebugEntities_WarningColor, AZ::Colors::Red, nullptr, AZ::ConsoleFunctorFlags::Null, "If true, prints debug text over entities that use a considerable amount of network traffic"); -AZ_CVAR(AZ::Color, net_DebugNetworkEntity_BelowWarningColor, AZ::Colors::Grey, nullptr, AZ::ConsoleFunctorFlags::Null, +AZ_CVAR(AZ::Color, net_DebugEntities_BelowWarningColor, AZ::Colors::Grey, nullptr, AZ::ConsoleFunctorFlags::Null, "If true, prints debug text over entities that use a considerable amount of network traffic"); namespace Multiplayer @@ -133,7 +133,8 @@ namespace Multiplayer { RecordEntitySerializeStart(mode, entityId, entityName); }); - m_eventHandlers.m_componentSerializeEnd = decltype(m_eventHandlers.m_componentSerializeEnd)([this](AzNetworking::SerializerMode mode, Multiplayer::NetComponentId netComponentId) + m_eventHandlers.m_componentSerializeEnd = decltype(m_eventHandlers.m_componentSerializeEnd)([this](AzNetworking::SerializerMode mode, + NetComponentId netComponentId) { RecordComponentSerializeEnd(mode, netComponentId); }); @@ -141,19 +142,25 @@ namespace Multiplayer { RecordEntitySerializeStop(mode, entityId, entityName); }); - m_eventHandlers.m_propertySent = decltype(m_eventHandlers.m_propertySent)([this](Multiplayer::NetComponentId netComponentId, Multiplayer::PropertyIndex propertyId, uint32_t totalBytes) + m_eventHandlers.m_propertySent = decltype(m_eventHandlers.m_propertySent)([this](NetComponentId netComponentId, + 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) + m_eventHandlers.m_propertyReceived = decltype(m_eventHandlers.m_propertyReceived)([this](NetComponentId netComponentId, + 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) + m_eventHandlers.m_rpcSent = decltype(m_eventHandlers.m_rpcSent)([this](AZ::EntityId entityId, const char* entityName, + NetComponentId netComponentId, + 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) + m_eventHandlers.m_rpcReceived = decltype(m_eventHandlers.m_rpcReceived)([this](AZ::EntityId entityId, const char* entityName, + NetComponentId netComponentId, + RpcIndex rpcId, uint32_t totalBytes) { RecordRpcSent(entityId, entityName, netComponentId, rpcId, totalBytes); }); @@ -161,11 +168,6 @@ namespace Multiplayer GetMultiplayer()->GetStats().ConnectHandlers(m_eventHandlers); } - MultiplayerDebugPerEntityReporter::~MultiplayerDebugPerEntityReporter() - { - m_updateDebugOverlay.RemoveFromQueue(); - } - // -------------------------------------------------------------------------------------------- void MultiplayerDebugPerEntityReporter::OnImGuiUpdate() { @@ -228,7 +230,8 @@ namespace Multiplayer } } - void MultiplayerDebugPerEntityReporter::RecordComponentSerializeEnd(AzNetworking::SerializerMode mode, [[maybe_unused]] Multiplayer::NetComponentId netComponentId) + void MultiplayerDebugPerEntityReporter::RecordComponentSerializeEnd(AzNetworking::SerializerMode mode, [[maybe_unused]] NetComponentId + netComponentId) { switch (mode) { @@ -256,11 +259,11 @@ namespace Multiplayer } void MultiplayerDebugPerEntityReporter::RecordPropertySent( - Multiplayer::NetComponentId netComponentId, - Multiplayer::PropertyIndex propertyId, + NetComponentId netComponentId, + PropertyIndex propertyId, uint32_t totalBytes) { - if (const Multiplayer::MultiplayerComponentRegistry* componentRegistry = Multiplayer::GetMultiplayerComponentRegistry()) + if (const MultiplayerComponentRegistry* componentRegistry = GetMultiplayerComponentRegistry()) { m_currentSendingEntityReport.ReportField(static_cast(netComponentId), componentRegistry->GetComponentName(netComponentId), @@ -269,11 +272,11 @@ namespace Multiplayer } void MultiplayerDebugPerEntityReporter::RecordPropertyReceived( - Multiplayer::NetComponentId netComponentId, - Multiplayer::PropertyIndex propertyId, + NetComponentId netComponentId, + PropertyIndex propertyId, uint32_t totalBytes) { - if (const Multiplayer::MultiplayerComponentRegistry* componentRegistry = Multiplayer::GetMultiplayerComponentRegistry()) + if (const MultiplayerComponentRegistry* componentRegistry = GetMultiplayerComponentRegistry()) { m_currentReceivingEntityReport.ReportField(static_cast(netComponentId), componentRegistry->GetComponentName(netComponentId), @@ -281,9 +284,10 @@ namespace Multiplayer } } - void MultiplayerDebugPerEntityReporter::RecordRpcSent(AZ::EntityId entityId, const char* entityName, Multiplayer::NetComponentId netComponentId, Multiplayer::RpcIndex rpcId, uint32_t totalBytes) + void MultiplayerDebugPerEntityReporter::RecordRpcSent(AZ::EntityId entityId, const char* entityName, NetComponentId netComponentId, + RpcIndex rpcId, uint32_t totalBytes) { - if (const Multiplayer::MultiplayerComponentRegistry* componentRegistry = Multiplayer::GetMultiplayerComponentRegistry()) + if (const MultiplayerComponentRegistry* componentRegistry = GetMultiplayerComponentRegistry()) { // MultiplayerDebugByteReporter requires a RecordEntitySerializeStart(AzNetworking::SerializerMode::ReadFromObject, entityId, entityName); @@ -303,7 +307,7 @@ namespace Multiplayer RpcIndex rpcId, uint32_t totalBytes) { - if (const Multiplayer::MultiplayerComponentRegistry* componentRegistry = Multiplayer::GetMultiplayerComponentRegistry()) + if (const MultiplayerComponentRegistry* componentRegistry = GetMultiplayerComponentRegistry()) { RecordEntitySerializeStart(AzNetworking::SerializerMode::WriteToObject, entityId, entityName); @@ -320,19 +324,18 @@ namespace Multiplayer { m_networkEntitiesTraffic.clear(); + // Merging up and down traffic to provide a unified debug text per entity 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) { m_networkEntitiesTraffic[entityPair.first].m_name = entityPair.second.GetEntityName(); m_networkEntitiesTraffic[entityPair.first].m_up = entityPair.second.GetKbitsPerSecond(); } - //get debug display interface for the viewport if (m_debugDisplay == nullptr) { AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus; @@ -342,28 +345,28 @@ namespace Multiplayer const AZ::u32 stateBefore = m_debugDisplay->GetState(); - for (AZStd::pair& networkEntity : m_networkEntitiesTraffic) + for (const AZStd::pair& networkEntity : m_networkEntitiesTraffic) { - if (networkEntity.second.m_down < net_DebugNetworkEntity_ShowAboveKbps && networkEntity.second.m_up < net_DebugNetworkEntity_ShowAboveKbps) + if (networkEntity.second.m_down < net_DebugEntities_ShowAboveKbps && networkEntity.second.m_up < net_DebugEntities_ShowAboveKbps) { continue; } - if (networkEntity.second.m_down > net_DebugNetworkEntity_WarnAboveKbps || networkEntity.second.m_up > net_DebugNetworkEntity_WarnAboveKbps) + if (networkEntity.second.m_down > net_DebugEntities_WarnAboveKbps || networkEntity.second.m_up > net_DebugEntities_WarnAboveKbps) { - m_debugDisplay->SetColor(net_DebugNetworkEntity_WarningColor); + m_debugDisplay->SetColor(net_DebugEntities_WarningColor); } else { - m_debugDisplay->SetColor(net_DebugNetworkEntity_BelowWarningColor); + m_debugDisplay->SetColor(net_DebugEntities_BelowWarningColor); } - if (networkEntity.second.m_down > net_DebugNetworkEntity_ShowAboveKbps && networkEntity.second.m_up > net_DebugNetworkEntity_ShowAboveKbps) + if (networkEntity.second.m_down > net_DebugEntities_ShowAboveKbps && networkEntity.second.m_up > net_DebugEntities_ShowAboveKbps) { azsprintf(m_statusBuffer, "[%s] %.0f down / %0.f up (kbps)", networkEntity.second.m_name, networkEntity.second.m_down, networkEntity.second.m_up); } - else if (networkEntity.second.m_down > net_DebugNetworkEntity_ShowAboveKbps) + else if (networkEntity.second.m_down > net_DebugEntities_ShowAboveKbps) { azsprintf(m_statusBuffer, "[%s] %.0f down (kbps)", networkEntity.second.m_name, networkEntity.second.m_down); } @@ -373,9 +376,12 @@ namespace Multiplayer } AZ::Vector3 entityPosition = AZ::Vector3::CreateZero(); - constexpr bool centerText = true; AZ::TransformBus::EventResult(entityPosition, networkEntity.first, &AZ::TransformBus::Events::GetWorldTranslation); - m_debugDisplay->DrawTextLabel(entityPosition, 1.0f, m_statusBuffer, centerText, 0, 0); + if (entityPosition.IsZero() == false) + { + constexpr bool centerText = true; + m_debugDisplay->DrawTextLabel(entityPosition, 1.0f, m_statusBuffer, centerText, 0, 0); + } } m_debugDisplay->SetState(stateBefore); diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h index 8a33bc78ee..8a68110b93 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugPerEntityReporter.h @@ -18,34 +18,34 @@ namespace Multiplayer { /** - * \brief GridMate network live analysis tool via ImGui. + * \brief Multiplayer traffic live analysis tool via ImGui. */ class MultiplayerDebugPerEntityReporter { public: MultiplayerDebugPerEntityReporter(); - ~MultiplayerDebugPerEntityReporter(); - // main update loop + //! main update loop void OnImGuiUpdate(); //! Event handlers // @{ void RecordEntitySerializeStart(AzNetworking::SerializerMode mode, AZ::EntityId entityId, const char* entityName); - void RecordComponentSerializeEnd(AzNetworking::SerializerMode mode, Multiplayer::NetComponentId netComponentId); + void RecordComponentSerializeEnd(AzNetworking::SerializerMode mode, 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 RecordPropertySent(NetComponentId netComponentId, PropertyIndex propertyId, uint32_t totalBytes); + void RecordPropertyReceived(NetComponentId netComponentId, PropertyIndex propertyId, 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); // }@ + //! Draws bandwidth text over entities void UpdateDebugOverlay(); private: AZ::ScheduledEvent m_updateDebugOverlay; - Multiplayer::MultiplayerStats::EventHandlers m_eventHandlers; + MultiplayerStats::EventHandlers m_eventHandlers; AZStd::map m_sendingEntityReports{}; MultiplayerDebugEntityReporter m_currentSendingEntityReport; diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp index 407b6f5f2d..b6dc9573fa 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp @@ -13,9 +13,9 @@ #include #include -void OnDebugNetworkEntity_ShowBandwidth_Changed(const bool& showBandwidth); +void OnDebugEntities_ShowBandwidth_Changed(const bool& showBandwidth); -AZ_CVAR(bool, net_DebugNetworkEntity_ShowBandwidth, false, &OnDebugNetworkEntity_ShowBandwidth_Changed, AZ::ConsoleFunctorFlags::Null, +AZ_CVAR(bool, net_DebugEntities_ShowBandwidth, false, &OnDebugEntities_ShowBandwidth_Changed, AZ::ConsoleFunctorFlags::Null, "If true, prints bandwidth values over entities that use a considerable amount of network traffic"); namespace Multiplayer @@ -458,13 +458,10 @@ namespace Multiplayer { if (ImGui::Begin("Multiplayer Per Entity Stats", &m_displayPerEntityStats, ImGuiWindowFlags_AlwaysAutoResize)) { - if (ImGui::Checkbox("Show Bandwidth over Entities", &m_displayPerEntityBandwidth)) + // This overrides @net_DebugNetworkEntity_ShowBandwidth value + if (m_reporter == nullptr) { - // This overrides @net_DebugNetworkEntity_ShowBandwidth value - if (m_reporter == nullptr) - { - ShowEntityBandwidthDebugOverlay(); - } + ShowEntityBandwidthDebugOverlay(); } if (m_reporter) @@ -477,7 +474,7 @@ namespace Multiplayer #endif } -void OnDebugNetworkEntity_ShowBandwidth_Changed(const bool& showBandwidth) +void OnDebugEntities_ShowBandwidth_Changed(const bool& showBandwidth) { if (showBandwidth) { diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h index 9be53cca02..7555073f10 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h @@ -43,7 +43,7 @@ namespace Multiplayer void Deactivate() override; //! @} - //! IMultiplayerDebugSystem overrides + //! IMultiplayerDebug overrides //! @{ void ShowEntityBandwidthDebugOverlay() override; void HideEntityBandwidthDebugOverlay() override; @@ -62,8 +62,6 @@ namespace Multiplayer bool m_displayMultiplayerStats = false; bool m_displayPerEntityStats = false; - bool m_displayPerEntityBandwidth = false; - AZStd::unique_ptr m_reporter; }; } From 2118ef7a21ad2d5d80979e80d9516e9a6177a443 Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Tue, 3 Aug 2021 12:48:36 -0400 Subject: [PATCH 11/13] Preparing for PR Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayerDebug.h | 4 ++-- .../Code/Source/Debug/MultiplayerDebugSystemComponent.cpp | 4 ---- .../Code/Source/Debug/MultiplayerDebugSystemComponent.h | 1 - 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayerDebug.h b/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayerDebug.h index 384db66317..e528a44ed9 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayerDebug.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayerDebug.h @@ -19,10 +19,10 @@ namespace Multiplayer virtual ~IMultiplayerDebug() = default; - //! + //! Enables printing of debug text over entities that have significant amount of traffic. virtual void ShowEntityBandwidthDebugOverlay() = 0; - //! + //! Disables printing of debug text over entities that have significant amount of traffic. virtual void HideEntityBandwidthDebugOverlay() = 0; }; } diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp index b6dc9573fa..27a4dff485 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp @@ -63,10 +63,6 @@ namespace Multiplayer m_reporter.reset(); } - void MultiplayerDebugSystemComponent::OnImGuiInitialize() - { - } - #ifdef IMGUI_ENABLED void MultiplayerDebugSystemComponent::OnImGuiMainMenuUpdate() { diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h index 7555073f10..7b3c852f58 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h @@ -52,7 +52,6 @@ namespace Multiplayer #ifdef IMGUI_ENABLED //! ImGui::ImGuiUpdateListenerBus overrides //! @{ - void OnImGuiInitialize() override; void OnImGuiMainMenuUpdate() override; void OnImGuiUpdate() override; //! @} From 72aed355cedf9fe28e24e396c64db93a4b1946a2 Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Tue, 3 Aug 2021 12:54:32 -0400 Subject: [PATCH 12/13] Cleanup Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- .../Source/NetworkEntity/EntityReplication/EntityReplicator.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp index 457ed3eed5..4155f8813b 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp @@ -30,8 +30,6 @@ #include -#pragma optimize("", off) - namespace Multiplayer { EntityReplicator::EntityReplicator From a550827e978d97abb83c1bb4a03aaca4aa5ffdfd Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Wed, 4 Aug 2021 14:32:15 -0400 Subject: [PATCH 13/13] Addressing PR Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- .../Code/Source/Debug/MultiplayerDebugByteReporter.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp index f69291013a..45305e3b39 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugByteReporter.cpp @@ -43,7 +43,6 @@ namespace Multiplayer { if (m_count == 0) { - AZ_Warning("MultiplayerDebugByteReporter", m_totalBytes == 0, "Attempted to average bytes with a zero count."); return 0.0f; } @@ -158,7 +157,7 @@ namespace Multiplayer if (m_currentComponentReport == nullptr) { std::stringstream component; - component << "[" << std::setw(2) << std::setfill('0') << static_cast(index) << "]" << " " << componentName; + component << "[" << std::setw(2) << std::setfill('0') << aznumeric_cast(index) << "]" << " " << componentName; m_currentComponentReport = &m_componentReports[component.str().c_str()]; }