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 online engine pre moju hru. Predtým som nevedel o sieťovaní v hrách vôbec nič, takže som čítal veľa článkov a robil veľa experimentov, aby som pochopil všetky koncepty a mohol napísať svoj vlastný sieťový engine.

V tejto príručke by som sa s vami rád podelil o rôzne koncepty, ktoré sa musíte naučiť pred napísaním vlastného herného enginu, ako aj o najlepšie zdroje a články, ako sa ich naučiť.

Vo všeobecnosti 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 ľubovoľnými pármi pripojených prehrávačov, zatiaľ čo v architektúre klient-server sa údaje prenášajú iba medzi prehrávačmi a serverom.

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

Najmä nás najviac zaujímajú autoritárske servery: v takýchto systémoch má server vždy pravdu. Napríklad, ak si hráč myslí, že je na súradniciach (10, 5) a server mu povie, že je na (5, 3), potom by mal klient nahradiť svoju pozíciu tou, ktorú nahlásil server, a nie naopak. naopak. Používanie autoritatívnych serverov uľahčuje identifikáciu podvodníkov.

Sieťové herné systémy majú tri hlavné komponenty:

  • Transportný protokol: ako sa dáta prenášajú medzi klientmi a serverom.
  • Aplikačný protokol: čo sa prenáša z klientov na server a zo servera na klientov a v akom formáte.
  • Aplikačná logika: ako sa prenesené údaje používajú na aktualizáciu stavu klientov a servera.

Je veľmi dôležité pochopiť úlohu každej časti a výzvy, ktoré sú s nimi spojené.

Transportný protokol

Prvým krokom je výber protokolu na prenos údajov medzi serverom a klientmi. Na to existujú dva internetové protokoly: TCP и UDP. Môžete si však vytvoriť svoj vlastný transportný protokol založený na jednom z nich alebo použiť knižnicu, ktorá ich používa.

Porovnanie TCP a UDP

TCP aj UDP sú založené na IP. IP umožňuje preniesť paket zo zdroja k príjemcovi, ale nezaručuje, že sa odoslaný paket skôr či neskôr dostane k príjemcovi, že sa k nemu dostane aspoň raz a že poradie paketov dorazí v správnom poradí. objednať. Navyše, paket môže obsahovať len obmedzené množstvo dát, dané napr MTU.

UDP je len tenká vrstva na vrchu IP. Preto má rovnaké obmedzenia. Naproti tomu TCP má mnoho funkcií. Poskytuje 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. HTTP, FTP и SMTP. Všetky tieto funkcie však majú svoju cenu: meškanie.

Aby sme pochopili, prečo tieto funkcie môžu spôsobiť oneskorenie, musíme pochopiť, ako funguje TCP. Keď vysielací uzol vysiela paket do prijímacieho uzla, očakáva prijatie potvrdenia (ACK). Ak ho po určitom čase neprijme (pretože sa paket alebo potvrdenie stratili, alebo z nejakého iného dôvodu), potom paket odošle znova. Okrem toho TCP zaručuje, že pakety sú prijímané v správnom poradí, takže kým nie je prijatý stratený paket, všetky ostatné pakety nemôžu byť spracované, aj keď už boli prijaté prijímajúcim hostiteľom.

Ale ako si asi viete predstaviť, latencia v hrách pre viacerých hráčov je veľmi dôležitá, najmä v akčných žánroch, ako je FPS. To je dôvod, prečo mnoho hier používa UDP s vlastným protokolom.

Natívny protokol založený na UDP môže byť z rôznych dôvodov efektívnejší ako TCP. Môže napríklad označiť niektoré pakety ako dôveryhodné a iné ako nedôveryhodné. Preto je jedno, či sa nedôveryhodný paket dostane k príjemcovi. Alebo dokáže spracovať viacero dátových tokov, aby stratený paket v jednom toku nespomalil zostávajúce toky. Napríklad tam môže byť vlákno pre vstup hráča a iné vlákno pre chatové správy. Ak sa stratí chatová správa, ktorá nie je naliehavá, nespomalí to zadávanie, ktoré je naliehavé. Alebo proprietárny protokol môže implementovať spoľahlivosť inak ako TCP, aby bol efektívnejší v prostredí videohier.

Takže, ak je TCP tak nanič, potom si vytvoríme vlastný transportný protokol založený na UDP?

Je to trochu zložitejšie. Aj keď je TCP takmer neoptimálne pre herné sieťové systémy, môže celkom dobre fungovať pre vašu konkrétnu hru a ušetriť vám drahocenný čas. Napríklad latencia nemusí byť problémom pre ťahovú hru alebo hru, ktorú možno hrať iba v sieťach LAN, kde je latencia a strata paketov oveľa nižšia ako na internete.

