O sieťovom modeli v hrách pre začiatočníkov

O sieťovom modeli v hrách pre začiatočníkov
Posledné dva týždne som pracoval na sieťovom engine pre svoju hru. Predtým som vo vlastne nič nevedel o sieťových technológiách v hrách, preto som prečítal množstvo článkov a uskutočnil množstvo experimentov, aby som pochopil všetky koncepty a mohol napísať svoj vlastný sieťový engine.

V tomto sprievodcovi by som sa s vami rád podelil o rôzne koncepty, ktoré by ste mali študovať pred písaním vlastného herného enginu, ako aj o najlepších zdrojoch a článkoch na ich štúdium.

V zásade existujú dva hlavné typy sieťových architektúr: peer-to-peer a klient-server. V architektúre peer-to-peer (p2p) sa údaje prenášajú medzi akýmikoľvek dvojicami pripojených hráčov, zatiaľ čo v klient-server architektúre sú údaje prenášané iba medzi hráčmi a serverom.

Hoci architektúra peer-to-peer sa stále používa v niektorých hrách, štandardom je klient-server architektúra: je jednoduchšia na implementáciu, vyžaduje menšiu šírku pásma a uľahčuje ochranu pred podvodmi. Preto sa v tomto sprievodcovi zameriame na klient-server architektúru.

Osobitne sa zameriavame na autoritatívne servery: v takýchto systémoch má server vždy pravdu. Napríklad, ak hráč predpokladá, že sa nachádza na súradniciach (10, 5), zatiaľ čo server mu hovorí, že je na (5, 3), klient musí nahradiť svoju pozíciu tou, ktorú poskytuje server, a nie naopak. Použitie autoritatívnych serverov zjednodušuje rozpoznávanie podvodníkov.

V herných sieťových systémoch existujú tri základné komponenty:

  • Transportný protokol: ako sa prenášajú údaje medzi klientmi a serverom.
  • Aplikačný protokol: čo sa prenáša od klientov na server a od servera na klientov a v akom formáte.
  • Logika aplikácie: ako sa prenášané údaje používajú na aktualizáciu stavu klientov a servera.

Je veľmi dôležité pochopiť úlohu každej časti a s nimi spojené ťažkosti.

Transportný protokol

Prvý krok spočíva vo výbere protokolu na transport údajov medzi serverom a klientmi. Na to existujú dva internetové protokoly: TCP a UDP. Ale môžete si vytvoriť aj vlastný transportný protokol založený na jednom z nich alebo použiť knižnicu, v ktorej sa používajú.

Porovnanie TCP a UDP

Oba, TCP a UDP, sú založené na IPIP umožňuje prenášať pakety od zdroja k príjemcovi, avšak nezaručuje, že zaslaný paket sa nakoniec dostane k príjemcovi, aspoň raz, a ani že poradie paketov príde v správnom poradí. Navyše, paket môže obsahovať len obmedzenú veľkosť dát, ktorú určuje veľkosť MTU.

UDP je iba tenká vrstva nad IP. Preto má rovnaké obmedzenia. Na rozdiel od toho, TCP má množstvo vlastností. Zabezpečuje spoľahlivé usporiadané spojenie medzi dvoma uzlami s kontrolou chýb. Preto je TCP veľmi pohodlné a používa sa v mnohých iných protokoloch, napríklad v HTTP, FTP a SMTP. Ale všetky tieto funkcie majú svoju cenu: oneskorenie.

Aby sme pochopili, prečo tieto funkcie môžu spôsobovať oneskorenie, musíme si objasniť, ako TCP funguje. Keď odosielateľský uzol posiela paket prijímajúcemu uzlu, očakáva potvrdenie (ACK). Ak ho po určitej dobe nedostane (pretože paket alebo potvrdenie sa stratili, alebo z iných dôvodov), paket odošle znova. Navyše, TCP garantuje prijatie paketov v správnom poradí, takže kým sa stratný paket nedostane, všetky ostatné pakety nemôžu byť spracované, aj keď už boli prijaté uzlom prijímateľa.

Ako iste chápete, oneskorenie v multiplayerových hrách je veľmi dôležité, najmä v aktívnych žánroch ako FPS. Preto mnohé hry používajú UDP s vlastným protokolom.

