언리얼 엔진 소스 4.27.2를 받아다가 컴파일을 할 일이 생겼다.

엔진 소스를 깃허브에서 받고, 맨 먼저 Setup.bat를 한번 실행해줘야 하는 데 다음과 같은 에러가 떴다.

Failed to download 'http://cdn.unrealengine.com/dependencies/2605550-2722e8035d7444a18952cbd04a5c58c7/0104416c142ca7b3174660267c22f049db573bdb': 원격 서버에서 (403) 사용할 수 없음 오류를 반환했습니다. (WebException)

 

Setup.bat를 실행 시 깃허브에 접근해서 필요한 파일을 다운로드하게 되어 있는데, 그새 저장소 경로가 바뀌어서 생기는 문제일 걸로 보인다.

 

해결방법은 Commit.gitdeps.xml 파일을 최신 버전으로 다시 받는 것이다.

https://github.com/EpicGames/UnrealEngine/releases/download/{엔진버전}-release/Commit.gitdeps.xml 

 

위와 같은 경로인데, 지금 내가 필요한 버전은 4.27.2이므로, 다음의 경로에서 파일을 받으면 된다.

https://github.com/EpicGames/UnrealEngine/releases/download/4.27.2-release/Commit.gitdeps.xml

 

 

받은 파일은 다음의 위치에 넣어 주면 된다.

{엔진 소스 폴더}\Engine\Build\Commit.gitdeps.xml

 

 

참고 링크: https://forums.unrealengine.com/t/unable-to-build-4-27-from-source-setup-bat-403-forbidden-error/1156805/9

언리얼 엔진 최신 버전(5.4.2)을 비주얼 스튜디오 최신 버전 (2022)으로 컴파일하려고 하니 다음과 같은 경고가 뜬다.

Visual Studio 2022 compiler version 14.40.33811 is not a preferred version. Please use the latest preferred version 14.38.33130

 

그리고, 이상한 곳에서 컴파일 에러도 뜬다.

...Engine\Source\Runtime\Core\Public\Templates\SharedPointer.h(1092) : error C4702: unreachable code

 

검색을 해 보니, 언리얼 엔진 최신 버전과 비주얼 스튜디오 최신 버전간 호환성 문제가 있다고 한다.

비주얼 스튜디오 인스톨러에서 14.38에 해당되는 툴체인을 설치하면 해결된다.

정확히 뭐가 필요한 지 몰라서 14.38로 검색되는 걸 일단 다 설치해 보니 문제가 해결되었다.

일반적으로 많이 사용하는 Actor나 ActorComponent가 아니라, 간혹 Object를 바로 상속받거나 LocalPlayerSubsystem 같은 클래스를 상속받은 BP 클래스를 만들어서 사용해야 할 때가 있다. 그런데, 그렇게 상속받은 클래스에서 BlueprintFunctionLibrary에 정의된 함수를 호출하려고 하면 잘 안된다. 에디터에서 마우스 오른쪽을 눌러 다른 BP 함수 라이브러리의 함수를 찾아도 아예 보이지가 않는다.

 

정확한 원인은 잘 모르겠지만, BlueprintFunctionLibrary 함수를 호출할 때는 호출하려는 클래스의 GetWorld 함수 접근이 필요한데, Actor나 ActorComponent의 경우 해당 함수가 에디터에서도 접근할 수 있게 노출되어 있지만, UObject나 Subsystem 계통의 클래스들은 그게 안되어 있어서 생긴 문제로 보인다.

 

그래서, BP 클래스를 만들기 전에 부모 클래스를 c++로 만들고, Blueprintable 속성을 넣어주고, GetWorld 함수를 오버라이드하면 해결이 된다.

// MyGameSoundSubsystem.h
UCLASS(Blueprintable)
class MYGAME_API UMyGameSoundSubsystem : public ULocalPlayerSubsystem
{
    GENERATED_BODY()

public:
    virtual UWorld* GetWorld() const override;
//...
};
  
  
// MyGameSoundSubsystem.cpp
UWorld* UMyGameSoundSubsystem::GetWorld() const
{
#if WITH_EDITOR
    if (IsTemplate())
    {
        return nullptr;
    }
#endif

    return Super::GetWorld();
}