Mnoho úspešných hier, vrátane World of Warcraft, Minecraft a Terraria, používa TCP. Väčšina FPS však používa svoje vlastné protokoly založené na UDP, preto si o nich povieme viac nižšie.

Ak sa rozhodnete použiť TCP, uistite sa, že je vypnutý Nagleho algoritmus, pretože pred odoslaním ukladá pakety do vyrovnávacej pamäte, čo znamená, že zvyšuje latenciu.

Ak sa chcete dozvedieť viac o rozdieloch medzi UDP a TCP v kontexte hier pre viacerých hráčov, môžete si prečítať článok Glenna Fiedlera UDP vs. TCP.

Vlastný protokol

Chcete si teda vytvoriť svoj vlastný transportný protokol, ale neviete, kde začať? Máte šťastie, pretože Glenn Fiedler o tom napísal dva úžasné články. Nájdete v nich množstvo chytrých myšlienok.

Prvý článok Networking pre herných programátorov 2008, ľahší ako druhý, Budovanie herného sieťového protokolu 2016. Odporúčam začať tým starším.

Všimnite si, že Glenn Fiedler je veľkým zástancom používania vlastného protokolu založeného na UDP. A po prečítaní jeho článkov si pravdepodobne osvojíte jeho názor, že TCP má vo videohrách vážne nedostatky a budete chcieť implementovať svoj vlastný protokol.

Ale ak ste v sieťovaní nováčik, urobte si láskavosť a použite TCP alebo knižnicu. Ak chcete úspešne implementovať svoj vlastný transportný protokol, musíte sa vopred veľa naučiť.

Sieťové knižnice

Ak potrebujete niečo efektívnejšie ako TCP, ale nechcete sa trápiť s implementáciou vlastného protokolu a zachádzať do mnohých detailov, môžete použiť sieťovú knižnicu. Je ich veľa:

Neskúšal som ich všetky, ale preferujem ENet, pretože sa ľahko používa a je spoľahlivý. Navyše má prehľadnú dokumentáciu a návod pre začiatočníkov.

Prepravný protokol: Záver

Aby sme to zhrnuli: existujú dva hlavné transportné protokoly: TCP a UDP. TCP má mnoho užitočných funkcií: spoľahlivosť, zachovanie poradia paketov, detekcia chýb. UDP toto všetko nemá, ale TCP má zo svojej podstaty zvýšenú latenciu, čo je pre niektoré hry neprijateľné. To znamená, že na zabezpečenie nízkej latencie si môžete vytvoriť svoj vlastný protokol založený na UDP alebo použiť knižnicu, ktorá implementuje transportný protokol na UDP a je prispôsobená pre videohry pre viacerých hráčov.

Výber medzi TCP, UDP a knižnicou závisí od viacerých faktorov. Po prvé, z potrieb hry: potrebuje nízku latenciu? Po druhé, z požiadaviek na aplikačný protokol: potrebuje spoľahlivý protokol? Ako uvidíme v ďalšej časti, je možné vytvoriť aplikačný protokol, pre ktorý sa celkom hodí nedôveryhodný protokol. Nakoniec musíte vziať do úvahy aj skúsenosti vývojára sieťového motora.

Mám dve rady:

  • Abstrahujte transportný protokol od zvyšku aplikácie čo najviac, aby ho bolo možné jednoducho nahradiť bez prepisovania celého kódu.
  • Neoptimalizujte sa. Ak nie ste sieťový expert a nie ste si istí, či potrebujete vlastný transportný protokol založený na UDP, môžete začať s TCP alebo knižnicou, ktorá poskytuje spoľahlivosť, a potom testovať a merať výkon. Ak sa vyskytnú problémy a ste si istí, že príčinou je transportný protokol, potom je možno čas vytvoriť si vlastný transportný protokol.

Na konci tejto časti vám odporúčam prečítať si Úvod do programovania hier pre viacerých hráčov od Briana Hooka, ktorá pokrýva mnohé z tém, o ktorých sa tu diskutuje.

Aplikačný protokol

Teraz, keď si môžeme vymieňať dáta medzi klientmi a serverom, musíme sa rozhodnúť, aké dáta preniesť a v akom formáte.

Klasická schéma je taká, že klienti posielajú vstup alebo akcie na server a server posiela aktuálny stav hry klientom.

Server neposiela úplný stav, ale filtrovaný stav s entitami, ktoré sa nachádzajú v blízkosti prehrávača. Robí to z troch dôvodov. Po prvé, úplný stav môže byť príliš veľký na to, aby bol prenášaný vysokou frekvenciou. Po druhé, klientov zaujímajú hlavne obrazové a zvukové dáta, pretože väčšina logiky hry je simulovaná na hernom serveri. Po tretie, v niektorých hrách hráč nemusí poznať určité údaje, napríklad polohu nepriateľa na druhej strane mapy, inak môže čuchať pakety a presne vedieť, kam sa má presunúť, aby ho zabil.

