GetPartyInterface() returns nullptr

Hi.
I’ve been trying to get parties to work. When i run my project as a standalone i can see in my logs that OnlineSubsystem->GetPartyInterface() returns nullptr for me.

I found this post:

Where Ssamuraiss said that Epic has the only working party system and could provide the code but that was 2 years ago and I’ve found 
FOnlineSubsystemSteam::GetPartyInterface 
I’m using steam as my subsystem, it works with SessionInterface and IdentityInterface but not with PartyInterface. 
What am i missing? Do i need to add module or something to DefaultEngine.ini?  Or is Epics code still the only way to go?

Best Regards

I have the same problem! If you find the answer let me know!

"We would like to support the Party interface on other platforms. But, currently it is only available via our own Epic online service which is only used internally at this point. " - Epic

Find some other way, epic havent shipped the code for it to work

PartyInterface is returned as nullptr if your online subsystem plugin doesn’t support it (eg default plugin for Epic Online Services, OnlineSubsystemEOS).

However, you can achieve party functionality with lobbies. Some party code (full file here). It may need further fixes, as I haven’t yet tested it fully

FOnlineSessionSettings UECRGameInstance::GetPartySessionSettings()
{
	FOnlineSessionSettings SessionSettings;
	SessionSettings.NumPublicConnections = 4;
	SessionSettings.bIsDedicated = false;
	SessionSettings.bIsLANMatch = false;
	SessionSettings.bAllowJoinInProgress = true;
	SessionSettings.bAllowJoinViaPresence = false;
	SessionSettings.bUsesPresence = false;
	SessionSettings.bUseLobbiesIfAvailable = true;
        SessionSettings.bAllowInvites = true;
	return SessionSettings;
}

void UECRGameInstance::CreateParty()
{
	if (OnlineSubsystem)
	{
		if (const IOnlineIdentityPtr Identity = OnlineSubsystem->GetIdentityInterface())
		{
			if (IOnlineSessionPtr SessionInterface = OnlineSubsystem->GetSessionInterface())
			{
				if (GetIsInParty())
				{
					OnPartyCreationComplete(PARTY_LOBBY_SESSION_NAME, true);
				}
				else
				{
					SessionInterface->CreateSession(0, PARTY_LOBBY_SESSION_NAME, GetPartySessionSettings());
					SessionInterface->ClearOnCreateSessionCompleteDelegates(this);
					SessionInterface->OnCreateSessionCompleteDelegates.AddUObject(
						this, &UECRGameInstance::OnPartyCreationComplete);
				}
			}
		}
	}
}

bool UECRGameInstance::GetIsInParty()
{
	if (OnlineSubsystem)
	{
		if (const IOnlineIdentityPtr Identity = OnlineSubsystem->GetIdentityInterface())
		{
			if (IOnlineSessionPtr SessionInterface = OnlineSubsystem->GetSessionInterface())
			{
				return SessionInterface->IsPlayerInSession(PARTY_LOBBY_SESSION_NAME, *Identity->GetUniquePlayerId(0).Get());
			}
		}
	}
	return false;
}

bool UECRGameInstance::GetIsPartyLeader()
{
	if (OnlineSubsystem)
	{
		if (const IOnlineIdentityPtr Identity = OnlineSubsystem->GetIdentityInterface())
		{
			if (IOnlineSessionPtr SessionInterface = OnlineSubsystem->GetSessionInterface())
			{
				FNamedOnlineSession* NamedOnlineSession = SessionInterface->GetNamedSession(PARTY_LOBBY_SESSION_NAME);
				if (NamedOnlineSession)
				{
					return NamedOnlineSession->bHosting;
				}
			}
		}
	}
	return false;
}

FString UECRGameInstance::GetPartyMemberName(FUniqueNetIdRepl MemberId)
{
	if (OnlineSubsystem)
	{
		if (APlayerController* PC = GetPrimaryPlayerController())
		{
			if (APlayerState* PlayerState = PC->GetPlayerState<APlayerState>())
			{
				if (PlayerState->GetUniqueId() == MemberId)
				{
					return GetPlayerNickname();
				}
			}
		}

		if (const IOnlineFriendsPtr FriendInterface = OnlineSubsystem->GetFriendsInterface())
		{
			TSharedPtr<FOnlineFriend> OnlineFriend = FriendInterface->
				GetFriend(0, *MemberId.GetUniqueNetId().Get(), "");
			if (OnlineFriend)
			{
				return OnlineFriend->GetDisplayName();
			}
		}
	}
	return "";
}

void UECRGameInstance::KickPartyMember(FUniqueNetIdRepl MemberId)
{
	if (OnlineSubsystem)
	{
		if (const IOnlineIdentityPtr Identity = OnlineSubsystem->GetIdentityInterface())
		{
			if (IOnlineSessionPtr SessionInterface = OnlineSubsystem->GetSessionInterface())
			{
				SessionInterface->
					RemovePlayerFromSession(0, PARTY_LOBBY_SESSION_NAME, *MemberId.GetUniqueNetId().Get());
			}
		}
	}
}

void UECRGameInstance::LeaveParty()
{
	if (OnlineSubsystem)
	{
		if (const IOnlineIdentityPtr Identity = OnlineSubsystem->GetIdentityInterface())
		{
			if (IOnlineSessionPtr SessionInterface = OnlineSubsystem->GetSessionInterface())
			{
				SessionInterface->DestroySession(
					PARTY_LOBBY_SESSION_NAME,
					FOnDestroySessionCompleteDelegate::CreateUObject(
						this, &UECRGameInstance::OnPartyLeaveComplete));
			}
		}
	}
}

