Skip to main content

Put it all together - Stat tracking and display - (Unreal Engine module)

Last updated on September 9, 2024

Connect the UI to display player statistics

  1. Open the the StatsProfileWidget_Starter class CPP file. Replace the QueryLocalUserStats() 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 the OnQueryLocalUserStatsComplete() 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);
    }
  2. 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 is 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);
    }
  3. Now, compile your project and make sure there are no errors.

Resources