- CobolCraft es un servidor de Minecraft implementado en COBOL y es compatible con Minecraft 1.21.4, la versión más reciente al momento de su creación
- Ya implementa generación de terreno infinita, carga dinámica de chunks, guardado en disco de datos del mundo y de jugadores, importación de mundos existentes, multijugador, visualización del estado del servidor, destrucción y colocación de bloques, inventario, crafting, recolección de ítems, chat, comandos y más
- Los bloques con múltiples estados, direcciones e interacciones requieren mucho código dedicado para implementar correctamente su comportamiento, y todavía hay muchos bloques no compatibles
- Fue desarrollado con GnuCOBOL en Linux x86_64 o arm64, y también se puede distribuir usando Docker, pero no se ha probado la compatibilidad con otros sistemas operativos como Windows
- Extrae datos JSON del datapack predeterminado de Minecraft y de los
.jar oficiales del servidor y del cliente, y los usa para generar código COBOL en tiempo de compilación y cargar datos en tiempo de ejecución
Funcionalidades del servidor de Minecraft implementadas por CobolCraft
- CobolCraft es un servidor de Minecraft escrito en COBOL y es compatible con Minecraft 1.21.4
- Las funcionalidades implementadas incluyen lo siguiente
- Generación de terreno infinita y carga dinámica de chunks
- Guardado en disco de los datos del mundo y de los jugadores
- Compatibilidad con formatos de archivo de Minecraft e importación de mundos existentes
- Multijugador con cantidad configurable de jugadores conectados simultáneamente
- ping/server status para aparecer en línea en la lista de servidores
- Destrucción y colocación de bloques, y código de loot tables generado automáticamente
- Interacción con bloques basada en clic derecho
- Inventario del jugador
- Crafting 2x2 y 3x3
- Entidades de ítems y recolección de ítems
- Chat
- Comandos dentro del juego y comandos interactivos de consola
- Configuración basada en
server.properties
- whitelist persistente guardada en
whitelist.json
- Colisiones muy básicas de bloques y jugadores, y física de entidades
- Daño por caída, daño por void, muerte y respawn
Alcance y límites de compatibilidad con bloques
- Los bloques con varios estados, direcciones e interacciones requieren mucho código especializado para comportarse correctamente
- Todavía hay muchos bloques no compatibles
- Entre los bloques que funcionan se incluyen
- torches
- slabs
- stairs
- rotated pillars como logs
- buttons sin interacción
- doors
- trapdoors
- beds
- signs
Entorno de compilación y ejecución
- CobolCraft fue desarrollado con GnuCOBOL y está pensado para ejecutarse en Linux
- Las arquitecturas objetivo son x86_64 y arm64
- No se ha probado la compatibilidad con otros sistemas operativos como Windows
- Con Docker es posible distribuirlo de forma independiente de la plataforma
- Los requisitos para distribuirlo en Linux son los siguientes
- GnuCOBOL 3.1.2 o superior
- Por rendimiento, se recomienda GnuCOBOL 3.2 o superior
make
gcc, g++
zlib
curl, necesario para descargar el .jar oficial del servidor
- Java 21 o superior, necesario para extraer datos del
.jar del servidor
- Los comandos de compilación y ejecución son los siguientes
make --jobs=$(nproc)
make run
- Se puede usar la imagen de Docker Hub o compilarla directamente y ejecutarla
docker pull meyfa/cobolcraft:latest
git clone https://github.com/meyfa/CobolCraft.git cobolcraft && cd cobolcraft
docker build --tag meyfa/cobolcraft .
Configuración del servidor y acceso por red
- La configuración del servidor se realiza modificando el archivo
server.properties
- Este archivo se genera automáticamente en el primer arranque con los valores predeterminados de todas las opciones compatibles
server-port: valor predeterminado 25565
level-name: valor predeterminado "world"
white-list: valor predeterminado false
motd: valor predeterminado "CobolCraft"
max-players: valor predeterminado 10, máximo 100
- De forma predeterminada, solo se puede acceder al servidor desde el propio sistema mediante
localhost:25565
- Para permitir acceso externo, como desde una red local, VPN, port forwarding o un servidor alquilado, se puede enlazar el puerto como
0.0.0.0:25565:25565 al ejecutar Docker
docker run --rm -it -p 0.0.0.0:25565:25565 meyfa/cobolcraft
Por qué crear un servidor de Minecraft en COBOL
- El desarrollador no tenía experiencia previa con COBOL, pero quería conocer mejor el lenguaje tras ver los rumores y estigmas sobre COBOL
- Eligió escribir algo por su cuenta como la mejor forma de aprender el lenguaje
- Considera que elegir escribir un servidor de Minecraft en COBOL fue una idea buena y mala a la vez, por la complejidad y escala del código de Minecraft
- Tuvo que construir desde cero tareas que en otros lenguajes son sencillas
- Parseo y codificación de JSON
- Procesamiento de varios tipos de datos binarios
- Networking multijugador en tiempo real
- Trasladar a un lenguaje procedural un sistema de Minecraft orientado a objetos
- Señala que la curva de aprendizaje pronunciada lo llevó a investigar y entender en profundidad COBOL y sus conceptos, y que el proceso fue gratificante
- Para quienes usan COBOL por primera vez, recomienda la GnuCOBOL Programmer's Guide
- Como material para aprender el protocolo de Minecraft, se puede consultar la documentación de wiki.vg
- En algunos casos, ver tráfico real de servidores con herramientas como Wireguard también puede ayudar a entender el flujo de información
Estructura del código fuente y binario ejecutable
- El código fuente COBOL está principalmente en el directorio
src/
src/main.cob es el punto de entrada
src/server.cob contiene el código de arranque del servidor y la lógica del juego
- El directorio
codegen/ contiene generadores de código escritos en COBOL
- Generan código fuente adicional a partir de datos JSON, como el datapack predeterminado de Minecraft
- El directorio
cpp/ contiene código fuente en C++ para integración con el sistema operativo que es difícil de manejar en COBOL
- Gestión de sockets TCP de bajo nivel
- Temporización precisa
- Manejo de señales de procesos
- Todo el código fuente COBOL y C++ se compila en un único binario
cobolcraft
Extracción de datos de Minecraft y procesamiento de JSON
- Las aplicaciones oficiales de servidor y cliente de Minecraft Java Edition contienen muchos datos
- Bloques, ítems y tipos de entidades
- biomes
- ID de protocol de paquetes
- tags, como bloques que se pueden minar con pico
- recipes
- loot tables que indican qué ítems caen bajo qué condiciones cuando se rompe un bloque
- El
Makefile de CobolCraft incluye targets para descargar el .jar oficial y extraer los datos como JSON
- Los datos JSON extraídos se usan de dos formas
- Generar automáticamente, en tiempo de compilación, código COBOL como las loot tables de bloques
- Cargar datos en memoria durante la ejecución
- Ambas tareas usan un parser JSON de propósito general, escrito en COBOL y con pruebas unitarias completadas
Pruebas y actualizaciones
- Las pruebas unitarias están en el directorio
tests/
- Las pruebas usan un framework de testing personalizado basado en copybooks
- Hace seguimiento de suites de prueba, unidades y assertions
- Entrega un resumen al finalizar la ejecución
- El comando para ejecutar las pruebas es
make test
- El objetivo principal de las pruebas es verificar áreas difíciles de depurar, como la codificación y decodificación de datos JSON y binarios
- Las pruebas de la lógica del juego en sí no se consideran tan importantes
- El procedimiento para actualizar el servidor a una nueva versión de Minecraft y los pasos de prueba están en
Updating.md
Licencia y marcas comerciales
- CobolCraft se distribuye bajo la MIT License
- “Minecraft” es una marca comercial de Mojang Synergies AB
- CobolCraft no está afiliado a Mojang ni cuenta con el respaldo de Mojang
1 comentarios
Opiniones en Hacker News
Hay muchos rumores y estigmas alrededor de COBOL; estaría bueno que escribieras qué aprendizajes concretos sacaste
Yo también solo he escuchado esas historias, y me da curiosidad saber con qué se topó un principiante en COBOL al implementar un primer proyecto bastante complejo
Aun así, no pasaba como con el FORTRAN antiguo, que ignoraba los espacios y podía compilar silenciosamente
DO 10 I=1.10no como un error de sintaxis de bucle, sino como una asignaciónDO10I = 1.10. El código pretendido seguramente eraDO 10 I=1,10Si te interesa, aquí hay cosas que aprendí creando un compilador de COBOL a C#: https://github.com/otterkit/otterkit-cobol/issues/40
Ahora estoy convencido de que COBOL no es más que un ensamblador de alto nivel
Realmente genial
Para mi proyecto de graduación de la secundaria hice un sistema completo en COBOL que automatizaba cuotas de apuestas de fútbol. Ya era una tecnología pasada de moda, pero la escuela todavía no se había puesto al día
Era absurdamente inadecuado, pero disfruté cada línea. Hay algo raramente satisfactorio en un lenguaje que, cada vez que tipeas, te susurra “¿te acuerdas de las tarjetas perforadas?”
Puede que sea una impresión equivocada, pero siento que veo bastante seguido proyectos personales pequeños e impresionantes escritos en lenguajes simples y comunes, como C o COBOL en este caso
En cambio, proyectos similares en Rust parecen tener unas 10 veces más líneas de código y aun así casi no funcionar
Mi hipótesis es que un lenguaje simple facilita capturar una idea rápidamente, como un plano, y hacer que una base de código desordenada al menos funcione. En cambio, los lenguajes modernos te obligan a escribir código que aguante más tiempo. O quizá los lenguajes modernos estén haciendo algo mal
Hay servidores que llevan 3 a 5 años en desarrollo y todavía no están terminados, y también hay otros enfocados en funciones específicas, como https://github.com/MCHPR/MCHPRS para exhibiciones de redstone
Este servidor en COBOL todavía no implementó el procesamiento de iluminación, y la generación de mobs también depende de eso, así que es una de las partes más difíciles. Algunos bloques tampoco están completamente implementados. Terminar un servidor de Minecraft requiere años, así que hacer algo rápido no siempre es el mejor camino
Estoy trabajando en 2 juegos en Rust y, si eliges el motor adecuado, fue bastante fácil hacer un prototipo de gameplay muy mínimo. Pero a medida que fui agregando funciones, el código creció muchísimo, y pasar de single-player a multiplayer fue un desastre. También perdí tiempo siguiendo modas y luego quitándolas
Rust odia de verdad las estructuras de grafos complejos donde los objetos del juego están conectados entre sí. Cada vez que un evento del juego deriva en actualizaciones de varios tipos, aparece fricción. Una opción era simplemente aceptarlo y escribir un poco más de código; otra era buscar una solución sistemática que ahorrara tiempo más adelante, aunque exigiera escribir más código al principio
Elegí la segunda e hice varios experimentos, pero siento que el punto de equilibrio queda demasiado lejos para proyectos pequeños con punto de equilibrio en 1
Incluso dentro del mismo lenguaje la diferencia puede ser de más de un orden de magnitud. En Rust hay 2 motores 3D utilizables: uno es famoso, tiene muchos colaboradores y recibe patrocinio suficiente como para reemplazar un salario del Bay Area. El otro lo mantiene casi una sola persona, alternando entre vivir de sus ahorros y trabajar full time
Pero el primer motor se enfoca mucho en la promoción y lleva años prometiendo varias funciones con poco para mostrar, mientras que el segundo está adelante tanto en cantidad de funciones como en calidad de implementación
Al final creo que es una diferencia de actitud. Hay gente que programa por diversión, gente con objetivos claros que se enfoca en cumplirlos, gente que lo hace por dinero y gente atraída por el reconocimiento público. Una base de código desordenada no es necesariamente imprescindible, pero existe un punto medio productivo. Cuanto más se enfoca alguien en lucirse, más fácil es que persiga modas y arquitecturas llamativas
La premisa central de Rust es intercambiar velocidad de desarrollo y flexibilidad por seguridad de memoria, pero en desarrollo de juegos quedó claro que la velocidad de desarrollo y la flexibilidad importan mucho más que la seguridad de memoria
Si tienes un microkernel con especificación formal ya delineada hasta el detalle, Rust puede ser una excelente opción. En cambio, si necesitas tirar barro rápido contra la pared para ver qué termina siendo gameplay divertido, Rust hace ese proceso más difícil que casi cualquier otro lenguaje y sus ventajas no son evidentes. El resultado es, como mucho, una pieza rápida y desordenada de gameplay que tardó más en hacerse y es apenas más segura en memoria
No soy el único que, después de hacer desarrollo de juegos en Rust, lo dejó claramente para ese uso. Por ejemplo, está “Leaving Rust gamedev after 3 years” [0], que hasta ahora es uno de los posts relacionados con Rust más discutidos y votados en Hacker News
En un plano más amplio, es evidente que Rust recibe muchísima más atención exagerada que COBOL. Por eso hay muchos ejemplos de desarrolladores vulnerables a esa ola de hype —normalmente principiantes entusiastas— que se lanzaron valientemente a proyectos open source o de hobby en Rust. En cambio, escribir un servidor de Minecraft en COBOL requiere un poco más de ingenio y audacia, y eso por lo general se asocia con más experiencia
[0] https://news.ycombinator.com/item?id=40172033
Por cierto, yo me pongo a mí mismo en la segunda categoría
En algún momento, por intentar escribir código que durara mucho, terminé en un estado en el que no terminaba nada. Con los años encontré el equilibrio, aprendí que si mejoras iterativamente código basura al final se convierte en algo decente, y desde entonces hago eso
https://raw.githubusercontent.com/meyfa/CobolCraft/main/src/...
Para alguien con experiencia en lenguajes procedurales, en realidad no es tan difícil de entender, y me recuerda un poco a esos servidores de juegos escritos en VB que vi hace unos 20 años.
Desde que dejé de usar COBOL en 1978, nunca volví a admitir que conocía este lenguaje.
Me persigno esperando no ver este código y me voy por un café bien cargado :-)
Aun así, es impresionante que lo hayan logrado.
Pueden burlarse si quieren, pero el código es bastante fácil de leer.
Contrasta con algunos lenguajes modernos en los que hay que quedarse mirando varios minutos para entender qué está pasando.
Pregunté en una lista interna de C++ si una línea específica de código podía provocar una fuga de memoria; era código que usaba puramente plantillas de STL y conversiones de tipo. Pero los expertos no lograron ponerse de acuerdo sobre si lo estaba haciendo correctamente. Algunos decían que habría una fuga, otros opinaban que no.
Esta pequeña historia real dice mucho sobre C++. JavaScript también está lleno de cosas así.
Empecé a programar en 1976 y aprendí COBOL e ICL PLAN; usé tarjetas perforadas y, después de terminar la capacitación, terminales. Los programas eran 100% programas batch.
Había un sesgo muy fuerte hacia la legibilidad para que cualquiera pudiera leer y entender el código fuente. Aunque eso se compensaba en parte con la necesidad de leer y entender los core dumps que se generaban cuando un programa fallaba. En el mejor de los casos podías rastrear la falla hasta una línea específica de código, así que se te quedaba grabado el hábito de ejecutar el programa mentalmente.
Cuando dejé una agencia gubernamental y pasé a la programación comercial, hasta principios de los 80 seguía siendo COBOL y programas batch. Hice soporte nocturno durante 3 años, y ahí se notaba el valor de COBOL. Incluso tomando un listado y un core dump que veía por primera vez, por lo general podía arreglarlo bastante rápido. Claro, siempre con la salvedad de que eran correcciones tácticas.
Pueden ser algo verbosos, pero son mucho más fáciles de leer que lenguajes más “modernos”.
Al menos en teoría.
MOVE FUNCTION MIN(BLOCK-ENTRY-MINIMUM-STATE-ID(LK-BLOCK), STATE-ID) TO BLOCK-ENTRY-MINIMUM-STATE-ID(LK-BLOCK)En la secundaria aprendí un poco de COBOL en una ciudad pequeña de Pakistán.
No estaba mal, e hice un proyecto que imitaba estados financieros. Tenía sus rarezas, pero para la mayoría de los humanos, es decir, para los no programadores, cualquier lenguaje de programación debe parecer bastante raro, así que no entiendo bien el estigma que carga COBOL.
Por la misma época también aprendí C, y ese sí se quedó conmigo :-)
Siempre escucho que los programadores de Cobol son escasos y ganan sueldos altos.
Me pregunto si a esta persona le llovieron ofertas de trabajo por este proyecto.
Cobol se usa a menudo en operaciones de negocio muy complejas.
Si no fuera así, bastaría con crear un cross-compiler y listo.
COBOL en realidad parece un lenguaje bastante genial.
El código también está muy bien organizado.
Me gusta que tenga pruebas unitarias.