Powrót do Bloga

Naprawa błędu UEFN AddItem Far Distance Bug: Rozwiązywanie desynchronizacji Spatial Replication

Opublikowano 11 czerwca 2026
Naprawa błędu UEFN AddItem Far Distance Bug: Rozwiązywanie desynchronizacji Spatial Replication

W skrócie

Artykuł szczegółowo omawia problem z uefn additem far distance bug, który powoduje niewidzialność przedmiotów dodawanych do ekwipunku z dużej odległości na skutek działania World Partition i limitów network relevancy. Wyjaśnia cykl życia komponentów w UEFN oraz mechanizm automatycznego resetowania współrzędnych niezreplikowanych obiektów do punktu zero `{0.0, 0.0, 0.0}`. Przedstawia trzy wbudowane strategie rozwiązania problemu oparte na lokalnym spawnowaniu, opóźnieniu przypisywania stanu oraz reinicjalizacji interfejsu. Jako ostateczne rozwiązanie proponuje decoupling stanu ekwipunku od replikacji Unreal Engine za pomocą zewnętrznego backendu horizOn.

Spawnujesz własny item prefab w Verse, dodajesz go do hotbaru gracza i... nic. Ekwipunek gracza pozostaje pusty lub ikona przedmiotu wyświetla się jako uszkodzony, biały kwadrat. Jednak gdy tylko gracz wraca w kierunku punktu startowego mapy {0.0, 0.0, 0.0}, przedmiot pojawia się jak za dotknięciem czarodziejskiej różdżki. Jeśli zmagasz się z uefn additem far distance bug, walczysz z podstawową architekturą network replication silnika Unreal Engine kolidującą z regułami spatial streaming w UEFN.

Zrozumienie Spatial Streaming w Fortnite Creative

Mapy Fortnite to ogromne środowiska, które muszą dynamicznie ładować i wyładowywać komponenty w locie, aby oszczędzać pamięć. Aby utrzymać stabilną częstotliwość ticków serwera (server ticks) i wysoką płynność na kliencie, UEFN wykorzystuje system spatial streaming oparty na World Partition. Serwer po prostu nie replikuje każdego actora do każdego klienta w każdym momencie. Zamiast tego replikacja jest kontrolowana przez reguły network relevancy, które określają, które pakiety danych są wysyłane do poszczególnych graczy.

World Partition i Network Relevancy Distance

Przy standardowych ustawieniach Fortnite, NetRelevancyDistance to promień, w którym actor jest replikowany do gracza. Jeśli encja (entity) zostanie zespawnowana poza tym obszarem (zazwyczaj około 15 000 Unreal Units lub 150 metrów), serwer odmawia przesłania jej danych replikacyjnych do klienta. Ta optymalizacja przestrzenna pozwala zmniejszyć liczbę aktywnych kanałów replikacji nawet o 80% na mapach typu open-world. Oznacza to jednak również, że klient może być całkowicie „ślepy” na encje znajdujące się na dalekich współrzędnych.

Gdy gracz przemieszcza się po mapie, klient dynamicznie żąda komórek siatki (grid cells) od serwera. Jeśli encja zostanie zespawnowana w komórce siatki, która nie jest aktualnie załadowana (streamed in) przez klienta gracza, klient nie wie o jej istnieniu. Taki culling pomaga oszczędzać cenną pamięć GPU i zapobiega dławieniu się rendering pipelines przy dalekich draw calls.

Jak UEFN obsługuje instancjonowanie encji

W UEFN własne prefaby przedmiotów (item prefabs) składają się z bazowej encji połączonej z takimi komponentami jak item_component, mesh_component oraz icon_component. Gdy Twój skrypt Verse tworzy instancję jednego z tych prefabów, serwer tworzy w pamięci kontener encji wraz z jego podkomponentami. Jednak fizyczna replikacja tych komponentów renderowania do klienta pozostaje powiązana ze spatial transform danej encji. Jeśli ten transform znajduje się zbyt daleko od gracza, klient nigdy nie zostanie poinformowany o istnieniu tych komponentów.

Dekonstrukcja AddItem Distance Bug

