Documentação do Steamworks
Estatísticas e conquistas

Visão geral

Estatísticas e conquistas Steam oferecem uma forma fácil para o seu jogo disponibilizar um acompanhamento de conquistas e estatísticas persistente e disponível em qualquer lugar. Os dados do usuário são associados à conta Steam, e as conquistas e estatísticas de cada usuário podem ser formatadas para exibição no perfil da Comunidade Steam.

Para que servem

Além de oferecerem recompensas valiosas a jogadores dos seus jogos, conquistas são úteis para encorajar e recompensar trabalho em equipe e interação entre jogadores, oferecendo uma dimensionalidade a mais aos objetivos do jogo e recompensando jogadores por passarem mais tempo jogando.

Estatísticas contabilizam dados detalhados, como tempo de jogo, quantidade de poderes usados, etc. É possível usá-las simplesmente para contabilizar dados internos do jogo — para, por exemplo, atrelar uma conquista com base em estatísticas que abrangem várias sessões, coletadas do usuário de diversos computadores.

Visão geral da implementação

Defina as estatísticas e conquistas do jogo

Conquistas são separadas por jogo e são configuradas na página de administração de aplicativo do site de parceiros Steamworks.

Há três tipos de estatísticas que podem ser armazenadas pelo jogo:
  • INT — Um número inteiro (com sinal) de 32 bits (ex: partidas jogadas);
  • FLOAT — Um número em ponto flutuante de 32 bits (ex: quilômetros dirigidos);
  • AVGRATE — Uma média móvel. Consulte: O tipo de estatística AVGRATE

O site de parceiros Steamworks oferece uma interface para definição e atualização das estatísticas e conquistas do jogo. Por meio dela, é possível:
  • Definir as estatísticas e conquistas iniciais;
  • Adicionar mais estatísticas e conquistas;
  • Atualizar nomes, descrições e ícones de conquistas;
  • Atualizar parâmetros e limites de estatísticas (valores máximos e mínimos, tamanho dos intervalos de valores para médias móveis, etc).
Estatísticas têm as seguintes propriedades:
  • ID — Um ID numérico gerado automaticamente para cada estatística;
  • Type — O tipo da estatística — INT, FLOAT ou AVGRATE;
  • Nome na API — A string usada para acessar a estatística por meio da API;
  • Definida por — Define quem pode alterar a estatística. O valor padrão é Cliente. Para mais informações, consulte Estatísticas do servidor de jogos;
  • Apenas incrementos? — Se verdadeiro, o valor da estatística não pode ser alterado para um valor menor que o atual;
  • Diferença máx. — Se definido, será o limite de diferença no valor da estatística entre chamadas SetStat;
  • Valor mínimo — Se definido, será o valor numérico mínimo permitido para a estatística. O valor padrão é o mínimo do tipo numérico em uso (INT_MIN ou -FLT_MAX);
  • Valor máximo — Se definido, será o valor numérico máximo permitido para a estatística. O valor padrão é o máximo do tipo numérico em uso (INT_MAX ou FLT_MAX);
  • Valor padrão — Se definido, será o valor padrão da estatística para um usuário novo. Caso contrário, o valor padrão é zero;
  • Agregada — Se verdadeiro, o Steam contabilizará um total global para a estatística. Consulte a seção de estatísticas globais abaixo para mais informações;
  • Nome de exibição — O nome da estatística quando exibida na Comunidade Steam. Pode ser localizado.
AVGRATE faz uso das seguintes propriedades adicionais:
  • Intervalo — O tamanho do "intervalo de valores" usado para calcular a média dos dados.
Uma estatística do tipo AVGRATE tem a média calculada automaticamente pelo Steam. Consulte a seção AVGRATE abaixo para mais informações.

