Bir MMORPG'yi tek oyunculu bir oyundan ayıran şey, arkada çalışan sunucudur. Ancient Online: Remastered geliştirme günlüğünün bu ilk bölümünde Unreal Engine 5.8 ile bir MMORPG'yi nasıl kurduğumuzu anlatıyoruz: İstemciyle sunucu arasında işleri nasıl paylaştırdık, dünyayı sunucuda nasıl çalıştırıyoruz ve tek parça dünyayı oyun açıkken nasıl düzenleyebiliyoruz?
İki parça: istemci ve sunucu
Ancient Online: Remastered iki ayrı yazılımdan oluşuyor:
- İstemci, yani oyuncunun cihazında çalışan oyun. Unreal Engine 5.8 üzerinde C++ ile yazıyoruz. Görüntü, ses, arayüz ve tuş girişleri onun işi.
- Sunucu, Unreal'dan bağımsız olarak C++23 ile sıfırdan yazdığımız program. Oyunun bütün kuralları burada çalışıyor.
Sunucuyu neden oyun motorunun içinde değil de ayrı yazdık? Çünkü bir MMORPG sunucusunun ihtiyaçları bir oyun motorununkinden farklı. Sunucuda grafik yok ama binlerce nesne, kalıcı veriler, haftalarca kesintisiz çalışma ve her an aynı kalması gereken bir performans var. Ayrı bir sunucuyla yalnızca gereken işi yapıyor ve gönderilen her baytı kontrol edebiliyoruz.
Son sözü sunucu söyler
Temel kuralımız şu: İstemci bir şey ister, sunucu karar verir.
- Hareket: Oyuncunun bastığı tuşlar sunucuya gider, konumu sunucu hesaplar. İstemci, sunucunun bildirdiği konumu yumuşak bir geçişle ekranda gösterir. Böylece kendini ışınlamaya ya da duvardan geçmeye çalışan bir hileli istemci, sunucunun gözünde yerinden kıpırdamaz.
- Dövüş: Hasar, isabet ve savrulma gibi sonuçları sunucu hesaplar. Örneğin bir kombo vuruşunun rakibi yere düşürüp düşürmeyeceğine sunucu karar verir ve sonucu herkese aynı anda gönderir.
- Ekonomi: Eşyalar, para ve market işlemleri yalnızca sunucuda ve veritabanında değişir.
Bunun bedeli, ağ gecikmesini iyi yönetmek zorunda olmamız. Karşılığında hile yapmanın çok daha zor olduğu ve herkesin aynı kurallarla oynadığı bir dünya elde ediyoruz.
Saniyede 25 adım
Sunucu dünyayı saniyede 25 kez günceller. Her adımda canavarların yapay zekâsı, hareket, dövüş, beceri etkileri ve hava durumu bir adım ilerler. Adım aralığının sabit olması sayesinde dünya her seferinde aynı şekilde işler; aynı girdi her zaman aynı sonucu verir.
Her oyuncunun dünyadaki her şeyi bilmesi gerekmiyor. Sunucu dünyayı karelere böler ve her oyuncuya yalnızca yakınındaki nesnelerle ilgili güncellemeleri gönderir. Böylece kalabalık bir şehirde bile ağ trafiği makul seviyede kalır.
Hafif, ikili bir protokol
İstemciyle sunucu arasında JSON ya da REST kullanmıyoruz. Her mesaj, düzeni önceden belli olan ikili (binary) bir paket. Bu hem internet bağlantısından hem de işlemciden tasarruf sağlıyor. Hava durumu, hareket ya da oyun içi hesap servisi gibi yeni bir sistem eklediğimizde onun için ayrı ve sürüm numarası olan bir paket tanımı yazıyoruz. İstemciyle sunucunun aynı tanımı kullandığından da ortak başlık dosyalarıyla emin oluyoruz.
Oyunu bekletmeden kaydetmek
Oyuncu verileri PostgreSQL veritabanında duruyor. Ama dünyanın her adımda veritabanını beklemesi kabul edilemez. Bu yüzden kayıtları arka planda yapıyoruz: Dünya sunucusu değişiklikleri bir sıraya (Redis) bırakıyor, arka plandaki bir yazıcı da bunları toplu hâlde veritabanına işliyor. Böylece oyunun akışı veritabanının hızına bağlı kalmıyor.
Kanallar ve giriş sunucusu
Oyuncular önce bir giriş sunucusuna bağlanıyor. Hesap doğrulama, karakter seçimi ve oturum burada yönetiliyor. Sonra dört oyun kanalından birine (CH1–CH4) geçiyorlar. Kanalların o anki durumu oyun sitesindeki sunucu durumu sayfasında görünüyor.
Tek parça dünya ve canlı düzenleme
Ancient Online: Remastered'ın dünyasını yükleme ekranlarıyla ayrılmış haritalar yerine tek parça, birleşik bir dünya olarak tasarladık. Dünya parçalara bölünüyor ve oyuncu ilerledikçe parça parça yükleniyor.
Dünyanın içeriği (arazi, nesneler, canavarların yerleri) kodun içinde değil, veritabanında sürüm sürüm tutuluyor. Bu dünyayı oyunun içindeki bir dünya editörüyle düzenleyebiliyoruz. Değişiklikleri önce bir taslakta yapıyor, kontrol ediyor, sonra yayınlıyoruz. Her yayın yeni bir sürüm oluşturuyor. İstemci, elindeki dünya verisinin sunucudakiyle aynı olup olmadığını kısa bir parmak izini (digest) karşılaştırarak kontrol ediyor. Aynı değilse oyuna devam etmeden önce verinin güncellenmesini bekliyor.
Görevler için Lua
Görevleri ve NPC konuşmalarını sunucuda Lua 5.4 ile yazıyoruz. Böylece görevleri, sunucuyu yeniden derlemeden geliştirip test edebiliyoruz.
Oyuncu mesajları dışarı çıkmıyor
Oyun içi sohbet çevirisi için dışarıdan bir çeviri servisi kullanmıyoruz. Kendi sunucularımızda, yalnızca işlemciyle çalışan bir çeviri modeli çalıştırıyoruz. Oyuncu mesajları hiçbir dış servise gönderilmiyor. Böylece farklı dil konuşan oyuncular, mesajları stüdyonun dışına çıkmadan birbirini anlayabiliyor.
Devamı
Günlüğün ikinci bölümü, aynı dünyayı fareyle, dokunmatik ekranla ve kumandayla oynanabilir yaparken verdiğimiz kararları anlatıyor. Stüdyoyu tanımak için Astronaut Entertainment kimdir? yazısına, oyunun kendisi için Oyunlar sayfasına bakabilirsiniz.


