Dlaczego „dodajmy multiplayer” to nie jedno zadanie

Gdy studio prosi o multiplayer, brzmi to jak pojedyncza funkcja. W praktyce to kilka odrębnych obszarów odpowiedzialności, które działają w różnych miejscach, psują się na różne sposoby i często mają różnych właścicieli:

  • klient gry na komputerze gracza;
  • serwer gry czasu rzeczywistego, który prowadzi mecz;
  • backend aplikacyjny, który obsługuje wszystko wokół meczu;
  • utrzymanie (operations): budowanie, wdrażanie, monitorowanie i aktualizowanie wszystkich powyższych.

Większość niespodzianek w zakresie projektów online bierze się nie z samych obszarów, ale z luk między nimi. Nikt nie zdecydował, czy trafienie weryfikuje serwer, czy klient, kto przydziela serwer na start meczu ani co dzieje się z trwającym meczem, gdy wychodzi nowy build. Ten artykuł omawia kolejno cztery obszary, daje Ci macierz odpowiedzialności do wykorzystania we własnym planowaniu i kończy się listą decyzji, które warto wyjaśnić, zanim poprosisz kogokolwiek o wycenę.

Klient gry: input, prezentacja i informacja zwrotna

Zadaniem klienta jest sprawić, by gra była natychmiastowa dla jednego gracza. Odczytuje input, renderuje świat, odtwarza dźwięk i efekty oraz pokazuje graczowi, co się dzieje. W grze online dodatkowo wysyła intencje gracza do serwera, a aktualizacje z serwera zamienia z powrotem w płynny obraz.

Klient nie powinien być ostatecznym arbitrem w niczym, co ma znaczenie dla innych graczy. Obrażenia, wyniki, zmiany w ekwipunku i rezultaty meczu łatwo zmanipulować na maszynie, nad którą nie masz kontroli. Ogólna zasada brzmi: klient proponuje, serwer decyduje.

Główny wyjątek to predykcja i powinna być świadomym wyborem, a nie ustawieniem domyślnym. W szybkich grach akcji czekanie na odpowiedź serwera przed ruchem własnej postaci czy pokazaniem strzału sprawia wrażenie ociężałości, więc klient symuluje te akcje lokalnie i koryguje się, gdy nadejdzie autorytatywny wynik. Ten krok korekty, czyli rekoncyliacja, to miejsce, gdzie leży znaczna część złożoności netcode’u. Wolniejsza gra turowa albo kooperacyjna może w ogóle nie potrzebować predykcji. Dla porównania: w VOXSYS, kompetycyjnej strzelance na mobilne VR stworzonej przez obecnych członków zespołu Sourcegarden Studio w ramach ich wcześniejszej pracy w VR Storm Studio, framework multiplayer z predykcją po stronie klienta ograniczał odczuwalne opóźnienie w walce.

Typowe zadania klienta:

  • odczyt inputu i wysyłanie intencji gracza do serwera;
  • rendering, dźwięk, UI i natychmiastowa informacja zwrotna;
  • predykcja i rekoncyliacja dla akcji, które muszą działać natychmiast;
  • interpolacja innych graczy i obiektów między aktualizacjami z serwera;
  • czytelna obsługa stanów połączenia: łączenie, ładowanie, rozłączenie, niezgodność wersji.

Serwer gry czasu rzeczywistego: autorytet i symulacja

Serwer czasu rzeczywistego jest właścicielem prawdy o meczu, dopóki mecz trwa. Odbiera input graczy, prowadzi symulację, stosuje zasady gry i replikuje wynikowy stan do wszystkich połączonych klientów.

Tę warstwę definiują cztery pytania:

  • Autorytet. Który system decyduje o danym elemencie stanu: ruchu, trafieniach, podnoszeniu przedmiotów, zmianach świata? Autorytet może różnić się między systemami i dla każdego powinien być zapisany.
  • Symulacja. Co serwer musi symulować sam i z jaką częstotliwością aktualizacji? Strzelanka z fizyką i modyfikowalnym światem wymaga od serwera znacznie więcej niż gra karciana.
  • Replikacja. Jaki stan trafia do których klientów, jak często i w jakim budżecie? Budżety przepustowości i aktualizacji to ograniczenia projektowe, a nie szczegóły implementacji.
  • Walidacja zasad. Które żądania klienta są sprawdzane przed zastosowaniem i co się dzieje, gdy weryfikacja się nie powiedzie?

