Giuseppe.Rega
← Torna ai progetti

Vellum Online — MMORPG browser a microservizi

Un mondo persistente in cui i bot giocano dalla stessa porta d'ingresso dei giocatori veri.

Online ↗2025 — in corso
  • .NET 8
  • YARP
  • Node.js
  • Socket.IO
  • TypeScript
  • Python
  • FastAPI
  • Three.js
  • PostgreSQL
  • Redis
  • MongoDB
  • RabbitMQ

Il problema

Un gioco multiplayer in tempo reale mette sotto pressione tutto insieme: latenza, stato condiviso, autorevolezza del server e costo per giocatore. In più ha un problema che i gestionali non hanno: un mondo vuoto è un mondo morto, e all'inizio i giocatori non ci sono.

Risultato

Un MMORPG giocabile nel browser, online su vellumonline.cc, con una dozzina di servizi coordinati, un mondo popolato da account automatici che giocano davvero e un'interfaccia MCP con cui un agente IA può connettersi e giocare come chiunque altro.

La divisione dei servizi

Il sistema è diviso per dominio, non per comodità di sviluppo:

Servizio Tecnologia Ruolo
api-gateway .NET 8 + YARP Unico ingresso: reverse proxy HTTP e WebSocket
identity-service .NET 8 Registrazione, login, sessioni
catalog-service .NET 8 Oggetti, ricette, equipaggiamento
world-content-service .NET 8 Zone, risorse, contenuti del mondo
social-service .NET 8 Gilde, party, chat
i18n-service .NET 8 Testi localizzati
physics-server Node.js + Socket.IO Simulazione, combattimento, movimento
npc-service TypeScript Popolazione di giocatori ambientali
ai-service Python + FastAPI Macchine a stati e ML degli NPC
game-client Three.js + Vite Client 3D nel browser
game-mcp TypeScript Interfaccia MCP per agenti

Sotto: PostgreSQL per i dati relazionali, Redis per la cache, MongoDB per i documenti e RabbitMQ per gli eventi fra servizi.

Perché la fisica sta da sola

Il ciclo di simulazione ha un vincolo che nessun altro servizio ha: deve chiudere ogni frame entro una finestra fissa. Metterlo nello stesso processo della logica di dominio significa che una query lenta sull’inventario diventa uno scatto visibile a schermo. Separarlo permette anche di scalarlo su una metrica diversa — giocatori simultanei per zona, non richieste al secondo.

La decisione di cui vado più fiero

I giocatori ambientali che popolano il mondo non hanno alcun accesso privilegiato. Nessuna API interna, nessuna connessione al database, nessuna scorciatoia: si registrano con POST /api/auth/login attraverso il gateway e giocano via Socket.IO, esattamente come il client di un essere umano.

Era la strada più difficile e ha ripagato due volte.

La prima: i bot non possono divergere dal gioco. Se una meccanica cambia, loro vedono ciò che vede un giocatore vero — non una vista interna che qualcuno si è dimenticato di aggiornare.

La seconda, meno ovvia: sono diventati un test end-to-end permanente. Ogni funzione che un bot usa — equipaggiarsi, scegliere un bersaglio che può davvero ferire, raccogliere, craftare, vendere al mercato — è una funzione che qualcuno sta esercitando in continuazione sul sistema in produzione. Più di una volta il primo segnale che qualcosa si era rotto è arrivato dal comportamento dei bot, non da un test.

I bot hanno anche vincoli che il gioco non impone ma il buon senso sì: comprano dai listing dei giocatori reali e mai da quelli dei propri compagni di flotta, perché un’economia in cui i bot si scambiano merce fra loro produce prezzi finti e statistiche inutili.

Un mondo giocabile da un agente

game-mcp espone il gioco come server MCP: autenticazione tramite il gateway, sessione Socket.IO con uno snapshot del mondo aggiornato in tempo reale, e l’intero catalogo di azioni — movimento, combattimento, raccolta, crafting, mercato, quest, pesca, agricoltura, chat, cambio zona.

Le azioni di sola osservazione leggono lo snapshot locale senza toccare il server, così un agente può guardarsi intorno quanto vuole senza generare traffico. È lo stesso principio dei bot, portato più in là: se l’interfaccia pubblica basta a giocare, allora basta anche a un agente automatico — e il gioco non ha bisogno di sapere chi c’è dall’altra parte.

Cosa mi ha insegnato

Che il numero giusto di microservizi è quello che i confini del dominio impongono, non quello che sembra moderno — e che la parte costosa non è scriverli, è tenere allineati i contratti fra di loro.

E che vincolarsi alla porta d’ingresso pubblica, quando è possibile, ripaga: ogni volta che ho resistito alla tentazione di aprire una scorciatoia interna, il sistema è diventato più facile da verificare.