Protokół Sieciowy i API Serwera
Architektura sieciowa wykorzystuje bezpołączeniowy protokół UDP. Serwer pełni rolę „matchmakera" oraz przekaźnika (relay) wysyłającego pakiety do członków danej sesji.
1. Zunifikowany Pakiet Sieciowy (NetworkPacket)
Zamiast budować rozbudowane warstwy serializacji, cała komunikacja opiera się na przesyłaniu fizycznej struktury C++ (unii NetworkPacket). Zapewnia to maksymalną wydajność i natychmiastowe parsowanie za pomocą sizeof(NetworkPacket).
struct NetworkPacket {
PacketHeader header;
union Payload {
PlayerData gameData;
struct {
int count;
SessionInfo sessions[10];
} sessionList;
} payload;
};
Pola nagłówka (PacketHeader) jednoznacznie wskazują jaki to rodzaj komunikatu i do jakiej sesji ma trafić. Dostępne typy pakietów (PacketType):
REQ_SESSIONS— pytanie klienta o dostępne pokoje.RES_SESSIONS— odpowiedź serwera (wysyła maksymalnie 10 aktywnych sesji).CREATE_SESSION— żądanie utworzenia instancji nowego meczu.JOIN_SESSION— chęć wpięcia się do gry na podstawie zadanegosessionId.GAME_DATA— czysta pętla gry (x, y, z, kąt kamery gracza).
2. Architektura Serwera UDP i Zarządzanie Sesjami
Serwer napisany jest w jednym pliku server.cpp (nasłuchuje domyślnie na porcie 54000).
- Rejestracja graczy — serwer nie ufa IP/port w 100%, traktuje strukturę
ClientEndpointjako klucz do mapy poszczególnych pokoi (sesji). Odbierając pakietGAME_DATA, serwer rozsyła go do wszystkich podłączonych do tej sesji oponentów. - Heartbeat / Timeout — zarówno klient, jak i serwer usuwają gracza z sesji, jeżeli nastąpi cisza w transmisji dłuższa niż 5 sekund (serwer) lub 2 sekundy (klient wymazuje graficzne „duchy").
- Utrata hosta — gdy twórca sesji wyjdzie lub przekroczy timeout (zerowy indeks na liście graczy), serwer automatycznie zamyka całą sesję.
3. Klient: Interpolacja Sieciowa
Pola targetX, targetY, targetZ oraz targetAngle w strukturze PlayerData nigdy nie opuszczają komputera lokalnego (nie wchodzą w transmisję UDP z racji unii). Pakiety asynchronicznie nadpisują zmienne target, po czym silnik powoli dociąga pozycję bazową gracza w renderowaniu (p.x = lerp(p.x, p.targetX, lerpFactor)), aby zniwelować skoki animacji.