UE5/UE5 MultiPlayerGame

MultiPlayerGame) 13. 서브시스템 콜백함수

PJNull 2022. 6. 14.
728x90
반응형

서브시스템 콜백함수

 

 

1.지금까지 진행 사항

 

게임인스턴스서브시스템을 기반으로 한 멀티플레이어 세션서브시스템 클래스에서 세션 인터페이스 기능에 액세스 하고 있다. 서브시스템은 몇가지 델레게이트 함수를 가지고 있는데, 이것은 세션인터페이스 함수를 호출 할때 자체 콜백을 가질수 있게 한다. 메뉴클래스는 서브시스템 함수를 호출하고, 서브시스템 함수는 세션인터페이스 함수를 호출하고 있다.
세션 인터페이스 함수(CreateSession)를 호출하면 세션 인터페이스가 델레게이트 리스트를 통해 반복되며, 
여기에 추가한 델레게이트를 찾고 멀티플레이어 세션 서브 시스템 클래스에 존재하는 콜백을 호출한다.

 

 

 

 

 


하지만 그 정보를 메뉴 클래스에 다시 가져오는 방법은 어떻게 해야될 것인가?

 

 

이를 위해서 서브시스템에 서브시스템 델레게이트를 추가하고 콜백을 만들고 델레게이트에 바인딩할 것이다. 이것은 서브시스템 콜백이 세션 인터페이스 델레게이트에 응답하면, 델레게이트들은 메뉴 클래스가 콜백들에 묶은 커스텀 델레게이트를 제거하는 방식이다. 이러한 방식은 메뉴클래스는 서브시스템에 따라 다르게 되지만, 서브시스템은 메뉴클래스에 대해 알 필요가 없다. 마찬가지로 서브시스템은 세션인터페이스에 따라 다르지만 세션인터페이스는 서브시스템에 대해 알 필요가 없다.

 

 

 

 

2.메뉴 클래스에 바인딩할 델레게이트 선언

 

//MultiplayerSessionSubsystem.h


DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiplayerOnCreateSessionComplete,bool, bWasSuccessful);
DECLARE_MULTICAST_DELEGATE_TwoParams(FMultiplayerOnFindSessionComplete,const TArray<FOnlineSessionSearchResult>& SessionResults,bool bWasSuccessful);
DECLARE_MULTICAST_DELEGATE_OneParam(FMultiplayerOnJoinSessionComplete,EOnJoinSessionCompleteResult::Type Result);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiplayerOnDestorySessionComplete,bool,bWasSuccessful);


UCLASS()
{
public:
	FMultiplayerOnCreateSessionComplete MultiplayerOnCreateSessionComplete;
	FMultiplayerOnFindSessionComplete MultiplayerFindSessionComplete;
	FMultiplayerOnJoinSessionComplete MultiplayerJoinSessionComplete;
	FMultiplayerOnDestorySessionComplete MultiplayerDestorySessionComplete;
}

 

 

 

3. 메뉴에서 콜백함수 만들기

 

//Menu.h

protected:
	UFUNCTION()
		void OnCreateSession(bool bWasSuccessful);
	UFUNCTION()
		void OnDestroySession(bool bWasSuccessful);
	     
   	void OnFindSession(const TArray<FOnlineSessionSearchResult>& SessionResults, bool bWasSuccessful);
	void OnJoinSession(EOnJoinSessionCompleteResult::Type Result);

 

 

 

 

 

4. 콜백함수 바인딩

 

//Menu.cpp

void UMenu::MenuSetUp(int32 NumberOfPublicConnections, FString MatchOfType,FString LobbyPath)
{
	if (MultiplayerSessionSubsystem)
	{
		MultiplayerSessionSubsystem->MultiplayerOnCreateSessionComplete.AddDynamic(this,&ThisClass::OnCreateSession);
		MultiplayerSessionSubsystem->MultiplayerFindSessionComplete.AddUObject(this,&ThisClass::OnFindSession);
		MultiplayerSessionSubsystem->MultiplayerJoinSessionComplete.AddUObject(this,&ThisClass::OnJoinSession);
		MultiplayerSessionSubsystem->MultiplayerDestorySessionComplete.AddDynamic(this, &ThisClass::OnDestroySession);
	}
}

 

 

 

 

 

  A. CreateSession

 

 

//MultiplayerSessionSubsystem.cpp


void UMultiplayerSessionSubsystem::CreateSession(int32 NumPublicConnections, FString MatchType)
{
	const ULocalPlayer* LocalPlayer=GetWorld()->GetFirstLocalPlayerFromController();
	if(!SessionInterface->CreateSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, *LastSessionsettings))
	//밑의 Broadcast에서 false를 주면 통과하게 되어있다.
    {
		SessionInterface->ClearOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegateHandle);
	
		MultiplayerOnCreateSessionComplete.Broadcast(false);
        	//델레게이트를 브로드캐스트한다.

	}
}


void UMultiplayerSessionSubsystem::OnCreateSessionComplete(FName SessionName, bool bWasSuccessful)
{
	if (SessionInterface)
	{
		SessionInterface->ClearOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegateHandle);
		//델레게이트를 제거한다.	
	}
	MultiplayerOnCreateSessionComplete.Broadcast(bWasSuccessful);
}

 

//Menu.cpp

void UMenu::HostBtnClick()
{
	
	if (MultiplayerSessionSubsystem)
	{
		MultiplayerSessionSubsystem->CreateSession(NumPublicConnections,MatchType);
	
	}
}

