void AFPSGPlayerController::onClickEndGame() const { //Make sure it is the server calling the function if (Role < ROLE_Authority && GetNetMode() == NM_Client) return; //GEngine->AddOnScreenDebugMessage(-1, 40.0f, FColor::Cyan, "AFPSGPlayerController::onClickEndGame"); IOnlineSubsystem* onlineSubsystem = IOnlineSubsystem::Get(); IOnlineSessionPtr sessions = onlineSubsystem != NULL ? onlineSubsystem->GetSessionInterface() : NULL; if (sessions.IsValid()) { UWorld* world = GetWorld(); AFPSGGameState* gameState = world != NULL ? world->GetGameState<AFPSGGameState>() : NULL; if (gameState != NULL) { //Retrieve the session state and match state EOnlineSessionState::Type sessionState = sessions->GetSessionState(GameSessionName); FName matchState = gameState->GetMatchState(); //Only attempt to end the game if both the session and match are in progress if (sessionState == EOnlineSessionState::Type::InProgress && matchState == MatchState::InProgress) { gameState->onClickEndGame(); } } } }
/** * Register all delegates needed to manage online sessions */ void UOnlineSessionClient::RegisterOnlineDelegates(UWorld* InWorld) { IOnlineSubsystem* OnlineSub = Online::GetSubsystem(InWorld); if (OnlineSub) { SessionInt = OnlineSub->GetSessionInterface(); if (SessionInt.IsValid()) { int32 ControllerId = GetControllerId(); if (ControllerId != INVALID_CONTROLLERID) { // Always on the lookout for invite acceptance (via actual invite or join from external ui) OnSessionInviteAcceptedDelegate = FOnSessionInviteAcceptedDelegate::CreateUObject(this, &UOnlineSessionClient::OnSessionInviteAccepted); SessionInt->AddOnSessionInviteAcceptedDelegate(ControllerId, OnSessionInviteAcceptedDelegate); } } OnJoinSessionCompleteDelegate = FOnJoinSessionCompleteDelegate::CreateUObject(this, &UOnlineSessionClient::OnJoinSessionComplete); OnEndForJoinSessionCompleteDelegate = FOnEndSessionCompleteDelegate::CreateUObject(this, &UOnlineSessionClient::OnEndForJoinSessionComplete); OnDestroyForJoinSessionCompleteDelegate = FOnDestroySessionCompleteDelegate::CreateUObject(this, &UOnlineSessionClient::OnDestroyForJoinSessionComplete); } // Register disconnect delegate even if we don't have an online system OnDestroyForMainMenuCompleteDelegate = FOnDestroySessionCompleteDelegate::CreateUObject(this, &UOnlineSessionClient::OnDestroyForMainMenuComplete); }
/** * Delegate fired when a session start request has completed * * @param SessionName the name of the session this callback is for * @param bWasSuccessful true if the async action completed without error, false if there was an error */ void URadeGameInstance::OnStartOnlineGameComplete(FName SessionName, bool bWasSuccessful) { //GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Red, FString::Printf(TEXT("OnStartSessionComplete %s, %d"), *SessionName.ToString(), bWasSuccessful)); // Get the Online Subsystem so we can get the Session Interface IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get(); if (OnlineSub) { // Get the Session Interface to clear the Delegate IOnlineSessionPtr Sessions = OnlineSub->GetSessionInterface(); if (Sessions.IsValid()) { // Clear the delegate, since we are done with this call Sessions->ClearOnStartSessionCompleteDelegate_Handle(OnStartSessionCompleteDelegateHandle); } } // If the start was successful, we can open a NewMap if we want. Make sure to use "listen" as a parameter! if (bWasSuccessful) { //BattleArena UGameplayStatics::OpenLevel(GetWorld(), *TheMapName, true, "listen"); } }
bool APartyBeaconClient::RequestReservation(const FOnlineSessionSearchResult& DesiredHost, const FUniqueNetIdRepl& RequestingPartyLeader, const TArray<FPlayerReservation>& PartyMembers) { bool bSuccess = false; if (DesiredHost.IsValid()) { UWorld* World = GetWorld(); IOnlineSubsystem* OnlineSub = Online::GetSubsystem(World); if (OnlineSub) { IOnlineSessionPtr SessionInt = OnlineSub->GetSessionInterface(); if (SessionInt.IsValid()) { FString ConnectInfo; if (SessionInt->GetResolvedConnectString(DesiredHost, BeaconPort, ConnectInfo)) { FString SessionId = DesiredHost.Session.SessionInfo->GetSessionId().ToString(); return RequestReservation(ConnectInfo, SessionId, RequestingPartyLeader, PartyMembers); } } } } if (!bSuccess) { OnFailure(); } return bSuccess; }
// Join Session bool URadeGameInstance::JoinSession(TSharedPtr<const FUniqueNetId> UserId, FName SessionName, const FOnlineSessionSearchResult& SearchResult) { // Return bool bool bSuccessful = false; // Get OnlineSubsystem we want to work with IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get(); if (OnlineSub) { // Get SessionInterface from the OnlineSubsystem IOnlineSessionPtr Sessions = OnlineSub->GetSessionInterface(); if (Sessions.IsValid() && UserId.IsValid()) { // Set the Handle again OnJoinSessionCompleteDelegateHandle = Sessions->AddOnJoinSessionCompleteDelegate_Handle(OnJoinSessionCompleteDelegate); // Call the "JoinSession" Function with the passed "SearchResult". The "SessionSearch->SearchResults" can be used to get such a // "FOnlineSessionSearchResult" and pass it. Pretty straight forward! bSuccessful = Sessions->JoinSession(*UserId, SessionName, SearchResult); } } return bSuccessful; }
void URadeGameInstance::OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result) { // Get the OnlineSubsystem we want to work with IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get(); if (OnlineSub) { // Get SessionInterface from the OnlineSubsystem IOnlineSessionPtr Sessions = OnlineSub->GetSessionInterface(); if (Sessions.IsValid()) { // Clear the Delegate again Sessions->ClearOnJoinSessionCompleteDelegate_Handle(OnJoinSessionCompleteDelegateHandle); // Get the first local PlayerController, so we can call "ClientTravel" to get to the Server Map // This is something the Blueprint Node "Join Session" does automatically! APlayerController * const PlayerController = GetFirstLocalPlayerController(); // We need a FString to use ClientTravel and we can let the SessionInterface contruct such a // String for us by giving him the SessionName and an empty String. We want to do this, because // Every OnlineSubsystem uses different TravelURLs FString TravelURL; if (PlayerController && Sessions->GetResolvedConnectString(SessionName, TravelURL)) { // Finally call the ClienTravel. If you want, you could print the TravelURL to see // how it really looks like PlayerController->ClientTravel(TravelURL, ETravelType::TRAVEL_Absolute); } } } }
/** * Delegate fired when a session create request has completed * * @param SessionName the name of the session this callback is for * @param bWasSuccessful true if the async action completed without error, false if there was an error */ void URadeGameInstance::OnCreateSessionComplete(FName SessionName, bool bWasSuccessful) { //GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Red, FString::Printf(TEXT("OnCreateSessionComplete %s, %d"), *SessionName.ToString(), bWasSuccessful)); // Get the OnlineSubsystem so we can get the Session Interface IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get(); if (OnlineSub) { // Get the Session Interface to call the StartSession function IOnlineSessionPtr Sessions = OnlineSub->GetSessionInterface(); if (Sessions.IsValid()) { // Clear the SessionComplete delegate handle, since we finished this call Sessions->ClearOnCreateSessionCompleteDelegate_Handle(OnCreateSessionCompleteDelegateHandle); if (bWasSuccessful) { // Set the StartSession delegate handle OnStartSessionCompleteDelegateHandle = Sessions->AddOnStartSessionCompleteDelegate_Handle(OnStartSessionCompleteDelegate); //printr(SessionName.ToString()); // Our StartSessionComplete delegate should get called after this Sessions->StartSession(SessionName); } } } }
/** Starts the online game using the session name in the PlayerState */ void AShooterPlayerController::ClientStartOnlineGame_Implementation() { if (!IsPrimaryPlayer()) return; AShooterPlayerState* ShooterPlayerState = Cast<AShooterPlayerState>(PlayerState); if (ShooterPlayerState) { IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get(); if (OnlineSub) { IOnlineSessionPtr Sessions = OnlineSub->GetSessionInterface(); if (Sessions.IsValid()) { UE_LOG(LogOnline, Log, TEXT("Starting session %s on client"), *ShooterPlayerState->SessionName.ToString() ); Sessions->StartSession(ShooterPlayerState->SessionName); } } } else { // Keep retrying until player state is replicated GetWorld()->GetTimerManager().SetTimer(FTimerDelegate::CreateUObject(this, &AShooterPlayerController::ClientStartOnlineGame_Implementation), 0.2f, false); } }
/** Ends and/or destroys game session */ void AShooterPlayerController::CleanupSessionOnReturnToMenu() { bool bPendingOnlineOp = false; // end online game and then destroy it AShooterPlayerState* ShooterPlayerState = Cast<AShooterPlayerState>(PlayerState); if (ShooterPlayerState) { IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get(); if (OnlineSub) { IOnlineSessionPtr Sessions = OnlineSub->GetSessionInterface(); if (Sessions.IsValid()) { EOnlineSessionState::Type SessionState = Sessions->GetSessionState(ShooterPlayerState->SessionName); UE_LOG(LogOnline, Log, TEXT("Session %s is '%s'"), *ShooterPlayerState->SessionName.ToString(), EOnlineSessionState::ToString(SessionState)); if (EOnlineSessionState::InProgress == SessionState) { UE_LOG(LogOnline, Log, TEXT("Ending session %s on return to main menu"), *ShooterPlayerState->SessionName.ToString() ); Sessions->AddOnEndSessionCompleteDelegate(OnEndSessionCompleteDelegate); Sessions->EndSession(ShooterPlayerState->SessionName); bPendingOnlineOp = true; } else if (EOnlineSessionState::Ending == SessionState) { UE_LOG(LogOnline, Log, TEXT("Waiting for session %s to end on return to main menu"), *ShooterPlayerState->SessionName.ToString() ); Sessions->AddOnEndSessionCompleteDelegate(OnEndSessionCompleteDelegate); bPendingOnlineOp = true; } else if (EOnlineSessionState::Ended == SessionState || EOnlineSessionState::Pending == SessionState) { UE_LOG(LogOnline, Log, TEXT("Destroying session %s on return to main menu"), *ShooterPlayerState->SessionName.ToString() ); Sessions->AddOnDestroySessionCompleteDelegate(OnDestroySessionCompleteDelegate); Sessions->DestroySession(ShooterPlayerState->SessionName); bPendingOnlineOp = true; } else if (EOnlineSessionState::Starting == SessionState) { UE_LOG(LogOnline, Log, TEXT("Waiting for session %s to start, and then we will end it to return to main menu"), *ShooterPlayerState->SessionName.ToString() ); Sessions->AddOnStartSessionCompleteDelegate(OnStartSessionCompleteEndItDelegate); bPendingOnlineOp = true; } } } } if (!bPendingOnlineOp) { GEngine->HandleDisconnect(GetWorld(), GetWorld()->GetNetDriver()); } }
// Destroy Session void URadeGameInstance::DestroySessionAndLeaveGame() { IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get(); if (OnlineSub) { IOnlineSessionPtr Sessions = OnlineSub->GetSessionInterface(); if (Sessions.IsValid()) { Sessions->AddOnDestroySessionCompleteDelegate_Handle(OnDestroySessionCompleteDelegate); Sessions->DestroySession(GameSessionName); } } }
void AFPSGPlayerController::onClickQuitToMainMenu() { //GEngine->AddOnScreenDebugMessage(-1, 40.0f, FColor::Cyan, "AFPSGPlayerController::onClickQuitToMainMenu"); IOnlineSubsystem* onlineSubsystem = IOnlineSubsystem::Get(); IOnlineSessionPtr sessions = onlineSubsystem != NULL ? onlineSubsystem->GetSessionInterface() : NULL; if (!sessions.IsValid()) return; UWorld* world = GetWorld(); AFPSGGameState* gameState = world != NULL ? world->GetGameState<AFPSGGameState>() : NULL; if (gameState != NULL) { //Retrieve the session state and match state FName matchState = gameState->GetMatchState(); EOnlineSessionState::Type sessionState = EOnlineSessionState::Type::NoSession; if (Role == ROLE_Authority && GetNetMode() < NM_Client) { sessionState = sessions->GetSessionState(GameSessionName); } else { sessionState = PlayerState != NULL ? sessions->GetSessionState(PlayerState->SessionName) : EOnlineSessionState::Type::NoSession; } //Only attempt to end the game if both the session and match are in progress if (sessionState == EOnlineSessionState::Type::InProgress && matchState == MatchState::InProgress) { //Check if it is a server or client that wants to quit to the main menu if (Role == ROLE_Authority && GetNetMode() < NM_Client) { gameState->onClickQuitToMainMenu(); } else { //Client will end and destroy its session locally, and then return to the main menu clientEndSession(); clientOnlineMatchHasEnded(EEndMatchReason::NONE); clientDestroySession(); ClientReturnToMainMenu_Implementation(""); } } } }
/** * Delegate fired when ending an online session has completed * * @param SessionName the name of the session this callback is for * @param bWasSuccessful true if the async action completed without error, false if there was an error */ void AShooterPlayerController::OnEndSessionComplete(FName SessionName, bool bWasSuccessful) { UE_LOG(LogOnline, Log, TEXT("OnEndSessionComplete: Session=%s bWasSuccessful=%s"), *SessionName.ToString(), bWasSuccessful ? TEXT("true") : TEXT("false") ); IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get(); if (OnlineSub) { IOnlineSessionPtr Sessions = OnlineSub->GetSessionInterface(); if (Sessions.IsValid()) { Sessions->ClearOnEndSessionCompleteDelegate(OnEndSessionCompleteDelegate); } } // continue CleanupSessionOnReturnToMenu(); }
void UUModGameInstance::OnStartOnlineGameComplete(FName SessionName, bool bWasSuccessful) { GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Red, FString::Printf(TEXT("OnStartSessionComplete %s, %d"), *SessionName.ToString(), bWasSuccessful)); IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get(); if (OnlineSub) { IOnlineSessionPtr Sessions = OnlineSub->GetSessionInterface(); if (Sessions.IsValid()) { Sessions->ClearOnStartSessionCompleteDelegate_Handle(OnStartSessionCompleteDelegateHandle); } } if (bWasSuccessful) { DelayedRunMap = true; } }
/** * Find an online session * * @param UserId user that initiated the request * @param SessionName name of session this search will generate * @param bIsLAN are we searching LAN matches * @param bIsPresence are we searching presence sessions */ void URadeGameInstance::FindSessions(TSharedPtr<const FUniqueNetId> UserId, FName SessionName, bool bIsLAN, bool bIsPresence) { // Get the OnlineSubsystem we want to work with IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get(); if (OnlineSub) { bIsSearchingSession = true; // Get the SessionInterface from our OnlineSubsystem IOnlineSessionPtr Sessions = OnlineSub->GetSessionInterface(); if (Sessions.IsValid() && UserId.IsValid()) { /* Fill in all the SearchSettings, like if we are searching for a LAN game and how many results we want to have! */ SessionSearch = MakeShareable(new FOnlineSessionSearch()); SessionSearch->bIsLanQuery = bIsLAN; SessionSearch->MaxSearchResults = 20; SessionSearch->PingBucketSize = 50; // We only want to set this Query Setting if "bIsPresence" is true if (bIsPresence) { SessionSearch->QuerySettings.Set(SEARCH_PRESENCE, bIsPresence, EOnlineComparisonOp::Equals); } TSharedRef<FOnlineSessionSearch> SearchSettingsRef = SessionSearch.ToSharedRef(); // Set the Delegate to the Delegate Handle of the FindSession function OnFindSessionsCompleteDelegateHandle = Sessions->AddOnFindSessionsCompleteDelegate_Handle(OnFindSessionsCompleteDelegate); // Finally call the SessionInterface function. The Delegate gets called once this is finished Sessions->FindSessions(*UserId, SearchSettingsRef); } } else { // If something goes wrong, just call the Delegate Function directly with "false". OnFindSessionsComplete(false); } }
/** Ends the online game using the session name in the PlayerState */ void AShooterPlayerController::ClientEndOnlineGame_Implementation() { if (!IsPrimaryPlayer()) return; AShooterPlayerState* ShooterPlayerState = Cast<AShooterPlayerState>(PlayerState); if (ShooterPlayerState) { IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get(); if (OnlineSub) { IOnlineSessionPtr Sessions = OnlineSub->GetSessionInterface(); if (Sessions.IsValid()) { UE_LOG(LogOnline, Log, TEXT("Ending session %s on client"), *ShooterPlayerState->SessionName.ToString() ); Sessions->EndSession(ShooterPlayerState->SessionName); } } } }
// Destroy Session And return to Start Map void URadeGameInstance::OnDestroySessionComplete(FName SessionName, bool bWasSuccessful) { // Get the OnlineSubsystem we want to work with IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get(); if (OnlineSub) { // Get the SessionInterface from the OnlineSubsystem IOnlineSessionPtr Sessions = OnlineSub->GetSessionInterface(); if (Sessions.IsValid()) { // Clear the Delegate Sessions->ClearOnDestroySessionCompleteDelegate_Handle(OnDestroySessionCompleteDelegateHandle); // If it was successful, we just load another level (could be a MainMenu!) if (bWasSuccessful) { UGameplayStatics::OpenLevel(GetWorld(), "SelectMap", true); } } } }
bool AFPSGPlayerController::destroySession(FName sessionName) const { bool success = false; IOnlineSubsystem* onlineSubsystem = IOnlineSubsystem::Get(); IOnlineSessionPtr sessions = onlineSubsystem != NULL ? onlineSubsystem->GetSessionInterface() : NULL; if (sessions.IsValid()) { //Destroy the session success = sessions->DestroySession(sessionName); if (success) { GEngine->AddOnScreenDebugMessage(-1, 40.0f, FColor::Cyan, TEXT("AFPSGPlayerController::destroySession success")); } else { GEngine->AddOnScreenDebugMessage(-1, 40.0f, FColor::Cyan, TEXT("AFPSGPlayerController::destroySession NOT success")); } } return success; }
bool UQosEvaluator::FindQosServersByRegion(int32 RegionIdx, FOnQosSearchComplete InCompletionDelegate) { bool bSuccess = false; if (Datacenters.IsValidIndex(RegionIdx)) { FQosRegionInfo& Datacenter = Datacenters[RegionIdx]; Datacenter.Reset(); IOnlineSubsystem* OnlineSub = Online::GetSubsystem(GetWorld()); if (OnlineSub) { IOnlineSessionPtr SessionInt = OnlineSub->GetSessionInterface(); if (SessionInt.IsValid()) { if (!Datacenter.Region.RegionId.IsEmpty()) { const TSharedRef<FOnlineSessionSearch> QosSearchParams = MakeShareable(new FOnlineSessionSearchQos()); QosSearchParams->QuerySettings.Set(SETTING_REGION, Datacenter.Region.RegionId, EOnlineComparisonOp::Equals); QosSearchQuery = QosSearchParams; FOnFindSessionsCompleteDelegate OnFindDatacentersCompleteDelegate = FOnFindSessionsCompleteDelegate::CreateUObject(this, &ThisClass::OnFindQosServersByRegionComplete, RegionIdx, InCompletionDelegate); OnFindDatacentersCompleteDelegateHandle = SessionInt->AddOnFindSessionsCompleteDelegate_Handle(OnFindDatacentersCompleteDelegate); SessionInt->FindSessions(ControllerId, QosSearchParams); } else { OnFindQosServersByRegionComplete(false, RegionIdx, InCompletionDelegate); } bSuccess = true; } } } return bSuccess; }
void UQosEvaluator::OnFindQosServersByRegionComplete(bool bWasSuccessful, int32 RegionIdx, FOnQosSearchComplete InCompletionDelegate) { IOnlineSubsystem* OnlineSub = Online::GetSubsystem(GetWorld()); if (OnlineSub) { IOnlineSessionPtr SessionInt = OnlineSub->GetSessionInterface(); if (SessionInt.IsValid()) { SessionInt->ClearOnFindSessionsCompleteDelegate_Handle(OnFindDatacentersCompleteDelegateHandle); } } if (!bCancelOperation) { FQosRegionInfo& Datacenter = Datacenters[RegionIdx]; Datacenter.Result = bWasSuccessful ? EQosCompletionResult::Success : EQosCompletionResult::Failure; // Copy the search results for later evaluation Datacenter.SearchResults = QosSearchQuery->SearchResults; QosSearchQuery = nullptr; int32 NextRegionIdx = GetNextRegionId(RegionIdx); if (Datacenters.IsValidIndex(NextRegionIdx)) { TWeakObjectPtr<UQosEvaluator> WeakThisCap(this); GetWorldTimerManager().SetTimerForNextTick(FTimerDelegate::CreateLambda([InCompletionDelegate, NextRegionIdx, WeakThisCap]() { if (WeakThisCap.IsValid()) { auto StrongThis = WeakThisCap.Get(); // Move to the next region results if (!StrongThis->FindQosServersByRegion(NextRegionIdx, InCompletionDelegate)) { // Failed to start StrongThis->GetWorldTimerManager().SetTimerForNextTick(FTimerDelegate::CreateLambda([InCompletionDelegate, WeakThisCap]() { if (WeakThisCap.IsValid()) { auto StrongThis1 = WeakThisCap.Get(); StrongThis1->FinalizeDatacenterResult(InCompletionDelegate, EQosCompletionResult::Failure, TArray<FQosRegionInfo>()); } })); } } })); } else { // Evaluate search results for all regions next tick FOnQosPingEvalComplete CompletionDelegate = FOnQosPingEvalComplete::CreateUObject(this, &ThisClass::OnEvaluateForDatacenterComplete, InCompletionDelegate); TWeakObjectPtr<UQosEvaluator> WeakThisCap(this); GetWorldTimerManager().SetTimerForNextTick(FTimerDelegate::CreateLambda([CompletionDelegate, WeakThisCap]() { if (WeakThisCap.IsValid()) { auto StrongThis = WeakThisCap.Get(); StrongThis->bInProgress = false; StrongThis->StartServerPing(CompletionDelegate); } })); } } else { QosSearchQuery = nullptr; // Mark all remaining datacenters as canceled for (int32 Idx = RegionIdx; Idx < Datacenters.Num(); Idx++) { Datacenters[Idx].Result = EQosCompletionResult::Canceled; } FinalizeDatacenterResult(InCompletionDelegate, EQosCompletionResult::Canceled, Datacenters); } }