Megapack: Paano Nalutas ng Factorio ang 200-Player Multiplayer Problem

Megapack: Paano Nalutas ng Factorio ang 200-Player Multiplayer Problem
Noong Mayo ng taong ito ay lumahok ako bilang isang manlalaro sa Mga kaganapan sa MMO KatherineOfSky. Napansin ko na kapag ang bilang ng mga manlalaro ay umabot sa isang tiyak na bilang, bawat ilang minuto ang ilan sa kanila ay "nahuhulog". Sa kabutihang-palad para sa iyo (ngunit hindi para sa akin), ako ay isa sa mga manlalaro na na-disconnect tuwing, kahit na may magandang koneksyon. Kinuha ko ito bilang isang personal na hamon at nagsimulang maghanap ng mga sanhi ng problema. Pagkatapos ng tatlong linggo ng pag-debug, pagsubok, at pag-aayos, sa wakas ay naayos na ang bug, ngunit hindi ganoon kadali ang paglalakbay.

Ang mga problema sa mga multiplayer na laro ay napakahirap subaybayan. Karaniwang nangyayari ang mga ito sa ilalim ng napakaspesipikong mga parameter ng network at napakaspesipikong kundisyon ng laro (sa kasong ito, mayroong higit sa 200 manlalaro). At kahit na mai-reproduce ang problema, hindi ito ma-debug nang maayos dahil ang pagpasok ng mga breakpoint ay humihinto sa laro, nakakalito sa mga timer, at kadalasang nagiging sanhi ng pag-time out ng koneksyon. Ngunit salamat sa pagtitiyaga at isang kahanga-hangang tool na tinatawag pangit ang yari ng bangkang iyon Nagawa kong malaman kung ano ang nangyayari.

Sa madaling sabi, dahil sa isang bug at hindi kumpletong pagpapatupad ng latency state simulation, minsan ay makikita ng kliyente ang sarili sa isang sitwasyon kung saan kailangan nitong magpadala ng network packet na binubuo ng mga aksyon ng pagpili ng input ng player na humigit-kumulang 400 na entity ng laro sa isang ikot ng orasan ( tinatawag namin itong "mega-packet"). Hindi lamang dapat matanggap ng server nang tama ang lahat ng mga pagkilos na ito sa pag-input, ngunit ipadala din ang mga ito sa lahat ng iba pang kliyente. Kung mayroon kang 200 kliyente, mabilis itong nagiging problema. Ang link sa server ay mabilis na nagiging barado, na humahantong sa pagkawala ng packet at isang kaskad ng muling hiniling na mga packet. Ang pagkaantala sa pagkilos ng pag-input ay nagiging sanhi ng higit pang mga kliyente na magpadala ng mga megapacket, na nagiging sanhi ng paglaki ng avalanche. Ang mga masuwerteng kliyente ay namamahala upang makabawi; lahat ng iba ay nahuhulog.

Megapack: Paano Nalutas ng Factorio ang 200-Player Multiplayer Problem
Ang problema ay medyo fundamental at inabot ako ng 2 linggo upang ayusin ito. Medyo teknikal ito, kaya ipapaliwanag ko ang mga makatas na teknikal na detalye sa ibaba. Ngunit una, kailangan mong malaman na mula noong bersyon 0.17.54, na inilabas noong Hunyo 4, sa harap ng mga pansamantalang problema sa koneksyon, ang multiplayer ay naging mas matatag, at ang pagtatago ng mga pagkaantala ay naging mas kaunting buggy (mas kaunting pagbagal at teleporting). Binago ko rin ang paraan ng pagtatago ng combat lag at umaasa akong gagawin itong mas maayos.

Multiplayer Mega Pack - Mga Teknikal na Detalye

Sa madaling salita, gumagana ang multiplayer sa isang laro tulad nito: ginagaya ng lahat ng kliyente ang estado ng laro, tumatanggap at nagpapadala lamang ng input ng manlalaro (tinatawag na "mga aksyon sa pag-input", Mga Pagkilos sa Pag-input). Ang pangunahing gawain ng server ay ang paglipat Mga Pagkilos sa Pag-input at kontrolin na ang lahat ng mga kliyente ay nagsasagawa ng parehong mga aksyon sa parehong ikot ng orasan. Maaari mong basahin ang higit pa tungkol dito sa post FFF-149.

