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; } }