Tentang model jaringan dalam game untuk pemula

Tentang model jaringan dalam game untuk pemula
Selama dua minggu terakhir saya telah mengerjakan mesin jaringan untuk game saya. Sebelumnya, saya sama sekali tidak tahu apa-apa tentang jaringan dalam game, jadi saya membaca banyak artikel dan melakukan banyak eksperimen untuk memahami semua konsep dan dapat menulis mesin jaringan saya sendiri.

Dalam panduan ini, saya ingin berbagi dengan Anda berbagai konsep yang perlu Anda pelajari sebelum menulis mesin permainan Anda sendiri, serta sumber daya dan artikel terbaik untuk mempelajarinya.

Secara umum, ada dua tipe utama arsitektur jaringan: peer-to-peer dan client-server. Dalam arsitektur peer-to-peer (p2p), data ditransfer antara sepasang pemain yang terhubung, sedangkan dalam arsitektur client-server, data hanya ditransfer antara pemain dan server.

Meskipun arsitektur peer-to-peer masih digunakan di beberapa game, client-server adalah standarnya: lebih mudah diterapkan, memerlukan lebar saluran yang lebih kecil, dan lebih mudah dilindungi dari kecurangan. Oleh karena itu, dalam panduan ini, kami akan fokus pada arsitektur client-server.

Secara khusus, kami paling tertarik pada server otoriter: dalam sistem seperti itu, server selalu benar. Misalnya, jika pemain mengira dia berada di (10, 5) dan server memberitahunya bahwa dia berada di (5, 3), maka klien harus mengganti posisinya dengan yang dilaporkan oleh server, bukan sebaliknya. Penggunaan server authoritative memudahkan dalam mengenali cheater.

Ada tiga komponen utama dalam sistem jaringan game:

  • Protokol transport: bagaimana data ditransfer antara klien dan server.
  • Protokol aplikasi: apa yang dikirimkan dari klien ke server dan dari server ke klien, dan dalam format apa.
  • Logika aplikasi: bagaimana data yang dikirimkan digunakan untuk memperbarui status klien dan server.

Sangat penting untuk memahami peran masing-masing bagian dan kesulitan yang terkait dengannya.

Protokol Transportasi

Langkah pertama adalah memilih protokol untuk mengangkut data antara server dan klien. Ada dua protokol Internet untuk ini: TCP ΠΈ UDP. Namun Anda dapat membuat protokol transport Anda sendiri berdasarkan salah satunya atau menggunakan perpustakaan yang menggunakannya.

Perbandingan TCP dan UDP

Baik TCP dan UDP didasarkan pada IP. IP memperbolehkan sebuah paket untuk ditransmisikan dari sumber ke penerima, namun hal ini tidak menjamin bahwa paket yang dikirim akan sampai ke penerima cepat atau lambat, bahwa paket tersebut akan sampai ke penerima setidaknya satu kali, dan bahwa rangkaian paket akan sampai di penerima. urutan yang benar. Selain itu, sebuah paket hanya dapat berisi ukuran data terbatas, yang ditentukan oleh nilainya MTU.

UDP hanyalah lapisan tipis di atas IP. Oleh karena itu, ia memiliki keterbatasan yang sama. Sebaliknya, TCP memiliki banyak fitur. Ini menyediakan koneksi terurut yang andal antara dua node dengan pemeriksaan kesalahan. Oleh karena itu, TCP sangat nyaman dan digunakan di banyak protokol lain, misalnya di HTTP, FTP ΠΈ SMTP. Namun semua fitur ini ada harganya: menunda.

Untuk memahami mengapa fungsi-fungsi ini dapat menyebabkan latensi, kita perlu memahami cara kerja TCP. Ketika host pengirim mengirimkan paket ke host penerima, ia mengharapkan untuk menerima pengakuan (ACK). Jika setelah jangka waktu tertentu tidak diterima (karena paket atau konfirmasi hilang, atau karena alasan lain), maka paket tersebut dikirim kembali. Selain itu, TCP menjamin bahwa paket diterima dalam urutan yang benar, sehingga sampai paket yang hilang diterima, semua paket lainnya tidak dapat diproses, meskipun sudah diterima oleh node penerima.

Namun seperti yang mungkin Anda pahami, latensi dalam game multipemain sangatlah penting, terutama dalam genre aktif seperti FPS. Itu sebabnya banyak game menggunakan UDP dengan protokolnya sendiri.

