Bloga Dön

Server Hop ve Harita Güncellemeleri Sırasında UEFN Verse Save Corruption Nasıl Önlenir?

Yayınlanma tarihi 1 Nisan 2026
Server Hop ve Harita Güncellemeleri Sırasında UEFN Verse Save Corruption Nasıl Önlenir?

Şunu hayal edin: UEFN projenize devasa bir harita güncellemesi yayınladınız. Oyuncular yeni içeriği görmek için akın ederken eşzamanlılık (Concurrency) tavan yapıyor. Ancak bir saat sonra Discord'unuz destek biletleriyle dolup taşıyor. Deneyimli oyuncular, 500 saatlik kayıt dosyalarının tamamen silindiğini görmek için giriş yapıyorlar.

Bu varsayımsal bir senaryo değil. Şu anda Unreal Editor for Fortnite (UEFN) platformunu etkileyen kritik bir motor seviyesi hatası mevcut: Oyuncular, tam yeni bir harita sürümü yayınlandığı sırada sunucu değiştirdiklerinde (Server Hop) tam veri kaybı yaşıyorlar.

Verse persistence sistemine güvenen geliştiriciler için bu uefn verse save corruption server hop zafiyeti tam bir kabus. UEFN kapalı bir ekosistem olarak çalıştığı için, kaybolan verileri geri yüklemek amacıyla backend veritabanına doğrudan erişemezsiniz. weak_map, oyuncunun kaydını boş bir durumla bir kez üzerine yazdığında, o oyun saatleri sonsuza dek gider.

Bu eğitimde, bu dağıtık veritabanı race condition durumunun tam olarak neden oluştuğunu, oyuncularınızı korumak için nasıl savunmacı Verse scriptleri tasarlayacağınızı ve bozuk üzerine yazmaları önlemek için save-state validation işlemlerini nasıl uygulayacağınızı inceleyeceğiz.

UEFN Server Hop Kayıt Silinmesinin Anatomisi

Sorunu düzeltmek için önce buna neden olan altyapı hatasını anlamalıyız. Epic Games, Verse persistence işlemlerini yönetmek için dağıtık bir backend kullanır. Bir oyuncu oyununuzla etkileşime girdiğinde, oturumu kendi persistence veri kaydı üzerinde bir kilit (Lock) tutar.

Bozulma, birbiriyle çakışan çok özel koşullar altında tetiklenir:

  1. Ağır Yazma Hacmi: Verse scripti verileri sık sık kaydedecek şekilde tasarlanmıştır (örneğin, bir oyuncu her altın topladığında kaydetmek, dakikada 50'den fazla yazma işlemiyle sonuçlanır).
  2. Güncelleme Çakışması: Oluşturucu, oyuncu aktif olarak eski sürümü (v1.0) oynarken haritanın yeni bir sürümünü (v1.1) yayınlar.
  3. Server Hop (Bağlantı Kesilmesi/Yeniden Bağlanma): Oyuncu v1.0 örneğinden ayrılır ve hemen yeni bir v1.1 örneğine katılır.

Race Condition

Oyuncu v1.0 sunucusundan ayrıldığında, sunucu son bir kaydetme işlemi başlatır. Ancak oyuncu hemen v1.1 sunucusuna bağlandığı için, yeni sunucu, v1.0 sunucusu yazma işlemini bitirip database lock kilidini serbest bırakmadan önce persistence verilerini okumaya çalışır.

Kilitli veya kısmen yazılmış bir veritabanı kaydıyla karşılaşan v1.1 sunucusunun Verse ortamı verileri yükleyemez. weak_map, fatal error verip oyuncuyu atmak yerine, yepyeni ve boş bir persistable sınıfı başlatır.

Oyun mantığınız bunun yeni bir oyuncu olduğunu varsaydığı için, bu boş durumu veritabanına geri yazmaya başlar. Oyuncu yeni sunucuda bir eşya topladığı anda, boş durum eski verilerin üzerine yazılır. Silinme artık kalıcıdır.

Adım 1: Savunmacı Verse Persistence Mimarisi

Çoğu UEFN kayıt sistemindeki temel kusur körü körüne güvendir. Geliştiriciler, weak_map boş bir sınıf döndürürse oyuncunun gerçekten yeni olduğunu varsayar. Bu paradigmayı Schema Versioning ve Sanity Checks uygulayarak değiştirmeliyiz.

Düz bir veri yapısı yerine, persistable sınıfınız bir sürüm izleyici ve bir başlatma bayrağı (initialization flag) içermelidir. Bir oyuncu bağlandığında verileri boşsa ancak ikincil kontrollerimiz yeni olmamaları gerektiğini gösteriyorsa, kaydetme yeteneklerini kilitleriz.

Kayıt Yükünün (Save Payload) Tasarlanması

Sürüm geçişlerinden sağ çıkmak ve yanlışlıkla üzerine yazmaları önlemek için kalıcı verilerinizi şu şekilde yapılandırmalısınız:

using { /Fortnite.com/Characters }
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Verse }

