Powrót do Bloga

Jak naprawić błędy logowania Unreal Blueprint i błędy achievementów w Epic Online Services

Opublikowano 9 lipca 2026
Jak naprawić błędy logowania Unreal Blueprint i błędy achievementów w Epic Online Services

W skrócie

Artykuł omawia przyczyny i rozwiązania częstych błędów logowania oraz zapisu osiągnięć w Unreal Engine podczas integracji z Epic Online Services (EOS). Wyjaśnia kluczowe różnice między Epic Account ID (EAID) a Product User ID (PUID) oraz opisuje, jak zapobiegać problemom wynikającym z asynchroniczności za pomocą C++ i Blueprintów. Przedstawiono w nim także właściwą konfigurację pliku `DefaultEngine.ini` oraz alternatywne, wieloplatformowe rozwiązanie w postaci usługi horizOn.

Kompilujesz shipping build swojej gry w Unreal Engine, uruchamiasz ją z Epic Games Launcher i klikasz własny przycisk logowania. Nic się nie dzieje lub klient gry się zawiesza, a w logach pojawiają się niejasne komunikaty o błędach autoryzacji. Co gorsza, Twój węzeł odblokowujący achievementy działa bez zgłaszania jakichkolwiek widocznych błędów, ale profil gracza w overlay Epic Games Store pozostaje pusty. Te błędy są niezwykle powszechne podczas integracji storefront API. Na szczęście można je łatwo rozwiązać, poprawiając asynchroniczny przepływ wykonywania (asynchronous execution flow) i rozumiejąc, jak subsystem mapuje tożsamości użytkowników.

Zrozumienie potoku uwierzytelniania EOS: EAID vs. PUID

Integracja Epic Online Services (EOS) za pośrednictwem Online Subsystem (OSS) w Unreal Engine wymaga poruszania się w dwupoziomowym systemie tożsamości. Epic Account ID (EAID) jest zarządzany przez Auth Interface. Weryfikuje on tożsamość użytkownika na poziomie sklepu, co umożliwia korzystanie z funkcji takich jak social overlay, lista znajomych czy weryfikacja biblioteki Epic Games Store.

Z kolei Product User ID (PUID) jest zarządzany przez Connect Interface. PUID to identyfikator specyficzny dla danej gry, który łączy użytkownika z usługami backendowymi gry. Usługi te obejmują matchmaking, statystyki, cloud saves oraz achievementy.

Dlaczego niezgodność EAID i PUID uniemożliwia działanie achievementów

Częstym problemem (failure mode) jest sytuacja, w której deweloperzy pomyślnie uwierzytelniają użytkownika w Auth Interface (generując EAID), ale subsystem nie loguje się do Connect Interface. Ponieważ achievementy są zarządzane przez Connect Interface za pomocą PUID-ów, zapisywanie postępu osiągnięć bez powiązanego PUID kończy się błędem EOS_InvalidUser.

W grach uruchamianych bez storefront wrapper, użytkownicy zazwyczaj logują się przy użyciu danych uwierzytelniających, które są sprawdzane w scentralizowanej tabeli użytkowników. In a modern storefront ecosystem like Epic Games Store, tożsamość jest federowana. Po uruchomieniu gry otrzymuje ona kryptograficzny ticket z launchera. Następnie gra przekazuje ten ticket do serwerów uwierzytelniających sklepu. SDK zwraca Epic Account ID, który działa jak paszport użytkownika we wszystkich grach na platformie.

Jednak w celu zapewnienia prywatności i bezpieczeństwa cross-play, Epic nie pozwala na bezpośredni odczyt Epic Account ID przez specyficzne dla gry funkcje, takie jak achievementy. Zamiast tego gra musi zainicjować Connect Interface, który wykonuje wtórną wymianę danych w celu pobrania Product User ID. Ta separacja gwarantuje, że w przypadku zhakowania gry, globalne dane uwierzytelniające Epic Account graczy nie zostaną naruszone. Bez PUID Twoja gra działa w praktyce w nieuwierzytelnionym stanie gościa (guest state), co blokuje dostęp do funkcji EGS. Jeśli w credentials config lub w sekcji client policy w Epic Developer Portal brakuje odpowiednich uprawnień, to powiązanie się nie powiedzie. Interfejs tożsamości zgłosi pomyślne logowanie, ponieważ konto Epic jest prawidłowe, ale warstwa usług gry (game services layer) nie będzie mogła zapisać danych osiągnięć, ponieważ żaden PUID nie został powiązany.

Anatomia wadliwej sekwencji logowania w Blueprintach

