모딩/마인크래프트 모드 개발 일지

[마인크래프트 모딩] #5 주민 AI가 단체로 파업한 이유

kimchangmin02 2025. 6. 24. 22:32

모드를 만들다 보면 꼭 한 놈만 말을 듣고 나머지는 단체로 파업하는 경우가 있음. 내 모드가 딱 그 짝이었음. 튼튼한 '탱커' 주민만 잘 싸우고, 힐러, 궁수, 전사는 그냥 멀뚱멀뚱 구경만 함. 로그엔 에러도 안 찍힘. 대체 뭐가 문제였을까? 기나긴 삽질의 기록을 시작함.

 

사건의 발단: 왜 너만 일하냐, 탱커!

내 모드의 핵심은 직업별로 특별한 AI를 가진 주민 용사들임. 근데 탱커(갑옷 대장장이)만 제 역할을 하고 나머지는 그냥 바닐라 주민이었음.

결론부터 말하면, AI를 심어주는 '선생님'의 꼼꼼함 차이 때문이었음.

  • 성공한 탱커 (꼼꼼한 선생님): 학생(주민)이 (1)학교에 처음 나타났을 때 그리고 (2)스스로 "저 갑옷 만들래요!" 하고 직업을 정했을 때, 두 번이나 찾아가서 "자, 이제 너는 탱커다!" 하고 AI 칩을 심어줌. 기회를 놓칠 리가 없음.
  • 실패한 나머지 (게으른 선생님): 학생이 (1)학교에 처음 나타났셔을 때 딱 한 번만 물어봄. 근데 대부분 학생은 처음엔 직업이 없는 '백수' 상태. "전 아직 아무것도 아닌데요?" 라는 대답을 듣고 그냥 가버림. 나중에 학생이 직업을 정해도 다시는 찾아오지 않음. 결국 AI 없는 평범한 주민으로 남게 됨.

▶ 해결: 모든 직업의 EventHandler(선생님)들이 탱커처럼 (1)스폰 시, (2)직업 획득 시 두 번의 기회를 갖도록 코드를 통일함. 이제 모든 주민이 제 역할을 찾기 시작함.



함정 카드 발동: 수많은 에러와의 전쟁

주민들이 일을 시작하나 싶었더니, 이번엔 온갖 에러가 터지기 시작함.

1. ClassCastException: "여긴 서버 세상인데, 왜 클라이언트 규칙을 들이대?"
커스텀 스포너를 설치하는 순간 게임이 터짐. 원인은 ClientLevel cannot be cast to ServerLevel.

  • 비유: 마인크래프트는 '눈에 보이는 세상(클라이언트)'과 '실제 규칙이 돌아가는 세상(서버)'으로 나뉨. 몹 스폰 같은 실제 규칙은 당연히 서버 세상에서 처리해야 함.
  • 내 실수: 클라이언트인지 서버인지 구분도 안 하고 "무조건 서버 규칙으로 처리해!" 라고 명령함. 당연히 눈에 보이는 세상 담당자는 "그게 뭔데요?" 하면서 게임을 터뜨림.
  • ▶ 해결: 코드가 실행되는 곳이 서버 세상일 때만 몹 스폰 로직이 돌아가도록 조건을 추가해줌.

 

2. IllegalArgumentException: "이력서에 없는 항목은 물어보지 마세요."
이번엔 전사 주민이 스킬을 쓰려다 게임이 터짐. 에러는 Can't find attribute minecraft:generic.attack_damage.

  • 비유: 바닐라 주민의 '이력서'에는 "체력", "이속" 항목은 있지만, 싸우질 않으니 "공격력" 항목이 아예 없음.
  • 내 실수: 전사 스킬 코드에서 주민에게 다짜고짜 "네 이력서에 적힌 공격력 값 좀 내놔!" 라고 물어봄.
  • 게임 반응: "이 이력서엔 그런 항목 없는데요? 잘못된 질문임!" 하고 시스템 전체를 멈춰버림.
  • ▶ 해결: 게임이 시작될 때 모든 주민의 이력서에 '공격력: 1.0' 이라는 항목을 기본으로 추가해주는 '법률'을 제정함. 이제 누가 물어봐도 당당히 대답할 수 있게 됨.

 

3. 자동 등록의 배신: "게시판을 잘 찾아갔어야지!"
코드를 깔끔하게 하려고 @Mod.EventBusSubscriber 라는 '자동 등록' 기능을 썼더니, 이번엔 아예 아무도 일을 안 함.

  • 비유: Forge에는 두 개의 공지 게시판이 있음.
    • MOD 버스: '게임 로딩 중'에만 공지가 올라오는 학술 동아리 게시판. (아이템/블록 등록 등)
    • FORGE 버스: '게임 플레이 중'에 일어나는 모든 일을 알리는 운동부 게시판. (공격, 상호작용 등)
  • 내 실수: 주민 AI 이벤트 핸들러(EventHandler) 파일에 어느 게시판으로 갈지 bus=... 설정을 안 적어줌. 얘네는 '운동부 게시판' 공지를 들어야 하는데, 기본값인 '학술 동아리 게시판' 앞에 멍하니 서 있었던 것.
  • ▶ 해결: 모든 이벤트 핸들러에 bus = Mod.EventBusSubscriber.Bus.FORGE 라는 주소를 정확히 적어줌. 제자리를 찾은 핸들러들이 드디어 공지를 듣고 일하기 시작함.

-----------------------------------------------------------------------------------------------------------------------------------------

좀비 스포너와 전사주민 추가함

 

 

 

 

------------------------------------------------------------------------------------------------------------------------------------

오늘의 교훈

  • 타이밍이 생명: 코드가 언제 실행되는지(스폰 시? 상호작용 시?) 명확히 아는 게 중요함.
  • 기본 스펙 확인: 없는 능력치를 달라고 하면 게임은 터질 뿐. 없으면 만들어주자.
  • 자동화의 함정: 편한 기능일수록 원리를 모르면 뒤통수 맞기 딱 좋음.

결국 하루 종일 삽질했지만, 덕분에 Forge의 이벤트 시스템과 자바의 깐깐함에 대해 많이 배운 하루였음. 이제 진짜 주민 용병단 만들러 가야지.