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.


