1 points par GN⁺ 2024-12-27 | 1 commentaires | Partager sur WhatsApp
  • CobolCraft est un serveur Minecraft implémenté en COBOL qui prend en charge la version la plus récente au moment de l’écriture, Minecraft 1.21.4
  • Il implémente déjà la génération de terrain infinie, le chargement dynamique des chunks, l’enregistrement sur disque des données du monde et des joueurs, l’import de mondes existants, le multijoueur, l’affichage de l’état du serveur, la destruction et la pose de blocs, l’inventaire, le crafting, le ramassage d’objets, le chat, les commandes, etc.
  • Les blocs ayant plusieurs états, orientations et interactions nécessitent beaucoup de code dédié pour fonctionner correctement, et de nombreux blocs ne sont pas encore pris en charge
  • Le projet a été développé avec GnuCOBOL sur Linux x86_64 ou arm64, et peut aussi être déployé avec Docker, mais la prise en charge d’autres systèmes d’exploitation comme Windows n’a pas été testée
  • Il extrait les données JSON du datapack de base de Minecraft ainsi que des .jar officiels du serveur et du client afin de générer du code COBOL à la compilation et de charger des données à l’exécution

Fonctionnalités du serveur Minecraft implémentées par CobolCraft

  • CobolCraft est un serveur Minecraft écrit en COBOL et prend en charge Minecraft 1.21.4
  • Les fonctionnalités implémentées incluent notamment :
    • génération de terrain infinie et chargement dynamique des chunks
    • sauvegarde sur disque des données du monde et des joueurs
    • prise en charge des formats de fichiers Minecraft et import de mondes existants
    • multijoueur avec nombre de joueurs simultanés configurable
    • ping/statut serveur pour apparaître en ligne dans la liste des serveurs
    • destruction et pose de blocs, avec code de loot tables généré automatiquement
    • interactions avec les blocs via clic droit
    • inventaire du joueur
    • crafting 2x2 et 3x3
    • entités d’objets et ramassage d’objets
    • chat
    • commandes en jeu et commandes de console interactives
    • configuration basée sur server.properties
    • whitelist persistante enregistrée dans whitelist.json
    • collisions très basiques des blocs et des joueurs, ainsi que physique des entités
    • dégâts de chute, dégâts du void, mort et réapparition

Étendue et limites de la prise en charge des blocs

  • Les blocs avec plusieurs états, orientations et interactions demandent beaucoup de code spécialisé pour fonctionner correctement
  • De nombreux blocs ne sont pas encore pris en charge
  • Parmi les blocs qui fonctionnent, on trouve :
    • torches
    • slabs
    • stairs
    • rotated pillars comme les logs
    • buttons non interactifs
    • doors
    • trapdoors
    • beds
    • signs

Environnement de build et d’exécution

  • CobolCraft a été développé avec GnuCOBOL et vise une exécution sur Linux
    • architectures cibles : x86_64 et arm64
    • la prise en charge d’autres systèmes d’exploitation comme Windows n’a pas été testée
    • Docker permet un déploiement indépendant de la plateforme
  • Les éléments requis pour un déploiement Linux sont les suivants :
    • GnuCOBOL 3.1.2 ou plus récent
    • GnuCOBOL 3.2 ou plus récent recommandé pour les performances
    • make
    • gcc, g++
    • zlib
    • curl pour télécharger le .jar officiel du serveur
    • Java 21 ou plus récent pour extraire les données du .jar du serveur
  • Les commandes de build et d’exécution sont les suivantes :
make --jobs=$(nproc)
make run
  • Il est possible d’utiliser l’image Docker Hub ou de construire l’image soi-même avant de l’exécuter
docker pull meyfa/cobolcraft:latest

git clone https://github.com/meyfa/CobolCraft.git cobolcraft && cd cobolcraft
docker build --tag meyfa/cobolcraft .

