Megapack: como resolveu Factorio o problema do multixogador de 200 xogadores

Megapack: como resolveu Factorio o problema do multixogador de 200 xogadores
En maio deste ano, participei como xogador Eventos MMO de KatherineOfSky. Notei que cando o número de xogadores chega a un número determinado, cada poucos minutos algúns deles "caen". Por sorte para ti (pero non para min), fun un deses xogadores todo o tempomesmo cunha boa conexión. Toméino como un reto persoal e comecei a buscar as causas do problema. Despois de tres semanas de depuración, proba e arranxo, o erro finalmente solucionouse, pero a viaxe non foi tan fácil.

Os problemas nos xogos multixogador son moi difíciles de localizar. Adoitan ocorrer baixo parámetros de rede moi específicos e en estados de xogo moi específicos (neste caso, máis de 200 xogadores). E mesmo cando se pode reproducir un problema, non se pode depurar correctamente porque inserir puntos de interrupción detén o xogo, desordena os temporizadores e normalmente fai que a conexión se agote debido a un tempo de espera. Pero grazas á perseveranza e unha ferramenta marabillosa chamada desajeitado Puiden descubrir o que está a pasar.

En resumo, debido a un erro e a implementación incompleta da simulación de estado de atraso, o cliente ás veces atopábase nunha situación na que tiña que enviar un paquete de rede nun ciclo de reloxo, consistente en accións de entrada do xogador para seleccionar aproximadamente 400 entidades de xogo ( chamámoslle un "megapaquete"). Despois diso, o servidor non só necesita recibir correctamente todas estas accións de entrada, senón tamén envialas a todos os demais clientes. Se tes 200 clientes, isto convértese rapidamente nun problema. A canle ao servidor obstrúese rapidamente, o que provoca a perda de paquetes e unha cascada de paquetes solicitados de novo. O aprazamento das accións de entrada fai que máis clientes comecen a enviar megapaquetes e a súa avalancha faise aínda máis forte. Os clientes exitosos conseguen recuperarse, todo o resto cae.

Megapack: como resolveu Factorio o problema do multixogador de 200 xogadores
O problema foi bastante fundamental e tardei 2 semanas en solucionalo. É bastante técnico, así que explicarei os detalles técnicos suculentos a continuación. Pero primeiro, cómpre saber que desde a versión 0.17.54, publicada o 4 de xuño, ante os problemas de conexión temporais, o modo multixogador volveuse máis estable e a ocultación do atraso é moito menos defectuosa (menos freadas e teletransportación). Ademais, cambiei a forma en que se ocultan os atrasos dos combates, e espero que isto os faga un pouco máis suaves.

Mega Pack multixogador - Detalles técnicos

Para dicilo de forma sinxela, o multixogador nun xogo funciona así: todos os clientes simulan o estado do xogo recibindo e enviando só a entrada do xogador (chamadas "accións de entrada" Accións de entrada). A principal tarefa do servidor é transferir Accións de entrada e garantindo que todos os clientes realicen as mesmas accións no mesmo ciclo. Podes ler máis sobre isto na publicación. FFF-149.

Dado que o servidor ten que tomar decisións sobre que accións realizar, as accións do xogador móvense polo seguinte camiño: acción do xogador -> cliente do xogo -> rede -> servidor -> rede -> cliente do xogo. Isto significa que cada acción do xogador realízase só despois de que fixo un camiño de ida e volta pola rede. Debido a isto, o xogo parecería terriblemente lento, polo que case inmediatamente despois da aparición do multixogador no xogo, introduciuse un mecanismo para ocultar os atrasos. A ocultación de latencia simula a entrada do xogador sen ter en conta as accións doutros xogadores e a toma de decisións do servidor.

Megapack: como resolveu Factorio o problema do multixogador de 200 xogadores
Factorio ten un estado de xogo estado do xogo é o estado completo do mapa, o xogador, as entidades e todo o demais. Simúlase de forma determinista en todos os clientes en función das accións recibidas do servidor. O estado do xogo é sagrado e, se algunha vez comeza a diferir do servidor ou de calquera outro cliente, prodúcese a desincronización.

Pero estado do xogo temos un estado de atrasos Estado de latencia. Contén un pequeno subconxunto do estado principal. Estado de latencia non é sagrado e só representa unha imaxe de como será o estado do xogo no futuro en función das entradas do xogador Accións de entrada.

Para iso, conservamos unha copia do xerado Accións de entrada na cola de atraso.

