Documentación de Steamworks
Logros y estadísticas

Descripción general

Las funciones de estadísticas y logros de Steam brindan un modo sencillo para que tu juego proporcione a sus usuarios información continua e itinerante sobre logros, así como seguimiento de estadísticas. Los datos del usuario están asociados a su cuenta de Steam, y los logros y estadísticas de cada usuario se pueden formatear y mostrar en su perfil de la Comunidad Steam.

Utilidad

Además de ofrecer recompensas muy apreciadas por los jugadores, los logros son útiles para estimular y recompensar el trabajo de equipo y la interacción entre los jugadores, ya que agregan más dimensiones a los objetivos del juego y premian a los usuarios por dedicar más tiempo a jugar.

Las estadísticas siguen datos detallados, como el tiempo de juego, la cantidad de potenciadores empleados, etc. Se pueden usar, simplemente, para llevar un seguimiento de los datos internos del juego; de esta forma, por ejemplo, podría concederse un logro a partir de las estadísticas de juego multisesión del usuario, recogidas de varios equipos.

Descripción general de la implementación

Define las estadísticas y logros de tu juego

Los logros son específicos para cada aplicación y se configuran en la página del administrador de aplicaciones del sitio asociado de Steamworks.

El juego puede almacenar tres tipos de estadísticas:
  • INT: un entero de 32 bits (con signo) (por ejemplo, la cantidad de juegos jugados)
  • FLOAT: un valor de punto flotante de 32 bits (por ejemplo, número de millas recorridas)
  • AVGRATE: una media móvil. Mira: Tipo de estadística AVGRATE

El sitio web de asociados de Steamworks proporciona una interfaz para definir y actualizar las estadísticas y logros del juego. Se puede utilizar para lo siguiente:
  • Definir las estadísticas y logros iniciales.
  • agregar más estadísticas y logros.
  • Actualizar los nombres, descripciones e íconos de los logros.
  • Actualizar los parámetros y restricciones de las estadísticas (valores máximos y mínimos, tamaños de media móvil de ventanas, etc.).
Las estadísticas tienen las siguientes propiedades:
  • ID: una identificación numérica generada automáticamente para cada estadística.
  • Type: el tipo de esta estadística: INT, FLOAT o AVGRATE.
  • API Name: la cadena utilizada para acceder a esta estadística mediante la API.
  • Set By: establece quién puede modificar la estadística. El valor predeterminado es "Client". Para más información, mira Estadísticas del servidor de juego.
  • Increment Only: si se establece, esta estadística solo puede aumentar su valor con el tiempo.
  • Max Change: si se establece, establece un límite en la cantidad que el valor de la estadística puede cambiar de una llamada a SetStat a la siguiente.
  • Min Value: si se establece, el valor numérico mínimo que puede tomar esta estadística. De forma predeterminada, el mínimo es el mínimo del tipo numérico subyacente (INT_MIN o -FLT_MAX).
  • Max Value: si se establece, el valor numérico máximo que puede tomar esta estadística. De forma predeterminada, el máximo es el máximo del tipo numérico subyacente (INT_MAX o FLT_MAX).
  • Default Value: si se establece, el valor predeterminado con el que se establecerá inicialmente esta estadística para un nuevo usuario. Si no se establece, el valor predeterminado es 0.
  • Aggregated: si se establece, Steam mantendrá un total global para esta estadística. Consulta las Estadísticas globales siguientes para obtener más información.
  • Display Name: El nombre de esta estadística cuando se muestra en tu aplicación.
Las estadísticas de AVGRATE tienen las siguientes propiedades adicionales:
  • Ventana: tamaño de la "ventana deslizante" que se usará para hallar la media de los datos.
Una estadística de AVGRATE es una que promedia automáticamente Steam. Consulta la sección AVGRATE a continuación para obtener más información.

Los logros tienen las siguientes propiedades:
  • ID: una identificación numérica generada automáticamente para cada logro.
  • API Name: la cadena utilizada para acceder a este logro mediante la API.
  • Progress Stat: especifica una estadística que se usa como una barra de progreso en la Comunidad para este logro. El logro se desbloqueará automáticamente cuando la estadística alcance el valor de desbloqueo.
  • Display Name: el nombre que este logro tendrá en las ventanas emergentes de notificación al cliente y en la Comunidad. Se puede traducir a otros idiomas.
  • Description: una descripción de este logro, para mostrar en la Comunidad. Se puede traducir a otros idiomas.
  • Set By: establece quién puede desbloquear el logro. El valor predeterminado es "client". Para más información, mira Estadísticas del servidor de juego.
  • Hidden?: si es "true", es un logro "oculto" que no se muestra en la página de la comunidad de un usuario (en absoluto) hasta que lo hayan logrado.
  • Achieved Icon: el ícono que se muestra cuando se alcanza.
  • Unachieved Icon: el ícono que se muestra cuando aún no se ha alcanzado.