Vlastný protokol založený na UDP môže byť efektívnejší ako TCP z rôznych dôvodov. Napríklad, môže označovať niektoré pakety ako spoľahlivé, zatiaľ čo iné ako nespoľahlivé. Preto ho nezaujíma, či sa nespoľahlivý paket dostal k prijímateľovi. Môže tiež spracovávať viaceré prúdy dát, takže stratený paket v jednom prúde nezpomaluje ostatné prúdy. Napríklad, môže existovať prúd pre vstup hráča a ďalší prúd pre chatové správy. Ak sa stratí chatová správa, ktorá nie je naliehavou informáciou, nenarúša to vstup, ktorý je naliehavý. Alebo môže vlastný protokol implementovať spoľahlivosť inak ako v TCP, aby bol efektívnejší v podmienkach videohier.

Takže, ak je TCP taký zlý, budeme vytvárať vlastný transportný protokol na báze UDP?

Všetko je trochu zložitejšie. Aj keď je TCP takmer suboptimálny pre herné sieťové systémy, môže celkom dobre fungovať vo vašej hre a ušetriť vám cenný čas. Napríklad, latencia nemusí byť problémom pre ťahovú hru alebo hru, ktorú je možné hrať len na LAN sieťach, kde sú latencie a strata paketov oveľa menšie ako v internete.

V mnohých úspešných hrách, vrátane World of Warcraft, Minecraft a Terraria, sa používa TCP. Na druhej strane, väčšina FPS používa vlastné protokoly na báze UDP, takže sa nižšie o nich podrobnejšie porozprávame.

Ak sa rozhodnete použiť TCP, uistite sa, že je vypnutý algoritmus Nagle, pretože ten bufferuje pakety pred odoslaním, čo znamená, že zvyšuje latenciu.

Ak sa chcete podrobnejšie oboznámiť s rozdielmi medzi UDP a TCP v kontexte multiplayerových hier, môžete si prečítať článok Glena Fiedlera UDP vs. TCP.

Vlastný protokol

Takže, chcete vytvoriť vlastný transportný protokol, ale neviete, kde začať? Máte šťastie, pretože Glenn Fiedler o tom napísal dva úžasné články. V nich nájdete množstvo inteligentných myšlienok.

Prvý článok, Networking for Game Programmers z roku 2008 je jednoduchší ako druhý, Building A Game Network Protocol z roku 2016. Odporúčam vám začať so starším.

Majte na pamäti, že Glenn Fiedler je veľkým zástancom používania vlastného protokolu na báze UDP. Po prečítaní jeho článkov si určite osvojíte jeho názor, že TCP má vo videohrách vážne nedostatky, a budete chcieť realizovať vlastný protokol.

Ale ak ste začiatočník v práci so sieťami, urobte si láskavosť a použite TCP alebo knižnicu. Na úspešnú implementáciu vlastného transportného protokolu sa musíte najskôr veľa naučiť.

Sieťové knižnice

Ak potrebujete niečo efektívnejšie ako TCP, ale nechcete sa obťažovať s implementáciou vlastného protokolu a zaoberať sa množstvom podrobností, môžete využiť sieťovú knižnicu. Tých je veľmi veľa:

Neskúsil som ich všetky, ale preferujem ENet, pretože je jednoduché na používanie a spoľahlivé. Okrem toho má jasnú dokumentáciu a tutoriály pre začiatočníkov.

Transportný protokol: zhrnutie

Zhrnieme to: existujú dva hlavné transportné protokoly: TCP a UDP. TCP má množstvo užitočných funkcií: spoľahlivosť, zachovanie poradia paketov, detekciu chýb. UDP to nemá, ale TCP má z povahy vyššie oneskorenia, čo nie je prijateľné pre niektoré hry. To znamená, že na zabezpečenie nízkych oneskorení je možné vytvoriť vlastný protokol založený na UDP, alebo použiť knižnicu implementujúcu transportný protokol na UDP prispôsobenú pre viac hráčov vo videohrách.

