Megapack: com Factorio va resoldre el problema del multijugador de 200 jugadors

Megapack: com Factorio va resoldre el problema del multijugador de 200 jugadors
El maig d'aquest any vaig participar com a jugador Esdeveniments MMO de KatherineOfSky. Em vaig adonar que quan el nombre de jugadors arriba a un nombre determinat, cada pocs minuts alguns d'ells "cauen". Per sort per a vosaltres (però no per a mi), vaig ser un d'aquests jugadors cada vegadafins i tot amb una bona connexió. Ho vaig prendre com un repte personal i vaig començar a buscar les causes del problema. Després de tres setmanes de depuració, prova i correcció, finalment s'ha solucionat l'error, però el viatge no ha estat tan fàcil.

Els problemes als jocs multijugador són molt difícils de localitzar. Normalment es produeixen sota paràmetres de xarxa molt específics i sota estats de joc molt específics (en aquest cas, més de 200 jugadors). I fins i tot quan es pot reproduir un problema, no es pot depurar correctament perquè la inserció de punts d'interrupció atura el joc, fa malbé els temporitzadors i normalment fa que la connexió s'esgoti a causa d'un temps d'espera. Però gràcies a la perseverança i una meravellosa eina anomenada maldestre Vaig poder esbrinar què estava passant.

En resum, a causa d'un error i d'una implementació incompleta de la simulació d'estat de retard, el client de vegades es trobava en una situació en què havia d'enviar un paquet de xarxa en un cicle de rellotge, que consistia en accions d'entrada del jugador per seleccionar aproximadament 400 entitats del joc ( l'anomenem "megapaquet"). Després d'això, el servidor no només ha de rebre correctament totes aquestes accions d'entrada, sinó que també les ha d'enviar a la resta de clients. Si teniu 200 clients, això es converteix ràpidament en un problema. El canal al servidor s'obstrueix ràpidament, provocant la pèrdua de paquets i una cascada de paquets sol·licitats de nou. L'ajornament de les accions d'entrada fa que més clients comencin a enviar megapaquets i la seva allau es faci encara més forta. Els clients d'èxit aconsegueixen recuperar-se, la resta cauen.

Megapack: com Factorio va resoldre el problema del multijugador de 200 jugadors
El problema era bastant fonamental i vaig trigar 2 setmanes a solucionar-lo. És força tècnic, així que explicaré els detalls tècnics sucosos a continuació. Però primer, cal saber que des de la versió 0.17.54, publicada el 4 de juny, davant els problemes de connexió temporals, el multijugador s'ha tornat més estable i l'amagat retardat és molt menys problemàtic (menys frenada i teletransportació). A més, he canviat la manera com s'oculten els retards de combat, i espero que això els faci una mica més suaus.

Mega Pack multijugador - Detalls tècnics

Per dir-ho simplement, el multijugador en un joc funciona així: tots els clients simulen l'estat del joc reben i enviant només les entrades del jugador (anomenades "accions d'entrada" Accions d'entrada). La tasca principal del servidor és transferir Accions d'entrada i assegurant que tots els clients realitzen les mateixes accions en el mateix cicle. Podeu llegir més sobre això a la publicació. FFF-149.

Com que el servidor ha de prendre decisions sobre quines accions ha de fer, les accions del jugador es mouen pel camí següent: acció del jugador -> client de joc -> xarxa -> servidor -> xarxa -> client de joc. Això vol dir que cada acció del jugador es realitza només després d'haver fet un camí d'anada i tornada per la xarxa. Per això, el joc hauria semblat terriblement lent, de manera que gairebé immediatament després de l'aparició del multijugador al joc, es va introduir un mecanisme per amagar els retards. L'ocultació de latència simula l'entrada del jugador sense tenir en compte les accions d'altres jugadors i la presa de decisions del servidor.

Megapack: com Factorio va resoldre el problema del multijugador de 200 jugadors
Factorio té un estat de joc estat del joc és l'estat complet del mapa, jugador, entitats i tota la resta. Es simula de manera determinista en tots els clients en funció de les accions rebudes del servidor. L'estat del joc és sagrat i, si mai comença a diferir del servidor o de qualsevol altre client, es produeix la desincronització.

Sinó estat del joc tenim un estat de retards Estat de latència. Conté un petit subconjunt de l'estat principal. Estat de latència no és sagrat i només representa una imatge de com serà l'estat del joc en el futur segons les aportacions del jugador. Accions d'entrada.

Per fer-ho, conservem una còpia del generat Accions d'entrada a la cua de retard.

