From a703502810d4944ebf0efade255fbe4a75c08813 Mon Sep 17 00:00:00 2001 From: Marat Radchenko Date: Sun, 6 Jul 2025 15:44:44 +0300 Subject: [PATCH] Add StartMatchmaking and CancelMatchmaking async nodes --- .../Classes/CancelMatchmakingCallbackProxy.h | 32 ++++++++ .../Classes/StartMatchmakingCallbackProxy.h | 34 ++++++++ .../CancelMatchmakingCallbackProxy.cpp | 54 ++++++++++++ .../Private/StartMatchmakingCallbackProxy.cpp | 82 +++++++++++++++++++ 4 files changed, 202 insertions(+) create mode 100644 AdvancedSessions/Source/AdvancedSessions/Classes/CancelMatchmakingCallbackProxy.h create mode 100644 AdvancedSessions/Source/AdvancedSessions/Classes/StartMatchmakingCallbackProxy.h create mode 100644 AdvancedSessions/Source/AdvancedSessions/Private/CancelMatchmakingCallbackProxy.cpp create mode 100644 AdvancedSessions/Source/AdvancedSessions/Private/StartMatchmakingCallbackProxy.cpp diff --git a/AdvancedSessions/Source/AdvancedSessions/Classes/CancelMatchmakingCallbackProxy.h b/AdvancedSessions/Source/AdvancedSessions/Classes/CancelMatchmakingCallbackProxy.h new file mode 100644 index 0000000..0978d37 --- /dev/null +++ b/AdvancedSessions/Source/AdvancedSessions/Classes/CancelMatchmakingCallbackProxy.h @@ -0,0 +1,32 @@ +#pragma once + +#include "BlueprintDataDefinitions.h" +#include "CancelMatchmakingCallbackProxy.generated.h" + +UCLASS(MinimalAPI) +class UCancelMatchmakingCallbackProxy : public UOnlineBlueprintCallProxyBase +{ + GENERATED_BODY() + + virtual void Activate() override; + + void OnCancelMatchmakingComplete(FName SessionName, bool bWasSuccessful); + + TWeakObjectPtr PlayerControllerWeakPtr; + + FOnCancelMatchmakingCompleteDelegate Delegate; + + FDelegateHandle DelegateHandle; + + TWeakObjectPtr WorldContextObject; + +public: + UPROPERTY(BlueprintAssignable) + FEmptyOnlineDelegate OnSuccess; + + UPROPERTY(BlueprintAssignable) + FEmptyOnlineDelegate OnFailure; + + UFUNCTION(BlueprintCallable, meta=(BlueprintInternalUseOnly = "true", WorldContext="WorldContextObject"), Category = "Online|AdvancedSessions") + static UCancelMatchmakingCallbackProxy* CancelMatchmaking(UObject* WorldContextObject, APlayerController* PlayerController); +}; diff --git a/AdvancedSessions/Source/AdvancedSessions/Classes/StartMatchmakingCallbackProxy.h b/AdvancedSessions/Source/AdvancedSessions/Classes/StartMatchmakingCallbackProxy.h new file mode 100644 index 0000000..8e0fa71 --- /dev/null +++ b/AdvancedSessions/Source/AdvancedSessions/Classes/StartMatchmakingCallbackProxy.h @@ -0,0 +1,34 @@ +#pragma once + +#include "BlueprintDataDefinitions.h" +#include "Net/OnlineBlueprintCallProxyBase.h" +#include "StartMatchmakingCallbackProxy.generated.h" + +UCLASS(MinimalAPI) +class UStartMatchmakingCallbackProxy : public UOnlineBlueprintCallProxyBase +{ + GENERATED_BODY() + + TWeakObjectPtr WorldContextObject; + + TWeakObjectPtr PlayerControllerWeakPtr; + + TArray Filters; + + FDelegateHandle DelegateHandle; + + UFUNCTION() + void OnMatchmakingComplete(FName SessionName, bool bWasSuccessful); + +public: + UPROPERTY(BlueprintAssignable) + FEmptyOnlineDelegate OnSuccess; + + UPROPERTY(BlueprintAssignable) + FEmptyOnlineDelegate OnFailure; + + UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true", WorldContext = "WorldContextObject", AutoCreateRefTerm="Filters"), Category = "Online|AdvancedSessions") + static UStartMatchmakingCallbackProxy* StartMatchmaking(UObject* WorldContextObject, APlayerController* PlayerController, const TArray& Filters); + + virtual void Activate() override; +}; diff --git a/AdvancedSessions/Source/AdvancedSessions/Private/CancelMatchmakingCallbackProxy.cpp b/AdvancedSessions/Source/AdvancedSessions/Private/CancelMatchmakingCallbackProxy.cpp new file mode 100644 index 0000000..b843a88 --- /dev/null +++ b/AdvancedSessions/Source/AdvancedSessions/Private/CancelMatchmakingCallbackProxy.cpp @@ -0,0 +1,54 @@ +#include "CancelMatchmakingCallbackProxy.h" + +UCancelMatchmakingCallbackProxy* UCancelMatchmakingCallbackProxy::CancelMatchmaking(UObject* WorldContextObject, APlayerController* PlayerController) +{ + auto* Proxy = NewObject(); + Proxy->PlayerControllerWeakPtr = PlayerController; + Proxy->WorldContextObject = WorldContextObject; + return Proxy; +} + +void UCancelMatchmakingCallbackProxy::Activate() +{ + FOnlineSubsystemBPCallHelperAdvanced Helper(TEXT("CancelMatchmakingCallbackProxy"), GEngine->GetWorldFromContextObject(WorldContextObject.Get(), EGetWorldErrorMode::LogAndReturnNull)); + Helper.QueryIDFromPlayerController(PlayerControllerWeakPtr.Get()); + + if (Helper.IsValid()) + { + if (const auto& Sessions = Helper.OnlineSub->GetSessionInterface()) + { + DelegateHandle = Sessions->AddOnCancelMatchmakingCompleteDelegate_Handle(FOnMatchmakingCompleteDelegate::CreateUObject(this, &ThisClass::OnCancelMatchmakingComplete)); + Sessions->CancelMatchmaking(*Helper.UserID, NAME_GameSession); + return; + } + else + { + FFrame::KismetExecutionMessage(TEXT("Sessions not supported by Online Subsystem"), ELogVerbosity::Warning); + } + } + + OnFailure.Broadcast(); +} + +void UCancelMatchmakingCallbackProxy::OnCancelMatchmakingComplete(const FName SessionName, const bool bWasSuccessful) +{ + FOnlineSubsystemBPCallHelperAdvanced Helper(TEXT("CancelMatchmakingCallbackProxy"), GEngine->GetWorldFromContextObject(WorldContextObject.Get(), EGetWorldErrorMode::LogAndReturnNull)); + Helper.QueryIDFromPlayerController(PlayerControllerWeakPtr.Get()); + + if (Helper.IsValid()) + { + if (const auto& Sessions = Helper.OnlineSub->GetSessionInterface()) + { + Sessions->ClearOnCancelMatchmakingCompleteDelegate_Handle(DelegateHandle); + } + } + + if (bWasSuccessful) + { + OnSuccess.Broadcast(); + } + else + { + OnFailure.Broadcast(); + } +} diff --git a/AdvancedSessions/Source/AdvancedSessions/Private/StartMatchmakingCallbackProxy.cpp b/AdvancedSessions/Source/AdvancedSessions/Private/StartMatchmakingCallbackProxy.cpp new file mode 100644 index 0000000..83fce1a --- /dev/null +++ b/AdvancedSessions/Source/AdvancedSessions/Private/StartMatchmakingCallbackProxy.cpp @@ -0,0 +1,82 @@ +#include "StartMatchmakingCallbackProxy.h" +#include "Interfaces/OnlineSessionInterface.h" +#include "OnlineSessionSettings.h" +#include "OnlineSubsystemUtils.h" + +UStartMatchmakingCallbackProxy* UStartMatchmakingCallbackProxy::StartMatchmaking(UObject* WorldContextObject, APlayerController* PlayerController, const TArray& Filters) +{ + auto* Proxy = NewObject(); + Proxy->WorldContextObject = WorldContextObject; + Proxy->PlayerControllerWeakPtr = PlayerController; + Proxy->Filters = Filters; + return Proxy; +} + +void UStartMatchmakingCallbackProxy::Activate() +{ + auto* World = GEngine->GetWorldFromContextObject(WorldContextObject.Get(), EGetWorldErrorMode::LogAndReturnNull); + + FOnlineSubsystemBPCallHelperAdvanced Helper(TEXT("StartMatchmakingCallbackProxy"), World); + Helper.QueryIDFromPlayerController(PlayerControllerWeakPtr.Get()); + + if (World && Helper.IsValid()) + { + if (const auto& SessionInt = Helper.OnlineSub->GetSessionInterface()) + { + auto OnlineSearch = MakeShared(); + + FOnlineSearchSettingsEx SearchSettings; + for (const auto& Filter : Filters) + { + SearchSettings.HardSet(Filter.PropertyKeyPair.Key, Filter.PropertyKeyPair.Data, Filter.ComparisonOp); + } + OnlineSearch->QuerySettings = SearchSettings; + + TArray> LocalPlayers; + for (const auto* LocalPlayer : World->GetGameInstance()->GetLocalPlayers()) + { + if (const auto& UniqueNetId = LocalPlayer->GetPreferredUniqueNetId(); UniqueNetId.IsValid()) + { + LocalPlayers.Add(UniqueNetId->AsShared()); + } + } + + // TODO: What's the purpose of this? + const static FOnlineSessionSettings Dummy; + + DelegateHandle = SessionInt->AddOnMatchmakingCompleteDelegate_Handle(FOnMatchmakingCompleteDelegate::CreateUObject(this, &ThisClass::OnMatchmakingComplete)); + SessionInt->StartMatchmaking(LocalPlayers, NAME_GameSession, Dummy, OnlineSearch); + return; + } + else + { + FFrame::KismetExecutionMessage(TEXT("Sessions not supported by Online Subsystem"), ELogVerbosity::Warning); + } + } + + OnFailure.Broadcast(); +} + +void UStartMatchmakingCallbackProxy::OnMatchmakingComplete(const FName SessionName, const bool bWasSuccessful) +{ + if (const auto* World = GEngine->GetWorldFromContextObject(WorldContextObject.Get(), EGetWorldErrorMode::LogAndReturnNull)) + { + if (const auto& SessionInt = Online::GetSessionInterface(World)) + { + SessionInt->ClearOnMatchmakingCompleteDelegate_Handle(DelegateHandle); + + if (bWasSuccessful && PlayerControllerWeakPtr.IsValid()) + { + if (FString ConnectString; SessionInt->GetResolvedConnectString(SessionName, ConnectString)) + { + UE_LOG_ONLINE_SESSION(Log, TEXT("Matchmaking: traveling to %s"), *ConnectString); + PlayerControllerWeakPtr->ClientTravel(ConnectString, TRAVEL_Absolute); + OnSuccess.Broadcast(); + return; + } + } + } + } + + OnFailure.Broadcast(); +}