Výber medzi TCP, UDP a knižnicou závisí od niekoľkých faktorov. Predovšetkým od potrieb hry: sú potrebné nízke oneskorenia? Po druhé, od požiadaviek aplikačného protokolu: potrebuje spoľahlivý protokol? Ako uvidíme v nasledujúcej časti, môžeme vytvoriť aplikačný protokol, pre ktorý bude úplne vyhovovať nespoľahlivý protokol. Nakoniec, treba tiež zohľadniť skúsenosti vývojára sieťového enginu.

Mám dva tipy:

  • Maximálne abstrahujte transportný protokol od ostatnej časti aplikácie, aby ste ho mohli ľahko nahradiť bez prepisovania celého kódu.
  • Neriešte predčasnú optimalizáciu. Ak nie ste odborník na siete a nie ste si istí, či potrebujete vlastný transportný protokol založený na UDP, môžete začať s TCP alebo knižnicou zabezpečujúcou spoľahlivosť, a potom otestovať a zmerať výkon. Ak sa objavia problémy a ste si istí, že príčina spočíva v transportnom protokole, možno prišiel čas na vytvorenie vlastného transportného protokolu.

Na záver tejto časti odporúčam prečítať si Introduction to Multiplayer Game Programming Bryana Hooka, v ktorom sú rozobrané mnohé témy diskutované tu.

Aplikačný protokol

Teraz, keď môžeme vymieňať údaje medzi klientmi a serverom, musíme rozhodnúť, aké údaje presne posielať a v akom formáte.

Klasický model spočíva v tom, že klienti posielajú serveru vstup alebo akcie a server posiela klientom aktuálny herný stav.

Server odosiela filtrovaný stav s entitami, ktoré sa nachádzajú v blízkosti hráča, nie úplný stav. Dôvodom sú tri faktory. Po prvé, úplný stav môže byť príliš veľký na to, aby sa prenášal s vysokou frekvenciou. Po druhé, klientov zvyčajne zaujímajú vizuálne a audiudátum, pretože väčšina hernej logiky sa simuluje na hernom serveri. Po tretie, v niektorých hrách by hráč nemal vedieť určité údaje, ako napríklad polohu protivníka na druhom konci mapy, inak môže sniffovať pakety a presne vedieť, kam sa má pohybovať, aby ho zabil.

Serializácia

Prvým krokom bude prevod údajov, ktoré chceme odoslať (vstup alebo herný stav), do vhodného formátu na prenos. Tento proces sa nazýva serializácia.

Hneď ma napadne použiť formát čitateľný pre človeka, ako je JSON alebo XML. Ale to bude úplne neefektívne a zbytočne zaberie veľkú časť prenosového kanála.

Namiesto toho sa odporúča použiť binárny formát, ktorý je oveľa kompaktnejší. Tým pádom budú pakety obsahovať len niekoľko bajtov. Je potrebné brať do úvahy problém poradia bajtov, ktorý sa môže na rôznych počítačoch líšiť.

Na serializáciu údajov je možné použiť knižnicu, napríklad:

Len sa uistite, že knižnica vytvára prenosné archívy a dbá na poradie bajtov.

Alternatívnym riešením môže byť samostatná implementácia, ktorá nie je veľmi zložitá, najmä ak v kóde používate prístup orientovaný na údaje. Okrem toho vám umožní vykonávať optimalizácie, ktoré nie sú vždy možné pri použití knižnice.

Glenn Fiddler napísal o serializácii dva články: Čítanie a písanie paketov a Stratégie serializácie.

Komprimácia

Množstvo údajov prenášaných medzi klientmi a serverom je obmedzené šírkou pásma kanála. Kompresia údajov umožní preniesť v každom snímku viac údajov, zvýšiť frekvenciu aktualizácie alebo jednoducho znížiť požiadavky na kanál.

Bitové balenie

Prvá technika je bitové balenie. Spočíva v použití presne toľkého počtu bitov, aké sú potrebné na opísanie požadovanej veličiny. Napríklad, ak máte výber, ktorý môže mať 16 rôznych hodnôt, môžete namiesto celého bajtu (8 bitov) použiť iba 4 bity.

Glenn Fidler vysvetľuje, ako to implementovať, v druhej časti článku. Čítanie a písanie paketov.

Bitové balenie funguje obzvlášť dobre s diskrétnym kódovaním, ktoré bude témou nasledujúcej sekcie.

Diskrétnosť