Wielu deweloperów napotyka problemy z logowaniem, łącząc piny wykonawcze Blueprint liniowo. Przeciągnięcie pinu wykonawczego bezpośrednio z węzła Login do węzła Query Achievements lub Write Achievement Progress zawsze zakończy się niepowodzeniem.

Zapytania uwierzytelniające muszą trafić do backendu Epic, co czyni je asynchronicznymi. Silnik kontynuuje wykonywanie grafu Blueprint w kolejnej klatce, na długo przed tym, jak serwery Epic zwrócą dane uwierzytelniające użytkownika. Na tym etapie Unique Net ID gracza pozostaje wartością null.

Problem "brakującego węzła": Race Conditions w asynchronicznym wykonywaniu kodu

Jeśli wywołasz węzły osiągnięć natychmiast po węźle logowania, subsystem zgłosi cichy błąd, ponieważ zbuforowany stan użytkownika jest pusty. Prawidłowy przepływ pracy wymaga podpięcia niestandardowych zdarzeń (custom events) pod asynchroniczne delegaty (delegates) subsystemu.

Ponadto deweloperzy często pomijają kluczowy krok, jakim jest caching achievementów przed próbą zapisu. Nie można zmodyfikować postępu osiągnięcia bez uprzedniego odpytania serwera o aktualny schemat (schema). Wywołanie Write Achievements bez wcześniejszego Query Achievements skutkuje cichym niepowodzeniem lub błędem EOS_InvalidUser w logach konsoli, ponieważ rozmiar lokalnej pamięci podręcznej achievementów wynosi 0.

Prawidłowy asynchroniczny przepływ w Blueprintach

Aby to rozwiązać, należy oddzielić wyzwolenie logowania od aktualizacji osiągnięć. Najpierw wywołaj węzeł logowania i określ poprawne dane uwierzytelniające (authentication credentials).

Po drugie, podepnij zdarzenie pod delegat On Login Complete interfejsu tożsamości. Gdy to zdarzenie się wywoła i zwróci status powodzenia, pobierz Unique Net ID użytkownika.

Po trzecie, przekaż ten identyfikator do węzła Query Achievements. Na koniec podepnij zdarzenie pod delegat On Query Achievements Complete i wywołaj Write Achievement Progress wyłącznie wewnątrz tego callbacku.

Implementacja stabilnego kontrolera logowania i osiągnięć EOS w C++

Aby czysto obsłużyć te asynchroniczne operacje, wysoce zalecana jest implementacja pętli uwierzytelniania w C++. Zapewnia to bezpośredni dostęp do IOnlineSubsystem oraz jego interfejsów.

Poniżej znajduje się kompletna, gotowa do wdrożenia produkcyjnego implementacja obsługi logowania i achievementów w C++:

#include "OnlineSubsystem.h"
#include "Interfaces/OnlineIdentityInterface.h"
#include "Interfaces/OnlineAchievementsInterface.h"
#include "OnlineSubsystemUtils.h"

void UEOSLoginHandler::LoginToEpicGames(APlayerController* PlayerController)

{
    if (!PlayerController) return;

    IOnlineSubsystem* Subsystem = IOnlineSubsystem::Get(TEXT("EOS"));
    if (!Subsystem)
    {
        UE_LOG(LogTemp, Warning, TEXT("EOS Subsystem not found. Make sure the plugin is enabled."));
        return;
    }

    IOnlineIdentityPtr Identity = Subsystem->GetIdentityInterface();
    if (Identity.IsValid())
    {
        FOnlineAccountCredentials Credentials;
        Credentials.Type = TEXT("ExchangeCode");
        Credentials.Id = TEXT("");
        Credentials.Token = TEXT(""); // The launcher passes this via command line arguments

        Identity->AddOnLoginCompleteDelegate_Handle(0, FOnLoginCompleteDelegate::CreateUObject(this, &UEOSLoginHandler::OnLoginComplete));
        Identity->Login(0, Credentials);
    }
}

void UEOSLoginHandler::OnLoginComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& UserId, const FString& Error)
{
    if (!bWasSuccessful)
    { 
        UE_LOG(LogTemp, Error, TEXT("Epic Online Services Login Failed. Error: %s"), *Error);
        return;
    }

    UE_LOG(LogTemp, Log, TEXT("EOS Login Successful. ID resolved: %s"), *UserId.ToString());

    IOnlineSubsystem* Subsystem = IOnlineSubsystem::Get(TEXT("EOS"));
    IOnlineAchievementsPtr Achievements = Subsystem->GetAchievementsInterface();
    if (Achievements.IsValid())
    { 
        Achievements->QueryAchievements(UserId, FOnQueryAchievementsCompleteDelegate::CreateUObject(this, &UEOSLoginHandler::OnQueryAchievementsComplete));
    }
}