Megapack: como resolveu Factorio o problema do multixogador de 200 xogadores
É dicir, ao final do proceso no lado do cliente, a imaxe parece algo así:

  1. Solicitar Accións de entrada todos os xogadores a estado do xogo a forma en que estas accións de entrada foron recibidas do servidor.
  2. Elimina todo da cola de atraso Accións de entrada, que, segundo o servidor, xa se aplicaron estado do xogo.
  3. Eliminar Estado de latencia e restablecelo para que pareza exactamente igual que estado do xogo.
  4. Aplica todas as accións da cola de atraso a Estado de latencia.
  5. En base a datos estado do xogo и Estado de latencia render o xogo ao xogador.

Todo isto repítese en cada ritmo.

Demasiado difícil? Non te relaxes, iso non é todo. Para compensar as conexións a Internet pouco fiables, creamos dous mecanismos:

  • Ticks omitidos: cando o servidor decide iso Accións de entrada executarase no tacto do xogo, entón se non recibiu Accións de entrada algún xogador (por exemplo, debido a un aumento do atraso), non esperará, pero informará a este cliente "Non tiven en conta o teu Accións de entrada, tentarei engadilos na seguinte barra. Isto faise para que debido a problemas coa conexión (ou co ordenador) dun xogador, a actualización do mapa non se ralentice para todos os demais. Paga a pena sinalar que Accións de entrada non se ignoran, senón que simplemente se aprazan.
  • Latencia total de ida e volta: o servidor tenta adiviñar cal é a latencia de ida e volta entre o cliente e o servidor para cada cliente. Cada 5 segundos, negocia un novo atraso co cliente segundo sexa necesario (dependendo de como se comportase a conexión no pasado) e aumenta ou diminúe o atraso de ida e volta en consecuencia.

Por si mesmos, estes mecanismos son bastante sinxelos, pero cando se usan xuntos (o que adoita ocorrer con problemas de conexión), a lóxica do código faise difícil de xestionar e con moitos casos extremos. Ademais, cando estes mecanismos entran en xogo, o servidor e a cola de atraso deben implementar correctamente un especial Acción de entrada chamado StopMovementInTheNextTick. Grazas a isto, en caso de problemas de conexión, o personaxe non correrá por si só (por exemplo, baixo un tren).

Agora teño que explicarche como funciona a selección de entidades. Un dos tipos aprobados Acción de entrada é un cambio no estado de selección dunha entidade. Indícanos a todos a entidade sobre a que pasou o xogador co rato. Como vedes, esta é unha das accións de entrada máis frecuentes que envían os clientes, polo que para aforrar ancho de banda optimizámolo para que ocupe o menor espazo posible. Isto impléntanse así: cando se selecciona cada entidade, en lugar de almacenar coordenadas do mapa absolutas e de alta precisión, o xogo almacena un desfase relativo de baixa precisión da selección anterior. Isto funciona ben porque a selección do rato adoita ocorrer moi preto da selección anterior. Isto dá lugar a dous requisitos importantes: Accións de entrada nunca se debe omitir e debe facerse na orde correcta. Estes requisitos cúmprense para estado do xogo. Pero xa que a tarefa estado de latencia en "ver o suficientemente bo" para o xogador, non están satisfeitos co estado de atraso. Estado de latencia non ten en conta moitos casos límiteasociado con omitir reloxos e cambiar os atrasos de transmisión de ida e volta.

Xa podes adiviñar a onde vai isto. Finalmente, comezamos a ver as causas do problema do megapaquete. A raíz do problema é na que se basea a lóxica de selección de entidades Estado de latencia, e este estado non sempre contén a información correcta. Polo tanto, o megapaquete xérase así:

  1. O xogador está a ter problemas de conexión.
  2. Entran en xogo os mecanismos para saltar ciclos e regular o atraso da transmisión de ida e volta.
  3. A cola de estado de atraso non ten en conta estes mecanismos. Isto fai que algunhas accións se eliminen de forma prematura ou se executen na orde incorrecta, dando lugar a unha incorrecta Estado de latencia.
  4. O xogador non ten ningún problema de conexión e simula ata 400 ciclos para poñerse ao día co servidor.
  5. En cada ciclo, xérase unha nova acción e prepárase para ser enviada ao servidor, cambiando a selección da entidade.
  6. O cliente envía un megapaquete de máis de 400 cambios de selección de entidades ao servidor (e con outras accións: estado de disparo, estado de marcha, etc. tamén sufriron este problema).
  7. O servidor recibe 400 accións de entrada. Dado que non se permite omitir unha única acción de entrada, indícase a todos os clientes que realicen estas accións e envíaas pola rede.

A ironía é que un mecanismo deseñado para conservar o ancho de banda resultou en enormes paquetes de rede.

Resolvemos este problema corrixindo todos os casos de actualización e a compatibilidade con filas de atraso. Aínda que levou bastante tempo, pagou a pena facelo ben ao final en lugar de confiar en hackeos rápidos.

Fonte: www.habr.com

Engadir un comentario