카테고리 없음

2025.07.02 13주차 수요일

mochoa 2025. 7. 2. 20:48

 

1. 문제 발견

  • DefaultInventory.Start() → InsertPossible 또는 RemainderIfInserted 호출 시 NullReferenceException 발생
  • 오류가 ItemSlotWithProcessor 내부의 insertionProcessors 리스트 중 null 요소를 건드릴 때 터짐
  • 콘솔 로그로 확인해 보니, ConstraintCollection.Constraints 의 0번 인덱스에 빈(삭제되지 않은) 슬롯(null)이 남아 있었음

2. 디버깅 과정

  1. InitSlot()에 Debug.Log 추가
    • ConstraintCollection.Constraints 리스트 길이와 각 요소 타입(또는 null)을 출력
    • 로그 결과 
Constraints[0] = NULL  
Constraints[1] = MaxCapacityConstraint  
Constraints[2] = InstancesOnlyConstraint
  1. ItemSlotWithProcessor InsertPossible / RemainderIfInserted
    • 내부 반복문에 null 체크 로그 삽입
    • 어느 인덱스에서 null이 들어오는지 정확히 파악

3. 해결 방법

  1. Inspector 에셋 정리
    • InstantiateConstraint.asset·StandardSlotConstraints.asset 의 Constraints 리스트에서
      • “Missing (Mono Script)” 또는 빈 슬롯을 완전히 Remove Element
      • 순서대로 MaxCapacityConstraint, InstancesOnlyConstraint 등 올바르게 연결
  2. 코드 레벨 안전 처리
    • 이렇게 하면 런타임에 null이 섞이지 않아 이후 InsertPossible·RemainderIfInserted에서 더 이상 예외가 발생하지 않음
void InitSlot()
{
    if (ConstraintCollection)
        constraints.AddRange(
            ConstraintCollection.Constraints
                .Where(c => c != null)    // null 요소 필터링
        );
    slot = new ItemSlotWithProcessor(constraints, World);
    slot.Changed += FireChange;
}

4. 배운 점

  • Unity Asset 직렬화: ScriptableObject(Prefab) 안에 남아 있는 “Missing” 슬롯이 런타임 로직에 치명적인 null을 유발
  • 디버깅 팁: 컬렉션 상태를 런타임에 직접 찍어 보는 것이 문제 파악에 유용
  • IEnumerable 안전 처리: AddRange(...Where(...)) 패턴으로 null 항목을 사전에 차단
  • 에셋 vs 코드: 가능한 한 에셋(Inspector)에서 올바르게 연결하고, 코드에서는 최소한의 방어 로직만 두는 것이 깔끔함

다음에 적용할 점

  • Asset 변경 시 에디터 경고(Missing types)를 즉시 해결하기
  • 초기화 로직에 null 필터링 습관 들이기
  • 중요한 로직(Insert/Remainder) 앞뒤로 작은 단위 디버깅 로그 활용하기