가장 간단한 방법은 위의 코드처럼 cpp 함수의 구현부에서 그냥 부모 함수만 호출해도 되긴 하는데, 에디터에서는 뭔가 또 다르게 작동하는 게 있어서 예외처리는 필요하다.

 

항상 위의 코드처럼 작성해야 하는 건 아니고 경우에 따라서는 부모 클래스나 Outer 클래스를 참조해야 할 필요도 있고, WorldContext를 명시적으로 노출해서 사용해야 하는 경우도 있다.

 

코드 출처: https://forums.unrealengine.com/t/can-you-use-a-blueprint-function-library-in-an-object-class/350918/31

 

ps. 일반적으로 Actor나 ActorComponent는 현재 맵(Level)의 월드에 귀속되지만, UObject를 상속받은 클래스 혹은 Subsystem 클래스들은 싱글턴처럼 쓰이는 경우가 많고, 현재 월드가 아닌 다른 월드(엔진 기본 월드?)에 귀속되어 있을 수 있다.

UGameInstanceSubsystem을 상속받은 c++ 클래스는 싱글턴처럼 하나만 생성되는 게 원칙이다.

UCLASS()
class MYGAME_API UMySubsystem : public UGameInstanceSubsystem
{
	GENERATED_BODY()
	...
};

 

서브 시스템을 가져다 쓸 때는 클래스 타입으로 검색해서 사용한다.

GetGameInstance()->GetSubsystem<UMySubsystem>()

 

그런데, 만약 c++ 클래스를 상속 받은 블루프린트 클래스를 만들어서 그걸 사용하고 싶다면 어떻게 해야 하는지 궁금해졌다. 검색해서 알아낸 방법은 다음과 같다.

 

먼저, c++의 서브시스템을 블루프린트에서 상속 받을 수 있게 Blueprintable 속성을 추가하고, ShouldCreateSubsystem 함수를 오버라이드해서 c++ 클래스의 생성은 막고 블루프린트 클래스만 생성할 수 있게 한다.

// MySubsystem.h
UCLASS(Blueprintable)
class MYGAME_API UMySubsystem : public UGameInstanceSubsystem
{
	GENERATED_BODY()
	
public:
	virtual bool ShouldCreateSubsystem(UObject* Outer) const override;
    ...
};

// MySubsystem.cpp
bool UMySubsystem::ShouldCreateSubsystem(UObject* Outer) const
{
    TArray<UClass*> ChildClasses;
    GetDerivedClasses(GetClass(), ChildClasses, false);
    return (ChildClasses.Num() == 0); // 최종 자식 클래스만 생성
}

 

에디터를 실행해서 MySubsystem을 상속 받는 BP_MySubsystem이라는 블루프린트 클래스를 생성한다.

 

일단 이렇게만 해도 에디터 플레이에서는 잘 작동한다.

 

하지만, 패키징 단계에서 해당 블루프린트 클래스에 대한 참조가 없으면 누락될 수 있으니, GameInstance에서 클래스 참조를 넣어 두자.

