- 엔진이 어떤 방식으로 작업을 진행하는지 볼 수 있다, 더 엔진을 잘 이해할 수 있게 된다. 엔진 코드를 수정할 것이 아니라면 Install 시 런처에서 add하면 된다.
- 엔진 코드를 수정하여 커스텀 애셋을 만들 수 있다.
- 커스텀 엔진 빌드를 하는 경우 레지스트리에 빌드 ID가 등록된다.
- 커스텀 엔진 경로를 기존 엔진 경로와 동일한 위치에 두면 Perforce로 버전을 관리할 때 UnrealGameSync 툴을 이용하여 프로젝트를 팀 내에서 공유할 수 있다. 사용자들은 로컬에서 컴파일하지 않고 미리 빌드된 바이너리들을 서버에서 다운로드 받을 수 있다.
폴더 구조
- 엔진의 폴더 구조와 프로젝트 폴더 구조는 유사하다.
프로젝트는 엔진의 확장과 같은 역할을 하기 때문이다.
- Content 폴더
모든 애셋을 저장하는 폴더
애셋을 옮기고 싶으면 에디터의 Content Browser에서 옮겨야 엔진이 레퍼런스 변화를 기록할 수 있다.
- Binaries 폴더
빌드 모듈이 존재한다. (PDB 파일, UBT에 의해 만들어진 Executable 파일)
엔진 폴더에는 다양한 툴이 존재한다. (Swarm Agent, SwarmCoordinator, UnrealInsights, UnrealEditor.exe )
- Config 폴더
프로젝트 세팅이 저장되는 곳
엔진 폴더에는 BaseEditor.ini 프로젝트 폴더에는 DefaultEditor.ini가 있는데 프로젝트 폴더에 있는 Config 파일이 엔진의 것을 오버라이드 할 수 있다.
Config 폴더 내에 Platform 폴더가 존재하는데 폴더 이름은 플랫폼 명으로 만들어지고, Config 파일 이름은 플랫폼 이름을 포함해야 한다.
- Saved 폴더
프로젝트의 첫 실행 시 생성되는 폴더이다.
로컬 세팅 및 몇몇 데이터를 생성한다.
Saved 폴더 아래에 있는 폴더들
수정된 애셋을 자동 저장하는 Autosaves 폴더 : 애셋 복구하는데 사용할 수 있다.
Config 폴더 : 로컬 프로젝트를 위한 모든 오버라이드 설정 파일 포함
Crashes폴더 : 크래시 발생 시 로그를 저장, Dump파일 생성 (콜 스택 확인용)
Log 폴더 : 과거에 에디터나 게임 세션에서 찍혔던 로그를 확인할 수 있다.
- Intermediate 폴더
첫 실행 시 생성되는 폴더
Visual Studio 프로젝트 파일, 컴파일된 오브젝트 파일, 애셋 레지스트리 파일 (분석을 위해 사용됨) 등
에디터가 잘 안 켜질 경우 Intermediate 폴더와 Saved 폴더를 백업 후 삭제한 다음 다시 시도해 볼 수 있다.
이 폴더들에 프로젝트의 사용자의 로컬과만 관련 있는 파일들이 존재하기 때문에 이 폴더들은 다른 사용자들과 공유되지 않기 떄문이다.
공유되는 폴더 및 파일은 Config, Cotent, Source, Uproject 파일, (필요하다면 Binaries 및 커스텀 폴더를 추가 공유한다.)
보통 커스텀 폴더에는 Source Asset을 담는다. 이렇게 할 경우 다른 모든 사용자들에게도 상대 경로가 동일하기 때문에 아티스트가 애셋을 업데이트해도 reimport 할 필요가 없다.
- 플러그인 폴더
엔진 플러그인 폴더에 있는 플러그인들은 어느 프로젝트에서 사용 가능하다. 빌트 인 플러그인과 마켓에서 설치한 플러그인들이 위치해 있다. 커스텀 플러그인을 만든다면 프로젝트의 플러그인 폴더에 저장된다.
- UProject 파일
프로젝트를 정의하는 파일이다.
모듈 정의, 활성화된 플러그인 , Engine Association (엔진 버전) 정보를 포함한다.
Config는 계층적으로 오버라이딩 된다.
엔진 > 엔진 플랫폼 > 프로젝트 > 프로젝트 플랫폼 > 로컬
애셋을 관리하는 방법
애셋은 두 가지 방법으로 만들어진다.
1. 외부 DCC tool에서 Import
2. 에디터에서 직접 만들기
엔진에서 material을 텍스처로 굽는 거나 Modeling 툴을 사용하여 3D 메시를 생성하는 것도 애셋을 생성하는 방법 중 하나다.
애셋이 생성되면 asset Validation 플러그인이 애셋의 퀄리티를 보장하기 위해 사용된다. C++ 나 BP를 통해서 룰을 만들 수 있다. 예를 들면 네이밍 컨벤션, 텍스처 해상도, 메시 정점 수 등을 제한할 수 있다.
애셋은 모든 프로퍼티, 압축되지 않은 포맷의 Raw Data를 포함하는데, 이는 나중에 쿠깅 과정에서 타겟 플랫폼에 최적화된다.
- Derived Data Cache
현재 플랫폼에서 사용되는 애셋의 버전을 저장한다.
- Shared DDC
공유 폴더에 있는 맵을 최초로 열면 셰이더 컴파일, distance field와 같은 데이터가 생성되는데 공유 폴더에 저장되면 누군가 한 번만 실행하면 된다.
- Redirector
레퍼런스가 업데이트 되지 않았는데 옮겨진 애셋
다른 사용자가 레퍼런스 중인 애셋을 다른 곳으로 옮겼을 경우 기존 Path에 생성된다. 나중에 가능할 때 Redirector를 Fix 하면 된다.
Primary Asset과 Secondary Asset
Primary Asset은 AssetManager에 의해 관리된다.
사용자는 커스텀 Primary Asset type을 정의하고 AssetManager가 그것을 인식하게 할 수 있다.
Primary Asset은 Secondary Asset들의 로드를 관리한다.
Level은 Primary Asset이다. 레벨에 존재하는 모든 액터 (Secondary Asset)의 로드를 관리한다.
Tool
- Session Frontend 툴
Tool 메뉴에서 액세스하거나 독립형 애플리케이션으로 실행 가능하다.
PC나 네트워크로 연결된 장치에서 실행되는 게임에 연결할 수 있다.
내부 기능 :
Automated Testing
Console
legacy Profiler
- Device Output Log, Device Manager
연결된 장치의 로그 출력, 실행 관리
- Unreal Insights
Session Frontend 내부에 있던 나머지 기능들이 이것으로 대체됨
에디터 툴 메뉴에서 실행된다.
이전 툴에 없던 추가적인 기능으로 모든 스레드에서 일어나는 이벤트를 자세하게 보여준다.
메모리 할당 및 각각의 네트워크 패킷을 분석할 수 있다.
빌드
Unreal Automation Tool에 의해 관리된다.
다양한 방법으로 빌드할 수 있다
1. basic packing 프로세스를 에디터에서 직접 진행할 수 있다.
2. Project Launcher를 사용하여 특수 빌드를 진행할 수 있다.
3. Command List를 사용하여 진행할 수 있다.
- Building
C++ 코드를 포함한 프로젝트는 바이너리 빌드부터 시작한다. 바이너리 빌드 시 빌드 설정이 필요하다. (타겟, State)
target : Standalone Game, Editor, Client, Dedicated Server
State : Debug, Development, Shipping
- Cooking
바이너리 빌드 한 후에는 Cooking 과정을 거친다.
애셋을 타겟 플랫폼에 최적화하는 작업이다.
1. Cook by the book : 모든 애셋을 쿠킹한다. 시간이 걸린다.
2. Cook on the fly : Cook process가 생략되고 Cook Server가 내 장치에서 실행되어 게임에서 애셋이 필요할 때 쿠킹된다. 로딩 시간이 길어지지만 반복 작업을 하는데 있어서는 효율적이다.
TSoftObjectPtr : 해당 경로를 통해 로드되거나 로드되지 않을 수 있는 개체를 참조하는데 사용된다.
로드되지 않더라도 다른 레벨에 있는 액터를 가리킬 수 있다. 특별한 목적을 위해서 메시와 같은 애셋을 비동기 로딩하는 함수에서 사용된다. 블루프린트에서의 Soft Object Reference 블루프린트 변수 타입과 같은 역할이다.
TSoftClassPtr : 해당 경로를 통해 로드되거나 로드되지 않을 수 있는 클래스를 참조하는데 사용된다.일단 로드되면 사용자는 이것을 이용해 인스턴스를 만들 수 있다. 이것들을 비동기로 로드하는 함수에서 사용된다. 블루프린트에서의 Soft Class Reference 블루프린트 변수 타입과 같은 역할이다.
TWeakObjectPtr : 이미 인스턴스화된 객체를 참조하는데 사용된다. 객체가 사라지거나 가비지 컬렉팅되는 경우 Null값을 가지게 된다.
❌ 이러한 포인터 유형을 사용하지 마십시오.
FSoftObjectPath: 다른 포인터 유형 에서 내부적으로 사용됩니다.결과를 캐시하지 않기 때문에 느립니다.에디터에서 설정하면 UBlueprintGeneratedClass 대신 UBlueprint 클래스를 가리킬 것인데, 이는 일반적으로 게임플레이 코드가 원하는 것이 아닙니다.하지만 Editor Plugins 제작자는 해당 기능을 원할 수 있습니다.
FSoftClassPath: FSoftObjectPath와 동일하지만 클래스 로딩과 관련된 일부 도우미 함수가 있습니다.지금은 대부분 레거시 유형입니다.
FSoftObjectPtr: TSoftObjectPtr의 비템플릿 및 비-BP 노출 버전입니다.
Weak Pointer vs Soft Pointer
Weak Pointer는 존재하는 UObject를 대상으로 만들어진다. 이 UObject는 GUObjectArray 인덱스에 의해 이미 만들어진 UObject이다.
Weak Pointer는 가리키는 대상이 가비지 컬렉팅 되었는지 알 필요가 없기 때문에 UPROPERTY로 지정하지 않아도 된다.
Soft Pointer는로드되거나 로드되지 않을 수 있는객체 또는 애셋에 대한 경로의 문자열 표현입니다.개체가 쿼리되고 발견된 후 개체를 추적하기 위해 추가 Weak Pointer를 내부에 저장합니다
Soft Pointer
FSoftObjectPath
게임플레이 코드용FSoftObjectPath변수를 직접 만들지 마세요.그들은 확인된 개체를 캐시하지 않으므로 모든 쿼리는 개체를 다시 검색합니다.또한 생성된 클래스( UBlueprintGeneratedClass, 경로 이름의"_C") 대신 블루프린트 클래스 애셋(UBlueprint) 을 가리킵니다 .UBlueprint는패키지 빌드에서 제거됩니다.TSoftObjectPtr또는TSoftClassPtr 을사용하십시오.
FSoftObjectPath는 모든 타입의 Soft 포인터에서 내부적으로 사용된다. 소프트 오브젝트 경로 변수는 블루프린트에서 생성할 수 있지만, 수행 중인 작업을 알고 있고 , UBlueprintGeneratedClass클래스를 가리키고 싶지 않으며캐싱이 필요하지 않은 에디터 유틸리티에서만 수행해야 한다.
블루프린트에서 사용하는 경우 개체 인스턴스가 아닌 디스크 상의 애셋만 선택할 수 있습니다.인스턴스를 가리키려면 TSoftObjectPtr 을사용하십시오
FSoftObjectPath는 템플릿이 아닙니다.애셋 유형으로 선택을 제한하려면MetaClassUProperty메타데이터를 사용할 수 있습니다 (또는해당 종류의 기능 대신TSoftClassPtr 사용).
개체를 resolve 할 때 해쉬를 사용해 검색한다. 일반 혹은 WeakPointer에 비해 약간의 오버헤드가 있다. 확장 클래스는 일반적으로 그것들을 캐시하므로 다시 검색할 때 한번 resolve하면 다시 검색하지 않는다.
FSoftClassPath
FSoftObjectPath와 거의 동일하지만 로딩 관련 헬퍼 함수를 갖고 있다. 대부분 오래된 시스템이기 때문에 직접 만들어 샤용하는 대신에 TSoftClassPtr을 사용하자
FSoftObjectPtr
소프트 개체 및 클래스 포인터의 기본 클래스입니다.내부적으로오브젝트를 찾기 위한FSoftObjectPath와 찾은 후 캐싱하기 위한FWeakObjectPtr을 유지합니다.
많은 기능이 있는TPersistentObjectPtr을확장합니다 .
USTRUCT가아니므로 블루프린트에서는 사용할 수 없으며 C++에서만 사용할 수 있습니다.
TSoftObjectPtr또는TSoftClassPtr의 두 가지 확장 유형이 있습니다. 이 유형은 각각 개체 인스턴스 또는 애셋(CDO)을 가리키는 템플릿, 블루프린트에 Visible 되는 방식을 제공합니다. 이것들이 대신 사용되어야 한다.
Get()을호출하면기본 클래스에서 호출하여 내부WeakPtr이이전에 캐시되었는지(비 PIE 세션에서) 먼저 확인하고, 그렇지 않으면FSoftObjectPath.ResolveObject를호출하여 객체를 찾습니다.
TSoftObjectPtr
FSoftObjectPtr의 템플릿화된 Wrapper 이다. 블루프린트에서 사용될 수 있다.
경로 이름이 있는 모든 항목을 가리키는 데 사용할 수 있습니다.디스크에 있는 애셋이든 레벨에 있는 개체든 로드되지 않을 수 있는 항목을 가리키는 데 가장 적합합니다.
액터가 현재 로드되지 않은 다른 레벨에 있어도 경로 값을 유지한다.
이미 인스턴스화된 액터를 참조하려면 TSoftObjectPtr 대신TWeakObjectPtr을사용하십시오.
기본값은 블루프린트 타입으로 설정할 수 없습니다 (블루프린트 타입을 사용하려면TSoftClassPtr 사용).하지만 Data Assets을 가리킬 수 있습니다.
이 값은 로드된 액터를 선택하여 인스턴스 Detail 창에서 설정하거나 현재 열려 있는 맵의 액터에 대한 Class Defaults에서 설정할 수 있습니다.
가리키는 객체가 로드되지 않았을 때 Get()이 호출되면nullptr을반환합니다 .일단 로드되면 일치하는 전체 이름을 가진 액터를 반환하고 미래의 쿼리를 위해 캐시합니다.
TSoftClassPtr
TSubclassOf처럼 작동하는FSoftObjectPtr주변의 템플릿 래퍼로 , 블루프린트 서브클래스용UProperties에서 사용할 수 있습니다.
로드 여부를 쿼리할 수 있는 블루프린트 유형(UBlueprintGeneratedClass) 을 가리키는 데 사용됩니다 .클래스를 비동기적으로(또는 동기적으로, 장애가 발생하더라도) 로드하는 데 사용할 수도 있습니다.
DataAssets는 인스턴스화하면 안 되므로 DataAsset에 대해서는 작동하지 않는다. 이것들에 대해서는 TSoftObjectPtr을대신 사용해야 한다.
WeakPointers
소프트 포인터처럼 경로를 저장하지 않고, 이미 인스턴스화된 개체에 대해서 참조만 한다.
weak pointer는 int32 ObjectIndex와 int32 ObjectSerialNumber 두 값만 저장한다.
Get을 호출하면 먼저 ObjectIndex를사용하여GUObjectArray에서 객체를 가져옵니다 (존재하는 경우).
"하지만 ObjectIndex는 32비트에 불과합니다. 액터를 계속 생성하고 제거하면 쉽게 숫자가 부족하지 않습니까? "훌륭한 질문입니다. 예, 이론적으로는 그럴 수 있지만 항상 기껏해야 수십만 개의 객체만 살아 있기 때문에 해당 인덱스가 재사용됩니다.
그 때문에인덱스 재사용의 경우 우리가 원하는 개체인지 확인하기 위해ObjectSerialNumber가 있습니다.ObjectSerialNumber는 Weak 포인터가UObject 를처음 가리킬 때만 할당되며, 그렇지 않으면 0입니다.스레드 안전 증분 int32카운터 입니다.
" 일련번호가 다 떨어지면 어떻게 됩니까? " 그것은 게임에 크래시를 일으킨다. 즉 , 일련 번호가 소진되기 전에 최대 2,147,483,647개의 고유UObject에 대한 새로운 약한 포인터를 만들 수 있습니다 .대부분의 사용 사례에는 충분하지만 매우 오래 실행되는 프로세스 또는 약한 포인터의 이상한 사용을 고려하십시오.
일련 번호를 비교한 후 최종적으로 UObjectIsValid() 가아닌지 확인하고, 그렇지 않으면(PendingKill의 경우 )null 을반환하고 , 그렇지 않으면 객체를 반환합니다.이 때문에 약한 포인터를 역참조하면 항상 유효한UObject또는 그렇지 않은 경우nullptr이반환된다는 것을 확신할 수 있습니다 .
모든델리게이트는AddUObject/BindUObject함수를 사용할 때Weak Pointer를통해UObject에 대한 참조를 유지하므로파괴 중 구독 취소에 대한 걱정 없이 델리게이트를 안전하게 구독할 수 있습니다.이는 관리되지 않는 C++ 포인터를 사용하는AddRaw/BindRaw 함수를 사용하는 것과는 반대이므로UObject 를다룰 때 이를 신중하게 다루고 전혀 사용하지 않으려고 합니다 .
UObject가 아닌 C++ 클래스의 멤버함수를 등록하는 경우에는 AddRaw / BindRaw 사용
요약
요약하자면,약한 포인터는역참조할 때 약간의 오버헤드가 있는UObject를가리키는 훌륭하고 안전한 방법입니다 .결국 그렇게 약하지 않습니다!UObject가져오기 및 유효성 검사의 모든 내부를 처리하기 때문에UPROPERTY일 필요도 없습니다.
FWeakObjectPtr
메모리의 UObject에 대한 약한 포인터입니다.USTRUCT가아니므로 블루프린트에서 사용할 수 없습니다. C++에서만 가능합니다.
TWeakObjectPtr의 Base 클래스입니다 .
TWeakObjectPtr
일반FWeakObjectPtr의 템플릿 버전입니다.블루프린트에서 사용할 수 있지만 C++에서 선언해야 합니다.
개체의 문자열 표현을 내부적으로 사용하지 않더라도인스턴스 Detail 창(Class Defaults 말고) 에서 값을 설정할 수 있습니다 .
문자열 경로를 사용하지 않기 때문에 애셋을 찾는 오버헤드를 건너뛰지만 이미 인스턴스화된 개체로만 설정할 수 있습니다.
C++에서는 인스턴스화된 UObject 가어느 레벨에 있든 상관없이 이미 로드되어 있는 한 가리킬 수 있습니다 .