▣ 코드 설명
- UWorld* World = GetWorld();
GetWorld() 함수는 현재 캐릭터가 속한 UWorld 객체를 반환합니다.
UWorld는 게임의 맵과 관련된 정보를 포함하는 핵심 클래스입니다.
World 변수를 통해 현재 실행 중인 게임의 환경을 참조할 수 있습니다.
- if (World)
World가 nullptr이 아니라면, 즉, 유효한 UWorld 객체라면 다음 동작을 수행합니다.
nullptr이면 아무 동작도 하지 않도록 안전하게 처리합니다.
- World->ServerTravel(FString("/Game/ThirdPerson/Maps/Lobby.Lobby?listen"));
ServerTravel 함수는 서버가 새로운 맵으로 이동하도록 만듭니다.
"/Game/ThirdPerson/Maps/Lobby": 이동할 맵의 경로입니다.
"?listen": 서버가 호스트 역할을 하도록 설정하는 옵션입니다.
즉, 이 코드를 실행하는 인스턴스가 서버로 작동하고 클라이언트들이 접속할 수 있도록 만듭니다.
멀티플레이어 게임에서 사용됩니다.
▣ CreateGameSession함수에 추가합니다.
▣ 코드 설명
- SessionSettings->Set(FName("MatchType"), FString("FreeForAll"), EOnlineDataAdvertisementType::ViaOnlineServiceAndPing);
SessionSettings는 FOnlineSessionSettings 타입의 포인터이며, 게임 세션의 다양한 설정을 저장하는 객체입니다.
Set 함수는 특정 키(FName)에 해당하는 값을 저장하는 역할을 합니다.
▣ 매개변수 분석
- FName("MatchType")
"MatchType"이라는 이름의 키(Key)를 생성합니다.
FName은 UE5에서 문자열을 최적화하여 빠르게 비교할 수 있도록 설계된 데이터 타입입니다.
"MatchType"은 세션의 유형을 결정하는 역할을 합니다.
- FString("BattleRoyale")
"MatchType" 키에 대한 값(Value)으로 " BattleRoyale"을 설정합니다.
" BattleRoyale"은 일반적으로 모든 플레이어가 각자 경쟁하는 방식(개인전)을 의미합니다.
이를 "TeamDeathMatch" 또는 다른 유형으로 변경하여 게임 모드를 다르게 설정할 수 있습니다.
- EOnlineDataAdvertisementType::ViaOnlineServiceAndPing
이 인자는 세션 정보를 어떻게 공개할지를 결정합니다.
ViaOnlineServiceAndPing 옵션은 다음을 의미합니다:
세션 정보를 온라인 서비스에 등록하여 다른 플레이어가 찾을 수 있도록 합니다.
또한, 핑(Ping) 값을 활용하여 최적의 세션을 검색할 수 있도록 합니다.
다른 옵션으로 EOnlineDataAdvertisementType::DontAdvertise(세션을 공개하지 않음)나
ViaOnlineService(온라인 서비스에만 등록) 등이 있습니다.
▣ 사용 가능한 값 예시
- "TeamDeathMatch" → 팀 기반 데스매치 모드
- "CaptureTheFlag" → 깃발 뺏기 모드
- "BattleRoyale" → 배틀로얄 모드
- "CoopSurvival" → 협동 서바이벌 모드
- "CustomMode123" → 커스텀 모드
▣ 코드 설명
- Result.Session.SessionSettings.Get(FName("MatchType"), MatchType);
SessionSettings.Get(FName("MatchType"), MatchType)는 "MatchType" 키를 찾아 그 값을 MatchType 변수에 저장합니다.
"MatchType" 값은 세션 생성 시 설정된 게임 모드입니다. (예: "FreeForAll", "BattleRoyale", "TeamDeathMatch" 등)
만약 "MatchType" 키가 존재하지 않는다면, MatchType은 빈 문자열("")이 됩니다.
- if (MatchType == FString("BattleRoyale"))
검색된 세션이 "BattleRoyale" 모드인지 확인합니다.
"MatchType"이 "BattleRoyale"과 동일하면, GEngine->AddOnScreenDebugMessage를 사용하여 디버그 메시지를 출력합니다.
이는 클라이언트가 특정 유형의 게임을 필터링하여 선택할 때 유용합니다.
▣ 코드 설명
- FOnJoinSessionCompleteDelegate JoinSessionCompleteDelegate;
FOnJoinSessionCompleteDelegate는 세션 참가(Join Session) 작업이 완료되었을 때 호출되는 델리게이트(Delegate) 입니다.
델리게이트는 이벤트 기반 프로그래밍에서 특정 작업이 완료되었을 때 실행될 함수를 저장하는 역할을 합니다.
즉, 세션 참가 요청을 보낸 후, 결과를 받아 처리할 함수를 바인딩하기 위해 사용됩니다.
- void OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result);
OnJoinSessionComplete 함수는 세션 참가가 완료되었을 때 실행될 콜백 함수입니다.
매개변수:
FName SessionName → 참가한 세션의 이름
EOnJoinSessionCompleteResult::Type Result → 참가 성공 여부를 나타내는 결과 값
이 함수는 JoinSessionCompleteDelegate에 바인딩되어 있으며, 세션 참가 요청이 완료되면 자동으로 호출됩니다.
▣ EOnJoinSessionCompleteResult::Type 설명
EOnJoinSessionCompleteResult::Type은 세션 참가 결과를 나타내는 열거형(enum) 입니다.
세션 참가 요청이 끝난 후, 성공 여부나 실패 원인을 나타내는 값을 가집니다.
주요 값은 다음과 같습니다:
- 값설명
Success | 세션 참가 성공 |
SessionIsFull | 세션이 가득 차서 참가할 수 없음 |
SessionDoesNotExist | 세션이 존재하지 않음 (이미 종료되었거나 삭제됨) |
CouldNotRetrieveAddress | 세션의 네트워크 주소를 가져올 수 없음 |
AlreadyInSession | 이미 해당 세션에 참가 중 |
UnknownError | 알 수 없는 오류 발생 |
▣ 코드 설명
OnlineSessionInterface->AddOnJoinSessionCompleteDelegate_Handle(JoinSessionCompleteDelegate);
목적: JoinSessionCompleteDelegate 델리게이트를 세션 참가 완료 이벤트에 바인딩하는 역할을 합니다.
OnlineSessionInterface 객체는 온라인 세션을 관리하는 핵심 인터페이스로, 세션 생성, 검색, 참가, 종료 등의 기능을 제공합니다.
AddOnJoinSessionCompleteDelegate_Handle() 함수는 세션 참가 요청이 완료되었을 때 실행할 델리게이트를 등록하는 역할을 합니다.
▣ 코드 설명
- const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();
현재 게임 월드에서 첫 번째 로컬 플레이어를 가져옵니다.
ULocalPlayer는 현재 로컬에서 실행 중인 플레이어 정보를 포함하는 객체입니다.
GetFirstLocalPlayerFromController()는 첫 번째 로컬 플레이어(클라이언트)를 반환합니다.
- *LocalPlayer->GetPreferredUniqueNetId()
플레이어의 고유 네트워크 ID (Unique Net ID) 를 가져옵니다.
이 ID는 플레이어의 온라인 서비스 계정(Epic, Steam, Xbox 등) 에 따라 결정됩니다.
JoinSession()을 호출할 때, 참가하려는 플레이어의 고유 ID가 필요하기 때문에 이를 사용합니다.
- OnlineSessionInterface->JoinSession(...)
세션 참가 요청을 보냅니다.
JoinSession() 함수는 온라인 세션 인터페이스(IOnlineSession)의 함수로, 특정 플레이어가 원하는 세션에 참가할 수 있도록 합니다.
- 매개변수 설명
*LocalPlayer->GetPreferredUniqueNetId() | 참가할 플레이어의 고유 네트워크 ID |
NAME_GameSession | 참가할 세션의 이름 (보통 "GameSession") |
Result | 참가하려는 세션의 검색 결과 (FOnlineSessionSearchResult 객체) |
▣ 이 코드가 필요한 이유
온라인 멀티플레이어에서는 다음과 같은 과정이 필요합니다.
세션을 검색 → (어떤 서버가 있는지 찾음)
원하는 세션에 참가 → (서버에 접속)
맵 이동 및 접속 완료 → (서버로 이동)
이 코드(JoinSession())는 2단계: "원하는 세션에 참가" 를 수행합니다.
▣ 코드설명
- GetResolvedConnectString()은 현재 참가한 세션의 접속 주소(서버 주소)를 가져오는 함수입니다.
NAME_GameSession는 참가한 세션의 이름을 나타내며, 기본적으로 "GameSession"으로 설정됩니다.
가져온 주소는 Address 변수에 저장됩니다.
▣ 코드 설명
- 현재 로컬 플레이어의 컨트롤러를 가져옴 (GetFirstLocalPlayerController())
ClientTravel(Address, ETravelType::TRAVEL_Absolute)을 사용하여 서버로 이동(맵 전환)
ETravelType::TRAVEL_Absolute → 절대 주소 기반 이동
Address는 GetResolvedConnectString()에서 가져온 서버의 접속 주소
이 함수가 실행되면, 클라이언트는 서버에 접속하여 멀티플레이어 세션에 들어감.
▣ TravelType의 역할
ETravelType은 맵 이동(Travel)을 수행할 때, 어떤 방식으로 경로를 해석할지 결정하는 열거형(Enum)입니다.
ETravelType 값설명
TRAVEL_Absolute | 절대 경로를 사용하여 이동 (서버 주소 또는 전체 맵 경로 필요) |
TRAVEL_Relative | 현재 경로를 기준으로 맵 이동 (상대 경로 사용) |
TRAVEL_Partial | 상대 경로로 이동하되, 실패 시 절대 경로를 사용 |
▣ 언리얼 엔진에서는 맵 이동(Travel) 시 주소를 해석하는 방법에 따라 절대 주소(Absolute), 상대 주소(Relative), 부분 주소(Partial)로 나뉩니다.
이렇게 나뉘는 이유는 서버와 클라이언트 간의 이동 방식이 다르기 때문입니다.
▣ TRAVEL_Absolute (절대 주소)란?
개념
절대 주소(Absolute Address)란 서버의 IP 또는 전체 경로를 포함한 이동 방식을 의미합니다.
클라이언트가 완전한 서버 주소(예: 192.168.1.100:7777)로 접속할 때 사용합니다.
▣ 절대 주소 (TRAVEL_Absolute)가 필요한 이유
절대 주소(Absolute Address)란?
서버의 전체 주소(IP 또는 경로)가 포함된 경우
클라이언트가 다른 서버로 접속하려면 반드시 절대 주소가 필요함
멀티플레이어에서 서버에 직접 접속할 때 사용됨
▣ TRAVEL_Relative (상대 주소)란?
개념
상대 주소(Relative Address)란 현재 실행 중인 맵을 기준으로 상대적인 경로를 사용하여 이동하는 방식입니다.
같은 서버 내에서 맵을 변경할 때 유용합니다.
▣ 상대 주소 (TRAVEL_Relative)가 필요한 이유
상대 주소(Relative Address)란?
현재 실행 중인 맵을 기준으로 상대적인 경로를 사용하여 이동하는 방식
서버 내부에서 맵을 변경할 때 사용됨
클라이언트가 아닌, 서버 내에서 맵을 이동할 때 사용됨
▣ TRAVEL_Partial (부분 주소)란?
개념
TRAVEL_Relative와 TRAVEL_Absolute를 혼합한 방식입니다.
기본적으로 상대 주소(TRAVEL_Relative 방식)를 사용하지만, 실패하면 절대 주소(TRAVEL_Absolute 방식)를 시도합니다.
▣ 부분 주소 (TRAVEL_Partial)가 필요한 이유
부분 주소(Partial Address)란?
우선 상대 주소(TRAVEL_Relative)를 사용하려고 시도하고, 실패하면 절대 주소(TRAVEL_Absolute)로 이동하는 방식
현재 실행 중인 서버에서 맵을 찾을 수 있으면 상대 주소를 사용하고, 찾을 수 없으면 전체 경로를 사용함
▣ TravelType::TRAVEL_Absolute를 사용해야 하는 경우
TRAVEL_Absolute를 사용해야 하는 경우
클라이언트가 서버에 연결할 때 (멀티플레이어 접속)
클라이언트가 특정 서버(192.168.1.100:7777)에 접속하려면 절대 주소가 필요합니다.
상대 주소(TRAVEL_Relative 또는 TRAVEL_Partial 사용)만으로는 다른 서버에 접속할 수 없습니다.
다른 서버로 이동할 때 (ServerTravel 사용 시)
예를 들어, 로비에서 게임 서버로 이동하려면 절대 경로가 필요합니다.
ETravelType설명사용 예제
TRAVEL_Absolute | 서버 주소 또는 전체 맵 경로 사용 | open 192.168.1.100 |
TRAVEL_Relative | 현재 맵을 기준으로 상대 이동 | ServerTravel("/Game/Maps/Lobby") |
TRAVEL_Partial | 상대 이동을 시도하고, 실패 시 절대 이동 | ClientTravel("Lobby", ETravelType::TRAVEL_Partial); |
▣ OnFindSessionsComplete함수에 추가
▣ CreateGameSession()과 OnFindSessionsComplete()는 서로 다른 역할
- CreateGameSession()
서버(호스트)가 세션을 생성하는 함수
이 함수에서 설정한 SessionSettings는 서버가 세션을 생성할 때만 적용됨
즉, 호스트가 설정한 값이지, 클라이언트가 이 세션을 검색할 때 직접적인 영향을 주지 않음
- OnFindSessionsComplete()
클라이언트가 세션을 검색한 후, 특정 세션에 참가하기 위해 호출되는 함수
클라이언트가 검색한 세션(Result.Session.SessionSettings)에는 서버가 설정한 정보가 들어 있음
하지만, 일부 플랫폼에서는 클라이언트가 해당 세션의 SessionSettings를 다시 설정해야 정상적으로 참가할 수 있음
특히, Steam 서브시스템을 사용할 때 bUsesPresence = true;와 bUseLobbiesIfAvailable = true;를 추가해야 참가가 원활히 이루어짐
즉, 서버는 CreateGameSession()에서 설정을 하고, 클라이언트는 OnFindSessionsComplete()에서 다시 설정하는 것!
클라이언트가 참가하려는 세션의 설정을 명확하게 적용하기 위해 OnFindSessionsComplete()에서 다시 설정하는 것입니다.
▣ 일부 플랫폼에서는 클라이언트가 세션 참가 시 추가 설정이 필요
- bUseLobbiesIfAvailable = true;를 다시 설정하는 이유
Steam과 같은 일부 플랫폼에서는 기본적으로 bUseLobbiesIfAvailable 값이 클라이언트에서 비활성화될 수 있음
클라이언트가 세션을 찾은 후, Steam 매치메이킹 시스템이 이를 로비 기반 세션으로 처리해야 하는데, 설정이 없으면 JoinSession()이 실패할 수도 있음
따라서, 클라이언트가 세션에 참가할 때도 bUseLobbiesIfAvailable = true;를 설정해줘야 함
- bUsesPresence = true;를 다시 설정하는 이유
클라이언트가 세션을 찾고 참가할 때, Steam의 친구 초대 기능과 같은 "Presence(온라인 상태)" 기능이 필요함
일부 플랫폼에서는 클라이언트가 이 값을 직접 설정하지 않으면 세션 참가가 불가능할 수도 있음
따라서, 클라이언트가 세션에 참가하기 전에 bUsesPresence = true;를 다시 설정하면 참가 성공률이 높아짐
▣ 추가 설정이 없으면 발생할 수 있는 문제
문제 1 : Steam 서브시스템에서 클라이언트가 JoinSession()을 실행할 때 세션을 찾았지만 참가할 수 없는 문제 발생
문제 2 : GetResolvedConnectString() 호출이 실패하여 클라이언트가 서버의 주소를 받아오지 못하는 문제
문제 3 : Epic Online Services(EOS) 같은 특정 온라인 서브시스템에서는 클라이언트가 bUsesPresence = true;를 설정하지 않으면 참가 실패
▣ HasAuthority()란?
HasAuthority() == true → 현재 실행 중인 객체가 서버
HasAuthority() == false → 현재 실행 중인 객체가 클라이언트
▣ List of maps to include in a packaged build에 맵을 등록해야 하는 이유
언리얼 엔진에서 게임을 패키징(Build)할 때, 어떤 맵들을 포함할지 명시적으로 지정해야 합니다.
이 설정을 하지 않으면, 패키징된 게임에서 특정 맵을 불러올 때 맵을 찾을 수 없거나 로드되지 않는 문제가 발생할 수 있습니다.
- 맵을 등록해야 하는 이유
패키징된 게임에 포함되지 않으면 실행 불가능
언리얼 엔진은 프로젝트에서 사용되지 않는 리소스를 자동으로 제외하는 기능이 있습니다.
List of maps to include in a packaged build에 등록하지 않으면, 패키징 과정에서 해당 맵이 패키징 대상에서 제외됩니다.
따라서, 실행 중에 Open Level이나 ServerTravel()을 사용하여 해당 맵을 로드하려고 하면 맵이 존재하지 않아 실행이 불가능합니다.
- 서버/클라이언트 간 맵 동기화 문제
멀티플레이어 게임에서는 클라이언트가 서버에서 실행 중인 맵을 로드해야 합니다.
만약 List of maps to include in a packaged build에 해당 맵을 등록하지 않았다면, 클라이언트가 해당 맵을 로드할 수 없습니다.
특히, ServerTravel() 또는 ClientTravel() 을 사용할 때 클라이언트가 맵을 찾을 수 없으면 세션 참가가 실패합니다.
- 맵을 동적으로 로드하는 기능이 정상 작동하지 않음
UGameplayStatics::LoadStreamLevel() 또는 OpenLevel()을 사용하여 맵을 동적으로 로드하는 경우,
맵이 패키징에 포함되지 않으면 런타임에서 해당 맵을 찾을 수 없음.
이 문제는 특히 DLC(다운로드 콘텐츠)나 오픈 월드 게임에서 중요한 이슈가 될 수 있음.
▣ 두개의 스팀계정으로 로그인 후 서버를 생성하고 들어가는 과정 확인
'[ Unreal5 ] > - 언리얼엔진5 멀티' 카테고리의 다른 글
언리얼엔진5 Multiplay Plugin Create (0) | 2025.02.19 |
---|---|
언리얼엔진5 Session Join Setup (0) | 2025.02.15 |
언리얼엔진5 Create Session (0) | 2025.02.14 |
언리얼엔진5 Online Subsystem Steam Connection (0) | 2025.02.13 |
언리얼엔진5 Online Subsystem Steam Setting (0) | 2025.02.13 |
댓글