void UEOSLoginHandler::OnQueryAchievementsComplete(const FUniqueNetId& PlayerId, bool bWasSuccessful)
{
    if (!bWasSuccessful)
    {
        UE_LOG(LogTemp, Warning, TEXT("Failed to query achievements from Epic Developer Portal."));
        return;
    }

    UE_LOG(LogTemp, Log, TEXT("Achievements queried successfully. Now writing progress."));

    IOnlineSubsystem* Subsystem = IOnlineSubsystem::Get(TEXT("EOS"));
    IOnlineAchievementsPtr Achievements = Subsystem->GetAchievementsInterface();
    if (Achievements.IsValid())
    {
        FOnlineAchievementsWriteRef WriteObject = MakeShared<FOnlineAchievementsWrite>();
        WriteObject->SetFloatStat(TEXT("ACH_FIRST_BLOOD"), 100.0f);

        Achievements->WriteAchievements(PlayerId, WriteObject, FOnAchievementsWrittenDelegate::CreateUObject(this, &UEOSLoginHandler::OnAchievementsWritten));
    }
}

void UEOSLoginHandler::OnAchievementsWritten(const FUniqueNetId& PlayerId, bool bWasSuccessful)
{
    if (bWasSuccessful)
    {
        UE_LOG(LogTemp, Log, TEXT("Achievement successfully unlocked on Epic Games Store!"));
    }
    else
    {
        UE_LOG(LogTemp, Error, TEXT("Failed to write achievement progress. Check sandbox mappings."));
    }
}

Ten kontroler wykorzystuje sekwencyjne callbacki. Gwarantuje to, że interfejs osiągnięć jest wywoływany dopiero wtedy, gdy interfejs tożsamości pomyślnie powiąże zarówno Epic Account ID, jak i Product User ID.

Konfiguracja pliku DefaultEngine.ini dla EOS

Węzły logowania Blueprint nie zostaną poprawnie zainicjowane, jeśli konfiguracja w pliku Config/DefaultEngine.ini jest nieprawidłowa. Wtyczka Online Subsystem EOS wymaga określonych parametrów do powiązania jej z klientem gry.

Użyj poniższego szablonu konfiguracji, aby upewnić się, że Twój subsystem zainicjuje się poprawnie:

[OnlineSubsystem]
DefaultPlatformService=EOS

[OnlineSubsystemEOS]
bEnabled=true
bUseEpicConnect=true
ProductId=your_product_id_here
SandboxId=your_sandbox_id_here
DeploymentId=your_deployment_id_here
ClientId=your_client_id_here
ClientSecret=your_client_secret_here

[OnlineSubsystemEOS.Auth]
bUseEpicAccount=true

Konfiguracja pliku DefaultEngine.ini działa jako most łączący skompilowane pliki binarne gry z Epic Developer Portal. Parametry w sekcji [OnlineSubsystemEOS] muszą dokładnie odpowiadać ustawieniom Twojego produktu.

Częstym powodem nieporozumień jest różnica między client credentials a identyfikatorami sandbox. Client ID oraz Client Secret reprezentują dane uwierzytelniające klienta gry, umożliwiając mu komunikację z backendem EOS. Sandbox ID reprezentuje konkretne środowisko (takie jak Development, Staging lub Live), do którego uzyskuje dostęp Twój klient.

Jeśli klient gry spróbuje uwierzytelnić się za pomocą Sandbox ID, który nie pasuje do reguł Client Credentials policy, żądanie uwierzytelnienia zostanie odrzucone. Dodatkowo flagę bUseEpicConnect należy ustawić na true, aby upewnić się, że Online Subsystem automatycznie obsługuje mapowanie EAID do PUID w tle.

Zarządzanie utratą focusu przez overlay i integracja z platformą

Wtyczka EOS do Unreal Engine w dużym stopniu opiera się na Epic Games Overlay w celu wyświetlania powiadomień, obsługi zaproszeń do znajomych oraz uwierzytelniania webowego OAuth. Gdy klient gry wywołuje logowanie przy użyciu typu danych AccountPortal, system operacyjny uruchamia okno przeglądarki lub otwiera overlay.

To przekierowanie przenosi focus (aktywne okno) poza obszar gry. Jeśli Twoje input modes nie są skonfigurowane do obsługi utraty focusu, gra może się zawiesić lub rejestrować zablokowane klawisze.