Dahil ang server ay dapat gumawa ng mga desisyon tungkol sa kung anong mga aksyon ang gagawin, ang mga aksyon ng manlalaro ay gumagalaw nang humigit-kumulang sa landas na ito: pagkilos ng manlalaro -> game client -> network -> server -> network -> game client. Nangangahulugan ito na ang aksyon ng bawat manlalaro ay ginagawa lamang pagkatapos gumawa ng round trip sa buong network. Dahil dito, ang laro ay mukhang napakabagal, kaya halos kaagad pagkatapos ng pagpapakilala ng multiplayer sa laro, isang mekanismo ang ipinakilala upang itago ang mga pagkaantala. Ang pagtatago ng pagkaantala ay ginagaya ang input ng manlalaro nang hindi isinasaalang-alang ang mga aksyon ng iba pang mga manlalaro at ang mga desisyon ng server.

Megapack: Paano Nalutas ng Factorio ang 200-Player Multiplayer Problem
Ang Factorio ay may estado ng laro Estado ng Laro ay ang kumpletong estado ng card, player, entity at lahat ng iba pa. Ito ay deterministikong ginagaya sa lahat ng mga kliyente batay sa mga aksyon na natanggap mula sa server. Sagrado ang estado ng laro, at kung magsisimula itong mag-iba mula sa server o anumang iba pang kliyente, magaganap ang desync.

Pero Estado ng Laro mayroon kaming estado ng pagkaantala Katayuan ng Latency. Naglalaman ito ng maliit na subset ng ground state. Katayuan ng Latency hindi sagrado at kumakatawan lamang sa isang larawan kung ano ang magiging hitsura ng estado ng laro sa hinaharap batay sa mga input ng player Mga Pagkilos sa Pag-input.

Para sa layuning ito, nag-iimbak kami ng kopya ng ginawa Mga Pagkilos sa Pag-input sa pagkaantala ng pila.

Megapack: Paano Nalutas ng Factorio ang 200-Player Multiplayer Problem
Iyon ay, sa dulo ng proseso sa panig ng kliyente ang larawan ay mukhang ganito:

  1. Mag-apply Mga Pagkilos sa Pag-input lahat ng mga manlalaro sa Estado ng Laro ang paraan ng pagtanggap ng mga pagkilos na ito mula sa server.
  2. Inalis namin ang lahat sa pila ng pagkaantala Mga Pagkilos sa Pag-input, na, ayon sa server, ay nailapat na sa Estado ng Laro.
  3. Tanggalin Katayuan ng Latency at i-reset ito upang mukhang eksaktong kapareho ng Estado ng Laro.
  4. Inilapat namin ang lahat ng pagkilos mula sa pila ng pagkaantala hanggang Katayuan ng Latency.
  5. Batay sa datos Estado ng Laro ΠΈ Katayuan ng Latency Ibinibigay namin ang laro sa manlalaro.

Ang lahat ng ito ay paulit-ulit sa bawat sukat.

Masyadong mahirap? Huwag magpahinga, hindi lang ito. Upang mabayaran ang mga hindi mapagkakatiwalaang koneksyon sa Internet, gumawa kami ng dalawang mekanismo:

  • Mga napalampas na tik: kapag napagpasyahan iyon ng server Mga Pagkilos sa Pag-input ay ipapatupad sa beat ng laro, pagkatapos ay kung hindi siya nakatanggap Mga Pagkilos sa Pag-input ilang manlalaro (halimbawa, dahil sa tumaas na pagkaantala), hindi siya maghihintay, ngunit sasabihin sa kliyenteng ito "Hindi ko isinasaalang-alang ang iyong Mga Pagkilos sa Pag-input, susubukan kong idagdag ang mga ito sa susunod na bar." Ginagawa ito upang dahil sa mga problema sa koneksyon (o computer) ng isang manlalaro, ang pag-update ng mapa ay hindi bumabagal para sa lahat. Ito ay nagkakahalaga ng pagpuna na Mga Pagkilos sa Pag-input hindi binabalewala, bagkus ay isinantabi lamang.
  • Buong round-trip latency: Sinusubukan ng server na hulaan kung ano ang round-trip latency sa pagitan ng client at server para sa bawat client. Bawat 5 segundo, nakikipagnegosasyon ito ng bagong latency sa kliyente kung kinakailangan (batay sa kung paano kumilos ang koneksyon sa nakaraan), at pinapataas o binabawasan ang round-trip latency nang naaayon.