Typowa decyzja architektoniczna na tym etapie to wybór między serwerem dedykowanym, listen serverem (hostem jest jeden z graczy) a relayem. Serwer dedykowany daje najczytelniejszy model autorytetu i chroni uczciwość rozgrywki, ale niesie ze sobą build serwera, hosting i utrzymanie. Ten kompromis warto rozstrzygnąć jawnie na samym początku, bo zmienia zakres każdego innego obszaru.

Backend aplikacyjny: tylko to, czego produkt naprawdę potrzebuje

Backend to zestaw usług wokół meczu: jak gracz trafia do gry i co zostaje po jej zakończeniu. Tu zakres najczęściej rośnie niepostrzeżenie, dlatego zacznij od tego, czego produkt faktycznie potrzebuje, a nie od listy wszystkiego, co gra online mogłaby mieć.

Obszary, które może obejmować backend:

  • Tożsamość: czy gracze w ogóle potrzebują kont, czy wystarczy tożsamość z platformy.
  • Przepływ sesji: wyszukiwanie lub tworzenie sesji, party lub lobby, przydział serwera oraz przekazanie klientowi adresu serwera i danych połączenia.
  • Trwałość danych: które dane muszą przetrwać mecz – progresja, ekwipunek, ustawienia, wyniki meczów.
  • Integracje: usługi platformowe, analityka lub zewnętrzne platformy backendowe.

Każdy z tych obszarów niesie własne obowiązki w zakresie bezpieczeństwa, ochrony danych i utrzymania. Tam, gdzie sprawdzona usługa platformowa już pokrywa część przepływu, jej integracja jest zwykle tańsza niż budowanie od nowa; własne usługi mają sens tam, gdzie gra naprawdę ich wymaga. Prototypowi może wystarczyć możliwość uruchomienia serwera i połączenia się z nim. Jeśli Twoje główne otwarte pytanie dotyczy tego, jak duża ma być ta warstwa, nasz osobny poradnik o określaniu zakresu backendu gry przed wyceną omawia to szerzej, a strona tworzenie backendu gier opisuje, jak podchodzimy do tych usług.

Utrzymanie: wdrożenie, obserwowalność i obsługa awarii

Serwer dedykowany działający na komputerze programisty to jeszcze nie coś, co zespół może utrzymywać. Utrzymanie to praca, dzięki której każda inna warstwa staje się powtarzalna i widoczna:

  • Build i wdrożenie: zautomatyzowany build serwera, kontener lub obraz, konfiguracja dla każdego środowiska i powtarzalny sposób uruchamiania i zatrzymywania serwerów.
  • Obserwowalność: ustrukturyzowane logi, metryki i sygnały health wokół sesji, procesów serwera i wywołań usług, tak aby zgłoszenie gracza dało się powiązać z przyczyną.
  • Zgodność wersji: zasada, które buildy klienta mogą łączyć się z którymi buildami serwera, oraz proces rolloutu, który nie psuje trwających meczów.
  • Obsługa awarii: graceful shutdown, ponowne łączenie, pełne serwery, padnięte procesy i nieudane wywołania usług – każde z określonym zachowaniem.
  • Pojemność i koszty: udokumentowane założenia co do tego, ile meczów obsłuży jeden serwer i co napędza rachunek za infrastrukturę – zmierzone, a nie zgadywane.

Utrzymanie łatwo odłożyć na później, bo pierwszy grywalny build go nie potrzebuje. To jednocześnie obszar, którego najczęściej brakuje w wycenie.

Macierz odpowiedzialności do ponownego użycia