Conquistas têm as seguintes propriedades:
  • ID — Um ID numérico gerado automaticamente para cada conquista.
  • Nome na API — A string usada para acessar a conquista por meio da API;
  • Estatística de progresso — Especifica uma estatística a ser usada como um medidor de progresso na Comunidade Steam para a conquista. A conquista também será alcançada automaticamente quando alcançar o valor de meta;
  • Nome de exibição — O nome da conquista em pop-ups de notificação no cliente e na Comunidade Steam. Pode ser localizado;
  • Descrição — Uma descrição da conquista para exibição na Comunidade Steam. Pode ser localizada;
  • Definida por — Define quem pode alcançar a conquista. O valor padrão é Cliente. Para mais informações, consulte Estatísticas do servidor de jogos;
  • Oculta? — Se verdadeiro, uma conquista "oculta" não é exibida (de forma alguma) na página do usuário na Comunidade Steam até ser alcançada;
  • Ícone de alcançada — O ícone para exibição quando alcançada;
  • Ícone de não alcançada — O ícone para exibição quando não alcançada.

Segue-se a lista de conquistas do Steamworks API Example Application (SpaceWar):
achievements_spacewar.png

Como usá-las

Como acessar estatísticas e conquistas pelo jogo:

O tipo de estatística AVGRATE

Este tipo de estatística oferece uma funcionalidade única e bastante útil, mas precisa ser explicada de forma mais detalhada.

Considere o caso em que deseja contabilizar uma estatística de média, como "Pontos marcados por hora". Uma abordagem seria ter duas estatísticas, um INT "TotalPontos" e um FLOAT "TotalHorasJogo", e dividir os pontos pelo tempo para recuperar os pontos por hora.

A desvantagem dessa implementação é que, assim que o jogador acumular muito tempo em jogo, a média calculada demorará muito para mudar. De fato, quanto mais o usuário jogar, menos responsiva a média será. Se o usuário passou 100 horas jogando, a média calculada estará "atrasada" em cerca de 50 horas. Se o jogador melhorar as habilidades no jogo, a estatística de pontos por hora não refletirá essa melhora de forma adequada.

O tipo de estatística AVGRATE permite a implementação de um efeito de "intervalo de valores" na média. Por exemplo, é possível usar apenas as últimas horas de jogo, para que a estatística reflita de forma mais precisa o nível de habilidade atual do jogador.

Imaginemos uma estatística do tipo AVGRATE para implementar "pontos por hora" onde apenas as últimas 20 horas de jogo afetem o valor. Para tal, faz-se o seguinte:
  • Antes de tudo, observe que, como a média será "por hora", as unidades de tempo em todos os parâmetros de tempo associados à estatística serão em "horas". Isso se aplica à propriedade de intervalo da estatística, assim como o parâmetro "dSessionLength" passado à função UpdateAvgRateStat abaixo;
  • Crie uma estatística do tipo AVGRATE de nome "MediaPontosPorHora", e uma propriedade de intervalo de valor 20 (lembre-se que o valor é em "horas");
  • Em momentos apropriados do jogo, chame a função ISteamUserStats::UpdateAvgRateStat com os parâmetros a seguir:
    • pchName — "MediaPontosPorHora";
    • flCountThisSession — A quantidade de pontos marcados pelo jogador desde a última chamada à função UpdateAvgRateStat;
    • dSessionLength — A quantidade de tempo de jogo desde a última chamada à função UpdateAvgRateStat. A unidade deve ser a mesma usada na propriedade de intervalo da estatística. Neste caso, "horas".
  • Por exemplo, se o jogador marcou 77 pontos na última rodada, que durou 0,225 hora (13 minutos e meio), a chamada da função ficaria assim: SteamUserStats()->UpdateAvgRateStat( "MediaPontosPorHora", 77, 0.225 )
No exemplo acima, o Steam pegará a média atual de 342,2 pontos por hora (77 dividido por 0,225) e a combinará com o valor anterior. O resultado refletirá a média total nas últimas 20 horas de jogo. Se essa foi a primeira atualização da estatística para o usuário atual, o valor atual seria de 342,2.

Este exemplo usa "horas" como a unidade de tempo, mas é possível usar a unidade de tempo que preferir. Apenas tenha em mente que você deve usar a mesma unidade para o valor de "dSessionLength" e para a propriedade de intervalo.

Como recuperar estatísticas de outros usuários

