From 92f264a78ff0e85746506f8e2011b594c5551e52 Mon Sep 17 00:00:00 2001 From: Kingsmedia Date: Wed, 27 Apr 2022 19:54:30 +0200 Subject: [PATCH] Added MultiplayerSessions plugin --- .gitignore | 1 + .../Content/WBP_Menu.uasset | Bin 0 -> 41224 bytes .../MultiplayerSessions.uplugin | 34 ++++ .../MultiplayerSessions/Resources/Icon128.png | Bin 0 -> 12699 bytes .../MultiplayerSessions.Build.cs | 58 ++++++ .../MultiplayerSessions/Private/Menu.cpp | 186 ++++++++++++++++++ .../Private/MultiplayerSessions.cpp | 20 ++ .../Private/MultiplayerSessionsSubsystem.cpp | 153 ++++++++++++++ .../Source/MultiplayerSessions/Public/Menu.h | 61 ++++++ .../Public/MultiplayerSessions.h | 15 ++ .../Public/MultiplayerSessionsSubsystem.h | 81 ++++++++ 11 files changed, 609 insertions(+) create mode 100644 Plugins/MultiplayerSessions/Content/WBP_Menu.uasset create mode 100644 Plugins/MultiplayerSessions/MultiplayerSessions.uplugin create mode 100644 Plugins/MultiplayerSessions/Resources/Icon128.png create mode 100644 Plugins/MultiplayerSessions/Source/MultiplayerSessions/MultiplayerSessions.Build.cs create mode 100644 Plugins/MultiplayerSessions/Source/MultiplayerSessions/Private/Menu.cpp create mode 100644 Plugins/MultiplayerSessions/Source/MultiplayerSessions/Private/MultiplayerSessions.cpp create mode 100644 Plugins/MultiplayerSessions/Source/MultiplayerSessions/Private/MultiplayerSessionsSubsystem.cpp create mode 100644 Plugins/MultiplayerSessions/Source/MultiplayerSessions/Public/Menu.h create mode 100644 Plugins/MultiplayerSessions/Source/MultiplayerSessions/Public/MultiplayerSessions.h create mode 100644 Plugins/MultiplayerSessions/Source/MultiplayerSessions/Public/MultiplayerSessionsSubsystem.h diff --git a/.gitignore b/.gitignore index 7f934cc..917aee4 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,7 @@ SourceArt/**/*.tga # Binary Files Binaries/* Plugins/*/Binaries/* +Plugins/Developer/ # Builds Build/* diff --git a/Plugins/MultiplayerSessions/Content/WBP_Menu.uasset b/Plugins/MultiplayerSessions/Content/WBP_Menu.uasset new file mode 100644 index 0000000000000000000000000000000000000000..22c4fa63cf0ef302df6aa75d9085dd7afe43025e GIT binary patch literal 41224 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 W4y^S@)6s*DF?3itJ^Hf=*Zm*JcvLz7 literal 0 HcmV?d00001 diff --git a/Plugins/MultiplayerSessions/MultiplayerSessions.uplugin b/Plugins/MultiplayerSessions/MultiplayerSessions.uplugin new file mode 100644 index 0000000..6c4eb6f --- /dev/null +++ b/Plugins/MultiplayerSessions/MultiplayerSessions.uplugin @@ -0,0 +1,34 @@ +{ + "FileVersion": 3, + "Version": 1, + "VersionName": "1.0", + "FriendlyName": "MultiplayerSessions", + "Description": "A plugin for handling online multiplayer sessions", + "Category": "Other", + "CreatedBy": "Bert", + "CreatedByURL": "", + "DocsURL": "", + "MarketplaceURL": "", + "SupportURL": "", + "CanContainContent": true, + "IsBetaVersion": false, + "IsExperimentalVersion": false, + "Installed": false, + "Modules": [ + { + "Name": "MultiplayerSessions", + "Type": "Runtime", + "LoadingPhase": "Default" + } + ], + "Plugins": [ + { + "Name": "OnlineSubsystem", + "Enabled": true + }, + { + "Name": "OnlineSubsystemSteam", + "Enabled": true + } + ] +} \ No newline at end of file diff --git a/Plugins/MultiplayerSessions/Resources/Icon128.png b/Plugins/MultiplayerSessions/Resources/Icon128.png new file mode 100644 index 0000000000000000000000000000000000000000..1231d4aad4d0d462fb7b178eb5b30aa61a10df0b GIT binary patch literal 12699 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 a;7#~yJh_ha>A&A^fRdb=Y>l)<=>Gxy=2LS3 literal 0 HcmV?d00001 diff --git a/Plugins/MultiplayerSessions/Source/MultiplayerSessions/MultiplayerSessions.Build.cs b/Plugins/MultiplayerSessions/Source/MultiplayerSessions/MultiplayerSessions.Build.cs new file mode 100644 index 0000000..2a4fa9f --- /dev/null +++ b/Plugins/MultiplayerSessions/Source/MultiplayerSessions/MultiplayerSessions.Build.cs @@ -0,0 +1,58 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; + +public class MultiplayerSessions : ModuleRules +{ + public MultiplayerSessions(ReadOnlyTargetRules Target) : base(Target) + { + PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; + + PublicIncludePaths.AddRange( + new string[] { + // ... add public include paths required here ... + } + ); + + + PrivateIncludePaths.AddRange( + new string[] { + // ... add other private include paths required here ... + } + ); + + + PublicDependencyModuleNames.AddRange( + new string[] + { + "Core", + "OnlineSubsystem", + "OnlineSubsystemSteam", + "UMG", + "Slate", + "SlateCore" + // ... add other public dependencies that you statically link with here ... + } + ); + + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "CoreUObject", + "Engine", + "Slate", + "SlateCore" + // ... add private dependencies that you statically link with here ... + } + ); + + + DynamicallyLoadedModuleNames.AddRange( + new string[] + { + // ... add any modules that your module loads dynamically here ... + } + ); + } +} diff --git a/Plugins/MultiplayerSessions/Source/MultiplayerSessions/Private/Menu.cpp b/Plugins/MultiplayerSessions/Source/MultiplayerSessions/Private/Menu.cpp new file mode 100644 index 0000000..0c7fd94 --- /dev/null +++ b/Plugins/MultiplayerSessions/Source/MultiplayerSessions/Private/Menu.cpp @@ -0,0 +1,186 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Menu.h" +#include "Components/Button.h" +#include "MultiplayerSessionsSubsystem.h" +#include "OnlineSessionSettings.h" +#include "OnlineSubsystem.h" + +void UMenu::MenuSetup(int32 NumberOfPublicConnections, FString TypeOfMatch) +{ + NumPublicConnections = NumberOfPublicConnections; + MatchType = TypeOfMatch; + + AddToViewport(); + SetVisibility(ESlateVisibility::Visible); + bIsFocusable = true; + + UWorld* World = GetWorld(); + if (World) + { + APlayerController* PlayerController = World->GetFirstPlayerController(); + if (PlayerController) + { + FInputModeUIOnly InputModeData; + InputModeData.SetWidgetToFocus(TakeWidget()); + InputModeData.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock); + PlayerController->SetInputMode(InputModeData); + PlayerController->SetShowMouseCursor(true); + } + } + + UGameInstance* GameInstance = GetGameInstance(); + if (GetGameInstance()) + { + MultiplayerSessionsSubsystem = GameInstance->GetSubsystem(); + } + + if (MultiplayerSessionsSubsystem != nullptr) + { + MultiplayerSessionsSubsystem->MultiplayerOnCreateSessionComplete.AddDynamic(this, &ThisClass::OnCreateSession); + MultiplayerSessionsSubsystem->MultiplayerOnFindSessionsComplete.AddUObject(this, &ThisClass::OnFindSessions); + MultiplayerSessionsSubsystem->MultiplayerOnJoinSessionComplete.AddUObject(this, &ThisClass::OnJoinSession); + MultiplayerSessionsSubsystem->MultiplayerOnDestroySessionComplete.AddDynamic(this, &ThisClass::OnDestroySession); + MultiplayerSessionsSubsystem->MultiplayerOnStartSessionComplete.AddDynamic(this, &ThisClass::OnStartSession); + } +} + +bool UMenu::Initialize() +{ + if (!Super::Initialize()) + { + return false; + } + + if (HostButton) + { + HostButton->OnClicked.AddDynamic(this, &UMenu::HostButtonClicked); + } + + if (JoinButton) + { + JoinButton->OnClicked.AddDynamic(this, &UMenu::JoinButtonClicked); + } + + return true; +} + +void UMenu::OnLevelRemovedFromWorld(ULevel* InLevel, UWorld* InWorld) +{ + MenuTearDown(); + + Super::OnLevelRemovedFromWorld(InLevel, InWorld); +} + +void UMenu::OnCreateSession(bool bWasSuccessful) +{ + if (bWasSuccessful) + { + if (GEngine) + { + GEngine->AddOnScreenDebugMessage( + -1, + 15.f, + FColor::Green, + FString(TEXT("Session created successfully!"))); + } + + UWorld* World = GetWorld(); + if (World) + { + World->ServerTravel(FString("/Game/ThirdPerson/Maps/Lobby?listen")); + } + } + else + { + if (GEngine) + { + GEngine->AddOnScreenDebugMessage( + -1, + 15.f, + FColor::Red, + FString(TEXT("Failed to create session!"))); + } + } +} + +void UMenu::OnFindSessions(const TArray& SessionResults, bool bWasSuccessful) +{ + if (MultiplayerSessionsSubsystem == nullptr) + { + return; + } + + for (auto Result : SessionResults) + { + FString SettingsValue; + Result.Session.SessionSettings.Get(FName("MatchType"), SettingsValue); + if (SettingsValue == MatchType) + { + MultiplayerSessionsSubsystem->JoinSession(Result); + return; + } + } +} + +void UMenu::OnJoinSession(EOnJoinSessionCompleteResult::Type Result) +{ + IOnlineSubsystem* Subsystem = IOnlineSubsystem::Get(); + if (Subsystem) + { + IOnlineSessionPtr SessionInterface = Subsystem->GetSessionInterface(); + + if (SessionInterface.IsValid()) + { + FString Address; + SessionInterface->GetResolvedConnectString(NAME_GameSession, Address); + + APlayerController* PlayerController = GetGameInstance()->GetFirstLocalPlayerController(); + if (PlayerController) + { + PlayerController->ClientTravel(Address, ETravelType::TRAVEL_Absolute); + } + } + } +} + +void UMenu::OnDestroySession(bool bWasSuccessful) +{ +} + +void UMenu::OnStartSession(bool bWasSuccessful) +{ +} + +void UMenu::HostButtonClicked() +{ + if (MultiplayerSessionsSubsystem) + { + MultiplayerSessionsSubsystem->CreateSession(NumPublicConnections, MatchType); + } +} + +void UMenu::JoinButtonClicked() +{ + if (MultiplayerSessionsSubsystem) + { + MultiplayerSessionsSubsystem->FindSessions(10000); + } +} + +void UMenu::MenuTearDown() +{ + RemoveFromParent(); + UWorld* World = GetWorld(); + if (World) + { + APlayerController* PlayerController = World->GetFirstPlayerController(); + if (PlayerController) + { + FInputModeGameOnly InputModeData; + PlayerController->SetInputMode(InputModeData); + PlayerController->SetShowMouseCursor(false); + } + } +} diff --git a/Plugins/MultiplayerSessions/Source/MultiplayerSessions/Private/MultiplayerSessions.cpp b/Plugins/MultiplayerSessions/Source/MultiplayerSessions/Private/MultiplayerSessions.cpp new file mode 100644 index 0000000..42c4b08 --- /dev/null +++ b/Plugins/MultiplayerSessions/Source/MultiplayerSessions/Private/MultiplayerSessions.cpp @@ -0,0 +1,20 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "MultiplayerSessions.h" + +#define LOCTEXT_NAMESPACE "FMultiplayerSessionsModule" + +void FMultiplayerSessionsModule::StartupModule() +{ + // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module +} + +void FMultiplayerSessionsModule::ShutdownModule() +{ + // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, + // we call this function before unloading the module. +} + +#undef LOCTEXT_NAMESPACE + +IMPLEMENT_MODULE(FMultiplayerSessionsModule, MultiplayerSessions) \ No newline at end of file diff --git a/Plugins/MultiplayerSessions/Source/MultiplayerSessions/Private/MultiplayerSessionsSubsystem.cpp b/Plugins/MultiplayerSessions/Source/MultiplayerSessions/Private/MultiplayerSessionsSubsystem.cpp new file mode 100644 index 0000000..30561ca --- /dev/null +++ b/Plugins/MultiplayerSessions/Source/MultiplayerSessions/Private/MultiplayerSessionsSubsystem.cpp @@ -0,0 +1,153 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "MultiplayerSessionsSubsystem.h" + +#include "OnlineSubsystem.h" +#include "OnlineSessionSettings.h" + +UMultiplayerSessionsSubsystem::UMultiplayerSessionsSubsystem(): + CreateSessionCompleteDelegate(FOnCreateSessionCompleteDelegate::CreateUObject(this, &ThisClass::OnCreateSessionComplete)), + FindSessionsCompleteDelegate(FOnFindSessionsCompleteDelegate::CreateUObject(this, &ThisClass::OnFindSessionsComplete)), + JoinSessionCompleteDelegate(FOnJoinSessionCompleteDelegate::CreateUObject(this, &ThisClass::OnJoinSessionComplete)), + DestroySessionCompleteDelegate(FOnDestroySessionCompleteDelegate::CreateUObject(this, &ThisClass::OnDestroySessionComplete)), + StartSessionCompleteDelegate(FOnStartSessionCompleteDelegate::CreateUObject(this, &ThisClass::OnStartSessionComplete)) +{ + IOnlineSubsystem* Subsystem = IOnlineSubsystem::Get(); + if (Subsystem) + { + SessionInterface = Subsystem->GetSessionInterface(); + } + +} + +void UMultiplayerSessionsSubsystem::CreateSession(int32 NumPublicConnections, FString MatchType) +{ + if (!SessionInterface.IsValid()) + { + return; + } + + auto ExistingSession = SessionInterface->GetNamedSession(NAME_GameSession); + if (ExistingSession != nullptr) + { + SessionInterface->DestroySession(NAME_GameSession); + } + + // Store the delegate in a FDelegateHandle so we can later remove it from the delegate list + CreateSessionCompleteDelegateHandle = SessionInterface->AddOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegate); + + LastSessionSettings = MakeShareable(new FOnlineSessionSettings()); + LastSessionSettings->bIsLANMatch = IOnlineSubsystem::Get()->GetSubsystemName() == "NULL" ? true : false; + LastSessionSettings->NumPublicConnections = NumPublicConnections; + LastSessionSettings->bAllowJoinInProgress = true; + LastSessionSettings->bAllowJoinViaPresence = true; + LastSessionSettings->bShouldAdvertise = true; + LastSessionSettings->bUsesPresence = true; + LastSessionSettings->bUseLobbiesIfAvailable = true; // For UE5 when not finding sessions + LastSessionSettings->Set(FName("MatchType"), FString(MatchType), EOnlineDataAdvertisementType::ViaOnlineServiceAndPing); + LastSessionSettings->BuildUniqueId = 1; + + const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController(); + if (!SessionInterface->CreateSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, *LastSessionSettings)) + { + SessionInterface->ClearOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegateHandle); + + // Broadcast our own custom delegate + MultiplayerOnCreateSessionComplete.Broadcast(false); + } +} + +void UMultiplayerSessionsSubsystem::FindSessions(int32 MaxSearchResults) +{ + if (!SessionInterface.IsValid()) + { + return; + } + + FindSessionCompleteDelegateHandle = SessionInterface->AddOnFindSessionsCompleteDelegate_Handle(FindSessionsCompleteDelegate); + + LastSessionSearch = MakeShareable(new FOnlineSessionSearch); + LastSessionSearch->MaxSearchResults = MaxSearchResults; + LastSessionSearch->bIsLanQuery = IOnlineSubsystem::Get()->GetSubsystemName() == "NULL" ? true : false; + LastSessionSearch->QuerySettings.Set(SEARCH_PRESENCE, true, EOnlineComparisonOp::Equals); + + const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController(); + if (!SessionInterface->FindSessions(*LocalPlayer->GetPreferredUniqueNetId(), LastSessionSearch.ToSharedRef())) + { + SessionInterface->ClearOnFindSessionsCompleteDelegate_Handle(FindSessionCompleteDelegateHandle); + + MultiplayerOnFindSessionsComplete.Broadcast(TArray(), false); + } +} + +void UMultiplayerSessionsSubsystem::JoinSession(const FOnlineSessionSearchResult& SessionResult) +{ + if (!SessionInterface.IsValid()) + { + MultiplayerOnJoinSessionComplete.Broadcast(EOnJoinSessionCompleteResult::UnknownError); + return; + } + + JoinSessionCompleteDelegateHandle = SessionInterface->AddOnJoinSessionCompleteDelegate_Handle(JoinSessionCompleteDelegate); + + const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController(); + if (!SessionInterface->JoinSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, SessionResult)) + { + SessionInterface->ClearOnJoinSessionCompleteDelegate_Handle(JoinSessionCompleteDelegateHandle); + + MultiplayerOnJoinSessionComplete.Broadcast(EOnJoinSessionCompleteResult::UnknownError); + } +} + +void UMultiplayerSessionsSubsystem::DestroySession() +{ +} + +void UMultiplayerSessionsSubsystem::StartSession() +{ +} + +void UMultiplayerSessionsSubsystem::OnCreateSessionComplete(FName SessionName, bool bWasSuccessful) +{ + if (SessionInterface) + { + SessionInterface->ClearOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegateHandle); + } + + MultiplayerOnCreateSessionComplete.Broadcast(bWasSuccessful); +} + +void UMultiplayerSessionsSubsystem::OnFindSessionsComplete(bool bWasSuccessful) +{ + if (SessionInterface) + { + SessionInterface->ClearOnFindSessionsCompleteDelegate_Handle(FindSessionCompleteDelegateHandle); + } + + if (LastSessionSearch->SearchResults.Num() <= 0) + { + MultiplayerOnFindSessionsComplete.Broadcast(TArray(), false); + return; + } + + MultiplayerOnFindSessionsComplete.Broadcast(LastSessionSearch->SearchResults, bWasSuccessful); +} + +void UMultiplayerSessionsSubsystem::OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result) +{ + if (SessionInterface) + { + SessionInterface->ClearOnJoinSessionCompleteDelegate_Handle(JoinSessionCompleteDelegateHandle); + } + + MultiplayerOnJoinSessionComplete.Broadcast(Result); +} + +void UMultiplayerSessionsSubsystem::OnDestroySessionComplete(FName SessionName, bool bWasSuccessful) +{ +} + +void UMultiplayerSessionsSubsystem::OnStartSessionComplete(FName SessionNAme, bool bWasSuccessful) +{ +} diff --git a/Plugins/MultiplayerSessions/Source/MultiplayerSessions/Public/Menu.h b/Plugins/MultiplayerSessions/Source/MultiplayerSessions/Public/Menu.h new file mode 100644 index 0000000..a53cbd5 --- /dev/null +++ b/Plugins/MultiplayerSessions/Source/MultiplayerSessions/Public/Menu.h @@ -0,0 +1,61 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Blueprint/UserWidget.h" +#include "Interfaces/OnlineSessionInterface.h" +#include "Menu.generated.h" + +/** + * + */ +UCLASS() +class MULTIPLAYERSESSIONS_API UMenu : public UUserWidget +{ + GENERATED_BODY() + +public: + + UFUNCTION(BlueprintCallable) + void MenuSetup(int32 NumberOfPublicConnections = 4, FString TypeOfMatch = FString(TEXT("FreeForAll"))); + +protected: + + virtual bool Initialize() override; + virtual void OnLevelRemovedFromWorld(ULevel* InLevel, UWorld* InWorld) override; + + /* + * Callbacks fot the custom delegates on the MultiplayerSessionsSubsystem + */ + UFUNCTION() + void OnCreateSession(bool bWasSuccessful); + void OnFindSessions(const TArray& SessionResults, bool bWasSuccessful); + void OnJoinSession(EOnJoinSessionCompleteResult::Type Result); + UFUNCTION() + void OnDestroySession(bool bWasSuccessful); + UFUNCTION() + void OnStartSession(bool bWasSuccessful); + +private: + + UPROPERTY(meta=(BindWidget)) + class UButton* HostButton; + + UPROPERTY(meta=(BindWidget)) + UButton* JoinButton; + + UFUNCTION() + void HostButtonClicked(); + + UFUNCTION() + void JoinButtonClicked(); + + void MenuTearDown(); + + // The subsystem designed to handle all online session functionality + class UMultiplayerSessionsSubsystem* MultiplayerSessionsSubsystem; + + int32 NumPublicConnections {4}; + FString MatchType {TEXT("FreeForAll")}; +}; diff --git a/Plugins/MultiplayerSessions/Source/MultiplayerSessions/Public/MultiplayerSessions.h b/Plugins/MultiplayerSessions/Source/MultiplayerSessions/Public/MultiplayerSessions.h new file mode 100644 index 0000000..c32ff38 --- /dev/null +++ b/Plugins/MultiplayerSessions/Source/MultiplayerSessions/Public/MultiplayerSessions.h @@ -0,0 +1,15 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "Modules/ModuleManager.h" + +class FMultiplayerSessionsModule : public IModuleInterface +{ +public: + + /** IModuleInterface implementation */ + virtual void StartupModule() override; + virtual void ShutdownModule() override; +}; diff --git a/Plugins/MultiplayerSessions/Source/MultiplayerSessions/Public/MultiplayerSessionsSubsystem.h b/Plugins/MultiplayerSessions/Source/MultiplayerSessions/Public/MultiplayerSessionsSubsystem.h new file mode 100644 index 0000000..7db1c11 --- /dev/null +++ b/Plugins/MultiplayerSessions/Source/MultiplayerSessions/Public/MultiplayerSessionsSubsystem.h @@ -0,0 +1,81 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "OnlineSessionSettings.h" +#include "Subsystems/GameInstanceSubsystem.h" +#include "Interfaces/OnlineSessionInterface.h" +#include "MultiplayerSessionsSubsystem.generated.h" + + +// Declaring our own custom delegates for the Menu class to bind callbacks to +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiplayerOnCreateSessionComplete, bool, bWasSuccessful); +DECLARE_MULTICAST_DELEGATE_TwoParams(FMultiplayerOnFindSessionsComplete, const TArray& SessionResults, bool bWasSuccessful); +DECLARE_MULTICAST_DELEGATE_OneParam(FMultiplayerOnJoinSessionComplete, EOnJoinSessionCompleteResult::Type Result) +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiplayerOnDestroySessionComplete, bool, bWasSuccessful); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiplayerOnStartSessionComplete, bool, bWasSuccessful); + +/** + * + */ +UCLASS() +class MULTIPLAYERSESSIONS_API UMultiplayerSessionsSubsystem : public UGameInstanceSubsystem +{ + GENERATED_BODY() + +public: + + UMultiplayerSessionsSubsystem(); + + /* + * To handle session functionality. The Menu class will call these + */ + void CreateSession(int32 NumPublicConnections, FString MatchType); + void FindSessions(int32 MaxSearchResults); + void JoinSession(const FOnlineSessionSearchResult& SessionResult); + void DestroySession(); + void StartSession(); + + /* + * Our own custom delegates for the Menu class to bind callbacks to + */ + FMultiplayerOnCreateSessionComplete MultiplayerOnCreateSessionComplete; + FMultiplayerOnFindSessionsComplete MultiplayerOnFindSessionsComplete; + FMultiplayerOnJoinSessionComplete MultiplayerOnJoinSessionComplete; + FMultiplayerOnDestroySessionComplete MultiplayerOnDestroySessionComplete; + FMultiplayerOnStartSessionComplete MultiplayerOnStartSessionComplete; + +protected: + + /* + * Internal callbacks for the delegates we'll add to the Online Session Interface delegate list. + * These don't need to be called outside this class + */ + void OnCreateSessionComplete(FName SessionName, bool bWasSuccessful); + void OnFindSessionsComplete(bool bWasSuccessful); + void OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result); + void OnDestroySessionComplete(FName SessionName, bool bWasSuccessful); + void OnStartSessionComplete(FName SessionNAme, bool bWasSuccessful); + +private: + + IOnlineSessionPtr SessionInterface; + TSharedPtr LastSessionSettings; + TSharedPtr LastSessionSearch; + + /* + * To add to the Online Session Interface delegate list. + * We'll bind our MultiplayerSessionSubsystem internal callbacks to these. + */ + FOnCreateSessionCompleteDelegate CreateSessionCompleteDelegate; + FDelegateHandle CreateSessionCompleteDelegateHandle; + FOnFindSessionsCompleteDelegate FindSessionsCompleteDelegate; + FDelegateHandle FindSessionCompleteDelegateHandle; + FOnJoinSessionCompleteDelegate JoinSessionCompleteDelegate; + FDelegateHandle JoinSessionCompleteDelegateHandle; + FOnDestroySessionCompleteDelegate DestroySessionCompleteDelegate; + FDelegateHandle DestroySessionCompleteDelegateHandle; + FOnStartSessionCompleteDelegate StartSessionCompleteDelegate; + FDelegateHandle StartSessionCompleteDelegateHandle; +};