Problem pojawia się, gdy połączysz przestrzenne spawnowanie encji z systemem ekwipunku gracza. Komponent paska skrótów ekwipunku (inventory hotbar component) jest replikowany globalnie, ponieważ jest przypisany bezpośrednio do postaci gracza. Kiedy wywołujesz AddItem() z dużej odległości, tworzysz bezpośredni desynchron (desync) między kontenerem o zasięgu globalnym (globally relevant) a zasobem wyciętym przestrzennie (spatially culled asset).

Przebieg pętli błędów krok po kroku

Przyjrzyjmy się dokładnie, co dzieje się pod maską podczas tej desynchronizacji:

  • Spawning: Skrypt Verse spawnuje prefab przedmiotu na odległych współrzędnych, np. {X:=0.0, Y:=0.0, Z:=25000.0}.
  • Inventory Call: Skrypt natychmiast wywołuje AddItem() na należącym do gracza fort_inventory_weapon_hotbar_component.
  • UI Registration: Interfejs użytkownika ekwipunku po stronie klienta odbiera zdarzenie replikacji informujące, że nowy przedmiot zajmuje slot w pasku skrótów.
  • Null Lookup: Klient próbuje rozpoznać referencję przedmiotu, aby załadować jego icon_component na potrzeby renderowania.
  • Visual Glitch: Ponieważ zespawnowana encja nie została zreplikowana do klienta z powodu wycinania odległości (distance culling), wyszukiwanie kończy się niepowodzeniem, co skutkuje wyrenderowaniem pustego slotu.

Analiza szczegółowa: Cykl życia komponentów UEFN i UI Binding

W UEFN komponenty takie jak mesh_component i icon_component są powiązane bezpośrednio z rendering pipelines po stronie klienta. Interfejs użytkownika jest zbudowany przy użyciu widgetów Slate UI, które pobierają ikony bezpośrednio z icon_component przedmiotów znajdujących się aktualnie w pasku skrótów. Gdy komponent paska skrótów przechodzi zmianę stanu (np. dodanie lub usunięcie przedmiotu), wyzwala wewnętrzne zdarzenie replikacji. Interfejs użytkownika po stronie klienta nasłuchuje tego zdarzenia i odświeża sloty UI.

Ponieważ jednak odświeżenie UI następuje natychmiast po odebraniu zdarzenia replikacji, klient próbuje uzyskać dostęp do tekstury ikony z referowanej encji przedmiotu. Jeśli kanał replikacyjny encji przedmiotu nie został jeszcze otwarty, wskaźnik do tekstury (texture pointer) jest nieprawidłowy, co prowadzi do błędu polegającego na braku lub uszkodzeniu przedmiotu. System ekwipunku używa soft object references dla komponentów, co pozwala mu na bezpieczną obsługę błędów (tzn. nie powoduje crashu gry), ale skutkuje błędem „niewidzialnego przedmiotu”.

Gdy Slate UI po stronie klienta otrzyma instrukcję aktualizacji, sprawdza referencję przedmiotu. Jeśli powiązany actor nie został jeszcze załadowany (streamed in) lub zreplikowany, silnik UI po stronie klienta jest zmuszony przydzielić reprezentację null lub wizualny stub. Skutkuje to pustymi slotami, które zapełniają się dopiero po jawnej inicjalizacji kanału replikacji. W standardowym Unreal Engine programista mógłby ręcznie zarejestrować callback dla replikacji actora, ale API Verse w UEFN obecnie to ukrywa, pozostawiając deweloperów bez bezpośredniego listenera dla replikacji komponentów.

Tajemnicze zachowanie w punkcie zero mapy {0.0, 0.0, 0.0}

Wielu deweloperów zauważa, że błąd ustępuje, gdy gracz zbliża się do punktu zero na współrzędnych {0.0, 0.0, 0.0}. W modelu replikacji Unreal Engine actory z nierozpoznanymi spatial parents lub niezainicjalizowanymi warstwami fizycznymi (physics layers) domyślnie ustawiają swój zreplikowany transform na punkt zero. To sprawia, że punkt zero staje się centralnym miejscem dla zakolejkowanych aktualizacji replikacji. Kiedy postać gracza zbliża się do {0.0, 0.0, 0.0}, silnik otwiera kanały replikacji dla tych nierozpoznanych referencji, zmuszając dane przedmiotu do pobrania.