void UECRGameInstance::InviteToParty(FUniqueNetIdRepl PlayerId)
{
	if (OnlineSubsystem)
	{
		if (const IOnlineIdentityPtr Identity = OnlineSubsystem->GetIdentityInterface())
		{
			if (IOnlineSessionPtr SessionInterface = OnlineSubsystem->GetSessionInterface())
			{
				SessionInterface->SendSessionInviteToFriend(0, PARTY_LOBBY_SESSION_NAME,
				                                            *PlayerId.GetUniqueNetId().Get());
			}
		}
	}
}

void UECRGameInstance::AcceptPartyInvite(FUniqueNetIdRepl PlayerId)
{
	if (OnlineSubsystem)
	{
		if (const IOnlineIdentityPtr Identity = OnlineSubsystem->GetIdentityInterface())
		{
			if (IOnlineSessionPtr SessionInterface = OnlineSubsystem->GetSessionInterface())
			{
				SessionInterface->ClearOnFindFriendSessionCompleteDelegates(0, this);
				SessionInterface->AddOnFindFriendSessionCompleteDelegate_Handle(
					0, FOnFindFriendSessionCompleteDelegate::CreateUObject(
						this, &UECRGameInstance::OnFindFriendSessionComplete));
				SessionInterface->FindFriendSession(0, *PlayerId.GetUniqueNetId().Get());
			}
		}
	}
}

void UECRGameInstance::DeclinePartyInvite(FUniqueNetIdRepl PlayerId)
{
}

TArray<FECRPartyMemberData> UECRGameInstance::GetPartyMembersList()
{
	TArray<FECRPartyMemberData> Result;
	if (OnlineSubsystem)
	{
		if (const IOnlineIdentityPtr Identity = OnlineSubsystem->GetIdentityInterface())
		{
			if (IOnlineSessionPtr SessionInterface = OnlineSubsystem->GetSessionInterface())
			{
				FNamedOnlineSession* NamedOnlineSession = SessionInterface->GetNamedSession(PARTY_LOBBY_SESSION_NAME);
				if (NamedOnlineSession)
				{
					for (TSharedRef<FUniqueNetId const, ESPMode::ThreadSafe> Member : NamedOnlineSession->
					     RegisteredPlayers)
					{
						FECRPartyMemberData Data = FECRPartyMemberData{
							GetPartyMemberName(Member),
							Member,
							Member == NamedOnlineSession->OwningUserId,
						};
						Result.Add(Data);
					}
				}
			}
		}
	}
	return Result;
}

bool UECRGameInstance::SetPartyData(FString Key, FString Value)
{
	if (OnlineSubsystem)
	{
		if (const IOnlineIdentityPtr Identity = OnlineSubsystem->GetIdentityInterface())
		{
			if (IOnlineSessionPtr SessionInterface = OnlineSubsystem->GetSessionInterface())
			{
				FOnlineSessionSettings* OnlineSessionSettings = SessionInterface->GetSessionSettings(
					PARTY_LOBBY_SESSION_NAME);
				OnlineSessionSettings->Set(FName{Key}, Value);
				return true;
			}
		}
	}
	return false;
}

void UECRGameInstance::StartListeningForPartyEvents()
{
	if (OnlineSubsystem)
	{
		if (const IOnlineIdentityPtr Identity = OnlineSubsystem->GetIdentityInterface())
		{
			if (IOnlineSessionPtr SessionInterface = OnlineSubsystem->GetSessionInterface())
			{
				// Invites
				SessionInterface->ClearOnSessionInviteReceivedDelegates(this);
				SessionInterface->AddOnSessionInviteReceivedDelegate_Handle(
					FOnSessionInviteReceivedDelegate::CreateUObject(this, &UECRGameInstance::OnPartyInviteReceived));

				// Member changes
				SessionInterface->ClearOnSessionParticipantsChangeDelegates(this);
				SessionInterface->AddOnSessionParticipantsChangeDelegate_Handle(
					FOnSessionParticipantsChangeDelegate::CreateUObject(this, &UECRGameInstance::OnPartyMemberJoined));

				// Party data updates
				SessionInterface->ClearOnSessionSettingsUpdatedDelegates(this);
				SessionInterface->AddOnSessionSettingsUpdatedDelegate_Handle(
					FOnSessionSettingsUpdatedDelegate::CreateUObject(this, &UECRGameInstance::OnPartyDataReceived));
			}
		}
	}
}

I dived more into the topic and found out following things:

  1. While lobbies can theoretically be used as parties, EOS implementation of them doesn’t allow to update custom parameters correctly, thank you Epic Games again (eg you can set session settings custom parameter on host to enter matchmaking queue, a delegate about session data change will be fired on clients, but custom parameter will be missing if advertisment via ping and only first value, no future updates, if via online subsystem).
  2. Sessions custom parameters in session settings will work, but I want to save them for matches, not for parties, because dedicated servers can’t create lobbies
  3. Anyway joining or creating lobby / session with OSS will trigger map change by the engine, which is completely undesirable in some cases, like parties
  4. I won’t be struggling with Epic Games ■■■■ anymore, as they don’t care about us making parties in our games via their online services, I’ll just make a websocket implementation for parties myself.