UCLASS(BlueprintType, Blueprintable)
class MYGAME_API UMyGameInstance : public UGameInstance
{
	GENERATED_BODY()

public:
	UPROPERTY(EditAnywhere, BlueprintReadOnly) 
	TSubclassOf<UMySubsystem> MySubsystemClass;

변수 선언은 위와 같이 하고, UMyGameInstance를 상속받은 블루프린트 클래스(예: BP_MyGameInstance)에서 MySubsystemClass 변수값에 BP_MySubsystem를 지정해 두도록 하자.

UE4Game.Target.cs 파일에 다음의 코드를 추가한다.

if (Target.Configuration == UnrealTargetConfiguration.Shipping || Target.Configuration == UnrealTargetConfiguration.Test)
{
  bAllowGeneratedIniWhenCooked = false;
  bAllowNonUFSIniWhenCooked = false;
}

엔진을 빌드한다.

이후, 게임 프로젝트의 *.Target.cs 파일에도 동일한 코드를 넣는다.

 

위의 코드를 넣어주면, 게임 구동시 [게임명]/Saved/Config/[빌드설정]/Config 폴더에 ini 파일을 쓰지도 않고, 읽지도 않는다. 단, GameUserSettings.ini 파일은 여전히 읽고 쓴다.

 

[부작용]

게임 옵션에서 인풋액션 설정을 Input.ini 파일을 통해서 저장하고 있었다면, 해당 기능을 더 이상 쓸 수 없다.

그런 경우, GameUserSettings.ini 파일을 이용하도록 코드를 수정하면 된다.

혹은, 엔진 수정을 통해 Input.ini 파일도 예외로 추가할 수도 있겠다.

4.26 기준.

 

1.Diff 후 BP 컴파일 에러

소스 컨트롤과 Diff를 하고 난 이후 게임을 컴파일하면 느닷없이 컴파일 에러가 뜰 때가 있음.

자세히 보면 에러나 블루프린트(BP) 파일에 temp 어쩌고 하는 이름이 들어 있음.

Diff를 할 때 임시로 생성한 예전 BP파일을 컴파일하려다가 오류가 발생하는 걸로 보임.

 

대처법: 에디터를 껐다가 다시 켠다.

 

2.BP 컴파일 도중 검색하면 에디터 먹통

Find in blutprints에서 뭘 찾고 있는 동안 BP를 컴파일하면 에디터가 간혹 먹통이 된다.

 

대처법: 작업 관리자에서 에디터를 강제로 종료하고 다시 켠다.

 

3.PIE 도중 검색하면 에디터 먹통

에디터에서 게임을 플레이(PIE)하는 도중에 Find in blutprints에서 뭘 찾으면 간혹 에디터가 먹통이 된다.

 

대처법: 작업 관리자에서 에디터를 강제로 종료하고 다시 켠다.

UDataAsset을 상속 받아서 만든 클래스에

TArray<enum> 으로 정의된 멤버를 추가했다.

 

enum 에 들어간 내용은 enum class 이름 : uint8 이었다.

그런데, 파일로 저장하니 배열의 사이즈 * 8 바이트의 사이즈로 저장된다.

 

배열의 사이즈가 작으면 별 문제가 안될 수 있으나, 내가 만든 데이터 에셋은 4096*4096 사이즈이다.

즉, 원래는 16MB 정도면 충분한데, 130MB로 저장되었다.

 

혹시나 싶어 TArray<uint8>로 변환해서 저장하니 16MB가 나왔다.

 

좀 알아보니, 언리얼에서는 enum 타입을 저장하면 메타데이터 같은 걸 같이 저장하기 때문에 용량이 커진다고 한다.

그래서 대량의 데이터를 저장할 때는 enum 그대로 저장하는 것 보다는 기본 타입으로 변형해서 저장하는 게 좋다.

 

 

 

 

TArray(배열)에서 아이템 제거해야 되는 경우,

원래는 RemoveAt(위치 인덱스) 사용한다.

이때 내부적으로는 memcpy가 호출되고, 따라서 나머지 항목들의 순서는 유지된다.

 

하지만, 굉장히 많은 항목을 반복적으로 제거해야 되고,

항목들의 순서가 중요하지 않거나 혹은 후처리로 따로 정렬을 해도 되는 경우라면,

RemoveAtSwap을 쓰는 게 낫다.

 

나머지 항목을 전체를 옮기지 않고, 배열의 맨 마지막 항목만 지우려는 위치로 복사한다.

참고 링크 : https://docs.unrealengine.com/4.26/ko/ProgrammingAndScripting/ProgrammingWithCPP/UnrealArchitecture/TArrays/

DefaultEngine.ini 파일에서 다음과 같이 추가한다.

 

[Core.Log]

Log[카테고리이름]=Verbose

UE4Editor-Cmd.exe를 실행할 때 -waitforattach 옵션을 추가해서 실행한다.

이후에 비주얼 스튜디오에서 UE4Editor-CMD 프로세스를 찾아서 어태치를 한다.

+ Recent posts