Retour au Blog

Corriger le bug AddItem à longue distance dans UEFN : résoudre les désynchronisations de réplication spatiale

Publié le 11 juin 2026
Corriger le bug AddItem à longue distance dans UEFN : résoudre les désynchronisations de réplication spatiale

En bref

Cet article analyse la cause racine du bug de distance AddItem dans UEFN, lié aux conflits entre la réplication réseau d'Unreal Engine et le spatial streaming basé sur World Partition. Il détaille comment le système de culling réseau empêche l'UI cliente de charger les assets des entités spawnées à longue distance. Enfin, trois stratégies de contournement natif en Verse sont proposées, ainsi qu'une solution de découplage via le backend horizOn pour éviter les limitations du moteur.

Vous spawnez un prefab d'item personnalisé en Verse, vous l'ajoutez à la hotbar du joueur et... rien. L'inventaire du joueur reste vide, ou l'icône de l'item s'affiche comme un carré blanc brisé. Mais dès que le joueur revient vers l'origine de la carte à {0.0, 0.0, 0.0}, l'item apparaît comme par magie. Si vous êtes confronté au uefn additem far distance bug, vous faites face à une collision entre le design de base de la réplication réseau d'Unreal Engine et les règles de spatial streaming de UEFN.

Comprendre le spatial streaming dans Fortnite Creative

Les cartes de Fortnite sont des environnements gigantesques qui doivent charger et décharger des composants dynamiques à la volée pour économiser de la mémoire. Pour maintenir la stabilité des ticks du serveur et des taux de rafraîchissement (framerate) élevés côté client, UEFN utilise un système de spatial streaming basé sur World Partition. Le serveur ne réplique tout simplement pas chaque actor à chaque client en permanence. À la place, la réplication est régie par des règles de pertinence réseau (network relevancy) qui déterminent quels paquets de données sont envoyés à quel joueur.

World Partition et Network Relevancy Distance

Sous les paramètres standards de Fortnite, la NetRelevancyDistance correspond au rayon à l'intérieur duquel un actor est répliqué pour un joueur. Si une entité est spawnée en dehors de cette bulle (généralement autour de 15 000 Unreal Units, soit 150 mètres), le serveur refuse d'envoyer ses données de réplication au client. Cette optimisation spatiale réduit les canaux de réplication actifs jusqu'à 80 % sur les cartes open-world. Cependant, cela signifie également qu'un client peut être complètement aveugle aux entités situées à des coordonnées éloignées.

Lorsqu'un joueur parcourt une carte, le client demande dynamiquement des cellules de grille au serveur. Si une entité est spawnée dans une cellule qui n'est pas encore chargée (streamed in) par le client du joueur, ce dernier ignore son existence. Ce culling permet d'économiser de la mémoire GPU précieuse et évite d'engorger le rendering pipeline avec des draw calls lointains.

Comment UEFN gère l'instanciation des entités

Dans UEFN, les prefabs d'items personnalisés sont composés d'une entité de base combinée avec des composants comme item_component, mesh_component et icon_component. Lorsque votre script Verse instancie l'un de ces prefabs, le serveur crée le conteneur de l'entité et ses sous-composants en mémoire. Cependant, la réplication physique de ces composants de rendu vers le client reste liée au transform spatial de l'entité. Si ce transform est trop éloigné du joueur, le client n'est jamais informé de l'existence des composants.

Décryptage du bug de distance AddItem

Le problème survient lorsque vous combinez le spawn d'entités spatiales avec le système d'inventaire du joueur. Le composant de hotbar d'inventaire est répliqué globalement car il est directement attaché au personnage du joueur. Lorsque vous appelez AddItem() à grande distance, vous créez une désynchronisation directe entre un conteneur globalement pertinent (globally relevant) et un asset soumis au spatial culling.

Étape par étape : anatomie de la boucle d'échec

