Zurück zum Blog

So beheben Sie Player Location Desync in UEFN und Unreal Engine Multiplayer

Veröffentlicht am 27. Februar 2026
So beheben Sie Player Location Desync in UEFN und Unreal Engine Multiplayer

Der Albtraum des Multiplayer Transform Desync

Jeder Multiplayer-Entwickler erlebt irgendwann den Moment, in dem der Netcode anfängt zu lügen. Du scriptest eine Sequenz, in der ein Spieler auf einem Stuhl sitzt, der Stuhl sich über die Map bewegt und auf dem Server alles perfekt aussieht. Doch sobald ein zweiter Client beitritt, zerbricht die Illusion. Client A sieht sich perfekt auf dem Stuhl reiten. Client B sieht den Stuhl wegfahren, während Client A eingefroren in der Luft am Startpunkt schwebt.

Dieses spezifische Phänomen – der uefn player location desync – ist ein bekannter Pain Point, wenn Player Inputs genutzt werden, um MoveTo-Befehle auf Props mit attached Players auszulösen. Der Server registriert die korrekte absolute Location, aber die simulated proxies (die Repräsentation des Spielers auf anderen Clients) erben den aktualisierten Transform nicht von ihrem Parent Prop.

Egal, ob du eine Custom Experience im Unreal Editor for Fortnite (UEFN) baust oder einen Standalone Dedicated Server in Unreal Engine 5 entwickelst: Zu verstehen, warum Attachment Replication fehlschlägt, ist entscheidend. In diesem Tutorial analysieren wir die Mechaniken von Network Dormancy, warum Attachments die Client-side Prediction stören und wie du den Replication Graph zwingst, deinen World State zu respektieren.

Warum Attachments Network Updates unterbrechen

Um den Desync zu fixen, musst du verstehen, wie Unreal Engine Actor Replication hierarchisch handhabt.

Wenn ein Character Actor an ein Prop attached wird (z. B. Sitzen in einem Chair Device), wird sein Transform relativ zum Parent Actor. In einer Netzwerkumgebung muss der Server entscheiden, wie er diese Daten effizient an 100 verschiedene Clients sendet. Um Bandbreite zu sparen, nutzt Unreal Engine aggressiv das Konzept der Network Dormancy.

Wenn ein Spieler im Stuhl sitzt und keinen direkten Movement Input mehr gibt, markiert der Replication Graph des Servers den Player Actor eventuell als dormant (ruhend). Der Server nimmt an: "Der Spieler bewegt sich nicht eigenständig, also muss ich keine Updates für ihn senden. Ich sende nur Updates für den sich bewegenden Stuhl."

Die Mathematik hinter dem Desync

Schauen wir uns die Zahlen an, die diesen Fehler verursachen:

  • Server Tick Rate: Typischerweise 30Hz in UEFN.
  • Prop NetUpdateFrequency: Standardmäßig oft 100 Updates pro Sekunde.
  • Character MinNetUpdateFrequency: Kann auf bis zu 2.0 sinken, wenn kein Input erkannt wird oder Dormancy eintritt.

Wenn du MoveTo auf dem Stuhl aufrufst, aktualisiert sich der Transform des Stuhls mit 30Hz. Da der attached Player jedoch dormant ist oder mit stark reduzierter Frequenz aktualisiert wird, erhalten die anderen Clients nie den RPC (Remote Procedure Call), der ihnen sagt, dass sie die relative Position des Spielers aktualisieren sollen. Das Ergebnis? Ein massiver visueller Desync.

Falls du Probleme mit anderen Variablen hast, die nicht synchronisiert werden, schau dir The Unreal Engine Multiplayer Sync Bug Ruining Your World States And How To Fix It an.

Schritt 1: Der UEFN Verse Workaround

In offiziellen UEFN Bug-Reports bemerkten Entwickler einen wichtigen Hinweis: Das Verlassen des Stuhls behebt das Problem.

Warum? Weil der Wechsel des Movement Mode von Custom (sitzend) zurück zu Walking den Server zwingt, die Network Dormancy zu flushen und ein hartes, absolutes Transform-Update an alle Clients zu senden.

Wir können diesen "Flush" programmatisch in Verse nachbauen, ohne dass der Spieler das Fahrzeug verlassen muss. Durch Manipulation des Player State oder einen Mikro-Teleport wecken wir den Replication Graph auf.

Hier ist eine Verse-Implementierung, die ein Prop bewegt und sicherstellt, dass der Transform des Spielers synchron bleibt:

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

