La idea detrás de todo esto es poder ejecutar scripts en función de las acciones realizadas en EmulationStation.
El principal uso es en los Raspberry Pi y otros sistemas embarcados porque estos sistemas permiten un control sencillo del hardware y de sus extensiones.
A partir de un determinado número de eventos de EmulationStation, vamos a poder lanzar un script (también llamado ejecutable) o bien enviar un mensaje MQTT para que otros sistemas reaccionen.
Para cada evento se proporciona un fichero lleno de un montón de informaciones que los scripts podrán utilizar si necesario.
En la siguiente lista se describen todos los eventos soportados, cuando son lanzados y las informaciones adicionales que se envían como parámetros a los scripts.
Evento | ¿Cuando? | Parámetros |
---|---|---|
Start | Arranque o reinicio de EmulationStation | Número de arranques |
Stop | Parada de EmulationStation | Número de arranques |
Shutdown | Parada completa del sistema | |
Reboot | Reinicio del sistema | |
Quit | Parada de EmulationStation como reaccion a una petición externa (parada del GPI case a través del botón on/off por ejemplo) | |
Relaunch | Reinicio de EmulationStation (cuando se modifica el fichero gamelist.xml desde el exterior o cuando se lanza una actualización de la lista de juegos desde EmulationStation) | |
SystemBrowsing | El usuario se encuentra en la lista de todos los sistemas y se selecciona un nuevo sistema. | Nombre corto del sistema |
GamelistBrowsing | El usuario se encuentra dentro de la lista de juegos de un sistema y selecciona un nuevo juego (o directorio). | Ruta del fichero seleccionado |
RunGame | Se va a lanzar un juego | Ruta de la rom del juego |
RunDemo | Se va a lanzar un juego en modo demo | Ruta de la rom del juego |
EndGame | Se acaba de salir de un juego | Ruta de la rom del juego |
EndDemo | Se acaba de terminar la demo de un juego | Ruta de la rom del juego |
Sleep | Arranca el protector de pantalla | |
WakeUp | Salida del protector de pantalla | |
ScrapStart | Se ha lanzado una sesión de scrapping multi-juegos | |
ScrapStop | Se ha terminado una sesión de scrapping multi-juegos | Número de juegos scrapados |
ScrapGame | Se acaba de scrapar un juego. | Ruta de la rom del juego |
ConfigurationChanged | Se ha modificado algo en la configuración |
Los scripts del usuario se deben colocar dentro de /recalbox/share/userscripts
o \\recalbox\share\userscripts
. Se pueden organizar en subcarpetas.
EmulationStation selecciona automáticamente el intérprete del script en función de su extensión:
Todas las demás extensiones se consideran ficheros ejecutables y se intentan lanzar directamente.
En el momento de escribir esta documentación, Python3 no está totalmente soportado todavía por Recalbox!
Cada script o ejecutable se lanza con los siguientes argumentos:
script -action action -statefile statefile [-param parameter]
Por defecto, los scripts se lanzan por todos los eventos.
Para filtrar y sólo lanzar los scripts en determinados eventos, basta con indicar dichos eventos entre corchetes y separados por comas. No importa si se escribe en mayúsculas o minúsculas.
Por ejemplo : /recalbox/share/userscripts/marquee[start,stop].sh
se lanzará únicamente al arranque o parada de EmulationStation.
O por ejemplo : /recalbox/share/userscripts/gamesinfo[browsinggamelist,rungame,rundemo,scrapgame].sh
se lanzará únicamente en los eventos relacionados con los juegos, para mostrar las informaciones de dichos juegos en una segunda pantalla.
Todos los scripts se lanzan de forma asíncrona, es decir, EmulationStation continúa su ejecución mientras que vuestro script se ejecuta en paralelo.
En la mayoría de los casos esta diferencia entre síncrono y asíncrono no es importante, pero puede ocurrir que se quiera bloquear EmulationStation hasta que nuestro script termine su ejecución. Un caso típico es el de un script que se ejecutaría sobre los eventos de reinicio o de parada del sistema.
En este caso, hay que asegurarse que nuestro script se ejecute antes de que el sistema comience el proceso de parada, o de lo contrario podríamos perder información o no terminar la ejecución de nuestro script (el sistema se pararía antes que nosotros).
Para que un script se ejecute de forma síncrona, basta con añadir (sync)
en el nombre del fichero.
Por ejemplo: /recalbox/share/userscripts/backup[reboot,shutdown](sync).sh
se lanzará al reinicio o parada de Recalbox. EmulationStation quedará bloqueado durante la ejecución del script y el proceso de apagado del sistema no comenzará hasta que nuestro script termine su ejecución.
Algunos scripts necesitan ejecutarse en continuo, sobre todo cuando son utilizados para interceptar mensajes los MQTT que vamos a describir más tarde.
Basta con colocar (permanent)
en el nombre del fichero para que el script se lance al arranque de Recalbox.
Si EmulationStation se reinicia, los scripts permanentes continuarán su ejecución y no se reiniciarán.
Recalbox proporciona un mini servidor MQTT (Mosquitto) que permite implementar un protocolo de "publish/subscribe".
Cuando EmulationStation lanza un script a partir de un evento, también publica dicho evento (todo en minúsculas) en el topic /Recalbox/EmulationStation/Event
de MQTT.
Un programa que escuche este topic puede interceptar todos los eventos de EmulationStation de una forma muy sencilla. Mosquitto también proporciona dos pequeños ejecutables mosquitto_pub
y mosquitto_sub
que permiten respectivamente publicar un mensaje o recibir uno.
De esta forma, podéis utilizar mosquitto_sub
en vuestros scripts para escuchar y leer los eventos de EmulationStation, de la siguiente forma:
event = $(mosquitto_sub -h 127.0.0.1 -p 1883 -q 0 -t /Recalbox/EmulationStation/Event -C 1)
Esta instrucción bash bloquea la ejecución del script hasta que se lea un evento. El tipo de evento se recupera en la variable event
.
Se comprende rápidamente el beneficio de los scripts permanentes: en lugar de ejecutar un script cada vez, para cada evento, se puede ejecutar un script permanente y hacer que intercepte todos los eventos en un ciclo. Es una solución mucho menos pesada para el sistema.
Mosquito escucha por defecto en la IP de loopback 127.0.0.1, lo cual impide su utilización fuera de Recalbox, por razones de seguridad.
Para modificar la configuración de Mosquito, consultad: https://mosquitto.org/man/mosquitto-conf-5.html
A cada evento, EmulationStation escribe un pequeño fichero en el disco de ram: /tmp/es_state.inf
.
Este fichero es un fichero de tipo ini que contiene asociaciones de clave=valor.
Este fichero se encuentra en su version 2.0. Al principio contenía un número fijo de claves, con valores vacíos dependiendo del contexto. La version 2.0 conserva la compatibilidad con la version 1.0 y añade varias claves fijas y opcionales dependiendo del contexto.
Aquí tenéis la lista de claves/valor disponibles desde la versión 1.0:
Clave | Valor | ¿Puede estar vacía? |
---|---|---|
System | Nombre completo del sistema relacionado con el evento. | Oui |
SystemId | Nombre corto del sistema relacionado con el evento. | Oui |
Game | Nombre completo del juego relacionado con el evento. | Oui |
GamePath | Ruta completa de la rom relacionada con el evento. | Oui |
ImagePath | Ruta completa de la imagen del juego relacionada con el evento. | Oui |
State | Contiene uno de los siguientes valores : playing : un juego está funcionando demo : un juego está funcionando en modo demo selected : todos los demás casos. |
Non |
Y aquí tenéis la lista de todo lo que se ha añadido desde la version 2.0:
Clave | Valor | Eventos |
---|---|---|
Action | El nombre del evento que ha generado la escritura del fichero state. | Todos |
ActionData | Parámetros del evento, puede estar vacío | Todos |
Emulator | Emulador por defecto relacionado con el sistema. | BrowsingSystem |
Core | Core por defecto relacionado con el sistema. Puede tener el mismo valor que la clave emulador para los emuladores standalone como Amiberry. | BrowsingSystem |
Emulator | Émulador utilizado para lanzar el juego. | Juegos (*) |
Core | Core utilizado para lanzar el juego. La misma observación que para el core sistema. | Juegos (*) |
IsFolder | 1 cuando se selecciona un directorio en la lista de juegos. 0 cuando se trata de un juego. | Juegos (*) |
ThumbnailPath | Ruta completa a la imagen miniatura del juego. (**) | Juegos (*) |
VideoPath | Ruta completa al vídeo del juego. (**) | Juegos (*) |
Developer | Nombre del desarrollador o de la empresa de desarrollo del juego. (**) | Juego (*) |
Publisher | Nombre del editor. (**) | Juegos (*) |
Players | Número de jugadores. (**) | Juegos (*) |
Region | Región del juego. (**) | Juegos (*) |
Genre | Género del juego. (**) | Juegos (*) |
GenreId | Identificador numérico del género del juego. (**) | Juegos (*) |
Favorite | 1 si el juego está en los favoritos, 0 en caso contrario. (**) | Juegos (*) |
Hidden | 1 si el juego está escondido, 0 en caso contrario. (**) | Juegos (*) |
Adult | 1 si el juego es para adultos, 0 en caso contrario. (**) | Juegos (*) |
(*) En detalle se aplica a: GameBrowsing, RunGame, RunDemo, EndGame, EndDemo et GameScrap.
(**) Cada una de estas informaciones se extrae de los metadata asociados al juego. Puede estar vacía si el juego no ha sido scrapeado.
Este fichero es escrito antes de lanzar los scripts y antes de que el mensaje MQTT se envíe. El fichero es válido durante la ejecución de los scripts, no obstante... Como algunos eventos se lanzan muy rápido unos detrás de otros, es posible que el fichero haya sido modificado por un segundo evento cuando intentaréis leerlo para responder al primero. Para evitar esto se aconseja:
- Comporobar el valor de la clave
action
para asegurarse que el contenido del fichero corresponde bien al evento que se quería tratar.- No suponer nunca que una clave opcional está presente o que una clave fija contendrá un valor.
Aquí tienes una serie de consejos para escribir tus scripts. Eres libre de no tenerlos en cuenta, pero ten en cuenta que ejecutar scripts en cada evento de EmulationStation puede tener un impacto en el sistema:
En la medida de lo posible, limita tus scripts al mínimo estrictamente necesario.
Evitad los scripts que no filtran los eventos. Si Recalbox agrega eventos en futuras versiones, tus scripts serán aún más solicitados.
Evitad los scripts síncronos si no es estrictamente necesario (durante la fase de apagado).
Utilizad al máximo el shell ASH
en lugar de SH
. Es mucho más veloz y está mejor optimizado. Sin embargo, tened presente que existen algunas diferencias con SH
.https://fr.wikipedia.org/wiki/Almquist_shell
Si necesitáis tratar muchos eventos a la vez, utilizad un sólo script permanente junto con mosquitto_sub
para ahorrar en recursos de vuestro sistema.