> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Estatísticas e conquistas

> Porte as conquistas e estatísticas do Steam para a API gerenciada pelo título do XBOX GDK, acompanhando o progresso no seu jogo e sincronizando os check-ins com os XBOX services.

No XBOX Game Development Kit (GDK) e no Steam, as conquistas têm informações como nome, descrição, ícone, se foram desbloqueadas para o usuário atual e, opcionalmente, o progresso para concluí-las. O Steam também tem uma API de estatísticas usada pelos jogos para comparar o progresso de um usuário com alguma meta predeterminada e desbloquear conquistas quando essas metas são superadas.

Na verdade, o XBOX Game Development Kit (GDK) tem duas APIs de conquistas: *baseada em eventos* (anteriormente chamada de *Achievements 2013*) e *gerenciada pelo título* (anteriormente chamada de *Achievements 2017*). Embora os dois sistemas sejam opções viáveis, as conquistas/estatísticas gerenciadas pelo título serão muito mais familiares para você se estiver vindo do Steam e corresponderão à lógica existente que provavelmente já está presente no seu jogo. Por esse motivo, descreveremos essa API neste tópico. Para obter mais informações sobre as diferenças entre as duas APIs, consulte [Conquistas baseadas em eventos e gerenciadas pelo título](/pt-BR/services/xbox-services/player-data/achievements/index). As seções a seguir descrevem as diferenças entre as conquistas na API do Steamworks e no XBOX Game Development Kit (GDK).

Para usar as APIs de conquistas gerenciadas pelo título, você precisa criar um identificador de contexto dos XBOX services. Isso pode ser feito usando a função [XblContextCreateHandle](/pt-BR/reference/live/xsapi-c/xbox_live_context_c/xbox_live_context_c_members) e um `XUserHandle` da [API XUserAddResult](/pt-BR/build/core-features/common/user/xuser_howto_best_practice_signing_in) (do tópico [Autenticação de usuários e propriedade](/pt-BR/build/steam-porting-guide/features/user-authentication-and-ownership)).

## Acompanhando o progresso das conquistas

Na API do Steam, você pode usar a API `ISteamUserStats::GetStat`/`ISteamUser::SetStat` para acompanhar o progresso de um usuário em direção a uma conquista, tornando os valores armazenados na API Steam Stats a fonte de verdade para o valor de progresso atual.

Com as conquistas gerenciadas pelo título, seu jogo é a única fonte de verdade e deve acompanhar o progresso atual do usuário por conta própria. A atualização do progresso atual na nuvem com uma chamada de API é feita como uma espécie de "check-in" e é usada para mostrar o progresso de um usuário em algumas superfícies do ecossistema XBOX. Não há orientação específica sobre onde o valor de progresso atual deve ficar, mas muitos jogos optam por armazená-lo no arquivo de salvamento (e na nuvem), enquanto outros podem armazená-lo no próprio serviço de back-end. Certifique-se de manter os valores entre a nuvem e o sistema interno de gerenciamento de estatísticas do seu jogo sincronizados entre si.

## Enumerando todas as conquistas

Para obter todas as estatísticas de um usuário com a API do Steamworks, normalmente você chamaria `ISteamUserStats::RequestUserStats` para extrair as estatísticas mais recentes do servidor. Depois que o retorno de chamada correspondente fosse disparado, você poderia iterar por cada conquista pelo nome da API usando as funções `ISteamUserStats::GetStat`/`ISteamUserStats::GetAchievement` e inicializar o estado do jogo usando os dados retornados.

Com o XBOX Game Development Kit (GDK), você pode simplesmente usar a função [XblAchievementsGetAchievementsForTitleIdAsync](/pt-BR/reference/live/xsapi-c/achievements_c/achievements_c_members) e, em seguida, usar os dados de cada objeto de conquista na matriz fornecida como parâmetro de saída de [XblAchievementsResultGetAchievements](/pt-BR/reference/live/xsapi-c/achievements_c/achievements_c_members) para inicializar o estado do jogo. Cada conquista é fornecida como uma struct [XblAchievement](/pt-BR/reference/live/xsapi-c/achievements_c/achievements_c_members). Para obter mais informações sobre os dados que ela contém, consulte [o tópico de referência](/pt-BR/reference/live/xsapi-c/achievements_c/achievements_c_members).

### Steamworks

```cpp theme={null}
void MyGameClass::Initialize()
{
    // ...
    SteamUserStats()->RequestCurrentStats();
    STEAM_CALLBACK( MyGameClass, OnUserStatsReceived, UserStatsReceived_t );
}

void MyGameClass::OnUserStatsReceived()
{
    // Iterate over stats/achievements, and initialize any necessary game data.
    // Assume that m_achievementIds is an array of "API names" for achievements.
    for (int i = 0; i < m_achievementIds.length; i++)
    {
        const char *achievementName = SteamUserStats()->GetAchievementDisplayAttribute(m_achievementIds[i], "name");
        const char *description = SteamUserStats()->GetAchievementDisplayAttribute(m_achievementIds[i], "desc");
        bool hidden = SteamUserStats()->GetAchievementDisplayAttribute(m_achievementIds[i], "hidden");
        bool isUnlocked;
        SteamUserStats()->GetAchievement(m_achievementIds[i], &isUnlocked);
        // Do any necessary achievement initialization...
    }
}
```

