Wszystkie wpisy

Tworzymy MMORPG na Unreal Engine 5.8 – Devlog #1: autorytatywny serwer i architektura świata

Architektura Ancient Online: klient na Unreal Engine 5.8, autorytatywny serwer w C++, pętla świata 25 Hz i jeden spójny świat edytowany na żywo.

Stanowisko pracy z ustawionymi obok siebie monitorami i laptopami w słabo oświetlonym studiu

Tym, co odróżnia MMORPG od gry dla jednego gracza, jest serwer stojący za wszystkim, co widzisz. W tej pierwszej części devlogu Ancient Online: Remastered wyjaśniamy, jak tworzymy MMORPG na Unreal Engine 5.8: jak praca jest podzielona między klienta a serwer, jak symulowany jest świat i jak to możliwe, że jeden spójny świat edytujemy na żywo.

Dwie części: klient i serwer

Ancient Online składa się z dwóch osobnych programów:

  • Klient jest napisany w C++ na silniku Unreal Engine 5.8. Odpowiada za renderowanie, dźwięk, interfejs i obsługę wejścia.
  • Serwer jest niezależny od Unreala: napisaliśmy go od zera w C++23. To tutaj działają wszystkie zasady gry.

Dlaczego napisaliśmy serwer osobno, a nie w silniku? Bo serwer MMORPG potrzebuje czegoś innego niż silnik gry: nie ma grafiki, są za to tysiące bytów, trwałe dane, długi czas nieprzerwanej pracy i potrzeba przewidywalnej wydajności. Osobny serwer pozwala nam wykonywać tylko niezbędną pracę i kontrolować każdy bajt.

Serwer autorytatywny: nie ufać klientowi

Nasza podstawowa zasada brzmi: klient zgłasza, serwer decyduje.

  • Ruch: Wejście gracza trafia na serwer, a serwer oblicza pozycję. Klient wyświetla pozycję przekazaną przez serwer, stosując płynną interpolację. Dlatego klient, który „sam się teleportuje” albo przechodzi przez ścianę, z punktu widzenia serwera nigdzie się nie przemieszcza.
  • Walka: Wyniki takie jak obrażenia, trafienia i odrzut są obliczane na serwerze. Na przykład to serwer decyduje, czy cios z kombinacji przewraca przeciwnika, i rozsyła wynik do wszystkich jednocześnie.
  • Gospodarka: Przedmioty, waluta i transakcje w sklepie zmieniają się wyłącznie na serwerze i w bazie danych.

Ceną tego podejścia jest konieczność dobrego radzenia sobie z opóźnieniami sieci; zyskiem jest świat, w którym oszukiwać jest znacznie trudniej, a wszystkich obowiązują te same zasady.

Pętla świata 25 Hz

Serwer aktualizuje świat 25 razy na sekundę. W każdym kroku postępują SI potworów, ruch, walka, efekty umiejętności i pogoda. Stały krok sprawia, że symulacja jest przewidywalna, a to samo wejście zawsze daje ten sam wynik.

Nie każdy gracz musi wiedzieć o wszystkim. Serwer dzieli świat na siatkę i wysyła każdemu graczowi aktualizacje tylko o bytach w jego obszarze zainteresowania (czyli tych w pobliżu). Dzięki temu ruch sieciowy pozostaje rozsądny nawet w zatłoczonym mieście.

Lekki protokół binarny

Między klientem a serwerem nie ma JSON-a ani REST-a; każda wiadomość to pakiet binarny o stałym układzie. Oszczędza to zarówno pasmo, jak i czas procesora. Gdy dodajemy nowy system (na przykład pogodę, ruch czy usługę kont w grze), piszemy dla niego osobny, wersjonowany kontrakt pakietów, a dzięki współdzielonym plikom nagłówkowym mamy gwarancję, że klient i serwer pracują na tym samym kontrakcie.

Trwałość danych: zapisywanie bez kazania grze czekać

Dane graczy są przechowywane w bazie PostgreSQL. Ale to, by pętla świata czekała na bazę danych w każdym kroku, jest nie do przyjęcia. Dlatego zapis odbywa się w tle, w modelu write-behind: serwer świata wrzuca zmiany do kolejki (Redis), a działający w tle proces zapisuje je do bazy danych partiami. Płynność gry nie zależy od szybkości bazy danych.

Kanały i serwer logowania

Gracze łączą się najpierw z serwerem logowania, który obsługuje weryfikację konta, wybór postaci i sesję. Następnie przechodzą na jeden z czterech kanałów gry (CH1–CH4). Aktualny status kanałów pokazuje strona Status serwerów w witrynie gry.

Jeden spójny świat edytowany na żywo

Świat Ancient Online został zaprojektowany jako jeden spójny świat, a nie osobne mapy rozdzielone ekranami ładowania; jest podzielony na komórki i wczytywany strumieniowo.

Zawartość świata (teren, obiekty, rozmieszczenie potworów) jest przechowywana nie w kodzie, lecz w bazie danych, w wersjach. Ten świat możemy edytować edytorem świata wbudowanym w grę: zmiany najpierw powstają w wersji roboczej, są sprawdzane, a potem publikowane. Każda publikacja tworzy nową wersję, a klient sprawdza, czy posiadane przez niego dane świata zgadzają się z danymi serwera, porównując skrót. W razie niezgodności czeka na aktualizację danych, zanim przejdzie dalej do gry.

Zadania: Lua jako język skryptowy

Zadania i dialogi NPC są pisane na serwerze w języku Lua 5.4. Dzięki temu możemy tworzyć i testować zadania bez ponownej kompilacji serwera.

Wiadomości graczy nigdy nie opuszczają naszych serwerów

Do tłumaczenia czatu w grze nie używamy zewnętrznej usługi tłumaczeniowej. Na własnych serwerach uruchamiamy lokalny model tłumaczący, który działa wyłącznie na procesorze; wiadomości graczy nie są wysyłane do żadnego zewnętrznego API. Dzięki temu gracze mówiący różnymi językami mogą się zrozumieć, a ich wiadomości nigdy nie wychodzą poza studio.

Co dalej

Druga część devlogu opisuje decyzje, które podjęliśmy, by w ten sam świat dało się grać myszą, na ekranie dotykowym i kontrolerem. Aby poznać studio, przeczytaj Kim jest Astronaut Entertainment?; o samej grze dowiesz się na stronie Gry.

Udostępnij:
Dostępne także w językach29