Ok, there was really a lot of digging around but I managed to write a function for gathering stats.
First of all - we need to override FStatsThreadState just to get access to the one protected field:
class MYGAME_API FStatsThreadStateOverlay : public FStatsThreadState
{
public:
int64 GetLastFullFrameProcessed()
{
return LastFullFrameProcessed;
}
};
Oh, the original FStatsThreadState and all needed methods are in “StatsData.h”
Then I had to prepare a Filter structure for future use:
struct FGroupFilter : public IItemFiler
{
TSet<FName> const& EnabledItems;
FGroupFilter(TSet<FName> const& InEnabledItems)
: EnabledItems(InEnabledItems)
{
}
virtual bool Keep(FStatMessage const& Item)
{
const FName MessageName = Item.NameAndInfo.GetRawName();
return EnabledItems.Contains(MessageName);
}
};
And now time for some magic. Here’s complete code to get all net stats (with comments):
// Get the reference to the stats thread
FStatsThreadStateOverlay& Stats = FStatsThreadStateOverlay&)FStatsThreadState::GetLocalState();
// Get the number of the last processed frame and check if it is valid (just for sure)
int64 LastGoodGameFrame = Stats.GetLastFullFrameProcessed();
if (Stats.IsFrameValid(LastGoodGameFrame) == false)
{
return;
}
// This is the name of the group where stats are.
FName GroupName = FName(TEXT("STATGROUP_net"));
// Gather the names of the stats that are in this group.
TArray<FName> GroupItems;
Stats.Groups.MultiFind(GroupName, GroupItems);
// Prepare the set of names and raw names of the stats we want to get
TSet<FName> EnabledItems;
for (const FName& ShortName : GroupItems)
{
EnabledItems.Add(ShortName);
if (FStatMessage const* LongName = Stats.ShortNameToLongName.Find(ShortName))
{
EnabledItems.Add(LongName->NameAndInfo.GetRawName());
}
}
// Create a filter (needed by stats gathering function)
FGroupFilter Filter(EnabledItems);
// Create empty stat stack node (needed by stats gathering function)
FRawStatStackNode HierarchyInclusive;
// Prepare the array for stat messages
TArray<FStatMessage> NonStackStats;
// COLLECT ALL STATS TO THE ARRAY HERE
Stats.UncondenseStackStats(LastGoodGameFrame, HierarchyInclusive, &Filter, &NonStackStats);
// Go through all stats
// There are many ways to display them, dig around the code to display it as you want :)
for (auto Stat : NonStackStats)
{
// Here we are getting the raw name
FName StatName = Stat.NameAndInfo.GetRawName();
UE_LOG(MyLog, Log, TEXT("Received Stat: %s"), *StatName.ToString());
// Here we are getting values
int64 iVal = 0;
double dVal = 0;
switch (Stat.NameAndInfo.GetField<EStatDataType>())
{
case EStatDataType::ST_int64:
iVal = Stat.GetValue_int64();
UE_LOG(DTLog, Log, TEXT("Value int64: %lld"), iVal);
break;
case EStatDataType::ST_double:
dVal = Stat.GetValue_double();
UE_LOG(MyLog, Log, TEXT("Value double: %f"), dVal);
break;
default:
check(0);
}
}
One important thing! The function will work only when the “stat net” has been enabled from console. Without it stats won’t be gathered.