Online Subsystem NULL : Cannot Find Sessions

I’d recommend being a bit more type safe with your variables.
Instead of using auto, why not use

IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get();

and

IOnlineSessionPtr Sessions = OnlineSub->GetSessionInterface();
?

1 Like

Also, where are you trying to use this? Best place I can think of is in your GameInstance.

I’m trying to get the null online subsystem going in c++. I basically made my own subclasses of UOnlineBlueprintCallProxyBase which is what the engine uses for the latent session nodes in BP.

But I see 3 discrepancies between my implementation and how the original in the engine works, and I can’t figure out why.
I’ve tried this in 4.15.3 and 4.16.1 btw.

1

When I create my session, it appears to succeeed as far as the callbacks.
But the log outputs:

LogOnline:Warning: OSS: AutoLogin missing AUTH_LOGIN=<login id>.
LogOnline:Warning: OSS: No game present to join for session (Game)

In contrast, if I use the engine’s built int create session BP nodes those 2 logs do not appear.

My session creation code is:

void UTTCreateNetSessionProxy::Activate()
{
	auto Sessions = GetOnlineSessions();

	if (!Sessions.IsValid()) {
		Failure.Broadcast();
	}

	FOnlineSessionSettings SessionSettings;
	SessionSettings.NumPublicConnections = 2;
	SessionSettings.bAllowJoinInProgress = true;
	SessionSettings.bShouldAdvertise = true;
	SessionSettings.bIsLANMatch = (SessionInfo.ConnectionType == ETTNetSessionConnectionType::LAN);
	SessionSettings.bUsesPresence = true;
	SessionSettings.bAllowJoinViaPresence = true;
	
	if (ActiveSession) {
		Sessions->DestroySession(ActiveSessionInfo.Name);
		ActiveSession = false;
	}

	HCreate = Sessions->AddOnCreateSessionCompleteDelegate_Handle(DCreate);
	auto OperationSuccessful = Sessions->CreateSession(*SessionInfo.NetID, SessionInfo.Name, SessionSettings);

	if (OperationSuccessful) {
		ActiveSessionInfo = SessionInfo;
		ActiveSession = true;
	}
}

void UTTCreateNetSessionProxy::OnSessionCreated(FName SessionName, bool OperationSuccessful)
{
	auto LogStatus = (OperationSuccessful ? TEXT("SUCCESS") : TEXT("FAILED"));
	TT_LOG_ARGS(TTNetworking, Log, TTConsole, "Session creation: %s. [%s]", LogStatus, *SessionName.ToString());

	if (OperationSuccessful) {
		auto Sessions = GetOnlineSessions();

		if (Sessions.IsValid()) {
			Sessions->ClearOnCreateSessionCompleteDelegate_Handle(HCreate);
			HStart = Sessions->AddOnStartSessionCompleteDelegate_Handle(DStart);
			Sessions->StartSession(SessionName);

			return;
		}
	}

	Failure.Broadcast();
}

2

If I try to search for sessions, I don’t get any results back, even though in theory I created a session in step 1.
And the only 2 plugins I have enabled are: OnlineSubSystem and OnlineSubSystem NULL.

My search session code is:

void UTTSearchNetSessionProxy::Activate()
{
	auto Sessions = GetOnlineSessions();
	
	if (!Sessions.IsValid()) {
		TArray<FTTSearchNetSessionResult> Results;
		Failure.Broadcast(Results);
	}

	SessionSearch = MakeShareable(new FOnlineSessionSearch);
	SessionSearch->MaxSearchResults = SearchCriteria.MaxResults;
	SessionSearch->bIsLanQuery = (SearchCriteria.SessionInfo.ConnectionType == ETTNetSessionConnectionType::LAN);
	SessionSearch->PingBucketSize = 50;
	
	//SessionSearch->QuerySettings.Set(SEARCH_PRESENCE, true, EOnlineComparisonOp::Equals);

	HSearch = Sessions->AddOnFindSessionsCompleteDelegate_Handle(DSearch);
	Sessions->FindSessions(*SearchCriteria.NetID, SessionSearch.ToSharedRef());	
}

void UTTSearchNetSessionProxy::OnSessionsSearched(bool OperationSuccessful)
{
	auto LogStatus = (OperationSuccessful ? TEXT("SUCCESS") : TEXT("FAILED"));
	TT_LOG_ARGS(TTNetworking, Log, TTConsole, "Session search: %s", LogStatus);

	TArray<FTTSearchNetSessionResult> Results;

	if (OperationSuccessful && SessionSearch.IsValid()) {
		auto Sessions = GetOnlineSessions();

		if (Sessions.IsValid()) {
			Sessions->ClearOnFindSessionsCompleteDelegate_Handle(HSearch);

			for (auto& Result : SessionSearch->SearchResults) {
				Results.Add({ Result });
			}

			Success.Broadcast(Results);
			return;
		}
	}

	Failure.Broadcast(Results);
}

3

Finally, I noticed that if I am playing in PIE and start a session as in step 1 and then click the stop button to kill the PIE and
go back to the editor, the session stays alive. And next time I start a PIE it fails to create a session cause one already exists.

I solved this in my code (step 1) by keeping static info around on the last created session and destroying any session before attempting to create another one.
But the engine’s session proxys do not seem to do anything like this and they still work. Which makes me think if there is something else to the whole session mechanism
that I am not aware of.

UPDATE:

Seems like this might be related to this snippet:

bool UOnlineEngineInterfaceImpl::DoesSessionExist(UWorld* World, FName SessionName)
{
	FOnlineSessionSettings* SessionSettings = nullptr;
	IOnlineSessionPtr SessionInt = Online::GetSessionInterface(World);
	if (SessionInt.IsValid())
	{
		SessionSettings = SessionInt->GetSessionSettings(SessionName);
	}

	return SessionSettings != nullptr;
}

The above code is from OnlineEngineInterfaceImpl which is private in the engine source.
I noticed that if I use the existing session creation proxies, SessionSettings = SessionInt->GetSessionSettings(SessionName); does return settings. But if I create my own session the above code always returns nullptr;

I did make sure that the SessionName matches too (since it’s hardcoded to be ‘Game’). So it’s not about the session name. Not sure why then my session settings are not persisting or not being found.

Maybe something to do with contexts? Cause I noticed the original engine callback proxies use a private helper class that registers sessions with Online::GetSessionInterface But that is private too, so I’be been using instead IOnlineSubsystem::Get()->GetSessionInterface().

1 Like

Ok, found the issue. Yes it was related to which subsystem sessions were registered with.

I had read online in several places to retrieve the online subsystem like so:

auto OnlineSubsystem = IOnlineSubsystem::Get();
auto Sessions = OnlineSubsystem->GetSessionInterface();

But the callback proxies in the engine are actually doing this (paraphrased by me):

UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject);
auto Sessions = Online::GetSessionInterface(World);

Well turns out that Online::GetSessionInterface(World) and OnlineSubsystem->GetSessionInterface() do not return the same subsystem instance… no idea why.

But the solution was to use Online::GetSessionInterface(World).

2 Likes