https://dev.epicgames.com/documentation/ko-kr/unreal-engine/unreal-engine-modules
- Unreal Engie Software Architecture에서 가장 기본적인 구성 요소
- 특정 Editor Tool, Runtime Ability, Library 등의 기능을 독립된 코드 단위로 캡슐화
- 모든 Project와 Plugin은 자체적인 Primary Module이 있다.
- 하지만 이와 별개의 Module을 따로 정의하여 코드 정리를 할 수 있다.
- C++ 20 Module과는 무관하다.
장점
- 적절한 코드 분리를 강제하고 기능을 캡슐화 하여 구현을 숨긴다.
- Module은 각기 다른 Compile Unit으로 Compile 되기 때문에 빌드 시간이 대폭 단축된다.
- 변경되지 않은 Module은 컴파일 대상에서 제외된다.
- Dependency Graph에서 서로 연결되며, IWYU 표준에 따라 Header에 실제 사용하는 코드만 포함하도록 제한한다.
- 이는 컴파일 하는 도중 Project에서 사용하지 않는 Module은 안전하게 제외할 수 있다는 의미이기도 하다.
- Runtime 중 지정한 Module의 Load/Unload 시간을 조절할 수 있다.
- 이를 통해 활성화 할 시스템을 관리하여 Project의 Performance를 최적화 할 수 있다.
- Compile 할 Platform 등 특정 조건에 따라 Project를 포함하거나 제외할 수 있다.
구성
- Project의 Source 폴더 최상위 경로에 Module용 Directory 생성
- 이 때, Directory의 이름은 Module의 이름과 동일해야 한다.
- 만약 Source 폴더의 Sub Directory에 Module을 만드려 한다면,
Module 이름도 Sub Directory를 모두 포함해야 한다.
- Module의 Root Directory에 [ModuleName].Build.cs 파일을 생성하고, 다른 Module과의 Dependency를 정의한다.
- Dependency를 정의하면 UBS(Unreal Build System)에서 Module을 발견한다.
- Module의 Root Directory에 Private, Public 폴더를 생성한다.
- Private 폴더에 [ModuleName]Module.cpp 파일을 생성한다.
- 이 파일을 통해 Module 및 Module 관리를 위한 일반 함수를 시작/중단할 수 있다.
- .uproject나 .uplugin 파일에 속한 Module에 환경설정 정보를 추가한다.
- 추가하는 목적은 Module을 언제 Load할지 정하기 위해서다.
- Name, Type, Platform, Loading Phase 정보가 포함되어야 한다.
- 이 Module을 사용해야 하는 모든 Module의 Build.cs 파일에 dependency로 Module을 나열한다.
- Project Primary Module에 대한 Build.cs 파일이 포함될 수 있다.
- [Module].Build.cs 파일이 변경되거나, Source 파일이 다른 Folder로 옮길 때 아래 함수로 Solution 파일을 생성한다.
- GenerateProjectFiles.bat
- .uproject 우클릭 -> Generate Project Files
- Editor에서 File -> Refresh -> Visual Studio -> Project
구조 이해하기
- 모든 Module은 Plugin이나 Project의 Source Directory에 위치해야 한다.
- Module의 Root Folder는 해당 Module과 이름이 동일해야 한다.
- Root Folder의 Module마다 다음 항목을 가지고 있어야 한다.
- [ModuleName].Build.cs
- Module의 C++ 코드
- Private, Public 폴더
Build.cs 파일에서 Dependency 설정
- UBS는 IDE Solution 대신 Target.cs 파일과 Module의 Build.cs 파일에 따라 빌드를 한다.
- UBT가 IDE Solution를 무시한다.
- 때문에 Solution을 인식하도록 하려면 모든 Module의 Root Directory에 [ModuleName].build.cs 파일을 배치해야 한다.
-
더보기
using UnrealBuildTool; public class ModuleTest: ModuleRules { public ModuleTest(ReadOnlyTargetRules Target) : base(Target) { PrivateDependencyModuleNames.AddRange(new string[] {"Core"}); } }
- DependencyModuleNames 목록에 Module Name을 추가하면 사용할 수 있는 Module이 Code에 설정된다.
PrivateDependencyModuleNames
- .cpp 파일처럼 Module을 Private으로만 사용하는 경우
- Project의 Compile 시간을 줄여주기에 어지간해서는 Private Dependency를 사용하는 것이 좋다.
- Header File 내에서 Forward Declaration을 사용해 수 많은 Dependency를 Private로 만들 수 있다.
PublicDependencyModuleNames
- .h 파일처럼 Module에 있는 Class를 사용하는 경우
- 이 Module에 Dependency를 가진 다른 Module도 이 항목에 등록된 Module의 Class를 사용할 수 있다.
Private/Public Folder
- Module이 일반 C++ Module인 경우,
해당 Module의 Root Directory 하위의 Private/Public Folder에 C++ 파일을 배치해야 한다.- ModuleType이 .uproject 혹은 .uplugin에서 External로 설정되지 않은 경우
- 이 파일들은 C++ 코드에서 제공하는 접근자와 관련이 없다.
- 대신 다른 Module의 Module Code에 대한 이용성을 제어한다.
- 보통 이런 Folder를 사용할 때에는 .cpp File이 Private Folder에 배치되어야 한다.
- .h File을 Private Folder에 배치한 경우
- 보유 중인 Module 외의 다른 Module에 노출되지 않는다.
- .h File을 Public Folder에 배치한 경우
- UBS가 Contents를 현재 Module에 Dependency를 가진 모든 Module에 노출한다.
- 외부 Module의 Class는 Public Folder에 포함된 Class를 확장할 수 있다.
- 때문에 Public Folder에 포함된 Class, Struct, Enum을 사용하는 Variable, Reference를 생성할 수 있다.
- 또한 코드 단위에서 제공하는 C++ 접근자가 그대로 동작한다.
- 다른 대상에 Dependency를 가지지 않는 Module을 작업하는 경우에는
Private, Public Folder를 사용할 필요가 없다.
- 단, 이 경우에는 Folder 외부 모든 Code는 Private Folder에 있는 것처럼 행동한다.
- 대표적인 예시로 Game에서 Dependency Chain의 끝에 자주 위치하는 Primary Module이 있다.
- Unreal Editor에서 New Class Wizard로 새 Class를 생성하면 자동으로 Folder간 병렬 구조를 형성해준다.
C++에서 Module 구현
- Module을 나머지 C++ Project에 노출하려면 다음 두가지 작업이 필요하다.
- IModuleInterface를 확장하는 Class 생성
- IMPLEMENT_MODULE Macro에 추가
- 가장 간단한 방법은 Private Directory의 Module에서 .cpp 파일을 생성하고,
이름을 [ModuleName]Module.cpp로 지정하는 것 -
더보기
#include "Modules/ModuleManager.h" IMPLEMENT_MODULE(FDefaultModuleImpl, ModuleTest);
- FDefaultModuleImpl
- IModuleInterface를 확장하는 빈 class
- .cpp File에 구현할 Class를 직접 작성하여 더 디테일한 구현이 가능
- IModuleInterface에는 Load/Unload를 수행할 때 Trigger 되는 여러 함수가 포함되어 있다.
- https://docs.unrealengine.com/4.26/en-US/API/Runtime/Core/Modules/IModuleInterface/
Project에서 Module 사용하기
- 신규 Unreal Engine Project나 Plugin을 생성할 때마다 자체적인 Primary Module이 Source Folder에 자동 생성된다.
- 외부 Module은 Primary Module의 Build.cs에 추가하여 Project에 포함시킬 수 있다.
- UBT는 Compile 속도를 최적화 하기 위해 Project의 Dependency Chain에서 발견 한 Module만 Compile 한다.
- 즉, 그 어떠한 Project에서 사용하는 Build.cs 파일에 포함되어 있지 않으면 컴파일에서 제외된다.
Module Load 방식 제어
- .uproject, .uplugin 파일의 Module 목록에서 Module 및 Load 방식을 정의할 수 있다.
- Project File을 재생성 할 때 Module에 대한 항목이 없는 경우 이 항목을 목록에 자동으로 추가한다.
- 원래 Module 관련 Depedency Chain에 포함되어 있다고 가정하기 때문이다.
-
더보기
"Modules": [ { "Name": "ModuleTest", "Type": "Runtime", "LoadingPhase": "Default", }, { "Name": "ModuleTestEditor", "Type": "Editor", } ]
- GamePlay Module은 대부분 Name만 추가되고, Type은 Runtime으로 설정된다.
- Type에 대한 자세한 정보는 아래 문서에서 참고할 수 있다.
- https://dev.epicgames.com/documentation/ko-kr/unreal-engine/API/Runtime/Projects/EHostType__Type/?application_version=5.4
- LoadingPhase가 정의되지 않았다면 Default로 설정된다.
- LoadingPhase에 대한 자세한 정보는 아래 문서에서 참고할 수 있다.
- https://dev.epicgames.com/documentation/ko-kr/unreal-engine/API/Runtime/Projects/ELoadingPhase__Type?application_version=5.4
기타 파라미터
- IncludelistPlatforms/ExcludelistPlatforms(배열)
- 목록에 포함된 Platform에서 Comiple 할 Module을 포함/제외한다.
- Win32
- Win64
- Mac
- Linux
- Android
- IOS
- 목록에 포함된 Platform에서 Comiple 할 Module을 포함/제외한다.
- IncludelistTargets/ExcludelistTargets(배열)
- 목록에 포함된 Build Target에서 Comiple 할 Module을 포함/제외한다.
- Game
- Server
- Client
- Editor
- Program
- 목록에 포함된 Build Target에서 Comiple 할 Module을 포함/제외한다.
- IncludelistTargetConfigurations/ExcludelistTargetConfigurations(배열)
- 목록에 포함된 Build Configuration에서 Compile 할 Module을 포함/제외한다.
- Debug
- DebugGame
- Development
- Shipping
- Test
- 목록에 포함된 Build Configuration에서 Compile 할 Module을 포함/제외한다.
- IncludelistPrograms/ExcludelistPrograms(배열)
- 특정 Program Name 범위 내에서 Compile 할 Module을 포함/제외한다.
- AdditionalDependencies(배열)
- Module에서 필요로 하는 Additional Dependency를 지정한다.
- 대신, Build.cs 파일에서 지정해줘야 한다.
Module API 지정자
- 가장 쉽게 생각해볼 수 있는 방법
- Function/Class/Data를 자기 Module DLL 파일에 public인 것으로 Tag를 다는데 사용
- 예를 들어 Engine Module에 있는 함수를 ENGINE_API로 마킹하면,
Engine을 Import 하는 Module은 그 함수를 직접 접근할 수 있다.
- 단, 이 방법은 Engine을 Modular Mode(Desktop에서의 DLL파일)로 Compile 할 때에만 사용된다.
- 위와 반대로 모든 Code를 하나의 Exe 파일에 몰아 넣는 경우도 있다.
- 이를 Monolithic Mode라 지칭한다.
- Build Type은 UnrealBuildTool Setting이나 Platform, Build Configuration에 따라 제어된다.
- 실제로 API 매크로는 UBT의 Compile 방식에 따라 다음과 같이 분류된다.
- __declspec(dllexport).
- Modular
- __declspec(dllimport).
- Import 중인 Module에 대한 Public Module Header를 포함할 때
- __declspec().
- Monolithic
- __declspec(dllexport).
- API 매크로는 다른 Module에서 정적으로 Import 되는 Module에 대해서만 의미가 있다.
- 대표적으로 "Core" Module이 있다.
- UE4의 거의 모든 Module은 *.Build.cs 파일에 "Core"를 Import Dependency로 지정한다.
- 다수의 Module은 절대 정적으로 Import 될 일 없다.
- 대표적인 예로 "SceneOutliner" Module
- 이러한 Module들은 "동적으로 Load 되는 Module"이라 지칭한다.
- 이러한 Module들이 재밌는 점은 일종의 Plugin처럼 시동 시 발견되고, 종종 즉시 Reload가 가능하다.
- API 매크로가 사용되는 곳은 대부분 이전 Code에서 새로운 Module이 그 DLL에서 Code에 접근하고자 할 때이다.
- 새로운 Code에서는 API 매크로가 훨씬 적게 사용된다.
- 그 대신 DLL 경계를 넘나들며 함수성을 노출시키는 예쁜 Interface Layer를 셋업한다.
Package
https://dev.epicgames.com/documentation/ko-kr/unreal-engine/packaging-unreal-engine-projects
- .uasset, .umap 파일을 포함하는 Container
- 게임 내 다양한 리소스(BP, Texture, Mesh 등)와 Level을 저장한다.
- Package는 각 Asset의 수정사항을 추적하고, Asset 간의 Dependency를 관리하는데 사용된다.
- Directory 설정에 따른 성능이 천차만별이기 때문에 Directory 정리를 잘 해줘야 한다.
Configuration
- Contents Directory 구조 정의
- Project의 Content Directory 안에 구조를 설정한다.
- 반드시 Content Directory에 직접 설정 될 필요 없고, Sub Folder를 사용해도 된다.
- Project의 Content Directory 안에 구조를 설정한다.
- Asset 관리
- 각 Folder 내에 관련된 Asset을 Group으로 나눈다.
- 예를 들어, 특정 Character에 대한 모든 Asset(BP, Texture, Animation 등)을 한 Folder 내에 저장한다.
- 이 방식은 논리적인 구조를 통해 팀원이 필요한 Asset을 쉽게 찾고, 관리할 수 있도록 한다.
- 각 Folder 내에 관련된 Asset을 Group으로 나눈다.
- Dependency, Reference 관리
- Asset간의 Dependency를 적절히 관리하기 위해 Unreal Engine의 Asset Manager를 사용한다.
- Asset Manager는 Project의 모든 Asset간의 Dependency를 추적하고,
필요한 Asset만 Load하여 불필요한 Load를 줄인다.
- Compile, Build Optimization
- UBS는 변경된 Asset만 Compile/Build한다.
- 따라서 Package 단위로 Asset을 관리하면 특정 부분의 수정이 전체 Build에 미치는 영향을 최소화 할 수 있다.
- 또한 Level Streaming과 같은 기능을 활용해 필요할 때 특정 Level이나 Asset을 Load하도록 설정할 수 있다.
'UE5 > Architecture' 카테고리의 다른 글
[Architecture] String (0) | 2024.05.06 |
---|---|
[Architecture] Asset Registry (1) | 2024.05.06 |
[Architecture] Asset Reference (0) | 2024.05.06 |
[Architecture] DataAsset과 Asset Manager (0) | 2024.05.03 |
[Architecture] Async Asset Loading (0) | 2024.05.03 |