Megapack: Kako je Factorio rešil težavo z več igralci z 200 igralci

Megapack: Kako je Factorio rešil težavo z več igralci z 200 igralci
Maja letos sem se kot igralec udeležil KatherineOfSky MMO dogodki. Opazil sem, da ko število igralcev doseže določeno številko, jih vsakih nekaj minut "odpade". Na vašo srečo (vendar ne zame) sem bil eden izmed teh igralcev vsakičtudi z dobro povezavo. Vzel sem to kot osebni izziv in začel iskati vzroke za težavo. Po treh tednih odpravljanja napak, testiranja in popravljanja je napaka končno odpravljena, vendar pot ni bila tako lahka.

Težave v igrah za več igralcev je zelo težko izslediti. Običajno se pojavijo pri zelo specifičnih omrežnih parametrih in pri zelo specifičnih stanjih igre (v tem primeru več kot 200 igralcev). In tudi ko je težavo mogoče reproducirati, je ni mogoče pravilno odpraviti, ker vstavljanje prekinitvenih točk ustavi igro, pokvari časovnike in običajno povzroči, da se povezava prekine zaradi časovne omejitve. Toda zahvaljujoč vztrajnosti in čudovitemu orodju, imenovanemu neroden Lahko sem ugotovil, kaj se dogaja.

Skratka, zaradi hrošča in nepopolne implementacije simulacije stanja zakasnitve se je odjemalec včasih znašel v situaciji, ko je moral v enem taktu poslati omrežni paket, sestavljen iz dejanj igralca, ki vnesejo dejanja za izbiro približno 400 entitet igre ( imenujemo ga "megapaket"). Po tem mora strežnik ne le pravilno prejeti vseh teh vhodnih dejanj, ampak jih mora tudi poslati vsem drugim odjemalcem. Če imaš 200 strank, to hitro postane problem. Kanal do strežnika se hitro zamaši, kar povzroči izgubljene pakete in kaskado ponovno zahtevanih paketov. Odlaganje vnosnih dejanj nato povzroči, da začne več strank pošiljati megapakete, njihov plaz pa postane še močnejši. Uspešne stranke uspejo ozdraveti, vse ostale odpadejo.

Megapack: Kako je Factorio rešil težavo z več igralci z 200 igralci
Težava je bila precej temeljna in potreboval sem 2 tedna, da sem jo odpravil. Je precej tehničen, zato bom spodaj razložil sočne tehnične podrobnosti. Najprej pa morate vedeti, da je od različice 0.17.54, izdane 4. junija, ob začasnih težavah s povezavo večigralstvo postalo stabilnejše, skrivanje zakasnitve pa veliko manj hrošča (manj zaviranja in teleportiranja). Prav tako sem spremenil način skrivanja bojnih zamud in upam, da bodo zaradi tega nekoliko bolj gladki.

Mega paket za več igralcev – tehnične podrobnosti

Preprosto povedano, igra za več igralcev v igri deluje takole: vsi odjemalci simulirajo stanje igre tako, da prejemajo in pošiljajo samo vnose igralcev (imenovane "vnosna dejanja" Vnosna dejanja). Glavna naloga strežnika je prenos Vnosna dejanja in zagotavljanje, da vse stranke izvajajo enaka dejanja v istem ciklu. Več o tem si lahko preberete v objavi. FFF-149.

Ker se mora strežnik odločiti, katera dejanja bo izvedel, se dejanja igralca premikajo po naslednji poti: dejanje igralca -> odjemalec igre -> omrežje -> strežnik -> omrežje -> odjemalec igre. To pomeni, da se vsako dejanje igralca izvede šele potem, ko je opravil krožno pot skozi omrežje. Zaradi tega bi se igra zdela strašno počasna, zato je bil skoraj takoj po pojavu večigralstva v igri uveden mehanizem za skrivanje zamud. Skrivanje zakasnitve simulira vnos igralca brez upoštevanja dejanj drugih igralcev in odločanja strežnika.

Megapack: Kako je Factorio rešil težavo z več igralci z 200 igralci
Factorio ima stanje igre stanje igre je celotno stanje zemljevida, igralca, entitet in vsega drugega. To je deterministično simulirano v vseh odjemalcih na podlagi dejanj, prejetih s strežnika. Stanje igre je sveto in če se kdaj začne razlikovati od strežnika ali katerega koli drugega odjemalca, pride do desinhronizacije.

Razen stanje igre imamo stanje zamud Stanje zakasnitve. Vsebuje majhno podmnožico glavnega stanja. Stanje zakasnitve ni sveto in samo predstavlja sliko, kako bo stanje igre videti v prihodnosti na podlagi vnosov igralca Vnosna dejanja.

Da bi to naredili, hranimo kopijo ustvarjenega Vnosna dejanja v čakalni vrsti za zamudo.

Megapack: Kako je Factorio rešil težavo z več igralci z 200 igralci
To pomeni, da je na koncu procesa na strani odjemalca slika videti nekako takole:

  1. Prijavite se Vnosna dejanja vsi igralci do stanje igre način, kako so bila ta vnosna dejanja sprejeta s strežnika.
  2. Odstranite vse iz čakalne vrste zakasnitve Vnosna dejanja, ki sta po strežniku že vložena v stanje igre.
  3. Izbriši Stanje zakasnitve in ga ponastavite tako, da bo videti popolnoma enako kot stanje igre.
  4. Uporabi vsa dejanja iz čakalne vrste zakasnitve na Stanje zakasnitve.
  5. Na podlagi podatkov stanje igre и Stanje zakasnitve upodobi igro igralcu.