Voyons en detail ce qui se passe sous le capot lors de cette désynchronisation :

  • Spawn : Un script Verse spawne un prefab d'item à des coordonnées éloignées, par exemple {X:=0.0, Y:=0.0, Z:=25000.0}.
  • Appel d'inventaire : Le script appelle immédiatement AddItem() sur le fort_inventory_weapon_hotbar_component du joueur.
  • Enregistrement de l'UI : L'UI d'inventaire côté client reçoit un événement de réplication indiquant qu'un nouvel item occupe l'emplacement de la hotbar.
  • Résolution nulle (Null Lookup) : Le client tente de résoudre la référence de l'item pour charger son icon_component afin de l'afficher.
  • Glitch visuel : Comme l'entité spawnée n'a pas été répliquée vers le client à cause du distance culling, la recherche échoue, affichant un emplacement vide.

Analyse technique : cycle de vie des composants UEFN et liaison UI

Dans UEFN, les composants comme mesh_component et icon_component sont directement liés aux rendering pipelines côté client. L'UI est construite à l'aide de widgets Slate UI qui récupèrent les icônes directement depuis l' icon_component des items présents dans la hotbar. Lorsque le composant de la hotbar subit un changement d'état (par exemple, l'ajout ou le retrait d'un item), il déclenche un événement de réplication interne. L'UI côté client écoute cet événement et redessine les emplacements de l'UI.

Cependant, le rafraîchissement de l'UI se produisant dès la réception de l'événement de réplication, le client tente d'accéder à la texture de l'icône à partir de l'entité d'item référencée. Si le canal de réplication de l'entité d'item n'a pas encore été ouvert, le pointeur de texture est invalide, provoquant le bug où l'item est manquant ou corrompu. Le système d'inventaire utilise des soft object references pour ses composants, ce qui lui permet d'échouer proprement (sans faire crasher le jeu) mais génère ce bug d'item invisible.

Lorsque la Slate UI côté client reçoit l'instruction de se mettre à jour, elle vérifie la référence de l'item. Si l'actor sous-jacent n'est pas encore chargé en streaming ou répliqué, le moteur d'UI du client est contraint d'allouer une représentation nulle ou un stub visuel. Cela entraîne des emplacements vides qui ne se remplissent que lorsque le canal de réplication est explicitement établi. Dans Unreal Engine standard, un développeur pourrait enregistrer manuellement un callback lors de la réplication de l'actor, mais l'API Verse de UEFN fait abstraction de cela, privant les développeurs d'un listener direct pour la réplication des composants.

Le comportement mystérieux à l'origine du monde {0.0, 0.0, 0.0}

Beaucoup de développeurs remarquent que le bug se résout de lui-même lorsque le joueur s'approche de l'origine des coordonnées à {0.0, 0.0, 0.0}. Dans le modèle de réplication d'Unreal Engine, les actors ayant des parents spatiaux non résolus ou des couches physiques non initialisées définissent par défaut leur transform répliqué sur l'origine. Cela fait de l'origine un point chaud pour les mises à jour de réplication en file d'attente. Lorsque le personnage du joueur s'approche de {0.0, 0.0, 0.0}, le moteur ouvre des canaux de réplication pour ces références non résolues, forçant le téléchargement des données de l'item.

Ce comportement est un comportement étrange mais connu du driver réseau d'Unreal Engine. Lorsque le spatial streaming ne parvient pas à résoudre le transform d'un actor répliqué, il réinitialise les coordonnées à leurs valeurs décimales par défaut. Comme le joueur passe généralement près de l'origine, ou parce que l'origine est toujours considérée comme pertinente pour certains actors gestionnaires globaux, le client finit par ouvrir le canal. Une fois ce canal ouvert, toutes les données de composants en attente se répliquent d'un coup, faisant apparaître subitement l'item.

