소프트 참조가 패키징에서만 nullptr이 될 때
에디터에선 잘 뜨던 UI가 패키징 빌드에선 안 뜬다. 로그도 조용하다.LoadSynchronous()가 에러 없이 nullptr을 돌려주기 때문이다. 이건 거의 항상 소프트 참조 에셋이 쿡에서 빠졌다는 신호다. 나는 이걸 세 번 반복하고 나서야 규칙으로 못 박았다.
원인 — 하드 참조 체인이 없으면 쿠커가 그 폴더에 안 간다
TSoftClassPtr나 LoadClass에 넘기는 경로 문자열은 하드 참조 체인이 없다.쿠커는 참조 그래프를 따라가며 쿡할 에셋을 정하는데, 소프트 참조만 걸린 디렉터리는 그 그래프에 안 잡혀 통째로 누락된다. 에디터에선 원본 에셋이 다 있으니 멀쩡하고, Shipping 패키지에서만 조용히 실패한다. 증상이 ‘조용한 nullptr’이라 원인 찾기가 더 오래 걸린다.
해결 — 두 겹으로 막는다
첫째, DefaultGame.ini에 소프트 참조가 사는 디렉터리를 명시적으로 쿡 대상에 넣는다.
; DefaultGame.ini
+DirectoriesToAlwaysCook=(Path="/Game/Retrieve/UI/Menu")
+DirectoriesToAlwaysCook=(Path="/Game/Retrieve/UI/Settings")둘째, 프로퍼티 지정을 깜빡한 경우까지 대비해 코드 폴백을 둔다.
TSubclassOf<URetrieveGamePanelWidget> PanelClass = PauseMenuClass.LoadSynchronous();
if (!PanelClass)
{
PanelClass = LoadClass<URetrieveGamePanelWidget>(
nullptr, TEXT("/Game/Retrieve/UI/Menu/WBP_PauseMenu.WBP_PauseMenu_C"));
}그리고 검증은 실제 산출물로 한다. 메모리상의 CDO 상태는 착각을 부른다.Saved/Cooked/ 출력 폴더를 직접 열어 그 에셋이 실제로 쿡됐는지 확인한다.
배운 점
이 패턴은 조준선 텍스처, 획득 토스트, UI 패널에서 세 번 반복됐다. 그래서 지금은 규칙이다 — 소프트 참조를 커밋할 때는 DirectoriesToAlwaysCook 검토가 필수.
패키지에서의 조용한 실패는 시그니처 증상이다. 에디터에서 멀쩡한데 패키지에서만 안 되고 로그도 없다면, 하드 참조가 없는 소프트 로드를 먼저 의심한다.
always-cook 폴더를 넣을 때 주의할 게 하나 있다. 그 폴더에 깨진 잔재(예전 테스트·임시 에셋)가 섞여 있으면 강제 로드가 도리어 쿠킹 크래시를 부른다. 폴더는 깔끔하게 관리한 상태로만 강제해야 한다.