Protokol asli berdasarkan UDP bisa lebih efisien daripada TCP karena berbagai alasan. Misalnya, ia dapat menandai beberapa paket sebagai tepercaya dan paket lainnya sebagai tidak tepercaya. Oleh karena itu, dia tidak peduli jika paket yang tidak dapat diandalkan itu sudah sampai ke penerima. Atau dapat memproses beberapa aliran data sehingga paket yang hilang dalam satu aliran tidak memperlambat aliran lainnya. Misalnya, mungkin ada thread untuk masukan pemain dan thread lain untuk pesan chat. Jika pesan chat yang datanya tidak mendesak hilang, maka tidak akan memperlambat input yang mendesak. Atau protokol berpemilik mungkin menerapkan keandalan secara berbeda dari TCP agar lebih efisien dalam lingkungan video game.

Jadi, jika TCP jelek, maka kita akan membuat protokol transport kita sendiri berdasarkan UDP?

Semuanya sedikit lebih rumit. Meskipun TCP hampir kurang optimal untuk sistem jaringan game, TCP dapat bekerja cukup baik untuk game spesifik Anda dan menghemat waktu Anda yang berharga. Misalnya, latensi mungkin tidak menjadi masalah untuk game berbasis giliran atau game yang hanya dapat dimainkan di jaringan LAN, yang latensi dan kehilangan paketnya jauh lebih sedikit dibandingkan di Internet.

Banyak game sukses, termasuk World of Warcraft, Minecraft, dan Terraria, menggunakan TCP. Namun, sebagian besar FPS menggunakan protokol berbasis UDP mereka sendiri, jadi kami akan membicarakannya lebih lanjut di bawah.

Jika Anda memilih untuk menggunakan TCP, pastikan itu dinonaktifkan Algoritma Nagle, karena melakukan buffering pada paket sebelum dikirim, yang berarti meningkatkan penundaan.

Untuk mempelajari lebih lanjut perbedaan antara UDP dan TCP dalam konteks game multipemain, lihat artikel Glenn Fiedler UDP vs TCP.

Protokol Kepemilikan

Jadi Anda ingin membuat protokol transport sendiri tetapi tidak tahu harus mulai dari mana? Anda beruntung, karena Glenn Fiedler menulis dua artikel luar biasa tentangnya. Anda akan menemukan banyak ide cerdas di dalamnya.

Artikel pertama Jaringan untuk Pemrogram Game 2008, lebih mudah dari yang kedua Membangun Protokol Jaringan Game 2016. Saya menyarankan Anda memulai dengan yang lebih tua.

Ketahuilah bahwa Glenn Fiedler adalah pendukung besar penggunaan protokol Anda sendiri berdasarkan UDP. Dan setelah membaca artikelnya, Anda mungkin akan menerima pendapatnya bahwa TCP memiliki kelemahan serius dalam video game, dan Anda ingin menerapkan protokol Anda sendiri.

Namun jika Anda baru mengenal jaringan, bantulah diri Anda sendiri dan gunakan TCP atau perpustakaan. Agar berhasil mengimplementasikan protokol transport Anda sendiri, Anda perlu belajar banyak sebelumnya.

Perpustakaan Jaringan

Jika Anda memerlukan sesuatu yang lebih efisien daripada TCP, tetapi tidak ingin repot menerapkan protokol Anda sendiri dan membahas banyak detail, Anda dapat menggunakan perpustakaan net. Ada banyak dari mereka:

Saya belum mencoba semuanya, tapi saya lebih memilih ENet karena mudah digunakan dan dapat diandalkan. Selain itu, ia memiliki dokumentasi yang jelas dan tutorial untuk pemula.

Kesimpulan Protokol Transportasi

Ringkasnya, ada dua protokol transport utama: TCP dan UDP. TCP memiliki banyak fitur berguna: keandalan, pelestarian urutan paket, deteksi kesalahan. UDP tidak memiliki semua itu, tetapi TCP, pada dasarnya, memiliki latensi tinggi yang tidak dapat diterima untuk beberapa game. Artinya, untuk memastikan latensi rendah, Anda dapat membuat protokol Anda sendiri berdasarkan UDP atau menggunakan perpustakaan yang mengimplementasikan protokol transport pada UDP dan disesuaikan untuk video game multipemain.

