[UE5] Dedicated Server

ChangJin·2025년 2월 24일
0

Unreal Engine5

목록 보기
117/122
post-thumbnail

글에 사용된 모든 그림과 내용은 직접 만들고 작성한 것입니다.

글의 목적

서로 다른 Public IP 주소를 가지는 디바이스끼리 게임을 할 수 있도록 만들기 위해 데디케이티드 서버를 공부하고 구현한 내용을 정리하기 위함

알게 된 점

  1. 데디케이티드 서버는 서버 컴퓨터에서 실행되는 하나의 프로세스이다.
  2. 데디케이티드 서버에서의 로직은 RPC로 만들어야한다.

참고한 문서

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/setting-up-dedicated-servers-in-unreal-engine
https://dev.epicgames.com/documentation/ko-kr/unreal-engine/sessions-interface-in-unreal-engine
https://dev.epicgames.com/community/learning/tutorials/eK7q/unreal-engine-setting-up-a-dedicated-server-to-host-eos-sessions
https://www.youtube.com/watch?app=desktop&v=09yWANtKmC8
https://www.youtube.com/watch?v=tfC7HtP1oKQ
https://forums.unrealengine.com/t/creating-a-session-on-dedicated-server-launch/326004/3
https://eoshelp.epicgames.com/s/question/0D54z00009JFxNYCA1/dedicated-server-session-on-join-delegates?language=en_US
https://velog.io/@kih0976/UE5-Steam-Join-Session-Issue
https://forums.unrealengine.com/t/ue-5-5-online-subsystem-join-session-always-results-in-on-failure/2125579/18

내용

구현 방법

다음의 포스팅 글을 참고해 진행했습니다. 구현에 많은 도움이 된 글입니다.
https://velog.io/@singery00/UE5-Dedicate-%EC%84%9C%EB%B2%84-%EA%B5%AC%EC%B6%95

🎯 Dedicated Server에 대해

  • 공식 홈페이지에서는 데디케이티드 서버를 다음처럼 소개하고 있습니다.

    "데디케이티드 서버(dedicated server) 는 헤드리스로 실행되는 서버로 구성됩니다. 즉 데디케이티드 서버 게임 인스턴스에서 직접 플레이하는 클라이언트가 없습니다. 각 플레이어는 연결된 원격 클라이언트로 참여합니다. 헤드리스 서버는 비주얼을 렌더링하지 않으며 로컬로 플레이하는 사람이 없습니다."

    제가 이해한 내용으로 풀어서 설명을 드리자면, 플레이어가 없는 깡통 클라이언트를 하나 만든다고 생각하시면 이해가 빠릅니다. 그리고 그 깡통 클라이언트가 이제부터 서버를 담당하게 되어 액션에 대한 Validation 체크나 다른 클라이언트들에게 정보를 넘겨주는 역할을 수행합니다. 즉 이 데디서버는 클라이언트들끼리 통신을 위한 것입니다.

''' 즉 클라들은 데디서버의 레벨에 참여하는 개념입니다. 사람이 없는 게임 월드에 우리가 참여한다고 생각하면 편합니다. '''

항상 궁금했던 저 서버 기본맵이라고 되어있는 부분이 바로 데디서버가 처음 실행 했을 때 열릴 레벨 입니다. 지금 스크린샷의 경우에 데디서버는 프로세스를 실행하면 Lobby 레벨을 오픈하고 대기하고 있습니다.

그리고 언리얼 엔진은 서버와 클라간의 통신을 위해 PlayerController와 PlayerState는 서버 클라 모두에게 생깁니다. GameMode는 서버에서만 존재합니다. 서버에서는 캐릭터가 없습니다. 즉 RPC에 대한 로직을 PlayerController 혹은 PlayerState에 만들어야 합니다. GAS 프레임워크도 PlayerState에서 Server, Client에 따라 AcknowledgePossession, PossesedBy, OnRep_PlayerState 등에서 InitAbilityActorInfo 함수를 사용하고 Ability System Component에서 항상 Owner Actor가 누군지 확인하는 이유가 이 때문입니다.

  • 예시를 통해 설명드리겠습니다. 채팅으로 명령어를 통해 캐릭터의 색상을 바꾸는 기능을 만들었습니다. (메테리얼 사용법과 Slate만을 사용해 채팅을 구현한 내용은 이후에 정리하겠습니다. UMG 아예 안썼습니다.)

데디케이티드 서버를 A, 클라이언트 1을 B, 클라이언트 2를 C라고 하겠습니다. 편의상 나는 B라고 해봅시다. 이렇게 나타낼 수 있습니다.

  1. 이제 B에서 채팅 명령어를 통해 A에게 색을 바꾸고 싶다고 요청합니다. 이때 나의 색상을 미리 바꾸고 서버에서 Validation을 false로 주면 다시 원래 색상인 검은색으로 돌리게 할 수 있습니다.

  2. 그 다음 A에서는 Validation 체크를 합니다. 혹은 현재 월드에서 적용이 가능한지, B가 바꿀 수 있는 상태인지 등을 확인합니다.

  3. 모든 검사를 통과하고 A가 연결된 모든 클라들에게 색상을 바꾸라고 요청합니다.

  4. B와 C는 B 캐릭터의 색상을 바꿉니다.

💡여기서 생각해 볼만한 문제입니다. A에서 B,C에게 색상을 바꾸라는 명령을 내릴때 다음처럼 코드를 작성 할 수 있습니다. 매개변수인 Character는 요청한 B의 캐릭터이고 Color는 색상입니다. 지금 코드는 B 클라에서 B 캐릭터의 색상만 바뀝니다. C 클라에서는 B 캐릭터의 색상이 바뀌지 않습니다. 왜 그럴까요? RPC의 개념을 잘 공부했다면 뭐가 문제인지 금방 알 수 있습니다. A 서버에 있는 B, C 캐릭터는 C클라에 있는 B, C 캐릭터와 그 오브젝트 정보가 같지 않습니다. 서로 다른 pc의 프로세스에서 메모리를 할당받아 만들어진 오브젝트이기 때문입니다. 이를 어떻게 해결할지는 잘 생각해보시기 바랍니다.

UFUNCTION(NetMulticast, Reliable, WithValidation)
virtual void Client_ChangeChatracterColor(ACharacter* Character, const FLinearColor Color);
    
void AMyPlayerState::Client_ChangeChatracterColor_Implementation(ACharacter* Character, const FLinearColor Color)
{
	for (FConstPlayerControllerIterator Iterator = GetWorld()->GetPlayerControllerIterator(); Iterator; ++Iterator) // find all controllers
	{
		APlayerController* TargetController = Cast<APlayerController>(*Iterator);
		if (Character == TargetController->GetCharacter())
		{
			if (AMyCharacter* ch = Cast<AMyCharacter>(Character))
			{
				ch->ChangeMaterialColor(Color);
			}
		}
	}
}
profile
게임 프로그래머

0개의 댓글