Retour au Blog

Corriger l'absence de l'option Clear Player Data dans Fortnite Creative : Resets Verse et récupération d'état via un Backend personnalisé

Publié le 18 juillet 2026
Corriger l'absence de l'option Clear Player Data dans Fortnite Creative : Resets Verse et récupération d'état via un Backend personnalisé Généré avec l'aide de l'IA

En bref

Ce tutoriel explique comment surmonter l'absence soudaine de l'option « Clear Player Data » dans Fortnite Creative en implémentant un système robuste de versioning de schéma directement dans Verse. Il détaille la configuration des paramètres locaux de l'UEFN pour le debug de la persistance, ainsi que les limites inhérentes à l'écosystème fermé d'Epic. Enfin, il présente l'intégration d'un backend externe comme [horizOn](https://horizon.pm) pour s'affranchir de ces contraintes et gérer la persistance de manière totalement indépendante.

Votre dernière map Fortnite Creative ou UEFN est prête. Vous avez refactorisé votre économie, repensé votre système de classes et optimisé votre gameplay loop. Mais au moment de publier, vous faites face à un cauchemar qui casse le moteur : l'option « Press Triangle to Clear Player Data » a disparu de l'écran de confirmation de publication. Vous êtes piégé. Vos joueurs chargent votre map avec des données de persistance obsolètes, ce qui provoque des stack overflows instantanés, des quêtes rompues et des désalignements d'état (state mismatches) provoquant le crash du jeu.

Ce problème précis empoisonne la vie des créateurs sur les forums de développeurs d'Epic, où l'absence soudaine du bouton de réinitialisation ne laisse aucune option dans l'interface utilisateur pour purger les états de production obsolètes. Lorsque le schéma de vos données de persistance joueur change, le Backend d'Epic tente de mapper les anciennes données sérialisées sur vos nouvelles structures. Si votre code n'est pas conçu pour gérer ces écarts de propriétés de manière propre, vous allez bloquer (bricker) l'état de jeu pour 100 % de vos joueurs de retour.

Dans ce tutoriel, nous allons analyser en détail les solutions techniques de contournement pour ce bug. Nous vous montrerons comment concevoir un système robuste de versioning de schéma en Verse, configurer les paramètres UEFN locaux pour effacer les états de test, et explorer comment des backends externes personnalisés peuvent vous affranchir des limites de la persistance sur plateforme fermée.

The Root Cause: Why Schemas Fail on Version Upgrades

Dans Fortnite Creative et Unreal Editor for Fortnite (UEFN), les données persistantes sont stockées dans l'infrastructure de base de données d'Epic à l'aide de structures weak_map. Une weak_map associe une instance de joueur à une classe personnalisée marquée du spécificateur <persistable>. Contrairement aux bases de données SQL ou documentaires classiques, la couche de stockage d'Epic n'exécute pas de pipeline de migration formel lorsque vous publiez une mise à jour. Au lieu de cela, elle tente de désérialiser la charge utile (payload) binaire présente dans la sauvegarde cloud du joueur pour l'injecter dans la définition actuelle de la classe Verse.