Pilihan antara TCP, UDP, dan perpustakaan bergantung pada beberapa faktor. Pertama, dari kebutuhan game: apakah memerlukan latensi rendah? Kedua, dari persyaratan protokol aplikasi: apakah memerlukan protokol yang andal? Seperti yang akan kita lihat di bagian selanjutnya, dimungkinkan untuk membuat protokol aplikasi yang cocok untuk protokol yang tidak dapat diandalkan. Terakhir, Anda juga perlu mempertimbangkan pengalaman pengembang mesin jaringan.

Saya punya dua tip:

  • Abstrak protokol transport sebanyak mungkin dari aplikasi lainnya sehingga dapat dengan mudah diganti tanpa menulis ulang semua kode.
  • Jangan terlalu mengoptimalkan. Jika Anda bukan ahli jaringan dan tidak yakin apakah Anda memerlukan protokol transport berbasis UDP sendiri, Anda bisa memulai dengan TCP atau pustaka yang memberikan keandalan, lalu menguji dan mengukur kinerja. Jika Anda mengalami masalah dan Anda yakin itu adalah protokol transport, mungkin inilah saatnya membuat protokol transport Anda sendiri.

Di akhir bagian ini, saya sarankan Anda membaca Pengantar Pemrograman Game Multi Pemain Brian Hook, yang mencakup banyak topik yang dibahas di sini.

Protokol Aplikasi

Sekarang kita dapat bertukar data antara klien dan server, kita perlu memutuskan data apa yang akan ditransfer dan dalam format apa.

Skema klasiknya adalah klien mengirimkan masukan atau tindakan ke server, dan server mengirimkan status permainan saat ini ke klien.

Server mengirimkan bukan keadaan penuh, tetapi keadaan terfilter dengan entitas yang berada di dekat pemain. Dia melakukan ini karena tiga alasan. Pertama, total keadaan mungkin terlalu besar untuk ditransmisikan pada frekuensi tinggi. Kedua, klien terutama tertarik pada data visual dan audio, karena sebagian besar logika game disimulasikan di server game. Ketiga, dalam beberapa permainan, pemain tidak perlu mengetahui data tertentu, seperti posisi musuh di sisi lain peta, karena jika tidak, ia dapat mengendus paket dan mengetahui secara pasti ke mana harus bergerak untuk membunuhnya.

Serialisasi

Langkah pertama adalah mengubah data yang ingin kita kirim (input atau status permainan) ke dalam format yang sesuai untuk transmisi. Proses ini disebut serialisasi.

Ide segera terlintas di benak saya untuk menggunakan format yang dapat dibaca manusia, seperti JSON atau XML. Namun hal ini sama sekali tidak efisien dan akan menghabiskan sebagian besar saluran secara sia-sia.

Sebaliknya, disarankan untuk menggunakan format biner, yang jauh lebih ringkas. Artinya, paket hanya berisi beberapa byte. Di sini kita harus memperhitungkan masalahnya urutan byte, yang mungkin berbeda pada komputer yang berbeda.

Untuk membuat serial data, Anda dapat menggunakan perpustakaan, misalnya:

Pastikan perpustakaan membuat arsip portabel dan menjaga endianness.

Solusi alternatifnya adalah dengan mengimplementasikannya sendiri, tidak terlalu sulit, terutama jika Anda menggunakan pendekatan data-centric dalam kode Anda. Selain itu, ini akan memungkinkan Anda melakukan optimasi yang tidak selalu mungkin dilakukan saat menggunakan perpustakaan.

Glenn Fiedler telah menulis dua artikel tentang serialisasi: Paket Membaca dan Menulis ΠΈ Strategi Serialisasi.

Kompresi

Jumlah data yang ditransfer antara klien dan server dibatasi oleh bandwidth saluran. Kompresi data akan memungkinkan Anda mentransfer lebih banyak data di setiap snapshot, meningkatkan kecepatan refresh, atau sekadar mengurangi kebutuhan bandwidth.

Sedikit pengepakan

Teknik pertama adalah bit packing. Ini terdiri dari penggunaan jumlah bit yang diperlukan untuk menggambarkan nilai yang diinginkan. Misalnya, jika Anda memiliki enum yang dapat memiliki 16 nilai berbeda, maka alih-alih menggunakan satu byte utuh (8 bit), Anda dapat menggunakan 4 bit saja.

