Journal Li-Ri : fork et portage de Ri-Li sous Android

Posté par  (site web personnel) . Licence CC By‑SA.
Étiquettes :
58
19
déc.
2023

Sommaire

Petit journal pour présenter les différentes tâches que j'ai du réaliser pour porter Ri-Li sous Android.

Description

Ri-Li est un jeu développé entre 2006 et 2007 en C++ avec la bibliothèque SDL par Dominique Roux-Serret. Il fonctionne sous Linux, Windows, MacOS et AmigaOS.
Il avait fait l'objet de plusieurs dépêches, la dernière présentant la version 2.0.0.
Mon but était de le porter sous Android (avec un neveu fan de trains, faisons lui plaisir !) sans trop m'embêter de préférence.

N'ayant pas pu rentrer en contact avec Dominique, j'ai préféré forker le projet et le renommer en Li-Ri.
Premièrement car mon talent pour trouver un nom n'a d'égal que mon talent de graphiste et que c'était le plus simple pour modifier les images (et c'était déjà beaucoup à mon niveau !).

Compilation du code initial

Pour rentrer dans la phase de développement, le code original ne compilait plus sous Linux. J'ai appliqué les différents patchs qui ont été utilisés pour faire la version FlatPak : désactivation de la compilation pour Gentoo, utilisation de iostream à la place de iostream.h, des comparaisons de buffer avec <= au lieu de == (ordered comparison of pointer with integer zero).

SDL1.2 => SDL 2

Maintenant que le code compile, je peux enfin m'attaquer au coeur du problème. Euhhh non, pas encore, le code utilise SDL 1.2 et comme SDL est en train de passer en version 3, je décide quand même de le migrer en SDL 2 pour qu'il soit plus maintenable. L'inconvénient est de perdre certaines plateformes en échange d'autres. Mon but étant de compiler sous Android principalement, pas de souci de passer en version 2 (désolé pour les adorateurs d'AmigaOS qui était maintenu en SDL 1 mais plus officiellement en SDL 2).

J'épargne les détails, le gros du changement est dans ce commit.
Un guide de migration est disponible et gère pas mal de cas. Le plus compliqué est le changement d'affichage des buffers entre les SDL_Surface et les SDL_Renderer.
Avant, on pouvait afficher des surfaces sur d'autres surfaces, effacer certaines parties de la surface et ensuite afficher les surfaces à l'écran. La nouvelle façon consiste à dessiner sur un renderer unique directement et afficher le renderer à l'écran.
Il y avait 2 SDL_Surface principales avant pour faire du double buffering, maintenant c'est géré tout seul avec le renderer.
Je n'ai pas géré les fonctionnalités de capture d'écran. Sur la version originale, il y avait la possibilité en utilisant la touche F12 de faire une capture, mais je n'ai pas cherché à remplacer la fonctionnalité (n'ayant pas de touche F12 sur mon téléphone/tablette de toute façon).

Compilation Android

