내일배움캠프 78일차 - 언리얼 엔진 C++ 멀티플레이어: 디버그 로깅과 네트워크 함수

전처리기 명령어

#pragma region {블록명} ~ #pragma endregion
 : 두 블록 사이의 영역을 접을 수 있게 해준다.
 : 이는 언리얼 뿐만 아니라 다른 코드에서도 사용할 수 있는 기능이다.


#include "CoreMineral.h"
 : 대부분의 게임개발에 쓰이는 헤더파일들의 집약체. 새 C++ 헤더 작성 시 이미 include 되어있지만, 최적화를 위해 해제하면 필요한 헤더를 하나하나 손수 include해줘야한다. 사실상 초보자 전용.

Assert 매크로

언리얼 엔진 환경에서 사용할 수 있는, 특정 상황에서 실행을 종료하고 문제 발생 지점을 체크할 수 있는 Assert 매크로 관련 코드이다.

매크로 발동 조건에는 DO_GUARD_SLOW / DO_CHECK / DO_ENSURE 가 있으며, 각 빌드모드에 따라 1(True), 0(False)로 갈린다.

check(표현식) (DO_CHECK == 1 일때 작동)
 : 언리얼의 Assert매크로. 반환값이 false라면 실행을 중지시킨다.

checkf(표현식, 문자열포맷) (DO_CHECK == 1 일때 작동)
 : check와 동일하지만, 실행 중지 시 매개변수에 입력된 메세지를 출력한다.

verify(표현식) (DO_CHECK 무관)
 : check와 동일하지만, DO_CHECK에 무관하게 작동한다.

verifyf(표현식, 문자열포맷) (DO_CHECK 무관)
 : checkf와 동일하지만, DO_CHECK에 무관하게 작동한다.

언리얼 매크로

FORCEINLINE 함수명
 : 함수를 강제적으로 inline화 시킨다.
 : inline화란 컴파일 단계에서 컴파일러가 함수 호출 지점에 함수 내용을 갖다 붙이는 것을 의미한다.
 : getter, setter 등 간단한 함수를 호출할 때 발생하는 오버헤드 비용이 호출지점에서 함수로 이동하는 것보다 코드내용을 직접 실행하는 것이 더 효율이 좋을 수 있다.

DECLARE_LOG_CATEGORY_EXTERN(Category, DefaultVerbosity, CompileTimeVerbosity)
 : UE_LOG에 사용할 로그 카테고리를 자작하겠다는 뜻이다. 선언 후 빌드 시 해당 로그타입을 사용하고 필터링에 사용할 수도 있다.
 : 이후 DEFINE_LOG_CATEGORY(Category)를 붙여 해당 자작로그를 사용할 것을 선언할 수 있다.

 - Category: 새로 정의할 카테고리명
 - DefaultVerbosity: 로그 출력, 표시를 어떻게 할 지
 - CompileTimeVerbosity: 최종 빌드에 포함할 로그 수준을 결정



ANSI_TO_TCHAR(__FUNCTION__)
 : 현재 호출된 함수(__FUNCTION__)의 이름을 TCHAR로 가져온다.

UE_DISABLE_OPTIMIZATION ~ UE_ENABLE_OPTIMIZATION
 : 중단점 디버깅을 위한 매크로. 두 매크로 사이의 영역의 최적화를 막아 중단점이 스킵 되지않게 한다.
 : DebugGame Editor에서라면 최적화를 하지 않아 대다수의 중단점 체크가 가능하지만 Development Editor에서는 해당 매크로를 사용해줘야 한다.

언리얼 함수

Cast<클래스>
 : 해당 파생클래스로 형변환하는 함수. 캐스팅이 성공하면 변환된 객체를 반환, 실패하면 nullptr을 반환한다.

CastChecked<클래스>
 : Cast와 비슷하나 캐스팅 실패 시 checkf()를 호출하여 예외를 발생, 캐스팅이 반드시 성공해야 하고 실패 시 프로그램을 종료해야 하는 경우에 적합하다.

언리얼 네트워크에서 사용되는 데이터 단위

넷커넥션(NetConnection)

 - 모든 멀티플레이 관련 데이터들이 드나드는 "통로".
 - 서버접속한 클라이언트의 개수만큼 넷커넥션을 가진다.
 - 클라이언트는 서버와의 통신을 위한 단 하나의 넷커넥션만 가진다.

