Veri yapısı bir ağ üzerinden senkronize nasıl tutulur?


12

bağlam

Üzerinde çalıştığım oyunda (bir tür nokta ve tıklama grafik macerası), oyun dünyasında gerçekleşen hemen hemen her şey, biraz yapılandırılmış bir eylem yöneticisi tarafından kontrol ediliyor:

resim açıklamasını buraya girin

Örneğin, bir nesneyi incelemenin sonucu karakterin merhaba demesini, biraz yürümesini ve sonra oturmasını sağlamalıysa, sadece aşağıdaki kodu doğururum:

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"));

Bu, yeni bir eylem grubu (yukarıdaki resimde tüm bir çizgi) oluşturur ve yöneticiye ekler. Tüm gruplar paralel olarak yürütülür, ancak her grup içindeki eylemler birlikte zincirlenir, böylece ikincisi yalnızca ilkinin bitmesinden sonra başlar. Bir gruptaki son eylem bittiğinde grup yok edilir.

Sorun

Şimdi bu bilgileri bir ağda çoğaltmam gerekiyor, böylece çok oyunculu bir oturumda tüm oyuncular aynı şeyi görüyor. Bireysel eylemlerin seri hale getirilmesi sorun değildir. Ancak ağ oluşturma konusunda mutlak bir acemiyim ve birkaç sorum var. Bence bu tartışmada basitlik adına eylem yöneticisi bileşenini basitçe özetleyebiliriz:

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

Yukarıdaki veri yapısının içeriğini tüm oyuncular arasında senkronize tutmak için nasıl ilerlemeliyim?

Temel sorunun yanı sıra, bununla ilgili başka endişelerim de var (yani aynı sorunun yukarıdaki tüm olası sonuçları):

  • Bir sunucu / istemci mimarisi kullanırsam (oyunculardan biri hem sunucu hem de istemci gibi davranıyorsa) ve istemcilerden biri doğrudan yöneticiye eklemesi veya yalnızca istek göndermesi durumunda bir grup eylem oluşturduysa sunucuya hangi sırayla her müşteriye bu grubu eklemesini emreder ?
  • Paket kayıpları ve benzerleri ne olacak? Oyun belirleyicidir, ancak bir istemcide gerçekleştirilen eylemler dizisindeki herhangi bir tutarsızlığın dünyanın tutarsız durumlarına yol açabileceğini düşünüyorum. Bu tür bir soruna karşı nasıl korunurum ?
  • Aynı anda çok fazla eylem eklersem, bu bağlantı için sorunlara neden olmaz mı? Bunu hafifletmenin bir yolu var mý?

5
Zorunlu "önce bu oku" bağlantısı gafferongames.com/networking-for-game-programmers bazı kodlara rağmen çok teknik değil ama garip ve seçeneklerinizi oldukça iyi açıklıyor. Ayrıca sizi bu bağlantıyı okuyan herkesle eşit bir yere koyacaktır ve bu mutlu bir yer.
Patrick Hughes

@PatrickHughes Bağlantı için teşekkürler! Kesinlikle hepsini okuyacağım.
David Gouveia

Bu tür şeyleri sizin için yöneten bazı paketler var. Ne kadar verimli veya hızlı olduğunu bilmiyorum, ama NowJS ( nowjs.com ) ilginç bir örnek. Geliştiriciler açısından, istemci ve sunucu arasında paylaşılan veri yapılarına sahip olmanız yeterlidir. Birini, diğerini değiştirin.
Tim Holt

Yanıtlar:


9

Bir sunucu / istemci mimarisi kullanırsam (oyunculardan biri hem sunucu hem de istemci gibi davranıyorsa) ve istemcilerden biri doğrudan yöneticiye eklemesi veya yalnızca istek göndermesi durumunda bir grup eylem oluşturduysa sunucuya hangi sırayla her müşteriye bu grubu eklemesini emreder?

Bu durumda, daha önce bahsettiğiniz üç seçeneğiniz var. Hangi seçeneği alacağınız seçimi, yalnızca en iyi yargıç olabileceğiniz çeşitli faktörlere bağlıdır:

1: İstemci eylem grubunu doğurur ve bunları doğrudan ekler ve ardından sunucuya gönderir. Sunucu herhangi bir kontrol yapmadan kabul eder

* Bu yaklaşımın faydaları, müşteri açısından, kendi eylemlerinin ağ gecikmesinden bağımsız olarak anında bir geri bildirim vermesidir. Dezavantajı, istemcinin iletilerinin sunucu tarafından gerçek olarak kabul edilmesidir (olmayabilir) *

2: İstemci, sunucuya bir istek gönderir; bu da isteği, isteği oluşturan istemci de dahil olmak üzere herkese yayınlar.

Bu yaklaşımın faydaları, sunucunun artık yasa dışı etkinlikle ilgili çoğu sorunu hafifleten oyunda gerçekleşen her şeyin kontrolünde olmasıdır (burada yasadışı, istemcinin bir duvarı kırpmasından, artık yasadışı olan bir hamleyi gerçekleştirmeye kadar değişebilir. belirli bir hamle yaptığında müşterinin sahip olmadığı daha fazla bilgi)

3: İstemci eylem grubunu oluşturur, doğrudan ekler ve ardından sunucuya gönderir. Sunucu isteği işler, yasadışı olmadıklarından emin olmak için eylemler üzerinde kendi denetimlerini yapar ve ardından hamleyi müşteri de dahil olmak üzere tüm oyunculara yayınlar.

Bu, 1 ve 2'nin en iyisini, biraz daha fazla bant genişliği gereksinimi pahasına alır. Faydaları, kendi hamleleri için istemciye anında geri bildirimdir ve istemcinin yaptığı hamleler yasa dışı ise, sunucu uygun eylemleri gerçekleştirir (istemciyi zorla düzeltir).

