1 pontos por GN⁺ 2024-12-27 | 1 comentários | Compartilhar no WhatsApp
  • CobolCraft é um servidor de Minecraft implementado em COBOL e oferece suporte ao Minecraft 1.21.4, a versão mais recente no momento da escrita
  • Já implementa geração infinita de terreno, carregamento dinâmico de chunks, salvamento em disco de dados de mundo e de jogadores, importação de mundos existentes, multiplayer, exibição de status do servidor, quebra e colocação de blocos, inventário, crafting, coleta de itens, chat, comandos e mais
  • Blocos com múltiplos estados, direções e interações exigem muito código dedicado para que o comportamento seja implementado corretamente, e ainda há muitos blocos sem suporte
  • Foi desenvolvido com GnuCOBOL em Linux x86_64 ou arm64, e também pode ser distribuído via Docker, mas o suporte a outros sistemas operacionais, como Windows, não foi testado
  • Extrai dados JSON do datapack padrão do Minecraft e dos .jar oficiais do servidor e do cliente, usando-os para geração de código COBOL em tempo de compilação e carregamento de dados em tempo de execução

Recursos do servidor de Minecraft implementados pelo CobolCraft

  • CobolCraft é um servidor de Minecraft escrito em COBOL e oferece suporte ao Minecraft 1.21.4
  • Os recursos implementados incluem:
    • geração infinita de terreno e carregamento dinâmico de chunks
    • salvamento em disco de dados de mundo e de jogadores
    • suporte ao formato de arquivos do Minecraft e importação de mundos existentes
    • multiplayer com número configurável de jogadores simultâneos
    • ping/server status para aparecer como online na lista de servidores
    • quebra e colocação de blocos, com código de loot table gerado automaticamente
    • interação com blocos baseada em clique direito
    • inventário do jogador
    • crafting 2x2 e 3x3
    • entidades de item e coleta de itens
    • chat
    • comandos dentro do jogo e comandos interativos no console
    • configuração baseada em server.properties
    • whitelist persistente armazenada em whitelist.json
    • colisão muito básica entre blocos e jogadores e física de entidades
    • dano por queda, dano do void, morte e respawn

Escopo e limitações do suporte a blocos

  • Blocos com vários estados, direções e interações exigem muito código especializado para funcionar corretamente
  • Ainda há muitos blocos sem suporte
  • Entre os blocos que funcionam estão:
    • torches
    • slabs
    • stairs
    • rotated pillars, como logs
    • buttons sem interação
    • doors
    • trapdoors
    • beds
    • signs

Ambiente de build e execução

  • CobolCraft foi desenvolvido com GnuCOBOL e tem como alvo a execução em Linux
    • As arquiteturas-alvo são x86_64 e arm64
    • O suporte a outros sistemas operacionais, como Windows, não foi testado
    • Usando Docker, é possível fazer uma distribuição independente de plataforma
  • Os requisitos para uma distribuição Linux são:
    • GnuCOBOL 3.1.2 ou superior
    • GnuCOBOL 3.2 ou superior é recomendado por desempenho
    • make
    • gcc, g++
    • zlib
    • curl, necessário para baixar o .jar oficial do servidor
    • Java 21 ou superior, necessário para extrair dados do .jar do servidor
  • Os comandos de build e execução são:
make --jobs=$(nproc)
make run
  • É possível executar usando a imagem do Docker Hub ou fazer o build por conta própria
docker pull meyfa/cobolcraft:latest

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

Configuração do servidor e acesso pela rede

  • A configuração do servidor é feita editando o arquivo server.properties
  • Esse arquivo é gerado automaticamente na primeira execução, com os valores padrão de todas as opções suportadas
    • server-port: valor padrão 25565
    • level-name: valor padrão "world"
    • white-list: valor padrão false
    • motd: valor padrão "CobolCraft"
    • max-players: valor padrão 10, máximo 100
  • Por padrão, o servidor só é acessível a partir do próprio sistema via localhost:25565
  • Para torná-lo acessível externamente, como por rede local, VPN, encaminhamento de porta ou servidor alugado, é possível vincular a porta como 0.0.0.0:25565:25565 ao executar o Docker
docker run --rm -it -p 0.0.0.0:25565:25565 meyfa/cobolcraft