La siguiente es la lista de logros de Ejemplo de aplicación de la API de Steamworks (Spacewar!):
achievements_spacewar.png

Consideraciones especiales

  • Los íconos y nombres de los logros deben ser apropiados para todas las edades.
  • De forma predeterminada, los juegos inicialmente tienen un límite de 100 logros. Podrás agregar más logros una vez que tu aplicación alcance el umbral para Características del perfil.

Cómo usarlos

¿Cómo acceder a los logros y estadísticas desde dentro del juego?:

Tipo de estadística AVGRATE

Este tipo de estadística ofrece una funcionalidad especial y muy útil, pero requiere una explicación algo más detallada.

Supongamos que queremos seguir una estadística media, como "puntos ganados por hora". Un enfoque sería tener dos estadísticas, un INT "TotalPoints" y un FLOAT "TotalPlayTimeHours", y luego dividir los puntos por tiempo para obtener puntos por hora.

El inconveniente de esta implementación es que, cuando el jugador acumula una amplia cantidad de tiempo de juego, la media calculada cambia con una lentitud extrema. De hecho, cuanto más juegue el usuario, peor responderá esta media. Si el usuario ha pasado 100 horas jugándolo, la media calculada estará "por detrás" unas 50 horas. Si el usuario aumenta su habilidad, no verá el aumento en puntos por hora que espera.

El tipo de estadística AVGRATE permite utilizar un "efecto de ventana deslizante" con la media. Por ejemplo, se pueden utilizar solo las últimas horas de juego para que la estadística refleje con más precisión el nivel de habilidad actual del jugador.

Configuremos una estadística AVGRATE que calcule "puntos por hora" y en la que solo se usen las 20 horas de juego anteriores para calcular el valor. Haríamos lo siguiente:
  • Se debe tener en cuenta que, como estamos calculando la media "por horas", la unidad de tiempo de todos los parámetros asociados con esta estadística será la "hora". Esto se aplica a la propiedad de la ventana en la estadística en sí, y también para la el parámetro colocado "dSessionLength" en UpdateAvgRateStat a continuación.
  • Crea una estadística AVGRATE llamada "AvgPointsPerHour" y una propiedad de ventana de 20.0 (recordemos que la unidad es en "horas").
  • En los puntos apropiados durante tu juego, llama a ISteamUserStats::UpdateAvgRateStat con los siguientes parámetros:
    • pchName: "AvgPointsPerHour"
    • flCountThisSession: número de puntos que ha ganado el jugador desde la última llamada a UpdateAvgRateStat.
    • dSessionLength: la cantidad de tiempo de juego desde la última llamada a UpdateAvgRateStat. La unidad debería ser la misma que la de la propiedad de la ventana de la estadística. En este caso, "horas".
  • Por ejemplo, si el jugador obtuvo 77 puntos en la última ronda, que duró 0.225 horas (13.5 minutos), eso sería SteamUserStats()->UpdateAvgRateStat( "AvgPointsPerHour", 77, 0.225 )
En el ejemplo anterior, Steam tomará la media de 342.2 puntos por hora (77 entre 0.225) de la ronda actual para combinarla con el valor anterior. El resultado reflejará la media total de las últimas 20 horas de juego del jugador. Si esta es la primera vez que se actualiza la estadística para el usuario actual, el valor actual sería 342.2.

Este ejemplo usa las "horas" como unidad de tiempo, pero se puede usar cualquier otra unidad de tiempo. Solo hay que tener en cuenta que esa unidad se debe usar homogéneamente como base para "dSessionLength", así como para la propiedad de la ventana.

Obtener estadísticas de otros usuarios

Puedes usar ISteamUserStats::RequestUserStats para obtener las estadísticas de otro usuario. Luego puedes usar ISteamUserStats::GetUserStat, ISteamUserStats::GetUserAchievement y ISteamUserStats::GetUserAchievementAndUnlockTime para obtener datos para el usuario. Estos datos no se actualizan automáticamente a medida que el otro usuario carga nuevas estadísticas, por lo tanto, para actualizar los datos simplemente vuelve a llamar a ISteamUserStats::RequestUserStats.