Configuration du serveur et accès réseau

  • La configuration du serveur s’effectue en modifiant le fichier server.properties
  • Ce fichier est généré automatiquement au premier lancement avec les valeurs par défaut de toutes les options prises en charge
    • server-port : valeur par défaut 25565
    • level-name : valeur par défaut "world"
    • white-list : valeur par défaut false
    • motd : valeur par défaut "CobolCraft"
    • max-players : valeur par défaut 10, maximum 100
  • Par défaut, le serveur n’est accessible que depuis la machine locale via localhost:25565
  • Pour le rendre accessible depuis l’extérieur, via un réseau local, un VPN, une redirection de port ou un serveur loué, on peut lier le port à 0.0.0.0:25565:25565 au lancement de Docker
docker run --rm -it -p 0.0.0.0:25565:25565 meyfa/cobolcraft

Pourquoi créer un serveur Minecraft en COBOL

  • Le développeur n’avait auparavant aucune expérience avec COBOL, mais les rumeurs et les préjugés autour du langage lui ont donné envie d’en apprendre davantage
  • Il a choisi d’écrire lui-même quelque chose, considérant que c’était la meilleure façon d’apprendre le langage
  • Il estime que choisir d’écrire un serveur Minecraft en COBOL a été à la fois une bonne et une mauvaise idée, en raison de la complexité et de l’ampleur du code de Minecraft
  • Il a dû construire à partir de zéro des choses qui seraient simples dans d’autres langages :
    • parsing et encodage JSON
    • traitement de plusieurs types de données binaires
    • réseau multijoueur temps réel
    • transposition du système orienté objet de Minecraft vers un langage procédural
  • Cette courbe d’apprentissage abrupte l’a amené à étudier et comprendre en profondeur COBOL et ses concepts, un processus qu’il dit avoir trouvé gratifiant
  • Il recommande GnuCOBOL Programmer's Guide aux personnes qui débutent avec COBOL
  • Pour apprendre le protocole de Minecraft, on peut consulter la documentation wiki.vg
  • Selon les cas, observer le trafic réel du serveur avec des outils comme Wireguard peut aussi aider à comprendre le flux d’informations

Organisation du code source et binaire d’exécution

  • Le code source COBOL se trouve principalement dans le répertoire src/
    • src/main.cob est le point d’entrée
    • src/server.cob contient le code de démarrage du serveur et la logique du jeu
  • Le répertoire codegen/ contient un générateur de code écrit en COBOL
    • il génère du code source supplémentaire à partir de données JSON comme le datapack de base de Minecraft
  • Le répertoire cpp/ contient du code source C++ pour les intégrations système difficiles à gérer en COBOL
    • gestion des sockets TCP bas niveau
    • timing de précision
    • gestion des signaux de processus
  • Toutes les sources COBOL et C++ sont compilées en un unique binaire cobolcraft

Extraction des données Minecraft et traitement JSON

  • Les applications officielles serveur et client de Minecraft Java Edition contiennent de nombreuses données :
    • blocs, objets, types d’entités
    • biomes
    • ID de protocole des paquets
    • tags comme les blocs extractibles à la pioche
    • recipes
    • loot tables indiquant quels objets tombent, et dans quelles conditions, lorsqu’un bloc est détruit
  • Le Makefile de CobolCraft contient des cibles qui téléchargent les .jar officiels et en extraient les données au format JSON
  • Les données JSON extraites sont utilisées de deux façons :
    • génération automatique à la compilation de code COBOL comme les loot tables des blocs
    • chargement des données en mémoire à l’exécution
  • Ces deux traitements utilisent un parseur JSON générique écrit en COBOL et couvert par des tests unitaires

Tests et mises à jour

  • Les tests unitaires se trouvent dans le répertoire tests/
  • Les tests utilisent un framework de test personnalisé basé sur des copybooks
    • il suit les suites de tests, les unités et les assertions
    • il fournit un résumé à la fin de l’exécution
  • La commande pour lancer les tests est make test
  • L’objectif principal des tests est de valider des zones difficiles à déboguer, comme l’encodage et le décodage des données JSON et binaires
  • L’auteur considère que les tests de la logique de jeu elle-même sont moins importants
  • La procédure de mise à jour du serveur vers une nouvelle version de Minecraft ainsi que les étapes de test sont décrites dans Updating.md

