Cuentas de jugador

Dale a los jugadores de tu juego una cuenta que conservan en todos los juegos de Aukimi, con partidas guardadas que los siguen de un dispositivo a otro, en el servicio de Aukimi o en uno propio.

En una frase#

Un jugador inicia sesión una vez en play.aukimi.com y encuentra esa cuenta en todos los juegos hechos con Aukimi, partidas guardadas incluidas. Tu juego pide la cuenta; nunca maneja la contraseña.

Por qué tu juego nunca ve la contraseña#

Cualquiera puede publicar un juego. Un juego que pidiera una contraseña de Aukimi sería una página de phishing perfectamente convincente, y ninguna cantidad de buenas intenciones de tu parte cambiaría lo que un desarrollador distinto podría publicar.

Así que la contraseña se escribe en play.aukimi.com y en ningún otro sitio. Tu juego llama a PlayerLoginAsync(), se abre una ventana del navegador con los colores propios de Aukimi, el jugador aprueba, y la ventana le entrega a tu juego un token.

Ese token se emite solo para tu juego. Un token del juego A presentado al juego B se rechaza, no se ignora, se rechaza. Ese es el punto: la cuenta se comparte entre juegos, el acceso no. Sin esto, un juego malicioso podría leer las partidas guardadas de un jugador en todos los demás.

Qué recibes sobre un jugador#

Dos cosas, y nada más:

RecibesNunca recibes
Un nombre para mostrar (PlayerName())La dirección de correo
Un id opaco, distinto en cada juego (PlayerID())Nada que lo identifique en otro sitio

El id cambia de un juego a otro a propósito. Dos desarrolladores comparando sus listas de jugadores no pueden saber que están viendo a la misma persona. Eso también te mantiene como procesador y no como responsable de esos datos, lo cual es una distinción legal y no decorativa.

Nada bloquea el bucle del juego#

Todo comando que habla con la red devuelve un número de trabajo, nunca un resultado. Tu bucle sigue corriendo a sesenta fotogramas por segundo mientras la petición está en curso, que es la razón entera por la que un juego no puede simplemente "esperar al servidor".

job = PlayerLoginAsync()

Luego, una vez por fotograma:

etat$ = PlatformJobState(job)
if etat$ = "done"
    resultat$ = PlatformJobResult(job)
    PlatformJobRelease(job)
endif
if etat$ = "error"
    Print(PlatformJobError(job))
    PlatformJobRelease(job)
endif

Libera el trabajo en cuanto lo hayas leído. Un trabajo que nunca liberas mantiene su resultado en memoria durante el resto de la sesión. Nada se rompe, nada te avisa, y la fuga solo aparece en una sesión de juego larga.

Jugar sin cuenta#

No todo el mundo quiere registrarse antes de probar un juego. PlayerGuestAsync(name$) crea una cuenta sin correo, guardada en este navegador.

Es una cuenta real: guarda, carga, y se puede reclamar más tarde, el jugador añade un correo y una contraseña, y las partidas existentes siguen sin moverse.

La trampa honesta: borrar los datos del sitio del navegador pierde esa cuenta, y no hay forma de recuperarla. Ese es el precio de "sin registro", y tu juego debería decirlo en lugar de dejar que el jugador lo descubra. PlayerIsGuest() está ahí exactamente para esa frase.

Guardar#

job = PlayerSaveAsync(donnees$)
job = PlayerLoadAsync()

La partida guardada es JSON con la forma que tú decidas, almacenado contra el par (este jugador, este juego). Los sigue a otro navegador, otra máquina, otra plataforma.

Para un puñado de valores, SetCloudDataVariable() y CloudDataVariable() son más simples, sin job, sin JSON. Comprueba CloudDataAllowed() primero: devuelve 0 cuando no hay ningún jugador con sesión iniciada, y escribir de todas formas no llegaría a ningún sitio en silencio.

Dibujar la pantalla#

Aukimi no dibuja ningún formulario de inicio de sesión. Un formulario compuesto por el motor siempre se parecería a una página web soltada sobre un juego de pixel art, y sería la única parte de tu juego que no podrías restilizar.

Lo dibujas tú. La única pieza que tiene que venir del navegador es la entrada de texto, así que CreateEditBox() te da un campo de entrada real que colocas tú mismo:

CreateEditBox(1)
EditBoxPosition(1, 20, 42)
EditBoxSize(1, 60, 8)
nom$ = EditBoxText(1)

La demo Player Account en la lista de ejemplos del Engine es una pantalla completa y funcional en un centenar de líneas. Ábrela, léela, y luego reemplaza cada Print() con tu propio arte.

Antes de que nada de esto funcione#

El juego debe estar declarado desde tu cuenta de Aukimi, en My games (aukimi.com/app/games): un título, la dirección donde se puede jugar, y las direcciones a las que tu juego tiene permitido volver. Hasta entonces PlayerAvailable() devuelve 0, y un buen juego dice "las cuentas no están disponibles" en lugar de parecer que se ha colgado.

