Tutti gli articoli

Creare un MMORPG con Unreal Engine 5.8 — Devlog n. 1: il server autoritativo e l'architettura del mondo

L'architettura di Ancient Online: client in Unreal Engine 5.8, server autoritativo in C++, ciclo del mondo a 25 Hz e mondo unificato modificato dal vivo.

Una postazione di lavoro con monitor e portatili affiancati in uno studio in penombra

A distinguere un MMORPG da un gioco per giocatore singolo è il server che sta dietro a tutto ciò che vedi. In questa prima parte del diario di sviluppo (devlog) di Ancient Online: Remastered spieghiamo come stiamo costruendo un MMORPG con Unreal Engine 5.8: come il lavoro è diviso tra client e server, come viene simulato il mondo e come riusciamo a modificare dal vivo un mondo unico e unificato.

Due pezzi: client e server

Ancient Online è composto da due software distinti:

  • Il client è scritto in C++ su Unreal Engine 5.8. Rendering, audio, interfaccia e input sono compito suo.
  • Il server è indipendente da Unreal: lo abbiamo scritto da zero in C++23. Tutte le regole del gioco girano qui.

Perché abbiamo scritto il server a parte anziché dentro il motore? Perché ciò che serve a un server MMORPG è diverso da ciò che serve a un motore di gioco: non c'è grafica, ma ci sono migliaia di entità, dati persistenti, lunghi tempi di attività e un bisogno di prestazioni prevedibili. Un server separato ci permette di fare solo il lavoro necessario e di controllare ogni byte.

Il server autoritativo: non fidarsi del client

La nostra regola di base è questa: il client afferma, il server decide.

  • Movimento: l'input del giocatore va al server, ed è il server a calcolare la posizione. Il client mostra la posizione comunicata dal server, con un'interpolazione fluida. Così un client che «si teletrasporta» o attraversa un muro, per il server, non va da nessuna parte.
  • Combattimento: esiti come danni, colpi a segno e contraccolpi vengono calcolati sul server. Per esempio, è il server a decidere se un colpo di una combo atterra l'avversario, e trasmette il risultato a tutti nello stesso momento.
  • Economia: oggetti, valuta e transazioni del negozio cambiano solo sul server e nel database.

Il costo di questo approccio è dover gestire bene la latenza di rete; il vantaggio è un mondo in cui barare è molto più difficile e in cui le stesse regole valgono per tutti.

Un ciclo del mondo a 25 Hz

Il server aggiorna il mondo 25 volte al secondo. A ogni passo avanzano l'IA dei mostri, il movimento, il combattimento, gli effetti delle abilità e il meteo. Un passo fisso mantiene la simulazione prevedibile e garantisce che lo stesso input produca sempre lo stesso risultato.

Non serve che ogni giocatore sappia tutto. Il server divide il mondo in una griglia e invia a ciascun giocatore solo gli aggiornamenti delle entità all'interno della sua area di interesse (quelle vicine). In questo modo il traffico di rete resta ragionevole anche in una città affollata.

Un protocollo binario leggero

Tra client e server non ci sono JSON né REST; ogni messaggio è un pacchetto binario con una struttura fissa. Questo fa risparmiare sia banda sia tempo di CPU. Quando aggiungiamo un nuovo sistema (come il meteo, il movimento o il servizio account in gioco), scriviamo per esso un contratto di pacchetti separato e versionato, e usiamo file header condivisi per garantire che client e server lavorino sullo stesso contratto.

Persistenza: salvare senza far aspettare il gioco

I dati dei giocatori vivono in un database PostgreSQL. Ma far attendere il database al ciclo del mondo a ogni passo non è accettabile. Per questo il salvataggio avviene in background, con una persistenza write-behind (a scrittura differita): il server del mondo deposita le modifiche in una coda (Redis), e un processo di scrittura in background le registra nel database a blocchi. Lo scorrere del gioco non dipende dalla velocità del database.

I canali e il server di accesso

I giocatori si collegano prima a un server di accesso, che gestisce la verifica dell'account, la selezione del personaggio e la sessione. Poi passano a uno dei quattro canali di gioco (CH1–CH4). Lo stato in tempo reale dei canali è mostrato nella pagina Stato dei server del sito del gioco.

Un mondo unificato, modificato dal vivo

Il mondo di Ancient Online è progettato come un mondo unico e unificato anziché come mappe separate divise da schermate di caricamento; è suddiviso in celle e caricato in streaming.

Il contenuto del mondo (terreno, oggetti, posizionamento dei mostri) non è conservato nel codice ma nel database, in forma versionata. Possiamo modificare questo mondo con un editor del mondo dentro il gioco: le modifiche vengono prima fatte in una bozza, controllate e poi pubblicate. Ogni pubblicazione crea una nuova versione, e il client verifica che i dati del mondo in suo possesso corrispondano a quelli del server confrontando un digest. Se non corrispondono, attende che i dati vengano aggiornati prima di proseguire nel gioco.

Missioni: Lua come linguaggio di scripting

Le missioni e i dialoghi degli NPC sono scritti in Lua 5.4 sul server. Questo ci permette di sviluppare e testare le missioni senza ricompilare il server.

I messaggi dei giocatori non lasciano mai i nostri server

Per la traduzione della chat in gioco non usiamo un servizio di traduzione esterno. Sui nostri server gira un modello di traduzione locale che usa solo la CPU; i messaggi dei giocatori non vengono inviati ad alcuna API esterna. In questo modo giocatori che parlano lingue diverse possono capirsi senza che i loro messaggi lascino mai lo studio.

Che cosa viene dopo

La seconda parte del diario di sviluppo racconta le decisioni che abbiamo preso per rendere lo stesso mondo giocabile con il mouse, con il touchscreen e con il controller. Per conoscere lo studio, leggi Chi è Astronaut Entertainment?; per il gioco in sé, consulta la pagina Giochi.

Condividi:
Disponibile anche in29