Serializácia

Prvým krokom je previesť dáta, ktoré chceme odoslať (vstup alebo stav hry) do formátu vhodného na prenos. Tento proces sa nazýva serializácie.

Myšlienka, ktorá okamžite príde na myseľ, je použiť formát čitateľný pre ľudí, ako je JSON alebo XML. Bude to však úplne neúčinné a stratí väčšinu kanála.

Namiesto toho sa odporúča použiť binárny formát, ktorý je oveľa kompaktnejší. To znamená, že pakety budú obsahovať len niekoľko bajtov. Tu je potrebné zvážiť problém poradie bajtov, ktoré sa môžu na rôznych počítačoch líšiť.

Na serializáciu údajov môžete použiť knižnicu, napríklad:

Len sa uistite, že knižnica vytvára prenosné archívy a stará sa o endianness.

Alternatívnym riešením je implementovať to sami; nie je to obzvlášť ťažké, najmä ak k svojmu kódu používate prístup zameraný na údaje. Okrem toho vám umožní vykonávať optimalizácie, ktoré nie sú pri používaní knižnice vždy možné.

Glenn Fiedler napísal dva články o serializácii: Čítanie a písanie balíčkov и Stratégie serializácie.

kompresia

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

Balenie bitov

Prvou technikou je balenie bitov. Spočíva v použití presného počtu bitov, ktoré sú potrebné na opísanie požadovanej hodnoty. Napríklad, ak máte enum, ktoré môže mať 16 rôznych hodnôt, potom namiesto celého bajtu (8 bitov) môžete použiť iba 4 bity.

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

Balenie bitov funguje obzvlášť dobre pri vzorkovaní, čo bude témou nasledujúcej časti.

Vzorkovanie

Vzorkovanie je technika stratovej kompresie, ktorá na zakódovanie hodnoty používa iba podmnožinu možných hodnôt. Najjednoduchší spôsob implementácie diskretizácie je zaokrúhlenie čísel s pohyblivou rádovou čiarkou.

Glenn Fiedler (opäť!) vo svojom článku ukazuje, ako zaviesť sample do praxe Snímková kompresia.

Kompresné algoritmy

Ďalšou technikou budú bezstratové kompresné algoritmy.

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

  • Huffmanovo kódovanie s vopred vypočítaným kódom, ktorý je extrémne rýchly a môže priniesť dobré výsledky. Bol použitý na kompresiu paketov v sieťovom motore Quake3.
  • zlib je univerzálny kompresný algoritmus, ktorý nikdy nezvyšuje množstvo údajov. Ako môžeš vidieť tu, používa sa v rôznych aplikáciách. Pre aktualizáciu stavov môže byť nadbytočný. Ale môže to byť užitočné, ak potrebujete poslať aktíva, dlhé texty alebo terén klientom zo servera.
  • Kopírovanie dĺžok chodu - Toto je pravdepodobne najjednoduchší kompresný algoritmus, ale je veľmi efektívny pre určité typy údajov a možno ho použiť ako krok predspracovania pred zlib. Je vhodný najmä na stláčanie terénu zloženého z dlaždíc alebo voxelov, v ktorých sa mnoho susedných prvkov opakuje.

Delta kompresia

Poslednou kompresnou technikou je delta kompresia. Spočíva v tom, že sa prenášajú len rozdiely medzi aktuálnym stavom hry a posledným stavom prijatým klientom.

Prvýkrát bol použitý v sieťovom engine Quake3. Tu sú dva články vysvetľujúce, ako ho používať:

V druhej časti svojho článku to použil aj Glenn Fiedler Snímková kompresia.

šifrovanie

Okrem toho možno budete musieť zašifrovať prenos informácií medzi klientmi a serverom. Existuje na to niekoľko dôvodov:

  • súkromie/dôvernosť: správy si môže prečítať iba príjemca a nebude ich môcť prečítať žiadna iná osoba, ktorá si prečíta sieť.
  • autentifikácia: osoba, ktorá chce hrať rolu hráča, musí poznať svoj kľúč.
  • Prevencia cheatov: Pre hráčov so zlými úmyslami bude oveľa ťažšie vytvoriť si vlastné cheatové balíčky, budú musieť reprodukovať šifrovaciu schému a nájsť kľúč (ktorý sa mení s každým pripojením).

Na to dôrazne odporúčam použiť knižnicu. Odporúčam použiť libsodium, pretože je obzvlášť jednoduchý a má vynikajúce návody. Obzvlášť zaujímavý je návod na výmena kľúčov, ktorý umožňuje generovať nové kľúče pri každom novom pripojení.