Poniższa tabela to szablon wyjściowy. Kolumna właściciela wskazuje rolę, a nie liczbę osób: w małym zespole jeden programista może pełnić kilka ról i to nie problem, o ile interfejsy między obszarami pozostają jawne.

System Główne zadania Typowy właściciel Interfejs do innych warstw Materiał przekazywany przy handoverze
Klient gry Input, rendering, UI, informacja zwrotna; w razie potrzeby predykcja i rekoncyliacja; interpolacja; stany połączenia Programiści gameplayu / klienta Wysyła input i żądania do serwera gry; wywołuje API backendu dla sesji i danych Opis modelu sieciowego klienta, lista akcji objętych predykcją, przepływ stanów połączenia
Serwer gry czasu rzeczywistego Autorytet dla każdego systemu, symulacja, replikacja, walidacja zasad, cykl życia meczu Programista sieciowy / serwerowy Odbiera input, replikuje stan do klientów; raportuje wynik i status meczu do backendu Plan autorytetu i replikacji, budżety przepustowości i aktualizacji, headless build serwera
Backend aplikacyjny Tożsamość (jeśli potrzebna), przepływ sesji i lobby, przydział serwerów, trwałość danych, integracje Programista backendu lub zintegrowana usługa platformowa Wersjonowane kontrakty klient–backend; wywołania przydziału serwera i wyników meczu Dokument granic usług, kontrakty API, model danych i ich właściciele
Utrzymanie Automatyzacja buildów serwera, wdrożenia, środowiska, logi i metryki, rollout wersji, obsługa awarii DevOps / lider techniczny wraz z właścicielem konta hostingowego Health checki, logi i metryki z każdej warstwy; pipeline wdrożeniowy Kroki wdrożenia, runbooki dla typowych incydentów, znane ograniczenia, czynniki kosztowe
Decyzje produktowe Tryb gry, liczba graczy na sesję, regiony, platformy, zasady uczciwości i trwałości danych Producent / game director Wymagania i kryteria akceptacji dla wszystkich czterech warstw Spisane założenia, na których opiera się wycena

Jeśli nie potrafisz wypełnić jakiejś komórki, to zwykle pierwsza rzecz do wyjaśnienia, a nie coś do odłożenia na później.

Ta sama architektura jako przepływ

Czytane po kolei obszary łączą się tak:

  1. Gracz uruchamia klienta. Jeśli gra tego wymaga, klient identyfikuje gracza przez backend lub platformę.
  2. Klient prosi backend o sesję. Backend znajduje lub przydziela serwer gry i zwraca jego adres oraz dane połączenia.
  3. Klient łączy się z serwerem gry, który przed wpuszczeniem gracza sprawdza zgodność wersji.
  4. W trakcie meczu klient wysyła input, serwer go symuluje i weryfikuje, a następnie replikuje stan z powrotem. Klient przewiduje tylko to, co zostało uzgodnione.
  5. Po zakończeniu meczu serwer raportuje wynik do backendu, który zapisuje to, co ma przetrwać.
  6. Przez cały czas każda warstwa emituje logi, metryki i sygnały health, z których utrzymanie korzysta przy wdrażaniu, monitorowaniu i aktualizacjach.

Pytania, które kształtują projekt techniczny

Właściwa architektura wynika z kilku decyzji produktowych. Warto na nie odpowiedzieć – choćby w przybliżeniu – przed pierwszym spotkaniem technicznym:

Pytanie Dlaczego to ważne
Tryb gry: co-op, rywalizacja, trwały świat? Rywalizacja podnosi poprzeczkę dla autorytetu i walidacji po stronie serwera; w co-opie czasem można bardziej zaufać klientowi.
Liczba graczy na sesję Decyduje o obciążeniu symulacji, budżetach replikacji i liczbie meczów mieszczących się na jednym serwerze.
Regiony Określa, gdzie muszą działać serwery i czy gracze z różnych regionów grają razem.
Wrażliwość na opóźnienia Rozstrzyga, czy potrzebne są predykcja i rekoncyliacja, i dla których akcji.
Platformy Wpływa na tożsamość, crossplay, pipeline’y buildów i integracje z usługami platformowymi.
Trwałość danych Określa, ile backendu potrzebujesz: wcale, tylko wyniki meczów czy pełną progresję i ekwipunek.

