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:
- Gracz uruchamia klienta. Jeśli gra tego wymaga, klient identyfikuje gracza przez backend lub platformę.
- Klient prosi backend o sesję. Backend znajduje lub przydziela serwer gry i zwraca jego adres oraz dane połączenia.
- Klient łączy się z serwerem gry, który przed wpuszczeniem gracza sprawdza zgodność wersji.
- 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.
- Po zakończeniu meczu serwer raportuje wynik do backendu, który zapisuje to, co ma przetrwać.
- 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.