Bon maintenant, on a une version en SDL 2 (quasi-) équivalente à la version originale (aux bugs près non trouvés et les captures d'écran perdus).
Pour compiler sous Android, j'ai seulement regardé comment créer un paquet pour F-Droid.
J'avais déjà créé un paquet pour GCompris et il existe des paquets sur F-Droid utilisant SDL 1.2. J'ai donc adapté le code et suivi le guide android et ce post de blog du jeu Superflous Returnz.
Les gros points :
* Pour avoir les logs dans la console en utilisant adb, il ne faut pas utiliser printf/std::cout/std::cerr, mais SDL_LogInfo/SDL_LogError…
* Ne pas utiliser les fonctions fopen/fread/fseek/fclose mais SDL_RWFromFile/SDL_RWRead/SDL_RWseek/SDL_RWClose qui fonctionnent bien sur toutes les plateformes… Les ressources que l'on met dans le dossier assets:/ du paquet sont accessibles en faisant un SDL_RWFromFile(). Par exemple, si on a un fichier language.dat dans assets/ : SDL_RWFromFile("language.dat"). Attention, "./language.dat" ne fonctionne pas.
* Le fichier de configuration était stocké dans un emplacement différent en fonction des OS. Pour simplifier, SDL fournit la fonction SDL_GetPrefPath qui donne le "bon" chemin selon l'OS.
* Copier le template Android fourni par SDL et ajouter dans le Android.mk nos sources.
* Créer un paquet pour F-Droid. Je me suis inspiré d'un paquet déjà existant que j'ai adapté pour utiliser SDL 2. Le build est un peu magique, je n'ai aucune idée de ce qu'il se passe mais ça produit un APK à la fin qui fonctionne donc c'est cool, mon but initial est atteint !

Les musiques sont des fichiers .mod, donc il a fallu activer la compilation du plugin dans SDL_mixer qui permet de jouer les .mod.

Les données pour générer les images étaient dans un fichier séparé du code. Pour le moment, je les ai gardé séparées, mais idéalement, il faudrait qu'elles soient inclues dans le flot de développement.
Les images sont générées à partir de fichiers pov. J'ai du rajouter dans chacun des fichiers de description de générer en version 1.6 pour avoir une image proche de l'originale (il y a encore quelques petites différences mais rien d'important pour que je passe plus de temps) car sinon des changements de valeurs par défaut (ambient je pense) font que l'image est hyper claire.
L'exécutable pour générer les fichiers binaires de données est encore en SDL 1.2, je n'ai pas regardé pour le modifier pour le moment.

Portage CMake

Bonus : je n'avais pas prévu de bosser plus dessus mais bon la curiosité… J'ai donc migré le code vers CMake. En soi, rien de folichon, c'est un projet très basique et générique donc définitions des sources, ajout de l'exécutable, un petit coup d'IPO, deux-trois install par-ci par-là et bingo.
Là où c'est devenu plus intéressant est de générer via les actions Github les exécutables pour différentes plate-formes.
Le premier point a été de trouver comment installer de partout SDL2 et ses dépendances. J'ai tenté d'utiliser l'action officielle https://github.com/libsdl-org/setup-sdl mais elle ne gère que SDL2 et pas SDL2_mixer donc j'ai vite bloqué. En cherchant un peu plus, il y avait différentes solutions mais chacune par OS (apt install pour Linux, nuget pour Windows et brew pour macOS) et ça devenait vite compliqué.
Et puis, conan est venu frapper à ma porte ! Le point positif est qu'il y a des paquets SDL2 et SDL2_mixer sous conan. Les négatifs sont que ce sont des versions assez anciennes et pas encore sous la version 2 de conan (c'est en cours).
Et la gestion des versions des dépendances en C++, c'est compliqué. SDL demande OpenSSL en version 1.1.1 et tire PulseAudio qui lui veut OpenSSL en version 3.0.0. En forçant la main à conan dans le fichier de définition (conanfile.txt) en choisissant les versions pour certains paquets, ça passe enfin !

Bon ben, ça compile sur les 3 OS principaux, tant qu'à faire, autant packager ! Encore une fois, cmake vient avec l'outil cpack qui permet de générer des paquets dans différents formats. Il suffit de mettre un certain nombre de variables et cela va générer les paquets avec la bonne configuration.
Le plus compliqué étant de s'assurer qu'une fois installé, le paquet trouve bien les différents fichiers de données.

J'ai pu tester sur Linux et Windows, mais n'ayant pas accès à un mac, je n'ai pas pu tester le paquet macOS.

Un point assez positif est que le code des actions dans le fichier yaml est quasiment le même pour les 3 OS. Il faut que je regarde pour simplifier et utiliser une matrice si possible afin de ne plus dupliquer les lignes. La seule différence est l'installation de NSIS pour Windows, j'imagine qu'il y a la possibilité de pouvoir avoir cette étape seulement sur cet OS.

Les versions:
* Android (une seconde MR est en cours pour rajouter l'icône sur le jeu).
* Linux, Windows et macOS

TODO list or not TODO

Je ne souhaite pas trop m'impliquer dans le code et ce projet (dit-il après l'avoir migré à cmake tout un dimanche), mais il reste encore pas mal de choses intéressantes à faire pour rendre la maintenance plus simple :
* Le code requiert maintenant C++11 suite à l'utilisation du type array. Il n'était peut-être pas nécessaire de l'utiliser si on veut rester compatible avec des OS ayant des compilateurs sans C++11 mais bon, on verra en temps voulu.
* continuer les ports : Emscripten, NintendoDS, Nintendo Switch… SDL fonctionne sur beaucoup de plateformes !
* clang-tidy, cppcheck… un peu d'analyse de code statique montre qu'il y a quelques améliorations à faire
* Nettoyage du code. Certaines variables sont globales, certaines ne sont plus nécessaires suite à la migration (Ecran…).
* conan 2 + conanfile.py si ça apporte des avantages par rapport au conanfile.txt ?
* Traduction du code en anglais. La plupart des commentaires, noms de fichiers et variables sont en français. Traduire en anglais permettrait de simplifier la maintenance si des personnes non francophones souhaitent aider.
* Intégrer les données dans le dépôt principal.
* Faciliter le processus de traduction. Pour le moment, il faut générer des images dans un dépôt à part pour rajouter une langue et des textes.
* Améliorer le jeu/rendu ? Rendre facultatives les questions sur la Déclaration Universelle des Droits de l'Homme, c'est vraiment affiché petit sur téléphone, faire des images 4K…
* Utiliser vsync plutôt que de gérer les fps (frame par secondes) à coup de sleep.
* Migrer le code sous Codeberg, gitlab… et/ou faire une organisation Github pour partager la maintenance.

  • # Quelques images

    Posté par  (site web personnel) . Évalué à 10.

    J'ai oublié de mettre quelques images (ce qui me fait voir que j'ai oublié de les mettre à jour suite au changement de nom) :
    Menu

    Niveau

  • # Les petits vont pouvoir dire merci!

    Posté par  . Évalué à 4.

    Les miens sont devenus grands, majorité depuis 2 mois, mais petits ils ont beaucoup apprécié Ri-Li sur PC en petit jeu simple…

    Un autre jeu simple et ludique qui les faisait bien marrer, surtout que l'on y jouait à 2 en alternance, c'est Slingshot (canardage version assistance gravitationnelle ou l'on peut s'amuser… à progressivement trouver les trajectoires les + chiadées pour exploser l'autre!).

    Après, en shoot-them-up version pas gore (paintball de minimoys dans des décors de maison/jardins…), en prime jouable sur réseau local quand ils ont eu leur PC: World Of Padman!

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.