Absolutely stuck trying to implement multiplayer using EOS

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;
}

You’re using the first person template right?

I’m assuming you are simply doing tests with this build, so…

The first person arms only render to the owner. Click on the mesh in the components panel. In details search for Only Owner See untick it. Then they’ll render for all clients.

For a production project you’ll need to re-tick that and add a full body mesh to the “Other” mesh component… CharacterMesh0.