나만의 작은 도서관
[TIL][C++] 250520 MMO 서버 개발 21일차: 언리얼에서의 모듈과 빌드 설정, PrivateIncludePaths 등등… 본문
Today I Learn
[TIL][C++] 250520 MMO 서버 개발 21일차: 언리얼에서의 모듈과 빌드 설정, PrivateIncludePaths 등등…
pledge24 2025. 5. 21. 13:12주의사항: 해당 글은 일기와 같은 기록용으로, 다듬지 않은 날것 그대로인 글입니다.
언리얼에서의 모듈과 빌드 설정
모듈?
- 언리얼에서의 모듈은 언리얼 엔진 소프트웨어 아키텍처의 가장 기본적인 구성요소로, 엔진은 대규모 모듈 모음으로 구현되어 있다.
- 모듈은 하나의 디렉터리이다. 예를 들어, P1 모듈은 P1이라는 이름의 디렉터리를 의미한다.
프로젝트 모듈
- 언리얼 프로젝트를 만들게 되면 자동으로 프로젝트 이름으로 된 모듈이 생긴다. 예를 들어 프로젝트 이름이 “P1”이라면 P1이라는 모듈이 생긴다.
- 해당 모듈은 Source 디렉터리 아래에 생성된다. 프로젝트 빌듯이 엔진을 제외한 모든 소스 파일들을 이곳에서 참고한다.
P1.Build.cs
- P1 모듈 아래에는 P1.Build.cs라는 파일이 하나 존재하는데, 이 파일은 P1 모듈을 빌드할 경우 P1이 의존하는 다른 모듈들을 지정하거나 헤더 파일들의 경로를 지정한다. 즉, 언리얼 버전 포함 디렉터리 경로 설정 같은 거다.
- 좀 더 비슷한 모양새는 다중 상속 같은 느낌이다. 여러 모듈들을 상속받은 다음 빌드하는 느낌이다.
- 다른 모듈들을 상속받을 때 Public으로 가져올 수도 있고, private으로 가져올 수도 있다. Public으로 가져올 경우, 해당 모듈을 상속받은 다른 모듈들도 상속받지만 private의 경우 해당 모듈만 사용하고, 해당 모듈을 상속받은 다른 모듈들은 상속받지 않는다. (그냥 상속 접근 지정하라고 생각하면 된다)
상속(의존성) 추가 함수(xxx.Build.cs에 추가해야 함)
- PublicDependencyModuleNames
- 현재 모듈이 상속받을 모듈을 public으로 지정. 현재 모듈을 상속받는 모듈들도 함께 필요한 헤더와 라이브러리를 자동으로 포함시킨다.
- PrivateDependencyModuleNames
- 현재 모듈이 상속받을 모듈을 private으로 지정. 현재 모듈만 헤더와 라이브러리를 자동으로 포함시킨다.
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "Sockets", "Networking", });
PrivateDependencyModuleNames.AddRange(new string[] { "ProtobufCore" });
모듈을 찾을 때 어느 디렉터리 아래에서 찾는가?
- 모듈은 기본적으로 엔진과 현재 프로젝트 디렉터리에 존재하는 Source 디렉터리 아래에서 모듈을 찾는다.
PrivateIncludePaths
- 이 함수는 필수가 아니다. 이 함수 안에 경로를 설정하면 include시 해당 경로를 추가적으로 기입할 필요가 없어진다.
- 예를 들어, 위처럼 Source→P1이라는 디렉터리 안에 Game이랑 Network 폴더가 있다면, include 할 때마다 아래와 같이 적어줘야 접근이 가능하다.
#include "Game/xxx1.h"
#include "Network/xxx2.h"
- 하지만 privateIncludePaths에 Game과 Network에 대한 추가 경로를 설정하면 #include시 경로 생략이 가능해진다.
PrivateIncludePaths.AddRange(new string[]
{
"P1/Network/",
"P1/Game/",
});
#include "xxx1.h"
#include "xxx2.h"
- 참고로 DependencyModuleNames가 그랬던 것처럼 Includepaths함수 계열도 Public/Private이 있다. 여기선 private으로 설명했지만, publicIncludePaths를 사용하면 해당 모듈을 상속받는 모듈도 똑같이 적용된다.
visual assist
- 언리얼에서는 visual studio에서 기본적으로 제공하는 IntelliSense 사용 시 여러모로 느려지는 문제가 있다. 그래서 언리얼에선 IntelliSense대신 visual assist라는 걸 사용하는데, 이걸 사용하면 보다 쾌적한 환경에서 개발을 진행할 수 있다.
- 문제는 visual assist는 유료 확장 도구이기 때문에, 돈이 든다는 것이다….
intelliSense의 역할?
- intelliSense가 뭐길래 느려지는가 할 수 있는데, 굉장히 여러모로 도움 되는 역할을 가지고 있었다. 역할은 코드 색상 강조, 심벌 기반 색상, 자동완성 기능 등이 있다.
- 이러한 역할을 하는 intelliSense를 비활성화하면 아래와 같이 변경된다.
항목 영향 여부 설명
코드 색상 강조 (Syntax Highlighting) | ✅ 유지됨 | 기본적인 키워드 색상 (int, if, class, #include 등)은 유지됨 |
심볼 기반 색상 (클래스명, 함수명, 매크로 등) | ⚠️ 제한됨 | 일부 사용자 정의 심볼은 색상이 빠지거나 회색 처리됨 |
자동완성 | ❌ 불가함 | 기본 자동완성 기능은 꺼짐 |
오류 밑줄 (Squiggles) | ❌ 비활성화됨 | 문법 오류 빨간줄 사라짐 |
함수 인자 툴팁 | ❌ 비활성화됨 | 함수 이름 위에 매개변수 정보 표시 안 됨 |
- 결국, 조금 느리더라도 intellisense를 활성화한 상태롤 사용하기로 했다…
gitignore은 여러 개 있어도 된다.
- 이번에 알게 된 내용인데, gitignore 파일을 현재 디렉터리 기준으로 하위 경로에만 적용되기 때문에 형제 디렉터리에는 영향이 가지 않는다. 따라서 각 디렉토리에 gitignore파일이 있어도 독립적으로 사용할 수 있다.
ProjectRoot/
├── CommonAssets/
│ └── .gitignore ← 이 파일은 CommonAssets/ 내부에만 적용
├── GameProject/
│ └── .gitignore ← 이 파일은 GameProject/ 내부에만 적용
└── .git/
- 또한, 최상위 폴더에서는 하위 폴더의 규칙이 병합되어 적용되므로, 여러 gitignore 사용으로 인한 모호성은 발생하지 않는다.
언리얼 GameInstance
- gameInstance는 게임이 시작할 때 만들어져 게임이 종료될 때까지 존재하는 인스턴스로, 전역적으로 하나만 존재하기 때문에 플레이어의 전역 정보를 저장하기 적합하다.
- 레벨이 전환될 때 플레이어의 정보를 GameInstance에서 가져와 초기화할 수 있다.
- Edit→ProjectSettings→Project→Maps&Modes의 Game Instance를 설정하여 내가 만든 게임 인스턴스 클래스를 기반으로 설정할 수 있다.
사용 예제
UCLASS()
class P1_API UP1GameInstance : public UGameInstance
{
GENERATED_BODY()
public:
// UFUNCTION: 블루프린트에 뜨도록 설정
UFUNCTION(BlueprintCallable)
void ConnectToGameServer();
UFUNCTION(BlueprintCallable)
void DisconnectFromGameServer();
public:
// GameServer
class FSocket* Socket;
FString IpAddress = TEXT("127.0.0.1");
int16 Port = 7777;
};
맵 블루프린트
- Event BeginPlay: 현재 맵 시작 시 발동
- Get Game Instance: 게임 인스턴스를 가져온다. 반환 타입은 기본 타입인 UGameInstance로 가져온다.
- cast to P1 GameInstance: 내가 만든 게임 인스턴스로 다운 캐스팅한다.
- connect to Gameserver: P1 GameInstance에 있는 멤버 함수인 ConnectToGameServer를 호출한다.