Ce n'est pas la première fois que la réplication spatiale cause des maux de tête dans le développement de jeux multiplayer. Par exemple, la gestion des déplacements rapides des joueurs ou des déclencheurs à distance sur de grands terrains introduit fréquemment des erreurs de positionnement, comme détaillé dans notre guide pour comment corriger les désynchronisations de position des joueurs dans UEFN et le multiplayer Unreal Engine. De même, la propriété des composants (component ownership) peut s'emmêler lorsque des items sont transférés entre différents actors, un sujet que nous abordons en détail dans notre guide pour résoudre les multiplayer inventory nightmares and swapped actorcomponent owners in Unreal Engine.

Corrections au niveau du moteur et solutions de contournement

Pour résoudre le uefn additem far distance bug à l'aide des outils natifs, vous devez vous assurer que l'entité est pertinente (relevant) pour le client avant d'appeler les fonctions d'inventaire. Étant donné que UEFN n'expose pas de contrôles de réplication bas niveau directs (comme bAlwaysRelevant ou des groupes de pertinence manuels) à Verse, nous devons utiliser des astuces spatiales de contournement. Voici les trois approches les plus fiables pour résoudre ce problème.

Stratégie 1 : Ancrage sur le joueur local

La solution native la plus fiable consiste à spawner le prefab d'item directement aux coordonnées de translation actuelles du joueur cible. Le joueur se trouvant toujours dans sa propre bulle de network relevancy, le serveur réplique instantanément l'entité et ses composants vers le client. Une fois que le client a enregistré l'entité, vous pouvez exécuter AddItem() pour insérer l'item dans la hotbar en toute sécurité. Comme le système d'inventaire possède désormais l'item, sa réplication spatiale est ancrée au joueur, ce qui lui permet de se déplacer n'importe où sur la carte sans perdre les assets visuels de l'item.

Stratégie 2 : Allocation différée de l'état

Si la logique de votre jeu nécessite de spawner des items dans des coffres éloignés, vous devriez différer l'ajout de l'item à la hotbar. Au lieu d'appeler AddItem() immédiatement après le spawn de l'entité, attendez que le joueur se trouve sous un certain seuil de proximité du coffre. Vous pouvez gérer ce seuil à l'aide d'un trigger Verse personnalisé ou d'une boucle de vérification de distance. Dès que le joueur entre dans le rayon de pertinence (à moins de 10 000 unités), l'entité se réplique et vous pouvez déclencher le transfert d'inventaire en toute sécurité.

Stratégie 3 : Réinitialisation de l'UI côté client

Si vous ne pouvez pas éviter de spawner des items à distance, vous pouvez forcer l'UI du client à se redessiner une fois l'entité répliquée. Pour ce faire, vous pouvez écouter un événement personnalisé qui se déclenche lorsque le joueur s'approche de la zone de spawn. Dès que le joueur est assez proche pour que l'entité soit chargée (streamed in), le script Verse met à jour une variable d'état de l'UI répliquée. Cela force le widget HUD personnalisé à réévaluer les composants d'inventaire et à afficher les bonnes textures.

Implémentation du code Verse : spawn local sécurisé

Le script Verse suivant montre comment spawner un prefab d'entité personnalisé aux coordonnées exactes du joueur avant de l'ajouter à son inventaire. Cette approche contourne le problème de distance culling en forçant la réplication à se produire dans la bulle réseau active du joueur.

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