Sa kanilang sarili, ang mga mekanismong ito ay medyo simple, ngunit kapag ginamit ang mga ito nang magkasama (na kadalasang nangyayari sa mga problema sa koneksyon), ang lohika ng code ay nagiging mahirap na pamahalaan at may maraming mga kaso sa gilid. Bilang karagdagan, kapag ang mga mekanismong ito ay naglaro, ang server at pagkaantala ng pila ay dapat na maayos na ipatupad ang espesyal Pagkilos ng Input tinawagan StopMovementInTheNextTick. Salamat dito, kung may mga problema sa koneksyon, ang karakter ay hindi tatakbo sa kanyang sarili (halimbawa, sa harap ng isang tren).

Ngayon ay kailangan naming ipaliwanag sa iyo kung paano gumagana ang pagpili ng entity. Isa sa mga ipinadalang uri Pagkilos ng Input ay isang pagbabago sa estado ng pagpili ng entity. Sinasabi nito sa lahat kung aling entity ang pinagmamasdan ng player. Gaya ng maiisip mo, isa ito sa mga pinakakaraniwang input na aksyon na ipinadala ng mga kliyente, kaya para makatipid ng bandwidth, na-optimize namin ito para kumuha ng kaunting espasyo hangga't maaari. Ang paraan ng paggana nito ay habang pinipili ang bawat entity, sa halip na mag-imbak ng ganap, mataas na katumpakan na mga coordinate ng mapa, ang laro ay nag-iimbak ng mababang-katumpakan na kamag-anak na offset mula sa nakaraang pagpili. Gumagana ito nang maayos dahil ang mga seleksyon ng mouse ay malamang na napakalapit sa nakaraang pagpili. Nagtataas ito ng dalawang mahahalagang pangangailangan: Mga Pagkilos sa Pag-input Hindi sila dapat laktawan at dapat kumpletuhin sa tamang pagkakasunud-sunod. Ang mga kinakailangang ito ay natutugunan para sa Estado ng Laro. Ngunit dahil sa gawain Katayuan ng latency sa "looking good enough" para sa player, hindi sila nasisiyahan sa estado ng pagkaantala. Katayuan ng Latency hindi isinasaalang-alang maraming edge cases, na nauugnay sa paglaktaw sa mga ikot ng orasan at pagbabago ng mga round-trip na pagkaantala sa paghahatid.

Maaari mo nang hulaan kung saan ito pupunta. Sa wakas ay nagsisimula na kaming makita ang mga dahilan ng problema sa megapack. Ang ugat ng problema ay umaasa ang logic sa pagpili ng entity Katayuan ng Latency, at ang estadong ito ay hindi palaging naglalaman ng tamang impormasyon. Samakatuwid, ang isang megapacket ay nabuo tulad nito:

  1. Ang manlalaro ay may mga problema sa koneksyon.
  2. Ang mga mekanismo para sa paglaktaw sa mga cycle ng orasan at pag-regulate ng pagkaantala ng round-trip transmission ay naglaro.
  3. Hindi isinasaalang-alang ng delay state queue ang mga mekanismong ito. Nagiging sanhi ito ng ilang pagkilos na maalis nang maaga o maisagawa sa maling pagkakasunud-sunod, na nagreresulta sa hindi tama Katayuan ng Latency.
  4. Ang manlalaro ay may problema sa koneksyon at, upang makahabol sa server, ay nag-simulate ng hanggang 400 cycle.
  5. Sa bawat tik, isang bagong aksyon, na binabago ang pagpili ng entity, ay nabuo at inihanda para sa pagpapadala sa server.
  6. Ang kliyente ay nagpapadala ng isang mega-batch ng 400+ mga pagbabago sa pagpili ng entity sa server (at kasama ang iba pang mga aksyon: mga estado ng pagbaril, mga estado ng paglalakad, atbp. ay nagdusa din sa problemang ito).
  7. Ang server ay tumatanggap ng 400 input na pagkilos. Dahil hindi pinapayagang laktawan ang anumang mga pagkilos sa pag-input, inuutusan nito ang lahat ng kliyente na gawin ang mga pagkilos na iyon at ipadala ang mga ito sa buong network.

Ang kabalintunaan ay ang isang mekanismo na idinisenyo upang makatipid ng bandwidth ay nauwi sa paglikha ng malalaking packet ng network.

Natugunan namin ang isyung ito sa pamamagitan ng pag-aayos sa lahat ng edge case ng update at backlog queue support. Bagama't tumagal ito ng kaunting oras, sa huli ay sulit na makuha ito nang tama kaysa umasa sa mga mabilisang hack.

Pinagmulan: www.habr.com

Magdagdag ng komento