Licence et marque

  • CobolCraft est distribué sous licence MIT
  • « Minecraft » est une marque de Mojang Synergies AB
  • CobolCraft n’est pas affilié à Mojang et n’est pas un projet approuvé par Mojang

1 commentaires

 
GN⁺ 2024-12-27
Avis sur Hacker News
  • Il y a beaucoup de rumeurs et de stigmates autour de COBOL ; ce serait bien que l’auteur écrive ce qu’il en a réellement tiré comme enseignements.
    Moi aussi, je n’ai entendu que ce genre de choses, et je suis curieux de savoir ce qu’un débutant en COBOL a rencontré en réalisant un premier projet assez complexe.

    • Il existe un stigmate mi-plaisanterie selon lequel la variante orientée objet de COBOL aurait une forme ingérable nommée ADD ONE TO COBOL YIELDING COBOL.
      Cela dit, contrairement à l’ancien FORTRAN, il n’ignorait pas les espaces au point que DO 10 I=1.10 soit compilé silencieusement comme l’affectation DO10I = 1.10 plutôt que comme une erreur de syntaxe dans une boucle. Le code voulu devait être DO 10 I=1,10.
    • C’est ce genre d’enseignements que j’aime.
      Si cela t’intéresse, voici ce que j’ai appris en créant un compilateur de COBOL vers C# : https://github.com/otterkit/otterkit-cobol/issues/40
      Je suis désormais convaincu que COBOL n’est qu’un assembleur de haut niveau.
  • Vraiment génial.
    Pour mon projet de fin de lycée, j’avais créé un système complet en COBOL pour automatiser les cotes de paris sur le football. C’était déjà une technologie dépassée, mais l’école n’avait pas encore rattrapé son retard.
    C’était absurdement inadapté, mais j’aimais chaque ligne. Il y a quelque chose d’étrangement satisfaisant dans un langage qui, à chaque frappe, semble murmurer : « tu te souviens des cartes perforées ? »

    • Le fait d’avoir utilisé du COBOL en majuscules pour un projet de lycée colle vraiment bien à l’époque. Ça a dû faire un excellent souvenir de lycée. J’espère que tous les noms de variables étaient des noms de dieux grecs.
  • Je me trompe peut-être, mais j’ai l’impression de voir assez souvent de petits side projects impressionnants écrits dans des langages simples et ordinaires comme C, ou ici COBOL.
    À l’inverse, des projets Rust similaires semblent souvent faire environ 10 fois plus de lignes de code tout en fonctionnant à peine.
    Mon hypothèse est que les langages simples permettent de capturer rapidement une idée comme un plan d’ensemble et de faire tourner quelque chose, même avec une base de code sale. Les langages modernes, eux, forcent à écrire du code censé durer plus longtemps. Ou alors les langages modernes font peut-être quelque chose de travers.

    • Un serveur Minecraft n’est pas exactement un petit side project.
      Il existe des serveurs en développement depuis 3 à 5 ans qui ne sont toujours pas terminés, et d’autres comme https://github.com/MCHPR/MCHPRS se concentrent sur certaines fonctionnalités pour des démonstrations de redstone.
      Ce serveur COBOL n’a pas encore implémenté la gestion de l’éclairage, et comme le spawn des mobs en dépend aussi, c’est l’une des parties les plus difficiles. Certains blocs ne sont pas non plus entièrement implémentés. Il faut des années pour terminer un serveur Minecraft, donc fabriquer quelque chose rapidement n’est pas toujours la bonne voie.
    • Je ne pense pas que ce soit forcément une illusion.
      Je travaille sur deux jeux en Rust, et avec le bon moteur, un prototype de gameplay vraiment minimal a été assez facile. Mais à mesure que j’ajoutais des fonctionnalités, le code a énormément gonflé, et le passage du solo au multijoueur a été un bazar. J’ai aussi perdu du temps à suivre des modes avant de les retirer.
      Rust déteste vraiment les structures en graphe où les objets de jeu sont reliés de façon complexe. Chaque fois qu’un événement de jeu entraîne des mises à jour de plusieurs types, il y a de la friction. Il y avait l’option de simplement l’accepter et d’écrire un peu plus de code, ou celle de chercher une solution systématique qui demanderait plus de code au début mais ferait gagner du temps ensuite.
      J’ai choisi la deuxième et fait quelques expérimentations, mais le seuil de rentabilité me semble trop éloigné pour un petit projet dont le seuil de rentabilité est 1.
      Même au sein d’un même langage, l’écart peut dépasser un ordre de grandeur. Rust a deux moteurs 3D utilisables : l’un est célèbre, compte beaucoup de contributeurs et reçoit un sponsoring capable de remplacer un salaire de la Bay Area ; l’autre est presque l’œuvre d’une seule personne, qui alterne entre vivre sur ses économies et travailler à plein temps.
      Pourtant, le premier moteur se concentre beaucoup sur la communication et promet diverses fonctionnalités depuis des années avec peu de choses à montrer, tandis que le second est en avance à la fois en nombre de fonctionnalités et en qualité d’implémentation.
      Au final, je pense que c’est une différence d’attitude. Il y a ceux qui codent pour le plaisir, ceux qui ont un objectif clair et se concentrent sur son atteinte, ceux qui le font pour l’argent, et ceux qui sont attirés par la reconnaissance publique. Une base de code sale n’est pas indispensable, mais il existe un juste milieu productif. Plus quelqu’un se concentre sur l’esbroufe, plus il risque de courir après les modes et les architectures tape-à-l’œil.
    • Rust a eu pas mal de mal à trouver sa percée dans le développement de jeux.
      Le postulat central de Rust consiste à échanger vitesse de développement et flexibilité contre sécurité mémoire, mais il s’avère que dans le développement de jeux, la vitesse de développement et la flexibilité comptent bien plus que la sécurité mémoire.
      Pour un microkernel à spécification formelle dont le plan est déjà détaillé jusque dans les moindres aspects, Rust peut être un excellent choix. À l’inverse, si l’on doit lancer rapidement de la boue contre le mur pour voir ce qui donne un gameplay amusant, Rust rend ce processus plus difficile que presque n’importe quel autre langage, avec des bénéfices peu évidents. On obtient surtout un morceau de gameplay rapide et sale, réalisé en plus longtemps, et légèrement plus sûr côté mémoire.
      Je ne suis pas le seul à avoir essayé le développement de jeux en Rust puis à l’avoir clairement abandonné pour cet usage. Par exemple, il y a “Leaving Rust gamedev after 3 years” [0], qui est l’un des articles liés à Rust les plus discutés et les plus appréciés jusqu’ici sur Hacker News.
      Plus largement, il est évident que Rust reçoit une attention bien plus exagérée que Cobol. Il y a donc beaucoup d’exemples de développeurs sensibles aux effets de mode, généralement des débutants enthousiastes, qui se sont courageusement lancés dans des projets open source ou hobby en Rust. À l’inverse, écrire un serveur Minecraft en Cobol demande un peu plus de fantaisie et d’audace, ce qui est en général associé à davantage d’expérience.
      [0] https://news.ycombinator.com/item?id=40172033
    • Au fond, ça ressemble à la différence entre les vrais hackers™, qui aiment les langages simples et peuvent créer un univers entier avec n’importe quoi, et les code monkeys qui courent après la dernière mode.
      Pour info, je me range moi-même dans la deuxième catégorie.
    • Les gens qui terminent les choses ne se soucient généralement pas trop de la qualité du code.
      À force d’essayer d’écrire du code qui durerait longtemps, je me suis retrouvé à un moment à ne plus rien finir. Au fil des années, j’ai trouvé un équilibre, appris qu’en améliorant de façon itérative du code pourri, il finit par devenir correct, et depuis, c’est comme ça que je fais.
  • https://raw.githubusercontent.com/meyfa/CobolCraft/main/src/...
    Pour quelqu’un qui vient d’un langage procédural, ce n’est en fait pas si difficile à comprendre, et ça me rappelle un peu les serveurs de jeu écrits en VB que j’avais vus il y a une vingtaine d’années

  • Depuis que j’ai arrêté d’utiliser COBOL en 1978, je n’ai jamais admis connaître ce langage
    Je fais un signe de croix en espérant ne pas voir ce code, puis je vais me chercher un café bien serré :-)
    Cela dit, c’est impressionnant d’avoir réussi ça

  • On peut se moquer, mais le code est assez lisible
    À comparer avec certains langages modernes où il faut fixer le code pendant plusieurs minutes pour comprendre ce qui se passe

    • J’ai travaillé un temps dans une entreprise FAANG et j’avais accès à des experts C++ de niveau mondial. Certains siégeaient à des comités internationaux de normalisation du langage
      J’ai demandé sur une liste interne C++ si une ligne de code donnée allait provoquer une fuite mémoire ; c’était du code utilisant uniquement des templates STL et des conversions de type. Et les experts n’arrivaient pas à se mettre d’accord sur le fait que je faisais les choses correctement ou non. Certains pensaient qu’il y aurait une fuite, d’autres non
      Cette petite histoire vraie en dit long sur C++. JavaScript est aussi rempli de ce genre de choses
    • C’était justement le point fort de COBOL
      J’ai commencé à programmer en 1976, j’ai appris COBOL et ICL PLAN, d’abord avec des cartes perforées, puis sur terminal après ma formation. Les programmes étaient à 100 % des programmes batch
      Il y avait un fort biais en faveur de la lisibilité, pour que n’importe qui puisse lire et comprendre le code source. Cela dit, cette lisibilité était en partie contrebalancée par le fait qu’il fallait lire et comprendre les core dumps générés quand un programme échouait. Au mieux, on pouvait remonter l’échec jusqu’à une ligne précise de code, ce qui m’a donné l’habitude d’exécuter le programme mentalement
      Quand j’ai quitté l’administration pour passer à la programmation commerciale, au début des années 80, c’était encore COBOL et des programmes batch. J’ai assuré le support de nuit pendant trois ans, et c’est là que la valeur de COBOL est apparue. Même avec un listing et un core dump que je voyais pour la première fois, je pouvais généralement corriger assez vite. Avec, bien sûr, la réserve que c’étaient toujours des corrections tactiques
    • C’est pour ça que j’aime Ada et VHDL
      Ils peuvent être un peu verbeux, mais ils sont bien plus lisibles que des langages plus « modernes »
    • COBOL a été conçu pour pouvoir être utilisé et lu par des non-programmeurs
      Du moins en théorie
    • MOVE FUNCTION MIN(BLOCK-ENTRY-MINIMUM-STATE-ID(LK-BLOCK), STATE-ID) TO BLOCK-ENTRY-MINIMUM-STATE-ID(LK-BLOCK)
  • Au lycée, dans une petite ville du Pakistan, j’ai appris un peu de COBOL
    Ce n’était pas mauvais, et j’ai fait un projet qui imitait des états financiers. Il y avait des aspects étranges, mais pour la plupart des humains, c’est-à-dire des non-programmeurs, n’importe quel langage de programmation doit sembler assez étrange, donc je ne comprends pas trop la mauvaise réputation de COBOL
    À la même époque, j’ai aussi appris le C, et c’est celui-là qui est resté :-)

  • J’entends toujours dire que les programmeurs COBOL sont rares et très bien payés
    Je me demande si ce projet lui a valu une avalanche d’offres d’emploi

    • Ce ne sont pas les programmeurs COBOL qui sont rares, ce sont les personnes qui comprennent la logique métier
      COBOL est souvent utilisé dans des opérations métier très complexes
    • Comme d’autres l’ont dit, le plus important est de comprendre la complexité de la logique métier existante, ainsi que les systèmes mainframe sur lesquels ce code tourne généralement
      Sinon, il suffirait de créer un compilateur croisé et ce serait terminé
    • Ces personnes ont de la valeur non pas tant pour leurs compétences en programmation que pour leur connaissance de systèmes très complexes, généralement peu documentés, et de leur contexte métier
  • COBOL ressemble en fait à un langage plutôt cool
    Le code est aussi vraiment bien organisé

  • J’aime le fait qu’il y ait des tests unitaires