void UMenu::OnCreateSession(bool bWasSuccessful)
{
	if (bWasSuccessful)
	{
		if (GEngine)
		{
			GEngine->AddOnScreenDebugMessage
			(
				-1, 15.f, FColor::Yellow, FString(TEXT("Success CreateSession"))
			);
		}

		UWorld* World = GetWorld();
		if (World)
		{
			World->ServerTravel(PathToLobby);
		}
		
	}
	else
	{
		if (GEngine)
		{
			GEngine->AddOnScreenDebugMessage
			(
				-1, 15.f, FColor::Red, FString(TEXT("Fail CreateSession"))
			);
		}
		Host_Btn->SetIsEnabled(true);
	}
}

 

 

 

 

  B. FindSession

 

//MultiplayerSessionSubsystem.h

private:
	TSharedPtr<FOnlineSessionSearch> LastSessionSearch;

 

 

//MultiplayerSessionSubsystem.cpp

void UMultiplayerSessionSubsystem::FindSession(int32 MaxSearchResult)
{
	if (!SessionInterface.IsValid())
	{
		return;
	}
	FindSessionCompleteDelegateHandle=SessionInterface->AddOnFindSessionsCompleteDelegate_Handle(FindSessionCompleteDelegate);
	
	LastSessionSearch = MakeShareable(new FOnlineSessionSearch());
	LastSessionSearch->MaxSearchResults = MaxSearchResult;
	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);
		
		MultiplayerFindSessionComplete.Broadcast(TArray<FOnlineSessionSearchResult>(),false);
	}


}


void UMultiplayerSessionSubsystem::OnFindSessionComplete(bool bWasSuccessful)
{
	if (SessionInterface)
	{
		SessionInterface->ClearOnFindSessionsCompleteDelegate_Handle(FindSessionCompleteDelegateHandle);
	
	}

	if (LastSessionSearch->SearchResults.Num() <= 0)
	{
		MultiplayerFindSessionComplete.Broadcast(TArray<FOnlineSessionSearchResult>(), false);

		return;
	}

	MultiplayerFindSessionComplete.Broadcast(LastSessionSearch->SearchResults,bWasSuccessful);

	
}

 

//Menu.cpp

void UMenu::OnFindSession(const TArray<FOnlineSessionSearchResult>& SessionResults, bool bWasSuccessful)
{
	if (MultiplayerSessionSubsystem == nullptr)return;

	for (auto Result : SessionResults)
	{
		FString SettingsValue;
		Result.Session.SessionSettings.Get(FName("MatchType"), SettingsValue);
		if (SettingsValue == MatchType)
		{
			MultiplayerSessionSubsystem->JoinSession(Result);
			return;
		}
	}
}

 

 

 

 

 

  C. JoinSession

 

 

 

//MultiplayerSessionSubsystem.cpp


void UMultiplayerSessionSubsystem::JoinSession(const FOnlineSessionSearchResult& SessionResult)
{
	if (!SessionInterface.IsValid())
	{
		MultiplayerJoinSessionComplete.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);
		MultiplayerJoinSessionComplete.Broadcast(EOnJoinSessionCompleteResult::UnknownError);
	}
}


void UMultiplayerSessionSubsystem::OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result)
{
	if (SessionInterface)
	{
		SessionInterface->ClearOnJoinSessionCompleteDelegate_Handle(JoinSessionCompleteDelegateHandle);
	}
	
	MultiplayerJoinSessionComplete.Broadcast(Result);
	
}

 

//Menu.cpp

void UMenu::JoinBtnClick()
{
	if (MultiplayerSessionSubsystem)
	{
		MultiplayerSessionSubsystem->FindSession(10000);
	}

}

void UMenu::OnJoinSession(EOnJoinSessionCompleteResult::Type Result)
{
	IOnlineSubsystem* Subsystem = IOnlineSubsystem::Get();
	if (Subsystem)
	{
		IOnlineSessionPtr SessionInterface = Subsystem->GetSessionInterface();
		if (SessionInterface.IsValid())
		{
			FString Adress;
			SessionInterface->GetResolvedConnectString(NAME_GameSession,Adress);

			APlayerController* PlayerController = GetGameInstance()->GetFirstLocalPlayerController();
			if (PlayerController)PlayerController->ClientTravel(Adress,ETravelType::TRAVEL_Absolute);
		}
	}

}

 

 

 

 

 

 

 

 

  D. DestorySession

 

//MultiplayerSessionSubsystem.cpp

void UMultiplayerSessionSubsystem::DestorySession()
{
	if (!SessionInterface.IsValid())
	{
		MultiplayerDestorySessionComplete.Broadcast(false);
		return;
	}
	DestorySessionCompleteDelegateHandle=SessionInterface->AddOnDestroySessionCompleteDelegate_Handle(DestorySessionCompleteDelegate);
	
	if (!SessionInterface->DestroySession(NAME_GameSession))
	{
		SessionInterface->ClearOnDestroySessionCompleteDelegate_Handle(DestorySessionCompleteDelegateHandle);
		MultiplayerDestorySessionComplete.Broadcast(false);

	}
}


void UMultiplayerSessionSubsystem::OnDestorySessionComplete(FName SessionName, bool bWasSuccessful)
{
	if (SessionInterface)SessionInterface->ClearOnDestroySessionCompleteDelegate_Handle(DestorySessionCompleteDelegateHandle);
	if (bWasSuccessful && bCreateSessionDestory)
	{
		bCreateSessionDestory = false;
		CreateSession(LastNumPublicConnections,LastMatchType);

	}
	MultiplayerDestorySessionComplete.Broadcast(bWasSuccessful);
	
}
728x90
반응형

댓글