Vse to se ponavlja v vsakem taktu.

Pretežko? Ne sprostite se, to še ni vse. Da bi nadomestili nezanesljive internetne povezave, smo ustvarili dva mehanizma:

  • Preskočene kljukice: ko se strežnik tako odloči Vnosna dejanja bo izveden v taktu igre, potem če ni prejel Vnosna dejanja nekega igralca (na primer zaradi povečane zamude), ne bo čakal, ampak bo to stranko obvestil »Nisem upošteval vašega Vnosna dejanja, jih bom poskusil dodati v naslednji vrstici. To se naredi tako, da se zaradi težav s povezavo (ali z računalnikom) enega igralca posodobitev zemljevida ne upočasni za vse ostale. Omeniti velja, da Vnosna dejanja niso prezrte, ampak preprosto odložene.
  • Polna povratna zakasnitev: Strežnik poskuša uganiti, kakšna je povratna zakasnitev med odjemalcem in strežnikom za vsakega odjemalca. Vsakih 5 sekund se po potrebi z odjemalcem dogovori za novo zakasnitev (odvisno od tega, kako se je povezava obnašala v preteklosti) in ustrezno poveča ali zmanjša zakasnitev povratnega potovanja.

Ti mehanizmi so sami po sebi precej preprosti, a ko se uporabljata skupaj (kar se pogosto zgodi pri težavah s povezavo), postane logika kode težko obvladljiva in z veliko robnimi primeri. Poleg tega morata strežnik in čakalna vrsta zakasnitve, ko pridejo v poštev ti mehanizmi, pravilno implementirati posebno Vnosno dejanje z naslovom StopMovementInTheNextTick. Zahvaljujoč temu v primeru težav s povezavo lik ne bo tekel sam (na primer pod vlakom).

Zdaj vam moram razložiti, kako deluje izbira entitete. Ena od opravljenih vrst Vnosno dejanje je sprememba izbirnega stanja entitete. Vsem pove, nad katero entiteto se je igralec pomaknil z miško. Kot lahko vidite, je to eno najpogostejših vnosnih dejanj, ki jih pošiljajo odjemalci, zato smo ga optimizirali, da prihranimo pasovno širino, tako da zavzame čim manj prostora. To je implementirano takole: ko je izbrana vsaka entiteta, igra namesto shranjevanja absolutnih, visoko natančnih koordinat zemljevida shrani nizko natančen relativni odmik od prejšnje izbire. To dobro deluje, ker je izbira z miško običajno zelo blizu prejšnje izbire. To povzroča dve pomembni zahtevi: Vnosna dejanja se ne sme nikoli preskočiti in mora biti opravljeno v pravilnem vrstnem redu. Te zahteve so izpolnjene za stanje igre. Toda od naloge stanje latence v "izgledati dovolj dobro" za igralca, niso zadovoljni v stanju zakasnitve. Stanje zakasnitve ne upošteva veliko mejnih primerovpovezana s preskakovanjem ur in spreminjanjem zakasnitev povratnega prenosa.

Kam to pelje, lahko že ugibate. Končno začenjamo opažati vzroke za problem megapaketov. Koren težave je v tem, da se logika izbire subjekta opira na Stanje zakasnitvein to stanje ne vsebuje vedno pravilnih informacij. Torej je megapaket ustvarjen takole:

  1. Predvajalnik ima težave s povezavo.
  2. V poštev pridejo mehanizmi za preskakovanje ciklov in uravnavanje zakasnitve povratnega prenosa.
  3. Čakalna vrsta stanja zakasnitve ne upošteva teh mehanizmov. To povzroči, da so nekatera dejanja predčasno odstranjena ali se izvajajo v napačnem vrstnem redu, kar ima za posledico napačno Stanje zakasnitve.
  4. Predvajalnik nima težav s povezavo in simulira do 400 ciklov, da dohiti strežnik.
  5. V vsakem ciklu se ustvari in pripravi novo dejanje za pošiljanje strežniku, pri čemer se spremeni izbor entitete.
  6. Odjemalec strežniku pošlje megapaket s 400+ spremembami izbire entitet (in z drugimi dejanji: stanje sprožitve, stanje hoje itd. je prav tako utrpelo to težavo).
  7. Strežnik prejme 400 vhodnih dejanj. Ker ni dovoljeno preskočiti niti enega vnosnega dejanja, naroči vsem odjemalcem, naj izvedejo ta dejanja, in jih pošlje po omrežju.

Ironija je, da je mehanizem, zasnovan za ohranjanje pasovne širine, povzročil ogromne omrežne pakete.

To težavo smo rešili tako, da smo popravili vse robne primere posodobitev in podporo za zakasnitev čakalne vrste. Čeprav je trajalo kar nekaj časa, se je na koncu splačalo narediti pravilno, namesto da bi se zanašali na hitre vdore.

Vir: www.habr.com

Dodaj komentar