Paket kayıpları ve benzerleri ne olacak? Oyun belirleyicidir, ancak bir istemcide gerçekleştirilen eylemler dizisindeki herhangi bir tutarsızlığın dünyanın tutarsız durumlarına yol açabileceğini düşünüyorum. Bu tür bir soruna karşı nasıl korunurum?

Paket kaybı ve aşırı gecikme, düzeltilmesi zor bir sorundur . Oyunun türüne (örneğin ölü hesaplaşma) bağlı olarak problemle başa çıkmak için farklı çözümler (hiçbiri mükemmel değildir) kullanılır. Oyunun fizik senkronize etmek zorunda olmadığını varsayacağım.

Yapmanız gereken ilk şeylerden biri, tüm hareketlerinizi zaman damgası yapmaktır. Sisteminiz daha sonra bunları dikkate almalı ve hareketleri uygun şekilde oynamalıdır (belki de sunucu bu sorumluluğa sahiptir ve daha sonra yasadışı hareketleri reddetmelidir). Bu sistemi uygularken 0 gecikme olduğunu varsayın (yerel olarak test edin).

0 gecikme elbette, yerel ağlarda bile iyi bir varsayım değildir, bu yüzden şimdi tüm hareketler zamana saygı duyuyor, hangi saate güveniyorsunuz? Zaman senkronizasyonu konusu devreye giriyor. Çevrimiçi birçok makale / makale bu sorunu çözmenizde size rehberlik edecektir.

Aynı anda çok fazla eylem eklersem, bu bağlantı için sorunlara neden olmaz mı? Bunu hafifletmenin bir yolu var mý?

İlk önce bariz şeyler. Asla dizeleri veya serileştirilmiş nesneleri göndermeyin. Oyunun kendisi güncellendiği kadar hızlı mesaj göndermeyin. Bunları parçalar halinde gönderin (örneğin saniyede 10 kez). Sunucu / istemcinin hataları arada bir düzeltmesi gereken bir hata (özellikle yuvarlama hatası) olacaktır (bu nedenle her saniye sunucu her şeyi [her şey = oyununuzdaki şeyleri doğru tutmak için önemli olan tüm veriler gönderir) durum] müşterinin durumunu düzeltmek için takıldığı ve / veya dikkate aldığı).DÜZENLEME: Meslektaşlarımdan biri UDP (eğer yapmanız gereken, çok fazla veri varsa) kullanıyorsanız ağ siparişi olmadığını söyledi. Saniyede 10'dan fazla paket göndermek, paketlerin sıra dışı gelen değişikliklerini artırır. Bu iddiaya atıf yapıp yapamayacağımı göreceğim. Bozuk paketlerin kendilerine gelince, bunları atabilir veya mevcut durumu düzeltmek için geçmişteki değişiklikleri işlemek üzere tasarlanmış olan sisteminizin ileti / taşıma sırasına ekleyebilirsiniz.

Çok az yer kaplayan bir şeye dayanan bir mesajlaşma sisteminiz olmalıdır. Yalnızca iki değeri olan bir şey göndermeniz gerekiyorsa, yalnızca bir bit gönderin. Yalnızca 256 hamle yapabileceğinizi biliyorsanız, imzasız bir karakter gönderin. Mesajları mümkün olduğunca sıkı bir şekilde paketlemek için çeşitli bit döndürme hileleri vardır.

Mesajlaşma sisteminiz büyük olasılıkla gelen bir mesajdan hareketleri kolayca çıkarmanızı sağlamak için çok sayıda numara kullanacaktır (burada ne demek istediğimi anlamadıysanız RakNet'e ve buradaki örneklere göz atmanızı öneririm).

Ben zaten sen olamayacağını biliyoruz eminim düzeltmek yüksekliği gecikme ve paket kaybı ile ortaya çıkan sorunlar ama onun etkileri daha az belirgin yapabilirsiniz. İyi şanslar!

EDIT: Patrick Hughes yukarıdaki bağlantı ile yorum bu cevabı eksik ve en iyi OP sorusuna özgü hale getirir. Bağlantılı konuları okumanızı şiddetle tavsiye ederim


Ayrıntılı yanıt için çok teşekkürler, bu neredeyse tüm endişelerimi kaplıyor. Söylediğin bölümle ilgili sadece bir soru so every second, the server sends everything ... which the client then snaps to. Bir kerede böyle büyük miktarda bilgi gönderebilir miyim? Makul bir maksimum boyut nedir?
David Gouveia

Makul bir gecikme gecikme getirmeyen bir sayı olacaktır :)) ... Bu cevabı aramadıklarını biliyorum ama bir sayı koymak istemiyorum çünkü oyununa aşina değilim.
Samaursa

Ayrıca, büyük bir parça göndermeniz gereken zor bir kural yok, bunu örnek olarak verdim.
Samaursa

@Samaursa - "UDP kullanıyorsanız [eğer yapmanız gereken, çok fazla veri varsa]" yorumuna katılmıyorum. Ağ programlamada yeni olduklarından, TCP sizin için en zor şeylerin çoğunu çok daha yavaş olmasıyla halleder. Onların durumunda bir darboğaz olana kadar TCP kullanırdım. Bu noktada, uygulamalarının ağı nasıl kullandığını daha iyi anlayacaklar, böylece UDP malzemelerini uygulamak daha kolay olurdu.
Chris

@Chris: Kabul etmeyeceğim :) ... TCP ve UDP kullanımı arasındaki karar (imo) geliştirme için Python ve C ++ 'ı seçme kararı gibidir. Teoride kulağa hoş gelebilir, ancak pratikte basitçe geçiş yapmak zor olacaktır (yine, bu imo).
Samaursa
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.