Radzenie sobie z problemami z inputem wywołanymi przez overlay to częsty ból głowy deweloperów tworzących na PC. Na przykład integracja overlay może kolidować ze sterownikami raw input i powodować zamrażanie stanu klawiatury/myszy. Aby zapobiec tym błędom psującym wrażenia z rozgrywki, możesz zapoznać się z naszą analizą The Marathon Input Issues Fix: Architecting PC Games to Survive Overlay Conflicts.

Ponadto błędy inicjalizacji podczas testów są często spowodowane przez nieprawidłowo skonfigurowane połączenia socket lub limity timeout w lokalnej konfiguracji. Jeśli diagnozujesz timeouty sterowników podczas session startup, zapoznaj się z naszym przewodnikiem Uefn Session Launch Timeout Nightmares: Diagnosing Unreal Engine Network Drivers.

Uproszczenie wieloplatformowych backendów storefront

Ręczna konfiguracja storefront subsystems, pisanie łańcuchów delegatów w C++ oraz radzenie sobie ze specyficznymi dla platformy problemami z focusem overlay jest niezwykle czasochłonne. Tworzenie tego dla wielu platform, takich jak Steam, EGS i konsole, wielokrotnie zwiększa nakład pracy (development overhead).

Samodzielne zbudowanie takiego rozwiązania wymaga konfiguracji load balancers, database sharding oraz zarządzania certyfikatami SSL – to z łatwością 4-6 tygodni pracy.

Dzięki horizOn otrzymujesz spójny, cross-platform backend, który ukrywa za abstrakcją te storefront API. Zamiast użerać się z podwójnymi tokenami tożsamości (EAID/PUID), sandboxami Epic czy kodem inicjalizacyjnym Steamworks, używasz jednego API, które obsługuje profile użytkowników, achievementy, matchmaking oraz leaderboardy.

horizOn działa jako most, automatycznie synchronizując achievementy i postępy gracza z dowolnym storefront, z którego gra została uruchomiona. Pozwala Ci to skupić się na core game loop zamiast na pisaniu storefront boilerplate. Oznacza to, że Twoi gracze mogą odblokowywać achievementy, korzystać z cloud saves i wyszukiwać mecze niezależnie od używanej platformy czy launchera, a Ty nie musisz pisać ani jednej linii kodu SDK specyficznego dla danego sklepu.

Nowoczesne dobre praktyki integracji Epic Online Services

  1. Nigdy nie łącz węzłów asynchronicznych bezpośrednio: Zawsze czekaj na wywołanie delegatów OnLoginComplete i OnQueryAchievementsComplete przed wykonaniem dalszych operacji (downstream), takich jak zapisywanie statystyk czy achievementów.

  2. Włącz szczegółowe logowanie (Verbose Logging) podczas developmentu: Dodaj poniższe linie do pliku DefaultEngine.ini w sekcji [Core.Log], aby śledzić ukryte ostrzeżenia EOS:

    [Core.Log]
    LogOnline=VeryVerbose
    LogOnlineGame=VeryVerbose
    LogEOSSDK=VeryVerbose
    
  3. Zmapuj achievementy do EOS w Dev Portal: Upewnij się, że achievementy utworzone w Epic Games Store (EGS) są jawnie przypisane do Twojego backendu Epic Online Services (EOS). Jeśli nie są powiązane, EOS SDK nie rozpozna identyfikatora osiągnięcia.

  4. Używaj ExchangeCode w shipping builds: Podczas lokalnego developmentu wygodny jest typ logowania Developer przy użyciu narzędzia Dev Auth Tool, ale w shipping builds uruchamianych bezpośrednio z Epic Games Launcher musisz zmienić typ credentials na ExchangeCode. Użycie typu autoryzacji ExchangeCode dostarczanego przez launcher pozwala pominąć przekierowanie OAuth w przeglądarce, skracając czas trwania sekwencji logowania z 8-12 sekund interakcji użytkownika do automatycznego handshake trwającego poniżej 500 ms.

Usprawnienie integracji ze storefrontami

Rozwiązanie błędów logowania i achievementów Epic Online Services w Unreal Engine sprowadza się do zrozumienia asynchronicznego potoku (async pipeline) oraz idealnego dopasowania profili konfiguracyjnych. Zarządzając przejściem między interfejsami tożsamości i usług gry, deweloperzy mogą wyeliminować ciche błędy i zapewnić graczom płynną rozgrywkę.

Chcesz skalować swój multiplayer backend? Wypróbuj horizOn za darmo lub zapoznaj się z API docs.


Źródło: Epic Games Store (Online Services AND Achievements)