### XBOX Game Development Kit (GDK)

```cpp theme={null}
auto asyncBlock = std::make_unique<XAsyncBlock>();
asyncBlock->context = nullptr;
asyncBlock->callback = [](XAsyncBlock* asyncBlock)
{
    // Take over ownership of the XAsyncBlock*
    std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; 

    XblAchievementsResultHandle resultHandle;
    auto hr = XblAchievementsGetAchievementsForTitleIdResult(asyncBlock, &resultHandle);

    if (SUCCEEDED(hr))
    {
        const XblAchievement* achievements = nullptr;
        size_t achievementsCount = 0;
        hr = XblAchievementsResultGetAchievements(resultHandle, &achievements, &achievementsCount);

        for (size_t i = 0; i < achievements.length; i++)
        {
            auto name = achievement[i].name;
            char description[256];
            char progress[4] = "100";
            if (achievement[i].progressState == XblAchievementProgressState::Achieved)
            {
                strcpy(description, achievement[i].unlockedDescription);
            }
            else
            {
                strcpy(description, achievement[i].lockedDescription);
                strcpy(progress, achievement[i].progression.requirements[0].currentProgressValue);
            }
            // Use this data to initialize achievements...
        }

        // When you're done with the handle, close it. This will free the achievements list 
        // from memory.
        XblAchievementsResultCloseHandle(resultHandle);
        achievements = nullptr; 
        // Instead, you couldn't close the handle and store it.  
        // If you needed to copy the handle, call XblAchievementsResultDuplicateHandle()
    }
};

// Assume m_xblContext is an XBOX services Context handle that has been initialized properly.
uint64_t xuid;
XblContextGetXboxUserId(m_xblContext, &xuid);

HRESULT hr = XblAchievementsGetAchievementsForTitleIdAsync(
    m_xblContext,
    xuid, 
    m_titleId, // Assume this is a uint32_t holding your game's title ID.
    XblAchievementType::Persistent, // achievementType: You probably want to use XblAchievementType::Persistent.
    false, //unlockedOnly: If true, returns only unlocked achievements.
    XblAchievementOrderBy::DefaultOrder, // orderBy: How to order the incoming achievements list. 
    0, // skipItems: The number of achievements to skip. 
    0, // maxItems: Set to 0 to get all achievements/disable pagination.
    asyncBlock.get()
);
if (SUCCEEDED(hr))
{
    // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.
    // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*
    asyncBlock.release();
}
```

Para obter mais informações sobre conquistas gerenciadas pelo título, consulte [Obtendo conquistas gerenciadas pelo título](/pt-BR/services/xbox-services/player-data/achievements/index).

## Atualizando o progresso de uma conquista e desbloqueando conquistas

No XBOX Game Development Kit (GDK) e no Steam, o código do jogo determina quando uma conquista deve ser desbloqueada. Com o XBOX Game Development Kit (GDK), definir o progresso de uma conquista como 100 a desbloqueia. As seções a seguir descrevem as etapas necessárias para atualizar o progresso de um usuário em uma conquista especificada com as duas APIs.

Veja a seguir um exemplo de código de um método `UpdateAchievement`, implementado nos dois SDKs, que recebe uma ID/nome de API da conquista (e o nome de API da estatística no Steam), o quanto incrementar a conquista e qual é o valor de destino para desbloquear essa conquista, e atualiza o progresso e o status de desbloqueio da conquista de acordo.

### Steamworks

```cpp theme={null}
void MyGame::UpdateAchievement(const char *achievementApiName, const char *statApiName, int diff, int target)
{
    bool isCompleted;
    int value;
    bool result = SteamUserStats()->GetAchievement(achievementApiName, &isCompleted);
    if (!result) {
        // Handle error.
    }

    result = SteamUserStats()->GetStat(statApiName, &value);
    if (!result) {
        // Handle error.
    }

    SteamUserStats()->SetStat(statApiName, value + diff);
    
    if (!isCompleted && value + diff >= target)
    {
             // Unlock the achievement.
        SteamUserStats()->SetAchievement(achievementApiName);
        SteamUserStats()->StoreStats();
    }
}

// At the next checkpoint...
if(!SteamUserStats()->StoreStats()) {
    // Handle error.
}
```

### XBOX Game Development Kit (GDK)

