O síťovém modelu ve hrách pro začátečníky

O síťovém modelu ve hrách pro začátečníky
Poslední dva týdny jsem pracoval na síťovém enginu pro svou hru. Předtím jsem o networkingu ve hrách nevěděl vůbec nic, takže jsem četl spoustu článků a dělal spoustu experimentů, abych porozuměl všem konceptům a mohl si napsat svůj vlastní síťový engine.

V této příručce bych se s vámi rád podělil o různé koncepty, které se musíte naučit, než napíšete svůj vlastní herní engine, a také o nejlepší zdroje a články, jak se je naučit.

Obecně existují dva hlavní typy síťových architektur: peer-to-peer a klient-server. V architektuře peer-to-peer (p2p) jsou data přenášena mezi libovolným párem připojených přehrávačů, zatímco v architektuře klient-server jsou data přenášena pouze mezi hráči a serverem.

Ačkoli se v některých hrách stále používá architektura peer-to-peer, standardem je klient-server: je snadněji implementovatelný, vyžaduje menší šířku kanálu a usnadňuje ochranu proti podvádění. Proto se v této příručce zaměříme na architekturu klient-server.

Zejména nás nejvíce zajímají autoritářské servery: v takových systémech má server vždy pravdu. Pokud si například hráč myslí, že je na (10, 5) a server mu řekne, že je na (5, 3), pak by měl klient nahradit svou pozici pozicí, kterou server hlásí, nikoli naopak. Použití autoritativních serverů usnadňuje rozpoznání podvodníků.

Herní síťové systémy mají tři hlavní součásti:

  • Transportní protokol: způsob přenosu dat mezi klienty a serverem.
  • Aplikační protokol: co se přenáší z klientů na server a ze serveru do klientů a v jakém formátu.
  • Aplikační logika: jak se přenášená data používají k aktualizaci stavu klientů a serveru.

Je velmi důležité porozumět roli každé části a obtížím s nimi spojenými.

Transportní protokol

Prvním krokem je výběr protokolu pro přenos dat mezi serverem a klienty. K tomu existují dva internetové protokoly: TCP и UDP. Ale můžete si vytvořit svůj vlastní transportní protokol založený na jednom z nich nebo použít knihovnu, která je používá.

Porovnání TCP a UDP

TCP i UDP jsou založeny na IP. IP umožňuje přenos paketu od zdroje k přijímači, ale nezaručuje, že odeslaný paket dříve nebo později dorazí k přijímači, že se k němu dostane alespoň jednou a že sekvence paketů dorazí v správné pořadí. Navíc paket může obsahovat pouze omezenou velikost dat, danou hodnotou MTU.

UDP je jen tenká vrstva na vrcholu IP. Má tedy stejná omezení. Naproti tomu TCP má mnoho funkcí. Poskytuje spolehlivé uspořádané spojení mezi dvěma uzly s kontrolou chyb. Proto je TCP velmi pohodlný a používá se v mnoha dalších protokolech, například v HTTP, FTP и SMTP. Všechny tyto funkce však mají svou cenu: zpoždění.

Abychom pochopili, proč tyto funkce mohou způsobit latenci, musíme pochopit, jak TCP funguje. Když odesílající hostitel předá paket přijímajícímu hostiteli, očekává přijetí potvrzení (ACK). Pokud jej po určité době nepřijme (z důvodu ztráty paketu nebo potvrzení nebo z nějakého jiného důvodu), odešle paket znovu. Kromě toho TCP zaručuje, že pakety jsou přijímány ve správném pořadí, takže dokud není přijat ztracený paket, nemohou být zpracovány všechny ostatní pakety, i když již byly přijaty přijímajícím uzlem.

Ale jak asi chápete, latence ve hrách pro více hráčů je velmi důležitá, zvláště v tak aktivních žánrech, jako je FPS. To je důvod, proč mnoho her používá UDP s vlastním protokolem.

Nativní protokol založený na UDP může být z různých důvodů efektivnější než TCP. Může například označit některé balíčky jako důvěryhodné a jiné jako nedůvěryhodné. Je mu tedy jedno, jestli nespolehlivý paket dorazil k příjemci. Nebo může zpracovat více datových toků, takže paket ztracený v jednom toku nezpomaluje ostatní toky. Například může existovat vlákno pro vstup hráče a další vlákno pro chatové zprávy. Pokud dojde ke ztrátě chatové zprávy, která nepředstavuje urgentní data, nezpomalí to naléhavý vstup. Nebo může proprietární protokol implementovat spolehlivost jinak než TCP, aby byl v prostředí videoher efektivnější.

Takže, když TCP je na hovno, pak si vybudujeme vlastní transportní protokol založený na UDP?