Glenn Fiedler menjelaskan cara menerapkannya di bagian kedua artikel. Paket Membaca dan Menulis.

Pengepakan bit bekerja sangat baik dengan diskritisasi, yang akan menjadi topik bagian selanjutnya.

Contoh

Contoh adalah teknik kompresi lossy yang hanya menggunakan sebagian dari nilai yang mungkin untuk mengkodekan suatu nilai. Cara termudah untuk menerapkan diskritisasi adalah dengan membulatkan bilangan floating-point.

Glenn Fiedler (sekali lagi!) menunjukkan bagaimana menerapkan diskritisasi dalam praktiknya dalam artikelnya Kompresi Cuplikan.

Algoritma kompresi

Teknik selanjutnya adalah algoritma kompresi lossless.

Menurut saya, inilah tiga algoritma paling menarik yang perlu Anda ketahui:

  • Pengkodean Huffman dengan kode yang telah dihitung sebelumnya, yang sangat cepat dan dapat memberikan hasil yang baik. Itu digunakan untuk mengompresi paket di mesin jaringan Quake3.
  • zlib adalah algoritma kompresi tujuan umum yang tidak pernah menambah jumlah data. Bagaimana kamu bisa melihat di sini, telah digunakan dalam berbagai aplikasi. Untuk memperbarui negara bagian, ini mungkin berlebihan. Namun ini bisa berguna jika Anda perlu mengirim aset, teks panjang, atau medan ke klien dari server.
  • Menyalin panjang proses mungkin merupakan algoritma kompresi yang paling sederhana, namun sangat efisien untuk jenis data tertentu, dan dapat digunakan sebagai langkah pra-pemrosesan sebelum zlib. Ini sangat cocok untuk mengompresi medan yang terdiri dari ubin atau voxel di mana banyak elemen di sekitarnya diulang.

kompresi delta

Teknik kompresi terakhir adalah kompresi delta. Itu terletak pada kenyataan bahwa hanya perbedaan antara keadaan permainan saat ini dan keadaan terakhir yang diterima oleh klien yang ditransmisikan.

Ini pertama kali digunakan di mesin jaringan Quake3. Berikut dua artikel yang menjelaskan cara menggunakannya:

Glenn Fiedler juga menggunakannya di bagian kedua artikelnya. Kompresi Cuplikan.

Enkripsi

Selain itu, Anda mungkin perlu mengenkripsi transmisi informasi antara klien dan server. Ada beberapa alasan untuk ini:

  • Privasi/Kerahasiaan: Pesan hanya dapat dibaca oleh penerima dan tidak ada jaringan sniffer lain yang dapat membacanya.
  • otentikasi: seseorang yang ingin memainkan peran sebagai pemain harus mengetahui kuncinya.
  • pencegahan cheat: akan lebih sulit bagi pemain jahat untuk membuat paket cheat mereka sendiri, mereka harus mereplikasi skema enkripsi dan menemukan kuncinya (yang berubah pada setiap koneksi).

Saya sangat merekomendasikan menggunakan perpustakaan untuk ini. Saya sarankan menggunakan libsodium, karena ini sangat sederhana dan memiliki tutorial yang bagus. Yang menarik adalah tutorialnya pertukaran kunci, yang memungkinkan Anda membuat kunci baru pada setiap koneksi baru.

Protokol Aplikasi: Kesimpulan

Ini menyimpulkan protokol aplikasi. Saya percaya bahwa kompresi sepenuhnya opsional dan keputusan untuk menggunakannya hanya bergantung pada game dan bandwidth yang diperlukan. Enkripsi, menurut saya, adalah wajib, tetapi pada prototipe pertama Anda dapat melakukannya tanpa itu.

Logika Aplikasi

Kami sekarang dapat memperbarui status di klien, namun kami mungkin mengalami masalah latensi. Pemain, setelah memberikan masukan, perlu menunggu pembaruan status permainan dari server untuk melihat apa pengaruhnya terhadap dunia.

Terlebih lagi, di antara dua pembaruan negara, dunia sepenuhnya statis. Jika tingkat pembaruan status rendah, maka pergerakannya akan sangat tersentak-sentak.

