Megapack: Ako Factorio vyriešilo problém s hrou pre 200 hráčov

Megapack: Ako Factorio vyriešilo problém s hrou pre 200 hráčov
V máji tohto roku som sa zúčastnil ako hráč MMO akcie KatherineOfSky. Všimol som si, že keď počet hráčov dosiahne určitý počet, každých pár minút niektorí z nich „odpadnú“. Našťastie pre vás (ale nie pre mňa) som bol jedným z tých hráčov, ktorí sa odpojili vždyaj pri dobrom spojení. Zobral som to ako osobnú výzvu a začal som pátrať po príčinách problému. Po troch týždňoch ladenia, testovania a opráv bola chyba konečne opravená, no cesta nebola taká jednoduchá.

Problémy s hrami pre viacerých hráčov je veľmi ťažké vystopovať. Zvyčajne sa vyskytujú pri veľmi špecifických sieťových parametroch a veľmi špecifických herných podmienkach (v tomto prípade s viac ako 200 hráčmi). A aj keď je možné problém reprodukovať, nie je možné ho správne odladiť, pretože vkladanie bodov prerušenia zastaví hru, mätie časovače a zvyčajne spôsobí časový limit pripojenia. Ale vďaka vytrvalosti a úžasnému nástroju tzv neohrabaný Podarilo sa mi zistiť, čo sa deje.

Stručne povedané, kvôli chybe a neúplnej implementácii simulácie stavu latencie sa klient niekedy ocitol v situácii, keď musel poslať sieťový paket pozostávajúci z hráčových vstupných výberových akcií približne 400 herných entít v jednom hodinovom cykle ( nazývame to „mega-paket“). Server potom musí všetky tieto vstupné akcie nielen správne prijať, ale aj odoslať všetkým ostatným klientom. Ak máte 200 klientov, rýchlo sa to stane problémom. Spojenie so serverom sa rýchlo upchá, čo vedie k strate paketov a kaskáde opätovne vyžiadaných paketov. Oneskorenie vstupnej akcie potom spôsobí, že ešte viac klientov pošle megapakety, čo spôsobí, že lavína sa ešte zväčší. Šťastní klienti sa dokážu zotaviť, všetci ostatní odpadnú.

Megapack: Ako Factorio vyriešilo problém s hrou pre 200 hráčov
Problém bol dosť zásadný a trvalo mi 2 týždne, kým som ho vyriešil. Je to dosť technické, takže nižšie vysvetlím šťavnaté technické detaily. Najprv však musíte vedieť, že od verzie 0.17.54, vydanej 4. júna, sa vďaka dočasným problémom s pripojením stal multiplayer stabilnejším a oneskorenia pri skrývaní sa stali oveľa menej chybnými (menej spomalenia a teleportovania). Zmenil som aj spôsob, akým je bojové oneskorenie skryté a dúfam, že to bude trochu plynulejšie.

Multiplayer Mega Pack - Technické detaily

Zjednodušene povedané, multiplayer v hre funguje takto: všetci klienti simulujú stav hry, pričom prijímajú a odosielajú iba vstup od hráča (nazývané „akcie vstupu“, Vstupné akcie). Hlavnou úlohou servera je vysielať Vstupné akcie a kontrolovať, že všetci klienti vykonávajú rovnaké akcie v rovnakom cykle hodín. Viac si o tom môžete prečítať v príspevku FFF-149.

Keďže server musí robiť rozhodnutia o tom, aké akcie má vykonať, akcie hráča sa pohybujú približne po tejto ceste: akcia hráča -> herný klient -> sieť -> server -> sieť -> herný klient. To znamená, že akcia každého hráča sa vykoná až po vykonaní spiatočnej cesty cez sieť. Z tohto dôvodu by sa hra zdala strašne pomalá, takže takmer okamžite po zavedení multiplayeru do hry bol zavedený mechanizmus na skrytie oneskorení. Skrytie oneskorenia simuluje vstup hráča bez zohľadnenia akcií ostatných hráčov a rozhodnutí servera.

Megapack: Ako Factorio vyriešilo problém s hrou pre 200 hráčov
Factorio má herný stav Stav hry je kompletný stav karty, hráča, entít a všetkého ostatného. Je deterministicky simulovaný vo všetkých klientoch na základe akcií prijatých zo servera. Stav hry je posvätný a ak sa niekedy začne líšiť od servera alebo akéhokoľvek iného klienta, dôjde k desynchronizácii.

Mimo Stav hry máme stav meškania Stav latencie. Obsahuje malú podmnožinu základného stavu. Stav latencie nie je posvätný a jednoducho predstavuje obraz toho, ako bude stav hry vyzerať v budúcnosti na základe vstupov hráčov Vstupné akcie.

Na tento účel ukladáme kópiu vytvorenej Vstupné akcie vo fronte oneskorenia.

Megapack: Ako Factorio vyriešilo problém s hrou pre 200 hráčov
To znamená, že na konci procesu na strane klienta vyzerá obrázok asi takto:

  1. Použiť Vstupné akcie všetkým hráčom Stav hry spôsob, akým boli tieto vstupné akcie prijaté zo servera.
  2. Odstránime všetko z frontu oneskorenia Vstupné akcie, na ktoré už bolo podľa servera prihlásené Stav hry.
  3. remove Stav latencie a resetujte ho tak, aby vyzeral úplne rovnako ako Stav hry.
  4. Aplikujeme všetky akcie z frontu oneskorenia na Stav latencie.
  5. Na základe údajov Stav hry и Stav latencie Vykreslíme hru hráčovi.