채널(Channel)

 - 넷커넥션 개체가 관리하는 속성.
 - ActorChannel, ControlChannel, VoiceChannel들을 관리한다. (ActorChannelActor Replication과 관련된 채널)

패킷(Packet), 번치(Bunch)

 - 네트워크에서 사용되는 통상적인 데이터 단위
 - 언리얼에서는 번치(Bunch)라는 특별한 패킷 단위를 사용한다.



멀티플레이 디버깅 팁

플레이어의 접속을 막고싶다면?

 "AGameModeBase::PreLogin() override" 함수에서  'ErrorMessage' 매개변수 문자열을 추가하면 접속을 거부한다. 비어 있으면 접속을 허용한다.

NetConnection의 생성을 살펴보고 싶다면?

 - 접속 후 서버에서의 ClientConnection 생성 확인
 : "AGameModeBase::PostLogin() override" 함수는 로그인 성공 후 호출되므로 이때 확인하면 된다. 또한, AGameModeBase서버에만 존재한다.

 - 접속 후 클라이언트에서의  ServerConnection 생성 확인
 : APlayerController가 클라이언트를 대변한다.
 : "APlayerController::PostNetInit() override" 함수는 액터의 네트워크 관련 속성들이 모두 초기화 된 후에 호출되는 함수이므로 NetConnection 관련 속성도 초기화 되었을 것이므로 이때 확인하면 된다.

AActor::BeginPlay() 함수의 호출 과정

GameMode::StartPlay() 함수가 호출되지 않으면 (Super::StartPlay() 미호출), 액터들의 BeginPlay() 함수도 호출되지 않는다.

GameMode서버에만 존재하므로 다른 클라이언트에게도 신호를 보내기 위해 각 PC의 GameState에게 BeginPlay() 함수 호출을 지시한다. (AGameStateBase::HandleBeginPlay)



시작 관련 주요 이벤트 함수

(PostInitializeComponentsPostNetInitGameMode::StartPlayBeginPlay)

PostInitializeComponents()

 - 해당 액터에 부착된 컴포넌트가 모두 준비된 상태에 호출된다.

PostNetInit()

 - 서버에서 해당 액터의 속성 등 변경된 내용 세팅이 모두 완료된 뒤 클라이언트에 복제되었을 때 호출되는 함수이다.
 - 멀티플레이에서BeginPlay()가 호출되려면 해당 액터에 대한 서버에서의 처리가 모두 완료되어야 한다. 

GameMode::StartPlay()

 - 게임의 시작을 지시하는 GameMode의 함수이다.

BeginPlay()

 - GameMode의 StartPlay() 함수를 통해 게임이 시작될 때 모든 액터에서 호출되는 함수이다.

Owner설정 관련 함수

APawn::PossessedBy(AController* NewController)

 - 컨트롤러가 해당 Pawn을 소유할 때 Pawn에서 호출되는 함수이다.
 - 주로 서버에서 호출되며, 새 컨트롤러에 의해 소유 될 때 필요한 초기화 작업을 수행한다.

APawn::UnPossessed()

 - 컨트롤러가 해당 Pawn의 소유권을 포기할 때 Pawn에서 호출되는 함수이다.

AController::OnPossess(APawn* InPawn)

 - 컨트롤러가 해당 Pawn을 소유할 때 Controller에서 호출되는 함수이다.
 - 서버에서만 호출되므로, 오너십 설정, 체력 초기화 등을 안전하게 초기화할 수 있다.

※ 주의
Possess(), OnPossess()클라이언트에서 호출되지 않는다. 대신 AActor::OwnerReplicatedUsing 키워드가 달린 속성을 가지므로, Owner가 초기화 되면 아래의 OnRep_Owner() 함수가 클라이언트에서 호출된다.


AActor::OnRep_Owner()

 - 클라이언트 측에서 Owner의 변경을 감지했을 때 호출되는 함수이다.
 - 이 함수가 호출되면 새로운 Owner의 NetConnection을 따르게 된다.

댓글

이 블로그의 인기 게시물

내일배움캠프 사전캠프 - 사전캠프설 연휴 커피 파밍 이벤트 작품 [ EXTREMITY ]

내일배움캠프 29일차 - 커리어데이 2일차 : 클라이언트 프로그래머로서 포트폴리오, 입사준비팁