Żadne z tych pytań nie wymaga ostatecznej odpowiedzi na start. Wymaga jednak spisanego założenia, bo wycena jest dokładnie tak stabilna jak założenia zapisane obok niej.

Przykład: jak Bad Goons rozdziela swoje systemy

Bad Goons to obecne autorskie IP Sourcegarden Studio: drużynowa strzelanka na PC rozgrywana na wokselowym polu bitwy, które gracze w trakcie meczu przekopują, niszczą i odbudowują. Gra jest w aktywnej produkcji, a powiązana z nią liczba 64 graczy to cel projektowy, a nie zmierzona pojemność.

Jej architektura traktuje opisane wyżej obszary jako jawne systemy produkcyjne:

  • Klient: klient gry w Unity 6.
  • Warstwa czasu rzeczywistego: FishNet jako framework sieciowy, z predykcją i rekoncyliacją.
  • Symulacja: symulacja wokselowa, której modyfikacje świata muszą być synchronizowane do każdego gracza – to jeden z powodów, dla których autorytet znajduje się na serwerze.
  • Serwery: autorytatywne serwery dedykowane uruchamiające headless buildy Unity na Linuksie.
  • Utrzymanie: wdrożenie oparte na kontenerach, w którym pojemność, zamykanie, health, logi i rollout wersji traktowane są jako kwestie dotyczące samej gry, bo zachowanie infrastruktury bezpośrednio wpływa na trwające mecze i na możliwość diagnozowania zgłoszeń graczy.

Sednem przykładu nie jest konkretny stack. FishNet został wybrany dla tej gry; inna gra, platforma czy zespół mogą uzasadniać inny framework. Chodzi o to, że każda granica jest jawna, więc klienta, serwer i wdrożenie można budować, testować i zmieniać niezależnie.

Checklista zamawiającego: decyzje do wyjaśnienia przed wyceną

Przynieś te odpowiedzi – albo swoje najlepsze obecne założenia – na pierwszą rozmowę z partnerem od multiplayera:

  • Tryb gry i model sesji: co-op, rywalizacja czy trwały świat; długość meczu; sposób, w jaki gracze trafiają do meczu.
  • Liczba graczy na sesję jako cel projektowy oraz, jeśli go masz, oczekiwany zakres liczby jednoczesnych graczy.
  • Model autorytetu: serwer dedykowany, listen server czy relay, i które akcje musi weryfikować serwer.
  • Predykcja: które akcje gracza muszą działać natychmiast, a które mogą poczekać na serwer.
  • Regiony i oczekiwania co do opóźnień dla Twojej grupy docelowej.
  • Platformy i to, czy potrzebny jest crossplay.
  • Silnik i obecny kod: wersja silnika, obecny framework sieciowy i to, czy gra była od początku projektowana z myślą o multiplayerze.
  • Potrzeby backendowe: tożsamość, sesje lub lobby, trwałość danych, integracje oraz używana już usługa platformowa, jeśli istnieje.
  • Odpowiedzialność za utrzymanie: kto jest właścicielem kont hostingowych, kto wdraża, kto dostaje alert, gdy serwer padnie, i czy po przekazaniu oczekujesz wsparcia.
  • Polityka wersji: jak muszą zgadzać się wersje klienta i serwera oraz jak aktualizacje docierają do trwających meczów.
  • Oczekiwania wobec przekazania: jakie dokumenty, buildy i runbooki są potrzebne Twojemu zespołowi, by przejąć wynik prac.
  • Harmonogram, kamienie milowe i budżet, w tym to, co musi udowodnić pierwszy kamień milowy.

Jeśli kilka z tych punktów jest wciąż otwartych, skoncentrowana ocena architektury albo prototyp ryzyka bywa lepszym pierwszym krokiem niż pełna wycena produkcji. Taki zakres prac określamy w ramach naszej usługi tworzenia gier multiplayer.