Toto všetko sa opakuje v každom takte.

Príliš zložité? Neuvoľňujte sa, to nie je všetko. Na kompenzáciu nespoľahlivých internetových pripojení sme vytvorili dva mechanizmy:

  • Zmeškané tikety: keď o tom server rozhodne Vstupné akcie bude vykonaný v takte hry, potom ak nedostal Vstupné akcie niektorého hráča (napríklad z dôvodu zvýšeného oneskorenia), nebude čakať, ale bude informovať tohto klienta „Nebral som do úvahy vaše Vstupné akcie, skúsim ich pridať v ďalšom takte.“ Deje sa tak preto, aby sa kvôli problémom s pripojením (alebo počítačom) jedného hráča aktualizácia mapy nespomalila všetkým ostatným. Stojí za zmienku, že Vstupné akcie nie sú ignorované, ale jednoducho odložené.
  • Úplná spiatočná latencia: Server sa snaží uhádnuť, aká je okružná latencia medzi klientom a serverom pre každého klienta. Každých 5 sekúnd vyjednáva s klientom v prípade potreby novú latenciu (na základe toho, ako sa spojenie správalo v minulosti) a podľa toho zvyšuje alebo znižuje spiatočnú latenciu.

Tieto mechanizmy sú samy osebe celkom jednoduché, ale keď sa používajú spolu (čo sa často stáva pri problémoch s pripojením), logika kódu sa stáva ťažko zvládnuteľnou as množstvom hraničných prípadov. Okrem toho, keď tieto mechanizmy vstúpia do hry, server a front oneskorenia musia správne implementovať špeciálne Vstupná akcia oprávnený StopMovementInTheNextTick. Vďaka tomu, ak sa vyskytnú problémy so spojením, postava sa sama nerozbehne (napríklad pred vlak).

Teraz vám musíme vysvetliť, ako funguje výber entity. Jeden z prenášaných typov Vstupná akcia je zmena stavu výberu entity. Každému povie, nad ktorou entitou sa hráč vznáša. Ako si viete predstaviť, toto je jedna z najbežnejších vstupných akcií odosielaných klientmi, takže aby sme ušetrili šírku pásma, optimalizovali sme ho tak, aby zaberal čo najmenej miesta. Funguje to tak, že keď je každá entita vybraná, namiesto ukladania absolútnych, vysoko presných súradníc mapy, hra ukladá relatívny posun s nízkou presnosťou od predchádzajúceho výberu. Funguje to dobre, pretože výber myšou má tendenciu byť veľmi blízko predchádzajúcemu výberu. To vyvoláva dve dôležité požiadavky: Vstupné akcie Nikdy by sa nemali preskakovať a musia byť vyplnené v správnom poradí. Tieto požiadavky sú splnené pre Stav hry. Ale od úlohy Stav latencie v „vyzerajú dosť dobre“ pre hráča, nie sú spokojní v stave oneskorenia. Stav latencie neberie do úvahy veľa okrajových prípadov, spojené s preskakovaním hodinových cyklov a zmenou spiatočných prenosových oneskorení.

Už tušíte, kam to smeruje. Konečne začíname vidieť dôvody problému s megapackom. Základom problému je, že logika výberu entity sa spolieha na Stav latenciea tento stav nie vždy obsahuje správne informácie. Preto sa megapaket vygeneruje niečo také:

  1. Prehrávač má problémy s pripojením.
  2. Do hry vstupujú mechanizmy na preskakovanie hodinových cyklov a reguláciu oneskorenia spiatočného prenosu.
  3. Fronta stavu oneskorenia nezohľadňuje tieto mechanizmy. To spôsobí, že niektoré akcie budú predčasne odstránené alebo vykonané v nesprávnom poradí, čo má za následok nesprávne Stav latencie.
  4. Prehrávač má problém s pripojením a aby dobehol server, simuluje až 400 cyklov.
  5. Pri každom zaškrtnutí sa vygeneruje nová akcia, ktorá zmení výber entity, a pripraví sa na odoslanie na server.
  6. Klient odošle megadávku 400+ zmien výberu entít na server (a pri iných akciách: stavy streľby, stavy chôdze atď. tiež trpeli týmto problémom).
  7. Server dostane 400 vstupných akcií. Keďže nie je dovolené preskočiť žiadne vstupné akcie, prikáže všetkým klientom vykonať tieto akcie a odošle ich cez sieť.

Iróniou je, že mechanizmus navrhnutý na šetrenie šírky pásma nakoniec vytvoril obrovské sieťové pakety.

Tento problém sme vyriešili opravou všetkých okrajových prípadov podpory frontu aktualizácií a nevybavených žiadostí. Aj keď to zabralo dosť času, v konečnom dôsledku sa oplatilo dať to správne, ako sa spoliehať na rýchle hacky.

Zdroj: hab.com

Pridať komentár