Hi everyone. I am trying to create my first multiplayer game in Unreal 5.2 in C++. I have EOS setup and I am able to create sessions, find sessions, and join sessions. My issue is that when a client joins an existing session, the OnJoinSessionCompleteDelegates delegate is triggered on their side…but the PlayerArray in the GameState is never updated and PostLogin() is never called for the new player on the host side. Both the host and joining client are on different epic games accounts. I have tried having both instances on the same machine and different machines with no luck. Both instances use different Epic Games accounts.
I am at a complete loss at what is stopping this from working correctly. If anyone has an idea, please let me know…
Sorry for the code dump…I just want to give as much context as I can here.
The following logic is for logging into eos and for creating my session on the host’s side:
UOnlineSessionManager::UOnlineSessionManager()
{
OnlineSubsystem = IOnlineSubsystem::Get();
SessionInterface = OnlineSubsystem->GetSessionInterface();
if (SessionInterface.IsValid())
{
if (IOnlineIdentityPtr Identity = OnlineSubsystem->GetIdentityInterface())
{
FOnlineAccountCredentials Credentials;
Credentials.Id = FString();
Credentials.Token = FString();
Credentials.Type = FString("accountportal");
Identity->OnLoginCompleteDelegates->AddUObject(this, &UOnlineSessionManager::OnLoginComplete);
Identity->Login(0, Credentials);
}
SessionInterface->OnCreateSessionCompleteDelegates.AddUObject(this, &UOnlineSessionManager::OnCreateSessionComplete);
SessionInterface->OnFindSessionsCompleteDelegates.AddUObject(this, &UOnlineSessionManager::OnFindSessionComplete);
SessionInterface->OnJoinSessionCompleteDelegates.AddUObject(this, &UOnlineSessionManager::OnJoinSessionComplete);
}
}
void UOnlineSessionManager::OnLoginComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& UserId, const FString& Error)
{
if (OnlineSubsystem)
{
if (IOnlineIdentityPtr Identity = OnlineSubsystem->GetIdentityInterface())
{
Identity->ClearOnLoginCompleteDelegates(0, this);
}
}
}
void UOnlineSessionManager::CreateSession(int NumPlayers)
{
if (SessionInterface.IsValid())
{
TSharedPtr<const FUniqueNetId> UserId = OnlineSubsystem->GetIdentityInterface()->GetUniquePlayerId(0);
auto Username = OnlineSubsystem->GetIdentityInterface()->GetPlayerNickname(0);
FString LobbyName = Username + TEXT("'s Lobby");
const FName SessionName = FName(LobbyName);
auto ExistingSession = SessionInterface->GetNamedSession(SessionName);
if (ExistingSession != nullptr)
{
SessionInterface->DestroySession(SessionName);
}
TSharedPtr<FOnlineSessionSettings> Settings = MakeShareable(new FOnlineSessionSettings());
Settings->bAllowJoinInProgress = true;
Settings->bAllowJoinViaPresence = true;
Settings->bIsLANMatch = false;
Settings->bShouldAdvertise = true;
Settings->bUsesPresence = true;
Settings->NumPublicConnections = NumPlayers;
Settings->BuildUniqueId = 1;
Settings->Set("SESSION_NAME", LobbyName, EOnlineDataAdvertisementType::ViaOnlineService);
const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();
SessionInterface->CreateSession(*LocalPlayer->GetPreferredUniqueNetId(), SessionName, *Settings);
}
}
And this is the code for joining a session and the completion of that join:
void UOnlineSessionManager::JoinSession(USessionInfo* Info)
{
if (SessionInterface.IsValid())
{
UE_LOG(LogTemp, Warning, TEXT("Joining session %s with ping %d"), *Info->Name, Info->Ping);
const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();
SessionInterface->JoinSession(*LocalPlayer->GetPreferredUniqueNetId(), FName(*Info->Name), Info->SearchResult);
}
}
void UOnlineSessionManager::OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result)
{
if (Result == EOnJoinSessionCompleteResult::Success)
{
const FString Username = OnlineSubsystem->GetIdentityInterface()->GetPlayerNickname(0);
// Add the username to the UI
}
}
I even added this little bit of code to my GameState class to temporarily track if a change is made to the PlayerArray…and there is never a change:
ACannonballsGameState::ACannonballsGameState()
{
PrimaryActorTick.bCanEverTick = true;
bReplicates = true;
}
void ACannonballsGameState::BeginPlay()
{
Super::BeginPlay();
PreviousPlayerStates = PlayerArray;
}
void ACannonballsGameState::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (PreviousPlayerStates.Num() != PlayerArray.Num() && OnPlayerStatesChanged.IsBound())
{
UE_LOG(LogTemp, Warning, TEXT("Number of player states changed: %d"), PlayerArray.Num());
OnPlayerStatesChanged.Broadcast(PlayerArray);
}
PreviousPlayerStates = PlayerArray;
}