[Unreal/Steam] Online Subsystem Steam 세션 생성하기
매치메이킹은 플레이어와 세션을 매치해 주는 프로세스를 말합니다. 세션은 기본적으로 서버에서 실행중인 게임의 인스턴스를 말하는 것으로, 여기에는 일정한 프로퍼티를 통해 공개적으로 홍보해서 게임을 플레이하고자 하는 플레이어가 검색하여 참가할 수 있도록 하는 공개 세션과, 초대를 받았거나 그 존재를 알고있는 사람만 참가할 수 있는 개인 세션이 있습니다.
현재 플레이중인 모든 게임이 나열된 온라인 게임 로비를 그려봅시다. 목록의 각 게임은 세션, 또는 개별 온라인 매치입니다. 플레이어는 검색이나 기타 수단을 통해 세션을 알게 되고, 그 세션에 참가하여 매치를 플레이합니다.
세션의 기본적인 수명은:
- 원하는 세팅으로 새로운 세션을 생성합니다.
- 플레이어의 매치 참가 요청을 기다립니다.
- 참여하고자 하는 플레이어를 등록시킵니다.
- 세션을 시작합니다.
- 매치를 플레이합니다.
- 세션을 종료합니다.
- 플레이어 등록을 해제합니다.
- 또는:
- 매치 유형을 변경하고자 하는 경우 또는 다른 플레이어 참가를 기다리려는 경우 세션을 업데이트합니다.
- 세션을 소멸시킵니다.
세션 인터페이스
세션 인터페이스 인 IOnlineSession 는 매치메이킹 수행은 물론 플레이어가 온라인 게임을 찾아 참가할 수 있도록 하기 위해 필요한 것들을 배후에 미리 구성하는 플랫폼 전용 함수성을 제공합니다. 여기에는 세션 관리, 검색이나 기타 방식을 통한 세션 찾기는 물론 그 세션 참가 및 나가기가 포함됩니다. 세션 인터페이스는 OnlineSubsystem 에 의해 생성 및 소유됩니다. 즉 서버에만 존재한다는 뜻입니다.
플랫폼마다 세션 인터페이스 클래스는 하나입니다. 새로운 플랫폼을 추가할 때, 새로운 유형의 세션 인터페이스를 생성해야 합니다. 여기서 플랫폼이라 함은 하드웨어 플랫폼을 가리킵니다. 그렇기에 한 번에 하나의 세션 인터페이스, 즉 엔진이 현재 실행중인 플랫폼에 대한 세션 인터페이스만 존재합니다.
세션 인터페이스가 모든 세션 처리를 수행하는 반면, 게임은 보통 직접 상호작용하지 못합니다. 그 대신 게임 세션 인 AGameSession 이 세션 인터페이스 주변을 감싸는 게임 전용 래퍼(wrapper) 역할을 하며, 게임 코드는 세션과 상호작용할 필요가 있을 때 그에 대한 호출을 합니다. 게임 세션은 게임 모드인 AGameModeBase 에 의해 생성 및 소유되며, 마찬가지로 온라인 게임 실행시 서버에만 존재합니다.
각 게임은 잠재적으로 다수의 게임 세션 유형을 가질 수 있지만, 한 번에 오직 하나만 사용됩니다. 게임이 둘 이상의 게임 세션 유형을 갖는 가장 흔한 경우는, 게임이 데디케이티드 서버를 사용할 때입니다.
세션 세팅
세션 세팅 은 FOnlineSessionSettings 클래스에 의해 정의되며, 세션의 특징을 정의하는 프로퍼티 집합입니다. 기본 구현에서는 이와 같은 것들입니다:
- 허용되는 플레이어 수
- 광고되는 세션인지 개인 세션인지
- 랜 매치 세션인지
- 데디케이티드 서버인지 플레이어가 호스트하는 서버인지
- 초대가 허용되는지
- 등등.
온라인 게임 로비를 예제로 들면, 각 게임은 세션이며, 별도의 세션 세팅이 있습니다. 예를 들어 어떤 세션은 플레이어 대 플레이어 (PvP) 일 수도 있고, 다른 세션은 협력 멀티플레이어 (Co-Op) 일 수도 있습니다. 각기 다른 세션에서 필요한 플레이어 수 같은 것도 제각각인 다른 맵 또는 플레이리스트를 플레이할 수 있습니다.
세션 관리
세션 인터페이스의 주요 임무중 하나는 세션 관리로, 여기에는 세션 셋업, 업데이트, 소멸(destroy)이 포함됩니다.
세션 생성
플레이어가 세션을 찾아 참가할 수 있으려면, 세션을 만들고 그 프로퍼티를 셋업해 줘야 할 뿐만 아니라, 그 프로퍼티 중 어느 것을 보이도록 하여 검색이 되도록 할지 결정해야 합니다.
세션 생성은 IOnlineSession::CreateSession() 를 사용하며, 세션 세팅 세트를 받아 새로운 세션의 환경설정에 사용합니다. 세션이 생성되면, OnCreateSessionComplete 델리게이트가 발동됩니다.
세션 업데이트
세션 업데이트는 기존 세션의 세팅을 바꾸고자 할 때 일어나며, IOnlineSession::UpdateSession() 함수를 통해 수행됩니다. 예를 들어, 세션이 현재 8 명의 플레이어까지만 받도록 셋업되어 있는데, 다음 매치에서는 12 명까지 허용하도록 할 필요가 있다 칩시다. 세션을 업데이트하려면, UpdateSession() 에다 최대 플레이어가 12 명이라는 새로운 세션 세팅을 전달하여 호출해야 합니다.
세션 업데이트 요청이 완료되면, OnUpdateSessionComplete 델리게이트가 발동됩니다. 이를 통해 세션 세팅 변경을 처리하는 데 필요한 환경설정 또는 초기화를 수행할 수 있는 기회가 제공됩니다.
세션 업데이트는 보통 서버에서 매치 사이에 일어나지만, 클라이언트에서 세션 정보 동기화 상태를 유지하기 위해 일어나기도 합니다.
세션 소멸
세션이 종료되어 더이상 필요치 않으면, IOnlineSession::DestroySession() 함수를 사용하여 세션을 소멸시킵니다. 소멸 작업이 완료되면 OnDestroySessionComplete 델리게이트가 발동되어 정리할 수 있도록 합니다.
매치메이킹 - 세션 찾기
Online Subsystem 은 활성 세션에서 플레이어 대진표를 짜는 데 필요한 기본적인 요소들을 제공합니다. 기본 구현에 내장된 특수 유형 매치메이킹을 제공하는 것은 아닙니다. 하지만 매치메이킹 서비스를 제공하는 플랫폼에서의 구현은 해당 서비스로의 접근이 노출되어 있습니다. 본질적으로는 플레이어가 참가할 수 있는 세션을 찾는 프로세스입니다. 세션을 찾았으면, 플레이어는 세션에 참가 할 수 있습니다.
세션 검색
세션을 찾는 가장 간단한 방법은, 원하는 특정 세팅을 만족하는 세션을 검색하는 것입니다. 플레이어가 유저 인터페이스에서 선택한 필터 모음에 대한 반응일 수도 있고, 플레이어의 스킬이나 기타 요소를 토대로 한 자동 검색일 수도 있으며, 그 두 방법을 조합한 것일 수도 있습니다.
세션 검색의 가장 기본적인 형태는, 가능한 모든 게임을 표시하고 플레이어가 플레이하고자 하는 게임 유형에 따라 필터를 적용한 뒤 거기에 맞는 세션 중 하나를 선택하여 참가하는 고전적인 방식입니다.
세션을 검색하려면, IOnlineSession::FindSessions() 를 사용하여 검색하려는 세션 세팅에 대한 레퍼런스를 FOnlineSessionSearch 오브젝트로 전달합니다. 세션 세팅 레퍼런스의 SearchResults 멤버가 일치하는 세션으로 채워집니다. 검색이 완료되면 OnFindSessionsComplete 델리게이트가 발동됩니다. 이 델리게이트에서 검색 결과를 대상으로 반복처리할 수 있습니다.
클라우드 기반 매치메이킹
클라우드 기반 매치메이킹이란 사용하게끔 내장된 매치메이킹 서비스를 말하며, 보통 플랫폼 전용입니다. 이러한 서비스 유형의 예로는, 마이크로소프트의 Xbox Live 서비스를 통해 사용가능한 TrueSkill 시스템을 들 수 있습니다.
그것을 지원하는 플랫폼에서 매치메이킹을 시작하려면, IOnlineSession::Startmatchmaking() 를 호출하여 매치메이킹할 플레이어의 컨트롤러 번호, 세션 이름, 세션을 새로 만드는 경우 사용하려 세션 세팅, 검색 대상 세팅을 전달합니다. 매치메이킹이 완료되면 OnMatchmakingComplete 델리게이트가 발동됩니다. 여기서는 프로세스가 성공했는지 나타내는 부울과, 성공한 경우 참가할 세션 이름이 제공됩니다.
진행중인 매치메이킹 작업은 IOnlineSession::CancelMatchmaking() 를 호출하여 처음에 매치메이킹 시작 호출시 전달했던 플레이어 컨트롤러 번호와 세션 이름을 전달합니다. 취소 작업이 완료되면 OnCancelMatchmakingComplete 델리게이트가 발동됩니다.
친구 따라가기 및 초대
친구 개념을 지원하는 플랫폼에서, 플레이어는 친구의 세션을 따라가거나 친구를 세션에 초대하는 것이 가능합니다.
친구 따라 세션으로 가는 것은 IOnlineSession:FindFriendSession() 를 호출하여 세션에 참가하고자 하는 로컬 플레이어 수 및 세션에 이미 있는 친구의 ID 를 전달합니다. 세션을 찾았고, 참가에 사용할 수 있는 검색 결과가 들어있는 경우 OnFindFriendSessionComplete 델리게이트가 발동됩니다.
플레이어는 IOnlineSession:SendSessionInviteToFriend() 또는 IOnlineSession::SendSessionInviteToFriends() 를 사용하여 로컬 플레이어 수, 세션 이름, 초대할 플레이어 ID 를 전달하는 것으로 하나 이상의 친구를 현재 세션에 초대할 수도 있습니다. 친구가 초대에 응하면, 참가할 세션 검색 결과가 들어있는 OnSessionInviteAccepted 델리게이트가 발동됩니다.
세션 참가
플레이어가 참가할 세션이 결정된 이후, 참가 프로세스는 IOnlineSession::JoinSession() 를 호출하고 플레이어 수와 이름 및 참가할 세션 검색 결과를 전달하여 시작됩니다. 참가 프로세스가 완료되면, OnJoinSessionComplete 델리게이트가 발동됩니다. 플레이어를 매치에 들여보내는 로직이 들어있는 곳입니다. 먼저 매치 참가에 필요한 플랫폼 전용 접속 정보를 반환하는 IOnlineSession::GetResolvedConnectString() 를 호출해야 합니다. 이 함수에서 얻은 스트링을 APlayerController::ClientTravel() 또는 UWorld::Servertravel() 에 전달하여 플레이어를 매치에 들여보냅니다.
// .h
#include "Interfaces/OnlineSessionInterface.h"
public :
// OnlineSessionInterface를 받아오고 델리게이트를 연결합니다.
void GetOnlineSession();
// 세션을 생성합니다.
void CreateSession();
// 세션 생성이 완료되면 호출됩니다.
void OnCreateSessionComplate(FName SessionName, bool bWasSuccessful);
private :
IOnlineSessionPtr OnlineSessionInterface;
FOnCreateSessionCompleteDelegate CreateSessionCompleteDelegate;
#include "OnlineSubsystem.h"
#include "OnlineSessionSettings.h"
void AMultiPlayerGameMode::GetOnlineSession()
{
// OnlineSubsystem에 Access
IOnlineSubsystem* OnlineSubsystem = IOnlineSubsystem::Get();
if (OnlineSubsystem)
{
// 온라인 세션 받아오기
OnlineSessionInterface = OnlineSubsystem->GetSessionInterface();
// 델리게이트 연결하기
CreateSessionCompleteDelegate.BindUObject(this, &AMultiPlayerGameMode::OnCreateSessionComplate);
if (GEngine)
{
// OnlineSubsystem 이름 출력하기
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Blue, FString::Printf(TEXT("Found subsystem %s"), *OnlineSubsystem->GetSubsystemName().ToString()));
}
}
}
void AMultiPlayerGameMode::CreateSession()
{
// Called when pressing the 1key
if (!OnlineSessionInterface.IsValid())
{
// log
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Red, FString(TEXT("Game Session is invailed")));
}
return;
}
// 이미 세션이 존재한다면 기존 세션을 삭제한다
auto ExistingSession = OnlineSessionInterface->GetNamedSession(NAME_GameSession);
if (ExistingSession != nullptr)
{
OnlineSessionInterface->DestroySession(NAME_GameSession);
// Log
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Black, FString::Printf(TEXT("Destroy session : %s"), NAME_GameSession));
}
}
// 세션 생성 완료 후 호출될 delegate 리스트에 CreateSessionCompleteDelegate 추가
OnlineSessionInterface->AddOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegate);
// 세션 세팅하기
TSharedPtr<FOnlineSessionSettings> SessionSettings = MakeShareable(new FOnlineSessionSettings());
SessionSettings->bIsLANMatch = false; // LAN 연결
SessionSettings->NumPublicConnections = 4; // 최대 접속 가능 수
SessionSettings->bAllowJoinInProgress = true; // Session 진행중에 접속 허용
SessionSettings->bAllowJoinViaPresence = true; // 세션 참가 지역을 현재 지역으로 제한 (스팀의 presence 사용)
SessionSettings->bShouldAdvertise = true; // 현재 세션을 광고할지 (스팀의 다른 플레이어에게 세션 홍보 여부)
SessionSettings->bUsesPresence = true; // 현재 지역에 세션 표시
SessionSettings->bUseLobbiesIfAvailable = true; // 플랫폼이 지원하는 경우 로비 API 사용
const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();
OnlineSessionInterface->CreateSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, *SessionSettings);
}
void AMultiPlayerGameMode::OnCreateSessionComplate(FName SessionName, bool bWasSuccessful)
{
// 세션 생성 성공!
if (bWasSuccssful)
{
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Blue, FString::Printf(TEXT("Created session : %s"), *SessionName.ToString()));
}
}
// 세선 생성 실패
else
{
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Red, FString(TEXT("Failed to create session!")));
}
}
}
'Unreal > Manual' 카테고리의 다른 글
Unreal 수명이 관리되는 자동 인스턴싱 프로그래밍 서브시스템(Programming Subsystems) (0) | 2024.03.15 |
---|---|
Unreal 하드코딩 된 REGISTER_NAME (1) | 2024.03.15 |
Unreal Steam Online Subsystem Steam 연결하기 (1) | 2024.03.14 |
Unreal Steamworks 온라인 서브시스템 Steam 가입하기 (0) | 2024.03.14 |
Unreal Enemy Spawner 구현 (3) | 2024.03.12 |