Para no usar demasiada memoria, se mantiene una caché LRU y se descargan ocasionalmente las demás estadísticas del usuario. Cuando esto sucede, se envía automáticamente una función callback ISteamUserStats::UserStatsUnloaded_t. Cuando se envíe esta función callback, las estadísticas del usuario especificado no estarán disponibles hasta que se vuelva a llamar a ISteamUserStats::RequestUserStats.

Modo desconectado

Steam mantiene una caché local de los datos de estadísticas y logros, de forma que las API se puedan usar con normalidad en modo desconectado. Las estadísticas que no se puedan enviar se guardan hasta la siguiente vez que el usuario se conecta. En caso de que se hayan modificado en más de una máquina, Steam combinará automáticamente los logros y elegirá el conjunto de estadísticas que tenga mayor progreso. Puesto que Steam guarda los datos de estadísticas en una caché local, no es necesario que el juego mantenga también en el disco una caché local de los datos. De hacerlo, se podría producir un conflicto entre ambas cachés y al usuario le parecería que su progreso ha desaparecido, lo que resultaría frustrante.

Estadísticas del servidor de juego

En paralelo a ISteamUserStats existe ISteamGameServerStats para los servidores de juego. Los servidores pueden obtener estadísticas de los usuarios del mismo modo que los clientes, tal como se describió arriba. También pueden configurar estadísticas y conceder logros, pero solo si "Establecido por" se establece como GS (servidor de juego) o como servidor oficial. La diferencia entre servidores de juego y servidores oficiales de juego es que tú controlas estos últimos y ofertas tu servicio desde ellos. Usar los servidores oficiales de juego para establecer estadísticas aporta mayor seguridad frente a las trampas, ya que los usuarios podrían modificar sus propios servidores de juego o simular ser un servidor de juego. Para definir los servidores oficiales del juego, ingresa los rangos de IP de los servidores aquí.

Las estadísticas y los logros configurables por parte de los servidores de juego no pueden configurarse por los clientes. Los servidores de juego solo pueden configurar estadísticas y logros para usuarios que estén jugando actualmente en el servidor. Si el usuario abandona el servidor, hay un breve periodo de gracia para establecer cualesquiera estadísticas finales, pero después cualquier nueva subida de estadísticas será denegada. Esto es para contribuir a garantizar la consistencia y evitar hacer posible para un servidor de juego malicioso establecer las estadísticas de alguien en cualquier momento. Dada la restricción, es importante no esperar hasta el final de una ronda para establecer las estadísticas. Han de establecerse de forma continuada, para poder almacenarlas cuando un usuario abandona el servidor.

Los clientes obtendrán actualizaciones automáticas cuando un servidor de juego cambie sus estadísticas. Sin embargo, al igual que los clientes, las estadísticas cargadas por el servidor para otros usuarios no se actualizan automáticamente y pueden quedar obsoletas.

Restablecer estadísticas

Durante el desarrollo, a menudo sucede que es deseable una eliminación completa de estadísticas y logros en una cuenta o en todas ellas con fines de prueba. Para borrar las estadísticas de una cuenta, llama a ISteamUserStats::ResetAllStats con bAchievementsToo establecido en true para borrar también los logros. Cuando termine la llamada, acuérdate de reiterar las estadísticas y logros, y restablecer el estado de juego en memoria. No hay forma de eliminar globalmente las estadísticas y los logros para todos los usuarios. Una de las razones para ello es que, incluso si se hiciera una eliminación global, el progreso dentro del juego podría detectar la eliminación y rescribir los valores en memoria. Afortunadamente, hay una forma sencilla de elaborar un sistema para eliminaciones globales integrado en los juegos. Para ello:
  • Define una estadística con un nombre como "Versión".
  • Pon un número de versión para estadísticas codificado de forma rígida en el juego.
  • Una vez que se hayan cargado las estadísticas, compara la estadística "Versión" con tu número de versión codificada.
  • Si no coinciden, llama a ISteamUserStats::ResetAllStats y luego configura la estadística "Versión" con el número codificado.
De esta forma, siempre que quieras hacer una eliminación global, solo tendrás que cambiar el número de versión para las estadísticas codificadas de forma rígida. La eliminación global tendrá lugar después, a medida que los usuarios accedan a la nueva compilación.

Consistencia de estadísticas