To zachowanie to znana specyfika sterownika sieciowego Unreal Engine. Gdy spatial streaming nie może rozpoznać transformu zreplikowanego actora, resetuje współrzędne do wartości domyślnych typu float. Ponieważ gracz zazwyczaj przechodzi w pobliżu punktu zero lub ze względu na to, że punkt zero jest zawsze uważany za istotny (relevant) dla określonych globalnych actorów menedżerskich, klient ostatecznie otwiera kanał. Gdy kanał jest otwarty, wszystkie oczekujące dane komponentów replikują się jednocześnie, sprawiając, że przedmiot nagle się pojawia.

To nie pierwszy raz, kiedy replikacja przestrzenna przysparza problemów przy tworzeniu gier multiplayer. Na przykład obsługa szybkiego poruszania się graczy lub zdalnych wyzwalaczy (triggers) na ogromnych terenach często wprowadza błędy pozycjonowania, o czym szczegółowo piszemy w naszym przewodniku o tym, jak naprawić player location desync w UEFN i Unreal Engine multiplayer. Podobnie, własność komponentów (component ownership) może ulec poplątaniu, gdy przedmioty są przekazywane między różnymi actorami. Temat ten dokładnie omawiamy w naszym artykule o rozwiązywaniu problemów z multiplayer inventory i zamienionymi właścicielami actorcomponent w Unreal Engine.

Rozwiązania i obejścia na poziomie silnika

Aby rozwiązać uefn additem far distance bug przy użyciu wbudowanych narzędzi, musisz upewnić się, że encja jest relevant dla klienta przed wywołaniem funkcji ekwipunku. Ponieważ UEFN nie udostępnia w Verse bezpośredniej kontroli nad niskopoziomową replikacją (taką jak bAlwaysRelevant czy ręczne grupy relevancy), musimy zastosować sprytne obejścia przestrzenne. Oto trzy najbardziej niezawodne podejścia do rozwiązania tego problemu.

Strategia 1: Local Player Anchoring

Najbardziej niezawodnym natywnym rozwiązaniem jest zespawnowanie przedmiotu (item prefab) bezpośrednio na aktualnych współrzędnych (translation coordinates) docelowego gracza. Ponieważ gracz zawsze znajduje się we własnej bańce net relevancy, serwer natychmiast replikuje encję i jej komponenty do klienta. Gdy klient zarejestruje encję, możesz wywołać AddItem(), aby bezpiecznie dodać przedmiot do paska skrótów. Ponieważ system ekwipunku przejmuje teraz własność nad przedmiotem, jego spatial replication jest powiązana (anchored) z graczem, co pozwala mu podróżować w dowolne miejsce na mapie bez utraty wizualnych zasobów przedmiotu.

Strategia 2: Delayed State Allocation

Jeśli logika Twojej gry wymaga spawnowania przedmiotów w odległych skrzyniach (chest locations), należy opóźnić dodanie przedmiotu do paska skrótów. Zamiast wywoływać AddItem() natychmiast po zespawnowaniu encji, odczekaj, aż gracz znajdzie się w określonej odległości (proximity threshold) od skrzyni. Możesz kontrolować tę granicę za pomocą własnego triggera w Verse lub pętli sprawdzającej odległość. Gdy gracz wejdzie w promień relevancy (poniżej 10 000 jednostek), encja zreplikuje się i będziesz mógł bezpiecznie zainicjować transfer do ekwipunku.

Strategia 3: Reinicjalizacja UI po stronie klienta

Jeśli nie możesz uniknąć spawnowania przedmiotów na odległość, możesz wymusić odświeżenie UI po stronie klienta po zreplikowaniu encji. Możesz to osiągnąć, nasłuchując własnego zdarzenia (custom event), które uruchamia się, gdy gracz zbliża się do strefy spawnu. Kiedy gracz znajdzie się wystarczająco blisko, by encja mogła się załadować (stream in), skrypt Verse aktualizuje zreplikowaną zmienną stanu UI. Wymusza to na własnym widgecie HUD ponowne sprawdzenie komponentów ekwipunku i wyrenderowanie prawidłowych tekstur.

