Zurück zum Blog

Behebung der fehlenden „Clear Player Data“-Option in Fortnite Creative: Verse-Resets und Custom-Backend-State-Recovery

Veröffentlicht am 19. Juli 2026
Behebung der fehlenden „Clear Player Data“-Option in Fortnite Creative: Verse-Resets und Custom-Backend-State-Recovery

Kurz und knapp

Dieser Artikel befasst sich mit einem kritischen Fehler in Fortnite Creative/UEFN, bei dem die Option „Clear Player Data“ in der Publishing-Konsole verschwindet. Er beschreibt eine manuelle Lösung mittels Schema-Versionierung in Verse, um veraltete Save-States von Spielern beim Session-Start automatisch zu überschreiben. Zudem werden die Einschränkungen der nativen UEFN-Persistenz erläutert und externe Backend-Lösungen wie [horizOn](https://horizon.pm) als skalierbare Alternative für komplexere Multiplayer-Spiele vorgestellt.

Deine neueste Fortnite Creative- oder UEFN-Map ist startbereit. Du hast deine Economy refaktoriert, dein Klassensystem überarbeitet und deinen Gameplay-Loop optimiert. Doch beim Veröffentlichen stoßt du auf einen Albtraum, der die Engine lahmlegt: Die Option „Press Triangle to Clear Player Data“ ist vom Bestätigungsbildschirm verschwunden. Du sitscht in der Falle. Deine Spieler laden deine Map mit veralteten Persistence-Daten, was zu sofortigen Stack Overflows, fehlerhaften Questreihen und Spielabstürzen durch State-Mismatches führt.

Genau dieses Problem plagt Creator in den Entwicklerforen von Epic, wo das plötzliche Fehlen des Reset-Buttons keinen UI-basierten Mechanismus zur Bereinigung veralteter Production-States übrig lässt. Wenn sich das Schema deiner Player-Persistence-Daten ändert, versucht das Backend von Epic, die alten serialisierten Daten auf deine neuen Strukturen abzubilden. Wenn dein Code nicht darauf ausgelegt ist, diese abweichenden Properties elegant abzufangen, zerschießt du den Game-State für 100 % deiner wiederkehrenden Spieler.

In diesem Tutorial tauchen wir tief in die technischen Workarounds für diesen Bug ein. Wir zeigen dir, wie du ein robustes Schema-Versionierungssystem in Verse aufbaust, lokale UEFN-Einstellungen konfigurierst, um Test-States zu löschen, und wie dich Custom-External-Backends von den Einschränkungen der Closed-Platform-Persistence befreien können.

Die Ursache: Warum Schemas bei Versions-Upgrades fehlschlagen

In Fortnite Creative und dem Unreal Editor for Fortnite (UEFN) werden persistente Daten in der Datenbank-Infrastruktur von Epic mithilfe von weak_map-Strukturen gespeichert. Eine weak_map verknüpft eine Player-Instanz mit einer benutzerdefinierten Klasse, die mit dem <persistable>-Spezifizierer gekennzeichnet ist. Im Gegensatz zu traditionellen SQL- oder Dokumenten-Datenbanken führt der Storage-Layer von Epic keine formelle Migrations-Pipeline aus, wenn du ein Update veröffentlichst. Stattdessen versucht er, den binären Payload aus dem Cloud-Save des Spielers in die aktuelle Verse-Klassendefinition zu deserialisieren.

Wenn du eine Variable löschst, eine Property umbenennst oder einen Typ änderst (z. B. ein Feld von int in float), stößt der Deserializer auf einen Mismatch. Je nach Schweregrad der Änderung führt diese Schema-Divergenz zu einem von drei Fehlerzuständen (Failure-Modes):

  • Silent Failures: Die Runtime weist den geänderten Properties Standardwerte zu, was den Fortschritt ohnehin löscht, aber ohne Absturz.
  • State-Corruption: Die Anwendung liest ungültige Speicherzustände (Memory-States) oder stößt auf unerwartete Datenstrukturen, was an anderer Stelle zu Logikfehlern führt.
  • Schwere Runtime-Crashes: Die Map lädt nicht oder die Verse-VM stoppt die Ausführung, weil sie die persistente Map nicht entpacken kann.

Wenn der Button „Clear Player Data“ in der Publisher-Konsole verschwindet, verlierst du die Möglichkeit, die Daten global zurückzusetzen. Wenn ein Entwickler grundlegende Änderungen an seinem Save-Data-Layout vornimmt, ist das Spiel kaputt.

Der manuelle Fix: Schema-Versionierung in Verse

Da du dich nicht darauf verlassen kannst, dass das Publishing-Portal von Epic die Daten löscht, musst du einen Fallback auf Softwareebene implementieren. Die Strategie ist einfach: Füge direkt einen Versions-Tracker in deine persistierbaren Klassen ein. Indem du die gespeicherte Version des Spielers beim Session-Start mit der aktiven Anwendungsversion vergleichst, kannst du veraltete Spielstände identifizieren und mit Standardwerten überschreiben.

Hier ist eine produktionsbereite Verse-Implementierung, die einen versionsgesteuerten Persistence-Layer einrichtet.

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

# A simple persistable class representing our player save schema.
# Note: Classes tagged with <persistable> can only contain certain types like int, float, string, and maps.
player_save_data := class<persistable>:
    # The SchemaVersion tracks which generation of player data this struct belongs to.
    SchemaVersion : int = 0
    GoldCount : int = 0
    XP : int = 0
    HasCompletedTutorial : int = 0  # Using int as a boolean flag representation for older Verse constraints

# The persistence manager device handles loading, validating, and migrating player data.
persistence_manager_device := class(creative_device):

    # By updating this value in the Editor, we force a schema migration next time the game runs.
    @editable
    TargetSchemaVersion : int = 2

    # Map to store player data in memory
    var PlayerDataMap : weak_map(player, player_save_data) = map{}

    # Initialize the persistence logic for a joining player
    InitializePlayer(Player : player) : void =
        # Check if the player already has persistent data
        if (ExistingData := PlayerDataMap[Player]):
            # If the stored version is older than our target version, trigger a manual reset
            if (ExistingData.SchemaVersion < TargetSchemaVersion):
                Print("Data version mismatch. Local: {ExistingData.SchemaVersion}, Target: {TargetSchemaVersion}. Resetting player data.")
                ResetPlayerData(Player)
            else:
                Print("Loaded existing player data. Version: {ExistingData.SchemaVersion}")
        else:
            # If no data exists, initialize a new record with the current version
            Print("No player data found. Initializing new record.")
            ResetPlayerData(Player)

    # Re-initializes a player's record with default values at the current version
    ResetPlayerData(Player : player) : void =
        NewData := player_save_data:
            SchemaVersion := TargetSchemaVersion
            GoldCount := 0
            XP := 0
            HasCompletedTutorial := 0

        # Save the freshly initialized data block to the persistence map
        if (set PlayerDataMap[Player] = NewData):
            Print("Successfully saved fresh persistent data block.")

Analyse des Versionierungs-Skripts

Dieses Pattern basiert auf einer frühzeitigen Validierung innerhalb der InitializePlayer-Methode. Die Schritt-für-Schritt-Logik sieht wie folgt aus:

  1. Der Entry-Check: Wenn ein Spieler beitritt, fragt das System die PlayerDataMap nach einer vorhandenen Instanz von player_save_data ab.
  2. Die Versions-Prüfung: Wenn ein Save-State existiert, überprüft die Engine dessen SchemaVersion-Property.
  3. Der Migrations-Trigger: Wenn die SchemaVersion niedriger ist als die @editable-Property TargetSchemaVersion des Devices, ruft das Skript ResetPlayerData(Player) auf.
  4. State-Überschreibung: ResetPlayerData erstellt eine neue Instanz von player_save_data mit der neuen TargetSchemaVersion und aktualisiert die Map.

Indem du die TargetSchemaVersion in der Konfiguration deines Devices innerhalb von UEFN manuell erhöhst, erzwingst du einen gezielten Daten-Wipe für alle Spieler bei ihrer nächsten Session-Initialisierung. Dadurch wird der fehlende Epic-UI-Button irrelevant.

Schritt-für-Schritt-Testverfahren

Um dieses Migrations-Skript innerhalb deines Playtest-Zyklus sicher zu validieren, folge diesen Schritten nacheinander:

  1. Ziehe dein Custom-persistence_manager_device in das Viewport deines UEFN-Levels.
  2. Setze im Details-Panel von UEFN die anfängliche TargetSchemaVersion auf 1.
  3. Starte eine Play-Session, sammle etwas Score oder Gold und beende das Spiel.
  4. Aktualisiere zurück im Editor das Feld TargetSchemaVersion auf dem Device von 1 auf 2.
  5. Starte die Session erneut. Beobachte die Ausgabe im Console-Log: 'Data version mismatch. Local: 1, Target: 2. Resetting player data.'
  6. Überprüfe, ob das Gold und der Spielfortschritt deines Spielers sauber zurückgesetzt wurden, ohne die Verse-VM zum Absturz zu bringen.

Lokale Entwicklungseinstellungen: Umgehen von Save-Files während der Iteration

Während die Runtime-Codeversionierung Probleme auf Live-Servern löst, sorgt sie beim lokalen Playtesting für unerwünschte Friction. Die Versionsnummer in UEFN jedes Mal manuell zu erhöhen, wenn du ein in Arbeit befindliches Feature änderst, ist mühsam. Um deinen Debugging-Prozess zu optimieren, kannst du die lokale Persistenz über deine Editor-Einstellungen komplett umgehen.

Folge diesen Schritten, um die lokale Persistenz zu deaktivieren:

  1. Navigiere in UEFN zu den Island Settings im Outliner-Panel.
  2. Suche nach dem Unterabschnitt User Options - Game Rules.
  3. Suche das Toggle Enable Persistence und deaktiviere es.
  4. Wenn du Multiplayer-Loops lokal testest, öffne die Editor Preferences, gehe zum Menü In-Game Play und suche das Kontrollkästchen Clear Local Saved Data On Launch. Wenn du dieses aktivierst, startet jede Simulation mit einem leeren Cache.

Lokale Bypasses simulieren jedoch keine Produktionsszenarien. Während die Iterationsgeschwindigkeit beim Testen mit deaktiviertem Persistence-Caching von 45 Sekunden auf unter 5 Sekunden sinken kann, musst du mindestens einen vollständigen Staging-Zyklus mit aktivierter Persistenz durchführen, bevor du live gehst. Hier können sich Verbindungsprobleme häufen. Lokale Playtest-Setups sind berüchtigt für Treiberkonflikte, wodurch Entwickler wertvolle Zeit verlieren, wenn sie Unreal Engine-Netzwerktreiber bei UEFN-Session-Launch-Timeouts diagnostizieren.

UEFNs integrierte Persistence-Limitations

Die Nutzung des nativen Persistence-Layers von Verse bringt erhebliche architektonische Einschränkungen mit sich. Selbst wenn die Optionen zum Löschen in der Cloud perfekt funktionieren, sind Entwickler an strenge Plattform-Limits gebunden:

  • Storage-Budgets: Persistierbare Datenblöcke sind auf 12 KB pro Spieler und Session begrenzt. Das Überschreiten dieses Limits verhindert das Speichern des States.
  • Nur primitive Typen: Du kannst keine Custom-Klassen serialisieren, die nicht als <persistable> markiert sind, und du kannst keine Referenzen auf Game-Objects (wie creative_device oder dynamische Actors) speichern.
  • Keine externen Abfragen: Das System von Epic ist eine komplette Blackbox. Du kannst Spielerdaten nicht über ein externes Dashboard abfragen, User-States auf Exploits prüfen oder Datenbanken dynamisch migrieren.
  • Telemetry-Bottlenecks: Das Entwerfen komplexer Analytics-Dashboards in UEFN wird durch Einschränkungen bei der String-Länge stark ausgebremst. So kämpfen Entwickler beispielsweise ständig mit Restriktionen beim Knacken des UEFN-Analytics-Device-Event-Name-Limits von 32 Zeichen.

Für Gelegenheits-Minispiele sind diese Grenzen überschaubar. Aber für komplexe persistente RPGs, Live-Ops-Shooter oder plattformübergreifende Titel blockiert die ausschließliche Nutzung proprietärer Closed-Loop-Persistenz deinen Skalierungspfad.

Die Alternative des Architekten: Externe Datenbank-States mit horizOn

Um ein skalierbares Spiel zu entwickeln, das nicht durch plattformspezifische UI-Bugs oder proprietäre Datengrößen eingeschränkt ist, setzen Entwickler auf externe Backend-Architekturen. Anstatt Game-States in den lokalen Memory-Maps von Verse zu speichern, kann dein UEFN-Projekt über das http_client-Modul in Verse mit einer externen Datenbank kommunizieren.

Dieser Ansatz gibt dir die volle Kontrolle über den Player-Save-Cycle. Wenn du Player-Persistence-Daten löschen musst, musst du nicht nach einem fehlenden Button in einer Epic-Konsole suchen oder ein Code-Update aufspielen. Du kannst einfach ein administratives Datenbank-Skript ausführen oder auf einen einzigen Button in deinem Backend-Control-Panel klicken, um Spieler-Tabellen zu löschen, zu migrieren oder zu patchen.

Dies selbst zu bauen erfordert die Einrichtung von Load Balancern, Datenbank-Sharding und SSL-Zertifikatsverwaltung – problemlos 4 bis 6 Wochen Arbeit. Mit horizOn sind diese Backend-Dienste bereits vorkonfiguriert, sodass du dein Spiel veröffentlichen kannst, anstatt dich um deine Infrastruktur zu kümmern.

Indem du Player-States über horizOn leitest, wird dein Verse-Code zu einem einfachen Client, der States über saubere REST-Endpunkte liest und schreibt:

# Pseudocode showing HTTP-based state synchronization with [horizOn](https://horizon.pm)
sync_manager_device := class(creative_device):

    # Send player progress to [horizOn](https://horizon.pm) endpoint
    SavePlayerState(Player : player, SaveData : player_save_data) : void =
        # In a real environment, you construct a JSON payload and dispatch it
        # via the Verse http_client. This bypasses the 12KB local persistence limit.
        RequestURL := "https://api.horizon.pm/v1/players/{GetPlayerID(Player)}/state"
        Print("Dispatching persistent payload to [horizOn](https://horizon.pm) at: {RequestURL}")
        
        # This keeps the server-side payload lightweight (under 240 bytes) 
        # while securing long-term storage off the Fortnite engine.

Dieses Setup entkoppelt deinen Gameplay-Loop vollständig von den physischen Backend-Bugs der Plattform. Wenn ein Patch deine lokale Save-Kompatibilität beeinträchtigt, kannst du eine gezielte Schema-Migration in deiner horizOn-Datenbank in Echtzeit auslösen – ganz ohne Unterbrechung des Live-Game-Servers. So vermeidest du das Risiko, Live-Server wegen geringfügiger struktureller Anpassungen lahmzulegen.

Best Practices für das Management der Game-State-Persistenz

Egal, ob du bei nativen Verse-Maps bleibst oder eine externe Server-Architektur nutzt: Die Aufrechterhaltung eines stabilen Persistenz-Lebenszyklus ist für Multiplayer-Spiele unerlässlich. Halte dich an diese Prinzipien, um Spieler-States zu schützen:

  1. Implementiere implizite Versionierung frühzeitig: Integriere immer einen SchemaVersion-Integer in dein initiales Save-Data-Layout. Selbst wenn du nicht planst, dein Schema zu ändern, verhindert der Versions-Key von Tag eins an katastrophale Datenkorruption in der Zukunft.
  2. Erzwinge State-Validierungsregeln: Validiere beim Lesen des geladenen States die Wertebereiche jedes Attributs. Wenn die gespeicherte Goldanzahl eines Spielers negativ ist oder das strukturelle Limit deiner Map überschreitet, setze diese spezifische Property zurück, um Economy-Exploits zu verhindern.
  3. Minimiere die Speicherhäufigkeit: Das Schreiben in die Cloud ist teuer. Statt die Datenbank bei jedem eingesammelten Coin zu aktualisieren, solltest du deine Schreibvorgänge bündeln. Triggere Speichervorgänge bei wichtigen Meilensteinen wie dem Match-Abschluss, einem Spieler-Level-up oder wenn der Spieler die Session verlässt.
  4. Erstelle saubere Fallback-Strukturen: Erlaube niemals, dass ein fehlgeschlagener Lesevorgang einen Spieler daran hindert, das Spiel zu betreten. Wenn der Deserialisierungsprozess des Persistence-Payloads fehlschlägt, weiche sofort auf eine Standard-State-Struktur aus.
  5. Entkopple Gameplay-Code von der Storage-Logik: Halte deine Storage-Abfragen in einem dedizierten Persistence-Manager-Device isoliert. Deine Waffen-, Progressions- und UI-Devices sollten dieses Manager-Device abfragen, anstatt direkte Aufrufe an die Data-Map zu tätigen.

Nächste Schritte

Sich bei kritischen State-Migrationen auf das Epic-Konsolen-UI zu verlassen, ist ein riskantes Design-Pattern. Wenn die Option „Clear Player Data“ fehlschlägt, dient die Runtime-Versionierung in Verse als deine erste Verteidigungslinie. Wenn dein Spiel jedoch hochfrequente Speichervorgänge, komplexe Telemetrie oder vollständige administrative Kontrolle erfordert, ist die Migration deiner Datenbank auf ein dediziertes Backend die ultimative Lösung.

Bereit, dein Multiplayer-Backend zu skalieren? Teste horizOn kostenlos oder wirf einen Blick in die API-Docs.


Quelle: clear players data button in creative 1