Kafayı yiyecektim. Network kodu yazmak zaten başlı başına bir dert, bir de üstüne "gerçek zamanlı" ve "adil" bir oyun deneyimi için lag compensation yazmaya kalktım. Meğer cehennemin kapısını aralamışım.
Hedefi Vurduk, Ama Nasıl?
Şöyle bir senaryo: Oyuncu A, 100ms ping ile oynuyor. Oyuncu B'yi görüyor, ateş ediyor ve vuruyor. Ancak sunucuya giden paketlerde gecikme var. Sunucu, ateş etme anındaki dünyanın durumunu geriye sararak (rewind) hesaplama yapmazsa, Oyuncu B aslında çoktan kaçmış olacak ve vurulmayacak. Bu da yüksek pinglilerin oynayamaması demek.
İşte bu "geri sarma" işlemi beni bitirdi. Client-side prediction, server reconciliation, entity interpolation... Her biri ayrı bir canavar. Unity'de Netcode for GameObjects ile uğraşıyordum ve şu basit gibi görünen mantık için saatlerce debug ettim:
Zaman Makinesi Yapmak
Lag compensation, özünde bir zaman makinesi kurmak demek. Sunucuda, her oyuncu için geçmiş konum ve durum bilgilerini bir süreliğine saklaman lazım. Sonra bir vuruş isteği geldiğinde, "Bu atış, 150ms önceki dünyada nereyi vururdu?" diye bakacaksın.
Buffer'ı ne kadar tutacaksın? 500ms? 1 saniye? Bellek tüketimi artar. 100ms? Yüksek pingliler ezilir. Optimizasyon ile adalet arasında kaldım. Bir de "peki bu geri sarılmış dünyada, diğer oyunculardan gelen diğer etkileşimleri de hesaba katıyor muyum?" sorusu var. O noktada kafamdaki tüm state machine'ler çöktü.
En Korkuncu: "Ama Ben Onu Vurdum!" Bug'ı
Test aşamasında en çok bu feedback'i aldım: "Client'te kesin vurdum gördüm, ama hasar gitmedi!". İşte bu, lag compensation'un düzgün çalışmadığı veya client prediction ile sunucu authoritatif durumun tutarsızlaştığı an. Debug loglarına boğuldum, paketleri sniff'ladım, Wireshark ile bakarken gözlerim kan çanağına döndü. StackOverflow'da bile net bir çözüm bulamadım, çünkü her oyunun network modeli biraz farklı.
Sonunda meğerse basit bir şeyi atlamışım: Silahın mermi hızı (projectile speed) ile oyuncunun ping'ini birlikte hesaplarken, sunucudaki geri sarma miktarına eklemeyi unutmuşum. Şaka gibi ama, iki satırlık bir hesaplama 3 gece uykumu aldı.
Neyse ki, bir şekilde çalışır hale getirdim. Ama şunu anladım: Network programlama, özellikle de gerçek zamanlı oyunlarda, %50 matematik ve mantık, %50 ise psikoloji ve sabır işi. Sürekli "acaba şimdi ne oldu?" diye sorgulamak, ruh halini alt üst ediyor.
Siz de benzer bir network kabusu yaşadınız mı? Özellikle FPS türünde lag compensation için kullandığınız, ruhu daha az yıpratan bir kütüphane veya metodunuz var mı? Yoksa siz de kendi çarkınızı kendiniz mi yontuyorsunuz? Yorumlara yazın, dertleşelim.
Şöyle bir senaryo: Oyuncu A, 100ms ping ile oynuyor. Oyuncu B'yi görüyor, ateş ediyor ve vuruyor. Ancak sunucuya giden paketlerde gecikme var. Sunucu, ateş etme anındaki dünyanın durumunu geriye sararak (rewind) hesaplama yapmazsa, Oyuncu B aslında çoktan kaçmış olacak ve vurulmayacak. Bu da yüksek pinglilerin oynayamaması demek.
İşte bu "geri sarma" işlemi beni bitirdi. Client-side prediction, server reconciliation, entity interpolation... Her biri ayrı bir canavar. Unity'de Netcode for GameObjects ile uğraşıyordum ve şu basit gibi görünen mantık için saatlerce debug ettim:
C#:
// Şaka gibi ama, bu timestamp karşılaştırması 2 günümü yedi.
if (serverTime <= shotInfo.hitTime)
{
// Geri sar ve kontrol et...
}
Lag compensation, özünde bir zaman makinesi kurmak demek. Sunucuda, her oyuncu için geçmiş konum ve durum bilgilerini bir süreliğine saklaman lazım. Sonra bir vuruş isteği geldiğinde, "Bu atış, 150ms önceki dünyada nereyi vururdu?" diye bakacaksın.
Buffer'ı ne kadar tutacaksın? 500ms? 1 saniye? Bellek tüketimi artar. 100ms? Yüksek pingliler ezilir. Optimizasyon ile adalet arasında kaldım. Bir de "peki bu geri sarılmış dünyada, diğer oyunculardan gelen diğer etkileşimleri de hesaba katıyor muyum?" sorusu var. O noktada kafamdaki tüm state machine'ler çöktü.
Test aşamasında en çok bu feedback'i aldım: "Client'te kesin vurdum gördüm, ama hasar gitmedi!". İşte bu, lag compensation'un düzgün çalışmadığı veya client prediction ile sunucu authoritatif durumun tutarsızlaştığı an. Debug loglarına boğuldum, paketleri sniff'ladım, Wireshark ile bakarken gözlerim kan çanağına döndü. StackOverflow'da bile net bir çözüm bulamadım, çünkü her oyunun network modeli biraz farklı.
Sonunda meğerse basit bir şeyi atlamışım: Silahın mermi hızı (projectile speed) ile oyuncunun ping'ini birlikte hesaplarken, sunucudaki geri sarma miktarına eklemeyi unutmuşum. Şaka gibi ama, iki satırlık bir hesaplama 3 gece uykumu aldı.
Neyse ki, bir şekilde çalışır hale getirdim. Ama şunu anladım: Network programlama, özellikle de gerçek zamanlı oyunlarda, %50 matematik ve mantık, %50 ise psikoloji ve sabır işi. Sürekli "acaba şimdi ne oldu?" diye sorgulamak, ruh halini alt üst ediyor.
Siz de benzer bir network kabusu yaşadınız mı? Özellikle FPS türünde lag compensation için kullandığınız, ruhu daha az yıpratan bir kütüphane veya metodunuz var mı? Yoksa siz de kendi çarkınızı kendiniz mi yontuyorsunuz? Yorumlara yazın, dertleşelim.