OSS Steam: unable to get SteamIds for players in a session (for P2P messaging)

Hi Epicfolk,

I’m working on an OSS Steam integration in UE4.27, and I’m hitting a snag:

I set up the online subsystem using the info here, and it seemed to be going smoothly. I’m able to create a session, search for it, and join the session using another Steam account on a different PC.

Once two players are in the session, I have a problem: session->RegisteredPlayers isn’t being updated. My understanding is that this array should contain a list of the SteamIds for all players in the session, but session->RegisteredPlayers.Num() returns 0, and I don’t see any other way to get the SteamIds of players in the session.

Also, I’ve set up delegates for these callbacks, but neither of the delegates fires for the session host when another player joins the session:

  • OnSessionParticipantsChange
  • OnRegisterPlayersComplete

Other pieces of information about the session like session->OwningUserId and session->GetSessionIdStr() return the correct value for all players, so I think the players have joined the session successfully. But I haven’t found a way to exchange the SteamIds! :thinking:

Why I need the SteamIds: I’m trying to set up a P2P connection using SteamSockets, which requires the SteamIds for NAT punchthrough and starting the connection.

Any ideas I can try?


Abridged code snippets, in case they’re relevant:

void UMultiplayerSessionsSubsystem::CreateSession(int32 NumPublicConnections, FString SessionName)
{
   //Create a new session settings object
   TSharedPtr<FOnlineSessionSettings> SessionSettings = MakeShareable(new FOnlineSessionSettings());

    //Standard settings (creating as a lobby, with presence)
	SessionSettings->bIsDedicated = false;
	SessionSettings->NumPublicConnections = NumPublicConnections;
	SessionSettings->bAllowJoinInProgress = true;
	SessionSettings->bAllowJoinViaPresence = true; 
	SessionSettings->bIsLANMatch = false; 
	SessionSettings->bShouldAdvertise = true;
	SessionSettings->bUsesPresence = true; 
	SessionSettings->Set(FName("SessionName"), SessionName, EOnlineDataAdvertisementType::ViaOnlineServiceAndPing);
	SessionSettings->bUseLobbiesIfAvailable = true;

    //Create the session
    SessionInterface->CreateSession(*NetId, NAME_GameSession, *LastSessionSettings);
}

//... Functions for searching for sessions and joining a session ...

//Print some info for testing
void UMultiplayerSessionSubsystem::PrintSessionData()
{
   //Get the named session object (the session name is stored when joining, for lookup)
   FNamedOnlineSession* session = SessionInterface->GetNamedSession(CurrentSessionName);
	
   //Print info. This correctly prints GetSessionIdStr(), but shows 0 for RegisteredPlayers.Num()
   GEngine->AddOnScreenDebugMessage(
		-1,
		15.f,
		FColor::Green,
		FString::Printf(TEXT("UMultiplayerSessionMenu::Tick --- net ids in session %s: %d), *session->GetSessionIdStr(), session->RegisteredPlayers.Num())
	);
}

I don’t know if this will ever help anyone else, but I’ll leave it here just in case:

UE assumes that you’ll be using a client-server model for player connections, and parts of their Online Subsystem are built around that assumption.

The normal way to implement OnlineSubsessionSteam requires calling ServerTravel or ClientTravel for each of the players after joining the session, and from that point the player data is synced using UE’s replication sytem. Then you can get the SteamId of players from the PlayerState, as described in the forum below:
https://forums.unrealengine.com/t/how-to-get-player-steam-id/21709/28?page=2

I did find a way to get the SteamId for players in a lobby without using UE’s replication system, described below. It requires modifications to the OnlineSubsystemSteam plugin. To do modify it, you must move (and delete) the plugin folder out of “C:\Program Files\Epic Games\UE_4.25\Engine\Plugins\Online”, and put it into your own own “\Plugins” directory

You can get the SteamId by implementing a FOnlineAsyncEventSteamLobbyChatUpdate callback. In OnlineSessionInterface.h, add:

//This goes at the top of the file, with the other definitions. The bool at the end is whether the user joined or left the lobby:
DEFINE_ONLINE_DELEGATE_THREE_PARAM(OnLobbyMemberStateChanged, uint64, uint64, bool);

//This goes inside the IOnlineSession class (lower in the file):
DECLARE_MULTICAST_DELEGATE_ThreeParams(FOnLobbyMemberStateChanged, uint64, uint64, bool);
typedef FOnLobbyMemberStateChanged::FDelegate FOnLobbyMemberStateChangedDelegate;

In OnlineAsyncTaskManagerSteam.cpp, find and update the FOnlineAsyncEventSteamLobbyChatUpdate constructor to look like this:

FOnlineAsyncEventSteamLobbyChatUpdate(FOnlineSubsystemSteam* InSubsystem, const LobbyChatUpdate_t& InResults) :
		FOnlineAsyncEvent(InSubsystem),
		CallbackResults(InResults)
	{
		//Trigger any registered callbacks
		FOnlineSessionSteamPtr SessionInt = StaticCastSharedPtr<FOnlineSessionSteam>(Subsystem->GetSessionInterface());
		if (SessionInt.IsValid())
		{
			SessionInt.Get()->TriggerOnLobbyMemberStateChangedDelegates(InResults.m_ulSteamIDLobby, InResults.m_ulSteamIDUserChanged, (InResults.m_rgfChatMemberStateChange == 0x0001)); 

//Note: From the documentation here, 0x0001 is used for entering the lobby and all other values indicate leaving: https://partner.steamgames.com/doc/api/ISteamMatchmaking#EChatMemberStateChange
		}
	}

And finally, put a callback into your code to handle the event and grab the SteamId:

//Register the callback 
SessionInterface->OnLobbyMemberStateChangedDelegates.AddUObject(this, &UMultiplayerSessionsSubsystem::OnLobbyMemberStateChanged);

void UMultiplayerSessionsSubsystem::OnLobbyMemberStateChanged(uint64 LobbyId, uint64 OtherPlayerSteamId, bool enteringLobby)
{
	//Convert the steam id to a string
	std::string idString = std::to_string(OtherPlayerSteamId);
	FString idFString = UTF8_TO_TCHAR(idString.c_str());

	//Print it to the screen
	GEngine->AddOnScreenDebugMessage(
		-1,
		15.f,
		FColor::Orange,
FString::Printf(TEXT("UMultiplayerSessionMenu::OnLobbyMemberStateChanged --- steam id: %s"), *idFString)
	);
}

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.