Implementacja w kodzie Verse: Bezpieczny lokalny spawn

Poniższy skrypt Verse pokazuje, jak zespawnować własną encję (entity prefab) dokładnie na współrzędnych gracza przed dodaniem jej do ekwipunku. Takie podejście pozwala ominąć problem z cullingiem odległości, wymuszając replikację wewnątrz aktywnej bańki sieciowej gracza.

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.")

Decoupling stanów ekwipunku z horizOn

Zarządzanie tymi obejściami replikacji na poziomie silnika może szybko stać się uciążliwe, szczególnie gdy Twoja mapa rośnie i wprowadzasz skomplikowane mechaniki rozgrywki. Jeśli Twoja gra wymaga trwałych ekwipunków (persistent inventories), postępu między meczami (cross-match progression) lub systemów wymiany (trading systems), poleganie na fizycznej replikacji actorów do zarządzania stanem ekwipunku tworzy ogromne wąskie gardło.

W takich sytuacjach wyspecjalizowany backend, taki jak horizOn, staje się nieoceniony.

Zamiast spawnować fizyczne encje w odległych miejscach tylko po to, by pobrać ich dane, horizOn pozwala odseparować (decouple) stan gry od potoku replikacji actorów (actor replication pipeline) w Unreal Engine.

Kiedy gracz zdobywa lub kupuje przedmiot, serwer gry wykonuje lekkie wywołanie API w celu zaktualizowania profilu gracza w systemie horizOn. Interfejs użytkownika po stronie klienta odczytuje ten stan bezpośrednio z backendu, renderując przedmioty za pomocą lokalnych zasobów statycznych, bez konieczności replikowania jakichkolwiek actorów przez sieć.

Taka architektura eliminuje desynchronizacje związane z odległością, gwarantuje bezpieczne zapisywanie danych ekwipunku i drastycznie zmniejsza obciążenie sieciowe serwera.

Dobre praktyki dla wysokowydajnego networkingu w UEFN

Jeśli zdecydujesz się ręcznie zarządzać spatial replication w UEFN, postępuj zgodnie z poniższymi najlepszymi praktykami branżowymi, aby zminimalizować narzut sieciowy i desynchronizacje:

  1. Always Instantiate Locally: Utrzymuj tymczasowe spawnowanie przedmiotów blisko postaci gracza, aby zagwarantować natychmiastową replikację.
  2. Implement Visual Fallbacks: Projektuj własne widgety UI tak, aby wyświetlały ikony zastępcze (placeholders), jeśli komponenty przedmiotu nie zostały jeszcze zreplikowane.
  3. Decouple Data from Visuals: Używaj struktur Verse do zarządzania stanem logicznym przedmiotów (durability, count, stats), a encji używaj wyłącznie do ich wizualnej reprezentacji.
  4. Throttle Inventory Operations: Unikaj wywoływania AddItem() lub RemoveItem() w szybkich odstępach czasu, ponieważ kolejki serializacji sieciowej mogą gubić aktualizacje pod dużym obciążeniem.

Podsumowanie i kolejne kroki

Błędy spatial replication, takie jak uefn additem far distance bug, pokazują, jak łatwo lokalne ograniczenia silnika mogą zepsuć wrażenia płynące z rozgrywki. Rozumiejąc, jak działają network relevancy oraz World Partition w UEFN, możesz projektować sprawniejsze procesy spawnowania, które utrzymają stany klienta i serwera w harmonii. Dla twórców budujących ambitne gry wymagające trwałych stanów (persistent states), globalnych profili graczy oraz bezpiecznych systemów ekonomii, wyjście poza replikację na poziomie silnika jest ostatecznym rozwiązaniem.

Gotowy na skalowanie swojego multiplayer backendu? Wypróbuj horizOn za darmo lub zapoznaj się z API docs.


Źródło: Adding Item not working in far distance