Use ISteamUserStats::RequestUserStats para recuperar as estatísticas de outro usuário. Então use ISteamUserStats::GetUserStat, ISteamUserStats::GetUserAchievement e ISteamUserStats::GetUserAchievementAndUnlockTime para recuperar os dados desse usuário. Esses dados não são atualizados quando o usuário informado envia novas estatísticas, então para atualizá-los basta chamar a função ISteamUserStats::RequestUserStats novamente.

Para evitar o uso demasiado de memória, um cache LRU (do inglês Least Recently Used, i.é., removendo os dados usados pela última vez há mais tempo) é mantido e estatísticas de outros usuários serão desalocadas ocasionalmente. Quando isso ocorrer, um retorno de chamada ISteamUserStats::UserStatsUnloaded_t será disparado automaticamente. Nesse caso, as estatísticas do usuário especificado estarão indisponíveis até que a função ISteamUserStats::RequestUserStats seja chamada novamente.

Modo offline

O Steam mantém um cache local dos dados de estatísticas e conquistas para que as APIs possam ser usadas normalmente no modo offline. Quaisquer estatísticas que não foram enviadas são salvas para a próxima vez que o usuário estiver online. Se houver modificações em mais de uma máquina, o Steam combinará as conquistas automaticamente e escolherá o conjunto de estatísticas com mais progresso. Como o Steam mantém um cache local dos dados de estatísticas, não é necessário que o jogo mantenha um cache local dos dados em disco. Tais caches costumam causar conflitos, o que para o usuário terá a aparência de progresso perdido, o que é frustrante.

Estatísticas do servidor de jogos

Paralela à API ISteamUserStats existe a API ISteamGameServerStats para servidores de jogos, que pode recuperar estatísticas de usuários da mesma forma que clientes (descrita acima). Ela também pode definir estatísticas e alcançar conquistas para usuários, mas apenas se o campo "Definida por" estiver com o valor "Servidor" ou "Servidor oficial". A diferença entre um servidor e um servidor oficial é que um servidor oficial é hospedado ou controlado por você. Usar servidores oficiais para a definição de estatísticas aumenta a segurança contra trapaças, pois usuários podem modificar um servidor próprio ou fingir que está hospedando um servidor. Para definir servidores oficiais, informe os intervalos de endereços IP dos servidores aqui.

Estatísticas e conquistas que podem ser definidas por servidores não podem ser definidas por clientes. Servidores só podem definir estatísticas e conquistas para usuários conectados ao servidor. Se um usuário sair do servidor, há um curto período para a definição de estatísticas, mas depois novos envios serão negados, assegurando consistência e evitando a possibilidade de um servidor malicioso definir a estatística de qualquer um a qualquer momento. Dada a restrição, é importante não esperar até o fim de uma rodada para definir estatísticas. Defina-as de forma contínua para que possa armazená-las quando um usuário sair.

Clientes receberão atualizações automáticas quando um servidor alterar as suas estatísticas. Contudo, assim como clientes, estatísticas de outros usuários carregadas pelo servidor não são atualizadas automaticamente, podendo ficar obsoletas.

Como zerar estatísticas

Durante o desenvolvimento, é comum ser necessário zerar as estatísticas e conquistas para uma ou todas as contas para testes. Para zerar as estatísticas de uma conta, chame a função ISteamUserStats::ResetAllStats com o parâmetro bAchievementsToo com valor true para zerar as conquistas também. Uma vez chamada, lembre-se de reiterar pelas estatísticas e conquistas e redefinir o estado do jogo na memória. Não há como zerar as estatísticas e conquistas para todos os usuários de uma vez. Um dos motivos é que, mesmo se tudo fosse zerado de uma vez, jogos abertos poderiam não notar e salvar os valores em memória. Felizmente, há uma forma fácil de se criar um sistema de limpeza global no jogo:
  • Defina uma estatística com um nome como "Versao";
  • Coloque um número fixo de versão no jogo;
  • Quando as estatísticas forem carregadas, compare o valor da estatística "Versao" com o número fixo de versão;
  • Se não forem iguais, chame a função ISteamUserStats::ResetAllStats e então defina a estatística "Versao" com o número fixo.
