Bloga Dön

Multiplayer Desyncs: State Yapınızı Bozan Unreal Engine RPC Replication Issue Çözümü

Yayınlanma tarihi 3 Mart 2026
Multiplayer Desyncs: State Yapınızı Bozan Unreal Engine RPC Replication Issue Çözümü

Her multiplayer indie geliştiricisi, netcode'un kendilerine ihanet ettiği o anı çok iyi bilir. Bir silah kuşanmak için Run on Server RPC'si gönderirsiniz. Server logları silahın kuşandığını onaylar. Server'ın collision cylinder'ı sizi nişan alma duruşunda gösterir. Peki ya client ekranında? Karakteriniz varsayılan idle pozunda öylece duruyor, state değişikliğine tamamen tepkisiz.

Silah kuşanma mantığınız, nişan alma state'leriniz, envanter etkileşimleriniz ve crafting sistemleriniz client tarafında aniden güncellenmeyi bıraktığında panik başlar. RPC'yi Multicast olarak değiştirmenin görsel hataları sihirli bir şekilde düzelttiğini fark edebilirsiniz.

Sakın Multicast'te bırakmayın.

Kalıcı state (persistent state) hatalarını düzeltmek için Multicast kullanmak, sonunda oyununuzun network performansını yok edecek ve geç katılan (late-joining) oyuncular için deneyimi mahvedecek geçici bir çözümdür. Bu derinlemesine incelemede, korkulan unreal engine rpc replication issue'nun kök nedenini ortaya çıkaracak, server state'lerinizin neden client'ları görmezden geldiğini açıklayacak ve C++ kullanarak kurşun geçirmez, server-authoritative bir state sync mimarisi kuracağız.

Multicast Tuzağı: Neden "Çalışıyor" (Ve Neden Oyununuzu Mahvedecek)

Geliştiriciler bu hatayla karşılaştığında düşünce süreci genellikle şöyledir:

  1. Client Server_EquipWeapon() çağırır.
  2. Server silahı kuşanır.
  3. Client görseli güncellenmez.
  4. Server_EquipWeapon() fonksiyonunu Multicast_EquipWeapon() çağıracak şekilde değiştir.
  5. Client görseli güncellendi! Hata düzeldi, değil mi?

Yanlış. Nedenini anlamak için RPCs (Remote Procedure Calls) ve Property Replication arasındaki temel farkı anlamalısınız.

Bir RPC geçici bir ağ olayıdır. Boşluğa atılan bir çığlıktır. Eğer bir oyuncu Multicast ateşlendiğinde network cull distance içindeyse, çığlığı duyar ve kuşanma animasyonunu oynatır.

Peki bir oyuncu server'a 10 saniye sonra katılırsa ne olur? Ya da bir oyuncu 5.000 Unreal Unit uzaktaysa, relevancy range içine girip karakterinizi gördüğünde ne olur? Multicast geçmişte ateşlendiği için yeni client bu olayı asla almaz. Karakterinizi görünmez bir silah tutarken, idle pozunda kayarak hareket ederken ve göğsünden mermi sıkarken görürler.

Multicast geçici, oynanış için kritik olmayan olaylar içindir: bir patlama görseli, bir ses efekti veya kozmetik bir particle.

Zaman içinde kalıcı olan her şey için — hangi silahı tuttuğunuz, nişan alıp almadığınız veya envanterinizde ne olduğu gibi — mutlaka Property Replication kullanmalısınız.

Kök Neden: Neden Aniden Bozuldu?

Eğer Run on Server RPC'leriniz daha önce çalışıyor ve aniden birden fazla sistemde (silahlar, nişan alma, crafting) bozulduysa, muhtemelen projenizdeki şu üç mimari değişiklikten birinin kurbanısınız:

1. Listen Server vs. Dedicated Server İllüzyonu

Daha önce Play-In-Editor (PIE) içinde bir Listen Server kullanarak test yapıyorsanız, host oyuncu hem client hem de server'dır. Host tarafından yürütülen bir "Run on Server" RPC'si yerel görsel state'i anında günceller çünkü host zaten server'dır. Sonunda Dedicated Server testine geçtiğinizde (veya Client 2 olarak test ettiğinizde) illüzyon bozulur. Server kendi izole belleğini günceller ve client geride kalır.

2. Bozuk ActorComponent Ownership

Envanter veya silah mantığınızı yakın zamanda UActorComponent sınıflarına refactor ettiyseniz, replication zincirini bozmuş olabilirsiniz. RPC'ler client'lardan ancak client Actor'ün sahibiyse (owns) çağrılabilir. Eğer bileşeniniz dinamik olarak spawn edildiyse ve SetOwner(PlayerController) aracılığıyla açıkça bir sahip atanmadıysa, server RPC'yi görmezden gelir veya state'i geri replicate edemez. Bu mimari kabusu Multiplayer Inventory Nightmares Fixing Swapped Actorcomponent Owners In Unreal Engine rehberimizde detaylıca ele alıyoruz.