Diskrétnosť je technika bezstratového kompresie, ktorá spočíva v použití len podmnožiny možných hodnôt na kódovanie veličiny. Najjednoduchšie je implementovať diskrétnosť zaokrúhľovaním čísel s pohyblivou desatinnou čiarkou.

Glenn Fidler (opäť!) ukazuje, ako prakticky aplikovať diskrétnosť vo svojom článku. Snapshot Compression.

Algoritmy kompresie

Nasledujúcou technikou budú algoritmy bezstratovej kompresie.

Tu sú, podľa môjho názoru, tri najzaujímavejšie algoritmy, ktoré musíte poznať:

  • Huffmanovo kódovanie s predpočítaným kódom, ktorý je mimoriadne rýchly a môže dosiahnuť dobré výsledky. Používal sa na kompresiu paketov v sieťovom engine Quake3.
  • zlib je algoritmus všeobecného použitia, ktorý nikdy nezvyšuje objem dát. Ako môžete vidieť, tubol aplikovaný v mnohých oblastiach použitia. Pre aktualizáciu stavov môže byť nadbytočný. Ale môže sa hodiť, ak potrebujete odosielať klientom z servera zdroje, dlhé texty alebo reliéf.
  • Kopírovanie dlhých sérií je asi najjednoduchší algoritmus kompresie, ale je veľmi účinný pre konkrétne typy dát, a môže byť použitý ako predspracovateľský krok pred zlib. Obzvlášť sa hodí na kompresiu reliéfu pozostávajúceho z dlaždíc alebo voxelov, kde sa opakuje množstvo susedných prvkov.

Delta kompresia

Posledná metóda kompresie je delta kompresia. Spočíva v tom, že sa prenášajú len rozdiely medzi aktuálnym herným stavom a posledným stavom, ktorý klient prijal.

Po prvýkrát bola aplikovaná v sieťovom engine Quake3. Tu sú dva články, ktoré vysvetľujú spôsob jej použitia:

Glenn Fiddler ju použil aj vo druhej časti svojho článku. Snapshot Compression.

Šifrovanie

Okrem toho môžete potrebovať šifrovať prenos informácií medzi klientmi a serverom. Na to existuje niekoľko dôvodov:

  • privátnosť/konfidencialita: správy môžu byť prečítané len prijímateľom a nikto iný, kto vykonáva sniffing siete, ich nedokáže prečítať.
  • autentifikácia: osoba, ktorá chce vystupovať ako hráč, musí poznať jeho kľúč.
  • prevencia podvádzania: zlomyseľným hráčom bude oveľa ťažšie vytvárať vlastné balíky na podvádzanie, budú musieť reprodukovať schému šifrovania a nájsť kľúč (ktorý sa mení pri každom pripojení).

Dôrazne odporúčam použiť na to knižnicu. Navrhujem používať libsodium, pretože je obzvlášť jednoduchá a má skvelé tutoriály. Obzvlášť zaujímavý je tutoriál o výmene kľúčov, ktorý umožňuje generovať nové kľúče pri každom novom pripojení.

Protokol aplikácie: záver

Týmto uzavrieme tému aplikácie. Domnievam sa, že kompresia je úplne zbytočná a rozhodnutie o jej použití závisí len od hry a požadovanej šírky pásma. Šifrovanie je podľa môjho názoru nevyhnutné, ale v prvom prototype sa bez neho dá zaobísť.

Logika aplikácie

Teraz sme schopní aktualizovať stav v klietovi, ale môžeme čeliť problémom so oneskorením. Hráč po vykonaní vstupu musí čakať na aktualizáciu stavu hry od servera, aby videl, aký dopad mal na svet.

Navyše, medzi dvoma aktualizáciami stavu je svet úplne statický. Ak je frekvencia aktualizácie stavov nízka, pohyby budú veľmi trhané.

Existuje niekoľko techník, ktoré umožňujú znížiť dopad tohto problému, a v nasledujúcej časti o nich poviem.

Techniky vyhladzovania oneskorení

Všetky techniky popísané v tejto časti sú podrobne rozobrané v sérii Rýchlo sa rozvíjajúci multiplayer Gabriela Gambettu. Dôrazne odporúčam prečítať si túto vynikajúcu sériu článkov. Obsahuje aj interaktívne demo, ktoré umožňuje vidieť, ako tieto techniky fungujú v praxi.