# Custom device to safely manage item spawning and inventory allocation
inventory_spawner_device := class(creative_device):

    # Reference to the custom item prefab asset
    @editable
    ItemPrefab : entity_prefab = entity_prefab{}

    # Triggers the item generation and addition to the player's inventory
    GiveItemToPlayer(Player : player) : void =
        if (FortChar := Player.GetFortCharacter[]):
            # Get the player's current location to bypass spatial culling
            PlayerLocation := FortChar.GetTransform().Translation
            
            # Spawn the item prefab directly at the player's position.
            # This guarantees that the entity falls within the client's network relevancy bubble.
            SpawnResult := SpawnEntity(ItemPrefab, PlayerLocation, IdentityRotation())
            
            if (SpawnedEntity := SpawnResult?):
                # Retrieve the item component from the spawned entity
                if (ItemComponent := SpawnedEntity.GetComponent(item_component[])):
                    # Get the player's hotbar inventory component
                    if (InventoryComponent := FortChar.GetInventoryComponent[fort_inventory_weapon_hotbar_component]):
                        # Safely add the item to the hotbar.
                        # Since the entity was spawned locally, the client has already replicated
                        # its icon_component and mesh_component, preventing desyncs.
                        InventoryComponent.AddItem(ItemComponent)
                        Print("Successfully added item to hotbar without desync.")
                    else: 
                        Print("Error: Could not locate fort_inventory_weapon_hotbar_component.")
                else:
                    Print("Error: Spawned entity is missing item_component.")
            else:
                Print("Error: Failed to spawn the entity prefab.")

Découpler les états d'inventaire avec horizOn

La gestion de ces solutions de contournement de réplication au niveau du moteur peut rapidement devenir fastidieuse, surtout à mesure que votre carte s'agrandit et que vous introduisez des mécaniques de gameplay complexes. Si votre jeu nécessite des inventaires persistants, une progression cross-match ou des systèmes d'échange (trading), s'appuyer sur la réplication physique des actors pour les états d'inventaire crée un goulot d'étranglement massif.

C'est là qu'un backend spécialisé comme horizOn devient inestimable.

Au lieu de spawner des entités physiques à des endroits éloignés simplement pour en extraire les données, horizOn vous permet de découpler l'état de votre jeu du pipeline de réplication (replication pipeline) des actors d'Unreal.

Lorsqu'un joueur obtient ou achète un item, le serveur de jeu effectue un appel API léger pour mettre à jour le profil du joueur sur horizOn. L'UI côté client lit cet état directement depuis le backend, affichant les items à l'aide d'assets statiques locaux sans avoir besoin de répliquer des actors sur le réseau.

Cette architecture élimine les désynchronisations liées à la distance, garantit que les données d'inventaire sont sauvegardées de manière sécurisée et réduit considérablement la charge réseau du serveur.

Best practices pour le networking haute performance dans UEFN

Si vous choisissez de gérer manuellement la réplication spatiale dans UEFN, suivez ces best practices du secteur pour minimiser la surcharge réseau et les désynchronisations :

  1. Toujours instancier localement : Gardez les spawners d'items temporaires à proximité des personnages des joueurs pour garantir une réplication immédiate.
  2. Implémenter des replis visuels (visual fallbacks) : Concevez vos widgets d'UI personnalisés pour afficher des icônes de substitution (placeholders) si les composants d'un item ne sont pas encore répliqués.
  3. Découpler les données du visuel : Utilisez des structs Verse pour gérer l'état logique des items (durabilité, quantité, stats) et n'utilisez des entités que pour la représentation visuelle.
  4. Limiter les opérations d'inventaire (throttle) : Évitez d'appeler AddItem() ou RemoveItem() en succession rapide, car les files d'attente de sérialisation réseau peuvent perdre des mises à jour sous forte charge.

Conclusion & prochaines étapes

Les bugs de réplication spatiale comme le uefn additem far distance bug montrent à quel point les limitations locales du moteur peuvent facilement perturber l'expérience de jeu. En comprenant le fonctionnement de la network relevancy et de World Partition dans UEFN, vous pouvez concevoir des flux de spawn plus intelligents qui maintiennent l'harmonie entre les états du client et du serveur. Pour les développeurs qui créent des jeux ambitieux nécessitant des états persistants, des profils de joueurs globaux et des systèmes économiques sécurisés, s'affranchir de la réplication au niveau du moteur est la solution ultime.

Prêt à faire évoluer votre backend multiplayer ? Essayez horizOn gratuitement ou consultez la documentation de l'API (API docs).


Source : Adding Item not working in far distance