TIL - 트러블 슈팅

Kyu_·어제

32주차

목록 보기
2/3

트러블슈팅 기록


1. WBP_PartPanel 컴파일 에러 — SlotButtonContainer not found

증상
WBP_PartPanel을 열면 "SlotButtonContainer를 찾을 수 없습니다" 컴파일 에러.

원인
NSPartPanelWidget.hBindWidget으로 선언된 SlotButtonContainer(UPanelWidget)가 WBP 디자이너에 존재하지 않았음.

수정
WBP_PartPanel 디자이너에 WrapBox를 추가하고 이름을 SlotButtonContainer로 지정.

선택 이유
BindWidget은 WBP에 정확히 같은 이름의 위젯이 있어야 컴파일을 통과한다. 이름 불일치가 유일한 원인이므로 코드 수정 없이 WBP에서 해결.


2. SlotButtonTemplate이 Details 패널에서 안 보임

증상
WBP_PartPanel을 선택하고 Details 패널에서 SlotButtonTemplate을 검색해도 나오지 않음.

원인
SlotButtonTemplateUPROPERTY(EditDefaultsOnly)로 선언되어 있어 Designer 탭 Details가 아니라 Graph 탭 Class Defaults에만 노출됨.

수정
Graph 탭 → Class Defaults에서 SlotButtonTemplate에 WBP_PartsButton 지정.

선택 이유
EditDefaultsOnly는 인스턴스별 수정이 필요 없는 클래스 수준 설정에 쓰는 지정자. 슬롯 버튼 템플릿은 모든 인스턴스가 같은 WBP를 공유하므로 설계가 맞고, 코드 변경 없이 에디터 탐색 경로를 바꿔 해결.


3. Tab 키를 눌러도 파츠 패널이 반응하지 않음

증상
인런에서 Tab을 눌러도 파츠 슬롯이 표시되지 않고 아무 반응 없음.

원인
Tab → Input.Augment.TogglePanel 태그 → ToggleAugmentationPanel() 함수가 내부에서 IsRunReady() 상태를 확인하는 구조. OutGame(HideOut 맵)에서 테스트했기 때문에 조건이 false여서 아무것도 실행되지 않았음.

수정
인런 맵에서 테스트.

선택 이유
조건 자체가 올바른 설계(인런에서만 파츠 패널 토글 허용). 구현 버그가 아니라 테스트 환경 오류였으므로 코드 수정 없음.


4. 인런에서 Tab을 눌러도 슬롯 버튼이 나타나지 않음 (타이밍 문제)

증상
인런에서 Tab을 누르면 패널 자체는 뜨지만 Arm / Leg / Body 슬롯 버튼이 비어 있음.

원인 (1단계)
UNSPartPanelWidget::NativeConstruct()에서 BuildSlotButtons()를 호출하는데, 이 시점에 CachedSlotRowsBySlot이 비어 있어 버튼이 생성되지 않았음.

원인 (2단계)
CachedSlotRowsBySlot이 비어 있는 이유는 BuildSlotRowCache()OnOutGameAssetsLoaded() 안에서만 호출되는데, PartSlotTableOnOutGamePrimaryAssetsLoaded()의 비동기 로드 목록에 포함되지 않아 DT 자체가 메모리에 없었음.

원인 (3단계, 근본 원인)
LoadOutGameData()가 HideOut 맵 진입 핸들러에서 호출되지 않고 있었음. OutGame 데이터 로딩 자체가 시작되지 않아 이후 모든 단계가 동작하지 않았음.

수정

// NSPlayerController.cpp — HideOut 맵 핸들러
if (UNSDataSubsystem* DataSubsystem = UNSDataSubsystem::Get(this))
{
    DataSubsystem->LoadOutGameData();  // ← 추가
    ...
}
// NSDataSubsystem.cpp — OnOutGamePrimaryAssetsLoaded
// PartSlotTable을 비동기 로드 목록에 추가
if (!Settings->PartSlotTable.IsNull() && Settings->PartSlotTable.Get() == nullptr)
    PendingLoads.Add(Settings->PartSlotTable.ToSoftObjectPath());
// NSDataSubsystem.cpp — OnOutGameAssetsLoaded
void UNSDataSubsystem::OnOutGameAssetsLoaded()
{
    BuildPartRowCache();
    BuildSlotRowCache();  // ← 추가
    SetPhase(ENSDataLoadPhase::OutGameReady);
    OnOutGameDataReady.Broadcast();
}
// NSPartPanelWidget.cpp — NativeConstruct (타이밍 대응)
if (!DataSS->GetAllSlotRows().IsEmpty())
{
    BuildSlotButtons();
    ...
}
else
{
    // 아직 로드 전이면 완료 델리게이트 구독
    DataSS->OnOutGameDataReady.AddDynamic(this, &UNSPartPanelWidget::OnOutGameDataReady);
}

선택 이유

  • LoadOutGameData() 미호출은 단순 누락이므로 있어야 할 자리(HideOut 핸들러의 DataSubsystem 블록)에 추가.
  • PartSlotTable 누락도 동일한 이유로 PartDefinitionTable과 같은 방식으로 추가.
  • NativeConstruct 타이밍 문제는 "데이터가 준비됐으면 즉시, 아니면 델리게이트 구독 후 콜백"으로 처리. 위젯 생성 시점과 데이터 준비 시점이 보장되지 않는 구조에서 표준적인 패턴.
  • NativeDestruct에서 RemoveDynamic으로 구독 해제하여 위젯 파괴 후 콜백 호출 방지.

요약 — 디버깅 순서와 실제 원인 계층

Tab 눌러도 슬롯 안 나옴
  └─ BuildSlotButtons()에서 슬롯 데이터가 비어 있음
       └─ BuildSlotRowCache()가 실행되지 않았음
            └─ PartSlotTable이 로드되지 않았음
                 └─ LoadOutGameData()가 호출되지 않았음  ← 근본 원인

증상은 UI에서 보였지만 원인은 PlayerController의 맵 전환 핸들러에 있었음.
데이터 로드 → 캐시 빌드 → 위젯 구독 → UI 반영으로 이어지는 의존 체인 전체를 역추적해야 찾을 수 있는 유형의 버그.

0개의 댓글