Por que criar um servidor de Minecraft em COBOL

  • O desenvolvedor não tinha nenhuma experiência prévia com COBOL, mas, ao ver os rumores e o estigma em torno da linguagem, quis conhecê-la melhor
  • Escolheu escrever algo por conta própria como a melhor forma de aprender a linguagem
  • Avalia que, pela complexidade e escala do código do Minecraft, escolher escrever um servidor de Minecraft em COBOL foi uma ideia ao mesmo tempo boa e ruim
  • Tarefas que são simples em outras linguagens precisaram ser criadas do zero
    • parsing e codificação de JSON
    • processamento de vários tipos de dados binários
    • rede multiplayer em tempo real
    • transpor sistemas orientados a objetos do Minecraft para uma linguagem procedural
  • A curva de aprendizado íngreme levou a investigar e entender profundamente o COBOL e seus conceitos, e o processo foi descrito como recompensador
  • Para quem está começando em COBOL, recomenda o GnuCOBOL Programmer's Guide
  • Como material para aprender o protocolo do Minecraft, é possível consultar a documentação da wiki.vg
  • Em alguns casos, observar tráfego real de servidores com ferramentas como Wireguard também pode ajudar a entender o fluxo de informações

Organização do código-fonte e binário executável

  • O código-fonte em COBOL fica principalmente no diretório src/
    • src/main.cob é o ponto de entrada
    • src/server.cob contém o código de inicialização do servidor e a lógica do jogo
  • O diretório codegen/ contém geradores de código escritos em COBOL
    • Eles geram código-fonte adicional a partir de dados JSON, como o datapack padrão do Minecraft
  • O diretório cpp/ contém código-fonte C++ para integrações com o sistema operacional que são difíceis de tratar em COBOL
    • gerenciamento de sockets TCP de baixo nível
    • temporização precisa
    • tratamento de sinais de processo
  • Todo o código-fonte COBOL e C++ é compilado em um único binário cobolcraft

Extração de dados do Minecraft e processamento de JSON

  • As aplicações oficiais de servidor e cliente do Minecraft Java Edition contêm muitos dados
    • blocos, itens e tipos de entidades
    • biomes
    • IDs de protocolo de pacotes
    • tags, como blocos que podem ser minerados com uma picareta
    • recipes
    • loot tables que indicam quais itens caem e sob quais condições quando um bloco é quebrado
  • O Makefile do CobolCraft tem alvos para baixar o .jar oficial e extrair dados como JSON
  • Os dados JSON extraídos são usados de duas formas
    • geração automática, em tempo de compilação, de código COBOL, como loot tables de blocos
    • carregamento de dados em memória em tempo de execução
  • Ambas as tarefas usam um parser JSON genérico, escrito em COBOL e coberto por testes unitários

Testes e atualização

  • Os testes unitários ficam no diretório tests/
  • Os testes usam um framework de testes customizado baseado em copybooks
    • Ele rastreia suites de teste, unidades e assertions
    • Fornece um resumo ao final da execução
  • O comando para executar os testes é make test
  • O principal objetivo dos testes é validar áreas difíceis de depurar, como codificação e decodificação de dados JSON e binários
  • Testar a lógica do jogo em si não é considerado tão importante
  • O procedimento para atualizar o servidor para uma nova versão do Minecraft e as etapas de teste estão em Updating.md

Licença e marcas registradas

  • CobolCraft é distribuído sob a MIT License
  • “Minecraft” é uma marca registrada da Mojang Synergies AB
  • CobolCraft não é afiliado à Mojang nem é um projeto endossado por ela

