UE4 | Peralatan untuk Multiplayer # 5 | Transfer informasi antara Server dan Klien


Pada artikel ini kami akan mempertimbangkan transfer data antara Server dan Klien di Unreal Engine 4 diimplementasikan dalam C ++ . Pada awalnya, bagi orang yang tidak memiliki pendidikan khusus, ini tampaknya menjadi sesuatu yang sangat rumit. Terlepas dari sejumlah besar contoh dan analisis, secara pribadi sangat sulit bagi saya pribadi untuk mengumpulkan gambaran lengkap dari proses ini. Tetapi, ketika jumlah kritis dari informasi yang diperoleh melalui membaca dan tes yang dibuat tercapai, sebuah pemahaman datang tentang bagaimana semua ini bekerja.




Pertama-tama, Anda perlu memahami dengan jelas bahwa semua objek dalam game (dengan pengecualian langka) dapat memiliki banyak salinan. Objek asli terletak di Server. Yang asli selalu ada. Salinan dapat ada pada Klien, tetapi tidak sama sekali, yaitu mungkin tidak. Semua peristiwa penting terjadi di Server, dan dialah yang memutuskan siapa yang perlu tahu tentang hal itu dan siapa yang tidak.

Segala sesuatu yang terjadi pada Klien tidak diketahui siapa pun kecuali Klien.

Contoh

Kami memulai permainan dengan dua Klien. Ada sebuah kubus di atas panggung. Asli kubus ini terletak di Server. Dia yang paling penting. Salinan pertama akan ditempatkan pada Klien pertama, dan yang kedua - pada Klien kedua. Jika kami melakukan sesuatu dengan salinan objek pada salah satu pelanggan mereka, maka yang asli tidak akan menderita . Perubahan hanya akan bersifat lokal, hanya untuk Klien ini. Jika Anda mengubah yang asli, maka ada 2 skenario utama:


  1. Salinan pelanggan akan tetap tidak berubah.
  2. Salinan pelanggan akan disinkronkan dengan yang asli.



Sekarang setelah aturan dasar permainan jelas, kita dapat mempertimbangkan opsi apa untuk mentransmisikan informasi antara Server dan Klien yang tersedia untuk kita. Saya tahu 3 cara, tetapi kami hanya akan mempertimbangkan dua yang pertama, karena yang ketiga memungkinkan Anda untuk mentransfer apa saja dan di mana saja, dan hanya berlaku jika Anda dibatasi oleh keterbatasan dari dua yang pertama.


  1. Replikasi
  2. RPC ( Panggilan Prosedur Jarak Jauh ).
  3. TCP


    Replikasi


Hal pertama yang harus diterima tanpa syarat:

Replikasi adalah jalan satu arah, dan hanya berfungsi dari Server ke Klien.
Hal kedua yang perlu Anda ketahui:
Hanya objek atau variabel kelas yang dapat direplikasi.
Dan ketiga, kondisi penting:
Replikasi hanya terjadi ketika perubahan telah terjadi di Server.

Jika dalam Blueprint kita baru saja menandai tempat yang tepat, maka C ++ tidak jauh lebih rumit. Hal utama adalah jangan lupa untuk memasukkan #include "UnrealNetwork.h" .

Pertama, pertimbangkan replikasi objek.
Di konstruktor, kita menulis:


bReplicates = true; 

Jika kita ingin meniru gerakan:


 bReplicateMovement = true; 

Jika Anda perlu mereplikasi komponen yang terhubung:


 Component->SetReplicates(true); 

Deskripsi lengkap dapat ditemukan di sini .


Dengan replikasi variabel, semuanya menjadi sedikit lebih menarik.
Mari kita mulai dengan file header .h .
Anda cukup mereplikasi variabel:


 UPROPERTY(Replicated) bool bMyReplicatedVariable; 

Atau Anda dapat menjalankan beberapa fungsi di sisi Klien jika variabel telah direplikasi. Tidak masalah apa nilai yang diambil variabel. Fakta perubahannya penting.


 UPROPERTY(ReplicatedUsing = OnRep_MySomeFunction) TArray<float> MyReplicatedArray; UFUNCTION() void OnRep_MySomeFunction(); 

Menjalankan fungsi hanyalah salah satu cara untuk mengirim perintah dari Server. Sangat penting untuk mengetahui bahwa replikasi array tidak terjadi sepenuhnya, tetapi hanya bagian yang diubah. Jadi, hanya dengan satu variabel, Anda dapat mengirim banyak perintah dari server, mem-parsing array menjadi elemen, dan elemen menjadi bit.


Sekarang mari kita beralih ke .cpp
Kami menulis kondisi replikasi:


 void AMySuperActor::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); DOREPLIFETIME(AMySuperActor, bMyReplicatedVariable); DOREPLIFETIME_CONDITION(AMySuperActor, MyReplicatedArray, COND_OwnerOnly); } 

Variabel pertama bMyReplicatedVariable direplikasi tanpa syarat untuk semua Klien sekaligus, sedangkan yang kedua, MyReplicatedArray , diperbarui hanya untuk Klien yang memiliki objek AMySuperActor , kecuali, tentu saja, dinyatakan sebagai satu.


Daftar lengkap kondisi yang memungkinkan dapat ditemukan di sini .




RPC ( Panggilan Prosedur Jarak Jauh )