# 1. Sürümleme özelliğine sahip kalıcı sınıfı tanımlayın
player_save_data := class<persistable>:
    # Bu kayıt dosyasının şema sürümü
    SaveVersion<public>: int = 1
    
    # Bunun bozuk bir boş yükleme olmadığını onaylayan bayrak
    IsInitialized<public>: logic = false
    
    # Gerçek oyun verileri
    TotalGold<public>: int = 0
    PlayerLevel<public>: int = 1
    PlayTimeSeconds<public>: int = 0

# 2. weak_map tanımlayın
var PlayerDataMap: weak_map(player, player_save_data) = map{}

Adım 2: Güvenli Yükleme Doğrulamasının Uygulanması

Bir oyuncu sunucuya katıldığında, weak_map'ten aldığımız verileri dikkatlice değerlendirmemiz gerekir. Yükleme işlemi başarısız olursa veya bir harita güncellemesi sırasında şüpheli veriler dönerse, bozuk bir yazmayı önlemek için oyuncuyu sandbox'a almalıyız.

# Güvenli kaydetme ve yüklemeyi yöneten cihaz
safe_save_manager := class(creative_device):

    # Oyuncu oturuma katıldığında çağrılır
    OnPlayerJoined(Player: player): void=
        InitializePlayerState(Player)

    InitializePlayerState(Player: player): void=
        if (ExistingData := PlayerDataMap[Player]):
            # Veri mevcut. Doğrula.
            if (ExistingData.IsInitialized = true):
                Print("Oyuncu verileri başarıyla yüklendi. Sürüm: {ExistingData.SaveVersion}")
                # Oyuncuyu spawn etmeye devam et
            else:
                # KRİTİK: Veri mevcut ancak başlatılmamış. Bu bozuk bir durumdur.
                Print("UYARI: Bozuk durum tespit edildi. Kayıt yazma işlemi kilitleniyor.")
                LockPlayerSaving(Player)
        else:
            # Veri bulunamadı. Bu yeni bir oyuncu mu yoksa server hop race condition mı?
            # Geçici bir varsayılan durum atıyoruz ancak ilk yazmayı geciktiriyoruz.
            NewData := player_save_data{
                SaveVersion := 1,
                IsInitialized := true,
                TotalGold := 0,
                PlayerLevel := 1
            }
            
            # Veriyi map'e yerleştir
            if (set PlayerDataMap[Player] = NewData):
                Print("Yeni oyuncu profili oluşturuldu.")
            else:
                Print("Yeni oyuncu profili oluşturulamadı.")

Başlatma Bayrağının Önemi

IsInitialized := true gerektirerek bir failsafe oluşturuyoruz. Backend veritabanı, bir server hop kilidi nedeniyle verileri okuyamazsa ve tamamen sıfırlanmış bir bellek alanı döndürürse, IsInitialized varsayılan olarak false olacaktır. Scriptimiz bunu yakalar ve sistemin bu bozuk sıfır durumunu veritabanına geri yazmasını engeller.

Adım 3: Persistence Yazma İşlemlerini Sınırlama (Throttling)

Hata raporları, bozulmanın "ağır kaydetme" (heavy saving) nedeniyle şiddetlendiğini açıkça gösteriyor. Verse scriptiniz oyuncu her silah ateşlediğinde verileri kaydediyorsa, database lock kilidini neredeyse sürekli aktif tutuyorsunuz demektir. Bu, hızlıca bağlantı kesip yeniden bağlandıklarında bir çakışmayı garanti eder.

Bunu hafifletmek için bir Write-Throttling (Batching) sistemi uygulamalısınız. Her olayda kaydetmek yerine, verileri bellekte önbelleğe alın ve sabit bir aralıkla weak_map'e gönderin.

Kayıt Kuyruğu Oluşturma

    # Sınırlama değişkenleri
    SaveIntervalSeconds<private>: float = 60.0
    var ActivePlayers: []player = array{}

    OnBegin<override>()<suspends>:void=
        # Arka plan kayıt döngüsünü başlat
        spawn{ SaveLoop() }

    # Yazma işlemlerini her 60 saniyede bir toplu hale getiren arka plan döngüsü
    SaveLoop()<suspends>: void=
        loop:
            Sleep(SaveIntervalSeconds)
            
            for (ActivePlayer : ActivePlayers):
                if (PlayerData := PlayerDataMap[ActivePlayer]):
                    # Sadece veri geçerli olarak işaretlenmişse yaz
                    if (PlayerData.IsInitialized = true):
                        CommitSave(ActivePlayer, PlayerData)

    CommitSave(Player: player, Data: player_save_data): void=
        # Gerçek weak_map yazma işlemini burada gerçekleştirin
        if (set PlayerDataMap[Player] = Data):
            Print("Periyodik kayıt başarılı.")

Yazma sıklığınızı dakikada ~120'den dakikada sadece 1'e düşürerek, race condition olasılığını %99 oranında azaltırsınız. Bu sadece kaydetme için değil, genel sunucu sağlığı için de çok önemli bir kavramdır; tıpkı The Uefn Server Performance Exploit Explained Hard Armoring Your Unreal Engine Netcode kılavuzumuzda tartışılan stratejiler gibi.

