Video Summary and Transcription
Travis TI Kevin83 McGeehan, ingeniero de software senior, embajador de Task Videos, especialista en React Native, titular del récord de tareas en Pokemon Yellow Glitchless, proceso de verificación TAS para la validación de entrada de consola. Mickey Mouse $61 mil millones en ventas de mercancías, RPGs de Pokemon, concepto de speedrunning, diferentes categorías, TASing en emuladores, registros TAS en TASvideos.org, mascota TASbot. Verificación TAS, interfaces de controladores, mascota TASbot, desafíos de accesibilidad de T3 Boy, preservación de videos TAS, complejidad de Kolmogorov en la precisión de emulación. Qt para interfaces frontales de emuladores, beneficios de WebAssembly, integración del sitio web de T3 Boy con núcleos de emulación, integración de T3 stack para guardados de juegos, API de eventos de puntero personalizados, visión general de la interfaz de T3 Boy. Integración del módulo WASM en la plantilla de Next.js, declaración de función global en TypeScript, funciones importantes como cwrap para la interacción con WebAssembly. Función cwrap para la interacción con módulos de JavaScript, concepto de puntero en lenguajes de bajo nivel, gestión de memoria con malloc, heapuate y free. Carga de BIOS y gestión de memoria, manejo de valores individuales, uso de la función Add para callbacks, peculiaridades con la API de Web Audio y limitaciones de re-muestreo. Utilizando la API de Eventos de Puntero, función de guardado en la nube con autenticación de Discord, emulador T3Boy e integración de WebAssembly en React.
1. Explorando TypeScript y Speed Running
Travis TI Kevin83 McGeehan, ingeniero de software senior, embajador de Task Videos, especialista en React Native, poseedor del récord de tareas en Pokemon Yellow Glitchless, proceso de verificación TAS para la validación de entrada de consola.
Hola, soy Travis TI Kevin83 McGeehan. Soy ingeniero de software senior en Gordon Food Service, y soy embajador de Task Videos y administrador en Taskbot. Explicaré un poco sobre lo que son en un segundo, pero esta es una charla sobre TypeScript en speed running y el front end de emulación T3 boy. Así que voy a repasar quién soy, qué es Pokemon, por si acaso nadie sabe aún qué es speed running, y luego hablaremos sobre T3 boy, el nuevo emulador front end que construí en la pila de React y Next.js con WebAssembly.
Entonces, ¿quién soy? Soy especialista en React Native y GitLab CI CD en Gordon Food Service, mostrando patrones de React en JS World y React Summit. Soy poseedor del récord de tareas en Pokemon Yellow Glitchless y No Save Corruption categorías, que son solo algunas categorías diferentes para carreras más largas o más cortas con diferentes glitches. Y también fui poseedor del récord en las tareas de Red Blue Glitchless. Otros tienen récords en la categoría de Save Corruption también, donde puedes ganar en solo un minuto apagando la consola en medio de un guardado. Soy un embajador oficial de Task Videos donde alojamos los récords y archivamos videos de esos récords para diferentes juegos.
Y he realizado estas presentaciones en GDQ, TwitchCon, MagFest, Long Island Retro, Midwest Gaming Classic y el Linus Tech Tips Expo. También soy administrador del equipo de Taskbot, y volveremos a lo que son Task Videos y Taskbot en un segundo. Pero también, por si acaso alguien no lo sabe aún, Pokemon es la franquicia de medios más rentable en la historia, habiendo totalizado $99 mil millones en ventas de mercancías.
2. Explorando la Franquicia de Pokemon y la Verificación TAS
Mickey Mouse $61 mil millones en ventas de mercancías, RPGs de Pokemon, concepto de speedrunning, diferentes categorías, TASing en emuladores, registros TAS en TASvideos.org, mascota TASbot.
Y para comparar, Mickey Mouse solo ha totalizado $61 mil millones en ventas de mercancías , así que realmente es una franquicia masiva. Y los juegos de Pokemon son RPGs que implican capturar, entrenar y duelar en un universo ficticio de animales salvajes conocidos como Pokemon. Hay un popular programa de televisión de anime de Pokemon que lleva mucho tiempo al aire con algunas películas derivadas, y Pokemon Yellow, el juego en el que me especializo y que me interesó en este concepto de TAS, es parte de la primera generación de juegos RPG de Pokemon que fueron lanzados en el Game Boy en 1996 en Japón y 1998 en los EE. UU. La primera generación tenía más errores y estaba menos conectada al resto del universo general del anime de lo que eventualmente cambiaron para Yellow.
Y ahora hay nueve generaciones basadas en diferentes regiones de Japón, y recientemente también en algunos países diferentes. Así que he hablado mucho sobre speedrunning. ¿Qué es speedrunning? Speedrunning es la idea de jugar un videojuego a menudo, pero no necesariamente un videojuego retro, con un temporizador en marcha para rastrear el tiempo de finalización. Los speedrunners añaden objetivos de finalización arbitrarios a los juegos para habilitar el tiempo, creando una variedad de categorías potenciales de diferentes longitudes, es decir, terminar un juego con o sin glitches, o si quieres terminar en Pokemon, por ejemplo, si quieres vencer a los Elite Four, o capturar todos los Pokemon. Así que tienes todas estas diferentes categorías con diferentes tiempos. Y a veces estas carreras requieren herramientas externas que podemos escribir en algo como TypeScript, y esas ayudan a evaluar la calidad de la carrera, verificando cosas como la calidad de tus Pokemon, sus estadísticas, o ayudando con diferentes categorías como rastrear cuántos Pokemon has capturado. Así que eso es speedrunning, pero entonces, ¿qué es TASing y los videos TAS? Las speedruns asistidas por herramientas es la idea de jugar a través de juegos, no a mano, sino cuadro por cuadro en un emulador donde podemos pausar y evaluar la toma de decisiones perfecta, asegurando un movimiento y ejecución perfectos de estrategias, y rebobinando y regrabando estas entradas para corregir errores.
Esto actúa efectivamente como un piano de jugador lo hace para la música de piano, pero para un videojuego, y estos registros TAS se rastrean por separado en TASvideos.org en lugar de speedrun.com para mantener las carreras humanas y TAS independientes y justas. Así que esto es solo una visualización a la izquierda de cómo se ve un piano de jugador, y luego a la derecha, cómo se ve la grabación TAS. La misma idea fluyendo a través, pero en lugar de las teclas del piano, son las pulsaciones de botones de un videojuego. Ahora hablamos sobre speedrunning y TASing, pero luego hay otra capa que se adentra en lo que hago en estas masterclasses llamadas verificación TAS.
3. Explorando la Verificación TAS y la Emulación Web
Verificación TAS, interfaces de controladores, mascota TASbot, desafíos de accesibilidad de T3 Boy, preservación de videos TAS, complejidad de Kolmogorov en la precisión de emulación.
La idea de la verificación TAS es tomar estas interfaces de controladores e inyectar entradas en una consola programáticamente diseñando una interfaz personalizada para cada consola. Convertimos estos registros de entrada que construimos en un emulador a un formato que la consola puede entender eléctricamente con cómo se conecta a los controladores, y reproducimos esa secuencia de piano en lugar de en el emulador en la consola real. TASbot es nuestra mascota para realizar este proceso, y esto prueba que un emulador es lo suficientemente preciso como para simular perfectamente el comportamiento de una consola para todos los propósitos prácticos. Esto también actúa como una especie de suite de pruebas o prueba de Roma, que se puede usar para hacer una prueba unitaria o de integración de un emulador. Una vez que un registro de entrada ha sido probado en una consola, ahora se puede usar en cualquier otro emulador para probar que es de ese nivel de precisión.
Entonces, hablando de todo eso, ¿qué es entonces T3 Boy? Así que entremos en algunas de las historias de usuarios sobre por qué quise construir el sitio T3 Boy. Primero, accesibilidad. Algunos aspirantes a speedrunners pueden tener acceso solo a dispositivos limitados. Pueden ser jóvenes que solo tienen un teléfono móvil o solo un Chromebook en el que no pueden instalar aplicaciones. No tienen privilegios de administrador en el Chromebook. Así que pueden acceder a sitios web, pero no pueden instalar cosas. Además, ya hay emuladores móviles y de navegador, pero no tienen el nivel de precisión necesario para hacer la reproducción de cosas como TAS a un nivel de precisión que necesitamos para nuestra verificación. Puede que no admitan la BIOS oficial que el usuario sube. Nos aseguramos de que el usuario la suba por razones de derechos de autor. Pero si la suben, entonces podemos tener esa precisión adicional que necesitamos para algo como la verificación TAS. Y hay otros detalles de la precisión de emulación que no son comúnmente soportados en emuladores de navegador.
Otra cosa de la que me encanta hablar en este contexto es la preservación de speedruns y la preservación de TAS. Normalmente en los videos TAS, cuando tenemos un registro finalizado, creamos un video de ese registro TAS para ponerlo en YouTube y archivarlo en el sitio web. Pero esto es costoso, caro, y también de menor calidad porque el video tiene que ser comprimido para ser enviado a los usuarios finales. Así que una de las cosas que pensé al construir un emulador web es que la suma total de la Roma del juego, esa BIOS de la que hablé, y el emulador pueden actuar como un reproductor de video cuando se le da un registro de entrada en lugar de un video. Así que esto nos permite recrear el video en la computadora del usuario final y escalarlo directamente para su pantalla, aumentando la calidad del video de la reproducción. Y otra forma de pensar en esto es que es algo llamado complejidad de Kolmogorov en matemáticas. Reducir la complejidad total de los datos necesarios para recrear un programa es la idea de la complejidad de Kolmogorov. Y a veces verás desafíos para esto en el sitio web Stack Exchange CodeGolf donde un desafío específico tiene la idea de reducir la complejidad general de un programa. Así que otros problemas sobre hacer esto. Así que imagina que queremos hacer un emulador web más preciso. Históricamente, los emuladores que son lo suficientemente precisos para speedrunning han sido limitados a construcciones de PC de escritorio y el equipo necesario para transmitir carreras realizadas en el hardware original en lugar de un emulador es caro. Tienes que comprar todo el equipo especializado para poder capturar hardware de videojuegos antiguos. Así que los núcleos de emulador típicamente han sido escritos en lenguajes de bajo nivel como C y C++ para poder ejecutarse lo suficientemente rápido a la velocidad original de la consola. Y aunque C++ en sí es bastante portátil, las interfaces de usuario que construimos alrededor de él no son necesariamente tan portátiles.
4. Integrando WebAssembly y el Emulador T3 Boy
Qt para interfaces de emulador, beneficios de WebAssembly, integración del sitio web T3 Boy con núcleos de emulación, integración de T3 stack para guardados de juegos, API de eventos de puntero personalizados, descripción general de la interfaz T3 Boy.
Hemos hecho cosas como Qt en el pasado para diseñar estas interfaces de emulador. Y Qt solo ha comenzado recientemente a tener accesibilidad de web assembly. Así que eso se relaciona con el beneficio de la llegada de web assembly. Así que WebAssembly es un entorno de ejecución en sandbox para código binario. Su uso principal es para sitios web para habilitar la ejecución de código de alto rendimiento directamente en el navegador al tener una pequeña máquina virtual para código de alto rendimiento. Y scripting es la tecnología que nos permite tomar código C o C++ y compilarlo a WebAssembly, lo que significa que ahora podemos tomar nuestra emulación de alto rendimiento y altamente precisa que hemos construido para el escritorio y empaquetarla para que se ejecute en un sitio web. Y la interfaz de usuario del front end puede ser escrita en JavaScript u otros marcos web comunes como React o Angular e interactuar con el núcleo web wasm a través de hooks en Emscripten.
Y eso es lo que estamos llamando T3 Boy. Así que T3Boy.Versel.app es un sitio web que puedes seguir con el código QR aquí. Y la idea de esto es hacer exactamente eso, empaquetar el Gambat existente, Speedrunner, ahora el núcleo GSR en un front end web en lugar de un front end de escritorio. Y al integrarnos con el T3 stack, TypeScript, Tailwind y TRPC, podemos usar cosas como Discord OAuth para respaldar tus guardados de juegos y estados de guardado en la nube a través de la autenticación a tu usuario. Y el emulador también tiene un uso realmente genial de la API de eventos de puntero personalizados que hablaré más tarde para hacer algunas cosas más elegantes que normalmente no serían posibles en un emulador web básico de JavaScript. Y el emulador también se dimensiona a sí mismo y su salida de video de acuerdo con los mismos principios que previamente demostré para RGBscaler.com para maximizar la calidad de video de la salida como estaba hablando sobre propósitos de preservación.
Así que esto es lo que T3 Boy parece. Tienes tus pads de botones, tu inicio, seleccionar A, B, tus direcciones y un botón de encendido. Y también tuve que agregar un botón de reproducir/pausar porque no puedes simplemente iniciar el emulador automáticamente cuando se lanza el sitio debido a las protecciones que tienen ahora los navegadores sobre la reproducción automática de audio y video. Así que necesito un botón de inicio. Pero una vez que ese botón de inicio ha sido presionado por el usuario, pueden jugar esto como lo harían con un conjunto normal de botones de Game Boy. Y solo ten cuidado, vamos a ver muchas malas ideas que se avecinan aquí en ese trabajo. Una cosa que he aprendido al demostrar cosas sobre tecnología web es que si quieres aprender algo de la manera correcta en internet, lo primero que tienes que hacer es mostrar cómo hacerlo de la manera incorrecta.
5. Integrando el Módulo WASM en Next.js
Integración del módulo WASM en la plantilla de Next.js, Declaración de función global en TypeScript, Funciones importantes como cwrap para la interacción con WebAssembly.
Así que vamos a mostrarte algunas formas incorrectas de hacer las cosas. Y espero que todos podamos aprender juntos de las personas que den retroalimentación en el futuro después de esta charla.
Así que lo primero que hice fue integrar el módulo WASM en una plantilla de Next.js en un sitio web. Así que en la cabeza de la función del documento, añadí un script con la fuente apuntando a el paquete WASM, lo tenía en script y hacer un modo de exportación de un solo archivo. Y utilizo la estrategia before interactive para cargar el archivo JavaScript. Se supone que hay una forma de engancharse y cargar de forma perezosa esa función WASM, pero no estaba funcionando de la manera correcta en que lo estaba usando. Y así tuve que recurrir a simplemente usar un set timeout y esperar cinco o 10 segundos para que todo se cargara antes de intentar llamar a la función WASM.
Así que de nuevo, si alguien tiene experiencia haciendo ese tipo de cosas, me encantaría recibir consejos y retroalimentación después. Pero entrando en el núcleo de cómo luego integramos con el módulo de WebAssembly, he declarado una función global en TypeScript, que tiene el nombre module. Así que es un módulo global, pero Emscripten nombró su cosa module. Así que se llama, en realidad se llama module en el ámbito global. Y tiene estas funciones necesarias para interactuar con los enlaces de Emscripten para el código C. Y voy a explicar qué hace cada uno de esos enlaces. Así que el primero realmente importante es cwrap.
6. WebAssembly Memory Management
Función Cwrap para la interacción con el módulo JavaScript, concepto de puntero en lenguajes de bajo nivel, gestión de memoria con malloc, heapuate y free.
Cwrap devuelve una función de JavaScript que se puede usar para llamar a funciones exportadas en el módulo JavaScript. Esto toma argumentos como el nombre de la función que deseas llamar en el módulo C, el tipo de retorno de esa función, un array de tipos de argumentos. Molestamente, esto se duplica con el valor de los genéricos de TypeScript que pueden tipar la función de retorno. Parece realmente que Emscripten fue escrito antes de la llegada de TypeScript. Así que hay algo de duplicación allí. Pero cwrap nos devuelve entonces una función como, por ejemplo, gamback create. Gamback create nos da el objeto emulador completo, que en realidad solo nos da un puntero.
Un puntero en C y en lenguajes de bajo nivel es solo un número. No necesitamos pensar en ello de manera más compleja que simplemente, es un número que se usa para referenciar un cierto objeto en memoria. Cwrap nos devuelve esa función que se puede llamar para obtener un número que referencia nuestra ubicación de nuestro emulador de Game Boy en memoria. Luego hay tres conceptos más importantes para la gestión de memoria. En JavaScript, normalmente no necesitas preocuparte por la gestión de memoria, pero porque estamos interactuando con una biblioteca C, necesitamos hacer algo alrededor de la gestión de memoria. Así que malloc, heapuate y free son los más importantes.
Malloc asigna memoria para nosotros y nos da un puntero, nuevamente un número que referencia el inicio de esa sección de memoria. Heapuate es un array Uint8 en JavaScript que accede y establece bloques de memoria a la vez en lugar de punteros individuales. Cada malloc necesita un free correspondiente para que no se produzca una fuga de memoria. Hay una interacción realmente genial de conceptos entre cómo JavaScript hace la limpieza y cómo un lenguaje de bajo nivel hace la limpieza, donde en React podrías tener un use effect donde haces un malloc cuando algo cambia y luego en el retorno del use effect donde haces tu limpieza, harías ese free entonces para asegurarte de que no estás filtrando memoria.
7. WebAssembly Audio and Callbacks
Cargando BIOS y gestión de memoria, manejo de valores individuales, usando la función Add para callbacks, peculiaridades con la API de Web Audio y limitaciones de re-muestreo.
Cada vez que hace un nuevo malloc, hace un free correspondiente. En este ejemplo aquí necesitamos encontrar una manera de cargar la BIOS porque, como dije, la BIOS del Game Boy es algo que el usuario necesita proporcionar porque está protegida por derechos de autor de Nintendo. No podemos simplemente proporcionarla libremente en internet. Decimos, alójanos una sección de memoria de la longitud de la BIOS, establece los datos que tenemos para la BIOS en el área de heap en esa ubicación, y luego le decimos al emulador que cargue la BIOS dándole el puntero al objeto emulador y el puntero a donde cargamos esos datos. Y luego, después de que todo eso esté hecho y dicho, liberamos los datos de la BIOS como RAM para que no esté siendo utilizado.
Otro ejemplo son las funciones setValue y getValue. setValue y getValue son como heap U8 pero mejores para trabajar con números individuales de 8, 16, o 32 bits. Usamos setValue para decirle al núcleo del emulador cuántos ciclos intentar ejecutar, lo cual es útil porque queremos ir por aproximadamente un fotograma a la vez y renderizar ese fotograma de audio y video. Y podemos decirle, OK, ve 35,000 ciclos. Eso nos dará un fotograma. Y luego usamos getValue después de que el emulador ha ejecutado ese fotograma para verificar cuántos ciclos realmente ejecutó porque no puede ejecutar un número exacto de ciclos. Hace un comportamiento basado en eventos que significa que podría necesitar exceder eso un poco, así que necesitamos saber cuántos realmente ejecutó y lo obtenemos de vuelta después de ejecutar el emulador. Y sí, setValue y getValue son útiles para obtener esos tipos de valores individuales en lugar de intentar acceder a estos grandes valores de la RAM. Y cosas similares para obtener el video y el audio. Podríamos estar usando heap U8, pero el video sale en el orden incorrecto de rojo, verde, azul, así que realmente necesitamos volver y hacer una modificación en la rama que es una versión WASM para que el video salga en ese otro orden para que podamos usar el heap U8 completo y simplemente extraer un bloque de video a la vez.
De todos modos, continuando, también hay la función add. La función add es realmente útil cuando necesitamos tener una función de callback. En la biblioteca C, podrías darle a una cosa una función que está en otro lugar en C, pero también podemos en scripting darle una función de JavaScript que luego se porta al lado de WebAssembly. Así que la función add nos permite hacer algo como dar un callback de recuperación de botón al emulador que puede llamar para obtener el estado actual del botón, porque la forma en que funciona el emulador es que no puedes simplemente enviarle botones cuando quieras. Cuando llega al punto en que necesita leer botones y está en un bucle, necesita llamar a esa función de callback. Así que usamos la función add para obtener la función. Obtenemos un puntero de función de botón. Usamos C wrap como hicimos antes para obtener un getter de entrada, y luego realmente asignamos el puntero a esa ubicación de la función add al getter de entrada. Así que un poco complicado allí, pero veremos un poco más por qué necesitamos ese comportamiento de entrada también en un segundo. Así que otra cosa de la que quería hablar eran algunas peculiaridades interesantes con la API de Web Audio con las que me encontré al construir esto, que es que el audio del Game Boy sale realmente raro para la mayoría de los emuladores. El Game Boy era un sistema de audio de 2 megahercios, y creo que es como audio de 1-bit a 2 megahercios o algo loco así. Y re-muestrear eso es realmente complejo porque los navegadores solo nativamente en la API de Web Audio, excepto hasta 768 kilohertz, y eso depende del navegador. No es algo de especificación. Cada navegador tiene un límite diferente de cuán alto puede llegar su API de Web Audio en términos de re-muestreo nativo. Así que en el futuro, para solucionar esto, necesitaremos cambiar la biblioteca C subyacente al sitio para emitir audio pre-re-muestreado a 48 kilohertz, que es una frecuencia más normal para que un emulador esté usando y para reproducir en la web.
8. Pointer Events API and Cloud Saving
Utilizando la API de Eventos de Puntero, Función de Guardado en la Nube con Discord Auth, Emulador T3Boy e Integración de WebAssembly en React.
Otra cosa, y esta es una razón realmente genial por la que quería construir mi propio emulador sitio para esto, es usar la API de Eventos de Puntero. Así que hay este concepto llamado captura de puntero, que es como, si cambias un control deslizante de volumen o avanzas en un video, no quieres que el movimiento de tu dedo suba o baje un poco y se mueva fuera del avance y ya no lo estés arrastrando. Así que hay esta cosa llamada captura, donde una vez que lo estás moviendo, sigues moviendo ese control deslizante sin importar dónde vaya tu dedo en la pantalla hasta que sueltes tu dedo. Pero en el caso de las entradas de Game Boy, no queremos esa captura de puntero porque queremos emular el comportamiento de, por ejemplo, poner tu pulgar en el botón de arriba y moverlo al botón de la derecha. No levantas tu pulgar y lo pones en el botón de la derecha. Podrías mover tu pulgar directamente entre el botón de arriba y el botón de la derecha sin que se levante de la pantalla. Así que para emular eso, cada vez que obtenemos un evento de captura de puntero, tenemos que inmediatamente liberar la captura de puntero. Y eso nos permite, entonces, que cuando movemos nuestro pulgar del botón de arriba al cuadro del botón de la derecha en la pantalla, detecte ese nuevo objetivo y diga, hey, ahora estás presionando el botón de la derecha a nuestros eventos de puntero. Y esto es enorme porque también la API de Eventos de Puntero nos permite hacer algo como presionar el botón A en el lado derecho de la pantalla y el botón de arriba en el lado izquierdo de la pantalla. Y luego podemos hacer control multi-táctil y hacer todos nuestros métodos de manipulación avanzados que requieren movimientos muy precisos de los botones para llegar a lugares en la pantalla y manipular el RNG.
Así que por último, otra característica realmente genial de T3Boy fue habilitar el guardado en la nube. Discord Auth y una rápida base de datos de railway habilitaron copias de seguridad de guardado en la nube en el sitio para usuarios autenticados. Y esto lo implementé de forma gratuita en este momento. Así que si ustedes se vuelven locos y usan esto un montón, podría tener que bloquearlo detrás de una suscripción de Patreon o algo así. Pero por ahora, pueden salir y usar T3Boy y tener guardados de Game Boy respaldados en la nube en el navegador. Muchas gracias a todos por ver. Esto ha sido un recorrido por lo básico de configurar una integración de WebAssembly en un sitio web de React con la pila T3. Y espero que lo hayan disfrutado. Nos vemos la próxima vez.
Comments