You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/CryEngine/CryNetwork/GridMate/NetworkGridmateDebug.cpp

773 lines
29 KiB
C++

/*
* 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 "CryNetwork_precompiled.h"
#include "NetworkGridMate.h"
#include "NetworkGridmateDebug.h"
#include "Replicas/EntityReplica.h"
#include <AzCore/PlatformIncl.h>
#include <CryPath.h>
#include <ILevelSystem.h>
#include <stdio.h>
#include <IRenderer.h>
#include <ITextModeConsole.h>
namespace
{
/**
* Helper for debug text printing, with colorization and formatting options.
*
* Example:
*
* DebugTextHelper text( gEnv->pRenderer, 100, 100 ); // At screen pos (100,100)
* text.SetAutoNewlined( true );
* text.SetMonospaced( true );
* text.SetColor( Col_Yellow );
* text.SetSize( 2.f );
* text.AddText( "This is a yellow title" );
* text.SetSize( 1.5f );
* text.AddText( "This is some detail." );
*/
class DebugTextHelper
{
public:
static const int kTextModeRowSize = 10;
static const int kTextModeColSize = 10;
static const int kTextModeColCount = 128; // WINDOWS_CONSOLE_WIDTH
static const int kTextModeRowCount = 48; // WINDOWS_CONSOLE_HEIGHT - 2
DebugTextHelper(IRenderer* r,
float x = 0.f, float y = 0.f,
float fontSize = 1.5f,
ColorF defaultColor = Col_White)
: m_pos(x, y, 0.f)
, m_defaultColor(defaultColor)
, m_fontSize(fontSize)
, m_flags(kFlag_AutoNewline | kFlag_Monospaced | kFlag_TextModeConsole)
, m_renderer(r)
{
}
~DebugTextHelper() {};
enum
{
kMaxLabelSize = 512
};
void AddText(const char* format, ...)
{
va_list argList;
char buffer[kMaxLabelSize];
va_start(argList, format);
const int len = vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, format, argList);
buffer[sizeof(buffer) - 1] = '\0';
va_end(argList);
AddText(m_defaultColor, buffer);
}
void AddText(ColorF color, const char* format, ...)
{
va_list argList;
char buffer[kMaxLabelSize];
va_start(argList, format);
const int len = vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, format, argList);
buffer[sizeof(buffer) - 1] = '\0';
va_end(argList);
const uint32 drawFlags = IsMonospaced() ?
(eDrawText_2D | eDrawText_800x600 | eDrawText_FixedSize | eDrawText_Monospace) :
(eDrawText_2D | eDrawText_800x600 | eDrawText_FixedSize);
m_renderer->Draw2dLabelWithFlags(m_pos.x, m_pos.y, m_fontSize, color, drawFlags, buffer);
if (m_flags & kFlag_TextModeConsole)
{
if (ITextModeConsole* textConsole = gEnv->pSystem->GetITextModeConsole())
{
const int posX = static_cast<int>(m_pos.x) / kTextModeColSize;
const int posY = static_cast<int>(m_pos.y) / kTextModeRowSize;
if (posX < kTextModeColCount && posY < kTextModeRowCount)
{
textConsole->PutText(posX, posY, buffer);
}
}
}
if (m_flags & kFlag_AutoNewline)
{
Newline();
}
}
void ClearLines(float startY, float height)
{
const int startRow = std::min(static_cast<int>(startY) / kTextModeRowSize, int(kTextModeRowCount));
const int numRows = std::min(static_cast<int>(height) / kTextModeRowSize, int(kTextModeRowCount));
// Text mode console requires wiping the frame buffer to maintain a reasonable
// quality display. The frame profiler doesn't do this, and as a result is
// sometimes completely unreadable. It's very slow to set characters in the
// console, so for now, we're wiping in scanline fashion.
if (ITextModeConsole* textConsole = gEnv->pSystem->GetITextModeConsole())
{
static char s_emptyLine[kTextModeColCount + 1] = { '\0' };
if (0 == s_emptyLine[0])
{
for (int col = 0; col < kTextModeColCount; ++col)
{
s_emptyLine[col] = ' ';
}
s_emptyLine[kTextModeColCount] = 0;
}
for (int row = startRow; row < numRows; ++row)
{
textConsole->PutText(0, row, s_emptyLine);
}
}
}
inline ColorF GetDefaultColor() const { return m_defaultColor; }
inline void SetDefaultColor(ColorF color) { m_defaultColor = color; }
inline Vec3 GetPosition() const { return m_pos; }
inline void SetPosition(const Vec3& pos) { m_pos = pos; }
inline float GetFontSize() const { return m_fontSize; }
inline void SetFontSize(float fontSize) { m_fontSize = fontSize; }
inline void Newline() { m_pos.y += m_fontSize * 10.f; }
inline bool IsAutoNewlined() const { return !!(m_flags & kFlag_AutoNewline); }
inline bool IsMonospaced() const { return !!(m_flags & kFlag_Monospaced); }
inline void SetAutoNewlined(bool set)
{
if (set)
{
m_flags |= kFlag_AutoNewline;
}
else
{
m_flags &= ~kFlag_AutoNewline;
}
}
inline void SetMonospaced(bool set)
{
if (set)
{
m_flags |= kFlag_Monospaced;
}
else
{
m_flags &= ~kFlag_Monospaced;
}
}
inline void SetTextModeConsole(bool set)
{
if (set)
{
m_flags |= kFlag_TextModeConsole;
}
else
{
m_flags &= ~kFlag_TextModeConsole;
}
}
private:
Vec3 m_pos;
ColorF m_defaultColor;
float m_fontSize;
enum Flags
{
kFlag_AutoNewline = (1 << 0), // Auto advance to next line after AddText().
kFlag_Monospaced = (1 << 1), // Print out using monospaced font.
kFlag_TextModeConsole = (1 << 2), // Write to "text mode console" (dedicated server).
};
uint32 m_flags;
IRenderer* m_renderer;
};
}
namespace GridMate
{
namespace Debug
{
const char* const GetAspectNameByBitIndex(size_t aspectIndex)
{
static const char* AspectNames[] =
{
#define ADD_ASPECT(x, y) #x,
#include "Compatibility/GridMateNetSerializeAspects.inl"
#undef ADD_ASPECT
};
STATIC_ASSERT(AZ_ARRAY_SIZE(AspectNames) <= NetSerialize::kNumAspectSlots,
"Too many Engine aspects for the replica.");
if (aspectIndex >= AZ_ARRAY_SIZE(AspectNames))
{
return "<invalid aspect index>";
}
return AspectNames[ aspectIndex ];
}
#if GRIDMATE_DEBUG_ENABLED
int s_DebugDraw = 0;
int s_TraceLevel = 0;
int s_EnableAsserts = 0;
struct TrackedDebugMsg
{
typedef CryFixedStringT<256> StringStorage;
TrackedDebugMsg(DebugMessageType type, const char* msg)
: m_type(type)
, m_string(msg)
{
#ifdef WIN32
time(&m_time);
#endif // WIN32
}
#ifdef WIN32
time_t m_time;
#endif // WIN32
DebugMessageType m_type;
StringStorage m_string;
};
AZStd::vector<TrackedDebugMsg, AZ::StdLegacyAllocator> s_trackedMessages;
CryCriticalSection s_debugLock;
void TrackMessage(DebugMessageType type, const char* msg)
{
enum
{
kMaxTrackedMessages = 20
};
while (s_trackedMessages.size() >= kMaxTrackedMessages)
{
s_trackedMessages.erase(s_trackedMessages.begin());
}
s_trackedMessages.push_back(TrackedDebugMsg(type, msg));
}
void DebugTrace(bool isAssertFailure, const char* format, ...)
{
enum
{
kMaxTraceMessageSize = 512
};
CryAutoLock<CryCriticalSection> lock(s_debugLock);
va_list argList;
char buffer[ kMaxTraceMessageSize ];
va_start(argList, format);
const int len = vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, format, argList);
buffer[ sizeof(buffer) - 1 ] = '\0';
va_end(argList);
if (isAssertFailure)
{
CryWarning(VALIDATOR_MODULE_NETWORK, VALIDATOR_ERROR, "<GridMate Assert> %s", buffer);
TrackMessage(DebugMessageType::kAssert, buffer);
if (s_EnableAsserts)
{
CryDebugBreak();
}
}
else
{
CryLog("<GridMate Trace> %s", buffer);
TrackMessage(DebugMessageType::kTrace, buffer);
}
}
//-----------------------------------------------------------------------------
static void CmdSetDebugDraw(IConsoleCmdArgs* args)
{
if (args->GetArgCount() > 1)
{
using namespace CryStringUtils;
char* items = const_cast<char*>(args->GetArg(1));
int value = 0;
const char* delims = "+";
char* nextToken = nullptr;
char* token = azstrtok(items, 0, delims, &nextToken);
while (token)
{
if (nullptr != stristr(token, "basic"))
{
value |= Debug::Basic;
}
if (nullptr != stristr(token, "trace"))
{
value |= Debug::Trace;
}
if (nullptr != stristr(token, "stat"))
{
value |= Debug::Stats;
}
if (nullptr != stristr(token, "rep"))
{
value |= Debug::Replicas;
}
if (nullptr != stristr(token, "act"))
{
value |= Debug::Actors;
}
if (nullptr != stristr(token, "detail"))
{
value |= Debug::EntityDetail;
}
if (nullptr != stristr(token, "full"))
{
value = Debug::Full;
break;
}
token = azstrtok(nullptr, 0, delims, &nextToken);
}
Debug::s_DebugDraw = value;
}
else
{
Debug::s_DebugDraw = Debug::Full;
}
}
//-----------------------------------------------------------------------------
static void OnDumpStatsChanged(ICVar* /*cvar*/)
{
if (Network::s_DumpStatsFile)
{
fclose(Network::s_DumpStatsFile);
Network::s_DumpStatsFile = nullptr;
}
ICVar* cvarFilename = gEnv->pConsole->GetCVar("gm_dumpstats_file");
if (Network::s_DumpStatsEnabled > 0 &&
cvarFilename && cvarFilename->GetString() && cvarFilename->GetString()[0])
{
const CryStringT<char> logFile = PathUtil::Make(
"@log@",
PathUtil::GetFile(cvarFilename->GetString()));
char resolvedPath[MAX_PATH] = { 0 };
gEnv->pFileIO->ResolvePath(logFile.c_str(), resolvedPath, MAX_PATH);
Network::s_DumpStatsFile = nullptr;
azfopen(&Network::s_DumpStatsFile, resolvedPath, "wt");
}
}
void RegisterCVars()
{
REGISTER_CVAR2("gm_debugdraw", &s_DebugDraw, s_DebugDraw, VF_DEV_ONLY, "GridMate debugging visualization level.");
REGISTER_CVAR2("gm_tracelevel", &s_TraceLevel, s_TraceLevel, VF_DEV_ONLY, "GridMate debugging trace verbosity level.");
REGISTER_CVAR2("gm_asserts", &s_EnableAsserts, s_EnableAsserts, VF_DEV_ONLY, "GridMate asserts.");
REGISTER_COMMAND("gm_setdebugdraw", CmdSetDebugDraw, VF_DEV_ONLY,
"Helper for setting up debug draw level: e.g. gm_setdebugdraw Basic+Stats+Trace."
"Options are Basic, Trace, Stats, Replicas, and Actors.");
// Profiling commands.
REGISTER_CVAR2_CB("gm_dumpstats", &Network::s_DumpStatsEnabled, Network::s_DumpStatsEnabled, VF_DEV_ONLY,
"Enable dumping of net profiling stats to file.", OnDumpStatsChanged);
REGISTER_STRING_CB("gm_dumpstats_file", "net_profile.log", VF_DEV_ONLY,
"Target file for net profiling stats.", OnDumpStatsChanged);
REGISTER_CVAR2("gm_stats_interval_msec", &Network::s_StatsIntervalMS, Network::s_StatsIntervalMS, VF_DEV_ONLY,
"Net profiling statistics will be gathered on this interval (in milliseconds). "
"If stats are being dumped to file, it will also occur on this interval.");
}
void UnregisterCVars()
{
UNREGISTER_CVAR("gm_stats_interval_msec");
UNREGISTER_CVAR("gm_dumpstats_file");
UNREGISTER_CVAR("gm_dumpstats");
if (gEnv->pConsole)
{
gEnv->pConsole->RemoveCommand("gm_setdebugdraw");
}
UNREGISTER_CVAR("gm_setdebugdraw");
UNREGISTER_CVAR("gm_asserts");
UNREGISTER_CVAR("gm_tracelevel");
UNREGISTER_CVAR("gm_debugdraw");
}
#endif // GRIDMATE_DEBUG_ENABLED
} // namespace Debug
//-----------------------------------------------------------------------------
void Network::DebugDraw()
{
#if GRIDMATE_DEBUG_ENABLED
using namespace Debug;
if (0 == Debug::s_DebugDraw)
{
return;
}
auto* levelSystem = GetLevelSystem();
static const float startX = 50.f;
static const float startY = 50.f;
static const float columnWidth = 500.f;
DebugTextHelper text(gEnv->pRenderer, startX, startY, 1.2f);
text.SetMonospaced(true);
text.ClearLines(startY, gEnv->pRenderer->GetHeight() - startY);
text.AddText(Col_Yellow, "=== GridMate ===");
text.Newline();
text.AddText(Col_Coral, "[Status]");
text.AddText(Col_White, "%-20s %s", "Is Server?", gEnv->bServer ? "yes" : "no");
text.AddText(Col_White, "%-20s %s", "Is Multiplayer?", gEnv->bMultiplayer ? "yes" : "no");
text.AddText(Col_White, "%-20s %u", "Local Channel", m_localChannelId);
string sessionStatusStr = "(none)";
if (m_session)
{
sessionStatusStr = "Multiplayer";
if (m_session->IsHost())
{
sessionStatusStr += " hosted";
}
else
{
sessionStatusStr += " joined";
}
}
text.AddText(Col_White, "%-20s %s", "Session Status", sessionStatusStr.c_str());
text.AddText(Col_White, "%-20s %s", "Current Level", (levelSystem && levelSystem->GetCurrentLevel()) ?
levelSystem->GetCurrentLevel()->GetLevelInfo()->GetName() : "(none)");
if (m_session)
{
text.Newline();
const char* sessionType = (m_session->IsHost()) ? "Server" : "Client";
text.AddText(Col_Coral, "[Session - %s]", sessionType);
if (!m_session->IsHost())
{
text.AddText(Col_White, "%-20s %u", "Server Channel",
GetServerChannelId());
}
text.AddText(Col_White, "%-20s %u", "Members", m_session->GetNumberOfMembers());
}
if (!!(s_DebugDraw & Stats) && !(s_DebugDraw & EntityDetail))
{
text.Newline();
text.AddText(Col_Coral, "[Overview (last %d msec)]", Network::s_StatsIntervalMS);
text.AddText(Col_LightBlue, "%-20s %-10s %-12s %-14s %-14s %-10s %-10s", "To Channel", "RTT", "Packet Loss", "Data Sent(kb)", "Data Recv(kb)", "Pack Sent", "Pack Recv");
for (const auto& stat : m_statisticsPerChannel)
{
text.AddText(Col_White, "%-20u %-10.2f %-12.2f %-14.2f %-14.2f %-10u %-10u",
stat.first, stat.second.m_rtt, stat.second.m_packetLossRate,
float( stat.second.m_totalSentBytes ) / 1024.f, float( stat.second.m_totalReceivedBytes ) / 1024.f,
stat.second.m_packetsSent, stat.second.m_packetsReceived);
}
const auto& stats = GetGameStatistics();
auto& rmiActor = stats.m_rmiGlobalActor;
auto& rmiLegacy = stats.m_rmiGlobalLegacy;
auto& rmiScript = stats.m_rmiGlobalScript;
text.Newline();
text.AddText(Col_Coral, "[Lifetime RMI]");
text.AddText(Col_LightBlue, "%-14s %-14s %-14s %-14s",
"Num Sent", "Num Received", "Total Sent(kb)", "Total Received(kb)");
text.AddText(Col_White, "%-14u %-14u %-14.2f %-14.2f",
rmiActor.m_sendCount + rmiLegacy.m_sendCount + rmiScript.m_sendCount,
rmiActor.m_receiveCount + rmiLegacy.m_receiveCount + rmiScript.m_receiveCount,
float( rmiActor.m_totalSentBytes + rmiLegacy.m_totalSentBytes + rmiScript.m_totalSentBytes ) / 1024.f,
float( rmiActor.m_totalReceivedBytes + rmiLegacy.m_totalReceivedBytes + rmiScript.m_totalReceivedBytes ) / 1024.f);
text.Newline();
text.AddText(Col_Coral, "[Lifetime Aspects]");
text.AddText(Col_LightBlue, "%-14s %-14s %-14s %-14s",
"Num Sent", "Num Received", "Total Sent(kb)", "Total Received(kb)");
text.AddText(Col_White, "%-14u %-14u %-14.2f %-14.2f",
stats.m_aspectsSent, stats.m_aspectsReceived,
float( stats.m_aspectSentBytes ) / 1024.f,
float( stats.m_aspectReceivedBytes ) / 1024.f);
}
if (!!(s_DebugDraw & Replicas) && !(s_DebugDraw & EntityDetail))
{
text.Newline();
text.AddText(Col_Coral, "[Entity Replicas By Type]");
text.AddText(Col_LightBlue, "%-20s %-10s", "Entity Class", "Count");
}
if (!!(s_DebugDraw & Actors) && !(s_DebugDraw & EntityDetail))
{
text.Newline();
text.AddText(Col_Coral, "[Game Actors]");
text.AddText(Col_LightBlue, "%-20s %-10s %-10s %-15s %-10s", "Name", "Channel", "Entity Id", "Client Actor?", "Player?");
}
if (!!(s_DebugDraw & Trace) && !(s_DebugDraw & EntityDetail))
{
text.Newline();
text.AddText(Col_Coral, "[Trace]");
for (auto iter = s_trackedMessages.rbegin(); iter != s_trackedMessages.rend(); ++iter)
{
const char* time = "";
#ifdef WIN32
char timeFriendly[ 128 ];
{
tm timeStruct;
localtime_s(&timeStruct, &iter->m_time);
strftime(timeFriendly, 20, "%H:%M:%S", &timeStruct);
time = timeFriendly;
}
#endif // WIN32
text.AddText(iter->m_type == DebugMessageType::kAssert ? Col_Red : Col_White,
"[%s] %s", time, iter->m_string.c_str());
}
}
#endif // GRIDMATE_DEBUG_ENABLED
}
//-----------------------------------------------------------------------------
void Network::DumpNetworkStatistics()
{
#if GRIDMATE_DEBUG_ENABLED
if (s_DumpStatsFile)
{
static uint32 s_actorRMIOverhead = 0;
static uint32 s_legacyRMIOverhead = 0;
static uint32 s_scriptRMIOverhead = 0;
static uint32 s_aspectOverhead = 0;
static bool s_overheadsComputed = false;
// Compute some overhead values.
{
char tempBuffer[2048];
GridMate::WriteBufferStaticInPlace buffer(EndianType::BigEndian, tempBuffer, sizeof(tempBuffer));
if (!s_overheadsComputed)
{
{
buffer.Clear();
GridMate::RMI::ActorInvocationWrapper::Ptr invocation = new GridMate::RMI::ActorInvocationWrapper();
GridMate::RMI::ActorInvocationWrapper::Marshaler().Marshal(buffer, invocation);
s_actorRMIOverhead = buffer.Size();
}
{
buffer.Clear();
GridMate::RMI::LegacyInvocationWrapper::Ptr invocation = new GridMate::RMI::LegacyInvocationWrapper();
GridMate::RMI::LegacyInvocationWrapper::Marshaler().Marshal(buffer, invocation);
s_legacyRMIOverhead = buffer.Size();
}
{
buffer.Clear();
GridMate::RMI::ScriptInvocationWrapper::Ptr invocation = new GridMate::RMI::ScriptInvocationWrapper();
GridMate::RMI::ScriptInvocationWrapper::Marshaler().Marshal(buffer, invocation);
s_scriptRMIOverhead = buffer.Size();
}
{
buffer.Clear();
GridMate::NetSerialize::AspectSerializeState aspect;
GridMate::NetSerialize::AspectSerializeState::Marshaler().Marshal(buffer, aspect);
s_aspectOverhead = buffer.Size();
}
s_overheadsComputed = true;
}
}
fprintf(s_DumpStatsFile, "Last %d msec\n", s_StatsIntervalMS);
static const char* s_unknown = "<unknown>";
//
// Global stats.
//
auto& stats = GetGameStatistics();
auto carrier = GetCarrierStatistics();
fprintf(s_DumpStatsFile,
"[Global]\n"
"Ping\tTotalBytesSent\tTotalBytesRecv\t"
"TotalPackSent\tTotalPackRecv\t"
"TotalRMIsSent\tTotalRMIsRecv\t"
"TotalRMIBytesSent\tTotalRMIBytesRecv\t"
"TotalAspectsSent\tTotalAspectsRecv\t"
"TotalAspectBytesSent\tTotalAspectBytesRecv\t"
"PacketsLost\tPackLossRate\t"
"ActorRMIOverheadBytes\tLegacyRMIOverheadBytes\tScriptRMIOverheadBytes\tAspectOverheadBytes\n");
fprintf(s_DumpStatsFile, "%.2f\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%.2f\t%u\t%u\t%u\t%u\n",
carrier.m_rtt,
carrier.m_totalSentBytes, carrier.m_totalReceivedBytes,
carrier.m_packetsSent, carrier.m_packetsReceived,
stats.m_rmiGlobalActor.m_sendCount + stats.m_rmiGlobalLegacy.m_sendCount + stats.m_rmiGlobalScript.m_sendCount,
stats.m_rmiGlobalActor.m_receiveCount + stats.m_rmiGlobalLegacy.m_receiveCount + stats.m_rmiGlobalScript.m_receiveCount,
stats.m_rmiGlobalActor.m_totalSentBytes + stats.m_rmiGlobalLegacy.m_totalSentBytes + stats.m_rmiGlobalScript.m_totalSentBytes,
stats.m_rmiGlobalActor.m_totalReceivedBytes + stats.m_rmiGlobalLegacy.m_totalReceivedBytes + stats.m_rmiGlobalScript.m_totalReceivedBytes,
stats.m_aspectsSent, stats.m_aspectsReceived,
stats.m_aspectSentBytes, stats.m_aspectReceivedBytes,
carrier.m_packetsLost, carrier.m_packetLossRate,
s_actorRMIOverhead, s_legacyRMIOverhead, s_scriptRMIOverhead, s_aspectOverhead);
//
// Per-entity detail.
//
fprintf(s_DumpStatsFile, "\n[Entity Detail]\n");
fprintf(s_DumpStatsFile, "Entity\tClass\tEventType\tSendCount\tRecvCount\tSentBytes\tRecvBytes\tOverheadBytes\tTotalBytes\n");
for (const auto& entityEntry : stats.m_entities)
{
const EntityId entityId = entityEntry.first;
const auto& entityStats = entityEntry.second;
bool hasTrafficData = false;
if (!entityStats.m_rmiActor.empty() || !entityStats.m_rmiLegacy.empty())
{
hasTrafficData = true;
}
if (!hasTrafficData)
{
for (size_t aspectIndex = 0; aspectIndex < AZ_ARRAY_SIZE(entityStats.m_aspects); ++aspectIndex)
{
const auto& aspectStats = entityStats.m_aspects[ aspectIndex ];
if (aspectStats.m_receiveCount + aspectStats.m_sendCount > 0)
{
hasTrafficData = true;
}
}
}
if (!hasTrafficData)
{
continue;
}
for (const auto& rmi : entityStats.m_rmiActor)
{
const uint32 rmiRepId = rmi.first;
const GameStatistics::RMIStatistics& rmiStats = rmi.second;
const IActorRMIRep* rep = RMI::FindActorRMIRep(rmiRepId);
const char* rmiName = rep ? rep->GetDebugName() : s_unknown;
const uint32 overhead = s_actorRMIOverhead * (rmiStats.m_sendCount + rmiStats.m_receiveCount);
fprintf(s_DumpStatsFile,
"\t\tRMI: %s\t%u\t%u\t%u\t%u\t%u\t%u\n",
rmiName,
rmiStats.m_sendCount, rmiStats.m_receiveCount,
rmiStats.m_totalSentBytes, rmiStats.m_totalReceivedBytes,
overhead,
overhead + rmiStats.m_totalSentBytes + rmiStats.m_totalReceivedBytes);
}
for (const auto& rmi : entityStats.m_rmiLegacy)
{
const uint32 rmiRepId = rmi.first;
const GameStatistics::RMIStatistics& rmiStats = rmi.second;
const uint32 overhead = s_actorRMIOverhead * (rmiStats.m_sendCount + rmiStats.m_receiveCount);
fprintf(s_DumpStatsFile,
"\t\tRMI: %s\t%u\t%u\t%u\t%u\t%u\t%u\n",
s_unknown,
rmiStats.m_sendCount, rmiStats.m_receiveCount,
rmiStats.m_totalSentBytes, rmiStats.m_totalReceivedBytes,
overhead,
overhead + rmiStats.m_totalSentBytes + rmiStats.m_totalReceivedBytes);
}
for (size_t aspectIndex = 0; aspectIndex < AZ_ARRAY_SIZE(entityStats.m_aspects); ++aspectIndex)
{
const auto& aspectStats = entityStats.m_aspects[ aspectIndex ];
if (aspectStats.m_receiveCount + aspectStats.m_sendCount > 0)
{
const uint32 overhead = s_aspectOverhead * (aspectStats.m_receiveCount + aspectStats.m_sendCount);
fprintf(s_DumpStatsFile,
"\t\tAspect: %s\t%u\t%u\t%u\t%u\t%u\t%u\n",
GridMate::Debug::GetAspectNameByBitIndex(aspectIndex),
aspectStats.m_sendCount, aspectStats.m_receiveCount,
aspectStats.m_totalSentBytes, aspectStats.m_totalReceivedBytes,
overhead,
overhead + aspectStats.m_totalSentBytes + aspectStats.m_totalReceivedBytes);
}
}
}
fprintf(s_DumpStatsFile, "\n");
}
#endif // GRIDMATE_DEBUG_ENABLED
}
} // namespace GridMate