1 comentários

 
GN⁺ 2024-12-27
Opiniões no Hacker News
  • Há muitos rumores e estigmas em torno do COBOL; seria bom se você escrevesse sobre que insights realmente obteve.
    Eu também só ouvi esse tipo de coisa, e tenho curiosidade sobre o que um iniciante em COBOL encontrou ao implementar um primeiro projeto bem complexo.

    • Existe um estigma meio em tom de piada de que a variante orientada a objetos do COBOL tem uma forma difícil de lidar, chamada ADD ONE TO COBOL YIELDING COBOL.
      Ainda assim, ao contrário do FORTRAN antigo, ele não ignorava espaços em branco a ponto de DO 10 I=1.10 não ser um erro de sintaxe de loop, mas compilar silenciosamente como uma atribuição DO10I = 1.10. O código pretendido provavelmente era DO 10 I=1,10.
    • Gosto desse tipo de insight.
      Se tiver interesse, há aqui algumas coisas que aprendi criando um compilador de COBOL para C#: https://github.com/otterkit/otterkit-cobol/issues/40
      Agora estou convencido de que COBOL é apenas um assembler de alto nível.
  • Muito legal.
    Como projeto de conclusão do ensino médio, criei um sistema inteiro em COBOL para automatizar odds de apostas de futebol. Já era uma tecnologia ultrapassada, mas a escola ainda não tinha acompanhado os tempos.
    Era absurdamente inadequado, mas eu gostava de cada linha. Há algo estranhamente satisfatório em uma linguagem que, a cada tecla digitada, sussurra “lembra dos cartões perfurados?”.

    • O fato de você ter usado COBOL EM MAIÚSCULAS em um projeto de ensino médio combina perfeitamente com a época. Deve ter virado uma ótima lembrança do colégio. Espero que todos os nomes de variáveis fossem nomes de deuses gregos.
  • Posso estar enganado, mas tenho a impressão de ver com bastante frequência projetos paralelos pequenos e impressionantes escritos em linguagens simples e comuns, como C ou, neste caso, COBOL.
    Em contraste, projetos parecidos em Rust muitas vezes parecem ter umas 10 vezes mais linhas de código e, ainda assim, mal funcionam.
    Minha hipótese é que linguagens simples tornam mais fácil capturar rapidamente uma ideia como um blueprint e fazer uma base de código bagunçada ao menos rodar. Já linguagens modernas forçam você a escrever código que dure mais. Ou talvez as linguagens modernas estejam fazendo algo errado.

    • Um servidor de Minecraft, a rigor, não é um pequeno projeto paralelo.
      Há servidores em desenvolvimento há 3 a 5 anos que ainda não estão completos, e também há os focados em funcionalidades específicas, como https://github.com/MCHPR/MCHPRS, voltado a exibições de redstone.
      Este servidor em COBOL ainda não implementou processamento de iluminação, e a geração de mobs também depende disso, então é uma das partes mais difíceis. Alguns blocos também não foram totalmente implementados. Para terminar um servidor de Minecraft são necessários anos; portanto, fazer algo rápido nem sempre é o melhor caminho.
    • Acho que isso não é necessariamente uma ilusão.
      Tenho 2 jogos em andamento em Rust e, escolhendo o engine certo, foi bem fácil criar um protótipo de gameplay extremamente mínimo. Mas, conforme fui adicionando funcionalidades, o código cresceu muito, e a transição de single-player para multiplayer foi uma bagunça. Também perdi tempo seguindo modas e depois removendo-as.
      Rust detesta de verdade estruturas de grafo em que objetos de jogo estão conectados de formas complexas. Sempre há atrito quando um único evento do jogo leva a atualizações de vários tipos. Havia a opção de simplesmente aceitar isso e escrever um pouco mais de código, ou de procurar uma solução sistemática que economizasse tempo depois, mesmo exigindo mais código no início.
      Escolhi a segunda opção e fiz alguns experimentos, mas a sensação é que o ponto de equilíbrio fica longe demais para um projeto pequeno cujo break-even é 1.
      Mesmo dentro da mesma linguagem, a diferença pode passar de uma ordem de grandeza. Rust tem 2 engines 3D utilizáveis: uma é famosa, tem muitos contribuidores e recebe patrocínio suficiente para substituir um salário da Bay Area. A outra é feita quase por uma única pessoa, que se sustenta com economias ou alterna com trabalho em tempo integral.
      Só que o primeiro engine foca muito em promoção e promete várias funcionalidades há anos, mas mostrou pouco; o segundo está à frente tanto em quantidade de recursos quanto em qualidade de implementação.
      No fim, acho que é uma diferença de atitude. Há quem programe por diversão, quem tenha objetivos claros e foque em alcançá-los, quem faça por dinheiro e quem seja atraído por reconhecimento público. Uma base de código bagunçada não é obrigatória, mas existe um meio-termo produtivo. Quanto mais alguém foca em se exibir, mais tende a perseguir modas e arquiteturas chamativas.
    • Rust tem penado bastante para encontrar um avanço em desenvolvimento de jogos.
      A premissa central do Rust é trocar velocidade de desenvolvimento e flexibilidade por segurança de memória, mas, em desenvolvimento de jogos, ficou claro que velocidade de desenvolvimento e flexibilidade são muito mais importantes que segurança de memória.
      Se for um microkernel com especificação formal já detalhadamente planejada, Rust pode ser uma excelente escolha. Por outro lado, se você precisa jogar lama rapidamente na parede para ver o que vira uma gameplay divertida, Rust torna esse processo mais difícil do que quase qualquer linguagem, sem benefícios claros. O resultado é um pedaço de gameplay rápido e bagunçado, feito em mais tempo, que é apenas um pouco mais seguro em termos de memória.
      Não sou o único que experimentou desenvolvimento de jogos em Rust e depois abandonou a linguagem definitivamente para esse uso. Por exemplo, há “Leaving Rust gamedev after 3 years” [0], que até agora é um dos posts sobre Rust mais discutidos e curtidos no Hacker News.
      De forma mais ampla, é evidente que Rust recebe muito mais hype do que Cobol. Por isso há muitos exemplos de desenvolvedores vulneráveis a ondas de hype, geralmente iniciantes entusiasmados, que se lançaram corajosamente em projetos open source ou de hobby em Rust. Em contraste, escrever um servidor de Minecraft em Cobol exige um pouco mais de excentricidade e coragem, o que em geral se relaciona a mais experiência.
      [0] https://news.ycombinator.com/item?id=40172033
    • No fim, parece a diferença entre hackers de verdade™, que gostam de linguagens simples e constroem o universo inteiro com qualquer coisa que lhes deem, e code monkeys que seguem a última moda.
      Para constar, eu me coloco no segundo grupo.
    • Pessoas que terminam as coisas normalmente não se preocupam muito com qualidade de código.
      Já passei por uma fase em que, tentando escrever código que durasse muito, acabei não terminando nada. Ao longo dos anos encontrei um equilíbrio, aprendi que, se você melhora iterativamente um código lixo, ele acaba virando algo decente, e desde então é assim que faço.
  • https://raw.githubusercontent.com/meyfa/CobolCraft/main/src/...
    Para quem vem de uma linguagem procedural, na prática não é tão difícil de entender, e lembra um pouco os servidores de jogos escritos em VB que vi uns 20 anos atrás

  • Desde que parei de usar COBOL em 1978, nunca mais admiti sequer que conhecia a linguagem
    Vou fazer o sinal da cruz e tomar um café forte, torcendo para não olhar esse código :-)
    Ainda assim, é impressionante terem conseguido fazer isso

  • Podem zoar, mas o código é bem fácil de ler
    Comparado a algumas linguagens modernas em que você precisa ficar olhando por vários minutos para entender o que está acontecendo

    • Trabalhei um tempo em uma empresa FAANG e tinha acesso a especialistas de nível mundial em C++. Alguns faziam parte de comitês internacionais de padronização da linguagem
      Perguntei em uma lista interna de C++ se uma linha específica de código criaria um vazamento de memória; era um código que usava puramente templates da STL e conversões de tipo. Mas os especialistas não conseguiram chegar a um consenso sobre se eu estava fazendo do jeito certo. Alguns achavam que haveria vazamento, outros achavam que não
      Essa pequena história real diz muito sobre C++. JavaScript também é cheio dessas coisas
    • Esse era o ponto forte do COBOL
      Comecei a programar em 1976 e aprendi COBOL e ICL PLAN; usei cartões perfurados e, depois de terminar o treinamento, passei a usar terminais. Os programas eram 100% programas batch
      Havia uma tendência muito forte a favor da legibilidade, para que qualquer pessoa pudesse ler e entender o código-fonte. Por outro lado, isso era parcialmente compensado pela necessidade de ler e entender o core dump gerado quando o programa falhava. Na melhor das hipóteses, dava para rastrear a falha até uma linha específica de código, então criei o hábito de executar o programa mentalmente
      Mesmo quando saí de um órgão público e fui para programação comercial, ainda era COBOL e programas batch até o começo dos anos 80. Fiz suporte noturno por 3 anos, e foi aí que o valor do COBOL ficou claro. Mesmo pegando uma listagem e um core dump que eu nunca tinha visto, geralmente conseguia corrigir bem rápido. Claro, sempre com a ressalva de que eram correções táticas
    • Por isso gosto de Ada e VHDL
      Podem ser meio verbosas, mas são muito mais fáceis de ler do que linguagens mais “modernas”
    • COBOL foi projetada para que pessoas que não eram programadoras também pudessem escrever e ler
      Pelo menos em teoria
    • MOVE FUNCTION MIN(BLOCK-ENTRY-MINIMUM-STATE-ID(LK-BLOCK), STATE-ID) TO BLOCK-ENTRY-MINIMUM-STATE-ID(LK-BLOCK)
  • Aprendi um pouco de COBOL no ensino médio, em uma pequena cidade do Paquistão
    Não era ruim, e fiz um projeto que imitava demonstrações financeiras. Tinha seus pontos esquisitos, mas para a maioria das pessoas, ou seja, não programadores, qualquer linguagem de programação deve parecer bem esquisita, então nunca entendi muito o estigma associado ao COBOL
    Na mesma época também aprendi C, e essa ficou comigo :-)

  • Sempre ouço dizer que programadores COBOL são raros e recebem salários altos
    Fico curioso se esse projeto fez chover propostas de emprego

    • O raro não são programadores COBOL, mas pessoas que entendem a lógica de negócio
      COBOL é muito usado em operações de negócio bastante complexas
    • Como outros disseram, o mais importante é entender a complexidade da lógica de negócio existente e, em geral, os sistemas mainframe em que esse código roda
      Caso contrário, bastaria criar um cross-compiler e pronto
    • Essas pessoas são valiosas mais pelo conhecimento de sistemas muito complexos e em geral sem documentação, e pelo conhecimento do contexto de negócio, do que pela habilidade de programação
  • COBOL na verdade parece uma linguagem bem bacana
    O código também está realmente bem organizado

  • Gosto do fato de haver testes unitários