목차

     

     


     

     

    Session 만들기

     


     

     

    IMPLEMENT CreateSession() - MultiplayerSessionsSubsystem

     

     

    MultiplayerSessionsSubsystem.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "Subsystems/GameInstanceSubsystem.h"
    #include "Interfaces/OnlineSessionInterface.h"
    #include "MultiplayerSessionsSubsystem.generated.h"
    
    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();
    
    protected:
    	// Internal callbacks for the delegates we'll add to the Online Session Interface delegate list.
    	// 아래의 함수들은 이 클래스 밖에서 콜하지 않는다.
    	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<FOnlineSessionSettings> LastSessionSettings;
    
    	//
    	// To add to the Online Session Interface delegate list.
    	// We'll bind our MultiplayerSessionsSubsystem internal callbacks to these.
    	//
    	FOnCreateSessionCompleteDelegate CreateSessionCompleteDelegate;
    	FDelegateHandle CreateSessionCompleteDelegateHandle;
    	FOnFindSessionsCompleteDelegate FindSessionsCompleteDelegate;
    	FDelegateHandle FindSessionsCompleteDelegateHandle;
    	FOnJoinSessionCompleteDelegate JoinSessionCompleteDelegate;
    	FDelegateHandle JoinSessionCompleteDelegateHandle;
    	FOnDestroySessionCompleteDelegate DestroySessionCompleteDelegate;
    	FDelegateHandle DestroySessionCompleteDelegateHandle;
    	FOnStartSessionCompleteDelegate StartSessionCompleteDelegate;
    	FDelegateHandle StartSessionCompleteDelegateHandle;
    };

    변수 추가

    • TSharedPtr<FOnlineSessionSettings> LastSessionSettings;

     

     

     

    MultiplayerSessionsSubsystem.cpp

    더보기
    #include "MultiplayerSessionsSubsystem.h"
    #include "OnlineSubsystem.h"
    #include "OnlineSessionSettings.h"
    
    UMultiplayerSessionsSubsystem::UMultiplayerSessionsSubsystem(): //Delegate을 만들어 On~함수에 연결한다.
    	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();//SessionInterface 변수에 IOnlineSubsystem의 SessionInterface 정보를 담는다.
    	}
    }
    
    void UMultiplayerSessionsSubsystem::CreateSession(int32 NumPublicConnections, FString MatchType)
    {
    	if (!SessionInterface.IsValid())
    	{
    		return;
    	}
    
    	//이미 존재하는 Session이 있다면 제거해준다.
    	auto ExistingSession = SessionInterface->GetNamedSession(NAME_GameSession);
    	if (ExistingSession != nullptr)
    	{
    		SessionInterface->DestroySession(NAME_GameSession);
    	}
    
    	// 새로 만드는 Session을 세팅해준다.
    	// FDelegateHandle 내에 delegate을 저장한다. 그리고 추후에 Delegate List에서 제거한다.
    	// 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;//Steam Subsystem에 연결하는 경우는 LAN Match가 아니다. NULL Subsystem을 사용하는 경우 LAN Match다.
    	LastSessionSettings->NumPublicConnections = NumPublicConnections;//함수 Input값을 적용. 접속 가능한 Players 수 제한
    	LastSessionSettings->bAllowJoinInProgress = true;//Session이 on going일 때 참가할 수 있게 설정. Session이 실행중일 때 Player들이 원할 때 들어올 수 있음
    	LastSessionSettings->bAllowJoinViaPresence = true;//Steam 기준에서 같은 region에 있는 Player들만 들어올 수 있게 설정.
    	LastSessionSettings->bShouldAdvertise = true;//Steam에서 Advertise가 가능하여 사람들이 찾아 들어올 수 있게 한다.
    	LastSessionSettings->bUsesPresence = true;//같은 region에서 session을 찾을 수 있게 해준다.
    	LastSessionSettings->Set(FName("MatchType"), MatchType, EOnlineDataAdvertisementType::ViaOnlineServiceAndPing);
    
    	const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();
    	if (false == SessionInterface->CreateSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, *LastSessionSettings))//CreateSession 리턴값이 false라면(=Session 만들기에 실패한다면)
    	{
    		//Delegate Handle를 사용하여 Delegate List에서 제거한다.
    		SessionInterface->ClearOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegateHandle);
    	}
    }
    
    void UMultiplayerSessionsSubsystem::FindSessions(int32 MaxSearchResults)
    {
    }
    
    void UMultiplayerSessionsSubsystem::JoinSession(const FOnlineSessionSearchResult& SessionResult)
    {
    }
    
    void UMultiplayerSessionsSubsystem::DestroySession()
    {
    }
    
    void UMultiplayerSessionsSubsystem::StartSession()
    {
    }
    
    void UMultiplayerSessionsSubsystem::OnCreateSessionComplete(FName SessionName, bool bWasSuccessful)
    {
    }
    
    void UMultiplayerSessionsSubsystem::OnFindSessionsComplete(bool bWasSuccessful)
    {
    }
    
    void UMultiplayerSessionsSubsystem::OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result)
    {
    }
    
    void UMultiplayerSessionsSubsystem::OnDestroySessionComplete(FName SessionName, bool bWasSuccessful)
    {
    }
    
    void UMultiplayerSessionsSubsystem::OnStartSessionComplete(FName SessionName, bool bWasSuccessful)
    {
    }

    헤더 추가

    • #include "OnlineSessionSettings.h"

     

    void UMultiplayerSessionsSubsystem::CreateSession(int32 NumPublicConnections, FString MatchType)

    • CreateSessionCompleteDelegateHandle = SessionInterface->AddOnCreateSessionCompleteDelegate_Handle (CreateSessionCompleteDelegate);
      • 새로 만드는 Session을 세팅해준다. FDelegateHandle 내에 delegate을 저장한다. 그리고 추후에 Delegate List에서 제거한다.
    • const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();
    • if (false == SessionInterface->CreateSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, *LastSessionSettings)) //CreateSession 리턴값이 false라면(=Session 만들기에 실패한다면)
      • SessionInterface->ClearOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegateHandle);
        • Delegate Handle를 사용하여 Delegate List에서 제거한다.

     


     

     

     

     

    Travel to Lobby - Menu

     

     

    Menu.h

    더보기
    #pragma once
    
    #include "CoreMinimal.h"
    #include "Blueprint/UserWidget.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")));//접속할 수 있는 Player 숫자를 input으로 만들고 4를 기본값으로 설정한다.
    
    protected:
    
    	virtual bool Initialize() override;
    	virtual void OnLevelRemovedFromWorld(ULevel* InLevel, UWorld* InWorld) override;//다른 Level로 이동하면 기존의 Level을 지우는 함수.
    
    private:
    	//meta = (BindWidget)을 사용하면 BP의 Button Widget이 아래의 변수와 연결된다. 이 때 BP와 C++변수 이름은 일치하여야 한다.
    	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") };
    };

     

     

     

     

    Menu.cpp

    더보기
    #include "Menu.h"
    #include "Components/Button.h"
    #include "MultiplayerSessionsSubsystem.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 (GameInstance)
    	{
    		//헤더에서 만든 MultiplayerSessionsSubsystem 변수에 Subsystem을 리턴 값을 넣어준다.
    		MultiplayerSessionsSubsystem = GameInstance->GetSubsystem<UMultiplayerSessionsSubsystem>();
    	}
    }
    
    bool UMenu::Initialize()
    {
    	//Super버젼이 false면 false를 리턴한다.(=상위 클래스에서 Initialize 하는게 없으면 false를 리턴하여 Initialize()를 하지 않는다.)
    	if (!Super::Initialize())
    	{
    		return false;
    	}
    
    	if (HostButton)
    	{
    		//HostButton 클릭할 때 발생하는 이벤트를 Delegate로 연결해준다.
    		HostButton->OnClicked.AddDynamic(this, &ThisClass::HostButtonClicked);
    	}
    	if (JoinButton)
    	{
    		//JoinButton 클릭할 때 발생하는 이벤트를 Delegate로 연결해준다.
    		JoinButton->OnClicked.AddDynamic(this, &ThisClass::JoinButtonClicked);
    	}
    
    	return true;
    }
    
    void UMenu::OnLevelRemovedFromWorld(ULevel* InLevel, UWorld* InWorld)
    {
    	MenuTearDown();//Widget을 뷰포트에서 지우고 input mode가 리셋된다.
    	Super::OnLevelRemovedFromWorld(InLevel, InWorld);
    }
    
    void UMenu::HostButtonClicked()
    {
    	//디버깅 테스트
    	if (GEngine)
    	{
    		GEngine->AddOnScreenDebugMessage(
    			-1,
    			15.f,
    			FColor::Yellow,
    			FString(TEXT("Host Button Clicked"))
    		);
    	}
    
    	if (MultiplayerSessionsSubsystem)
    	{
    		MultiplayerSessionsSubsystem->CreateSession(NumPublicConnections, MatchType);//NumPublicConnections 숫자 크기까지 Players 접속 가능
    		UWorld* World = GetWorld();
    		if (World)
    		{
    			World->ServerTravel("/Game/ThirdPerson/Maps/Lobby?listen");
    		}
    	}
    }
    
    void UMenu::JoinButtonClicked()
    {
    	//디버깅 테스트
    	if (GEngine)
    	{
    		GEngine->AddOnScreenDebugMessage(
    			-1,
    			15.f,
    			FColor::Yellow,
    			FString(TEXT("Join Button Clicked"))
    		);
    	}
    }
    
    void UMenu::MenuTearDown()
    {
    	RemoveFromParent();
    	UWorld* World = GetWorld();
    	if (World)
    	{
    		APlayerController* PlayerController = World->GetFirstPlayerController();
    		if (PlayerController)
    		{
    			FInputModeGameOnly InputModeData;
    			PlayerController->SetInputMode(InputModeData);
    			PlayerController->SetShowMouseCursor(false);
    		}
    	}
    }

     


     

     

     

     

    BP_ThirdPersonCharacter

     

    Event Graph

     


     

     

    실행화면

     


     

     

     

     

    Subsystem 기능들에 Callback 하기

     


     

    구조

     

     


     

     

    MultiplayerSessionSubsystem

     

    MultiplayerSessionSubsystem.h

    더보기
    #pragma once
    
    #include "CoreMinimal.h"
    #include "Subsystems/GameInstanceSubsystem.h"
    #include "Interfaces/OnlineSessionInterface.h"
    #include "MultiplayerSessionsSubsystem.generated.h"
    
    //
    // Delcaring our own custom delegates for the Menu class to bind callbacks to
    //
    DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiplayerOnCreateSessionComplete, 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;
    
    protected:
    	// Internal callbacks for the delegates we'll add to the Online Session Interface delegate list.
    	// 아래의 함수들은 이 클래스 밖에서 콜하지 않는다.
    	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<FOnlineSessionSettings> LastSessionSettings;
    
    	//
    	// To add to the Online Session Interface delegate list.
    	// We'll bind our MultiplayerSessionsSubsystem internal callbacks to these.
    	//
    	FOnCreateSessionCompleteDelegate CreateSessionCompleteDelegate;
    	FDelegateHandle CreateSessionCompleteDelegateHandle;
    	FOnFindSessionsCompleteDelegate FindSessionsCompleteDelegate;
    	FDelegateHandle FindSessionsCompleteDelegateHandle;
    	FOnJoinSessionCompleteDelegate JoinSessionCompleteDelegate;
    	FDelegateHandle JoinSessionCompleteDelegateHandle;
    	FOnDestroySessionCompleteDelegate DestroySessionCompleteDelegate;
    	FDelegateHandle DestroySessionCompleteDelegateHandle;
    	FOnStartSessionCompleteDelegate StartSessionCompleteDelegate;
    	FDelegateHandle StartSessionCompleteDelegateHandle;
    };

    Delegate

    • DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiplayerOnCreateSessionComplete, bool, bWasSuccessful);
      •  Delcaring our own custom delegates for the Menu class to bind callbacks to

     

    Delegate 연결을 위한 변수 추가

    • FMultiplayerOnCreateSessionComplete MultiplayerOnCreateSessionComplete;

     

     

     

    MultiplayerSessionSubsystem.cpp

    더보기
    #include "MultiplayerSessionsSubsystem.h"
    #include "OnlineSubsystem.h"
    #include "OnlineSessionSettings.h"
    
    UMultiplayerSessionsSubsystem::UMultiplayerSessionsSubsystem(): //Delegate을 만들어 On~함수에 연결한다.
    	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();//SessionInterface 변수에 IOnlineSubsystem의 SessionInterface 정보를 담는다.
    	}
    }
    
    void UMultiplayerSessionsSubsystem::CreateSession(int32 NumPublicConnections, FString MatchType)
    {
    	if (!SessionInterface.IsValid())
    	{
    		return;
    	}
    
    	//이미 존재하는 Session이 있다면 제거해준다.
    	auto ExistingSession = SessionInterface->GetNamedSession(NAME_GameSession);
    	if (ExistingSession != nullptr)
    	{
    		SessionInterface->DestroySession(NAME_GameSession);
    	}
    
    	// 새로 만드는 Session을 세팅해준다.
    	// FDelegateHandle 내에 delegate을 저장한다. 그리고 추후에 Delegate List에서 제거한다.
    	// 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;//Steam Subsystem에 연결하는 경우는 LAN Match가 아니다. NULL Subsystem을 사용하는 경우 LAN Match다.
    	LastSessionSettings->NumPublicConnections = NumPublicConnections;//함수 Input값을 적용. 접속 가능한 Players 수 제한
    	LastSessionSettings->bAllowJoinInProgress = true;//Session이 on going일 때 참가할 수 있게 설정. Session이 실행중일 때 Player들이 원할 때 들어올 수 있음
    	LastSessionSettings->bAllowJoinViaPresence = true;//Steam 기준에서 같은 region에 있는 Player들만 들어올 수 있게 설정.
    	LastSessionSettings->bShouldAdvertise = true;//Steam에서 Advertise가 가능하여 사람들이 찾아 들어올 수 있게 한다.
    	LastSessionSettings->bUsesPresence = true;//같은 region에서 session을 찾을 수 있게 해준다.
    	LastSessionSettings->Set(FName("MatchType"), MatchType, EOnlineDataAdvertisementType::ViaOnlineServiceAndPing);
    
    	const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();
    	if (false == SessionInterface->CreateSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, *LastSessionSettings))//CreateSession 리턴값이 false라면(=Session 만들기에 실패한다면)
    	{
    		//Delegate Handle를 사용하여 Delegate List에서 제거한다.
    		SessionInterface->ClearOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegateHandle);
    
    		// 헤더에서 만든 MultiplayerOnCreateSessionComplete delegate을 Broadcast 해준다.
    		// Broadcast our own custom delegate
    		MultiplayerOnCreateSessionComplete.Broadcast(false);//위의 if조건에서는 false
    	}
    }
    
    void UMultiplayerSessionsSubsystem::FindSessions(int32 MaxSearchResults)
    {
    }
    
    void UMultiplayerSessionsSubsystem::JoinSession(const FOnlineSessionSearchResult& SessionResult)
    {
    }
    
    void UMultiplayerSessionsSubsystem::DestroySession()
    {
    }
    
    void UMultiplayerSessionsSubsystem::StartSession()
    {
    }
    
    void UMultiplayerSessionsSubsystem::OnCreateSessionComplete(FName SessionName, bool bWasSuccessful)
    {
    	//SessionInterfaces의 Delegate을 지워준다.
    	if (SessionInterface)
    	{
    		SessionInterface->ClearOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegateHandle);
    	}
    	//MultiplayerOnCreateSessionComplete delegate를 Broadcast 해준다. 이렇게하면 Menu 클래스는 callback function 가지게 된다.
    	MultiplayerOnCreateSessionComplete.Broadcast(bWasSuccessful);
    }
    
    void UMultiplayerSessionsSubsystem::OnFindSessionsComplete(bool bWasSuccessful)
    {
    }
    
    void UMultiplayerSessionsSubsystem::OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result)
    {
    }
    
    void UMultiplayerSessionsSubsystem::OnDestroySessionComplete(FName SessionName, bool bWasSuccessful)
    {
    }
    
    void UMultiplayerSessionsSubsystem::OnStartSessionComplete(FName SessionName, bool bWasSuccessful)
    {
    }

     

     


     

     

     

    Menu

     

    Menu.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "Blueprint/UserWidget.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")));//접속할 수 있는 Player 숫자를 input으로 만들고 4를 기본값으로 설정한다.
    
    protected:
    
    	virtual bool Initialize() override;
    	virtual void OnLevelRemovedFromWorld(ULevel* InLevel, UWorld* InWorld) override;//다른 Level로 이동하면 기존의 Level을 지우는 함수.
    
    	//
    	// Callbacks for the custom delegates on the MultiplayerSessionsSubsystem
    	// MultiplayerSessionsSubsystem.h의 Dynamic Delegate과 연결된다. Dynamic과 연결되는 경우 UFUNCTION()을 꼭 붙여야 한다. 붙이지 않으면 dynamic delegate과 연결되지 않는다.
    	UFUNCTION()
    		void OnCreateSession(bool bWasSuccessful);
    
    private:
    	//meta = (BindWidget)을 사용하면 BP의 Button Widget이 아래의 변수와 연결된다. 이 때 BP와 C++변수 이름은 일치하여야 한다.
    	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") };
    };

    함수 추가

    • UFUNCTION()
      void OnCreateSession(bool bWasSuccessful);
      • Callbacks for the custom delegates on the MultiplayerSessionsSubsystem

     

     

     

    Menu.cpp

    더보기
    #include "Menu.h"
    #include "Components/Button.h"
    #include "MultiplayerSessionsSubsystem.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 (GameInstance)
    	{
    		//헤더에서 만든 MultiplayerSessionsSubsystem 변수에 Subsystem을 리턴 값을 넣어준다.
    		MultiplayerSessionsSubsystem = GameInstance->GetSubsystem<UMultiplayerSessionsSubsystem>();
    	}
    
    	if (MultiplayerSessionsSubsystem)
    	{
    		//callback을 Bind해준다.
    		MultiplayerSessionsSubsystem->MultiplayerOnCreateSessionComplete.AddDynamic(this, &ThisClass::OnCreateSession);
    	}
    }
    
    bool UMenu::Initialize()
    {
    	//Super버젼이 false면 false를 리턴한다.(=상위 클래스에서 Initialize 하는게 없으면 false를 리턴하여 Initialize()를 하지 않는다.)
    	if (!Super::Initialize())
    	{
    		return false;
    	}
    
    	if (HostButton)
    	{
    		//HostButton 클릭할 때 발생하는 이벤트를 Delegate로 연결해준다.
    		HostButton->OnClicked.AddDynamic(this, &ThisClass::HostButtonClicked);
    	}
    	if (JoinButton)
    	{
    		//JoinButton 클릭할 때 발생하는 이벤트를 Delegate로 연결해준다.
    		JoinButton->OnClicked.AddDynamic(this, &ThisClass::JoinButtonClicked);
    	}
    
    	return true;
    }
    
    void UMenu::OnLevelRemovedFromWorld(ULevel* InLevel, UWorld* InWorld)
    {
    	MenuTearDown();//Widget을 뷰포트에서 지우고 input mode가 리셋된다.
    	Super::OnLevelRemovedFromWorld(InLevel, InWorld);
    }
    
    void UMenu::OnCreateSession(bool bWasSuccessful)
    {
    	if (bWasSuccessful)
    	{
    		if (GEngine)
    		{
    			GEngine->AddOnScreenDebugMessage(
    				-1,
    				15.f,
    				FColor::Yellow,
    				FString(TEXT("Session created successfully!"))
    			);
    		}
    
    		UWorld* World = GetWorld();
    		if (World)
    		{
    			World->ServerTravel("/Game/ThirdPerson/Maps/Lobby?listen");
    		}
    	}
    	else//실패한 경우
    	{
    		if (GEngine)
    		{
    			GEngine->AddOnScreenDebugMessage(
    				-1,
    				15.f,
    				FColor::Red,
    				FString(TEXT("Failed to create session!"))
    			);
    		}
    	}
    }
    
    void UMenu::HostButtonClicked()
    {
    	if (MultiplayerSessionsSubsystem)
    	{
    		MultiplayerSessionsSubsystem->CreateSession(NumPublicConnections, MatchType);//NumPublicConnections 숫자 크기까지 Players 접속 가능
    		UWorld* World = GetWorld();
    	}
    }
    
    void UMenu::JoinButtonClicked()
    {
    	//디버깅 테스트
    	if (GEngine)
    	{
    		GEngine->AddOnScreenDebugMessage(
    			-1,
    			15.f,
    			FColor::Yellow,
    			FString(TEXT("Join Button Clicked"))
    		);
    	}
    }
    
    void UMenu::MenuTearDown()
    {
    	RemoveFromParent();
    	UWorld* World = GetWorld();
    	if (World)
    	{
    		APlayerController* PlayerController = World->GetFirstPlayerController();
    		if (PlayerController)
    		{
    			FInputModeGameOnly InputModeData;
    			PlayerController->SetInputMode(InputModeData);
    			PlayerController->SetShowMouseCursor(false);
    		}
    	}
    }

    void UMenu::MenuSetup(int32 NumberOfPublicConnections, FString TypeOfMatch)

    • if (MultiplayerSessionsSubsystem) {
      MultiplayerSessionsSubsystem->MultiplayerOnCreateSessionComplete.AddDynamic(this, &ThisClass:: OnCreateSession); }

     

    레퍼런스 주소를 잘 기입해야 한다.

    • World->ServerTravel("/Game/ThirdPerson/Maps/Lobby?listen");

     


     

     

     

    실행화면