Initial work on multiple gem multiplayer components

main
karlberg 5 years ago
parent f26d7f9301
commit c8bc5b7463

@ -15,6 +15,7 @@
#include <AzCore/RTTI/RTTI.h> #include <AzCore/RTTI/RTTI.h>
#include <AzNetworking/ConnectionLayer/IConnection.h> #include <AzNetworking/ConnectionLayer/IConnection.h>
#include <AzNetworking/DataStructures/ByteBuffer.h> #include <AzNetworking/DataStructures/ByteBuffer.h>
#include <Include/MultiplayerStats.h>
namespace AzNetworking namespace AzNetworking
{ {
@ -23,21 +24,6 @@ namespace AzNetworking
namespace Multiplayer namespace Multiplayer
{ {
struct MultiplayerStats
{
uint64_t m_entityCount = 0;
uint64_t m_clientConnectionCount = 0;
uint64_t m_serverConnectionCount = 0;
uint64_t m_propertyUpdatesSent = 0;
uint64_t m_propertyUpdatesSentBytes = 0;
uint64_t m_propertyUpdatesRecv = 0;
uint64_t m_propertyUpdatesRecvBytes = 0;
uint64_t m_rpcsSent = 0;
uint64_t m_rpcsSentBytes = 0;
uint64_t m_rpcsRecv = 0;
uint64_t m_rpcsRecvBytes = 0;
};
//! Collection of types of Multiplayer Connections //! Collection of types of Multiplayer Connections
enum class MultiplayerAgentType enum class MultiplayerAgentType
{ {

@ -0,0 +1,147 @@
/*
* 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 <Include/MultiplayerStats.h>
namespace Multiplayer
{
void MultiplayerStats::ReserveComponentStats(uint16_t netComponentId, uint16_t propertyCount, uint16_t rpcCount)
{
if (m_componentStats.size() <= netComponentId)
{
m_componentStats.resize(netComponentId + 1);
}
m_componentStats[netComponentId].m_propertyUpdatesSent.resize(propertyCount);
m_componentStats[netComponentId].m_propertyUpdatesRecv.resize(propertyCount);
m_componentStats[netComponentId].m_rpcsSent.resize(rpcCount);
m_componentStats[netComponentId].m_rpcsRecv.resize(rpcCount);
}
void MultiplayerStats::RecordPropertySent(uint16_t netComponentId, uint16_t propertyId, uint32_t totalBytes)
{
m_componentStats[netComponentId].m_propertyUpdatesSent[propertyId].m_totalCalls++;
m_componentStats[netComponentId].m_propertyUpdatesSent[propertyId].m_totalBytes += totalBytes;
m_componentStats[netComponentId].m_propertyUpdatesSent[propertyId].m_callHistory[m_recordMetricIndex]++;
m_componentStats[netComponentId].m_propertyUpdatesSent[propertyId].m_byteHistory[m_recordMetricIndex] += totalBytes;
}
void MultiplayerStats::RecordPropertyReceived(uint16_t netComponentId, uint16_t propertyId, uint32_t totalBytes)
{
m_componentStats[netComponentId].m_propertyUpdatesRecv[propertyId].m_totalCalls++;
m_componentStats[netComponentId].m_propertyUpdatesRecv[propertyId].m_totalBytes += totalBytes;
m_componentStats[netComponentId].m_propertyUpdatesRecv[propertyId].m_callHistory[m_recordMetricIndex]++;
m_componentStats[netComponentId].m_propertyUpdatesRecv[propertyId].m_byteHistory[m_recordMetricIndex] += totalBytes;
}
void MultiplayerStats::RecordRpcSent(uint16_t netComponentId, uint16_t rpcId, uint32_t totalBytes)
{
m_componentStats[netComponentId].m_rpcsSent[rpcId].m_totalCalls++;
m_componentStats[netComponentId].m_rpcsSent[rpcId].m_totalBytes += totalBytes;
m_componentStats[netComponentId].m_rpcsSent[rpcId].m_callHistory[m_recordMetricIndex]++;
m_componentStats[netComponentId].m_rpcsSent[rpcId].m_byteHistory[m_recordMetricIndex] += totalBytes;
}
void MultiplayerStats::RecordRpcReceived(uint16_t netComponentId, uint16_t rpcId, uint32_t totalBytes)
{
m_componentStats[netComponentId].m_rpcsRecv[rpcId].m_totalCalls++;
m_componentStats[netComponentId].m_rpcsRecv[rpcId].m_totalBytes += totalBytes;
m_componentStats[netComponentId].m_rpcsRecv[rpcId].m_callHistory[m_recordMetricIndex]++;
m_componentStats[netComponentId].m_rpcsRecv[rpcId].m_byteHistory[m_recordMetricIndex] += totalBytes;
}
void MultiplayerStats::TickStats(AZ::TimeMs metricFrameTimeMs)
{
m_totalHistoryTimeMs = metricFrameTimeMs * static_cast<AZ::TimeMs>(RingbufferSamples);
m_recordMetricIndex = ++m_recordMetricIndex % RingbufferSamples;
}
static void CombineMetrics(MultiplayerStats::Metric& outArg1, const MultiplayerStats::Metric& arg2)
{
outArg1.m_totalCalls += arg2.m_totalCalls;
outArg1.m_totalBytes += arg2.m_totalBytes;
for (uint32_t index = 0; index < MultiplayerStats::RingbufferSamples; ++index)
{
outArg1.m_callHistory[index] += arg2.m_callHistory[index];
outArg1.m_byteHistory[index] += arg2.m_byteHistory[index];
}
}
static MultiplayerStats::Metric SumMetricVector(const AZStd::vector<MultiplayerStats::Metric>& metricVector)
{
MultiplayerStats::Metric result;
for (AZStd::size_t index = 0; index < metricVector.size(); ++index)
{
CombineMetrics(result, metricVector[index]);
}
return result;
}
MultiplayerStats::Metric MultiplayerStats::CalculateComponentPropertyUpdateSentMetrics(uint16_t netComponentId) const
{
return SumMetricVector(m_componentStats[netComponentId].m_propertyUpdatesSent);
}
MultiplayerStats::Metric MultiplayerStats::CalculateComponentPropertyUpdateRecvMetrics(uint16_t netComponentId) const
{
return SumMetricVector(m_componentStats[netComponentId].m_propertyUpdatesRecv);
}
MultiplayerStats::Metric MultiplayerStats::CalculateComponentRpcsSentMetrics(uint16_t netComponentId) const
{
return SumMetricVector(m_componentStats[netComponentId].m_rpcsSent);
}
MultiplayerStats::Metric MultiplayerStats::CalculateComponentRpcsRecvMetrics(uint16_t netComponentId) const
{
return SumMetricVector(m_componentStats[netComponentId].m_rpcsRecv);
}
MultiplayerStats::Metric MultiplayerStats::CalculateTotalPropertyUpdateSentMetrics() const
{
Metric result;
for (AZStd::size_t index = 0; index < m_componentStats.size(); ++index)
{
CombineMetrics(result, CalculateComponentPropertyUpdateSentMetrics(index));
}
return result;
}
MultiplayerStats::Metric MultiplayerStats::CalculateTotalPropertyUpdateRecvMetrics() const
{
Metric result;
for (AZStd::size_t index = 0; index < m_componentStats.size(); ++index)
{
CombineMetrics(result, CalculateComponentPropertyUpdateRecvMetrics(index));
}
return result;
}
MultiplayerStats::Metric MultiplayerStats::CalculateTotalRpcsSentMetrics() const
{
Metric result;
for (AZStd::size_t index = 0; index < m_componentStats.size(); ++index)
{
CombineMetrics(result, CalculateComponentRpcsSentMetrics(index));
}
return result;
}
MultiplayerStats::Metric MultiplayerStats::CalculateTotalRpcsRecvMetrics() const
{
Metric result;
for (AZStd::size_t index = 0; index < m_componentStats.size(); ++index)
{
CombineMetrics(result, CalculateComponentRpcsRecvMetrics(index));
}
return result;
}
}

@ -0,0 +1,70 @@
/*
* 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 <AzCore/Time/ITime.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/containers/fixed_vector.h>
namespace AzNetworking
{
class INetworkInterface;
}
namespace Multiplayer
{
struct MultiplayerStats
{
uint64_t m_entityCount = 0;
uint64_t m_clientConnectionCount = 0;
uint64_t m_serverConnectionCount = 0;
uint64_t m_recordMetricIndex = 0;
AZ::TimeMs m_totalHistoryTimeMs = AZ::TimeMs{ 0 };
static const uint32_t RingbufferSamples = 32;
using MetricRingbuffer = AZStd::fixed_vector<uint64_t, RingbufferSamples>;
struct Metric
{
uint64_t m_totalCalls = 0;
uint64_t m_totalBytes = 0;
MetricRingbuffer m_callHistory;
MetricRingbuffer m_byteHistory;
};
struct ComponentStats
{
AZStd::vector<Metric> m_propertyUpdatesSent;
AZStd::vector<Metric> m_propertyUpdatesRecv;
AZStd::vector<Metric> m_rpcsSent;
AZStd::vector<Metric> m_rpcsRecv;
};
AZStd::vector<ComponentStats> m_componentStats;
void ReserveComponentStats(uint16_t netComponentId, uint16_t propertyCount, uint16_t rpcCount);
void RecordPropertySent(uint16_t netComponentId, uint16_t propertyId, uint32_t totalBytes);
void RecordPropertyReceived(uint16_t netComponentId, uint16_t propertyId, uint32_t totalBytes);
void RecordRpcSent(uint16_t netComponentId, uint16_t rpcId, uint32_t totalBytes);
void RecordRpcReceived(uint16_t netComponentId, uint16_t rpcId, uint32_t totalBytes);
void TickStats(AZ::TimeMs metricFrameTimeMs);
Metric CalculateComponentPropertyUpdateSentMetrics(uint16_t netComponentId) const;
Metric CalculateComponentPropertyUpdateRecvMetrics(uint16_t netComponentId) const;
Metric CalculateComponentRpcsSentMetrics(uint16_t netComponentId) const;
Metric CalculateComponentRpcsRecvMetrics(uint16_t netComponentId) const;
Metric CalculateTotalPropertyUpdateSentMetrics() const;
Metric CalculateTotalPropertyUpdateRecvMetrics() const;
Metric CalculateTotalRpcsSentMetrics() const;
Metric CalculateTotalRpcsRecvMetrics() const;
};
}

@ -22,12 +22,16 @@ namespace {{ Namespace }}
void RegisterMultiplayerComponents() void RegisterMultiplayerComponents()
{ {
Multiplayer::MultiplayerComponentRegistry* multiplayerComponentRegistry = GetMultiplayerComponentRegistry(); Multiplayer::MultiplayerComponentRegistry* multiplayerComponentRegistry = GetMultiplayerComponentRegistry();
Multiplayer::MultiplayerStats& stats = AZ::Interface<Multiplayer::IMultiplayer>::Get()->GetStats();
{% for Component in dataFiles %} {% for Component in dataFiles %}
{% set ComponentName = Component.attrib['Name'] %} {% set ComponentName = Component.attrib['Name'] %}
{% set ComponentBaseName = ComponentName %} {% set ComponentBaseName = ComponentName %}
{% if Component.attrib['OverrideComponent']|booleanTrue %} {% if Component.attrib['OverrideComponent']|booleanTrue %}
{% set ComponentBaseName = ComponentName + "Base" %} {% set ComponentBaseName = ComponentName + "Base" %}
{% endif %} {% endif %}
{% set NetworkInputCount = Component.findall('NetworkInput') | len %}
{% set NetworkPropertyCount = Component.findall('NetworkProperty') | len %}
{% set RpcCount = Component.findall('RemoteProcedure') | len %}
{ {
Multiplayer::MultiplayerComponentRegistry::ComponentData componentData; Multiplayer::MultiplayerComponentRegistry::ComponentData componentData;
componentData.m_gemName = AZ::Name("{{ Namespace }}"); componentData.m_gemName = AZ::Name("{{ Namespace }}");
@ -35,6 +39,7 @@ namespace {{ Namespace }}
componentData.m_componentPropertyNameLookupFunction = {{ ComponentBaseName }}::GetNetworkPropertyName; componentData.m_componentPropertyNameLookupFunction = {{ ComponentBaseName }}::GetNetworkPropertyName;
componentData.m_componentRpcNameLookupFunction = {{ ComponentBaseName }}::GetRpcName; componentData.m_componentRpcNameLookupFunction = {{ ComponentBaseName }}::GetRpcName;
{{ ComponentBaseName }}::s_netComponentId = multiplayerComponentRegistry->RegisterMultiplayerComponent(componentData); {{ ComponentBaseName }}::s_netComponentId = multiplayerComponentRegistry->RegisterMultiplayerComponent(componentData);
stats.ReserveComponentStats(static_cast<uint16_t>({{ ComponentBaseName }}::s_netComponentId), static_cast<uint16_t>({{ NetworkPropertyCount }}), static_cast<uint16_t>({{ RpcCount }}));
} }
{% endfor %} {% endfor %}
} }

@ -508,7 +508,8 @@ bool {{ ClassName }}::Serialize{{ AutoComponentMacros.GetNetPropertiesSetName(Re
static_cast<int32_t>({{ AutoComponentMacros.GetNetPropertiesQualifiedPropertyDirtyEnum(Component.attrib['Name'], ReplicateFrom, ReplicateTo, Property) }}), static_cast<int32_t>({{ AutoComponentMacros.GetNetPropertiesQualifiedPropertyDirtyEnum(Component.attrib['Name'], ReplicateFrom, ReplicateTo, Property) }}),
m_{{ LowerFirst(Property.attrib['Name']) }}, m_{{ LowerFirst(Property.attrib['Name']) }},
"{{ Property.attrib['Name'] }}", "{{ Property.attrib['Name'] }}",
GetNetComponentId(), static_cast<uint16_t>(GetNetComponentId()),
static_cast<uint16_t>({{ UpperFirst(Component.attrib['Name']) }}Internal::NetworkProperties::{{ UpperFirst(Property.attrib['Name']) }}),
stats stats
); );
{% endif %} {% endif %}
@ -646,6 +647,16 @@ enum class RemoteProcedure
MAX MAX
}; };
{% endmacro %}
{% macro DeclareNetworkPropertyEnumerations(Component) %}
enum class NetworkProperties
{
{% for NetworkProperty in Component.iter('NetworkProperty') %}
{{ UpperFirst(NetworkProperty.attrib['Name']) }},
{% endfor %}
MAX
};
{% endmacro %} {% endmacro %}
{# {#
@ -881,6 +892,9 @@ m_{{ LowerFirst(Property.attrib['Name']) }} = m_{{ LowerFirst(Property.attrib['N
{% else %} {% else %}
{% set ControllerBaseName = ControllerName %} {% set ControllerBaseName = ControllerName %}
{% endif %} {% endif %}
{% set NetworkInputCount = Component.findall('NetworkInput') | len %}
{% set NetworkPropertyCount = Component.findall('NetworkProperty') | len %}
{% set RpcCount = Component.findall('RemoteProcedure') | len %}
#include "{{ includeFile }}" #include "{{ includeFile }}"
#include <AzCore/Console/IConsole.h> #include <AzCore/Console/IConsole.h>
#include <AzCore/Console/ILogger.h> #include <AzCore/Console/ILogger.h>
@ -906,6 +920,7 @@ namespace {{ Component.attrib['Namespace'] }}
namespace {{ UpperFirst(Component.attrib['Name']) }}Internal namespace {{ UpperFirst(Component.attrib['Name']) }}Internal
{ {
{{ DeclareRemoteProcedureEnumerations(Component)|indent(8) }} {{ DeclareRemoteProcedureEnumerations(Component)|indent(8) }}
{{ DeclareNetworkPropertyEnumerations(Component)|indent(8) }}
{{ DefineNetworkPropertyDirtyEnumeration(Component, ClassType, 'Authority', 'Authority')|indent(8) }} {{ DefineNetworkPropertyDirtyEnumeration(Component, ClassType, 'Authority', 'Authority')|indent(8) }}
{{ DefineNetworkPropertyDirtyEnumeration(Component, ClassType, 'Authority', 'Client')|indent(8) }} {{ DefineNetworkPropertyDirtyEnumeration(Component, ClassType, 'Authority', 'Client')|indent(8) }}
{{ DefineNetworkPropertyDirtyEnumeration(Component, ClassType, 'Authority', 'Server')|indent(8) }} {{ DefineNetworkPropertyDirtyEnumeration(Component, ClassType, 'Authority', 'Server')|indent(8) }}
@ -1383,12 +1398,32 @@ namespace {{ Component.attrib['Namespace'] }}
{% endif %} {% endif %}
const char* {{ ComponentBaseName }}::GetNetworkPropertyName([[maybe_unused]] uint16_t propertyIndex) const char* {{ ComponentBaseName }}::GetNetworkPropertyName([[maybe_unused]] uint16_t propertyIndex)
{ {
return ""; {% if NetworkPropertyCount > 0 %}
const {{ UpperFirst(Component.attrib['Name']) }}Internal::NetworkProperties propertyId = static_cast<{{ UpperFirst(Component.attrib['Name']) }}Internal::NetworkProperties>(propertyIndex);
switch (propertyId)
{
{% for NetworkProperty in Component.iter('NetworkProperty') %}
case {{ UpperFirst(Component.attrib['Name']) }}Internal::NetworkProperties::{{ UpperFirst(NetworkProperty.attrib['Name']) }}:
return "{{ UpperFirst(NetworkProperty.attrib['Name']) }}";
{% endfor %}
}
{% endif %}
return "Unknown network property";
} }
const char* {{ ComponentBaseName }}::GetRpcName([[maybe_unused]] uint16_t rpcIndex) const char* {{ ComponentBaseName }}::GetRpcName([[maybe_unused]] uint16_t rpcIndex)
{ {
return ""; {% if RpcCount > 0 %}
const {{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure rpcId = static_cast<{{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure>(rpcIndex);
switch (rpcId)
{
{% for RemoteProcedure in Component.iter('RemoteProcedure') %}
case {{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure::{{ RemoteProcedure.attrib['Name'] }}:
return "{{ RemoteProcedure.attrib['Name'] }}";
{% endfor %}
}
{% endif %}
return "Unknown Rpc";
} }
{% endfor %} {% endfor %}
} }

@ -104,13 +104,14 @@ namespace Multiplayer
template <typename TYPE> template <typename TYPE>
inline void SerializeNetworkPropertyHelper inline void SerializeNetworkPropertyHelper
( (
AzNetworking::ISerializer& serializer, AzNetworking::ISerializer& serializer,
bool modifyRecord, bool modifyRecord,
AzNetworking::FixedSizeBitsetView& bitset, AzNetworking::FixedSizeBitsetView& bitset,
int32_t bitIndex, int32_t bitIndex,
TYPE& value, TYPE& value,
const char* name, const char* name,
[[maybe_unused]] NetComponentId componentId, uint16_t componentId,
uint16_t propertyId,
MultiplayerStats& stats MultiplayerStats& stats
) )
{ {
@ -131,13 +132,11 @@ namespace Multiplayer
{ {
if (modifyRecord) if (modifyRecord)
{ {
stats.m_propertyUpdatesRecv++; stats.RecordPropertyReceived(componentId, propertyId, updateSize);
stats.m_propertyUpdatesRecvBytes += updateSize;
} }
else else
{ {
stats.m_propertyUpdatesSent++; stats.RecordPropertySent(componentId, propertyId, updateSize);
stats.m_propertyUpdatesSentBytes += updateSize;
} }
} }
} }

@ -95,26 +95,72 @@ namespace Multiplayer
} }
} }
void ComputePerSecondValues(const MultiplayerStats& stats, const MultiplayerStats::Metric& metric, float& outCallsPerSecond, float& outBytesPerSecond)
{
uint64_t summedCalls = 0;
uint64_t summedBytes = 0;
for (uint32_t index = 0; index < MultiplayerStats::RingbufferSamples; ++index)
{
summedCalls += metric.m_callHistory[index];
summedBytes += metric.m_byteHistory[index];
}
const float totalTimeSeconds = static_cast<float>(stats.m_totalHistoryTimeMs) / 1000.0f;
outCallsPerSecond = static_cast<float>(summedCalls) / totalTimeSeconds;
outBytesPerSecond = static_cast<float>(summedBytes) / totalTimeSeconds;
}
void DrawMetricTitle(const ImVec4& entryColour)
{
ImGui::Columns(6);
ImGui::TextColored(entryColour, "Name"); ImGui::NextColumn();
ImGui::TextColored(entryColour, "Category"); ImGui::NextColumn();
ImGui::TextColored(entryColour, "Total Calls"); ImGui::NextColumn();
ImGui::TextColored(entryColour, "Total Bytes"); ImGui::NextColumn();
ImGui::TextColored(entryColour, "Calls/Sec"); ImGui::NextColumn();
ImGui::TextColored(entryColour, "Bytes/Sec"); ImGui::NextColumn();
}
void DrawMetricRow(const char* name, const char* category, const ImVec4& entryColour, const MultiplayerStats& stats, const MultiplayerStats::Metric& metric)
{
float callsPerSecond = 0.0f;
float bytesPerSecond = 0.0f;
ComputePerSecondValues(stats, metric, callsPerSecond, bytesPerSecond);
ImGui::TextColored(entryColour, "%s", name); ImGui::NextColumn();
ImGui::TextColored(entryColour, "%s", category); ImGui::NextColumn();
ImGui::TextColored(entryColour, "%10llu", aznumeric_cast<AZ::u64>(metric.m_totalCalls)); ImGui::NextColumn();
ImGui::TextColored(entryColour, "%10llu", aznumeric_cast<AZ::u64>(metric.m_totalBytes)); ImGui::NextColumn();
ImGui::TextColored(entryColour, "%10.2f", callsPerSecond); ImGui::NextColumn();
ImGui::TextColored(entryColour, "%10.2f", bytesPerSecond); ImGui::NextColumn();
}
void MultiplayerDebugSystemComponent::OnImGuiUpdate() void MultiplayerDebugSystemComponent::OnImGuiUpdate()
{ {
const ImVec4 titleColour = ImColor(1.00f, 0.80f, 0.12f);
const ImVec4 entryColour = ImColor(0.32f, 1.00f, 1.00f);
if (m_displayStats) if (m_displayStats)
{ {
if (ImGui::Begin("Multiplayer Stats", &m_displayStats, ImGuiWindowFlags_HorizontalScrollbar)) if (ImGui::Begin("Multiplayer Stats", &m_displayStats, ImGuiWindowFlags_HorizontalScrollbar))
{ {
IMultiplayer* multiplayer = AZ::Interface<IMultiplayer>::Get(); IMultiplayer* multiplayer = AZ::Interface<IMultiplayer>::Get();
Multiplayer::MultiplayerStats& stats = multiplayer->GetStats(); const Multiplayer::MultiplayerStats& stats = multiplayer->GetStats();
ImGui::Text("Multiplayer operating in %s mode", GetEnumString(multiplayer->GetAgentType())); ImGui::Text("Multiplayer operating in %s mode", GetEnumString(multiplayer->GetAgentType()));
ImGui::Text("Total networked entities: %llu", aznumeric_cast<AZ::u64>(stats.m_entityCount)); ImGui::Text("Total networked entities: %llu", aznumeric_cast<AZ::u64>(stats.m_entityCount));
ImGui::Text("Total client connections: %llu", aznumeric_cast<AZ::u64>(stats.m_clientConnectionCount)); ImGui::Text("Total client connections: %llu", aznumeric_cast<AZ::u64>(stats.m_clientConnectionCount));
ImGui::Text("Total server connections: %llu", aznumeric_cast<AZ::u64>(stats.m_serverConnectionCount)); ImGui::Text("Total server connections: %llu", aznumeric_cast<AZ::u64>(stats.m_serverConnectionCount));
ImGui::Text("Total property updates sent: %llu", aznumeric_cast<AZ::u64>(stats.m_propertyUpdatesSent));
ImGui::Text("Total property updates sent bytes: %llu", aznumeric_cast<AZ::u64>(stats.m_propertyUpdatesSentBytes)); const MultiplayerStats::Metric propertyUpdatesSent = stats.CalculateTotalPropertyUpdateSentMetrics();
ImGui::Text("Total property updates received: %llu", aznumeric_cast<AZ::u64>(stats.m_propertyUpdatesRecv)); const MultiplayerStats::Metric propertyUpdatesRecv = stats.CalculateTotalPropertyUpdateRecvMetrics();
ImGui::Text("Total property updates received bytes: %llu", aznumeric_cast<AZ::u64>(stats.m_propertyUpdatesRecvBytes)); const MultiplayerStats::Metric rpcsSent = stats.CalculateTotalRpcsSentMetrics();
ImGui::Text("Total RPCs sent: %llu", aznumeric_cast<AZ::u64>(stats.m_rpcsSent)); const MultiplayerStats::Metric rpcsRecv = stats.CalculateTotalRpcsRecvMetrics();
ImGui::Text("Total RPCs sent bytes: %llu", aznumeric_cast<AZ::u64>(stats.m_rpcsSentBytes));
ImGui::Text("Total RPCs received: %llu", aznumeric_cast<AZ::u64>(stats.m_rpcsRecv)); DrawMetricTitle(titleColour);
ImGui::Text("Total RPCs received bytes: %llu", aznumeric_cast<AZ::u64>(stats.m_rpcsRecvBytes)); DrawMetricRow("Total", "PropertyUpdates Sent", entryColour, stats, propertyUpdatesSent);
DrawMetricRow("Total", "PropertyUpdates Received", entryColour, stats, propertyUpdatesRecv);
DrawMetricRow("Total", "Rpcs Sent", entryColour, stats, rpcsSent);
DrawMetricRow("Total", "Rpcs Received", entryColour, stats, rpcsRecv);
} }
ImGui::End(); ImGui::End();
} }

@ -52,5 +52,7 @@ namespace Multiplayer
#endif #endif
private: private:
bool m_displayStats = false; bool m_displayStats = false;
bool m_displayPropertyStats = false;
bool m_displayRpcStats = false;
}; };
} }

@ -513,14 +513,20 @@ namespace Multiplayer
AZLOG_INFO("Total networked entities: %llu", aznumeric_cast<AZ::u64>(stats.m_entityCount)); AZLOG_INFO("Total networked entities: %llu", aznumeric_cast<AZ::u64>(stats.m_entityCount));
AZLOG_INFO("Total client connections: %llu", aznumeric_cast<AZ::u64>(stats.m_clientConnectionCount)); AZLOG_INFO("Total client connections: %llu", aznumeric_cast<AZ::u64>(stats.m_clientConnectionCount));
AZLOG_INFO("Total server connections: %llu", aznumeric_cast<AZ::u64>(stats.m_serverConnectionCount)); AZLOG_INFO("Total server connections: %llu", aznumeric_cast<AZ::u64>(stats.m_serverConnectionCount));
AZLOG_INFO("Total property updates sent: %llu", aznumeric_cast<AZ::u64>(stats.m_propertyUpdatesSent));
AZLOG_INFO("Total property updates sent bytes: %llu", aznumeric_cast<AZ::u64>(stats.m_propertyUpdatesSentBytes)); const MultiplayerStats::Metric propertyUpdatesSent = stats.CalculateTotalPropertyUpdateSentMetrics();
AZLOG_INFO("Total property updates received: %llu", aznumeric_cast<AZ::u64>(stats.m_propertyUpdatesRecv)); const MultiplayerStats::Metric propertyUpdatesRecv = stats.CalculateTotalPropertyUpdateRecvMetrics();
AZLOG_INFO("Total property updates received bytes: %llu", aznumeric_cast<AZ::u64>(stats.m_propertyUpdatesRecvBytes)); const MultiplayerStats::Metric rpcsSent = stats.CalculateTotalRpcsSentMetrics();
AZLOG_INFO("Total RPCs sent: %llu", aznumeric_cast<AZ::u64>(stats.m_rpcsSent)); const MultiplayerStats::Metric rpcsRecv = stats.CalculateTotalRpcsRecvMetrics();
AZLOG_INFO("Total RPCs sent bytes: %llu", aznumeric_cast<AZ::u64>(stats.m_rpcsSentBytes));
AZLOG_INFO("Total RPCs received: %llu", aznumeric_cast<AZ::u64>(stats.m_rpcsRecv)); AZLOG_INFO("Total property updates sent: %llu", aznumeric_cast<AZ::u64>(propertyUpdatesSent.m_totalCalls));
AZLOG_INFO("Total RPCs received bytes: %llu", aznumeric_cast<AZ::u64>(stats.m_rpcsRecvBytes)); AZLOG_INFO("Total property updates sent bytes: %llu", aznumeric_cast<AZ::u64>(propertyUpdatesSent.m_totalBytes));
AZLOG_INFO("Total property updates received: %llu", aznumeric_cast<AZ::u64>(propertyUpdatesRecv.m_totalCalls));
AZLOG_INFO("Total property updates received bytes: %llu", aznumeric_cast<AZ::u64>(propertyUpdatesRecv.m_totalBytes));
AZLOG_INFO("Total RPCs sent: %llu", aznumeric_cast<AZ::u64>(rpcsSent.m_totalCalls));
AZLOG_INFO("Total RPCs sent bytes: %llu", aznumeric_cast<AZ::u64>(rpcsSent.m_totalBytes));
AZLOG_INFO("Total RPCs received: %llu", aznumeric_cast<AZ::u64>(rpcsRecv.m_totalCalls));
AZLOG_INFO("Total RPCs received bytes: %llu", aznumeric_cast<AZ::u64>(rpcsRecv.m_totalBytes));
} }
void MultiplayerSystemComponent::OnConsoleCommandInvoked void MultiplayerSystemComponent::OnConsoleCommandInvoked

@ -449,8 +449,7 @@ namespace Multiplayer
{ {
// Received rpc metrics, log rpc sent, number of bytes, and the componentId/rpcId for bandwidth metrics // Received rpc metrics, log rpc sent, number of bytes, and the componentId/rpcId for bandwidth metrics
MultiplayerStats& stats = AZ::Interface<IMultiplayer>::Get()->GetStats(); MultiplayerStats& stats = AZ::Interface<IMultiplayer>::Get()->GetStats();
stats.m_rpcsSent++; stats.RecordRpcSent(static_cast<uint16_t>(entityRpcMessage.GetComponentId()), entityRpcMessage.GetRpcMessageType(), entityRpcMessage.GetEstimatedSerializeSize());
stats.m_rpcsSentBytes += entityRpcMessage.GetEstimatedSerializeSize();
m_replicationManager.AddDeferredRpcMessage(entityRpcMessage); m_replicationManager.AddDeferredRpcMessage(entityRpcMessage);
} }
@ -633,8 +632,7 @@ namespace Multiplayer
{ {
// Received rpc metrics, log rpc received, time spent, number of bytes, and the componentId/rpcId for bandwidth metrics // Received rpc metrics, log rpc received, time spent, number of bytes, and the componentId/rpcId for bandwidth metrics
MultiplayerStats& stats = AZ::Interface<IMultiplayer>::Get()->GetStats(); MultiplayerStats& stats = AZ::Interface<IMultiplayer>::Get()->GetStats();
stats.m_rpcsRecv++; stats.RecordRpcReceived(static_cast<uint16_t>(entityRpcMessage.GetComponentId()), entityRpcMessage.GetRpcMessageType(), entityRpcMessage.GetEstimatedSerializeSize());
stats.m_rpcsRecvBytes += entityRpcMessage.GetEstimatedSerializeSize();
if (!m_netBindComponent) if (!m_netBindComponent)
{ {

@ -11,6 +11,8 @@
set(FILES set(FILES
Include/IMultiplayer.h Include/IMultiplayer.h
Include/MultiplayerStats.cpp
Include/MultiplayerStats.h
Source/Multiplayer_precompiled.cpp Source/Multiplayer_precompiled.cpp
Source/Multiplayer_precompiled.h Source/Multiplayer_precompiled.h
Source/MultiplayerSystemComponent.cpp Source/MultiplayerSystemComponent.cpp

Loading…
Cancel
Save