Seberapa sering memperbarui Klien Game tentang Dunia?


10

Menggunakan socket.io , saya memiliki komunikasi yang mirip dengan MMORPG lainnya, koneksi yang mantap dengan pesan.

Dalam desain saya sejauh ini, klien mengirimkan posisi pemain dan bingkai animasi dengan setiap bingkai pembaruan. Ketika server mendapatkan pesan itu, ia menyiarkannya ke semua klien, yang kemudian akan memindahkan grafik sesuai.

Akankah ide yang lebih baik untuk 'mengumpulkan' ini dan menyiarkannya, katakanlah, sekali dalam 1/10 detik?

Juga, haruskah klien mengirim banyak pesan berbeda (exp diperoleh, diklik pada item) segera setelah itu terjadi atau lebih tepatnya hanya satu yang dikumpulkan? Yang pertama akan diimplementasikan lebih mudah.

Jawaban:


16

Saya akan mendekati ini dari diskusi tingkat tinggi dan kemudian bekerja untuk pertanyaan Anda. Demi pengungkapan, saya tidak punya pengalaman pribadi menggunakan socket.io tetapi banyak paparan ruang masalah sehubungan dengan MMORPG.

Desain arsitektur jaringan mesin MMORPG dan / atau pemilihan proyek sumber tengah atau open source untuk menyediakan fungsionalitas adalah salah satu keputusan yang lebih menantang yang dipengaruhi oleh desain game, anggaran, dan keahlian teknis tim. Pilihan utama akan memengaruhi keputusan arsitektur lainnya (dan terkadang membuat keputusan juga).

Sebagai pengembang MMORPG, kami berencana untuk sukses besar (sering juga dikenal sebagai keberhasilan bencana) di mana sejumlah besar memicu lampu peringatan dan sirene. Salah satu angka besar menakutkan yang muncul adalah dalam algoritma yang N-kuadrat (N ^ 2 selanjutnya), dalam pertanyaan Anda hal pertama yang melompat keluar kepada saya adalah bahwa itu terdengar seperti desain yang meminta entitas untuk menyiarkan informasi ke semua entitas terhubung lainnya. Ini adalah contoh klasik dari masalah N ^ 2.

MMO umumnya mendekati menangani masalah N ^ 2 dengan menyerang masalah dalam beberapa cara yang berbeda; sistem kesadaran (situasional, spasial, dll.) di mana suatu entitas menyadari beberapa himpunan bagian dari semua entitas lain, mempartisi pemain menjadi "pecahan" yang berbeda, mempartisi pemain dalam "zona" dan / atau membuat, menerapkan mekanisme permainan yang mencegah terlalu banyak pemain berkumpul bersama (badai teleport Asheron Call), dll.

Sebagian besar MMORPG dan banyak mesin FPS memiliki arsitektur jaringan yang cukup canggih yang mendukung berbagai fitur termasuk:

  • jalur komunikasi yang andal dan tidak dapat diandalkan (TCP, implementasi kustom paket UDP dan UDP yang andal)
  • pembentukan bandwidth (penentuan prioritas, masa hidup, dll)
  • replikasi otomatis bidang / panggilan data dan fungsi yang tersedia
  • set data atom (yaitu data yang dikomunikasikan bersama)
  • pembaruan diskrit (yaitu di mana setiap transisi penting)
  • koreksi latensi
  • berbagai trik untuk membuat klien merasa responsif

Saya menemukan bahwa Dokumentasi Jaringan Unreal dan Dokumentasi Jaringan Katup memberikan primer yang baik pada berbagai masalah.

Jadi, sekarang mari kita mendekati pertanyaan.

Akankah ide yang lebih baik untuk 'mengumpulkan' ini dan menyiarkannya, katakanlah, sekali dalam 1/10 detik?

Sulit untuk memberikan jawaban ya atau tidak yang sederhana di sini ... karena itu tergantung pada skala (jumlah entitas yang mengamati), frekuensi pembaruan dan ukuran pembaruan. Misalnya, mengumpulkan semuanya mungkin salah besar jika ukuran pembaruan dapat membuat buffer di suatu tempat.

Klien untuk game MMORPG dan FPS pada umumnya dirancang sedemikian rupa sehingga mereka akan memvisualisasikan sesuatu yang "terlihat" benar bahkan jika mereka tidak menerima pembaruan untuk banyak frame pembaruan lebih banyak daripada yang "normal". Saat menggunakan komunikasi yang tidak dapat diandalkan (UDP) Anda hanya bisa berharap kehilangan sejumlah pembaruan ke dalam kekosongan, klien dapat menebusnya dengan mengirimkan pembaruan yang lebih sering daripada yang mungkin digunakan dengan transportasi yang andal.

Dari tinjauan sekilas dokumentasi socket.io, sepertinya mendukung jalur komunikasi yang andal dan tidak dapat diandalkan (volatile dalam terminologinya).

Saya akan mendekati ini dengan mengatasi, pada frekuensi berapa pembaruan diperlukan ...

Jika seorang pemain bergerak dalam garis lurus dengan laju konstan, frekuensi pembaruan yang lebih rendah baik-baik saja karena klien yang mengamati dapat memprediksi dengan akurasi tinggi di mana pemain akan berada pada titik waktu tertentu. Ketika seorang pemain berputar dalam lingkaran ketat atau membuat perubahan arah cepat, maka pembaruan yang lebih sering diperlukan. Sebaliknya, ketika seorang pemain tidak bergerak sama sekali, tidak ada alasan untuk mengirim pembaruan gerakan sama sekali.