```cpp theme={null}
void MyGame::UpdateAchievement(const std::string& achievementId, int diff, int target)
{
    // Assume this function returns the specified achievement's progress from wherever you're storing it.
    auto previousValue = MyGetAchievementProgress(achievementId);
    // If you're storing progress elsewhere, make sure to update it there, too! Again, we're assuming 
    // that this is a function you've written to update the progress value wherever it's stored.
    MySetAchievementProgress(previousValue + diff);
    // Calculate the percent of the target that the user has reached after adding the value of diff.
    uint32_t percentComplete = (previousValue + diff) / target;

    auto async = std::make_unique<XAsyncBlock>();
    async->context = nullptr;
    async->callback = [](XAsyncBlock *async)
    {
        // Take over ownership of the XAsyncBlock*
        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ async }; 

        HRESULT result = XAsyncGetStatus(async, true);

        if (SUCCEEDED(result))
        {
            // Success!
        }
        else
        {
            if (result == HTTP_E_STATUS_NOT_MODIFIED)
            {
                // The achievement was already completed or it was previously
                // set to a higher value, so it's unchanged.
            }
            else
            {
                // Handle error.
            }
        }
    };

    // Assume m_xblContext is an XBOX services Context handle that has been initialized properly.
    uint64_t xuid;
    XblContextGetXboxUserId(m_xblContext, &xuid);
    HRESULT hr = XblAchievementsUpdateAchievementAsync(
        m_xblContext,
        xuid,
        achievementId.c_str(),
        percentComplete,
        async
    );

    if (SUCCEEDED(hr))
    {
        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.
        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*
        asyncBlock.release();
    }
}
```

Para obter mais informações sobre conquistas gerenciadas pelo título, consulte [Atualizando conquistas gerenciadas pelo título](/pt-BR/services/xbox-services/player-data/achievements/index).

## Conquistas offline

Desbloquear uma conquista do XBOX não exige uma conexão de rede. Ela é desbloqueada automaticamente no servidor mais tarde, sem código adicional, se o usuário não estiver conectado à rede XBOX (também conhecida como XBOX Live).

## Obtendo as conquistas de outro usuário

Para obter as conquistas de outro usuário, você pode simplesmente chamar as funções [XblAchievementsGetAchievementsForTitleAsync](/pt-BR/reference/live/xsapi-c/achievements_c/achievements_c_members)/[XblAchievementsGetAchievementAsync](/pt-BR/reference/live/xsapi-c/achievements_c/achievements_c_members) com a XBOX User ID (XUID) do usuário cujas conquistas você deseja buscar. Isso é semelhante a usar as funções `ISteamUser::RequestUserStats`, `ISteamUserStats::GetUserStat` e `ISteamUserStats::GetUserAchievement` no Steam.

## Redefinindo conquistas

Ao contrário de `ISteamUserStats::ResetAllStats` da API do Steamworks, que pode ser usada para redefinir o progresso do usuário em todas as estatísticas e, se especificado, nas conquistas, o XBOX Game Development Kit (GDK) não tem nenhuma capacidade documentada de redefinir programaticamente o progresso ou o status de desbloqueio das conquistas. Tentar chamar [XblAchievementsUpdateAchievementAsync](/pt-BR/reference/live/xsapi-c/achievements_c/achievements_c_members) com um valor de progresso 0 deixa o valor de progresso inalterado. No entanto, você pode usar a [ferramenta Player Data Reset (XblPlayerDataReset.exe)](/pt-BR/tools/tools-services/live-player-data-reset) durante os testes para fazer isso.

## Limitação de taxa

Ao atualizar o progresso das conquistas, tome cuidado para evitar chamar a XBOX Services API (XSAPI) com muita frequência, pois isso pode fazer com que seu jogo atinja o limite de taxa. Isso pode causar um comportamento inesperado e uma experiência ruim para seus usuários.

Para conquistas que acompanham estatísticas atualizadas com frequência, tente agrupar as chamadas de API para que sejam disparadas depois que um determinado número de eventos ocorrer ou para atualizar no servidor em um determinado intervalo de tempo.

Você pode depurar suas chamadas de API usando o [XBOX services Trace Analyzer (XblTraceAnalyzer.exe)](/pt-BR/tools/tools-services/live-trace-analyzer).

Para obter mais informações sobre a limitação de taxa nos XBOX services, consulte [Limitação de taxa refinada](/pt-BR/services/xbox-services/develop/best-practices/live-fine-grained-rate-limiting).


## Related topics

- [Visão geral dos Dados do jogador do XBOX](/pt-BR/services/xbox-services/player-data/live-playerdata-overview.md)
- [Configurando os XBOX services](/pt-BR/publishing/game-publishing/concepts/xbox-services.md)
- [Diferenças conceituais entre o GDK e o Steamworks](/pt-BR/build/steam-porting-guide/conceptual-differences.md)
- [Estatísticas baseadas em eventos vs. estatísticas gerenciadas pelo título](/pt-BR/services/xbox-services/player-data/stats-leaderboards/live-stats-eb-vs-tm.md)
- [Conquistas baseadas em eventos vs. gerenciadas pelo título](/pt-BR/services/xbox-services/player-data/achievements/live-achievements-eb-vs-tm.md)
