Files
UnrealEngine/Engine/Plugins/Online/OnlineSubsystemTencent/Source/Private/OnlineSessionTencentRail.cpp
2025-05-18 13:04:45 +08:00

1235 lines
43 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "OnlineSessionTencentRail.h"
#if WITH_TENCENT_RAIL_SDK
#include "Interfaces/OnlineIdentityInterface.h"
#include "Online/OnlineBase.h"
#include "OnlineAsyncTasksTencent.h"
#include "OnlinePresenceTencent.h"
#include "OnlineSubsystemTencent.h"
#include "OnlineSubsystemTencentPrivate.h"
#include "MetadataKeysRail.h"
#include "Misc/App.h"
#include "Misc/CommandLine.h"
#define RAIL_INVITE_RAILID TEXT("--rail_connect_to_railid=")
#define RAIL_INVITE_CMDLINE TEXT("--rail_connect_cmd=")
FOnlineSessionTencentRail::FOnlineSessionTencentRail(FOnlineSubsystemTencent* InSubsystem)
: FOnlineSessionTencent(InSubsystem)
{
CheckPendingSessionInvite();
}
FOnlineSessionTencentRail::~FOnlineSessionTencentRail()
{
}
bool FOnlineSessionTencentRail::Init()
{
bool bSuccess = false;
if (FOnlineSessionTencent::Init())
{
FOnFriendMetadataChangedDelegate Delegate = FOnFriendMetadataChangedDelegate::CreateThreadSafeSP(this, &FOnlineSessionTencentRail::OnFriendMetadataChangedEvent);
OnFriendMetadataChangedDelegateHandle = TencentSubsystem->AddOnFriendMetadataChangedDelegate_Handle(Delegate);
bSuccess = true;
}
return bSuccess;
}
void FOnlineSessionTencentRail::Shutdown()
{
RailSdkWrapper& RailSDK = RailSdkWrapper::Get();
if (RailSDK.IsInitialized())
{
rail::IRailFactory* RailFactory = RailSDK.RailFactory();
if (RailFactory)
{
rail::IRailFriends* Friends = RailFactory->RailFriends();
if (Friends)
{
rail::RailResult RailResult = Friends->AsyncSetInviteCommandLine(rail::RailString(), rail::RailString());
}
}
}
TencentSubsystem->ClearOnFriendMetadataChangedDelegate_Handle(OnFriendMetadataChangedDelegateHandle);
}
void FOnlineSessionTencentRail::Tick(float DeltaTime)
{
//SCOPE_CYCLE_COUNTER(STAT_Session_Interface);
TickPendingInvites(DeltaTime);
}
void FOnlineSessionTencentRail::OnFriendMetadataChangedEvent(const FUniqueNetId& UserId, const FMetadataPropertiesRail& Metadata)
{
UE_LOG_ONLINE_SESSION(Verbose, TEXT("FOnlineSessionTencentRail::OnFriendMetadataChangedEvent"));
}
void FOnlineSessionTencentRail::CheckPendingSessionInvite()
{
const TCHAR* CmdLine = FCommandLine::Get();
FString CmdLineStr(CmdLine);
const FString UserRailIdCmd = RAIL_INVITE_RAILID;
int32 UserIdIdx = CmdLineStr.Find(UserRailIdCmd, ESearchCase::IgnoreCase, ESearchDir::FromEnd);
if (UserIdIdx != INDEX_NONE)
{
// Go to the value for the parameter
const TCHAR* Str = CmdLine + UserIdIdx + UserRailIdCmd.Len();
FString UserIdIdStr = FParse::Token(Str, 0).TrimStartAndEnd();
int64 UserId = FCString::Strtoui64(*UserIdIdStr, NULL, 10);
if (UserId > 0)
{
PendingInvite.InviterUserId = FUniqueNetIdRail::Create(UserId);
PendingInvite.bValidInvite = true;
}
}
const FString UserCmdLineArgs = RAIL_INVITE_CMDLINE;
int32 CmdLineIdx = CmdLineStr.Find(UserCmdLineArgs, ESearchCase::IgnoreCase, ESearchDir::FromEnd);
if (CmdLineIdx != INDEX_NONE)
{
// Go to the value for the parameter
const TCHAR* Str = CmdLine + CmdLineIdx + UserCmdLineArgs.Len();
FString UserCmdLineStr = FParse::Token(Str, 0).TrimStartAndEnd();
if (!UserCmdLineStr.IsEmpty())
{
PendingInvite.CommandLineArgs = UserCmdLineStr;
}
}
}
void FOnlineSessionTencentRail::TickPendingInvites(float DeltaTime)
{
if (PendingInvite.bValidInvite)
{
if (OnSessionUserInviteAcceptedDelegates.IsBound())
{
IOnlineIdentityPtr IdentityInt = TencentSubsystem->GetIdentityInterface();
// Wait until we have a valid user
FUniqueNetIdRailPtr UserId = StaticCastSharedPtr<const FUniqueNetIdRail>(GetFirstSignedInUser(IdentityInt));
if (UserId.IsValid() && ensure(PendingInvite.InviterUserId.IsValid()))
{
QueryAcceptedUserInvitation(UserId.ToSharedRef(), PendingInvite.InviterUserId.ToSharedRef());
// Clear the invite
PendingInvite.bValidInvite = false;
}
}
}
}
void FOnlineSessionTencentRail::QueryAcceptedUserInvitation(FUniqueNetIdRailRef InLocalUser, FUniqueNetIdRailRef InRemoteUser)
{
TWeakPtr<FOnlineSessionTencent, ESPMode::ThreadSafe> LocalWeakThis(AsShared());
FOnOnlineAsyncTaskRailGetUserInviteComplete CompletionDelegate = FOnOnlineAsyncTaskRailGetUserInviteComplete::CreateLambda([InLocalUser, LocalWeakThis](const FGetUserInviteTaskResult& Result)
{
FOnlineSessionTencentRailPtr StrongThis = StaticCastSharedPtr<FOnlineSessionTencentRail>(LocalWeakThis.Pin());
if (StrongThis.IsValid())
{
const int32 LocalUserIdx = StrongThis->GetLocalUserIdx(*InLocalUser);
if (Result.Error.WasSuccessful() && Result.Metadata.Num() && !Result.Commandline.IsEmpty())
{
TSharedRef<FOnlineSessionSearch> SessionSearch = MakeShared<FOnlineSessionSearch>();
StrongThis->ParseSearchResult(SessionSearch, Result);
if (SessionSearch->SearchResults.Num())
{
StrongThis->TriggerOnSessionUserInviteAcceptedDelegates(Result.Error.WasSuccessful(), LocalUserIdx, InLocalUser, SessionSearch->SearchResults[0]);
}
else
{
FOnlineSessionSearchResult EmptyResult;
StrongThis->TriggerOnSessionUserInviteAcceptedDelegates(Result.Error.WasSuccessful(), LocalUserIdx, InLocalUser, EmptyResult);
}
}
else
{
FOnlineSessionSearchResult EmptyResult;
StrongThis->TriggerOnSessionUserInviteAcceptedDelegates(Result.Error.WasSuccessful(), LocalUserIdx, InLocalUser, EmptyResult);
}
}
});
FOnlineAsyncTaskRailGetUserInvite* NewTask = new FOnlineAsyncTaskRailGetUserInvite(TencentSubsystem, *InRemoteUser, CompletionDelegate);
UE_LOG_ONLINE_SESSION(Verbose, TEXT("%s"), *NewTask->ToString());
TencentSubsystem->QueueAsyncTask(NewTask);
}
bool FOnlineSessionTencentRail::CreateSession(int32 HostingPlayerNum, FName SessionName, const FOnlineSessionSettings& NewSessionSettings)
{
uint32 Result = ONLINE_FAIL;
// Check for an existing session
FNamedOnlineSession* Session = GetNamedSession(SessionName);
if (Session == nullptr)
{
IOnlineIdentityPtr IdentityInt = TencentSubsystem->GetIdentityInterface();
if (IdentityInt.IsValid() && IdentityInt->GetLoginStatus(HostingPlayerNum) >= ELoginStatus::UsingLocalProfile)
{
// Create a new session and deep copy the game settings
Session = AddNamedSession(SessionName, NewSessionSettings);
check(Session);
Session->SessionState = EOnlineSessionState::Creating;
Session->OwningUserId = IdentityInt->GetUniquePlayerId(HostingPlayerNum);
Session->OwningUserName = IdentityInt->GetPlayerNickname(HostingPlayerNum);
if (Session->OwningUserId.IsValid() && Session->OwningUserId->IsValid())
{
// RegisterPlayer will update these values for the local player
Session->NumOpenPrivateConnections = NewSessionSettings.NumPrivateConnections;
Session->NumOpenPublicConnections = NewSessionSettings.NumPublicConnections;
Session->HostingPlayerNum = HostingPlayerNum;
// Unique identifier of this build for compatibility
Session->SessionSettings.BuildUniqueId = GetBuildUniqueId();
// Create Internet or LAN match
if (!NewSessionSettings.bIsLANMatch)
{
Result = CreateInternetSession(HostingPlayerNum, Session);
}
else
{
/** LAN NYI */
}
}
else
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("Cannot create session '%s': invalid user (%d)."), *SessionName.ToString(), HostingPlayerNum);
}
if (Result != ONLINE_IO_PENDING)
{
// Set the game state as pending (not started)
Session->SessionState = EOnlineSessionState::Pending;
if (Result != ONLINE_SUCCESS)
{
// Clean up the session info so we don't get into a confused state
RemoveNamedSession(SessionName);
}
else
{
RegisterLocalPlayers(Session);
}
}
}
else
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("Cannot create session '%s': user not logged in (%d)."), *SessionName.ToString(), HostingPlayerNum);
}
}
else
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("Cannot create session '%s': session already exists."), *SessionName.ToString());
}
if (Result != ONLINE_IO_PENDING)
{
TWeakPtr<FOnlineSessionTencent, ESPMode::ThreadSafe> LocalWeakThis(AsShared());
TencentSubsystem->ExecuteNextTick([LocalWeakThis, SessionName, Result]()
{
FOnlineSessionTencentRailPtr StrongThis = StaticCastSharedPtr<FOnlineSessionTencentRail>(LocalWeakThis.Pin());
if (StrongThis.IsValid())
{
StrongThis->TriggerOnCreateSessionCompleteDelegates(SessionName, (Result == ONLINE_SUCCESS) ? true : false);
}
});
}
return (Result == ONLINE_IO_PENDING) || (Result == ONLINE_SUCCESS);
}
bool FOnlineSessionTencentRail::CreateSession(const FUniqueNetId& HostingPlayerId, FName SessionName, const FOnlineSessionSettings& NewSessionSettings)
{
return CreateSession(GetLocalUserIdx(HostingPlayerId), SessionName, NewSessionSettings);
}
uint32 FOnlineSessionTencentRail::CreateInternetSession(int32 HostingPlayerNum, FNamedOnlineSession* Session)
{
check(Session && !Session->SessionInfo.IsValid());
TSharedRef<FOnlineSessionInfoTencent> SessionInfo = MakeShared<FOnlineSessionInfoTencent>();
SessionInfo->Init();
Session->SessionInfo = SessionInfo;
if (Session->SessionSettings.bUsesPresence)
{
// Always at least one frame later
FName SessionName = Session->SessionName;
TWeakPtr<FOnlineSessionTencent, ESPMode::ThreadSafe> LocalWeakThis(AsShared());
UpdateSessionMetadata(*Session, FOnUpdateSessionMetadataComplete::CreateLambda([SessionName, LocalWeakThis](const FOnlineError& Error)
{
FOnlineSessionTencentRailPtr StrongThis = StaticCastSharedPtr<FOnlineSessionTencentRail>(LocalWeakThis.Pin());
if (StrongThis.IsValid())
{
StrongThis->OnCreateInternetSessionComplete(SessionName, Error);
}
}));
return SessionInfo->IsValid() ? ONLINE_IO_PENDING : ONLINE_FAIL;
}
else
{
return SessionInfo->IsValid() ? ONLINE_SUCCESS : ONLINE_FAIL;
}
}
void FOnlineSessionTencentRail::OnCreateInternetSessionComplete(FName SessionName, const FOnlineError& Error)
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("CreateSession %s: %s"), *SessionName.ToString(), *Error.ToLogString());
bool bWasSuccessful = Error.WasSuccessful();
FNamedOnlineSession* NamedSession = GetNamedSession(SessionName);
if (NamedSession)
{
if (Error.WasSuccessful())
{
NamedSession->SessionState = EOnlineSessionState::Pending;
}
else
{
RemoveNamedSession(SessionName);
}
}
else
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("Unable to find session during creation = %s"), *SessionName.ToString());
bWasSuccessful = false;
}
TriggerOnCreateSessionCompleteDelegates(SessionName, bWasSuccessful);
}
bool FOnlineSessionTencentRail::StartSession(FName SessionName)
{
uint32 Result = ONLINE_FAIL;
// Grab the session information by name
FNamedOnlineSession* Session = GetNamedSession(SessionName);
if (Session)
{
// Can't start a match multiple times
if (Session->SessionState == EOnlineSessionState::Pending ||
Session->SessionState == EOnlineSessionState::Ended)
{
if (!Session->SessionSettings.bIsLANMatch)
{
Result = StartInternetSession(Session);
}
else
{
/** NYI LAN */
}
}
else
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("Can't start an online session (%s) in state %s"),
*SessionName.ToString(),
EOnlineSessionState::ToString(Session->SessionState));
}
}
else
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("Can't start an online game for session (%s) that hasn't been created"), *SessionName.ToString());
}
if (Result != ONLINE_IO_PENDING)
{
// Just trigger the delegate
TriggerOnStartSessionCompleteDelegates(SessionName, (Result == ONLINE_SUCCESS) ? true : false);
}
return Result == ONLINE_SUCCESS || Result == ONLINE_IO_PENDING;
}
uint32 FOnlineSessionTencentRail::StartInternetSession(FNamedOnlineSession* Session)
{
Session->SessionState = EOnlineSessionState::InProgress;
return ONLINE_SUCCESS;
}
bool FOnlineSessionTencentRail::UpdateSession(FName SessionName, FOnlineSessionSettings& UpdatedSessionSettings, bool bShouldRefreshOnlineData)
{
int32 Result = ONLINE_FAIL;
// Grab the session information by name
FNamedOnlineSessionTencent* Session = GetNamedSessionTencent(SessionName);
if (Session)
{
if (!Session->SessionSettings.bIsLANMatch)
{
TSharedPtr<FOnlineSessionInfoTencent> SessionInfo = StaticCastSharedPtr<FOnlineSessionInfoTencent>(Session->SessionInfo);
Session->SessionSettings = UpdatedSessionSettings;
if (bShouldRefreshOnlineData)
{
//const bool bOwnsSession = OwnsSession(Session);
//if (Session->SessionSettings.bUsesPresence && bOwnsSession)
if (Session->SessionSettings.bUsesPresence)
{
TWeakPtr<FOnlineSessionTencent, ESPMode::ThreadSafe> LocalWeakThis(AsShared());
UpdateSessionMetadata(*Session, FOnUpdateSessionMetadataComplete::CreateLambda([SessionName, LocalWeakThis](const FOnlineError& Error)
{
FOnlineSessionTencentRailPtr StrongThis = StaticCastSharedPtr<FOnlineSessionTencentRail>(LocalWeakThis.Pin());
if (StrongThis.IsValid())
{
StrongThis->OnUpdateSessionComplete(SessionName, Error);
}
}));
Result = ONLINE_IO_PENDING;
}
else
{
Result = ONLINE_SUCCESS;
}
}
else
{
UE_LOG_ONLINE_SESSION(Log, TEXT("UpdateInternetSession complete, skipping online refresh."));
Result = ONLINE_SUCCESS;
}
}
else
{
Session->SessionSettings = UpdatedSessionSettings;
Result = ONLINE_SUCCESS;
}
}
else
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("No session (%s) found for update!"), *SessionName.ToString());
}
if (Result != ONLINE_IO_PENDING)
{
TriggerOnUpdateSessionCompleteDelegates(SessionName, Result == ONLINE_SUCCESS);
}
return Result == ONLINE_SUCCESS || Result == ONLINE_IO_PENDING;
}
void FOnlineSessionTencentRail::OnUpdateSessionComplete(FName SessionName, const FOnlineError& Error)
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("UpdateSession %s: %s"), *SessionName.ToString(), *Error.ToLogString());
bool bWasSuccessful = Error.WasSuccessful();
FNamedOnlineSession* NamedSession = GetNamedSession(SessionName);
if (!NamedSession)
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("Unable to find session during update = %s"), *SessionName.ToString());
bWasSuccessful = false;
}
TriggerOnUpdateSessionCompleteDelegates(SessionName, bWasSuccessful);
}
bool FOnlineSessionTencentRail::EndSession(FName SessionName)
{
uint32 Result = ONLINE_FAIL;
// Grab the session information by name
FNamedOnlineSession* Session = GetNamedSession(SessionName);
if (Session)
{
// Can't end a match that isn't in progress
if (Session->SessionState == EOnlineSessionState::InProgress)
{
if (!Session->SessionSettings.bIsLANMatch)
{
Result = EndInternetSession(Session);
}
else
{
/** NYI LAN */
}
}
else
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("Can't end session (%s) in state %s"),
*SessionName.ToString(),
EOnlineSessionState::ToString(Session->SessionState));
}
}
else
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("Can't end an online game for session (%s) that hasn't been created"),
*SessionName.ToString());
}
if (Result != ONLINE_IO_PENDING)
{
if (Session)
{
Session->SessionState = EOnlineSessionState::Ended;
}
TriggerOnEndSessionCompleteDelegates(SessionName, (Result == ONLINE_SUCCESS) ? true : false);
}
return Result == ONLINE_SUCCESS || Result == ONLINE_IO_PENDING;
}
uint32 FOnlineSessionTencentRail::EndInternetSession(FNamedOnlineSession* Session)
{
uint32 Result = ONLINE_SUCCESS;
// Only called from EndSession/DestroySession and presumes only in InProgress state
check(Session && Session->SessionState == EOnlineSessionState::InProgress);
Session->SessionState = EOnlineSessionState::Ended;
return Result;
}
bool FOnlineSessionTencentRail::DestroySession(FName SessionName, const FOnDestroySessionCompleteDelegate& CompletionDelegate)
{
uint32 Result = ONLINE_FAIL;
// Find the session in question
FNamedOnlineSession* Session = GetNamedSession(SessionName);
if (Session)
{
if (Session->SessionState != EOnlineSessionState::Destroying)
{
if (!Session->SessionSettings.bIsLANMatch)
{
if (Session->SessionState == EOnlineSessionState::InProgress)
{
// Enqueue all the end session tasks first
Result = EndInternetSession(Session);
}
Result = DestroyInternetSession(Session, CompletionDelegate);
}
else
{
/** NYI LAN */
}
if (Result != ONLINE_IO_PENDING)
{
// The session info is no longer needed
RemoveNamedSession(Session->SessionName);
CompletionDelegate.ExecuteIfBound(SessionName, (Result == ONLINE_SUCCESS) ? true : false);
TriggerOnDestroySessionCompleteDelegates(SessionName, (Result == ONLINE_SUCCESS) ? true : false);
}
}
else
{
// Purposefully skip the delegate call as one should already be in flight
UE_LOG_ONLINE_SESSION(Warning, TEXT("Already in process of destroying session (%s)"), *SessionName.ToString());
}
}
else
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("Can't destroy a null online session (%s)"), *SessionName.ToString());
CompletionDelegate.ExecuteIfBound(SessionName, false);
TriggerOnDestroySessionCompleteDelegates(SessionName, false);
}
return Result == ONLINE_SUCCESS || Result == ONLINE_IO_PENDING;
}
uint32 FOnlineSessionTencentRail::DestroyInternetSession(FNamedOnlineSession* Session, const FOnDestroySessionCompleteDelegate& CompletionDelegate)
{
uint32 Result = ONLINE_SUCCESS;
Session->SessionState = EOnlineSessionState::Destroying;
if (Session->SessionSettings.bUsesPresence)
{
const FName SessionName = Session->SessionName;
// Clear the invite command line
FOnlineAsyncTaskRailSetInviteCommandline* NewCmdLineTask = new FOnlineAsyncTaskRailSetInviteCommandline(TencentSubsystem, FString(), FOnOnlineAsyncTaskRailSetInviteCommandlineComplete());
TencentSubsystem->QueueAsyncTask(NewCmdLineTask);
// Clear the session metadata keys by setting all known keys back to empty
FMetadataPropertiesRail EmptySessionMetadata;
TWeakPtr<FOnlineSessionTencent, ESPMode::ThreadSafe> LocalWeakThis(AsShared());
FOnlineAsyncTaskRailSetUserMetadata* NewMetadataTask = new FOnlineAsyncTaskRailSetSessionMetadata(TencentSubsystem, EmptySessionMetadata, FOnOnlineAsyncTaskRailSetUserMetadataComplete::CreateLambda([SessionName, LocalWeakThis, CompletionDelegate](const FSetUserMetadataTaskResult& Result)
{
FOnlineSessionTencentRailPtr StrongThis = StaticCastSharedPtr<FOnlineSessionTencentRail>(LocalWeakThis.Pin());
if (StrongThis.IsValid())
{
// The session info is no longer needed
StrongThis->RemoveNamedSession(SessionName);
CompletionDelegate.ExecuteIfBound(SessionName, Result.Error.WasSuccessful());
StrongThis->TriggerOnDestroySessionCompleteDelegates(SessionName, Result.Error.WasSuccessful());
}
}));
TencentSubsystem->QueueAsyncTask(NewMetadataTask);
Result = ONLINE_IO_PENDING;
}
return Result;
}
bool FOnlineSessionTencentRail::JoinSession(int32 PlayerNum, FName SessionName, const FOnlineSessionSearchResult& DesiredSession)
{
uint32 Return = ONLINE_FAIL;
FNamedOnlineSession* Session = GetNamedSession(SessionName);
// Don't join a session if already in one or hosting one
if (Session == nullptr)
{
// Create a named session from the search result data
Session = AddNamedSession(SessionName, DesiredSession.Session);
Session->HostingPlayerNum = PlayerNum;
// Create Internet or LAN match
if (!Session->SessionSettings.bIsLANMatch)
{
if (DesiredSession.Session.SessionInfo.IsValid())
{
TSharedPtr<const FOnlineSessionInfoTencent> SearchSessionInfo = StaticCastSharedPtr<const FOnlineSessionInfoTencent>(DesiredSession.Session.SessionInfo);
FOnlineSessionInfoTencent* NewSessionInfo = new FOnlineSessionInfoTencent(SearchSessionInfo->SessionId);
Session->SessionInfo = MakeShareable(NewSessionInfo);
Return = JoinInternetSession(PlayerNum, Session, &DesiredSession.Session);
}
else
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("Invalid session info on search result"), *SessionName.ToString());
}
}
else
{
/** NYI LAN */
}
if (Return != ONLINE_IO_PENDING)
{
if (Return != ONLINE_SUCCESS)
{
// Clean up the session info so we don't get into a confused state
RemoveNamedSession(SessionName);
}
else
{
RegisterLocalPlayers(Session);
}
}
}
else
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("Session (%s) already exists, can't join twice"), *SessionName.ToString());
}
if (Return != ONLINE_IO_PENDING)
{
// Just trigger the delegate as having failed
TriggerOnJoinSessionCompleteDelegates(SessionName, Return == ONLINE_SUCCESS ? EOnJoinSessionCompleteResult::Success : EOnJoinSessionCompleteResult::UnknownError);
}
return Return == ONLINE_SUCCESS || Return == ONLINE_IO_PENDING;
}
bool FOnlineSessionTencentRail::JoinSession(const FUniqueNetId& PlayerId, FName SessionName, const FOnlineSessionSearchResult& DesiredSession)
{
return JoinSession(GetLocalUserIdx(PlayerId), SessionName, DesiredSession);
}
uint32 FOnlineSessionTencentRail::JoinInternetSession(int32 PlayerNum, FNamedOnlineSession* Session, const FOnlineSession* SearchSession)
{
uint32 Result = ONLINE_FAIL;
if (Session->SessionInfo.IsValid())
{
TSharedPtr<FOnlineSessionInfoTencent> TencentSessionInfo = StaticCastSharedPtr<FOnlineSessionInfoTencent>(Session->SessionInfo);
if (TencentSessionInfo->SessionId.IsValid())
{
IOnlineIdentityPtr IdentityInt = TencentSubsystem->GetIdentityInterface();
if (IdentityInt.IsValid())
{
FUniqueNetIdPtr UniqueId = IdentityInt->GetUniquePlayerId(PlayerNum);
if (UniqueId.IsValid() && UniqueId->IsValid())
{
if (Session->SessionSettings.bUsesPresence)
{
FName SessionName = Session->SessionName;
TWeakPtr<FOnlineSessionTencent, ESPMode::ThreadSafe> LocalWeakThis(AsShared());
UpdateSessionMetadata(*Session, FOnUpdateSessionMetadataComplete::CreateLambda([SessionName, LocalWeakThis](const FOnlineError& Error)
{
FOnlineSessionTencentRailPtr StrongThis = StaticCastSharedPtr<FOnlineSessionTencentRail>(LocalWeakThis.Pin());
if (StrongThis.IsValid())
{
StrongThis->OnJoinInternetSessionComplete(SessionName, Error);
}
}));
Result = ONLINE_IO_PENDING;
}
else
{
Session->SessionState = EOnlineSessionState::Pending;
RegisterLocalPlayers(Session);
Result = ONLINE_SUCCESS;
}
}
else
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("Session (%s) invalid user id (%d)"), *Session->SessionName.ToString(), PlayerNum);
}
}
else
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("No identity interface trying to join session (%s)"), *Session->SessionName.ToString());
}
}
else
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("Session (%s) has invalid session id"), *Session->SessionName.ToString());
}
}
else
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("Session (%s) has invalid session info"), *Session->SessionName.ToString());
}
return Result;
}
void FOnlineSessionTencentRail::OnJoinInternetSessionComplete(FName SessionName, const FOnlineError& Error)
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("JoinSession %s: %s"), *SessionName.ToString(), *Error.ToLogString());
bool bWasSuccessful = Error.WasSuccessful();
FNamedOnlineSession* NamedSession = GetNamedSession(SessionName);
if (NamedSession)
{
if (Error.WasSuccessful())
{
NamedSession->SessionState = EOnlineSessionState::Pending;
}
else
{
RemoveNamedSession(SessionName);
}
}
else
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("Unable to find session during join = %s"), *SessionName.ToString());
bWasSuccessful = false;
}
TriggerOnJoinSessionCompleteDelegates(SessionName, bWasSuccessful ? EOnJoinSessionCompleteResult::Success : EOnJoinSessionCompleteResult::UnknownError);
}
bool FOnlineSessionTencentRail::RegisterPlayer(FName SessionName, const FUniqueNetId& PlayerId, bool bWasInvited)
{
TArray< FUniqueNetIdRef > Players;
Players.Add(FUniqueNetIdRail::Create(PlayerId));
return RegisterPlayers(SessionName, Players, bWasInvited);
}
bool FOnlineSessionTencentRail::RegisterPlayers(FName SessionName, const TArray< FUniqueNetIdRef >& Players, bool bWasInvited)
{
bool bSuccess = false;
FNamedOnlineSessionTencent* Session = GetNamedSessionTencent(SessionName);
if (Session)
{
if (Session->SessionInfo.IsValid())
{
TArray<FReportPlayedWithUser> ReportedUsers;
for (int32 PlayerIdx = 0; PlayerIdx < Players.Num(); PlayerIdx++)
{
const FUniqueNetIdRef& PlayerId = Players[PlayerIdx];
FUniqueNetIdMatcher PlayerMatch(*PlayerId);
if (Session->RegisteredPlayers.IndexOfByPredicate(PlayerMatch) == INDEX_NONE)
{
Session->RegisteredPlayers.Add(PlayerId);
if (GetLocalUserIdx(*PlayerId) == INDEX_NONE)
{
// Only report remote users
ReportedUsers.Emplace(PlayerId, FApp::GetProjectName());
}
}
else
{
UE_LOG_ONLINE_SESSION(Log, TEXT("Player %s already registered in session %s"), *PlayerId->ToDebugString(), *SessionName.ToString());
}
}
if (ReportedUsers.Num() > 0)
{
FOnlineAsyncTaskRailReportPlayedWithUsers* NewTask = new FOnlineAsyncTaskRailReportPlayedWithUsers(TencentSubsystem, ReportedUsers, FOnOnlineAsyncTaskRailReportPlayedWithUsersComplete::CreateLambda([](const FReportPlayedWithUsersTaskResult& Result)
{
if (!Result.Error.WasSuccessful())
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("Failed to report player: %s"), *Result.Error.ToLogString());
}
}));
TencentSubsystem->QueueAsyncTask(NewTask);
}
bSuccess = true;
}
else
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("No session info to join for session (%s)"), *SessionName.ToString());
}
}
else
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("No game present to join for session (%s)"), *SessionName.ToString());
}
TriggerOnRegisterPlayersCompleteDelegates(SessionName, Players, bSuccess);
return bSuccess;
}
void FOnlineSessionTencentRail::RegisterLocalPlayers(FNamedOnlineSession* Session)
{
if (!TencentSubsystem->IsDedicated())
{
IOnlineIdentityPtr IdentityInt = TencentSubsystem->GetIdentityInterface();
if (IdentityInt.IsValid())
{
TArray<FUniqueNetIdRef > PlayersToRegister;
for (int32 Index = 0; Index < MAX_LOCAL_PLAYERS; Index++)
{
FUniqueNetIdPtr UserId = IdentityInt->GetUniquePlayerId(Index);
if (UserId.IsValid())
{
PlayersToRegister.Add(UserId.ToSharedRef());
}
}
if (PlayersToRegister.Num())
{
RegisterPlayers(Session->SessionName, PlayersToRegister, false);
}
}
}
}
bool FOnlineSessionTencentRail::UnregisterPlayer(FName SessionName, const FUniqueNetId& PlayerId)
{
TArray< FUniqueNetIdRef > Players;
Players.Add(FUniqueNetIdRail::Create(PlayerId));
return UnregisterPlayers(SessionName, Players);
}
bool FOnlineSessionTencentRail::UnregisterPlayers(FName SessionName, const TArray< FUniqueNetIdRef >& Players)
{
bool bSuccess = false;
FNamedOnlineSessionTencent* Session = GetNamedSessionTencent(SessionName);
if (Session)
{
if (Session->SessionInfo.IsValid())
{
for (int32 PlayerIdx = 0; PlayerIdx < Players.Num(); PlayerIdx++)
{
const FUniqueNetIdRef& PlayerId = Players[PlayerIdx];
FUniqueNetIdMatcher PlayerMatch(*PlayerId);
int32 RegistrantIndex = Session->RegisteredPlayers.IndexOfByPredicate(PlayerMatch);
if (RegistrantIndex != INDEX_NONE)
{
Session->RegisteredPlayers.RemoveAtSwap(RegistrantIndex);
}
else
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("Player %s is not part of session (%s)"), *PlayerId->ToDebugString(), *SessionName.ToString());
}
}
bSuccess = true;
}
else
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("No session info to leave for session (%s)"), *SessionName.ToString());
}
}
else
{
UE_LOG_ONLINE_SESSION(Warning, TEXT("No game present to leave for session (%s)"), *SessionName.ToString());
}
TriggerOnUnregisterPlayersCompleteDelegates(SessionName, Players, bSuccess);
return bSuccess;
}
bool FOnlineSessionTencentRail::OwnsSession(FNamedOnlineSession* Session) const
{
bool bOwnsSession = false;
if (Session)
{
IOnlineIdentityPtr IdentityInt = TencentSubsystem->GetIdentityInterface();
if (IdentityInt.IsValid())
{
FUniqueNetIdPtr UserId = IdentityInt->GetUniquePlayerId(Session->HostingPlayerNum);
bOwnsSession = (UserId.IsValid() && (*UserId == *Session->OwningUserId)) ? true : false;
}
}
return bOwnsSession;
}
void FOnlineSessionTencentRail::RegisterLocalPlayer(const FUniqueNetId& PlayerId, FName SessionName, const FOnRegisterLocalPlayerCompleteDelegate& Delegate)
{
Delegate.ExecuteIfBound(PlayerId, EOnJoinSessionCompleteResult::Success);
}
void FOnlineSessionTencentRail::UnregisterLocalPlayer(const FUniqueNetId& PlayerId, FName SessionName, const FOnUnregisterLocalPlayerCompleteDelegate& Delegate)
{
Delegate.ExecuteIfBound(PlayerId, true);
}
void FOnlineSessionTencentRail::DumpSessionState()
{
FOnlineSessionTencent::DumpSessionState();
UE_LOG_ONLINE_SESSION(Display, TEXT("Current Known Session Keys:"));
for (const FString& CurrentKey : CurrentSessionPresenceKeys)
{
UE_LOG_ONLINE_SESSION(Display, TEXT("- %s"), *CurrentKey);
}
}
void FOnlineSessionTencentRail::UpdateSessionMetadata(const FNamedOnlineSession& InNamedSession, const FOnUpdateSessionMetadataComplete& InCompletionDelegate)
{
// Does this change require talking to the presence system to update keys
const bool bIsPresenceSession = InNamedSession.SessionSettings.bUsesPresence;
// Set/Unset the invite command line based on the session ability to allow invites
const bool bAllowInvites = InNamedSession.SessionSettings.bAllowInvites;
FMetadataPropertiesRail NewSessionMetadata;
if (InNamedSession.SessionInfo.IsValid() && InNamedSession.SessionInfo->IsValid())
{
const FOnlineSessionSettings& SessionSettings = InNamedSession.SessionSettings;
TSharedPtr<const FOnlineSessionInfo> SessionInfo = InNamedSession.SessionInfo;
NewSessionMetadata.Add(RAIL_SESSION_ID_KEY, FVariantData(InNamedSession.SessionInfo->GetSessionId().ToString()));
NewSessionMetadata.Add(RAIL_SESSION_OWNING_USER_ID_KEY, FVariantData(InNamedSession.OwningUserId->ToString()));
int32 NumBits = 0;
uint32 SessionBits = 0;
SessionBits |= SessionSettings.bShouldAdvertise ? (1 << NumBits) : 0; NumBits++;
SessionBits |= SessionSettings.bAllowJoinInProgress ? (1 << NumBits) : 0; NumBits++;
SessionBits |= SessionSettings.bAllowInvites ? (1 << NumBits) : 0; NumBits++;
SessionBits |= SessionSettings.bAllowJoinViaPresence ? (1 << NumBits) : 0; NumBits++;
SessionBits |= SessionSettings.bAllowJoinViaPresenceFriendsOnly ? (1 << NumBits) : 0; NumBits++;
NewSessionMetadata.Add(RAIL_SESSION_SESSIONBITS_KEY, FVariantData(SessionBits));
NewSessionMetadata.Add(RAIL_SESSION_BUILDUNIQUEID_KEY, FVariantData(SessionSettings.BuildUniqueId));
for (const TPair<FName, FOnlineSessionSetting>& Pair : SessionSettings.Settings)
{
if ((Pair.Value.AdvertisementType == EOnlineDataAdvertisementType::Type::ViaOnlineService) ||
(Pair.Value.AdvertisementType == EOnlineDataAdvertisementType::Type::ViaOnlineServiceAndPing))
{
NewSessionMetadata.Add(Pair.Key.ToString(), Pair.Value.Data);
}
}
for (const TPair<FString, FVariantData>& Pair : NewSessionMetadata)
{
UE_LOG_ONLINE_SESSION(Verbose, TEXT("Session Presence Data: [%s] %s"), *Pair.Key, *Pair.Value.ToString());
}
}
else
{
UE_LOG_ONLINE_SESSION(Verbose, TEXT("Clearing session presence keys, session not advertised"));
}
TWeakPtr<FOnlineSessionTencent, ESPMode::ThreadSafe> LocalWeakThis(AsShared());
FOnlineAsyncTaskRailSetSessionMetadata* NewPresenceTask = new FOnlineAsyncTaskRailSetSessionMetadata(TencentSubsystem, NewSessionMetadata, FOnOnlineAsyncTaskRailSetUserMetadataComplete::CreateLambda([LocalWeakThis, bIsPresenceSession, bAllowInvites, InCompletionDelegate](const FSetUserMetadataTaskResult& Result)
{
bool bSecondTaskTriggered = false;
UE_LOG_ONLINE_SESSION(Verbose, TEXT("UpdateSessionMetadata [Presence] %s"), *Result.Error.ToLogString());
if (Result.Error.WasSuccessful())
{
FOnlineSessionTencentRailPtr StrongThis = StaticCastSharedPtr<FOnlineSessionTencentRail>(LocalWeakThis.Pin());
if (StrongThis.IsValid())
{
// Update the invite command line with the new array of active keys
FString InviteCmdLine;
if (bAllowInvites)
{
InviteCmdLine = FString::Join(StrongThis->CurrentSessionPresenceKeys, RAIL_METADATA_KEY_SEPARATOR);
}
FOnlineAsyncTaskRailSetInviteCommandline* NewCmdlineTask = new FOnlineAsyncTaskRailSetInviteCommandline(StrongThis->TencentSubsystem, InviteCmdLine, FOnOnlineAsyncTaskRailSetInviteCommandlineComplete::CreateLambda([LocalWeakThis, bIsPresenceSession, InCompletionDelegate](const FSetUserMetadataTaskResult& Result)
{
UE_LOG_ONLINE_SESSION(Verbose, TEXT("UpdateSessionMetadata [CmdLine] %s"), *Result.Error.ToLogString());
if (Result.Error.WasSuccessful())
{
if (bIsPresenceSession)
{
FOnlineSessionTencentRailPtr StrongThis = StaticCastSharedPtr<FOnlineSessionTencentRail>(LocalWeakThis.Pin());
if (StrongThis.IsValid())
{
FOnlinePresenceTencentPtr PresenceInt = StaticCastSharedPtr<FOnlinePresenceTencent>(StrongThis->TencentSubsystem->GetPresenceInterface());
if (PresenceInt.IsValid())
{
// Update presence now that session data has changed
PresenceInt->UpdatePresenceFromSessionData();
}
}
}
}
// Always trigger that UpdateMetadata is complete
InCompletionDelegate.ExecuteIfBound(Result.Error);
}));
StrongThis->TencentSubsystem->QueueAsyncTask(NewCmdlineTask);
bSecondTaskTriggered = true;
}
}
if (!bSecondTaskTriggered)
{
// Always trigger that UpdateMetadata is complete
InCompletionDelegate.ExecuteIfBound(Result.Error);
}
}));
TencentSubsystem->QueueAsyncTask(NewPresenceTask);
}
void FOnlineSessionTencentRail::ParseSearchResult(TSharedPtr<FOnlineSessionSearch> InSearch, const FGetUserInviteTaskResult& InResult)
{
FOnlineSessionSearchResult* NewSearchResult = new (InSearch->SearchResults) FOnlineSessionSearchResult();
FOnlineSessionInfoTencent* SessionInfo = new FOnlineSessionInfoTencent();
NewSearchResult->Session.SessionInfo = MakeShareable(SessionInfo);
// Populate the session settings with any known defaults before parsing the result
NewSearchResult->Session.SessionSettings = *InSearch->GetDefaultSessionSettings();
const FVariantData* SessionId = InResult.Metadata.Find(RAIL_SESSION_ID_KEY);
const FVariantData* OwningUserUniqueId = InResult.Metadata.Find(RAIL_SESSION_OWNING_USER_ID_KEY);
const FVariantData* SessionBitsData = InResult.Metadata.Find(RAIL_SESSION_SESSIONBITS_KEY);
const FVariantData* RemoteBuildUniqueId = InResult.Metadata.Find(RAIL_SESSION_BUILDUNIQUEID_KEY);
if (SessionId && OwningUserUniqueId && SessionBitsData && RemoteBuildUniqueId)
{
FOnlineSessionSettings& SessionSettings = NewSearchResult->Session.SessionSettings;
SessionSettings.bUsesPresence = true;
if (SessionId->GetType() == EOnlineKeyValuePairDataType::String)
{
FString SessionIdStr;
SessionId->GetValue(SessionIdStr);
SessionInfo->SessionId = FUniqueNetIdString::Create(SessionIdStr, TENCENT_SUBSYSTEM);
}
if (OwningUserUniqueId->GetType() == EOnlineKeyValuePairDataType::String)
{
FString OwningUserUniqueIdStr;
OwningUserUniqueId->GetValue(OwningUserUniqueIdStr);
NewSearchResult->Session.OwningUserId = FUniqueNetIdRail::Create(OwningUserUniqueIdStr);
}
if (SessionBitsData->GetType() == EOnlineKeyValuePairDataType::UInt32)
{
uint32 SessionBits;
SessionBitsData->GetValue(SessionBits);
int32 NumBits = 0;
SessionSettings.bShouldAdvertise = !!(SessionBits & (1 << NumBits)); NumBits++;
SessionSettings.bAllowJoinInProgress = !!(SessionBits & (1 << NumBits)); NumBits++;
SessionSettings.bAllowInvites = !!(SessionBits & (1 << NumBits)); NumBits++;
SessionSettings.bAllowJoinViaPresence = !!(SessionBits & (1 << NumBits)); NumBits++;
SessionSettings.bAllowJoinViaPresenceFriendsOnly = !!(SessionBits & (1 << NumBits)); NumBits++;
}
if (RemoteBuildUniqueId->GetType() == EOnlineKeyValuePairDataType::Int32)
{
RemoteBuildUniqueId->GetValue(SessionSettings.BuildUniqueId);
}
static FName SessionIdFName(RAIL_SESSION_ID_KEY);
static FName OwningUserIdFName(RAIL_SESSION_OWNING_USER_ID_KEY);
static FName SessionBitsFName(RAIL_SESSION_SESSIONBITS_KEY);
static FName BuildUniqueIdFName(RAIL_SESSION_BUILDUNIQUEID_KEY);
for (TPair<FString, FVariantData> Pair : InResult.Metadata)
{
FName SettingKey(*Pair.Key);
if (SettingKey != SessionIdFName &&
SettingKey != OwningUserIdFName &&
SettingKey != SessionBitsFName &&
SettingKey != BuildUniqueIdFName)
{
FOnlineSessionSetting SessionSetting(Pair.Value, EOnlineDataAdvertisementType::ViaOnlineService);
SessionSettings.Set(SettingKey, SessionSetting);
}
}
}
#if !UE_BUILD_SHIPPING
DumpSession(&NewSearchResult->Session);
#endif
int32 BuildUniqueId = GetBuildUniqueId();
if (NewSearchResult->Session.SessionSettings.BuildUniqueId == 0 ||
NewSearchResult->Session.SessionSettings.BuildUniqueId != BuildUniqueId ||
!SessionInfo->IsValid())
{
const FString SessionIdStr = SessionInfo->SessionId.IsValid() ? SessionInfo->SessionId->ToString() : TEXT("InvalidSession");
if (!SessionInfo->SessionId.IsValid())
{
UE_LOG_ONLINE_SESSION(Verbose, TEXT("Rejecting search result [%s]: invalid session id"), *SessionIdStr);
}
if (NewSearchResult->Session.SessionSettings.BuildUniqueId == 0 ||
NewSearchResult->Session.SessionSettings.BuildUniqueId != BuildUniqueId)
{
UE_LOG_ONLINE_SESSION(Verbose, TEXT("Rejecting search result [%s]: invalid build id %d != %d"),
*SessionIdStr,
BuildUniqueId,
NewSearchResult->Session.SessionSettings.BuildUniqueId);
}
// Remove the failed element
InSearch->SearchResults.RemoveAtSwap(InSearch->SearchResults.Num() - 1);
}
}
bool FOnlineSessionTencentRail::FindFriendSession(int32 LocalUserNum, const FUniqueNetId& Friend)
{
bool bSuccess = false;
const FUniqueNetIdRail& RailFriendId = (const FUniqueNetIdRail&)Friend;
if (RailFriendId.IsValid())
{
TWeakPtr<FOnlineSessionTencent, ESPMode::ThreadSafe> LocalWeakThis(AsShared());
FOnOnlineAsyncTaskRailGetUserInviteComplete CompletionDelegate = FOnOnlineAsyncTaskRailGetUserInviteComplete::CreateLambda([LocalUserNum, LocalWeakThis](const FGetUserInviteTaskResult& Result)
{
FOnlineSessionTencentRailPtr StrongThis = StaticCastSharedPtr<FOnlineSessionTencentRail>(LocalWeakThis.Pin());
if (StrongThis.IsValid())
{
if (Result.Error.WasSuccessful() && Result.Metadata.Num() && !Result.Commandline.IsEmpty())
{
TSharedRef<FOnlineSessionSearch> SessionSearch = MakeShared<FOnlineSessionSearch>();
StrongThis->ParseSearchResult(SessionSearch, Result);
StrongThis->TriggerOnFindFriendSessionCompleteDelegates(LocalUserNum, Result.Error.WasSuccessful() && (SessionSearch->SearchResults.Num() > 0), SessionSearch->SearchResults);
}
else
{
TArray<FOnlineSessionSearchResult> EmptyResult;
StrongThis->TriggerOnFindFriendSessionCompleteDelegates(LocalUserNum, false, EmptyResult);
}
}
});
FOnlineAsyncTaskRailGetUserInvite* NewTask = new FOnlineAsyncTaskRailGetUserInvite(TencentSubsystem, RailFriendId, CompletionDelegate);
UE_LOG_ONLINE_SESSION(Verbose, TEXT("%s"), *NewTask->ToString());
TencentSubsystem->QueueAsyncTask(NewTask);
bSuccess = true;
}
if (!bSuccess)
{
TWeakPtr<FOnlineSessionTencent, ESPMode::ThreadSafe> LocalWeakThis(AsShared());
TencentSubsystem->ExecuteNextTick([LocalWeakThis, LocalUserNum, bSuccess]()
{
FOnlineSessionTencentRailPtr StrongThis = StaticCastSharedPtr<FOnlineSessionTencentRail>(LocalWeakThis.Pin());
if (StrongThis.IsValid())
{
TArray<FOnlineSessionSearchResult> EmptyResult;
StrongThis->TriggerOnFindFriendSessionCompleteDelegates(LocalUserNum, bSuccess, EmptyResult);
}
});
}
return bSuccess;
}
bool FOnlineSessionTencentRail::FindFriendSession(const FUniqueNetId& LocalUserId, const FUniqueNetId& Friend)
{
return FindFriendSession(GetLocalUserIdx(LocalUserId), Friend);
}
bool FOnlineSessionTencentRail::FindFriendSession(const FUniqueNetId& LocalUserId, const TArray<FUniqueNetIdRef>& FriendList)
{
/** NYI */
return false;
}
bool FOnlineSessionTencentRail::SendSessionInviteToFriend(int32 LocalUserNum, FName SessionName, const FUniqueNetId& Friend)
{
TArray< FUniqueNetIdRef > Friends;
Friends.Add(Friend.AsShared());
return SendSessionInviteToFriends(LocalUserNum, SessionName, Friends);
}
bool FOnlineSessionTencentRail::SendSessionInviteToFriend(const FUniqueNetId& LocalUserId, FName SessionName, const FUniqueNetId& Friend)
{
TArray< FUniqueNetIdRef > Friends;
Friends.Add(Friend.AsShared());
return SendSessionInviteToFriends(LocalUserId, SessionName, Friends);
}
bool FOnlineSessionTencentRail::SendSessionInviteToFriends(int32 LocalUserNum, FName SessionName, const TArray< FUniqueNetIdRef >& Friends)
{
IOnlineIdentityPtr IdentityInt = TencentSubsystem->GetIdentityInterface();
if (IdentityInt.IsValid())
{
FUniqueNetIdPtr UserId = IdentityInt->GetUniquePlayerId(LocalUserNum);
if (UserId.IsValid())
{
return SendSessionInviteToFriends(*UserId, SessionName, Friends);
}
}
return false;
}
bool FOnlineSessionTencentRail::SendSessionInviteToFriends(const FUniqueNetId& LocalUserId, FName SessionName, const TArray< FUniqueNetIdRef >& Friends)
{
if (!SessionName.IsNone() && Friends.Num() > 0)
{
FUniqueNetIdRailRef UserIdRail = StaticCastSharedRef<const FUniqueNetIdRail>(LocalUserId.AsShared());
TWeakPtr<FOnlineSubsystemTencent, ESPMode::ThreadSafe> LocalWeakSubsystem(TencentSubsystem->AsShared());
// This function doesn't work for querying your own details
//FOnlineAsyncTaskRailGetInviteDetails* OuterTask = new FOnlineAsyncTaskRailGetInviteDetails(TencentSubsystem, *UserIdRail, FOnOnlineAsyncTaskRailGetInviteDetailsComplete::CreateLambda([LocalWeakSubsystem, UserIdRail, Friends](const FGetInviteDetailsTaskResult& OuterResult)
FOnlineAsyncTaskRailGetInviteCommandline* OuterTask = new FOnlineAsyncTaskRailGetInviteCommandline(TencentSubsystem, *UserIdRail, FOnOnlineAsyncTaskRailGetInviteCommandLineComplete::CreateLambda([LocalWeakSubsystem, UserIdRail, Friends](const FGetInviteCommandLineTaskResult& OuterResult)
{
FOnlineSubsystemTencentPtr StrongSubsystem = StaticCastSharedPtr<FOnlineSubsystemTencent>(LocalWeakSubsystem.Pin());
if (StrongSubsystem.IsValid())
{
if (OuterResult.Error.WasSuccessful())
{
FOnlineAsyncTaskRailSendInvite* InnerTask = new FOnlineAsyncTaskRailSendInvite(StrongSubsystem.Get(), OuterResult.Commandline, Friends, FOnOnlineAsyncTaskRailSendInviteComplete::CreateLambda([LocalWeakSubsystem](const FSendInviteTaskResult& InnerResult)
{
if (InnerResult.Error.WasSuccessful())
{
UE_LOG_ONLINE_SESSION(Display, TEXT("Invite sent"));
}
else
{
UE_LOG_ONLINE_SESSION(Display, TEXT("Failed to send invite"));
}
}));
StrongSubsystem->QueueAsyncTask(InnerTask);
}
else
{
UE_LOG_ONLINE_SESSION(Display, TEXT("Failed to get invite details to send invite"));
}
}
}));
TencentSubsystem->QueueAsyncTask(OuterTask);
return true;
}
else
{
UE_LOG_ONLINE_SESSION(Display, TEXT("Invalid params sending invite Session %s FriendCount: %d"), *SessionName.ToString(), Friends.Num());
}
return false;
}
#endif // WITH_TENCENT_RAIL_SDK