Adım 4: Harita Güncellemeleri Sırasında Kademeli Azaltma

Epic sunucularının ne zaman bir harita güncellemesi yayınlayacağını kontrol edemediğiniz için oyuncuları uyaran UI öğeleri oluşturmalısınız.

Doğrulama scriptiniz bozuk bir yükleme tespit ederse (örneğin, IsInitialized = false), oyuncuya bir uyarı göstermek için bir HUD Message Device kullanmalısınız: "Kayıt Verileri Kilitlendi: Muhtemelen bir harita güncellemesi nedeniyle profiliniz yüklenirken bir sorun tespit ettik. Bu oturumdaki ilerlemeniz kaydedilmeyecek. Lütfen oyununuzu yeniden başlatın."

Bu, oyuncunun üç saat boyunca emek verip sonunda hiçbir şeyin kaydedilmediğini fark etmesini önlerken, aynı zamanda orijinal 500 saatlik kayıt dosyasının boş bir sayfa tarafından üzerine yazılmasını engeller.

Özel Backend Sistemlerine Geçiş

Opak, "kara kutu" bir altyapıyla uğraşmak UEFN geliştirmenin en zor kısmıdır. Epic'in persistence backend sistemi bir race condition yaşadığında, veritabanı günlüklerine erişiminiz olmaz, önceki bir snapshot'a geri dönme şansınız yoktur ve özel dağıtık kilitler uygulama yolunuz kapalıdır. Tamamen platformun insafına kalmış durumdasınız.

Bu kontrol eksikliği, birçok stüdyonun bağımsız ticari oyunları için sonunda UEFN'den özel Unreal Engine dedicated server sistemlerine geçmesinin tam nedenidir. Bağımsız bir ortamda, state synchronization sürecini siz kontrol edersiniz; bu da How To Fix Player Location Desync In Uefn And Unreal Engine Multiplayer makalesinde ele alınanlar gibi sorunlardan kaçınmanıza yardımcı olur.

Ancak, özel Unreal Engine oyununuz için dayanıklı ve kilit güvenli bir veritabanı oluşturmak; Redis kümeleri kurmayı, dağıtık kilitleri yönetmeyi, veritabanı sharding işlemlerini ve özel REST API'ler yazmayı gerektirir; bu da kolayca 4-6 haftalık özel backend mühendisliği işidir.

horizOn ile bu backend hizmetleri önceden yapılandırılmış olarak gelir. Altyapı race condition sorunlarıyla boğuşmak yerine, işlemsel veritabanlarına, gerçek zamanlı envanter yönetimine ve otomatik oyuncu verisi yedeklemelerine anında erişim sağlarsınız. Özel Unreal Engine projeleriniz için UEFN'de sahip olmayı dilediğiniz tam kontrolü kutudan çıktığı haliyle sunar.

UEFN Harita Güncellemeleri İçin 5 En İyi Uygulama

  1. Mevcut Değişken Türlerini Asla Değiştirmeyin: TotalGold v1.0'da bir int ise, sonsuza kadar int kalmalıdır. v1.1'de bunu float yapmak deserializer'ın hata vermesine neden olur.
  2. Ekleyin, Asla Silmeyin: Bir özelliği kaldırıyorsanız, değişkenini persistable sınıfınızdan silmeyin. Onu orada kullanımdan kaldırılmış (deprecated) bir alan olarak bırakın.
  3. Yazma İşlemlerinizi Sınırlayın (Throttle): Verileri asla yüksek frekanslı event listener'lar (örneğin OnWeaponFired) içinde kaydetmeyin.
  4. Kayıt Kilidi Uygulayın: Bir oyuncunun verileri yükleme sırasında sanity check kontrollerinden geçemezse, oturum süresince yazma yeteneğini hemen kilitleyin.
  5. Güncellemeleri Düşük CCU Sırasında Planlayın: Creator Portal analitiklerinize bakın. Eşzamanlı kullanıcı sayınızın (CCU) en düşük olduğu zamanı bulun ve harita güncellemelerini sadece o pencerede yayınlayın.

Sonuç

uefn verse save corruption server hop hatası, dağıtık backend mimarisinin gerçeklerinin sert bir hatırlatıcısıdır. Binlerce sunucu aynı anda açılıp kapanırken, veri kilitleri kaçınılmaz olarak başarısız olacaktır.

"Körü körüne güven" zihniyetinden "savunmacı programlama"ya geçerek oyuncularınızı feci veri kayıplarından koruyabilirsiniz. Şema sürümlemeyi uygulayın, yüklemelerinizi doğrulayın ve yazma işlemlerinizi sınırlayın.

Kara kutu veritabanlarının ötesine geçmeye ve kendi özel multiplayer backend sisteminizi ölçeklendirmeye hazır mısınız? horizOn'u ücretsiz deneyin ve oyuncu veri altyapınızın tam kontrolünü bugün elinize alın.