Všechno je trochu složitější. Přestože TCP není pro herní síťové systémy téměř optimální, může pro vaši konkrétní hru fungovat docela dobře a ušetřit vám drahocenný čas. Například latence nemusí být problémem pro tahovou hru nebo hru, kterou lze hrát pouze v sítích LAN, kde je latence a ztráta paketů mnohem menší než na internetu.

Mnoho úspěšných her, včetně World of Warcraft, Minecraft a Terraria, používá TCP. Většina FPS však používá své vlastní protokoly založené na UDP, proto si o nich povíme více níže.

Pokud se rozhodnete použít TCP, ujistěte se, že je zakázáno Nagleho algoritmus, protože před odesláním ukládá pakety do vyrovnávací paměti, což znamená, že zvyšuje zpoždění.

Další informace o rozdílech mezi UDP a TCP v kontextu her pro více hráčů naleznete v článku Glenna Fiedlera UDP vs. TCP.

Proprietární protokol

Chcete si tedy vytvořit svůj vlastní transportní protokol, ale nevíte, kde začít? Máte štěstí, protože Glenn Fiedler o tom napsal dva úžasné články. Najdete v nich spoustu chytrých nápadů.

První článek Networking pro herní programátory 2008, jednodušší než druhý Budování herního síťového protokolu 2016. Doporučuji začít tím starším.

Uvědomte si, že Glenn Fiedler je velkým zastáncem používání vašeho vlastního protokolu založeného na UDP. A po přečtení jeho článků si pravděpodobně osvojíte jeho názor, že TCP má ve videohrách vážné nedostatky, a budete chtít implementovat svůj vlastní protokol.

Ale pokud jste v sítích noví, udělejte si laskavost a použijte TCP nebo knihovnu. Chcete-li úspěšně implementovat svůj vlastní přenosový protokol, musíte se předem hodně naučit.

Síťové knihovny

Pokud potřebujete něco efektivnějšího než TCP, ale nechcete se obtěžovat implementací vlastního protokolu a zacházet do mnoha detailů, můžete použít síťovou knihovnu. Je jich hodně:

Nezkoušel jsem je všechny, ale preferuji ENet, protože se snadno používá a je spolehlivý. Navíc má přehlednou dokumentaci a návod pro začátečníky.

Závěr dopravního protokolu

Abychom to shrnuli, existují dva hlavní transportní protokoly: TCP a UDP. TCP má mnoho užitečných funkcí: spolehlivost, zachování pořadí paketů, detekce chyb. UDP to všechno nemá, ale TCP má ze své podstaty vysokou latenci, která je pro některé hry nepřijatelná. To znamená, že pro zajištění nízké latence si můžete vytvořit svůj vlastní protokol založený na UDP nebo použít knihovnu, která implementuje transportní protokol na UDP a je přizpůsobena pro videohry pro více hráčů.

Volba mezi TCP, UDP a knihovnou závisí na několika faktorech. Za prvé, z potřeb hry: potřebuje nízkou latenci? Za druhé, z požadavků aplikačního protokolu: potřebuje spolehlivý protokol? Jak uvidíme v dalším díle, je možné vytvořit aplikační protokol, pro který se docela hodí nespolehlivý protokol. Nakonec je také třeba vzít v úvahu zkušenosti vývojáře síťového motoru.

Mám dva tipy:

  • Abstrahujte transportní protokol co nejvíce od zbytku aplikace, aby jej bylo možné snadno nahradit bez přepisování celého kódu.
  • Neoptimalizujte se. Pokud nejste síťový expert a nejste si jisti, zda potřebujete svůj vlastní transportní protokol založený na UDP, můžete začít s TCP nebo knihovnou, která poskytuje spolehlivost, a poté testovat a měřit výkon. Pokud máte problémy a jste si jisti, že se jedná o přenosový protokol, pak je možná čas vytvořit si vlastní přenosový protokol.

Na konci této části doporučuji k přečtení Úvod do programování her pro více hráčů Briana Hooka, která pokrývá mnoho zde diskutovaných témat.

Aplikační protokol

Nyní, když si můžeme vyměňovat data mezi klienty a serverem, musíme se rozhodnout, jaká data přenést a v jakém formátu.

Klasické schéma je, že klienti posílají vstup nebo akce na server a server posílá klientům aktuální stav hry.

Server neodesílá úplný, ale filtrovaný stav s entitami, které jsou v blízkosti přehrávače. Dělá to ze tří důvodů. Za prvé, celkový stav může být příliš velký pro vysílání na vysoké frekvenci. Za druhé, klienty zajímají především obrazová a zvuková data, protože většina herní logiky je simulována na herním serveru. Zatřetí, v některých hrách hráč nemusí znát určité údaje, jako je pozice nepřítele na druhé straně mapy, protože jinak může čichat pakety a přesně vědět, kam se přesunout, aby ho zabil.