Esa misma pantalla es donde ves quién está jugando. Lee los números por lo que son: cuenta jugadores que iniciaron sesión y sesiones iniciadas, nunca partidas jugadas. Un juego que nunca le pide a nadie iniciar sesión no muestra nada ahí, y la pantalla lo dice en lugar de mostrar un cero silencioso.

Usar tu propio servidor de cuentas#

Todo lo anterior habla con el servicio de cuentas de Aukimi. Si alojas tu juego en tu propio servidor, los mismos doce comandos pueden hablar con tu servicio en su lugar, y tu script no cambia ni una sola línea.

En el Engine: panel Multiplayer → sección Player accounts → elige My own server → rellena un campo, la dirección de tu servidor. Esa dirección es un ajuste de la escena, así que dos juegos pueden usar dos servicios distintos.

Dos formas de iniciar sesión a un jugador#

La elección se hace en tu script, no en un ajuste. Ambas formas existen sea cual sea el servidor al que apuntes.

La ventana (la que ya conoces)#

job = PlayerLoginAsync()

Se abre una ventana, el jugador inicia sesión ahí, y le entrega a tu juego el derecho a actuar en su nombre. Con el servicio de Aukimi esa ventana es play.aukimi.com. Con tu propio servidor, esa página es tuya, para construirla tú.

Directamente, con un usuario y una contraseña#

job = PlayerLoginAsync(username$, password$)

Sin ventana. Tu juego lee lo que el jugador escribió en tu propia pantalla y se lo envía a tu servidor. Más simple de escribir, y te deja conservar el aspecto de tu juego de principio a fin.

Advertencia: en esta forma, la contraseña viaja de tu juego a tu servidor tal como se escribió. Dos consecuencias, ambas firmes: la dirección de tu servidor debe empezar por https:// (solo una prueba en tu propia máquina está exenta), y esta forma solo está pensada para un servidor que sea tuyo.

play.aukimi.com la rechaza, a propósito. Aukimi nunca quiere estar en posición de ver la contraseña de un jugador, y tampoco debería un juego que tú no escribiste.

Las dos opciones son independientes del ajuste: un servidor casero puede perfectamente ofrecer solo la ventana, y nunca aceptar una contraseña directamente.

Un ejemplo concreto#

Un juego con su propia pantalla de "Sign in": dos campos de texto dibujados por el juego, un botón, y esto detrás del botón.

job = PlayerLoginAsync(typedName$, typedPassword$)
DO
    etat$ = PlatformJobState(job)
    if etat$ = "done"
        PlatformJobRelease(job)
        Print("Welcome " + PlayerName())
    endif
    if etat$ = "error"
        PlatformJobRelease(job)
        Print(PlayerLastError())
    endif
    Sync()
LOOP

Todo lo que viene después del inicio de sesión es idéntico al resto de esta página: PlayerSaveAsync, PlayerLoadAsync, PlayerName y los demás no saben, y no les importa, qué servidor respondió.

Qué tiene que responder tu servidor#

Se necesitan cuatro direcciones, sea cual sea el inicio de sesión que ofrezcas:

Para qué sirveQué espera el juego
Jugar como invitadoDevolver una cuenta sin correo
Quién es este jugadorEl nombre para mostrar, el id, si es invitado
Leer la partidaLos datos guardados
Escribir la partidaGuardar lo que envía el juego

Luego, según lo que decidas ofrecer:

  • La forma de ventana necesita una página de inicio de sesión en tu servidor, que le diga al juego quién inició sesión una vez terminado.
  • La forma directa necesita una dirección más, que toma un usuario y una contraseña y responde sí o no.

Las direcciones exactas, la forma de cada respuesta y los códigos de error están en el repositorio, en docs/engine-player-accounts.md. Ese archivo es el contrato; esta página es el mapa.

Nota: nada de esto funciona en una exportación nativa. Los comandos Player* necesitan un servidor con el que hablar y un navegador a través del cual hablar, y una build nativa no tiene ninguno de los dos.

Los comandos#

ComandoQué hace
PlayerAvailable()Si el servicio de cuentas está configurado para este juego
PlayerLoginAsync()Abre la ventana de inicio de sesión. Devuelve un job
PlayerLoginAsync(user, pass)Inicia sesión directamente, solo en tu propio servidor. Devuelve un job
PlayerGuestAsync()Crea una cuenta sin correo. Devuelve un job
PlayerLoggedIn()Si alguien tiene sesión iniciada ahora mismo
PlayerName()Su nombre para mostrar
PlayerID()Su id opaco, específico de este juego
PlayerIsGuest()Si es una cuenta sin correo
PlayerSaveAsync()Escribe la partida guardada. Devuelve un job
PlayerLoadAsync()La lee de vuelta. Devuelve un job
PlayerRefreshAsync()Renueva el token antes de que expire
PlayerLogout()Cierra sesión en este dispositivo
PlayerLastError()Por qué falló la última llamada