Megapack: kuidas Factorio lahendas 200 mängijaga mitme mängija probleemi

Megapack: kuidas Factorio lahendas 200 mängijaga mitme mängija probleemi
Selle aasta mais osalesin mängijana MMO üritused KatherineOfSky. Märkasin, et kui mängijate arv jõuab teatud arvuni, siis iga paari minuti tagant mõni neist “kukkub ära”. Sinu õnneks (aga mitte minu jaoks) olin üks neist mängijatest, kes katkestas ühenduse iga kord, isegi hea ühenduse korral. Võtsin seda kui isiklikku väljakutset ja hakkasin otsima probleemi põhjuseid. Pärast kolmenädalast silumist, testimist ja parandamist sai viga lõpuks parandatud, kuid teekond polnud sugugi nii lihtne.

Mitme mängijaga mängudega seotud probleeme on väga raske leida. Tavaliselt esinevad need väga spetsiifiliste võrguparameetrite ja väga spetsiifiliste mängutingimuste korral (antud juhul rohkem kui 200 mängijaga). Ja isegi kui probleemi saab taasesitada, ei saa seda korralikult siluda, sest katkestuspunktide sisestamine peatab mängu, ajab taimerid segadusse ja põhjustab tavaliselt ühenduse ajalõpu. Aga tänu püsivusele ja imelisele tööriistale nimega kohmakas Mul õnnestus välja selgitada, mis toimub.

Lühidalt võib öelda, et vea ja latentsusoleku simulatsiooni mittetäieliku juurutamise tõttu satub klient mõnikord olukorda, kus ta pidi saatma võrgupaketi, mis koosneb mängija valikutoimingutest umbes 400 mänguolemi ühe taktitsükli jooksul (meie nimetage seda "megapaketiks"). Seejärel ei pea server mitte ainult kõiki neid sisestustoiminguid õigesti vastu võtma, vaid ka saatma need kõigile teistele klientidele. Kui teil on 200 klienti, muutub see kiiresti probleemiks. Link serveriga ummistub kiiresti, mis toob kaasa pakettide kadumise ja uuesti taotletud pakettide kaskaadi. Sisendtoimingu edasilükkamine paneb veelgi rohkem kliente saatma megapakette, mistõttu laviin muutub veelgi suuremaks. Õnnelikel klientidel õnnestub terveks saada, kõik teised kukuvad maha.

Megapack: kuidas Factorio lahendas 200 mängijaga mitme mängija probleemi
Probleem oli üsna põhimõtteline ja mul kulus selle parandamiseks 2 nädalat. See on üsna tehniline, nii et ma selgitan allpool mahlaseid tehnilisi üksikasju. Esmalt aga pead teadma, et alates 0.17.54. juunil välja antud versioonist 4 on ajutiste ühendusprobleemide taustal mitmikmäng muutunud stabiilsemaks ning viivituste peitmine on muutunud palju vähem lollakaks (vähem aeglustumist ja teleportimist). Olen muutnud ka võitlusviivituse peitmise viisi ja loodan, et see muudab selle pisut sujuvamaks.

Mitme mängijaga megapakett – tehnilised üksikasjad

Lihtsamalt öeldes töötab mitme mängijaga mäng mängus järgmiselt: kõik kliendid simuleerivad mängu olekut, võttes vastu ja saadades ainult mängija sisendit (nn sisestustoimingud, Sisendtoimingud). Serveri põhiülesanne on ülekandmine Sisendtoimingud ja kontrollida, et kõik kliendid sooritaksid sama kellatsükli jooksul samu toiminguid. Lähemalt saate selle kohta lugeda postitusest FFF-149.

Kuna server peab tegema otsuseid selle kohta, milliseid toiminguid teha, liiguvad mängija tegevused ligikaudu järgmiselt: mängija tegevus -> mänguklient -> võrk -> server -> võrk -> mänguklient. See tähendab, et iga mängija tegevus sooritatakse alles pärast võrgus ringkäiku. Selle tõttu tundus mäng kohutavalt aeglane, nii et peaaegu kohe pärast mitmikmängu kasutuselevõttu võeti mängu viivituste peitmiseks kasutusele mehhanism. Viivituse peitmine simuleerib mängija sisendit, võtmata arvesse teiste mängijate tegevust ja serveri otsuseid.

Megapack: kuidas Factorio lahendas 200 mängijaga mitme mängija probleemi
Factoriol on mängu olek Mängu olek on kaardi, mängija, üksuste ja kõige muu täielik olek. Seda simuleeritakse deterministlikult kõigis klientides serverist saadud toimingute põhjal. Mängu olek on püha ja kui see hakkab kunagi serverist või mõnest muust kliendist erinema, toimub desünkroonimine.

Kuid Mängu olek meil on viivitused Latentsusolek. See sisaldab väikest põhioleku alamhulka. Latentsusolek ei ole püha ja kujutab mängija sisendite põhjal lihtsalt pilti sellest, kuidas mängu olek tulevikus välja näeb Sisendtoimingud.

Selleks salvestame loodud koopia Sisendtoimingud viivitusjärjekorras.

Megapack: kuidas Factorio lahendas 200 mängijaga mitme mängija probleemi
See tähendab, et protsessi lõpus näeb kliendi poolel pilt välja umbes selline:

  1. Rakenda Sisendtoimingud kõik mängijad Mängu olek kuidas need sisestustoimingud serverist vastu võeti.
  2. Eemaldame kõik viivitusjärjekorrast Sisendtoimingud, millele on serveri andmetel juba rakendatud Mängu olek.
  3. Kustuta Latentsusolek ja lähtestage see nii, et see näeks välja täpselt samasugune nagu Mängu olek.
  4. Rakendame kõik toimingud viivitusjärjekorrast kuni Latentsusolek.
  5. Andmete põhjal Mängu olek и Latentsusolek Anname mängu mängijale.

Kõik see kordub igas mõõdus.

Liiga raske? Ärge lõdvestage, see pole veel kõik. Ebausaldusväärse Interneti-ühenduse kompenseerimiseks oleme loonud kaks mehhanismi:

  • Vastamata märgid: kui server nii otsustab Sisendtoimingud hukatakse mängu taktis, siis kui ta ei saanud Sisendtoimingud mõni mängija (näiteks suurenenud viivituse tõttu), ta ei oota, vaid teatab sellele kliendile: "Ma ei võtnud teie Sisendtoimingud, proovin need järgmisel ribal lisada. Seda tehakse selleks, et ühe mängija ühenduse (või arvuti) probleemide tõttu ei aeglustuks kaardiuuendus kõigil teistel. Väärib märkimist, et Sisendtoimingud ei jäeta tähelepanuta, vaid jäetakse lihtsalt kõrvale.
  • Täielik edasi-tagasi latentsusaeg: server proovib arvata, milline on iga kliendi edasi-tagasi latentsusaeg kliendi ja serveri vahel. Iga 5 sekundi järel lepib see vajadusel kliendiga läbi uue latentsusaja (lähtuvalt sellest, kuidas ühendus on varem käitunud) ja suurendab või vähendab vastavalt edasi-tagasi reisi latentsust.

Iseenesest on need mehhanismid üsna lihtsad, kuid kui neid kasutatakse koos (mis juhtub sageli ühenduse probleemidega), muutub koodi loogika raskesti hallatavaks ja paljude servajuhtumitega. Lisaks peavad nende mehhanismide käivitamisel server ja viivitusjärjekord spetsiaalset õigesti rakendama Sisendtoiming kutsutud StopMovementInTheNextTick. Tänu sellele, kui ühendusega on probleeme, ei jookse tegelane omapäi (näiteks rongi ette).

Nüüd peame teile selgitama, kuidas olemi valik toimib. Üks edastatavatest tüüpidest Sisendtoiming on olemi valiku oleku muutus. See annab kõigile teada, millise üksuse kohal mängija hõljub. Nagu võite ette kujutada, on see üks levinumaid klientide saadetud sisestustoiminguid, nii et ribalaiuse säästmiseks oleme selle optimeerinud nii, et see võtaks võimalikult vähe ruumi. See toimib nii, et iga olemi valimisel salvestab mäng absoluutsete suure täpsusega kaardikoordinaatide salvestamise asemel madala täpsusega suhtelise nihke eelmisest valikust. See toimib hästi, kuna hiire valikud kipuvad olema eelmisele valikule väga lähedased. See tõstatab kaks olulist nõuet: Sisendtoimingud Neid ei tohi kunagi vahele jätta ja need tuleb täita õiges järjekorras. Need nõuded on täidetud Mängu olek. Aga kuna ülesanne Latentsusseisund Mängija jaoks "piisavalt hea väljanägemisega" ei ole nad viivitusseisundis rahul. Latentsusolek ei arvesta palju äärejuhtumeid, mis on seotud kellatsüklite vahelejätmisega ja edasi-tagasi edastusviivituste muutmisega.

Võite juba arvata, kuhu see läheb. Lõpuks hakkame nägema megapaki probleemi põhjuseid. Probleemi juur on selles, et olemi valimise loogika toetub Latentsusolek, ja see olek ei sisalda alati õiget teavet. Seetõttu genereeritakse megapakett midagi sellist:

  1. Mängijal on ühendusega probleeme.
  2. Mängu tulevad mehhanismid kellatsüklite vahelejätmiseks ja edasi-tagasi edastamise viivituse reguleerimiseks.
  3. Viivituse oleku järjekord ei võta neid mehhanisme arvesse. See põhjustab mõne toimingu enneaegse eemaldamise või vales järjekorras sooritamise, mille tulemuseks on vale Latentsusolek.
  4. Mängijal on ühenduse probleem ja serverile järele jõudmiseks simuleerib ta kuni 400 tsüklit.
  5. Iga linnukese juures genereeritakse uus toiming, mis muudab olemi valikut ja valmistatakse ette serverisse saatmiseks.
  6. Klient saadab serverisse megapartii 400+ olemivaliku muudatust (ja muude toimingutega: selle probleemi all kannatasid ka pildistamisolekud, kõndimisolekud jne).
  7. Server võtab vastu 400 sisendtoimingut. Kuna sisestustoiminguid ei ole lubatud vahele jätta, annab see kõigile klientidele korralduse need toimingud sooritada ja saadab need üle võrgu.

Iroonia on see, et ribalaiuse säästmiseks loodud mehhanism lõi lõpuks tohutuid võrgupakette.

Lahendasime selle probleemi, parandades kõik värskenduste ja mahajäämuse järjekorra toe servajuhtumid. Kuigi aega kulus üsna vähe, tasus lõpuks pigem korda saada kui kiiretele häkkidele lootma jääda.

Allikas: www.habr.com

Lisa kommentaar