Bagaimana cara menjaga struktur data disinkronkan melalui jaringan?

12

Konteks

Dalam gim yang sedang saya kerjakan (semacam petualangan grafis titik dan klik), hampir semua yang terjadi di dunia gim dikendalikan oleh manajer aksi yang terstruktur seperti:

masukkan deskripsi gambar di sini

Jadi misalnya jika hasil dari memeriksa objek harus membuat karakter menyapa, berjalan sedikit dan kemudian duduk, saya cukup menelurkan kode berikut:

var actionGroup = actionManager.CreateGroup();
actionGroup.Add(new TalkAction("Guybrush", "Hello there!");
actionGroup.Add(new WalkAction("Guybrush", new Vector2(300, 300));
actionGroup.Add(new SetAnimationAction("Guybrush", "Sit"));

Ini membuat grup tindakan baru (seluruh baris pada gambar di atas) dan menambahkannya ke manajer. Semua grup dieksekusi secara paralel, tetapi aksi dalam setiap grup dirantai bersama sehingga yang kedua hanya dimulai setelah yang pertama selesai. Ketika aksi terakhir dalam grup selesai, grup dihancurkan.

Masalah

Sekarang saya perlu mereplikasi informasi ini melalui jaringan, sehingga dalam sesi multipemain, semua pemain melihat hal yang sama. Serialisasi tindakan individu bukanlah masalahnya. Tapi saya seorang pemula mutlak ketika datang ke jaringan dan saya punya beberapa pertanyaan. Saya pikir demi kesederhanaan dalam diskusi ini kita dapat mengabstraksi komponen action manager menjadi sederhana:

var actionManager = new List<List<string>>();

Bagaimana saya melanjutkan untuk menjaga konten struktur data di atas disinkronkan antara semua pemain?

Selain pertanyaan inti, saya juga memiliki beberapa masalah lain yang terkait dengannya (yaitu semua kemungkinan implikasi dari masalah yang sama di atas):

  • Jika saya menggunakan arsitektur server / klien (dengan salah satu pemain bertindak sebagai server dan klien), dan salah satu klien telah memunculkan sekelompok tindakan, haruskah ia menambahkannya langsung ke manajer, atau hanya mengirim permintaan ke server, yang pada gilirannya akan memerintahkan setiap klien untuk menambahkan grup itu ?
  • Bagaimana dengan paket loss dan sejenisnya? Gim ini bersifat deterministik, tetapi saya berpikir bahwa setiap ketidaksesuaian dalam urutan tindakan yang dilakukan pada klien dapat menyebabkan kondisi dunia yang tidak konsisten. Bagaimana saya melindungi terhadap masalah semacam itu ?
  • Bagaimana jika saya menambahkan terlalu banyak tindakan sekaligus, bukankah itu akan menyebabkan masalah untuk koneksi? Adakah cara untuk meringankannya?
David Gouveia
sumber
5
Wajib "baca ini dulu" tautan gafferongames.com/networking-for-game-programmer yang tidak terlalu teknis meskipun memiliki beberapa kode tetapi terlalu bertele-tele dan menjelaskan opsi Anda dengan cukup baik. Plus itu akan membuat Anda sejajar dengan orang lain yang membaca tautan itu dan itu adalah tempat yang menyenangkan.
Patrick Hughes
@ Patrickrick, Terima kasih atas tautannya! Saya pasti akan membaca semuanya.
David Gouveia
Ada beberapa paket yang mengatur hal semacam ini untuk Anda. Saya tidak tahu seberapa efisien atau cepatnya, tetapi NowJS ( nowjs.com ) adalah contoh yang menarik. Dari sudut pandang pengembang, Anda cukup membagikan struktur data antara klien dan server. Ubah satu, perubahan lainnya.
Tim Holt

Jawaban:

9

Jika saya menggunakan arsitektur server / klien (dengan salah satu pemain bertindak sebagai server dan klien), dan salah satu klien telah memunculkan sekelompok tindakan, haruskah ia menambahkannya langsung ke manajer, atau hanya mengirim permintaan ke server, yang pada gilirannya akan memerintahkan setiap klien untuk menambahkan grup itu?

Anda memiliki tiga opsi dalam hal ini, dua di antaranya telah Anda sebutkan. Pilihan opsi mana yang Anda ambil tergantung pada berbagai faktor yang hanya Anda yang bisa menjadi juri terbaik:

1: Klien memunculkan kelompok tindakan yang menambahkannya secara langsung dan kemudian mengirimkannya ke server. Server menerimanya tanpa cek

* Manfaat dari pendekatan ini adalah bahwa sejauh menyangkut klien, tindakan mereka sendiri memberi mereka umpan balik instan terlepas dari penundaan jaringan. Kerugiannya adalah bahwa pesan klien diterima oleh server sebagai fakta (yang mungkin bukan) *

2: Klien mengirimkan permintaan ke server, yang pada gilirannya menyiarkan permintaan itu kepada semua orang, termasuk klien yang membuat permintaan itu.

Manfaat dari pendekatan ini adalah bahwa server sekarang mengendalikan segala sesuatu yang terjadi dalam permainan yang meringankan sebagian besar masalah dengan aktivitas ilegal (di sini ilegal dapat berkisar dari klien memangkas dinding untuk melakukan langkah yang sekarang ilegal karena server memiliki lebih banyak informasi yang tidak dimiliki klien ketika klien melakukan tindakan tertentu)

3: Klien memunculkan kelompok tindakan, menambahkannya secara langsung dan kemudian mengirimkannya ke server. Server memproses permintaan, menjalankan pemeriksaan sendiri pada tindakan untuk memastikan mereka tidak ilegal, dan kemudian menyiarkan perpindahan ke semua pemain termasuk klien.

Ini mengambil yang terbaik dari kedua 1 dan 2 dengan biaya persyaratan bandwidth yang sedikit lebih. Manfaatnya adalah umpan balik instan ke klien untuk gerakan mereka sendiri dan jika gerakan yang dilakukan klien ilegal, server mengambil tindakan yang sesuai (secara paksa mengoreksi klien).

Bagaimana dengan paket loss dan sejenisnya? Gim ini bersifat deterministik, tetapi saya berpikir bahwa setiap ketidaksesuaian dalam urutan tindakan yang dilakukan pada klien dapat menyebabkan kondisi dunia yang tidak konsisten. Bagaimana saya melindungi terhadap masalah semacam itu?

Kehilangan paket dan keterlambatan ekstrem adalah masalah yang sulit untuk diperbaiki . Solusi yang berbeda (tidak ada yang sempurna) digunakan untuk menangani masalah tergantung pada jenis permainan (mis. Perhitungan mati). Saya akan menganggap permainan Anda tidak harus menyinkronkan fisika.

Salah satu hal pertama yang harus Anda lakukan adalah mengatur waktu semua gerakan Anda. Sistem Anda kemudian harus mempertimbangkan ini dan memainkan gerakan yang sesuai (mungkin server memiliki tanggung jawab ini dan kemudian menolak langkah ilegal). Saat menerapkan sistem ini, asumsikan 0 latensi (uji secara lokal).

0 latensi tentu saja, bukan asumsi yang baik, bahkan di jaringan lokal, jadi sekarang semua bergerak menghargai waktu, jam berapa yang Anda percayai? Di situlah masalah sinkronisasi waktu berperan. Banyak artikel / makalah online akan memandu Anda untuk menyelesaikan masalah ini.

Bagaimana jika saya menambahkan terlalu banyak tindakan sekaligus, bukankah itu akan menyebabkan masalah untuk koneksi? Adakah cara untuk meringankannya?

Pertama hal yang jelas. Jangan pernah mengirim string atau objek berseri. Jangan mengirim pesan secepat game itu sendiri memperbarui. Kirim mereka dalam bentuk potongan (mis. 10 kali per detik). Akan ada kesalahan (terutama kesalahan pembulatan) bahwa server / klien perlu memperbaiki kesalahan sesekali (jadi setiap detik, server mengirim semuanya [segalanya = semua data yang penting untuk menjaga hal-hal dalam permainan Anda di yang benar state] dimana klien kemudian mengambil dan / atau memperhitungkan untuk memperbaiki keadaannya).EDIT: Salah satu kolega saya menyebutkan bahwa jika Anda menggunakan UDP [yang seharusnya, jika Anda memiliki banyak data] maka tidak ada pemesanan jaringan. Mengirim lebih dari 10 paket per detik meningkatkan perubahan paket yang tiba dari pesanan. Saya akan melihat apakah saya dapat mengutip klaim itu. Sedangkan untuk paket yang tidak sesuai pesanan sendiri, Anda dapat membuangnya atau menambahkannya ke antrian pesan / pindahkan sistem Anda yang dirancang untuk menangani perubahan di masa lalu untuk memperbaiki keadaan saat ini

Anda harus memiliki sistem olahpesan yang bergantung pada sesuatu yang hanya memakan sedikit ruang. Jika Anda harus mengirim sesuatu yang hanya dapat memiliki dua nilai, maka kirimkan hanya satu bit. Jika Anda tahu Anda hanya dapat memiliki 256 gerakan, maka kirim char yang tidak ditandatangani. Ada berbagai trik memutar-mutar sedikit untuk mengemas pesan sekencang mungkin.

Sistem perpesanan Anda kemungkinan besar akan menggunakan banyak enum untuk memungkinkan Anda mengekstrak perpindahan dari pesan yang masuk (saya sarankan untuk melihat RakNet dan contoh-contoh di dalamnya jika Anda tidak mengerti apa yang saya maksud di sini).

Saya yakin Anda sudah tahu bahwa Anda tidak dapat memperbaiki masalah yang timbul dengan latensi yang tinggi dan kehilangan paket tetapi Anda dapat membuat efeknya kurang jelas. Semoga berhasil!

EDIT: Komentar Patrick Hughes di atas dengan tautan menjadikan jawaban ini tidak lengkap dan spesifik untuk pertanyaan OP. Saya akan sangat menyarankan membaca topik yang terhubung sebagai gantinya

Samaursa
sumber
Terima kasih banyak atas tanggapan terperinci, yang hampir mencakup semua kekhawatiran saya. Hanya satu pertanyaan tentang bagian yang Anda ucapkan so every second, the server sends everything ... which the client then snaps to. Bisakah saya mengirim sejumlah besar informasi seperti ini sekaligus? Apa ukuran maksimum yang masuk akal?
David Gouveia
Maksimum yang masuk akal adalah angka yang tidak menghasilkan lag:) ... Saya tahu Anda tidak mencari jawaban itu, tetapi saya tidak ingin menuliskan angka karena saya tidak terbiasa dengan permainan Anda.
Samaursa
Juga, tidak ada aturan keras bahwa Anda harus mengirim satu bongkahan besar, saya hanya memberikan itu sebagai contoh.
Samaursa
@Samaursa - Saya tidak setuju dengan komentar "Jika Anda menggunakan UDP [yang seharusnya, jika Anda memiliki banyak data]", komentar. Karena mereka baru dalam pemrograman jaringan, TCP menangani sebagian besar hal-hal sulit untuk Anda dengan biaya yang jauh lebih lambat. Dalam kasus mereka, saya akan menggunakan TCP sampai menjadi hambatan. Pada saat itu mereka akan memiliki pemahaman yang lebih baik tentang bagaimana aplikasi mereka menggunakan jaringan sehingga mengimplementasikan hal-hal UDP akan lebih mudah.
Chris
@ Chris: Saya akan tidak setuju :) ... keputusan antara menggunakan TCP dan UDP adalah seperti (imo) keputusan antara memilih Python dan C ++ untuk pengembangan. Secara teori mungkin terdengar ok, tetapi dalam praktiknya akan sulit untuk hanya beralih (sekali lagi, itu imo).
Samaursa