Serializace

Prvním krokem je převést data, která chceme odeslat (vstup nebo stav hry) do formátu vhodného pro přenos. Tento proces se nazývá serializace.

Okamžitě mě napadne použít formát čitelný pro člověka, jako je JSON nebo XML. Ale to bude zcela neefektivní a zabere většinu kanálu za nic.

Místo toho se doporučuje použít binární formát, který je mnohem kompaktnější. To znamená, že pakety budou obsahovat pouze několik bajtů. Zde musíme vzít v úvahu problém pořadí bajtů, které se mohou na různých počítačích lišit.

K serializaci dat můžete použít knihovnu, například:

Jen se ujistěte, že knihovna vytváří přenosné archivy a stará se o endianness.

Alternativním řešením by bylo implementovat to sami, není to tak těžké, zvláště pokud ve svém kódu používáte přístup zaměřený na data. Navíc vám umožní provádět optimalizace, které nejsou při používání knihovny vždy možné.

Glenn Fiedler napsal dva články o serializaci: Čtení a psaní paketů и Strategie serializace.

Komprese

Množství dat přenášených mezi klienty a serverem je omezeno šířkou pásma kanálu. Komprese dat vám umožní přenést více dat v každém snímku, zvýšit obnovovací frekvenci nebo jednoduše snížit požadavky na šířku pásma.

Balení bitů

První technikou je balení bitů. Spočívá v použití přesně takového počtu bitů, který je nutný k popisu požadované hodnoty. Pokud máte například výčet, který může mít 16 různých hodnot, můžete místo celého bajtu (8 bitů) použít pouze 4 bity.

Glenn Fiedler vysvětluje, jak to implementovat ve druhé části článku. Čtení a psaní paketů.

Balení bitů funguje obzvláště dobře s diskretizací, která bude tématem další části.

Vzorkování

Vzorkování je ztrátová kompresní technika, která ke kódování hodnoty používá pouze podmnožinu možných hodnot. Nejjednodušší způsob implementace diskretizace je zaokrouhlení čísel s plovoucí desetinnou čárkou.

Glenn Fiedler (opět!) ve svém článku ukazuje, jak aplikovat diskretizaci v praxi Komprese snímku.

Kompresní algoritmy

Další technikou budou bezeztrátové kompresní algoritmy.

Zde jsou podle mého názoru tři nejzajímavější algoritmy, které potřebujete znát:

  • Huffmanovo kódování s předpočítaným kódem, který je extrémně rychlý a může produkovat dobré výsledky. Byl použit ke kompresi paketů v síťovém enginu Quake3.
  • zlib je obecný kompresní algoritmus, který nikdy nezvyšuje množství dat. Jak můžeš vidět zde, byl použit v různých aplikacích. Pro stavy aktualizace může být nadbytečný. Může se ale hodit, pokud potřebujete klientům ze serveru poslat aktiva, dlouhé texty nebo terén.
  • Kopírování délek běhů je pravděpodobně nejjednodušší kompresní algoritmus, ale je velmi účinný pro určité typy dat a lze jej použít jako krok předběžného zpracování před zlib. Je vhodný zejména pro stlačování terénu tvořeného dlaždicemi nebo voxely, ve kterých se mnoho sousedních prvků opakuje.

delta komprese

Poslední kompresní technikou je delta komprese. Spočívá v tom, že jsou přenášeny pouze rozdíly mezi aktuálním stavem hry a posledním stavem přijatým klientem.

Poprvé byl použit v síťovém enginu Quake3. Zde jsou dva články vysvětlující, jak jej používat:

V druhé části svého článku jej použil i Glenn Fiedler. Komprese snímku.

Šifrování

Kromě toho může být nutné zašifrovat přenos informací mezi klienty a serverem. Důvodů je několik:

  • Soukromí/Důvěrnost: Zprávy může číst pouze příjemce a žádný jiný síťový sniffer je nebude moci číst.
  • autentizace: osoba, která chce hrát roli hráče, musí znát svůj klíč.
  • cheat prevence: pro zlomyslné hráče bude mnohem obtížnější vytvořit si vlastní cheatové balíčky, budou muset replikovat šifrovací schéma a najít klíč (který se mění při každém připojení).

K tomu důrazně doporučuji použít knihovnu. Doporučuji používat libsodium, protože je obzvláště jednoduchý a má skvělé návody. Zvláště zajímavý je tutoriál na výměna klíčů, který umožňuje generovat nové klíče při každém novém připojení.

Aplikační protokol: Závěr

Tím je aplikační protokol uzavřen. Věřím, že komprese je zcela volitelná a rozhodnutí o jejím použití závisí pouze na hře a požadované šířce pásma. Šifrování je podle mě povinné, ale v prvním prototypu se bez něj obejdete.