Prvá technika spočíva v tom, že aplikuje výsledok vstupu priamo, bez čakania na odpoveď od servera. Toto sa nazýva predikcia na strane klienta.. Avšak keď klient dostane aktualizáciu zo servera, musí sa uistiť, že jeho predpoklad bol správny. Ak nie, musí jednoducho zmeniť svoj stav podľa toho, čo dostal od servera, pretože server má konečné slovo. Táto technika bola prvýkrát použitá v Quake. Viac o nej sa dozviete v článku Kontrola kódu Quake Engine Fabiena Sanglara [preklad na Habre].

Druhý súbor techník sa používa na vyhladenie pohybu iných entít medzi dvoma aktualizáciami stavu. Existujú dva spôsoby, ako túto úlohu vyriešiť: interpolácia a extrapolácia. V prípade interpolácie sa vezmú dva posledné stavy a zobrazí sa prechod z jedného do druhého. Jej nevýhodou je, že spôsobuje malú latenciu, pretože klient vždy vidí to, čo sa udialo v minulosti. Extrapolácia spočíva v predpoklade, kde teraz musia byť entity na základe posledného stavu, ktorý klient dostal. Jej nevýhodou je, že ak sa entity úplne zmení smer pohybu, vznikne veľká odchýlka medzi predpokladom a skutočnou pozíciou.

Posledná, najpokročilejšia technika, užitočná len v FPS — je kompenzácia oneskorenia. Pri používaní kompenzácie oneskorenia server zohľadňuje oneskorenia klienta, keď mieri na cieľ. Napríklad, ak hráč uskutočnil headshot na svojej obrazovke, ale v skutočnosti sa jeho cieľ kvôli oneskoreniu nachádzal na inom mieste, bolo by nespravodlivé odoprieť hráčovi právo na zabitie kvôli oneskoreniu. Preto server posúva čas späť na okamih, keď hráč vystrelil, aby simuloval, čo hráč videl na svojej obrazovke, a skontroloval kolíziiu medzi jeho výstrelom a cieľom.

Glenn Fiddler (ako vždy!) napísal v roku 2004 článok Network Physics (2004), v ktorom ustanovil základ synchronizácie simulácie fyziky medzi serverom a klientom. V roku 2014 napísal novú sériu článkov Networking Physics, v ktorých popísal ďalšie techniky na synchronizáciu simulácie fyziky.

Taktiež vo wiki spoločnosti Valve sú dva články, Source Multiplayer Networking a Metódy kompenzácie oneskorenia v návrhu a optimalizácii protokolu v hre klient/server , v ktorých sa zaoberá kompenzáciou oneskorení.

Prevencia podvádzania

Existujú dve hlavné techniky prevencie podvádzania.

Prvá: zloženie odosielania škodlivých balíkov podvodníkmi. Ako je uvedené vyššie, dobrým spôsobom implementácie je šifrovanie.

Druhá: autoritatívny server by mal prijímať iba príkazy/vstupy/akcie. Klient by nemal mať možnosť meniť stav na serveri, iba zasielaním vstupov. Potom musí server vždy pred aplikovaním vstupu overiť jeho platnosť pri jeho prijatí.

Logika aplikácie: záver

Odporúčam implementovať spôsob simulácie veľkých oneskorení a nízkych obnovovacích frekvencií, aby ste mohli testovať správanie svojej hry v zlých podmienkach, aj keď je klient a server spustený na jednom počítači. To výrazne zjednoduší implementáciu metód pre hladkú latenciu.

Iné užitočné zdroje

Ak chcete preskúmať ďalšie zdroje venované sieťovým modelom, môžete ich nájsť tu:

  • Blog Glena Fiedlera — stojí za to prečítať si celý jeho blog, obsahuje množstvo skvelých článkov. Tu sú zhromaždené všetky články o sieťových technológiách.
  • Awesome Game Networking autor M. Fatih MAR — je to podrobný zoznam článkov a videí o sieťových enginoch videohier.
  • V wiki subreddit r/gamedev tiež obsahuje množstvo užitočných odkazov.

Zdroj: habr.com

Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster