Megapack: Hoe Factorio die 200-speler-multispelerprobleem opgelos het

Megapack: Hoe Factorio die 200-speler-multispelerprobleem opgelos het
In Mei vanjaar het ek as speler deelgeneem aan KatherineOfSky MMO-geleenthede. Ek het opgemerk dat wanneer die aantal spelers 'n sekere getal bereik, elke paar minute sommige van hulle "afval". Gelukkig vir jou (maar nie vir my nie), was ek een van daardie spelers elke keerselfs met 'n goeie verbinding. Ek het dit as 'n persoonlike uitdaging aanvaar en begin soek na die oorsake van die probleem. Na drie weke van ontfouting, toetsing en regmaak, is die fout uiteindelik reggestel, maar die reis was nie so maklik nie.

Probleme in multiplayer-speletjies is baie moeilik om op te spoor. Hulle kom gewoonlik voor onder baie spesifieke netwerkparameters en onder baie spesifieke speltoestande (in hierdie geval, meer as 200 spelers). En selfs wanneer 'n probleem gereproduseer kan word, kan dit nie behoorlik ontfout word nie, want die invoeging van breekpunte stop die speletjie, mors tydtellers, en veroorsaak gewoonlik dat die verbinding uittel weens 'n uitteltyd. Maar te danke aan deursettingsvermoë en 'n wonderlike hulpmiddel genoem lomp Ek kon agterkom wat aangaan.

Kortom, as gevolg van 'n fout en onvolledige implementering van die vertragingstaatsimulasie, het die kliënt hom soms in 'n situasie bevind waar dit 'n netwerkpakkie in een kloksiklus moes stuur, bestaande uit speler-invoeraksies vir die selektering van ongeveer 400 speletjie-entiteite ( ons noem dit 'n "megapakkie"). Daarna moet die bediener nie net al hierdie invoeraksies korrek ontvang nie, maar dit ook aan alle ander kliënte stuur. As jy 200 kliënte het, word dit vinnig 'n probleem. Die kanaal na die bediener raak vinnig verstop, wat lei tot pakkieverlies en 'n kaskade van herversoekte pakkies. Die uitstel van invoeraksies veroorsaak dan dat meer kliënte megapakkies begin stuur, en hul stortvloed word selfs sterker. Suksesvolle kliënte kry dit reg om te herstel, al die res val af.

Megapack: Hoe Factorio die 200-speler-multispelerprobleem opgelos het
Die probleem was redelik fundamenteel, en dit het my 2 weke geneem om dit reg te stel. Dit is redelik tegnies, so ek sal die sappige tegniese besonderhede hieronder verduidelik. Maar eers moet jy weet dat sedert weergawe 0.17.54, wat op 4 Junie vrygestel is, in die lig van tydelike verbindingsprobleme, multiplayer meer stabiel geword het, en vertraging wegkruip is baie minder karig (minder rem en teleporteer). Ek het ook die manier waarop gevegsvertragings versteek word verander, en hopelik sal dit hulle 'n bietjie gladder maak.

Multiplayer Mega Pack - Tegniese Besonderhede

Om dit eenvoudig te stel, multispeler in 'n speletjie werk soos volg: alle kliënte simuleer die toestand van die speletjie deur slegs spelerinsette te ontvang en te stuur (genoem "invoeraksies" Invoeraksies). Die hooftaak van die bediener is om oor te dra Invoeraksies en om te verseker dat alle kliënte dieselfde aksies in dieselfde siklus uitvoer. Jy kan meer hieroor lees in die pos. FFF-149.

Aangesien die bediener besluite moet neem oor watter aksies om te neem, beweeg die speler se aksies langs die volgende pad: speleraksie -> speletjiekliënt -> netwerk -> bediener -> netwerk -> speletjiekliënt. Dit beteken dat elke aksie van die speler slegs uitgevoer word nadat dit 'n heen-en-weer-pad deur die netwerk gemaak het. As gevolg hiervan sou die spel verskriklik stadig gelyk het, so amper onmiddellik na die verskyning van multispeler in die spel, is 'n meganisme ingestel om vertragings weg te steek. Latency-verberging simuleer spelerinvoer sonder om die optrede van ander spelers en bedienerbesluitneming in ag te neem.

Megapack: Hoe Factorio die 200-speler-multispelerprobleem opgelos het
Factorio het 'n spelstaat spelstaat is die volledige toestand van die kaart, speler, entiteite en alles anders. Dit word deterministies gesimuleer in alle kliënte gebaseer op aksies wat vanaf die bediener ontvang is. Die speltoestand is heilig, en as dit ooit van die bediener of enige ander kliënt begin verskil, vind desinchronisasie plaas.

Maar spelstaat ons het 'n toestand van vertragings Vertragingstoestand. Dit bevat 'n klein subset van die hoofstaat. Vertragingstoestand is nie heilig nie en verteenwoordig net 'n prentjie van hoe die toestand van die spel in die toekoms sal lyk, gebaseer op die insette van die speler Invoeraksies.

Om dit te doen, hou ons 'n kopie van die gegenereerde Invoeraksies in die vertragingsry.

Megapack: Hoe Factorio die 200-speler-multispelerprobleem opgelos het
Dit wil sê, aan die einde van die proses aan die kliëntkant, lyk die prentjie so iets:

  1. Doen aansoek Invoeraksies alle spelers aan spelstaat die manier waarop hierdie invoeraksies vanaf die bediener ontvang is.
  2. Verwyder alles uit die vertragingsry Invoeraksies, waarop, volgens die bediener, reeds toegepas is spelstaat.
  3. Verwyder Vertragingstoestand en stel dit terug sodat dit presies dieselfde lyk as spelstaat.
  4. Pas alle aksies vanaf die vertragingsry toe op Vertragingstoestand.
  5. Gebaseer op data spelstaat и Vertragingstoestand gee die spel aan die speler.

Dit alles word in elke mate herhaal.

Te moeilik? Moenie ontspan nie, dis nie al nie. Om te vergoed vir onbetroubare internetverbindings, het ons twee meganismes geskep:

  • Oorgeslaan regmerkies: wanneer die bediener dit besluit Invoeraksies sal uitgevoer word in die takt van die spel, dan as hy nie ontvang het nie Invoeraksies 'n speler (byvoorbeeld as gevolg van 'n groter vertraging), sal hy nie wag nie, maar sal hierdie kliënt inlig "Ek het nie jou Invoeraksies, Ek sal probeer om hulle in die volgende balk by te voeg. Dit word gedoen sodat as gevolg van probleme met die verbinding (of met die rekenaar) van een speler, die kaartopdatering nie vir almal vertraag nie. Dit is die moeite werd om daarop te let Invoeraksies word nie geïgnoreer nie, maar bloot uitgestel.
  • Volle retoer-latensie: Die bediener probeer om te raai wat die retoer-vertraging tussen kliënt en bediener vir elke kliënt is. Elke 5 sekondes onderhandel dit 'n nuwe vertraging met die kliënt soos nodig (afhangende van hoe die verbinding in die verlede opgetree het), en verhoog of verminder die retoervertraging dienooreenkomstig.

Op sigself is hierdie meganismes redelik eenvoudig, maar wanneer hulle saam gebruik word (wat dikwels met verbindingsprobleme gebeur), word die kodelogika moeilik om te bestuur en met baie randgevalle. Daarbenewens, wanneer hierdie meganismes in die spel kom, moet die bediener en die vertragingsry 'n spesiale korrek implementeer Invoeraksie genoem StopMovementInTheNextTick. Danksy hierdie, in geval van verbindingsprobleme, sal die karakter nie op sy eie hardloop nie (byvoorbeeld onder 'n trein).

Nou moet ek vir jou verduidelik hoe entiteitseleksie werk. Een van die geslaagde tipes Invoeraksie is 'n verandering in die seleksietoestand van 'n entiteit. Dit vertel almal oor watter entiteit die speler met die muis gesweef het. Soos u kan sien, is dit een van die mees gereelde invoeraksies wat deur kliënte gestuur word, so om bandwydte te bespaar, het ons dit geoptimaliseer sodat dit so min as moontlik spasie opneem. Dit word so geïmplementeer: wanneer elke entiteit gekies word, in plaas daarvan om absolute, hoë-presisie kaartkoördinate te stoor, stoor die speletjie 'n lae-presisie relatiewe offset vanaf die vorige keuse. Dit werk goed omdat die muiskeuse gewoonlik baie naby aan die vorige seleksie gebeur. Dit gee aanleiding tot twee belangrike vereistes: Invoeraksies moet nooit oorgeslaan word nie en moet in die regte volgorde gedoen word. Hierdie vereistes word nagekom vir spelstaat. Maar sedert die taak latensie toestand in "lyk goed genoeg" vir die speler, is hulle nie tevrede in die vertraging toestand. Vertragingstoestand in ag neem nie baie grensgevallegeassosieer met die oorslaan van horlosies en die verandering van retoer-transmissievertragings.

Jy kan reeds raai waarheen dit gaan. Uiteindelik begin ons die oorsake van die megapakketprobleem sien. Die wortel van die probleem is dat die entiteitseleksie-logika staatmaak op Vertragingstoestand, en hierdie toestand bevat nie altyd die korrekte inligting nie. Die megapakkie word dus so gegenereer:

  1. Die speler ondervind verbindingsprobleme.
  2. Die meganismes vir die oorslaan van siklusse en die regulering van die heen-en-weer transmissievertraging kom ter sprake.
  3. Die vertragingstaat-waglys maak nie rekening met hierdie meganismes nie. Dit veroorsaak dat sommige aksies voortydig verwyder word of in die verkeerde volgorde uitgevoer word, wat lei tot 'n verkeerde Vertragingstoestand.
  4. Die speler het geen verbindingsprobleem nie en simuleer tot 400 siklusse om die bediener in te haal.
  5. In elke siklus word 'n nuwe aksie gegenereer en voorberei om na die bediener gestuur te word, wat die entiteitseleksie verander.
  6. Die kliënt stuur 'n megapakkie van 400+ entiteitseleksieveranderinge na die bediener (en met ander aksies: vuurtoestand, looptoestand, ens. het ook onder hierdie probleem gely).
  7. Die bediener ontvang 400 invoeraksies. Aangesien dit nie toegelaat word om 'n enkele invoeraksie oor te slaan nie, gee dit alle kliënte opdrag om hierdie aksies uit te voer en stuur dit oor die netwerk.

Die ironie is dat 'n meganisme wat ontwerp is om bandwydte te bespaar, groot netwerkpakkies tot gevolg gehad het.

Ons het hierdie probleem opgelos deur alle opdateringsrandgevalle reg te stel en tou-ondersteuning te vertraag. Alhoewel dit 'n geruime tyd geneem het, was dit die moeite werd om dit op die ou end reg te kry eerder as om op vinnige hacks staat te maak.

Bron: will.com

Voeg 'n opmerking