Sinkronisasi klien lalu lintas rendah dengan server dalam MMO

22

Saya menerapkan MMO di mana pemain terbang di angkasa pada kapal luar angkasa mengendalikannya dengan tombol panah dan bekerja sama dengan pemain lain.

Saya ingin mengimplementasikannya sehingga pemain akan dapat menghindari kapalnya dari roket atau sesuatu yang lain, jadi saya mencoba untuk memprediksi seluruh kondisi permainan di sisi klien menggunakan algoritma simulasi dunia yang sama seperti penggunaan server. Dunia permainan itu ditulis pada C # dan akan dipanggil dalam klien secara langsung (ditulis di Unity3D) dan melalui CLR pada server C ++ (di Linux). Koneksi melalui UDP.

Masalahnya adalah bagaimana mempertahankan, misalnya, 1000 pemain dalam satu peta (tidak termasuk semua objek game lainnya, massa ...): Katakanlah saya akan:

  • sinkronisasi server dengan klien 50 kali per detik
  • kirim ke setiap negara klien hanya dari objek permainan (dan pemain) yang dapat dilihatnya (dalam beberapa radius)
  • harus mengirim 100 objek ke setiap pemain dalam radius pandangannya
  • harus mengirim rata-rata 50 byte per objek game (itu id, x, y coords, rotasi, status ...)

jadi, perlu memiliki bandwidth jaringan seperti itu: 1000 (klien) * 50 (kali per detik) * 100 (objek untuk dikirim ke setiap pemain) * 50 (byte per objek) = 250.000 000 byte per detik! Tidak mungkin!

Apakah mungkin mengurangi nilai ini? Sebagai contoh, biarkan klien untuk sepenuhnya mensimulasikan dunia game mereka (untuk jangka waktu yang lama) dan mengirim mereka hanya input dari klien lain dan menyinkronkan dunia game, katakanlah, setiap beberapa detik tetapi itu akan menyebabkan masalah desinkronisasi yang aneh pada leash karena perhitungan float .

Ngomong-ngomong, bagaimana game seperti itu diprogram secara umum? Terima kasih.

orang Slavia
sumber
1
Saya hanya mengirim info logis tentang objek (posisi dunia, keadaan saat ini (yang satu byte) dan sebagainya) - tidak ada grafik.
Slav
1
@Slav: Bagus! Semua perubahan bit itu mengingatkan saya pada hari-hari pemrograman ASM saya.
Randolf Richardson
1
Kenapa tidak "hari ini hari"? :) Ketika saya menulis di AS3, Java, Lua, C # dan menghadapi kinerja buruk seperti itu saya kehilangan C ++ dan ingat tentang ASM.
Slav
1
@Slav: Heheh, saya belum melakukan banyak ASM baru-baru ini. Sebagian besar hal bagi saya adalah di Jawa dan Perl (mod_perl2 kebanyakan) hari ini, tapi saya benar-benar menikmati bahasa ini juga.
Randolf Richardson
2
@Slav, Anda menulis: "Ketika saya menulis di AS3, Java, Lua, C # dan menghadapi kinerja buruk seperti itu saya kehilangan C ++ dan ingat tentang ASM". Anda harus belajar cara menggunakan Lua dan C # dengan benar, mungkin Anda akan menemukan kinerjanya lebih buruk. Juga, mengeluh tentang (diduga) bahasa skrip tercepat di luar sana paling tidak tunggal ... Apakah ini permainan tentang analisis genom manusia realtime?
Raine

Jawaban:

20

Anda hanya membutuhkan sekitar 30 pembaruan (atau bahkan kurang dari 10 atau 20) per detik. interpolasi posisi objek yang bergerak di sisi klien. Secara umum Anda hanya boleh mengirim data ketika itu SANGAT dibutuhkan. Di WoW Anda mungkin menerima lebih banyak pembaruan dari para pemain yang berada dalam grup dengan Anda daripada dari para pemain yang berada di lokasi yang sama. Juga, jika pemain lain jauh dari Anda, Anda tidak menerima banyak pembaruan per detik tentang dia.

Kemudian, hanya kirim satu snapshot lengkap ke setiap pemain saat dia terhubung. Setelah itu hanya mengirim perubahan objek game. Jika tidak ada perubahan, jangan kirim.

Kemudian, gunakan BitVectors dengan berat atau setiap kali Anda memanggilnya untuk mengurangi jumlah data yang tidak dibutuhkan! Contoh: Anda juga dapat mencoba menulis float menggunakan hanya satu byte (dalam rentang dari 0 hingga 1 atau -1 hingga 1) sehingga Anda hanya memiliki 256 atau 128 nilai yang berbeda. Tapi pemain tidak akan melihat gerakan tersentak-sentak berkat interpolasi.

