Megapack: bagaimana pengembang Factorio berhasil memecahkan masalah dengan 200 pemain multipemain

gambar

Pada bulan Mei tahun ini, saya berpartisipasi sebagai pemain dalam acara MMO KatherineOfSky . Saya perhatikan bahwa ketika jumlah pemain mencapai jumlah tertentu, setiap beberapa menit beberapa dari mereka “jatuh”. Untungnya bagi Anda (tetapi tidak bagi saya), saya adalah salah satu pemain yang terputus setiap saat , bahkan dengan koneksi yang baik. Saya menganggap ini sebagai tantangan pribadi dan mulai mencari penyebab masalah. Setelah tiga minggu debugging, pengujian dan perbaikan, kesalahan akhirnya diperbaiki, tetapi perjalanan ini tidak begitu sederhana.

Masalah permainan multipemain sangat sulit dilacak. Biasanya mereka muncul dalam kondisi yang sangat spesifik dari parameter jaringan dan dalam kondisi permainan yang sangat spesifik (dalam hal ini, kehadiran lebih dari 200 pemain). Dan bahkan ketika dimungkinkan untuk mereproduksi masalah, itu tidak dapat didebug dengan benar, karena penyisipan titik kontrol menghentikan permainan, membingungkan timer dan biasanya mengarah pada penghentian koneksi karena melebihi waktu tunggu. Namun berkat kekeraskepalaan dan alat luar biasa yang disebut canggung, saya berhasil mengetahui apa yang terjadi.

Singkatnya: karena kesalahan dan implementasi simulasi kondisi keterlambatan yang tidak lengkap, klien terkadang menemukan dirinya dalam situasi di mana ia harus mengirim paket jaringan dalam satu siklus clock, yang terdiri dari tindakan pemain untuk memilih sekitar 400 entitas game (kami menyebutnya "megapackage"). Setelah itu, server seharusnya tidak hanya menerima semua tindakan input ini dengan benar, tetapi juga mengirimkannya ke semua klien lain. Jika Anda memiliki 200 pelanggan, ini dengan cepat menjadi masalah. Saluran ke server dengan cepat tersumbat, yang menyebabkan hilangnya paket dan riam paket yang diminta kembali. Menunda tindakan input kemudian mengarah pada fakta bahwa semakin banyak klien mulai mengirim megapacket, dan longsoran salju mereka menjadi semakin kuat. Klien yang berhasil berhasil pulih, sisanya “jatuh”.

gambar

Masalahnya cukup mendasar, dan saya butuh 2 minggu untuk memperbaikinya. Ini cukup teknis, jadi di bawah ini saya akan menjelaskan detail teknis yang menarik. Tapi pertama-tama Anda perlu tahu bahwa sejak versi 0.17.54, dirilis pada 4 Juni, dalam menghadapi masalah koneksi sementara, multiplayer menjadi lebih stabil, dan penyembunyian penundaan jauh lebih sedikit buggy (kurang pengereman dan teleportasi). Selain itu, saya mengubah cara menyembunyikan penundaan dalam pertempuran dan saya berharap bahwa berkat ini mereka akan menjadi sedikit lebih lancar.

Megapack Multi-Pengguna - Detail Teknis


Dalam istilah sederhana, multipemain dalam permainan berfungsi sebagai berikut: semua klien mensimulasikan keadaan permainan, menerima dan mengirim hanya input pemain (disebut “Tindakan input”, Tindakan Input ). Tugas utama server adalah untuk mengirimkan Tindakan Input dan mengontrol bahwa semua klien melakukan tindakan yang sama dalam satu siklus. Baca lebih lanjut tentang ini di pos FFF-149 .

Karena server harus membuat keputusan tentang tindakan apa yang harus dilakukan, tindakan pemain bergerak di sepanjang jalur ini: tindakan pemain -> klien game -> jaringan -> server -> jaringan -> klien permainan. Ini berarti bahwa setiap tindakan pemain dilakukan hanya setelah ia membuat jalur bolak-balik melalui jaringan. Karena hal ini, permainan akan tampak sangat lambat, jadi hampir segera setelah multipemain muncul dalam permainan, mekanisme untuk menyembunyikan penundaan diperkenalkan. Menyembunyikan penundaan meniru input pemain tanpa memperhitungkan tindakan pemain lain dan keputusan server.


Factorio memiliki status permainan yang disebut Status Permainan - ini adalah status penuh dari peta, pemain, entitas, dan yang lainnya. Secara deterministik disimulasikan di semua klien berdasarkan tindakan yang diterima dari server. Status permainan adalah sakral, dan jika itu mulai berbeda dari server atau klien lain, maka terjadi sinkronisasi.

Selain Status Game , kami memiliki status latensi Status Latensi. Ini berisi subset kecil dari keadaan dasar. Status Latensi tidak sakral dan hanya menyajikan gambaran tentang bagaimana kondisi permainan di masa depan berdasarkan Tindakan Input yang diperkenalkan oleh pemain.

Untuk melakukan ini, kami menyimpan salinan Tindakan Input yang dibuat di antrean penundaan.


Yaitu, pada akhir proses di sisi klien, gambarnya terlihat seperti ini:

  1. Terapkan Tindakan Input dari semua pemain ke Status Game saat tindakan input ini diterima dari server.
  2. Kami menghapus dari antrian keterlambatan semua Tindakan Input yang, menurut server, telah diterapkan ke Status Game .
  3. Hapus Status Latensi dan setel ulang sehingga terlihat sama persis dengan Status Game .
  4. Terapkan semua tindakan dari antrian penundaan ke Status Latency .
  5. Berdasarkan data dari Game State dan Latency State, kami memberikan game tersebut kepada pemain.