Desta forma, sempre que precisar zerar as estatísticas de todos, basta alterar o número fixo de versão; as estatísticas serão zeradas assim que os usuários receberam a nova versão. Só não se esqueça de remover esse código na versão final.

Consistência entre estatísticas

É aconselhável ter em mente como estatísticas relacionadas podem ficar inconsistentes. Por exemplo, você tem três estatísticas: "Vitorias", "Derrotas" e "PartidasConcluidas". Mesmo fazendo de tudo, estatísticas podem e ficarão dessincronizadas entre si. Nesse caso, a quantidade de vitórias e derrotas somadas pode não ser igual ao total de partidas concluídas. Se tentasse resolver removendo a estatística "Derrotas" e computando-a como "PartidasConcluidas" - "Vitorias", uma inconsistência poderia resultar em uma estatística "Derrotas" negativa. Nesse caso, o melhor é remover a estatística "PartidasConcluidas" e computá-la como "Vitorias" + "Derrotas".

Estatísticas globais

É possível marcar uma estatística como agregada na página de administração para que o Steam mantenha um total global dos valores de todos os usuários para a mesma, o que pode ser usado para recuperar dados como total de dinheiro na economia, total de vítimas, armas favoritas, mapas favoritos e qual equipe costuma se sair melhor. Por outro lado, este recurso não deve ser usado para estatísticas como "MaisVitimas", pois somar este valor para vários usuários não oferece um resultado significativo. Como estatísticas estão nas mãos dos usuários, os dados estão sujeitos a manipulação. Logo, é crucial que, ao usar estatísticas agregadas, defina-se bons intervalos para valor mínimo, valor máximo, apenas incrementos (se apropriado) e diferença máxima. Diferença máxima tem um significado especial para estatísticas agregadas: quando um novo valor é enviado, o valor global não será alterado em um valor maior que o valor de diferença máxima, limitando o quão rápido um trapaceiro poderá influenciar o total global.

Para acessar os totais globais, chame a função ISteamUserStats::RequestGlobalStats e então ISteamUserStats::GetGlobalStat para cada estatística global. Também é possível usar ISteamUserStats::RequestGlobalStats para uma quantidade específica de dias de histórico. O histórico é o quanto a estatística mudou a cada dia. Para acessar o histórico, chame a função ISteamUserStats::GetGlobalStatHistory.

Também é possível requisitar porcentagens globais de conquistas a partir do cliente. Para tal, primeiro chame ISteamUserStats::RequestGlobalAchievementPercentages. Depois, itere pelas conquistas, começando pela com maior porcentagem alcançada ao chamar as funções ISteamUserStats::GetMostAchievedAchievementInfo e ISteamUserStats::GetNextMostAchievedAchievementInfo. Também é possível recuperar a porcentagem para uma conquista específica por meio da função ISteamUserStats::GetAchievementAchievedPercent.

A Comunidade Steam

Depois do lançamento do jogo, dados sobre progresso individual e global em conquistas serão exibidos na Comunidade Steam. Cada jogador terá um link no perfil da Comunidade que leva a uma página que exibe o que alcançaram e o que ainda precisa ser alcançado.
AVISO: As conquistas não serão exibidas até que o aplicativo tenha algum tipo de visibilidade na Comunidade.

Cada conquista é listada com o ícone apropriado, assim como o nome e descrição definidos no painel de controle do Steamworks. Se o nome e descrição da conquista estiverem localizados no idioma selecionado pelo usuário, eles serão exibidos nesse idioma.

Também haverá um link a partir desta página, e um a partir da página principal do jogo no Steam, para um conjunto de estatísticas globais de conquistas para o jogo. Essa página exibirá a porcentagem de jogadores no Steam que alcançaram cada uma, começando da conquista mais comum e terminando na mais rara. Esse recurso desperta o interesse de jogadores e também é um ótimo recurso para você, desenvolvedor: os seus desafios especiais são difíceis o bastante? Ou talvez difíceis demais? (Estes dados também estão disponíveis no site de relatórios de vendas e ativações).

Alguma dúvida?

Tire a sua dúvida no fórum de discussões de estatísticas e conquistas