Vellum Online — MMORPG browser a microservizi
Un mondo persistente in cui i bot giocano dalla stessa porta d'ingresso dei giocatori veri.
- .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.