Semua ini diulangi dalam setiap ukuran.

Terlalu rumit? Jangan santai, itu belum semuanya. Untuk mengimbangi koneksi Internet yang tidak dapat diandalkan, kami menciptakan dua mekanisme:

  • Kutu yang terlewat: ketika server memutuskan bahwa Tindakan Input akan dilakukan dalam permainan, maka jika tidak menerima Tindakan Input beberapa pemain (misalnya, karena keterlambatan yang meningkat), itu tidak akan menunggu, tetapi akan memberi tahu klien ini “Saya tidak mempertimbangkan Tindakan Input Anda, saya akan mencoba menambahkannya ke langkah berikutnya. " Hal ini dilakukan agar, karena masalah dengan koneksi (atau dengan komputer) dari satu pemain, pembaruan peta tidak akan melambat untuk semua orang. Perlu dicatat bahwa Tindakan Input tidak diabaikan, tetapi hanya ditunda.
  • Round Trip Delay: Server mencoba menebak berapa penundaan round-trip antara klien dan server untuk setiap klien. Setiap 5 detik, jika perlu, ia membahas dengan klien penundaan baru (tergantung pada bagaimana koneksi berperilaku di masa lalu), dan karenanya menambah atau mengurangi keterlambatan dalam mentransfer data bolak-balik.

Sendiri, mekanisme ini cukup sederhana, tetapi ketika mereka digunakan bersama-sama (yang sering terjadi dengan masalah koneksi), logika kode menjadi sulit untuk dikelola dan dengan banyak kasus garis batas. Selain itu, ketika mekanisme ini ikut berperan , server dan antrean penundaan harus benar mengimplementasikan Input Action khusus yang disebut StopMovementInTheNextTick . Karena ini, dengan masalah dengan koneksi, karakter tidak akan berjalan dengan sendirinya (misalnya, di bawah kereta).

Sekarang Anda perlu menjelaskan kepada Anda bagaimana pemilihan entitas bekerja. Salah satu jenis Tindakan Input yang disahkan adalah perubahan status pemilihan entitas. Ini memberi tahu semua orang entitas apa yang dibawa pemain itu. Seperti yang dapat Anda pahami, ini adalah salah satu tindakan input yang paling sering dikirim oleh klien, jadi untuk menghemat bandwidth, kami mengoptimalkannya sehingga membutuhkan ruang sesedikit mungkin. Ini diimplementasikan sebagai berikut: saat memilih setiap entitas, alih-alih mempertahankan koordinat peta absolut dan presisi tinggi, game mempertahankan perpindahan relatif arus rendah dari pilihan sebelumnya. Ini bekerja dengan baik karena pemilihan mouse biasanya terjadi sangat dekat dengan pilihan sebelumnya. Karena itu, dua persyaratan penting muncul: Tindakan Input tidak boleh dilewati dan harus dilakukan dalam urutan yang benar. Persyaratan ini dipenuhi untuk Status Game . Tetapi karena tugas dari negara Latency adalah untuk "terlihat cukup baik" untuk pemain, mereka tidak puas dalam kondisi penundaan. Negara Latency tidak memperhitungkan banyak kasus garis batas yang terkait dengan melewatkan siklus dan mengubah penundaan pulang-pergi.

Anda sudah bisa menebak ke mana semuanya berjalan. Akhirnya, kita mulai melihat penyebab masalah megapackage. Akar masalahnya adalah bahwa dalam memutuskan apakah akan melewati tindakan perubahan seleksi, logika pemilihan entitas bergantung pada Negara Latensi , dan negara ini tidak selalu berisi informasi yang benar. Oleh karena itu, megapackage dibuat seperti ini:

  1. Pemain memiliki masalah koneksi.
  2. Mekanisme untuk melewatkan jam dan mengatur penundaan pulang-pergi mulai berlaku.
  3. Keterlambatan status antrian tidak memperhitungkan mekanisme ini. Hal ini menyebabkan beberapa tindakan dihapus sebelum waktunya atau dilakukan dalam urutan yang salah, yang menghasilkan Status Latensi yang salah.
  4. Pemain memiliki masalah dengan koneksi dan dia, untuk mengejar ketinggalan dengan server, mensimulasikan hingga 400 siklus clock.
  5. Di setiap siklus jam, tindakan baru, mengubah pemilihan entitas, dihasilkan dan disiapkan untuk dikirim ke server.
  6. Klien mengirimkan megapacket lebih dari 400 perubahan dalam pilihan entitas (dan dengan tindakan lain: keadaan menembak, berjalan, dll., Juga menderita masalah ini).
  7. Server menerima 400 tindakan input. Karena ia tidak diizinkan untuk melewati satu tindakan input tunggal, ia memerintahkan semua klien untuk melakukan tindakan ini dan mengirimkannya melalui jaringan.

Ironisnya adalah bahwa mekanisme yang dirancang untuk menghemat bandwidth saluran menciptakan paket jaringan besar sebagai hasilnya.

Kami memecahkan masalah ini dengan memperbaiki semua kasus pembaruan dan mendukung antrean penundaan. Meskipun butuh waktu cukup lama, pada akhirnya itu layak menerapkan semuanya dengan benar dan tidak mengandalkan peretasan cepat.

Source: https://habr.com/ru/post/id466135/


All Articles