Tidak peduli apa, mungkin (umumnya) tidak perlu mengirim pembaruan setiap frame dari klien ke server. Server itu sendiri dapat memilih untuk mengirim pesan ke setiap frame di mana ia memilikinya, atau menunda mereka (lihat pembentukan bandwidth, penentuan prioritas, dan perbarui masa pakai).

Jenis pembaruan lainnya memiliki karakteristik berbeda ... misalnya, pertimbangkan bidang "kesehatan" yang dimodifikasi saat pemain atau makhluk rusak. Salah satu cara untuk mengimplementasikan ini adalah menyiarkan setiap perubahan segera ketika itu terjadi, tetapi ini mengarah pada pemborosan pemrosesan dan bandwidth jika nilainya diubah beberapa kali dalam satu frame atau frame yang berurutan (arsitektur jaringan yang mengimplementasikan pembentukan bandwidth menyelesaikan masalah ini dengan menggabungkan pembaruan ke hanya yang terbaru dikirim ke klien yang mengamati ketika mereka memiliki bandwidth yang tersedia).

haruskah klien mengirim banyak pesan berbeda (exp diperoleh, diklik pada item) segera setelah itu terjadi atau lebih tepatnya hanya satu yang dikumpulkan?

Sekali lagi, tidak ada jawaban ya atau tidak yang sederhana yang akan berfungsi di sini. Tergantung pada apa yang Anda maksudkan dengan dikumpulkan ... keduanya mungkin benar dalam keadaan yang berbeda dan juga tergantung pada implementasi lapisan jaringan.

Mengumpulkan pesan untuk entitas tertentu untuk dikirim sebagai satu pesan dapat (tergantung pada implementasi) mengurangi overhead bandwidth untuk mengirim pesan (mengurangi biaya Anda) secara sebaliknya (tergantung pada implementasi, seperti pemetaan bidang / nilai yang dikomunikasikan oleh string) dapat meningkatkan bandwidth persyaratan dibandingkan dengan jenis pesan spesifik yang lebih sederhana.

Meninjau dokumentasi socket.io, akan tampak bagi saya bahwa overhead pesan berada di ujung yang lebih tinggi dari spektrum yang akan lebih suka mengumpulkan pembaruan untuk dikirim sebagai pesan agregat dan bukan banyak pembaruan tunggal.

Saya akan merekomendasikan meninjau semua pembaruan yang Anda renungkan untuk direplikasi, misalnya sebagian besar MMORPG dan FPS tidak perlu mengirim pemain yang mengeklik peristiwa X untuk mengamati klien kecuali jika itu akan menghasilkan perubahan keadaan untuk objek yang mereka ketahui juga. .


3
+1 Jawaban bagus. Saya juga menyarankan mulai sederhana dan mengoptimalkan dari sana. Pesan spam, tentu saja, menjadi liar, dan melihat bandwidth Anda mulai melemah. Inilah sebabnya mengapa ada baiknya melakukan uji stres secara bertahap. Anda menerapkan pendekatan naivest yang mungkin dan melakukan beberapa pengujian; Anda melakukan beberapa optimisasi; Anda stress test lagi, Anda mengoptimalkan lebih lanjut, bilas, ulangi. Jika benar-benar sepele untuk menerapkan optimasi pada hari pertama, silakan; tetapi ketahuilah bahwa bahkan optimisasi yang paling sepele pun dapat membawa asumsi yang nantinya dapat dibantah dalam lingkungan produksi.
Insinyur

5

Inilah contoh dunia nyata: RuneScape "ticks" sekali setiap ~ 0,6 detik. Anda dapat membacanya di sini . Saya membayangkan itu menyederhanakan hal-hal dari sudut pandang mereka, seperti dalam skrip mereka, mereka mungkin menentukan waktu dan penundaan dalam kutu, bukan milidetik. Dan tentu saja, dengan tingkat centang yang besar / lambat, pengguna dengan koneksi lambat tidak berada pada posisi yang sangat buruk dibandingkan dengan pemain lain.


0

Salah satu cara untuk bekerja adalah dengan memisahkan perubahan data aktual dari penyiaran perubahan tersebut. Ketika suatu objek berubah, buat modifikasi dan atur bendera 'kotor', dan ketika tiba saatnya untuk menyiarkan perubahan apa pun, hanya kirim data untuk objek yang ditandai, dan hapus bendera. Nilai yang dapat diubah berkali-kali secara otomatis digabungkan di sini karena pembaruan Anda hanya mengirim negara pada saat siaran. Anda juga dapat menandai sub-objek atau properti individual sehingga Anda hanya menyiarkan apa yang telah berubah.

Oh, dan biasanya Anda tidak akan mengirim frame animasi ke server, atau klien lain. Keadaan animasi yang tepat biasanya dianggap sebagai detail presentasi dan diserahkan kepada setiap klien untuk diselesaikan, dan sebagai gantinya Anda hanya memastikan setiap klien tahu animasi mana yang sedang diputar.


Saya tidak akan? Bagaimana dengan pose atau sesuatu, saya harus yakin semua klien melihat hal yang sama?
Lanbo

Sangat tidak praktis untuk memastikan bahwa setiap klien melihat hal yang persis sama karena informasi membutuhkan waktu untuk melakukan perjalanan, klien yang berbeda memiliki latensi jaringan yang berbeda, mereka membuat dengan kecepatan yang berbeda, dll. Jadi mencoba membuat semua orang untuk menunjukkan frame yang persis sama secara bersamaan biasanya merupakan usaha yang sia-sia. Alih-alih, Anda mungkin hanya mencoba memastikan mereka memulai animasi yang sama pada waktu yang hampir bersamaan, dan itu cukup baik.
Kylotan
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.