Lihat ini sebagai contoh dengan LidgrenLibrary tentang cara mengompres data: http://code.google.com/p/lidgren-network-gen3/wiki/Optimization

Berikutnya: Coba kurangi radius tampilan pemain saat mereka bergerak, dan hanya kirimkan informasi penting pada waktu itu. Kemudian ketika mereka berhenti meningkatkan radius tampilan mereka lagi. Anda dapat menggunakan sistem hashing spasial atau pohon bsp untuk mengurangi overhead mencari objek yang "dalam jangkauan". Ini adalah bacaan yang bagus untuk topik: http://en.wikipedia.org/wiki/Collision_detection

Kompres data DIRI ANDA sendiri hanya ANDA yang tahu tentang struktur data dan koherensi temporal dalam data (yang dapat dan harus dieksploitasi). Algoritma umum seperti Bzip2, Deflate, apa pun, harus digunakan, tetapi hanya sebagai tahap akhir kompresi!

Selain itu, untuk informasi yang tidak penting untuk permainan, Anda juga bisa menggunakan teknik P2P tambahan. Contoh: Seorang pemain memainkan animasi "halo". (Hanya efek grafis) Pemain mengirim informasi ini ke server, tetapi server tidak menyampaikan informasi tersebut ke pemain lain. Alih-alih ini efek non-kritis dikirim oleh pemain itu sendiri ke klien lain dalam jangkauan.

EDIT (karena komentar):

Metode tambahan untuk mengurangi jumlah bit rata-rata per detik untuk setiap pemain:

  1. Anda menulis bahwa Anda mengirim "Objek tidak berubah". Tidak ada alasan untuk melakukan ini. Jika Anda khawatir tentang kehilangan paket (dan membuat simulasi Anda tidak sinkron karena hal ini) pertimbangkan hal berikut: Pada setiap catatan waktu tetap (mis. 100, 200, 300, 400 ...) hash kondisi simulasi dan kirimkan ke server . server mengkonfirmasi atau mengirim snapshot lengkap dari semua data kembali.

  2. Untuk hal-hal seperti roket atau bahkan pemain Anda dapat menggunakan tidak hanya interpolasi tetapi juga ekstrapolasi untuk membuat simulasi lebih realistis. Contoh 'Rocket': Alih-alih memperbarui dengan pesan seperti "Apakah sekarang di posisi x" hanya mengirim pesan sekali berisi yang berikut: "Rocket Spawned: position (vector), Time (di mana simulasi langkah roket itu muncul), kecepatan ( vektor) ". Jadi Anda bahkan tidak perlu memasukkan rotasi karena ujungnya akan selalu berada di arah "kecepatan".

  3. Gabungkan beberapa perintah dalam satu pesan dan jangan pernah mengirim pesan yang lebih kecil dari 16-20 byte karena header udp akan lebih besar dari pesan itu sendiri. Juga jangan mengirim paket yang lebih besar dari MTU protokol Anda karena fragmentasi akan memperlambat kecepatan transmisi.

Riki
sumber
Oh, itu ide yang baik untuk memperbarui beberapa objek lebih sering daripada yang lain, gunakan P2P, menurunkan akurasi floating point, mengirim perubahan saja (yang tidak sepele bagi saya karena saya bermaksud untuk menyinkronkan objek secara berkala tetapi "objek tidak berubah" adalah informasinya terlalu). Dengan semua modifikasi ini, keseluruhan gambar terlihat lebih realistis!
Slav
1
Mengirim "objek tidak berubah" pemberitahuan jenis mungkin merupakan teknik yang berguna untuk tujuan pengujian di mana Anda ingin melihat bagaimana kinerja permainan Anda saat pemain aktif selama masa sibuk karena memiliki potensi untuk mengajukan tuntutan pada pemrosesan serta jaringan, tetapi masih ada solusi yang lebih baik dari ini (seperti membuat daemon yang berdiri sendiri yang mengontrol karakter dalam gim yang sebenarnya, kemudian menjalankan deamon itu beberapa kali dari mesin yang berbeda).
Randolf Richardson
5

Berikut ini dua pendekatan:

Pertama:
Beralih ke fisika deterministik, mengirim perintah pemain, tindakan ai, objek yang terlihat dan apa pun yang tidak dapat ditentukan sisi klien ke klien. Ini harus menyertakan non-perintah, konfirmasi bahwa hingga titik waktu tertentu tidak lain adalah perintah yang telah dikirim dan diterima berlaku.