3. Yerel State'i Atlamak

Daha önce, client tarafındaki input event'iniz Server RPC'yi çağırmadan önce yerel bIsAiming boolean değerini ayarlıyor olabilir. Kodunuzu tamamen "Server Authoritative" (server'ın state'i belirlemesini beklemek) olacak şekilde refactor ettiyseniz ancak bu state'i client'a geri replicate etmeyi unuttuysanız, client'ınız asla gelmeyecek bir güncellemeyi sonsuza dek bekleyecektir.

Adım Adım Eğitim: Kurşun Geçirmez State Replication Mimarisi

Bu unreal engine rpc replication issue hatasını düzeltmek için RPC odaklı bir mimariden RepNotifies kullanan State-Driven Architecture yapısına geçmelisiniz.

İşte client'ı sorunsuz bir şekilde güncelleyen server-authoritative bir silah kuşanma ve nişan alma sisteminin doğru uygulanışı.

Adım 1: RepNotifies ile Replicated Property'leri Tanımlayın

Animasyonları tetiklemek için bir RPC'ye güvenmek yerine kalıcı değişkenler tanımlıyoruz. Server bu değişkenleri değiştirdiğinde, Unreal'ın Net Driver'ı bunları otomatik olarak client'larla senkronize eder. Bir ReplicatedUsing fonksiyonu (bir RepNotify) ekleyerek, client state değişikliğini öğrendiği anda animasyonları tetikleyebiliriz.

Character Header (.h) dosyanızda:

UCLASS()
class MYGAME_API AMyCharacter : public ACharacter
{
    GENERATED_BODY()

public:
    AMyCharacter();

    // Kalıcı state. Tüm client'lara replicate edilir.
    UPROPERTY(ReplicatedUsing = OnRep_EquippedWeapon)
    AWeapon* EquippedWeapon;

    UPROPERTY(ReplicatedUsing = OnRep_IsAiming)
    bool bIsAiming;

    // RepNotify fonksiyonları. Server değişkeni güncellediğinde client'ta çalışır.
    UFUNCTION()
    void OnRep_EquippedWeapon();

    UFUNCTION()
    void OnRep_IsAiming();

    // State değişikliklerini talep etmek için Server RPC'leri
    UFUNCTION(Server, Reliable, WithValidation)
    void Server_EquipWeapon(AWeapon* NewWeapon);

    UFUNCTION(Server, Reliable, WithValidation)
    void Server_SetAiming(bool bWantsToAim);

    // Temel replication kurulumu
    virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
};

Adım 2: Server RPC'lerini ve Replication Kurallarını Uygulayın

.cpp dosyanızda, bu değişkenleri GetLifetimeReplicatedProps içinde kaydetmelisiniz. Ardından, Server RPC'lerini yalnızca authoritative state'i güncelleyecek şekilde tanımlayın.

#include "MyCharacter.h"
#include "Net/UnrealNetwork.h"

void AMyCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
    Super::GetLifetimeReplicatedProps(OutLifetimeProps);

    // Bu değişkenleri tüm bağlı client'lara replicate et
    DOREPLIFETIME(AMyCharacter, EquippedWeapon);
    DOREPLIFETIME(AMyCharacter, bIsAiming);
}

// --- NİŞAN ALMA MANTIĞI ---

bool AMyCharacter::Server_SetAiming_Validate(bool bWantsToAim)
{
    // Anti-cheat: Oyuncunun nişan almasına izin verilip verilmediğini kontrol et
    return !bIsDead;
}

void AMyCharacter::Server_SetAiming_Implementation(bool bWantsToAim)
{
    bIsAiming = bWantsToAim;
    
    // KRİTİK: RepNotify'lar C++'da server üzerinde otomatik olarak çalışmaz.
    // Eğer server bir Listen Server ise, manuel olarak çağırmalıyız.
    if (GetNetMode() != NM_DedicatedServer)
    {
        OnRep_IsAiming();
    }
}

Adım 3: Görsel Güncellemeler için RepNotify'ları Uygulayın

Burada animasyon mantığınız, UI güncellemeleriniz ve mesh attachment'larınız yer alır. Bu, replicate edilen state'e dayandığı için, geç katılan oyuncular karakteriniz onlar için relevant olduğu anda bu mantığı otomatik olarak tetikleyecektir.

