Put it all together - Stat tracking and display - (Unreal Engine module)
Last updated on October 24, 2024
Connect the UI to display player statistics
Open the the
StatsProfileWidget_Starter
class CPP file. Replace theQueryLocalUserStats()
function with the code below. This function collects the statistics codes for all game modes and the queries them to get a player's statistics value list. Once the query is complete, it will call theOnQueryLocalUserStatsComplete()
function to display the statistics.void UStatsProfileWidget_Starter::QueryLocalUserStats()
{
UAccelByteWarsGameInstance* GameInstance = Cast<UAccelByteWarsGameInstance>(GetGameInstance());
if (!GameInstance)
{
UE_LOG_STATSESSENTIALS(Warning, TEXT("Failed to query local user stats. Game instance is invalid."));
Ws_Loader->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Error);
return;
}
TArray<FString> StatsCodes{};
for (const TTuple<FName, UDynamicEntryBox*>& EntryList : StatsDataEntryList)
{
FGameStatsData StatsData{};
if (GameInstance->GetGameStatsDataById(EntryList.Key, StatsData))
{
StatsCodes.Append(StatsData.GetStatsCodes());
}
}
if (StatsCodes.IsEmpty())
{
UE_LOG_STATSESSENTIALS(Warning, TEXT("Failed to query local user stats. No statistics code to query."));
Ws_Loader->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Empty);
return;
}
const bool bStarted = StatsEssentialsSubsystem->QueryLocalUserStats(
AccelByteWarsUtility::GetLocalUserNum(GetOwningPlayer()),
StatsCodes,
FOnlineStatsQueryUsersStatsComplete::CreateUObject(this, &ThisClass::OnQueryLocalUserStatsComplete));
Ws_Loader->SetWidgetState(bStarted ? EAccelByteWarsWidgetSwitcherState::Loading : EAccelByteWarsWidgetSwitcherState::Error);
}Still in the same file, replace the
OnQueryLocalUserStatsComplete()
function with the code below. This function display the statistics values to the respective Dynamic Entry Box based on game modes. If a specific statistic is not found, a 0 value will be displayed. If no statistics are found, an empty state will be displayed.void UStatsProfileWidget_Starter::OnQueryLocalUserStatsComplete(
const FOnlineError& ResultState,
const TArray<TSharedRef<const FOnlineStatsUserStats>>& UsersStatsResult)
{
if (!ResultState.bSucceeded)
{
UE_LOG_STATSESSENTIALS(Warning, TEXT("Failed to handle on-complete query local user stats. Error: %s"), *ResultState.ErrorMessage.ToString());
Ws_Loader->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Error);
return;
}
UAccelByteWarsGameInstance* GameInstance = Cast<UAccelByteWarsGameInstance>(GetGameInstance());
if (!GameInstance)
{
UE_LOG_STATSESSENTIALS(Warning, TEXT("Failed to handle on-complete query local user stats. Game instance is invalid."));
Ws_Loader->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Error);
return;
}
FUniqueNetIdPtr UserId = AccelByteWarsUtility::GetUserId(GetOwningPlayer());
if (!UserId.IsValid())
{
UE_LOG_STATSESSENTIALS(Warning, TEXT("Failed to handle on-complete query local user stats. User id is invalid."));
Ws_Loader->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Error);
return;
}
// Get stats for the target user.
TSharedPtr<const FOnlineStatsUserStats> TargetUserStats = nullptr;
for (TSharedRef<const FOnlineStatsUserStats> const& UserStats : UsersStatsResult)
{
if (UserStats.Get().Account.Get() == UserId.ToSharedRef().Get())
{
TargetUserStats = UserStats;
break;
}
}
if (!TargetUserStats)
{
UE_LOG_STATSESSENTIALS(Warning, TEXT("Failed to handle on-complete query local user stats. Local user's statistics are not found."));
Ws_Loader->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Empty);
return;
}
// Generate stats entries.
for (const TTuple<FName, UDynamicEntryBox*>& EntryList : StatsDataEntryList)
{
FGameStatsData StatsData{};
TWeakObjectPtr<UDynamicEntryBox> TargetStatsList = EntryList.Value;
if (!TargetStatsList.IsValid() || !GameInstance->GetGameStatsDataById(EntryList.Key, StatsData))
{
UE_LOG_STATSESSENTIALS(Warning, TEXT("Failed to handle on-complete query local user stats. Invalid properties to generate widget entry."));
continue;
}
TargetStatsList->Reset(true);
for (const FGameStatsModel& StatsModel : StatsData.GetStatsModels())
{
float StatsValue = 0;
if (const FVariantData* Stats = TargetUserStats->Stats.Find(StatsModel.CodeName))
{
Stats->GetValue(StatsValue);
}
const TWeakObjectPtr<UStatsProfileWidgetEntry> WidgetEntry = TargetStatsList->CreateEntry<UStatsProfileWidgetEntry>();
WidgetEntry->Setup(StatsModel.DisplayName, FText::AsNumber(StatsValue));
}
}
Ws_Loader->SetWidgetState(UsersStatsResult.IsEmpty() ? EAccelByteWarsWidgetSwitcherState::Empty : EAccelByteWarsWidgetSwitcherState::Not_Empty);
}Now, compile your project and make sure there are no errors.
Resources
- The files used in this tutorial section are available in the Byte Wars GitHub repository.