Ada beberapa teknik untuk mengurangi dampak masalah ini, dan saya akan membahasnya di bagian selanjutnya.

Teknik Penghalusan Penundaan

Semua teknik yang dijelaskan dalam bagian ini dibahas secara rinci dalam seri ini. Multiplayer Serba Cepat Gabriel Gambetta. Saya sangat merekomendasikan membaca rangkaian artikel yang luar biasa ini. Ini juga mencakup demo interaktif untuk melihat bagaimana teknik ini bekerja dalam praktiknya.

Teknik pertama adalah dengan menerapkan hasil input secara langsung tanpa menunggu respon dari server. Itu disebut prediksi sisi klien. Namun, ketika klien menerima pembaruan dari server, klien harus memverifikasi bahwa prediksinya benar. Jika tidak, maka dia hanya perlu mengubah statusnya sesuai dengan apa yang dia terima dari server, karena servernya otoriter. Teknik ini pertama kali digunakan di Quake. Anda dapat membaca lebih lanjut tentangnya di artikel. Tinjauan kode Quake Engine Fabien Sanglars [terjemahan di HabrΓ©].

Rangkaian teknik kedua digunakan untuk memperlancar pergerakan entitas lain antara dua pembaruan status. Ada dua cara untuk menyelesaikan masalah ini: interpolasi dan ekstrapolasi. Dalam kasus interpolasi, dua keadaan terakhir diambil dan transisi dari satu keadaan ke keadaan lainnya ditampilkan. Kerugiannya adalah menyebabkan sedikit penundaan, karena klien selalu melihat apa yang terjadi di masa lalu. Ekstrapolasi adalah tentang memprediksi di mana entitas seharusnya berada sekarang berdasarkan keadaan terakhir yang diterima oleh klien. Kerugiannya adalah jika entitas mengubah arah pergerakan sepenuhnya, maka akan terdapat kesalahan besar antara perkiraan dan posisi sebenarnya.

Teknik terakhir yang paling canggih, hanya berguna di FPS, adalah kompensasi keterlambatan. Saat menggunakan kompensasi lag, server memperhitungkan penundaan klien saat menembak sasaran. Misalnya, jika seorang pemain melakukan headshot di layarnya, namun kenyataannya targetnya berada di lokasi yang berbeda karena penundaan tersebut, maka tidak adil untuk menolak hak membunuh pemain tersebut karena penundaan tersebut. Jadi server memundurkan waktu ke saat pemain menembak untuk mensimulasikan apa yang dilihat pemain di layarnya dan memeriksa tabrakan antara tembakannya dan target.

Glenn Fiedler (seperti biasa!) menulis artikel pada tahun 2004 Fisika Jaringan (2004), di mana ia meletakkan dasar untuk sinkronisasi simulasi fisika antara server dan klien. Pada tahun 2014 ia menulis serangkaian artikel baru fisika jaringan, di mana dia menjelaskan teknik lain untuk menyinkronkan simulasi fisika.

Ada juga dua artikel di wiki Valve, Sumber Jaringan Multipemain ΠΈ Metode Kompensasi Latensi dalam Desain dan Optimasi Protokol Dalam Game Klien/Server menangani kompensasi keterlambatan.

Pencegahan Kecurangan

Ada dua teknik pencegahan kecurangan utama.

Pertama, mempersulit penipu untuk mengirim paket berbahaya. Seperti disebutkan di atas, cara yang baik untuk menerapkannya adalah enkripsi.

Kedua, server otoritatif hanya boleh menerima perintah/input/tindakan. Klien tidak boleh mengubah keadaan di server selain dengan mengirimkan input. Kemudian server, setiap kali menerima input, harus memeriksa validitasnya sebelum menerapkannya.

Logika Aplikasi: Kesimpulan

Saya menyarankan Anda menerapkan cara untuk mensimulasikan latensi tinggi dan kecepatan refresh rendah sehingga Anda dapat menguji perilaku game Anda dalam kondisi buruk, bahkan saat klien dan server berjalan di mesin yang sama. Hal ini sangat menyederhanakan penerapan teknik pemulusan penundaan.

Sumber Daya Bermanfaat Lainnya

Jika Anda ingin menjelajahi sumber daya model jaringan lainnya, Anda dapat menemukannya di sini:

Sumber: www.habr.com

Tambah komentar