void AMyCharacter::OnRep_IsAiming()
{
    if (UAnimInstance* AnimInst = GetMesh()->GetAnimInstance())
    {
        if (UMyAnimInstance* MyAnim = Cast<UMyAnimInstance>(AnimInst))
        { 
            MyAnim->bIsAiming = bIsAiming;
        }
    }

    GetCharacterMovement()->MaxWalkSpeed = bIsAiming ? 300.f : 600.f;
}

void AMyCharacter::OnRep_EquippedWeapon()
{
    if (EquippedWeapon)
    {
        EquippedWeapon->AttachToComponent(GetMesh(), FAttachmentTransformRules::SnapToTargetNotIncludingScale, FName("WeaponSocket"));
        PlayAnimMontage(EquipMontage);
    }
}

Profesyonel Dokunuş: Client-Side Prediction

Eğer sadece yukarıdakileri uygularsanız, yeni bir sorunla karşılaşırsınız: Input Latency. 100ms pingi olan bir oyuncu nişan alma tuşuna bastığında, server'a ulaşıp replication'ın geri dönmesi 200ms sürer. Modern bir shooter oyununda bu berbat hissettirir.

Bunu düzeltmek için Client-Side Prediction uyguluyoruz. Client, görsel olarak state değişikliğini hemen simüle ederken aynı zamanda server'dan izin ister.

void AMyCharacter::StartAiming()
{
    // 1. Yerel olarak hemen tahmin et (Oyuncu için sıfır gecikme)
    bIsAiming = true;
    OnRep_IsAiming(); 

    // 2. Server'a resmiyet kazandırmasını söyle
    if (!HasAuthority())
    {
        Server_SetAiming(true);
    }
}

Eğer server reddederse, replicate edilen bIsAiming değeri false kalacak ve client sorunsuz bir şekilde nişan alma durumundan geri dönecektir. Bu, The Unreal Engine Multiplayer Sync Bug Ruining Your World States And How To Fix It makalemizde tartıştığımız sağlam multiplayer mimarisinin temelidir.

Maçın Ötesine Geçmek: Oyuncu State'ini Kalıcı Hale Getirmek

Oyun içi replication'ı düzeltmek, maç sırasında server ve client'ların dünya durumu üzerinde anlaşmasını sağlar. Peki maç bittiğinde veya dedicated server kapandığında o senkronize envanter ve silah verilerine ne olur?

Oyuncuların ürettikleri silahları veya kuşandıkları eşyaları korumalarını istiyorsanız, bu state'in Unreal Engine instance'ından çıkıp güvenli, ölçeklenebilir bir veritabanında yaşaması gerekir. Bunu kendiniz kurmak (load balancers, database sharding, REST API'ler) haftalar süren zahmetli bir backend altyapı çalışması gerektirir.

horizOn ile bu backend servisleri önceden yapılandırılmış olarak gelir. Oyuncunuzun verilerini yerel SDK'lar kullanarak doğrudan server'ınızdan buluta kaydedebilirsiniz. Altyapıyla uğraşmak yerine oyununuzu yayınlamaya odaklanın.

Unreal Engine Replication İçin 5 En İyi Pratik

  1. Kalıcı State İçin Asla Multicast Kullanmayın: Eğer bir değişken dünya durumunu (envanter, silah, can) tanımlıyorsa, Replicated Property olmalıdır. Multicast'i sadece görsel efektler için saklayın.
  2. Server'da RepNotify'ları Manuel Çağırın: C++'da OnRep_ fonksiyonları server üzerinde otomatik tetiklenmez. Listen Server kullanıyorsanız manuel çağırmalısınız.
  3. Server RPC'lerinizi Valide Edin: Client'a asla güvenmeyin. _Validate fonksiyonlarını kullanarak işlemin mantıklı olup olmadığını kontrol edin.
  4. NetUpdateFrequency Değerine Dikkat Edin: Görsel state rastgele gecikiyorsa, Actor'ün güncelleme sıklığını kontrol edin.
  5. Component Ownership Kontrolü Yapın: Bir UActorComponent içinden Server RPC çağırıyorsanız, bileşenin replicate edildiğinden ve sahibinin bir APlayerController olduğundan emin olun.

Net Driver ile Savaşmayı Bırakın

Unreal Engine'in replication sistemi güçlüdür ancak kurallarını çiğnemeye çalışırsanız affetmez. Client state'leriniz güncellenmediğinde Multicast kullanma isteğine direnin. Otorite yolunu izleyin: client talep eder, server emreder ve property replicate edilir.

Multiplayer oyununuzu bir üst seviyeye taşımaya hazır mısınız? Altyapı yönetimi hakkında endişelenmeyi bırakın. horizOn'u ücretsiz deneyin ve oyuncularınıza kalıcı ilerleme, güvenli envanterler ve sorunsuz matchmaking sunun.