I apologise if this is the wrong place for questions like this, and if so please help to redirect me as to where i should be asking the question instead.
As the title says i am trying to implement multiplayer using EOS. I followed a LAN tutorial and have done my best to reapply the logic as to work for online EOS instead. I am testing this setup using DevAuthTool and having 2 players play as a standalone game. After many hours of work i can now successfully host and find said session by searching for it on the other instance and when i try to join and travel i get messages saying it was successfully done. However when both instances load into the default world for a First person game they don’t see eachother even though i have replicate on. (And i want to add that they successfully saw eachother when it was set up to LAN). Please help, i don’t know what to do:
When i join a session i get these logs:
"Joining Session"
"Join result: 0."
"Travel successful: 1"
This is my header file:
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "interfaces/OnlineSessionInterface.h"
#include "Interfaces/OnlineIdentityInterface.h" // <-- För IOnlineIdentity
//#include "OnlineSubsystem/OnlineSessionInterface.h"
#include "BaseGameInstance.generated.h"
/**
*
*/
UCLASS()
class COOLGAME_API UBaseGameInstance : public UGameInstance
{
GENERATED_BODY()
protected:
virtual void Init() override;
public:
UBaseGameInstance();
// callback för login
void OnLoginComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& UserId, const FString& Error);
bool bIsLoggedIn = false;
// Host an online session.
UFUNCTION(BlueprintCallable, Category = "Networking")
void HostSession();
void OnCreateSessionComplete(FName SessionName, bool bWasSuccessful);
FDelegateHandle OnCreateSessionCompleteDelegateHandle;
// Search for an online session.
UFUNCTION(BlueprintCallable, Category = "Networking")
void SearchForSessions();
void SearchForSessionsCompleted(bool _searchCompleted);
FOnFindSessionsCompleteDelegate SearchForSessionsCompletedDelegate;
FDelegateHandle SearchForSessionsCompletedHandle;
TSharedPtr<FOnlineSessionSearch> searchSettings;
// Join an online session.
UFUNCTION(BlueprintCallable, Category = "Networking")
void JoinSession();
void JoinSessionCompleted(FName _sessionName, EOnJoinSessionCompleteResult::Type _joinResult);
FOnJoinSessionCompleteDelegate JoinSessionCompletedDelegate;
FDelegateHandle JoinSessionCompletedHandle;
// Travel to the joined session (returns true if successful).
bool TravelToSession();
};
And this is my cpp file:
// Fill out your copyright notice in the Description page of Project Settings.
#include "BaseGameInstance.h"
#include "CoolGameTemplateGameMode.h"
#include "OnlineSubsystem.h"
#include "OnlineSessionSettings.h"
//#include "interfaces/OnlineSessionInterface.h"
UBaseGameInstance::UBaseGameInstance() {
// Instantiate the delegate for finding/searching for sessions (call the corresponding function upon completion).
SearchForSessionsCompletedDelegate = FOnFindSessionsCompleteDelegate::CreateUObject(this, &UBaseGameInstance::SearchForSessionsCompleted);
// Instatiate the delegate for joining sessions (call the corresponding function upon completion).
JoinSessionCompletedDelegate = FOnJoinSessionCompleteDelegate::CreateUObject(this, &UBaseGameInstance::JoinSessionCompleted);
}
void UBaseGameInstance::Init()
{
Super::Init();
IOnlineSubsystem* OnlineSubsystem = IOnlineSubsystem::Get(TEXT("EOS"));
if (!OnlineSubsystem) return;
IOnlineIdentityPtr Identity = OnlineSubsystem->GetIdentityInterface();
if (!Identity.IsValid()) return;
Identity->OnLoginCompleteDelegates->AddUObject(this, &UBaseGameInstance::OnLoginComplete);
// DevAuth login istället för anonymous
FOnlineAccountCredentials DevCreds(TEXT("developer"), TEXT("localhost:8081"), TEXT("TDDD23-Developer"));
Identity->Login(0, DevCreds);
}
void UBaseGameInstance::OnLoginComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& UserId, const FString& Error)
{
if (bWasSuccessful)
{
bIsLoggedIn = true;
UE_LOG(LogTemp, Log, TEXT("Login Succeeded! LocalUserNum=%d UserId=%s"), LocalUserNum, *UserId.ToString());
}
else
{
bIsLoggedIn = false;
UE_LOG(LogTemp, Error, TEXT("Login Failed: %s"), *Error);
}
// Om du vill: ta bort delegaten om du inte behöver fler login events
// Identity->OnLoginCompleteDelegates->RemoveAll(this); // alternativt spara handle och ta bort
}
void UBaseGameInstance::HostSession() {
if(bIsLoggedIn) {
if (IOnlineSubsystem* onlineSubsystem = IOnlineSubsystem::Get(TEXT("EOS"))) {
if (IOnlineSessionPtr onlineSessionInterface = onlineSubsystem->GetSessionInterface()) {
TSharedPtr<FOnlineSessionSettings> sessionSettings = MakeShareable(new FOnlineSessionSettings());
sessionSettings->bAllowInvites = true;
sessionSettings->bAllowJoinInProgress = true;
sessionSettings->bAllowJoinViaPresence = true;
sessionSettings->bAllowJoinViaPresenceFriendsOnly = false;
sessionSettings->bIsDedicated = false;
sessionSettings->bUsesPresence = true;
sessionSettings->bIsLANMatch = false;
sessionSettings->bShouldAdvertise = true;
sessionSettings->NumPrivateConnections = 0;
sessionSettings->NumPublicConnections = 2;
const ULocalPlayer* localPlayer = GetWorld()->GetFirstLocalPlayerFromController();
if (!localPlayer)
{
UE_LOG(LogTemp, Error, TEXT("No local player available!"));
return;
}
FUniqueNetIdRepl userIdRepl = localPlayer->GetPreferredUniqueNetId();
if (!userIdRepl.IsValid())
{
UE_LOG(LogTemp, Error, TEXT("UniqueNetId not ready yet"));
return;
}
// Få det som TSharedPtr<const FUniqueNetId>
TSharedPtr<const FUniqueNetId> userIdPtr = userIdRepl.GetUniqueNetId();
if (!userIdPtr.IsValid())
{
UE_LOG(LogTemp, Error, TEXT("Failed to convert UniqueNetId to TSharedPtr"));
return;
}
if (onlineSessionInterface->CreateSession(*userIdPtr, NAME_GameSession, *sessionSettings)) {
GEngine->AddOnScreenDebugMessage(0, 30.0f, FColor::Cyan, FString::Printf(TEXT("A session has been created!")));
UE_LOG(LogTemp, Warning, TEXT("A session has been created!"));
OnCreateSessionCompleteDelegateHandle = onlineSessionInterface->AddOnCreateSessionCompleteDelegate_Handle(
FOnCreateSessionCompleteDelegate::CreateUObject(this, &UBaseGameInstance::OnCreateSessionComplete)
);
}
else {
GEngine->AddOnScreenDebugMessage(0, 30.0f, FColor::Cyan, FString::Printf(TEXT("A session has failed to be created!")));
UE_LOG(LogTemp, Warning, TEXT("A session has failed to be created!"));
}
}
}
}
else {
UE_LOG(LogTemp, Log, TEXT("Can't host, user not yet initalized"));
}
}
void UBaseGameInstance::OnCreateSessionComplete(FName SessionName, bool bWasSuccessful)
{
IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get();
if (!OnlineSub) return;
IOnlineSessionPtr Sessions = OnlineSub->GetSessionInterface();
if (Sessions.IsValid())
{
Sessions->ClearOnCreateSessionCompleteDelegate_Handle(OnCreateSessionCompleteDelegateHandle);
}
if (bWasSuccessful)
{
UE_LOG(LogTemp, Log, TEXT("Session created successfully! Redirecting to map..."));
// Now you can safely travel with ?listen
UWorld* World = GetWorld();
if (World)
{
World->ServerTravel("/Game/FirstPerson/Lvl_FirstPerson?listen");
}
}
else
{
UE_LOG(LogTemp, Error, TEXT("Failed to create session!"));
}
}
void UBaseGameInstance::SearchForSessions() {
if (IOnlineSubsystem* onlineSubsystem = IOnlineSubsystem::Get(TEXT("EOS")))
{
if (IOnlineSessionPtr onlineSessionInterface = onlineSubsystem->GetSessionInterface())
{
// Initialize listening for the completion of the search operation.
SearchForSessionsCompletedHandle = onlineSessionInterface->AddOnFindSessionsCompleteDelegate_Handle(SearchForSessionsCompletedDelegate);
searchSettings = MakeShareable(new FOnlineSessionSearch());
searchSettings->bIsLanQuery = false;
searchSettings->MaxSearchResults = 5;
searchSettings->PingBucketSize = 30;
searchSettings->TimeoutInSeconds = 10.0f;
const ULocalPlayer* localPlayer = GetWorld()->GetFirstLocalPlayerFromController();
if (onlineSessionInterface->FindSessions(*localPlayer->GetPreferredUniqueNetId(), searchSettings.ToSharedRef())) {
GEngine->AddOnScreenDebugMessage(1, 30.0f, FColor::Cyan, FString::Printf(TEXT("Search Started.")));
UE_LOG(LogTemp, Warning, TEXT("Search Started."));
}
else {
GEngine->AddOnScreenDebugMessage(1, 30.0f, FColor::Cyan, FString::Printf(TEXT("Search failed to start.")));
UE_LOG(LogTemp, Warning, TEXT("Search failed to start."));
}
}
}
}
void UBaseGameInstance::SearchForSessionsCompleted(bool _searchCompleted) {
if (IOnlineSubsystem* onlineSubsystem = IOnlineSubsystem::Get(TEXT("EOS")))
{
if (IOnlineSessionPtr onlineSessionInterface = onlineSubsystem->GetSessionInterface())
{
// Clear the handle and stop listening for the completion of the search operation.
onlineSessionInterface->ClearOnFindSessionsCompleteDelegate_Handle(SearchForSessionsCompletedHandle);
GEngine->AddOnScreenDebugMessage(2, 30.0f, FColor::Cyan, FString::Printf(TEXT("Search found %d sessions after completing search."), searchSettings->SearchResults.Num()));
UE_LOG(LogTemp, Warning, TEXT("Search found %d sessions after completing search."), searchSettings->SearchResults.Num());
if (auto gameMode = Cast<ACoolGameTemplateGameMode>(GetWorld()->GetAuthGameMode()))
{
for (int i = 0; i < searchSettings->SearchResults.Num(); ++i)
{
gameMode->DisplaySessionInfo(searchSettings->SearchResults[i].Session.GetSessionIdStr());
}
}
}
}
}
void UBaseGameInstance::JoinSession() {
if (!bIsLoggedIn) {
UE_LOG(LogTemp, Warning, TEXT("Can't join, user not yet logged in"));
return;
}
if (IOnlineSubsystem* onlineSubsystem = IOnlineSubsystem::Get(TEXT("EOS")))
{
if (IOnlineSessionPtr onlineSessionInterface = onlineSubsystem->GetSessionInterface())
{
if (searchSettings->SearchResults.Num() > 0) {
GEngine->AddOnScreenDebugMessage(3, 30.0f, FColor::Cyan, FString::Printf(TEXT("Joining Session")));
UE_LOG(LogTemp, Warning, TEXT("Joining Session."));
const ULocalPlayer* localPlayer = GetWorld()->GetFirstLocalPlayerFromController();
JoinSessionCompletedHandle = onlineSessionInterface->AddOnJoinSessionCompleteDelegate_Handle(JoinSessionCompletedDelegate);
onlineSessionInterface->JoinSession(*localPlayer->GetPreferredUniqueNetId(), NAME_GameSession, searchSettings->SearchResults[0]);
}
}
}
}
void UBaseGameInstance::JoinSessionCompleted(FName _sessionName, EOnJoinSessionCompleteResult::Type _joinResult) {
GEngine->AddOnScreenDebugMessage(4, 30.0f, FColor::Cyan, FString::Printf(TEXT("Join result: %d."), (int32)(_joinResult)));
UE_LOG(LogTemp, Warning, TEXT("Join result: %d."), (int32)(_joinResult));
if (IOnlineSubsystem* onlineSubsystem = IOnlineSubsystem::Get(TEXT("EOS")))
{
if (IOnlineSessionPtr onlineSessionInterface = onlineSubsystem->GetSessionInterface())
{
// Clear the handle and stop listening for the completion of the "Join" operation.
onlineSessionInterface->ClearOnJoinSessionCompleteDelegate_Handle(JoinSessionCompletedHandle);
// Attempt to join the session.
bool wasTravelSuccessful = TravelToSession();
GEngine->AddOnScreenDebugMessage(5, 30.0f, FColor::Cyan, FString::Printf(TEXT("Travel successful: %d"), wasTravelSuccessful));
UE_LOG(LogTemp, Warning, TEXT("Travel successful: %d."), wasTravelSuccessful);
}
}
}
bool UBaseGameInstance::TravelToSession()
{
if (IOnlineSubsystem* onlineSubsystem = IOnlineSubsystem::Get(TEXT("EOS")))
{
if (IOnlineSessionPtr onlineSessionInterface = onlineSubsystem->GetSessionInterface())
{
FString connectionInfo;
if (onlineSessionInterface->GetResolvedConnectString(NAME_GameSession, connectionInfo)) {
// Travel the client to the server.
APlayerController* playerController = GetWorld()->GetFirstPlayerController();
playerController->ClientTravel(connectionInfo, TRAVEL_Absolute);
return true;
}
else {
// The connection information could not be obtained.
return false;
}
}
}
// The client was unable to travel.
return false;
}