Aplikačný protokol: Záver

Týmto sa uzatvára náš aplikačný protokol. Verím, že kompresia je úplne voliteľná a rozhodnutie o jej použití závisí len od hry a požadovanej šírky pásma. Šifrovanie je podľa mňa povinné, no v prvom prototype sa bez neho zaobídete.

Aplikačná logika

Teraz môžeme aktualizovať stav v klientovi, ale môžu sa vyskytnúť problémy s latenciou. Hráč musí po dokončení zadania počkať, kým sa herný stav aktualizuje zo servera, aby zistil, aký vplyv to malo na svet.

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

Existuje niekoľko techník na zníženie dopadu tohto problému a budem sa im venovať v ďalšej časti.

Techniky vyhladzovania latencie

Všetky techniky opísané v tejto časti sú podrobne diskutované v sérii Rýchly multiplayer Gabriel Gambetta. Vrelo odporúčam prečítať si túto skvelú sériu článkov. Obsahuje aj interaktívnu ukážku, ktorá vám umožní vidieť, ako tieto techniky fungujú v praxi.

Prvou technikou je použiť vstupný výsledok priamo bez čakania na odpoveď zo servera. To sa nazýva prognózovanie na strane klienta. Keď však klient dostane aktualizáciu zo servera, musí overiť, či bola jeho predpoveď správna. Ak to tak nie je, potom musí zmeniť svoj stav podľa toho, čo dostal zo servera, pretože server je autoritársky. Táto technika bola prvýkrát použitá v Quake. Viac si o tom môžete prečítať v článku Kontrola kódu Quake Engine Fabien Sanglars [preklad na Habré].

Druhá sada techník sa používa na vyhladenie pohybu iných entít medzi dvoma aktualizáciami stavu. Existujú dva spôsoby riešenia tohto problému: interpolácia a extrapolácia. V prípade interpolácie sa berú posledné dva stavy a zobrazuje sa prechod z jedného do druhého. Jeho nevýhodou je, že spôsobuje malé zdržanie, pretože klient vždy vidí, čo sa stalo v minulosti. Extrapolácia je o predpovedaní, kde by sa entity teraz mali nachádzať na základe posledného stavu, ktorý klient dostal. Jeho nevýhodou je, že ak entita úplne zmení smer pohybu, potom dôjde k veľkej chybe medzi predpoveďou a skutočnou polohou.

Najnovšia, najpokročilejšia technika použiteľná iba v FPS je kompenzácia oneskorenia. Pri použití kompenzácie oneskorenia server berie do úvahy oneskorenia klienta pri streľbe na cieľ. Napríklad, ak hráč na svojej obrazovke urobil headshot, ale v skutočnosti bol jeho cieľ kvôli oneskoreniu na inom mieste, potom by bolo nespravodlivé odoprieť hráčovi právo zabiť kvôli oneskoreniu. Server preto pretočí čas späť do momentu, keď hráč vystrelil, aby simuloval to, čo hráč videl na obrazovke a skontroloval, či nedošlo ku kolízii medzi jeho strelou a cieľom.

Glenn Fiedler (ako vždy!) napísal článok v roku 2004 Sieťová fyzika (2004), v ktorej položil základ pre synchronizáciu fyzikálnych simulácií medzi serverom a klientom. V roku 2014 napísal novú sériu článkov Sieťová fyzika, ktorý opísal ďalšie techniky synchronizácie fyzikálnych simulácií.

Na wiki Valve sú tiež dva články, Zdrojová sieť pre viacerých hráčov и Metódy kompenzácie latencie pri návrhu a optimalizácii protokolu klient/server v hre ktoré zvažujú náhradu za meškanie.

Predchádzanie podvádzaniu

Existujú dve hlavné techniky na predchádzanie podvádzaniu.

Po prvé: sťaženie podvodníkom pri odosielaní škodlivých paketov. Ako bolo uvedené vyššie, dobrým spôsobom, ako to implementovať, je šifrovanie.

Po druhé: autoritársky server by mal prijímať iba príkazy/vstupy/akcie. Klient by nemal mať možnosť zmeniť stav na serveri inak ako odoslaním vstupu. Potom vždy, keď server prijme vstup, musí pred jeho použitím skontrolovať, či je platný.

Aplikačná logika: záver

Odporúčam vám implementovať spôsob simulácie vysokej latencie a nízkej obnovovacej frekvencie, aby ste mohli testovať správanie vašej hry v zlých podmienkach, aj keď klient a server bežia na rovnakom počítači. To výrazne zjednoduší implementáciu techník vyhladzovania oneskorenia.

Ďalšie užitočné zdroje

Ak by ste chceli preskúmať ďalšie zdroje sieťových modelov, nájdete ich tu:

Zdroj: hab.com

Pridať komentár