Aplikační logika

Nyní jsme schopni aktualizovat stav v klientovi, ale můžeme narazit na problémy s latencí. Po provedení vstupu musí hráč počkat na aktualizaci stavu hry ze serveru, aby zjistil, jaký vliv to mělo na svět.

Navíc mezi dvěma aktualizacemi stavu je svět zcela statický. Pokud je rychlost aktualizace stavu nízká, budou pohyby velmi trhané.

Existuje několik technik ke zmírnění dopadu tohoto problému a já se jim budu věnovat v další části.

Techniky zpožděného vyhlazování

Všechny techniky popsané v této části jsou podrobně popsány v seriálu. Rychlý multiplayer Gabriel Gambetta. Vřele doporučuji přečíst si tuto skvělou sérii článků. Součástí je také interaktivní demo, abyste viděli, jak tyto techniky fungují v praxi.

První technikou je použít výsledek vstupu přímo bez čekání na odpověď ze serveru. To se nazývá predikce na straně klienta. Když však klient obdrží aktualizaci ze serveru, musí ověřit, že jeho předpověď byla správná. Pokud tomu tak není, pak stačí změnit svůj stav podle toho, co obdržel od serveru, protože server je autoritářský. Tato technika byla poprvé použita v Quake. Více si o tom můžete přečíst v článku. Kontrola kódu Quake Engine Fabien Sanglars [překlad na Habré].

Druhá sada technik se používá k vyhlazení pohybu dalších entit mezi dvěma aktualizacemi stavu. Tento problém lze vyřešit dvěma způsoby: interpolací a extrapolací. V případě interpolace se převezmou poslední dva stavy a zobrazí se přechod z jednoho do druhého. Jeho nevýhodou je, že způsobuje malý zlomek zpoždění, protože klient vždy vidí, co se stalo v minulosti. Extrapolace je o predikci, kde by se entity nyní měly nacházet, na základě posledního stavu obdrženého klientem. Jeho nevýhodou je, že pokud entita zcela změní směr pohybu, pak dojde k velké chybě mezi prognózou a skutečnou pozicí.

Poslední, nejpokročilejší technika, použitelná pouze v FPS, je kompenzace zpoždění. Při použití kompenzace zpoždění server bere v úvahu zpoždění klienta, když střílí na cíl. Pokud například hráč provedl na obrazovce headshot, ale ve skutečnosti byl jeho cíl kvůli zpoždění na jiném místě, pak by bylo nespravedlivé odepřít hráči právo zabíjet kvůli zpoždění. Server tedy přetočí čas zpět do doby, kdy hráč vystřelil, aby simuloval, co hráč viděl na obrazovce, a zkontroloval, zda nedošlo ke kolizi mezi jeho střelou a cílem.

Glenn Fiedler (jako vždy!) napsal článek v roce 2004 Síťová fyzika (2004), ve kterém položil základ pro synchronizaci fyzikálních simulací mezi serverem a klientem. V roce 2014 napsal novou sérii článků síťová fyzika, ve kterém popsal další techniky synchronizace fyzikálních simulací.

Na wiki společnosti Valve jsou také dva články, Zdrojová síť pro více hráčů и Metody kompenzace latence v návrhu a optimalizaci protokolu klient/server ve hře řeší náhradu za zpoždění.

Prevence cheatů

Existují dvě hlavní techniky prevence podvádění.

Za prvé, podvodníkům ztěžuje odesílání škodlivých paketů. Jak již bylo zmíněno výše, dobrým způsobem implementace je šifrování.

Za druhé, autoritářský server by měl přijímat pouze příkazy/vstupy/akce. Klient by neměl mít možnost změnit stav na serveru jinak než odesláním vstupu. Poté musí server pokaždé, když obdrží vstup, zkontrolovat jeho platnost, než jej použije.

Aplikační logika: Závěr

Doporučuji vám implementovat způsob simulace vysoké latence a nízké obnovovací frekvence, abyste mohli testovat chování vaší hry ve špatných podmínkách, i když klient a server běží na stejném počítači. To značně zjednodušuje implementaci technik vyhlazování zpoždění.

Další užitečné zdroje

Pokud chcete prozkoumat další zdroje síťového modelu, najdete je zde:

  • Blog Glenna Fiedlera — stojí za to přečíst si celý jeho blog, je v něm mnoho výborných článků. Zde shromažďují se všechny články o síťových technologiích.
  • Úžasná herní síť od M. Fatiha MAR je obsáhlý seznam článků a videí o síťových motorech videoher.
  • В wiki subreddit r/gamedev Je zde také mnoho užitečných odkazů.

Zdroj: www.habr.com

Přidat komentář