Merge branch 'development' of https://github.com/o3de/o3de into mp_lerp_jitter

This commit is contained in:
puvvadar
2021-07-29 09:58:07 -07:00
141 changed files with 5169 additions and 8892 deletions
@@ -23,36 +23,30 @@ namespace Multiplayer
->Version(1);
}
}
void MultiplayerDebugSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC_CE("MultiplayerDebugSystemComponent"));
}
void MultiplayerDebugSystemComponent::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required)
{
;
}
void MultiplayerDebugSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatbile)
{
incompatbile.push_back(AZ_CRC_CE("MultiplayerDebugSystemComponent"));
}
void MultiplayerDebugSystemComponent::Activate()
{
#ifdef IMGUI_ENABLED
ImGui::ImGuiUpdateListenerBus::Handler::BusConnect();
#endif
}
void MultiplayerDebugSystemComponent::Deactivate()
{
#ifdef IMGUI_ENABLED
ImGui::ImGuiUpdateListenerBus::Handler::BusDisconnect();
#endif
}
#ifdef IMGUI_ENABLED
void MultiplayerDebugSystemComponent::OnImGuiMainMenuUpdate()
{
@@ -63,7 +57,6 @@ namespace Multiplayer
ImGui::EndMenu();
}
}
void AccumulatePerSecondValues(const MultiplayerStats& stats, const MultiplayerStats::Metric& metric, float& outCallsPerSecond, float& outBytesPerSecond)
{
uint64_t summedCalls = 0;
@@ -80,8 +73,9 @@ namespace Multiplayer
bool DrawMetricsRow(const char* name, bool expandable, uint64_t totalCalls, uint64_t totalBytes, float callsPerSecond, float bytesPerSecond)
{
const ImGuiTreeNodeFlags flags = expandable ? ImGuiTreeNodeFlags_SpanFullWidth
: (ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth);
const ImGuiTreeNodeFlags flags = expandable
? ImGuiTreeNodeFlags_SpanFullWidth
: (ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth);
ImGui::TableNextRow();
ImGui::TableNextColumn();
const bool open = ImGui::TreeNodeEx(name, flags);
@@ -95,14 +89,12 @@ namespace Multiplayer
ImGui::Text("%11.2f", bytesPerSecond);
return open;
}
bool DrawSummaryRow(const char* name, const MultiplayerStats& stats)
{
const MultiplayerStats::Metric propertyUpdatesSent = stats.CalculateTotalPropertyUpdateSentMetrics();
const MultiplayerStats::Metric propertyUpdatesRecv = stats.CalculateTotalPropertyUpdateRecvMetrics();
const MultiplayerStats::Metric rpcsSent = stats.CalculateTotalRpcsSentMetrics();
const MultiplayerStats::Metric rpcsRecv = stats.CalculateTotalRpcsRecvMetrics();
const uint64_t totalCalls = propertyUpdatesSent.m_totalCalls + propertyUpdatesRecv.m_totalCalls + rpcsSent.m_totalCalls + rpcsRecv.m_totalCalls;
const uint64_t totalBytes = propertyUpdatesSent.m_totalBytes + propertyUpdatesRecv.m_totalBytes + rpcsSent.m_totalBytes + rpcsRecv.m_totalBytes;
float callsPerSecond = 0.0f;
@@ -111,17 +103,14 @@ namespace Multiplayer
AccumulatePerSecondValues(stats, propertyUpdatesRecv, callsPerSecond, bytesPerSecond);
AccumulatePerSecondValues(stats, rpcsSent, callsPerSecond, bytesPerSecond);
AccumulatePerSecondValues(stats, rpcsRecv, callsPerSecond, bytesPerSecond);
return DrawMetricsRow(name, true, totalCalls, totalBytes, callsPerSecond, bytesPerSecond);
}
bool DrawComponentRow(const char* name, const MultiplayerStats& stats, NetComponentId netComponentId)
{
const MultiplayerStats::Metric propertyUpdatesSent = stats.CalculateComponentPropertyUpdateSentMetrics(netComponentId);
const MultiplayerStats::Metric propertyUpdatesRecv = stats.CalculateComponentPropertyUpdateRecvMetrics(netComponentId);
const MultiplayerStats::Metric rpcsSent = stats.CalculateComponentRpcsSentMetrics(netComponentId);
const MultiplayerStats::Metric rpcsRecv = stats.CalculateComponentRpcsRecvMetrics(netComponentId);
const uint64_t totalCalls = propertyUpdatesSent.m_totalCalls + propertyUpdatesRecv.m_totalCalls + rpcsSent.m_totalCalls + rpcsRecv.m_totalCalls;
const uint64_t totalBytes = propertyUpdatesSent.m_totalBytes + propertyUpdatesRecv.m_totalBytes + rpcsSent.m_totalBytes + rpcsRecv.m_totalBytes;
float callsPerSecond = 0.0f;
@@ -130,10 +119,8 @@ namespace Multiplayer
AccumulatePerSecondValues(stats, propertyUpdatesRecv, callsPerSecond, bytesPerSecond);
AccumulatePerSecondValues(stats, rpcsSent, callsPerSecond, bytesPerSecond);
AccumulatePerSecondValues(stats, rpcsRecv, callsPerSecond, bytesPerSecond);
return DrawMetricsRow(name, true, totalCalls, totalBytes, callsPerSecond, bytesPerSecond);
}
void DrawComponentDetails(const MultiplayerStats& stats, NetComponentId netComponentId)
{
MultiplayerComponentRegistry* componentRegistry = GetMultiplayerComponentRegistry();
@@ -158,7 +145,6 @@ namespace Multiplayer
ImGui::TreePop();
}
}
{
const MultiplayerStats::Metric metric = stats.CalculateComponentPropertyUpdateRecvMetrics(netComponentId);
float callsPerSecond = 0.0f;
@@ -180,7 +166,6 @@ namespace Multiplayer
ImGui::TreePop();
}
}
{
const MultiplayerStats::Metric metric = stats.CalculateComponentRpcsSentMetrics(netComponentId);
float callsPerSecond = 0.0f;
@@ -202,7 +187,6 @@ namespace Multiplayer
ImGui::TreePop();
}
}
{
const MultiplayerStats::Metric metric = stats.CalculateComponentRpcsRecvMetrics(netComponentId);
float callsPerSecond = 0.0f;
@@ -226,45 +210,218 @@ namespace Multiplayer
}
}
void MultiplayerDebugSystemComponent::OnImGuiUpdate()
void DrawNetworkingStats()
{
const float TEXT_BASE_WIDTH = ImGui::CalcTextSize("A").x;
const float TEXT_BASE_HEIGHT = ImGui::GetTextLineHeightWithSpacing();
const ImGuiTableFlags flags = ImGuiTableFlags_BordersV
| ImGuiTableFlags_BordersOuterH
| ImGuiTableFlags_Resizable
| ImGuiTableFlags_RowBg
| ImGuiTableFlags_NoBordersInBody;
const ImGuiTreeNodeFlags nodeFlags = (ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth);
AzNetworking::INetworking* networking = AZ::Interface<AzNetworking::INetworking>::Get();
ImGui::Text("Total sockets monitored by TcpListenThread: %u", networking->GetTcpListenThreadSocketCount());
ImGui::Text("Total time spent updating TcpListenThread: %lld", aznumeric_cast<AZ::s64>(networking->GetTcpListenThreadUpdateTime()));
ImGui::Text("Total sockets monitored by UdpReaderThread: %u", networking->GetUdpReaderThreadSocketCount());
ImGui::Text("Total time spent updating UdpReaderThread: %lld", aznumeric_cast<AZ::s64>(networking->GetUdpReaderThreadUpdateTime()));
ImGui::NewLine();
for (auto& networkInterface : networking->GetNetworkInterfaces())
{
if (ImGui::CollapsingHeader(networkInterface.second->GetName().GetCStr()))
{
const char* protocol = networkInterface.second->GetType() == AzNetworking::ProtocolType::Tcp ? "Tcp" : "Udp";
const char* trustZone = networkInterface.second->GetTrustZone() == AzNetworking::TrustZone::ExternalClientToServer ? "ExternalClientToServer" : "InternalServerToServer";
const uint32_t port = aznumeric_cast<uint32_t>(networkInterface.second->GetPort());
ImGui::Text("%sNetworkInterface open to %s on port %u", protocol, trustZone, port);
if (ImGui::BeginTable("", 2, flags))
{
const AzNetworking::NetworkInterfaceMetrics& metrics = networkInterface.second->GetMetrics();
ImGui::TableSetupColumn("Stat", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f);
ImGui::TableHeadersRow();
ImGui::TableNextRow(); ImGui::TableNextColumn();
ImGui::Text("Total time spent updating (ms)");
ImGui::TableNextColumn();
ImGui::Text("%lld", aznumeric_cast<AZ::s64>(metrics.m_updateTimeMs));
ImGui::TableNextRow(); ImGui::TableNextColumn();
ImGui::Text("Total number of connections");
ImGui::TableNextColumn();
ImGui::Text("%llu", aznumeric_cast<AZ::u64>(metrics.m_connectionCount));
ImGui::TableNextRow(); ImGui::TableNextColumn();
ImGui::Text("Total send time (ms)");
ImGui::TableNextColumn();
ImGui::Text("%lld", aznumeric_cast<AZ::s64>(metrics.m_sendTimeMs));
ImGui::TableNextRow(); ImGui::TableNextColumn();
ImGui::Text("Total sent packets");
ImGui::TableNextColumn();
ImGui::Text("%llu", aznumeric_cast<AZ::s64>(metrics.m_sendPackets));
ImGui::TableNextRow(); ImGui::TableNextColumn();
ImGui::Text("Total sent bytes after compression");
ImGui::TableNextColumn();
ImGui::Text("%llu", aznumeric_cast<AZ::u64>(metrics.m_sendBytes));
ImGui::TableNextRow(); ImGui::TableNextColumn();
ImGui::Text("Total sent bytes before compression");
ImGui::TableNextColumn();
ImGui::Text("%llu", aznumeric_cast<AZ::u64>(metrics.m_sendBytesUncompressed));
ImGui::TableNextRow(); ImGui::TableNextColumn();
ImGui::Text("Total sent compressed packets without benefit");
ImGui::TableNextColumn();
ImGui::Text("%llu", aznumeric_cast<AZ::u64>(metrics.m_sendCompressedPacketsNoGain));
ImGui::TableNextRow(); ImGui::TableNextColumn();
ImGui::Text("Total gain from packet compression");
ImGui::TableNextColumn();
ImGui::Text("%lld", aznumeric_cast<AZ::s64>(metrics.m_sendBytesCompressedDelta));
ImGui::TableNextRow(); ImGui::TableNextColumn();
ImGui::Text("Total packets resent");
ImGui::TableNextColumn();
ImGui::Text("%llu", aznumeric_cast<AZ::u64>(metrics.m_resentPackets));
ImGui::TableNextRow(); ImGui::TableNextColumn();
ImGui::Text("Total receive time (ms)");
ImGui::TableNextColumn();
ImGui::Text("%lld", aznumeric_cast<AZ::s64>(metrics.m_recvTimeMs));
ImGui::TableNextRow(); ImGui::TableNextColumn();
ImGui::Text("Total received packets");
ImGui::TableNextColumn();
ImGui::Text("%llu", aznumeric_cast<AZ::u64>(metrics.m_recvPackets));
ImGui::TableNextRow(); ImGui::TableNextColumn();
ImGui::Text("Total received bytes after compression");
ImGui::TableNextColumn();
ImGui::Text("%llu", aznumeric_cast<AZ::u64>(metrics.m_recvBytes));
ImGui::TableNextRow(); ImGui::TableNextColumn();
ImGui::Text("Total received bytes before compression");
ImGui::TableNextColumn();
ImGui::Text("%llu", aznumeric_cast<AZ::u64>(metrics.m_recvBytesUncompressed));
ImGui::TableNextRow(); ImGui::TableNextColumn();
ImGui::Text("Total packets discarded due to load");
ImGui::TableNextColumn();
ImGui::Text("%llu", aznumeric_cast<AZ::u64>(metrics.m_discardedPackets));
ImGui::EndTable();
}
if (ImGui::BeginTable("", 7, flags))
{
// The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On
ImGui::TableSetupColumn("RemoteAddr", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("Conn. Id", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 6.0f);
ImGui::TableSetupColumn("Send (Bps)", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 10.0f);
ImGui::TableSetupColumn("Recv (Bps)", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 10.0f);
ImGui::TableSetupColumn("RTT (ms)", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 8.0f);
ImGui::TableSetupColumn("% Lost", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 8.0f);
ImGui::TableSetupColumn("Debug Settings", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 32.0f);
ImGui::TableHeadersRow();
auto displayConnectionRow = [](AzNetworking::IConnection& connection)
{
ImGui::PushID(&connection);
const AzNetworking::ConnectionMetrics& metrics = connection.GetMetrics();
const AzNetworking::IpAddress::IpString remoteAddr = connection.GetRemoteAddress().GetString();
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TreeNodeEx(remoteAddr.c_str(), nodeFlags);
ImGui::TableNextColumn();
ImGui::Text("%5llu", aznumeric_cast<AZ::u64>(connection.GetConnectionId()));
ImGui::TableNextColumn();
ImGui::Text("%9.2f", metrics.m_sendDatarate.GetBytesPerSecond());
ImGui::TableNextColumn();
ImGui::Text("%9.2f", metrics.m_recvDatarate.GetBytesPerSecond());
ImGui::TableNextColumn();
ImGui::Text("%7.2f", metrics.m_connectionRtt.GetRoundTripTimeSeconds() * 1000.0f);
ImGui::TableNextColumn();
ImGui::Text("%7.2f", metrics.m_sendDatarate.GetLossRatePercent());
ImGui::TableNextColumn();
{
AzNetworking::ConnectionQuality& quality = connection.GetConnectionQuality();
int32_t latency = aznumeric_cast<int32_t>(quality.m_latencyMs);
int32_t variance = aznumeric_cast<int32_t>(quality.m_varianceMs);
ImGui::SliderInt("Loss %", &quality.m_lossPercentage, 0, 100);
if (ImGui::SliderInt("Latency(ms)", &latency, 0, 3000))
{
quality.m_latencyMs = AZ::TimeMs{ latency };
}
if (ImGui::SliderInt("Jitter(ms)", &variance, 0, 1000))
{
quality.m_varianceMs = AZ::TimeMs{ variance };
}
}
ImGui::PopID();
};
networkInterface.second->GetConnectionSet().VisitConnections(displayConnectionRow);
ImGui::EndTable();
}
}
ImGui::NewLine();
}
ImGui::End();
}
void DrawMultiplayerStats()
{
const float TEXT_BASE_WIDTH = ImGui::CalcTextSize("A").x;
const float TEXT_BASE_HEIGHT = ImGui::GetTextLineHeightWithSpacing();
IMultiplayer* multiplayer = AZ::Interface<IMultiplayer>::Get();
MultiplayerComponentRegistry* componentRegistry = GetMultiplayerComponentRegistry();
const Multiplayer::MultiplayerStats& stats = multiplayer->GetStats();
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 client connections: %llu", aznumeric_cast<AZ::u64>(stats.m_clientConnectionCount));
ImGui::Text("Total server connections: %llu", aznumeric_cast<AZ::u64>(stats.m_serverConnectionCount));
ImGui::NewLine();
static ImGuiTableFlags flags = ImGuiTableFlags_BordersV
| ImGuiTableFlags_BordersOuterH
| ImGuiTableFlags_Resizable
| ImGuiTableFlags_RowBg
| ImGuiTableFlags_NoBordersInBody;
if (ImGui::BeginTable("", 5, flags))
{
// The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("Total Calls", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f);
ImGui::TableSetupColumn("Total Bytes", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f);
ImGui::TableSetupColumn("Calls/Sec", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f);
ImGui::TableSetupColumn("Bytes/Sec", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f);
ImGui::TableHeadersRow();
if (DrawSummaryRow("Totals", stats))
{
for (AZStd::size_t index = 0; index < stats.m_componentStats.size(); ++index)
{
const NetComponentId netComponentId = aznumeric_cast<NetComponentId>(index);
using StringLabel = AZStd::fixed_string<128>;
const StringLabel gemName = componentRegistry->GetComponentGemName(netComponentId);
const StringLabel componentName = componentRegistry->GetComponentName(netComponentId);
const StringLabel label = gemName + "::" + componentName;
if (DrawComponentRow(label.c_str(), stats, netComponentId))
{
DrawComponentDetails(stats, netComponentId);
ImGui::TreePop();
}
}
}
ImGui::EndTable();
ImGui::NewLine();
}
ImGui::End();
}
void MultiplayerDebugSystemComponent::OnImGuiUpdate()
{
if (m_displayNetworkingStats)
{
if (ImGui::Begin("Networking Stats", &m_displayNetworkingStats, ImGuiWindowFlags_None))
{
AzNetworking::INetworking* networking = AZ::Interface<AzNetworking::INetworking>::Get();
ImGui::Text("Total sockets monitored by TcpListenThread: %u", networking->GetTcpListenThreadSocketCount());
ImGui::Text("Total time spent updating TcpListenThread: %lld", aznumeric_cast<AZ::s64>(networking->GetTcpListenThreadUpdateTime()));
ImGui::Text("Total sockets monitored by UdpReaderThread: %u", networking->GetUdpReaderThreadSocketCount());
ImGui::Text("Total time spent updating UdpReaderThread: %lld", aznumeric_cast<AZ::s64>(networking->GetUdpReaderThreadUpdateTime()));
for (auto& networkInterface : networking->GetNetworkInterfaces())
{
const char* protocol = networkInterface.second->GetType() == AzNetworking::ProtocolType::Tcp ? "Tcp" : "Udp";
const char* trustZone = networkInterface.second->GetTrustZone() == AzNetworking::TrustZone::ExternalClientToServer ? "ExternalClientToServer" : "InternalServerToServer";
const uint32_t port = aznumeric_cast<uint32_t>(networkInterface.second->GetPort());
ImGui::Text("%sNetworkInterface: %s - open to %s on port %u", protocol, networkInterface.second->GetName().GetCStr(), trustZone, port);
const AzNetworking::NetworkInterfaceMetrics& metrics = networkInterface.second->GetMetrics();
ImGui::Text(" - Total time spent updating in milliseconds: %lld", aznumeric_cast<AZ::s64>(metrics.m_updateTimeMs));
ImGui::Text(" - Total number of connections: %llu", aznumeric_cast<AZ::u64>(metrics.m_connectionCount));
ImGui::Text(" - Total send time in milliseconds: %lld", aznumeric_cast<AZ::s64>(metrics.m_sendTimeMs));
ImGui::Text(" - Total sent packets: %llu", aznumeric_cast<AZ::s64>(metrics.m_sendPackets));
ImGui::Text(" - Total sent bytes after compression: %llu", aznumeric_cast<AZ::u64>(metrics.m_sendBytes));
ImGui::Text(" - Total sent bytes before compression: %llu", aznumeric_cast<AZ::u64>(metrics.m_sendBytesUncompressed));
ImGui::Text(" - Total sent compressed packets without benefit: %llu", aznumeric_cast<AZ::u64>(metrics.m_sendCompressedPacketsNoGain));
ImGui::Text(" - Total gain from packet compression: %lld", aznumeric_cast<AZ::s64>(metrics.m_sendBytesCompressedDelta));
ImGui::Text(" - Total packets resent: %llu", aznumeric_cast<AZ::u64>(metrics.m_resentPackets));
ImGui::Text(" - Total receive time in milliseconds: %lld", aznumeric_cast<AZ::s64>(metrics.m_recvTimeMs));
ImGui::Text(" - Total received packets: %llu", aznumeric_cast<AZ::u64>(metrics.m_recvPackets));
ImGui::Text(" - Total received bytes after compression: %llu", aznumeric_cast<AZ::u64>(metrics.m_recvBytes));
ImGui::Text(" - Total received bytes before compression: %llu", aznumeric_cast<AZ::u64>(metrics.m_recvBytesUncompressed));
ImGui::Text(" - Total packets discarded due to load: %llu", aznumeric_cast<AZ::u64>(metrics.m_discardedPackets));
}
DrawNetworkingStats();
}
}
@@ -272,50 +429,7 @@ namespace Multiplayer
{
if (ImGui::Begin("Multiplayer Stats", &m_displayMultiplayerStats, ImGuiWindowFlags_None))
{
IMultiplayer* multiplayer = AZ::Interface<IMultiplayer>::Get();
MultiplayerComponentRegistry* componentRegistry = GetMultiplayerComponentRegistry();
const Multiplayer::MultiplayerStats& stats = multiplayer->GetStats();
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 client connections: %llu", aznumeric_cast<AZ::u64>(stats.m_clientConnectionCount));
ImGui::Text("Total server connections: %llu", aznumeric_cast<AZ::u64>(stats.m_serverConnectionCount));
ImGui::NewLine();
static ImGuiTableFlags flags = ImGuiTableFlags_BordersV
| ImGuiTableFlags_BordersOuterH
| ImGuiTableFlags_Resizable
| ImGuiTableFlags_RowBg
| ImGuiTableFlags_NoBordersInBody;
if (ImGui::BeginTable("", 5, flags))
{
// The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("Total Calls", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f);
ImGui::TableSetupColumn("Total Bytes", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f);
ImGui::TableSetupColumn("Calls/Sec", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f);
ImGui::TableSetupColumn("Bytes/Sec", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f);
ImGui::TableHeadersRow();
if (DrawSummaryRow("Totals", stats))
{
for (AZStd::size_t index = 0; index < stats.m_componentStats.size(); ++index)
{
const NetComponentId netComponentId = aznumeric_cast<NetComponentId>(index);
using StringLabel = AZStd::fixed_string<128>;
const StringLabel gemName = componentRegistry->GetComponentGemName(netComponentId);
const StringLabel componentName = componentRegistry->GetComponentName(netComponentId);
const StringLabel label = gemName + "::" + componentName;
if (DrawComponentRow(label.c_str(), stats, netComponentId))
{
DrawComponentDetails(stats, netComponentId);
ImGui::TreePop();
}
}
}
ImGui::EndTable();
}
ImGui::End();
DrawMultiplayerStats();
}
}
}
@@ -69,19 +69,24 @@ namespace Multiplayer
{
using namespace AzNetworking;
AZ_CVAR(uint16_t, cl_clientport, 0, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The port to bind to for game traffic when connecting to a remote host, a value of 0 will select any available port");
AZ_CVAR(AZ::CVarFixedString, cl_serveraddr, AZ::CVarFixedString(LocalHost), nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The address of the remote server or host to connect to");
AZ_CVAR(AZ::CVarFixedString, cl_serverpassword, "", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Optional server password");
AZ_CVAR(uint16_t, cl_clientport, 0, nullptr, AZ::ConsoleFunctorFlags::DontReplicate,
"The port to bind to for game traffic when connecting to a remote host, a value of 0 will select any available port");
AZ_CVAR(AZ::CVarFixedString, cl_serveraddr, AZ::CVarFixedString(LocalHost), nullptr, AZ::ConsoleFunctorFlags::DontReplicate,
"The address of the remote server or host to connect to");
AZ_CVAR(uint16_t, cl_serverport, DefaultServerPort, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The port of the remote host to connect to for game traffic");
AZ_CVAR(uint16_t, sv_port, DefaultServerPort, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The port that this multiplayer gem will bind to for game traffic");
AZ_CVAR(AZ::CVarFixedString, sv_map, "nolevel", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The map the server should load");
AZ_CVAR(AZ::CVarFixedString, sv_gamerules, "norules", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "GameRules server works with");
AZ_CVAR(ProtocolType, sv_protocol, ProtocolType::Udp, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "This flag controls whether we use TCP or UDP for game networking");
AZ_CVAR(bool, sv_isDedicated, true, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Whether the host command creates an independent or client hosted server");
AZ_CVAR(bool, sv_isTransient, true, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Whether a dedicated server shuts down if all existing connections disconnect.");
AZ_CVAR(AZ::TimeMs, cl_defaultNetworkEntityActivationTimeSliceMs, AZ::TimeMs{ 0 }, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Max Ms to use to activate entities coming from the network, 0 means instantiate everything");
AZ_CVAR(AZ::TimeMs, cl_defaultNetworkEntityActivationTimeSliceMs, AZ::TimeMs{ 0 }, nullptr, AZ::ConsoleFunctorFlags::DontReplicate,
"Max Ms to use to activate entities coming from the network, 0 means instantiate everything");
AZ_CVAR(AZ::TimeMs, sv_serverSendRateMs, AZ::TimeMs{ 50 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Minimum number of milliseconds between each network update");
AZ_CVAR(AZ::CVarFixedString, sv_defaultPlayerSpawnAsset, "prefabs/player.network.spawnable", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The default spawnable to use when a new player connects");
AZ_CVAR(AZ::CVarFixedString, sv_defaultPlayerSpawnAsset, "prefabs/player.network.spawnable", nullptr, AZ::ConsoleFunctorFlags::DontReplicate,
"The default spawnable to use when a new player connects");
AZ_CVAR(float, cl_renderTickBlendBase, 0.15f, nullptr, AZ::ConsoleFunctorFlags::Null,
"The base used for blending between network updates, 0.1 will be quite linear, 0.2 or 0.3 will "
"slow down quicker and may be better suited to connections with highly variable latency");
void MultiplayerSystemComponent::Reflect(AZ::ReflectContext* context)
{
@@ -546,7 +551,7 @@ namespace Multiplayer
if ((GetAgentType() == MultiplayerAgentType::Client) && (packet.GetHostFrameId() > m_lastReplicatedHostFrameId))
{
// Update client to latest server time
m_renderBlendFactor = 0.0f;
m_tickFactor = 0.0f;
m_lastReplicatedHostTimeMs = packet.GetHostTimeMs();
m_lastReplicatedHostFrameId = packet.GetHostFrameId();
m_networkTime.AlterTime(m_lastReplicatedHostFrameId, m_lastReplicatedHostTimeMs, AzNetworking::InvalidConnectionId);
@@ -854,10 +859,18 @@ namespace Multiplayer
void MultiplayerSystemComponent::TickVisibleNetworkEntities(float deltaTime, float serverRateSeconds)
{
m_tickFactor += deltaTime / serverRateSeconds;
// Linear close to the origin, but asymptote at y = 1
const float targetAdjustBlend = AZStd::clamp(deltaTime / serverRateSeconds, 0.0f, 1.0f);
m_renderBlendFactor = 1.0f - (std::pow(0.2f, m_renderBlendFactor + targetAdjustBlend));
AZLOG(NET_Blending, "Computed blend factor of %0.2f using a frametime of %0.2f and a serverTickRate of %0.2f", m_renderBlendFactor, deltaTime, serverRateSeconds);
const float renderBlendFactor = AZStd::clamp(1.0f - (std::pow(cl_renderTickBlendBase, m_tickFactor)), 0.0f, 1.0f);
AZLOG
(
NET_Blending,
"Computed blend factor of %0.3f using a tick factor of %0.3f, a frametime of %0.3f and a serverTickRate of %0.3f",
renderBlendFactor,
m_tickFactor,
deltaTime,
serverRateSeconds
);
if (Camera::ActiveCameraRequestBus::HasHandlers())
{
@@ -900,7 +913,7 @@ namespace Multiplayer
for (NetBindComponent* netBindComponent : gatheredEntities)
{
netBindComponent->NotifyPreRender(deltaTime, m_renderBlendFactor);
netBindComponent->NotifyPreRender(deltaTime, renderBlendFactor);
}
}
else
@@ -912,7 +925,7 @@ namespace Multiplayer
NetBindComponent* netBindComponent = entity->FindComponent<NetBindComponent>();
if (netBindComponent != nullptr)
{
netBindComponent->NotifyPreRender(deltaTime, m_renderBlendFactor);
netBindComponent->NotifyPreRender(deltaTime, renderBlendFactor);
}
}
}
@@ -156,7 +156,7 @@ namespace Multiplayer
HostFrameId m_lastReplicatedHostFrameId = HostFrameId(0);
double m_serverSendAccumulator = 0.0;
float m_renderBlendFactor = 0.0f;
float m_tickFactor = 0.0f;
#if !defined(AZ_RELEASE_BUILD)
MultiplayerEditorConnection m_editorConnectionListener;