Klien harus menjalankan dua atau tiga simulasi simultan.
1: Menghentikan setiap kali ada data yang hilang untuk langkah selanjutnya.
2: Lanjutkan menggunakan data dugaan dan berikan status yang digunakan untuk rendering. 3: Setiap kali no 1 menghentikan simulasi ini menyalin keadaan no 1, mengejar waktu saat ini dan mengambil alih untuk no 2, yang kemudian dijatuhkan.

Jika mengejar cukup cepat Anda dapat meninggalkan perbedaan antara no 2 dan no 3 dan langsung drop data lama.

Kedua:
Jangan gunakan fisika deterministik, lakukan hal yang sama seperti di atas, tetapi kirim "frame penuh" sekali setiap beberapa detik. Anda dapat dengan mudah meninggalkan transfer hal-hal sementara seperti peluru.

Dalam kedua kasus ini, Anda mungkin ingin waspada dengan klien yang memprediksi siapa saja yang sekarat, agak konyol melihat lawan yang tidak meledak.

Dan +1 untuk perhitungan matematika, terlalu banyak orang gagal membuat estimasi penggunaan sumber daya sederhana.

aaaaaaaaaaaa
sumber
2
Apakah "fisika deterministik" berarti bahwa saya tidak dapat menggunakan nilai titik apung atau langkah simulasi yang berbeda? Saya bertanya-tanya bahwa desinkronisasi kritis dapat terjadi jika, misalnya, roket akan melewati beberapa menara musuh pada klien tetapi akan memukulnya di server (karena beberapa ketidaktepatan titik apung) yang akan menyebabkan pemain terus memerangi menara itu hingga paket sinkronisasi server yang masuk berikutnya (beberapa detik).
Slav
3
Ini berarti bilangan bulat dan langkah waktu tetap. Secara teoritis Anda bisa mengejek poin float untuk berperilaku, tetapi menggunakan bilangan bulat adalah cara yang lebih sederhana. Anda telah mendapatkan poin dengan contoh misil yang hilang, jika Anda menggunakan fisika non-deterministik, mungkin yang terbaik adalah membiarkan server sepenuhnya menangani kematian, dan mengirimkan kasus kematian / kehancuran dengan cepat.
aaaaaaaaaaaa
5

Beberapa pertanyaan dulu.

Apakah 'roket atau sesuatu yang lain' cerdas atau bodoh? Jika mereka bodoh, yang Anda butuhkan hanyalah cap waktu api, asal, dan vektor untuk mensimulasikan lintasan mereka. Jika mereka cerdas, seberapa pintar mereka? Bisakah Anda menghitung pada saat kebakaran itu mereka akan mengenai atau meleset? Jika demikian, Anda dapat mensimulasikan seluruh jalur pada klien. ("Pada T13 rudal akan mengenai kapal karena permainan kehilangan dodge roll / penembak mencetak hit kritis.")

Secara umum meskipun tidak ada banyak alasan untuk: A) memiliki clock rate 50Hz, (Kebanyakan penembak lolos dengan 15-20 dan MMO kurang dari itu.) B) mengirim keadaan penuh setiap frame. (Apakah rotasi rudal di ruang angkasa sama sekali? Atau bisakah Anda mengasumsikan bahwa 'depan' diorientasikan sepanjang vektor yang dilalui?)

Habiskan waktu dengan prediksi dan interpolasi, dan Anda akan melihat bandwidth Anda anjlok. Sebuah proyek yang saya kerjakan memiliki tingkat pembaruan 10Hz, dan representasi keadaan objek saya pikir 14 byte. (Kompres semua yang Anda bisa! Saya percaya kami menggunakan 6 bit untuk menentukan rotasi di sekitar bidang x dan kemudian 6 bit lainnya untuk kemiringan di atas / di bawah bidang itu, itu terlihat tidak dapat dibedakan dengan mengirimkan matriks rotasi / angka empat yang sebenarnya.)

Hal lain yang dapat Anda lakukan adalah memprioritaskan objek. Tunjukkan, mungkin ada 100 objek di set yang relevan, tetapi apakah Anda tahu pandangannya frustrasi di server? Jika sesuatu tidak ada dalam pandangannya, bisakah Anda menghentikan frekuensi pembaruannya dengan urutan besarnya?

Gagasan umum bukan untuk membuat simulasi yang sempurna pada klien, itu tidak mungkin, idenya adalah membuat permainan yang menyenangkan di mana para pemain tidak akan melihat bahwa itu bukan simulasi yang sempurna.

Doug-W
sumber