Toate articolele

Construim un MMORPG cu Unreal Engine 5.8 – Devlog #1: serverul autoritar și arhitectura lumii

Arhitectura Ancient Online: client în Unreal Engine 5.8, server autoritar scris în C++, o buclă a lumii la 25 Hz și o lume unificată, editată live.

O stație de lucru cu monitoare și laptopuri așezate unul lângă altul într-un studio slab luminat

Ce deosebește un MMORPG de un joc single-player este serverul din spatele a tot ce vezi. În această primă parte a devlogului Ancient Online: Remastered explicăm cum construim un MMORPG cu Unreal Engine 5.8: cum se împarte munca între client și server, cum este simulată lumea și cum reușim să edităm live o singură lume unificată.

Două piese: clientul și serverul

Ancient Online este alcătuit din două programe separate:

  • Clientul este scris în C++ pe Unreal Engine 5.8. Randarea, sunetul, interfața și inputul sunt treaba lui.
  • Serverul este independent de Unreal: l-am scris de la zero în C++23. Aici rulează toate regulile jocului.

De ce am scris serverul separat și nu în interiorul motorului? Pentru că nevoile unui server de MMORPG sunt altele decât ale unui motor de joc: nu există grafică, dar există mii de entități, date persistente, perioade lungi de funcționare neîntreruptă și nevoia unei performanțe previzibile. Un server separat ne lasă să facem doar munca necesară și să controlăm fiecare octet.

Serverul autoritar: nu avem încredere în client

Regula noastră de bază este aceasta: clientul afirmă, serverul decide.

  • Mișcare: Inputul jucătorului ajunge la server, iar serverul calculează poziția. Clientul afișează poziția raportată de server, printr-o interpolare lină. Așa că un client care „se teleportează singur” sau trece printr-un zid nu ajunge nicăieri din punctul de vedere al serverului.
  • Luptă: Rezultate precum daunele, loviturile și împingerea înapoi sunt calculate pe server. De exemplu, serverul hotărăște dacă o lovitură din combo doboară adversarul și transmite rezultatul tuturor în același timp.
  • Economie: Obiectele, moneda și tranzacțiile din magazin se schimbă doar pe server și în baza de date.

Prețul acestei abordări este că latența rețelei trebuie gestionată bine; câștigul este o lume în care e mult mai greu să trișezi și în care aceleași reguli sunt valabile pentru toți.

O buclă a lumii la 25 Hz

Serverul actualizează lumea de 25 de ori pe secundă. La fiecare pas avansează inteligența artificială a monștrilor, mișcarea, lupta, efectele abilităților și vremea. Un pas fix păstrează simularea previzibilă și garantează că același input produce întotdeauna același rezultat.

Nu fiecare jucător trebuie să știe despre toate. Serverul împarte lumea într-o grilă și îi trimite fiecărui jucător actualizări doar pentru entitățile din zona lui de interes (cele din apropiere). Astfel, traficul de rețea rămâne rezonabil chiar și într-un oraș aglomerat.

Un protocol binar ușor

Între client și server nu există JSON sau REST; fiecare mesaj este un pachet binar cu structură fixă. Asta economisește atât lățime de bandă, cât și timp de procesor. Când adăugăm un sistem nou (cum ar fi vremea, mișcarea sau serviciul de cont din joc), scriem pentru el un contract de pachete separat, versionat, și folosim fișiere header comune ca să garantăm că clientul și serverul lucrează după același contract.

Persistență: salvăm fără să facem jocul să aștepte

Datele jucătorilor stau într-o bază de date PostgreSQL. Dar nu e acceptabil ca bucla lumii să aștepte baza de date la fiecare pas. De aceea salvarea se face în fundal, ca persistență write-behind (scriere amânată): serverul lumii pune modificările într-o coadă (Redis), iar un proces de scriere din fundal le trimite în baza de date în loturi. Cursul jocului nu depinde de viteza bazei de date.

Canalele și serverul de autentificare

Jucătorii se conectează mai întâi la un server de autentificare, care se ocupă de verificarea contului, de selectarea personajului și de sesiune. Apoi trec pe unul dintre cele patru canale de joc (CH1–CH4). Starea în timp real a canalelor este afișată pe pagina Starea serverelor de pe site-ul jocului.

O singură lume unificată, editată live

Lumea din Ancient Online este proiectată ca o singură lume unificată, nu ca hărți separate despărțite de ecrane de încărcare; este împărțită în celule și se încarcă prin streaming.

Conținutul lumii (terenul, obiectele, amplasarea monștrilor) nu este păstrat în cod, ci în baza de date, versionat. Putem edita această lume cu un editor de lume aflat chiar în joc: modificările se fac mai întâi într-o ciornă, sunt verificate și apoi publicate. Fiecare publicare creează o versiune nouă, iar clientul verifică, prin compararea unui rezumat (digest), că datele de lume pe care le deține corespund cu cele ale serverului. Dacă există o nepotrivire, așteaptă actualizarea datelor înainte să continue intrarea în joc.

Misiuni: Lua ca limbaj de scripting

Misiunile și dialogurile cu NPC-urile sunt scrise în Lua 5.4, pe server. Așa putem dezvolta și testa misiuni fără să recompilăm serverul.

Mesajele jucătorilor nu părăsesc niciodată serverele noastre

Pentru traducerea chatului din joc nu folosim un serviciu extern de traducere. Rulăm pe propriile servere un model de traducere local, care funcționează doar pe CPU; mesajele jucătorilor nu sunt trimise către niciun API extern. Astfel, jucătorii care vorbesc limbi diferite se pot înțelege fără ca mesajele lor să părăsească vreodată studioul.

Ce urmează

Partea a doua a devlogului prezintă deciziile pe care le-am luat ca să facem aceeași lume jucabilă cu mouse, ecran tactil și controller. Ca să cunoști studioul, citește Cine este Astronaut Entertainment?; pentru jocul în sine, vezi pagina Jocuri.

Distribuie:
Disponibil și în29