Metode transfer data ini, tidak seperti replikasi, bekerja dua arah, tetapi lebih mahal. Untuk menggunakannya, Anda hanya perlu menghubungkan #include "UnrealNetwork.h" .

Fitur penting adalah Anda dapat mentransfer variabel menggunakan metode RPC .
Pertama, harus dikatakan bahwa RPC datang dengan pengakuan penerimaan Andal dan tanpa Tidak dapat diandalkan . Jika dalam kasus pertama Pengirim tidak tenang sampai ia yakin bahwa paket telah dikirim (dan akan mengirimnya lagi dan lagi jika tidak ada berita timbal balik), maka dalam kasus kedua, Pengirim tidak peduli apakah seseorang menerima bingkisan atau tidak. Terkirim dan lupa.
Jika memungkinkan - gunakan Tidak Dapat Dipercaya . Biasanya metode ini cocok untuk informasi yang tidak terlalu penting, atau untuk data yang sering diperbarui. Jika tidak mungkin, dalam hal pengiriman dari Server ke Klien, kami mencoba melakukan replikasi dengan panggilan fungsi, seperti yang ditunjukkan di atas.

Jadi, untuk mengirim paket kami dari Klien ke Server, Anda harus mendaftarkan tiga fungsi:


 UFUNCTION(Reliable, Server, WithValidation) void ServerTestFunction(float MyVariable); void ServerTestFunction_Implementation(float MyVariable); bool ServerTestFunction_Validate(float MyVariable); 

Dapat diandalkan - paket dengan tanda terima.
Server - mengirim dari Klien ke Server.
WithValidation - paket dibuka oleh penerima hanya jika kondisi yang dijelaskan dalam fungsi bool ServerTestFunction_Validate (float MyVariable) terpenuhi . Yaitu, jika fungsi mengembalikan true . Parameter ini hanya diperlukan untuk fungsi yang dijalankan di Server.
ServerTestFunction (float MyVariable) - fungsi ini dipanggil oleh klien jika ingin mengirim sesuatu ke server. Secara umum, bahkan tidak diperlukan untuk menggambarkannya dalam .cpp .
ServerTestFunction_Implementation (float MyVariable) - fungsi ini akan dipanggil langsung di Server hanya jika ...
ServerTestFunction_Validate (float MyVariable) - fungsi ini dieksekusi pada Server, dan jika true dikembalikan, ServerTestFunction_Implementation (float MyVariable) akan dipanggil.


Untuk mengirim paket dari Server ke Klien, jika kami pasti tidak senang dengan penggunaan replikasi, pada dasarnya hanya Server yang berubah ke Klien :


 UFUNCTION(Reliable, Client, WithValidation) 

Nama-nama fungsi, pada prinsipnya, dapat berubah-ubah, tetapi biasanya mereka harus mencerminkan kemana paket tersebut pergi. Untuk kenyamanan kita.


 UFUNCTION(Reliable, Client, WithValidation) void ClientTestFunction(float MyVariable); void ClientTestFunction_Implementation(float MyVariable); bool ClientTestFunction_Validate(float MyVariable); 

Kalau tidak, ia bekerja dengan cara yang persis sama seperti pada contoh sebelumnya, dengan mempertimbangkan fakta bahwa paket kali ini pergi dari Server ke Klien.


Ada opsi lain untuk mengirim dari Server, ketika paket masuk ke semua klien sekaligus.


 UFUNCTION(Reliable, NetMulticast, WithValidation) void NetMulticastTestFunction(); void NetMulticastTestFunction_Implementation(); bool NetMulticastTestFunction_Validate(); 

Jangan menyalahgunakan opsi ini. Pikirkan tentang bagaimana Anda mengelola replikasi.

Untuk Klien dan NetMulticast, validasi adalah opsional



Contoh implementasi permintaan server
 /*       ,     */ void ADreampaxActor::DoSomethingWithOtherActor(ADreampaxOtherActor * SomeOtherActor) { /*  ,      */ if (Role < ROLE_Authority) { /*    ,    ,      */ ServerDoSomethingWithOtherActor(SomeOtherActor); /*   ,        */ return; } /*         */ SomeOtherActor->Destroy(true); } /*      ,    ServerDoSomethingWithOtherActor(SomeOtherActor)     */ void ADreampaxCharacter::ServerDoSomethingWithOtherActor_Implementation(ADreampaxOtherActor * SomeOtherActor) { /*   ,       */ DoSomethingWithOtherActor(SomeOtherActor); } /*     ,    ServerDoSomethingWithOtherActor_Implementation(ADreampaxOtherActor * SomeOtherActor) */ bool ADreampaxCharacter::ServerDoSomethingWithOtherActor_Validate(ADreampaxOtherActor * SomeOtherActor) { /*      true,   ,   -    fasle.       */ return true; } 

Dan akhirnya, tautan ke manual, yang harus dibaca.
Kompendium Jaringan 'Unreal Engine 4'


Hanya itu yang perlu Anda ketahui tentang komunikasi antara Server dan Klien untuk melanjutkan ke bagian berikutnya, di mana kami akan menuliskan replikasi inventaris dan mempertimbangkan bagaimana cara mengubahnya dengan benar.


PS Jika Anda melihat ada kesalahan atau kesalahan, silakan tulis di komentar.

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


All Articles