온라인에서 Player들이 접근할 수 있게 만드는 Plugin을 만들것이다. 기존에 구현했던것과 달리 Plugin을 만들어 사용하면 관리가 용이하다. 기존에 했던 작업을 분리할 수 있는 Plugin을 만들고 좀 더 고도화 해보자.

 

 

목차

     

     


     

     

    Plugin 만들기

     


     

    Plugin 만들기

     

     

     

    새로운 Plugin 생성


     

     

     

    새로 만든 Plugin에 OnlineSubsystem, OnlineSubsystemSteam 플러그인 정보 기입  -  MultiplayerSessions.uplugin

     

    MultiplayerSessions.uplugin

    더보기
    {
    	"FileVersion": 3,
    	"Version": 1,
    	"VersionName": "1.0",
    	"FriendlyName": "MultiplayerSessions",
    	"Description": "Online Multiplayer Sessions",
    	"Category": "Other",
    	"CreatedBy": "SW",
    	"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
    		}
    	]
    }

    좌: 변경 전, 우: 변경 후(Plugin 정보를 기입하였다. )  


     

     

    새로 만든 Plugin에 OnlineSubsystem, OnlineSubsystemSteam 플러그인 정보 기입  -  MultiplayerSessions.Build.cs

     

    MultiplayerSessions.Build.cs

    더보기
    // 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",
    				// ... 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 ...
    			}
    			);
    	}
    }

     "OnlineSubsystem", "OnlineSubsystemSteam" 추가하기

     


     

     

     

    Plugin 기본 기능 추가하기 

     


     

    GameInstanceSubsystem으로부터 상속받는 클래스 만들기

     

    GameInstance를 부모로 가지는 클래스를 만들면 MultiplayerSession의 기능들을 포함할 수 있기 때문에 문제가 될 수 있다. 
    그래서 GameInstance를 상속받는 대신, GameInstanceSubsystem으로부터상속받는 새로운 클래스를 만들어 사용할 것이다.

     

     

    https://docs.unrealengine.com/4.27/en-US/ProgrammingAndScripting/Subsystems/

     

    Programming Subsystems

    An overview of programming subsystems in Unreal Engine 4.

    docs.unrealengine.com

     

    위 링크 언리얼 공식문서의 Reasons to Use Subsystems 참조. 

    • Engine classes의 overriding을 피하기 위해 사용 등등.

     

    Game Instance Game Instance Subsystem
    - Game 생성 시 Spawn 된다.
    - Game이 종료될 때까지 소멸되지 않는다. (=Game 종료 시 소멸)
    - 레벨 간 이동해도 계속해서 존재한다.  
    - Game Instance가 생성 된 후에 생성된다.
    - Game Instance 종료 시 소멸되고 Garbage Collector에서 처리된다.

     

    게임에서 레벨을 이동하는 경우(=던전 입장, 마을 이동 등등)가 빈번히 발생한다. 또한 FPS 게임의 경우, 한 게임이 끝나고 다시 게임이 시작되는 경우가 빈번히 발생한다. 

    그렇게 때문에 Game이 종료될 때까지 소멸하지 않는 Game Instance보다 Game Instance Subsytem을 사용하는 것이 더 유리하다. Game Instance Subsystem을 사용하면 엔진 클래스 오버라이드를 피할 수 있고 코드의 재사용성을 높일 수 있다.


     

    MultiplayerSessionsSubsystem 생성

     

    New C++ class - GameInstanceSubsystem - 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;
    
    	//
    	// 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;
    };

     

     

     

    MultiplayerSessionsSubsystem.cpp

    더보기
    #include "MultiplayerSessionsSubsystem.h"
    #include "OnlineSubsystem.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)
    {
    }
    
    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)
    {
    }

     


     

     

     

     

    MultiplayerSessions.Build.cs

     

    MultiplayerSessions.Build.cs

    더보기
    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 ...
    			}
    			);
    	}
    }

     "UMG", "Slate", "SlateCore" 추가

     


     

     

    Menu 생성

     

    New C++ class - UserWidget - 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();
    	
    };

     

     

     

     

    Menu.cpp

    더보기
    #include "Menu.h"
    
    void UMenu::MenuSetup()
    {
    	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);
    		}
    	}
    }

     

     

     

     


     

     

     

    WBP_Menu

     

    우클릭 - User Interface - Widget Blueprint - WBP_Menu 생성

     

    Canvas Panel

    • Button 2개와 버튼 안에 Text 추가.

     

    Widget 확인을 위해 Level Blueprint에  Widget을 생성하여 테스트한다. 

     

     


     

     

     

     

    실행화면