Es una práctica recomendada considerar que las estadísticas relacionadas podrían volverse inconsistentes. Por ejemplo, puedes tener tres estadísticas: "GamesWon", "GamesLost" y "GamesPlayed". A pesar de estar diseñadas con las mejores intenciones, las estadísticas pueden perder (y de hecho pierden) la sincronización entre sí. En este caso, podría producirse que las partidas ganadas y perdidas no dieran como suma el número total de partidas jugadas. Si esto se resolviera eliminando la estadística "GamesLost" y en su lugar se computara el valor como "GamesPlayed" - "GamesWon", una inconsistencia podría causar que "GamesLost" resultara en un valor negativo. En este caso, es mejor eliminar las estadísticas "GamesPlayed" y computar el valor como "GamesWon" + "GamesLost".

Estadísticas globales

Las estadísticas pueden marcarse como agregadas en la página de administración para ordenar a Steam mantener un total global de todos los valores de los usuarios para la estadística. Puede usarse para obtener datos del total de dinero en la economía, el total de muertes, armas favoritas, mapas favoritos y qué equipo suele obtener mejores resultados. Por otro lado, esta opción no debería usarse para estadísticas como "MostKills", ya que la suma total de ese valor para varios usuarios no tendría sentido. Como las estadísticas están en manos de los usuarios, estos datos están sujetos a manipulación. Por lo tanto, es crucial que cuando se usen estadísticas agregadas se establezcan buenos límites para el valor mínimo, el valor máximo, solo incremental (si fuese apropiado) y la diferencia máxima. La diferencia máxima tiene un significado especial para estadísticas agregadas. Cuando se carga un nuevo valor, el cambio en el valor global no superará el valor de la diferencia máxima. Esto limita lo rápido que un tramposo puede influenciar los totales globales.

Para acceder a los totales globales, llama a ISteamUserStats::RequestGlobalStats y luego ISteamUserStats::GetGlobalStat para cada estadística global. También puedes solicitar ISteamUserStats::RequestGlobalStats para un número específico de días de historial. El historial es la cantidad que cambió la estadística cada día. Puedes acceder a ese historial con ISteamUserStats::GetGlobalStatHistory.

También se pueden solicitar al cliente los porcentajes de los logros globales finales. Para hacerlo, primero llama a ISteamUserStats::RequestGlobalAchievementPercentages. Luego, ordena los logros en orden descendente de finalización llamando a ISteamUserStats::GetMostAchievedAchievementInfo y ISteamUserStats::GetNextMostAchievedAchievementInfo. También puedes obtener el porcentaje de finalización para un logro en particular llamando a ISteamUserStats::GetAchievementAchievedPercent.

Pruebas


Hasta que no se publique tu aplicación, no podrás ver qué logros se han obtenido en la Comunidad Steam ni en la biblioteca. La aplicación necesitará una forma de presentar los logros obtenidos por el usuario.

Para borrar un logro o estadísticas sin agregar código al juego, puedes usar la consola del cliente de Steam. Ejecuta steam.exe -console y luego escribe:
  • achievement_clear <appid> <achievement name>
  • reset_all_stats <appid>

La Comunidad de Steam

Después de que el desarrollador haya publicado el juego, la información sobre el progreso individual y global de logros se mostrará en la Comunidad Steam. Cada jugador tendrá un enlace desde su perfil de la comunidad que lleva a una página donde se muestran sus logros ya conseguidos y cuáles quedan aún por desbloquear.
NOTA: tus logros no se mostrarán hasta que tu aplicación sea visible para la Comunidad.

Cada logro se incluye con el ícono apropiado, y el nombre y la descripción tal y como se hayan establecido en el panel de control de Steamworks. Si el nombre y la descripción del logro han sido traducidos al idioma que el usuario haya elegido, se mostrarán en ese mismo idioma.

También habrá un enlace desde esta página y otro desde la página principal de Steam de tu juego para establecer un conjunto de estadísticas de logros globales para el mismo. Muestra el porcentaje de jugadores de Steam que han alcanzado cada logro, ordenados desde el logro más común al más infrecuente. Esto es algo que a los jugadores les gusta ver y también un gran recurso para los desarrolladores: ¿son los retos más especiales lo suficientemente difíciles? ¿O tal vez demasiado difíciles? (Esta información también está disponible en el sitio de informes de ventas y activaciones).

¿Tienes más preguntas?

Plantea tus preguntas en el foro de discusión de estadísticas y logros.