Lorsque vous supprimez une variable, renommez une propriété ou modifiez un type (par exemple, en passant un champ d'un int à un float), le désérialiseur rencontre une divergence. Selon la gravité du changement, cette divergence de schéma entraîne l'un des trois modes de défaillance suivants :

  • Silent Failures : Le runtime attribue des valeurs par défaut aux propriétés modifiées, réinitialisant la progression sans pour autant crasher.
  • State Corruption : L'application lit des états de mémoire non valides ou rencontre des structures de données inattendues, déclenchant des erreurs de logique ailleurs.
  • Severe Runtime Crashes : La map ne se charge pas, ou la Verse VM interrompt l'exécution car elle ne peut pas dépaqueter la map persistante.

Lorsque le bouton « Clear Player Data » de la console de publication disparaît, vous perdez la possibilité de faire table rase à l'échelle globale. Si un développeur apporte des modifications fondamentales à la structure de ses données de sauvegarde, le jeu est cassé.

The Manual Fix: Schema Versioning inside Verse

Puisque vous ne pouvez pas compter sur le portail de publication d'Epic pour effacer les données, vous devez implémenter un fallback au niveau logiciel. La stratégie est simple : introduire un suivi de version (version tracker) directement dans vos classes persistables. En comparant la version sauvegardée du joueur à la version active de l'application au démarrage de la session, vous pouvez identifier les sauvegardes obsolètes et les écraser avec des valeurs par défaut.

Voici une implémentation Verse prête pour la production qui met en place une couche de persistance contrôlée par version.

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 détaillée du script de versioning

Ce pattern repose sur une validation anticipée au sein de la méthode InitializePlayer. La logique étape par étape se déroule comme suit :

  1. Le contrôle d'entrée (Entry Check) : Lorsqu'un joueur rejoint la partie, le système interroge PlayerDataMap pour y chercher une instance existante de player_save_data.
  2. L'évaluation de la version (Version Assessment) : Si un état de sauvegarde existe, le moteur vérifie sa propriété SchemaVersion.
  3. Le déclencheur de migration (Migration Trigger) : Si la valeur SchemaVersion est inférieure à la propriété @editable TargetSchemaVersion du device, le script appelle ResetPlayerData(Player).
  4. L'écriture d'état (State Overwrite) : ResetPlayerData construit une nouvelle instance de player_save_data définie sur la nouvelle version TargetSchemaVersion et met à jour la map.

En incrémentant manuellement la valeur TargetSchemaVersion dans la configuration de votre device au sein d'UEFN, vous forcez la suppression des données cibles pour tous les joueurs lors de leur prochaine initialisation de session, rendant ainsi le bouton manquant de l'UI d'Epic sans importance.

Procédure de test étape par étape

Pour valider en toute sécurité ce script de migration lors de votre cycle de playtest, suivez ces étapes successives :

  1. Glissez-déposez votre persistence_manager_device personnalisé dans le viewport de votre niveau UEFN.
  2. Dans le panneau Details d'UEFN, définissez la valeur initiale de TargetSchemaVersion à 1.
  3. Lancez une session de jeu, accumulez du score ou de l'or, puis quittez la partie.
  4. De retour dans l'éditeur, modifiez le champ TargetSchemaVersion sur le device pour passer de 1 à 2.
  5. Lancez à nouveau la session. Observez la sortie de la console (console log) : 'Data version mismatch. Local: 1, Target: 2. Resetting player data.'
  6. Vérifiez que l'or et la progression de votre joueur ont été réinitialisés proprement sans faire crasher la Verse VM.

Local Development Settings: Bypassing Save Files during Iteration

Bien que le versioning du code au runtime résolve les problèmes sur les serveurs de production, il ajoute une friction indésirable pendant les playtests locaux. Augmenter manuellement le numéro de version dans UEFN à chaque fois que vous modifiez une fonctionnalité en cours de développement est fastidieux. Pour simplifier votre processus de debug, vous pouvez contourner complètement la persistance locale via les paramètres de votre éditeur.

Suivez ces étapes pour désactiver la persistance locale :

  1. Dans UEFN, accédez à Island Settings dans le panneau Outliner.
  2. Recherchez la sous-section User Options - Game Rules.
  3. Localisez le bouton de bascule Enable Persistence et désactivez-le.
  4. Si vous testez des boucles multijoueurs localement, ouvrez les Editor Preferences, accédez au menu In-Game Play, et cochez la case Clear Local Saved Data On Launch. Cela garantit que chaque simulation démarre avec un cache vide.

UEFN's Built-in Persistence Limitations

L'utilisation de la couche de persistance native de Verse s'accompagne de contraintes architecturales majeures. Même lorsque les options de nettoyage sur le cloud fonctionnent parfaitement, les développeurs restent soumis à des limites de plateforme strictes :

Pour les mini-jeux occasionnels, ces limites sont gérables. Mais pour les RPG persistants complexes, les shooters en direct ou les titres multiplateformes, dépendre uniquement de blocs de persistance propriétaires et fermés bloque vos possibilités de mise à l'échelle.

    # This keeps the server-side payload lightweight (under 240 bytes) 
    # while securing long-term storage off the Fortnite engine.

## Best Practices for Managing Game State Persistence

Que vous restiez sur les maps Verse natives ou que vous exploitiez une architecture de serveur externe, maintenir un cycle de vie de persistance stable est vital pour les jeux multijoueurs. Respectez ces principes pour protéger l'état de vos joueurs :

1. **Implémentez un versioning implicite dès le départ :** Incluez toujours un entier `SchemaVersion` dans votre structure initiale de données de sauvegarde. Même si vous n'envisagez pas de modifier votre schéma, disposer de cette clé de version dès le premier jour prévient toute corruption de données catastrophique à l'avenir.
2. **Appliquez des règles de validation d'état :** Lors de la lecture d'un état chargé, validez les plages (ranges) de chaque attribut. Si le nombre d'or sauvegardé d'un joueur est négatif ou dépasse la limite structurelle de votre map, réinitialisez cette propriété spécifique pour éviter les exploits d'économie.
3. **Minimisez la fréquence de sauvegarde :** Écrire dans le cloud coûte cher. Plutôt que de mettre à jour la base de données à chaque pièce ramassée, regroupez vos écritures (batching). Déclenchez des sauvegardes lors des moments clés, comme la fin d'un match, le passage de niveau d'un joueur ou lorsque le joueur quitte la session.
4. **Construisez des structures de fallback propres :** Ne laissez jamais une lecture échouée empêcher un joueur d'entrer dans le jeu. Si la désérialisation du payload de persistance échoue, basculez instantanément vers une structure d'état par défaut.
5. **Découplez le code de gameplay de la logique de stockage :** Gardez vos requêtes de stockage isolées dans un device gestionnaire de persistance (persistence manager) dédié. Vos devices d'armes, de progression et d'UI doivent interroger ce gestionnaire au lieu de faire des appels directs à la data map.

## Next Steps

Dépendre de l'UI de la console d'Epic pour gérer les migrations d'états critiques est un design pattern risqué. Lorsque l'option « Clear Player Data » fait défaut, le versioning au runtime dans Verse constitue votre première ligne de défense. Cependant, si votre jeu exige des sauvegardes haute fréquence, une télémétrie complexe ou un contrôle administratif complet, migrer votre base de données vers un backend dédié est la solution ultime.

---

Source : [clear players data button in creative 1](https://forums.unrealengine.com/t/clear-players-data-button-in-creative-1/2735737)