prop_mover_device := class(creative_device):
    
    @editable TargetProp : creative_prop = creative_prop{}
    @editable ChairSeat : chair_device = chair_device{}
    
    # Bewegt das Prop und erzwingt ein Network Update für attached Players
    SyncMoveProp(NewLocation : vector3, NewRotation : rotation, Duration: float)<suspends>:void=
        # 1. Bewegung auf dem Server ausführen
        MoveResult := TargetProp.MoveTo(NewLocation, NewRotation, Duration)
        
        # 2. Workaround für den UEFN Player Location Desync
        # State Refresh erzwingen, um den Replication Graph zu wecken
        ForceNetworkUpdate()

    ForceNetworkUpdate():void=
        # Prüfen, ob ein Spieler im Stuhl sitzt
        if (SeatedAgent := ChairSeat.GetSeatedPlayer[]):
            if (FortCharacter := SeatedAgent.GetFortCharacter[]):
                # Aktuellen absoluten Transform abrufen
                CurrentTransform := FortCharacter.GetTransform()
                
                # Charakter an exakt dieselbe Stelle teleportieren
                # Dies triggert einen sofortigen Broadcast des absoluten Transforms
                # an alle Proxy-Clients und löst den visuellen Desync.
                FortCharacter.TeleportTo[CurrentTransform.Translation, CurrentTransform.Rotation]
                Print("Forced replication update for seated player.")

Durch TeleportTo auf dieselben Koordinaten ändern wir nichts am Gameplay, aber wir tricksen die C++ Engine aus, ein TeleportPhysics Flag zu setzen, was die Client-side Prediction für diesen Actor komplett zurücksetzt.

Schritt 2: Der Native Unreal Engine C++ Fix

Wenn du außerhalb von UEFN arbeitest und Zugriff auf den Source Code oder Standard Unreal Engine C++ hast, kannst du direkt das Networking API nutzen.

Wenn du einen Actor bewegst, an dem andere Actors attached sind, musst du dem Server explizit sagen, dass er diese wecken soll.

// Beispiel für Force Net Update in UE5 C++
void AMyVehicle::MoveVehicleAndSync(FVector NewLocation, FRotator NewRotation)
{
    // 1. Parent Actor bewegen
    SetActorLocationAndRotation(NewLocation, NewRotation);

    // 2. Alle attached Actors iterieren (z.B. sitzende Spieler)
    TArray<AActor*> AttachedActors;
    GetAttachedActors(AttachedActors);

    for (AActor* AttachedActor : AttachedActors)
    { 
        if (AMyGameCharacter* SeatedPlayer = Cast<AMyGameCharacter>(AttachedActor))
        { 
            if (SeatedPlayer->HasAuthority())
            { 
                // Actor wecken, falls er dormant wurde
                SeatedPlayer->FlushNetDormancy();
                
                // Sofortiges Replication Update für den nächsten Tick erzwingen
                SeatedPlayer->ForceNetUpdate();
                
                // Bei extremer Latency einen gezielten Client RPC senden
                SeatedPlayer->Client_ForceSetLocation(SeatedPlayer->GetActorLocation(), SeatedPlayer->GetActorRotation());
            }
        }
    }
}

// In MyGameCharacter.cpp
void AMyGameCharacter::Client_ForceSetLocation_Implementation(FVector NewLoc, FRotator NewRot)
{
    // ETeleportType::TeleportPhysics überschreibt Client Prediction
    SetActorLocationAndRotation(NewLoc, NewRot, false, nullptr, ETeleportType::TeleportPhysics);
}

Schritt 3: Persistenz im Backend

Den Live-Desync zu fixen ist nur die halbe Miete. Wenn dein Spiel eine persistente Welt hat, musst du sicherstellen, dass die korrekten absoluten Koordinaten in der Datenbank landen. Nutze immer den server-authoritative Transform nach einem forced Net Update.

Ein eigenes Backend für High-Frequency Saves zu bauen, dauert Wochen. horizOn bietet ein Backend-as-a-Service speziell für Game Developer. Mit horizOn sind Real-time State Persistence und Database Management vorkonfiguriert.

Mehr zu WebSockets statt REST findest du hier: Ditch Http Polling An Unreal Engine Websockets Tutorial For Real Time Backends.

5 Best Practices für Multiplayer Movement & Attachments

  1. Traue niemals dem Client-Attachment-State: Nutze immer server-authoritative RPCs zur Validierung.
  2. NetDormancy manuell verwalten: Rufe FlushNetDormancy bei aktiven Bewegungen explizit auf.
  3. Flache Hierarchien: Vermeide tiefe Verschachtelungen (Player -> Chair -> Train -> Platform).
  4. Hard RPCs für kritische Änderungen: Nutze Reliable NetMulticast für Mount/Dismount.
  5. Validierung beim Dismount: Prüfe serverseitig die Distanz beim Aussteigen.

Fazit

Multiplayer Desyncs entstehen oft durch aggressive Optimierungen der Engine. Durch das Verständnis von Network Dormancy kannst du proaktiv Updates via Verse oder C++ erzwingen. Übernimm die Kontrolle über deinen Replication Graph.

Willst du dein Backend skalieren? Teste horizOn kostenlos und verbinde deine Unreal Engine Dedicated Server in Minuten mit einer praxiserprobten Datenbank.