Megapack: com Factorio va resoldre el problema del multijugador de 200 jugadors
És a dir, al final del procés del costat del client, la imatge sembla una cosa així:

  1. Aplicar Accions d'entrada tots els jugadors a estat del joc la manera com es van rebre aquestes accions d'entrada del servidor.
  2. Elimina-ho tot de la cua de retard Accions d'entrada, que, segons el servidor, ja s'han aplicat estat del joc.
  3. Suprimeix Estat de latència i reinicieu-lo perquè sembli exactament igual que estat del joc.
  4. Apliqueu totes les accions de la cua de retard a Estat de latència.
  5. Basat en dades estat del joc и Estat de latència presentar el joc al jugador.

Tot això es repeteix a cada ritme.

Massa difícil? No et relaxis, això no és tot. Per compensar les connexions a Internet poc fiables, hem creat dos mecanismes:

  • Marques omeses: quan el servidor ho decideix Accions d'entrada s'executarà en el tacte del joc, llavors si no ha rebut Accions d'entrada algun jugador (per exemple, a causa d'un major retard), no esperarà, però informarà a aquest client "No he tingut en compte el vostre Accions d'entrada, intentaré afegir-los a la barra següent. Això es fa perquè a causa de problemes amb la connexió (o amb l'ordinador) d'un jugador, l'actualització del mapa no s'alenteixi per a tots els altres. Val la pena assenyalar-ho Accions d'entrada no s'ignoren, sinó que simplement es posposen.
  • Latència d'anada i tornada completa: el servidor intenta endevinar quina és la latència d'anada i tornada entre el client i el servidor per a cada client. Cada 5 segons, negocia un nou retard amb el client segons sigui necessari (segons com s'hagi comportat la connexió en el passat) i augmenta o disminueix el retard d'anada i tornada en conseqüència.

Per si mateixos, aquests mecanismes són bastant senzills, però quan s'utilitzen conjuntament (cosa que passa sovint amb problemes de connexió), la lògica del codi es fa difícil de gestionar i amb molts casos extrems. A més, quan aquests mecanismes entren en joc, el servidor i la cua de retard han d'implementar correctament un especial Acció d'entrada anomenat StopMovementInTheNextTick. Gràcies a això, en cas de problemes de connexió, el personatge no correrà sol (per exemple, sota un tren).

Ara he d'explicar-vos com funciona la selecció d'entitats. Un dels tipus aprovats Acció d'entrada és un canvi en l'estat de selecció d'una entitat. Indica a tothom quina entitat ha passat el jugador amb el ratolí. Com podeu veure, aquesta és una de les accions d'entrada més freqüents que envien els clients, així que per estalviar ample de banda, l'hem optimitzat perquè ocupi el mínim espai possible. Això s'implementa així: quan es selecciona cada entitat, en lloc d'emmagatzemar coordenades del mapa absolutes i d'alta precisió, el joc emmagatzema un desplaçament relatiu de baixa precisió de la selecció anterior. Això funciona bé perquè la selecció del ratolí sol passar molt a prop de la selecció anterior. Això dóna lloc a dos requisits importants: Accions d'entrada mai s'ha de saltar i s'ha de fer en l'ordre correcte. Aquests requisits es compleixen per estat del joc. Però des de la tasca estat de latència en "que sembla prou bé" per al jugador, no estan satisfets amb l'estat de retard. Estat de latència no té en compte molts casos límitassociat amb saltar els rellotges i canviar els retards de transmissió d'anada i tornada.

Ja podeu endevinar cap a on va això. Finalment, estem començant a veure les causes del problema del megapaquet. L'arrel del problema és en què es basa la lògica de selecció d'entitats Estat de latència, i aquest estat no sempre conté la informació correcta. Així, el megapaquet es genera així:

  1. El jugador té problemes de connexió.
  2. Entren en joc els mecanismes per saltar cicles i regular el retard de transmissió d'anada i tornada.
  3. La cua d'estat de retard no té en compte aquests mecanismes. Això fa que algunes accions s'eliminin prematurament o s'executin en un ordre incorrecte, donant lloc a un error Estat de latència.
  4. El jugador no té cap problema de connexió i simula fins a 400 cicles per posar-se al dia amb el servidor.
  5. En cada cicle, es genera una nova acció i es prepara per ser enviada al servidor, canviant la selecció de l'entitat.
  6. El client envia un megapaquet de més de 400 canvis de selecció d'entitats al servidor (i amb altres accions: estat d'activació, estat de marxa, etc. també patien aquest problema).
  7. El servidor rep 400 accions d'entrada. Com que no està permès saltar-se una sola acció d'entrada, indica a tots els clients que realitzin aquestes accions i les envia per la xarxa.

La ironia és que un mecanisme dissenyat per conservar l'ample de banda va donar lloc a paquets de xarxa enormes.

Hem resolt aquest problema arreglant tots els casos extrems d'actualització i el suport de la cua de retard. Tot i que va trigar una mica de temps, valia la pena fer-ho bé al final en lloc de confiar en hacks ràpids.

Font: www.habr.com

Afegeix comentari