
📋목차: 농부 AI 시스템 개발 및 최적화
1. 지능형 행동 제어 시스템 (AI Behavior & Priority)
- AI 우선순위 시스템 (GoalSelector): 절차적 방식이 아닌 상황별 우선순위(Panic > Deposit > Work > Idle)에 따른 유연한 행동 결정 원리
- 상태 기반 로직 전환: 매 틱(0.05초) 검사가 아닌 특정 이벤트(아이템 감지, 가방 가득 참 등) 발생 시에만 상태를 변경하여 부하 감소
- 인벤토리 관리 기준: 가방이 27칸 가득 찼을 때의 보관 로직과 씨앗 부족 시 보급을 위한 상자 방문 조건 정립
2. 창고(상자) 상호작용 및 효율화 (Storage Interaction)
- 상자 위치 캐싱(Caching): 주변을 매번 뒤지지 않고 최초 탐색한 상자 좌표를 기억하여 이동하는 검색 비용 최적화
- 상호작용 로직 세분화:
- 아이템 보관(Deposit) 및 보급(Withdraw) 프로세스
- 상자에서 씨앗을 가져올 때 전부가 아닌 '절반만' 가져오는 밸런스 조정
- 상자 열기 애니메이션 등 시각적 효과 적용
- 집 영역(Bounding Box) 인식: NBT 구조물의 크기 데이터를 읽어와 정확한 집 내부 영역에서만 상자를 스캔하는 정밀 탐색
3. 사회적 상호작용 및 협동 (Social Sharing & Reputation)
- 농부 간 씨앗 나누기: 씨앗이 없는 동료에게 자기 물량의 절반을 던져주는 협동 로직
- 무한 루프(Ping-Pong) 방지: 아이템 비행 속도와 AI 판단 속도 차이로 인한 중복 나눔을 막기 위한 쿨타임(Cooldown) 적용
- 주민 평판 및 소문(Gossip) 시스템: 주민들 간의 데이터 동기화(전파, 감쇠, 망각)를 통한 사회적 관계 메커니즘 분석
4. 서버 성능 최적화 및 안정화 (Performance & Stability)
- 중첩 루프 제거 (성능 100배 향상): FarmerHarvestGoal의 주변 블록 전수조사 로직을 단일 블록 검사 방식으로 변경하여 CPU 부하 획기적 단축
- 월드 저장 프리징 해결: 서버 종료 시 AI가 자원을 점유하여 발생하는 '세계 저장 중 멈춤' 현상을 방지하기 위한 강제 종료 및 쿨타임 로직
- 스캔 딜레이(Scan Delay) 도입: 구조물 생성 직후 서버 렉 상황을 고려하여, 생성 5~10초 후 상자를 탐색하도록 하는 안정화 장치
5. 시각적 요소 및 UI (Visuals & User Interface)
- 경험치 및 숙련도 표시: 농부 머리 위에 실시간으로 차오르는 경험치 바(Fill Bar) 및 레벨 정보 출력 (패킷 최적화 적용)
- 직업 가독성 강화: 일반 주민과 차별화되는 농부 전용 의상 적용 및 바이옴별 외형 대응
- 상태 피드백: 씨앗 투척 감지 및 농사 시작 시의 동작 연출
6. 고급 모딩 사례 연구 (Case Study: TekTopia)
- 중앙 집중식 마을 관리: 모든 주민이 각자 계산하지 않고 '마을 관리자(Town Hall)' 객체를 통해 작업을 할당받는 구조 분석
- 구조물 마커 시스템: 아이템 액자 등을 이용한 건물 용도 지정 및 영역 인식 알고리즘
- 부하 분산 기법: 수많은 엔티티의 AI 연산을 틱 단위로 쪼개어 실행하는 Task Throttling 전략 관찰
[ ]코드주고, 어떤점에서 성능저하 의심인지 물어볼수도
[ ]관리자용 검에 isAlly도 추가하기
[ ]나중에, 전투관련주민도 공통인터페이스 만든것처럼,
농부, 성직자등이 추가되면 그런거 추가해볼수도
[ ]단지 레벨만 표시하는게 아니라
숙련도에 따른 칭호:
- Lv.1: 초보 농부
- Lv.5: 숙련된 농부
- Lv.10: 농사의 달인
[ ]아니면, 뭔가 레벨업할때,
특정 빌드 선택하면, 레벨업 경험치량이 증가한다거나, 그렇게 할수도잇을것같은데
[ ]
성장하는 이름: 레벨이 낮을 때는 이름만 뜨다가, 레벨이 아주 높아지면 이름 앞에 수식어를 붙여줄 수도 있습니다. (예: "전설적인 농부 바나비")
[ ]
조건에 따라 행동하기
<먼소린지 잘 이해가 안가네
이게 if else나, 절차적이랑 다른점이 뭔지
뭔가 레벨업 시스템이나 거래관련
일단 이건 보류할까나, 괜히 패킷 이동 추가하면 어지러울수도,
[ ]서버에서 클라이언트로 패킷이동<이건 탐색보다는 성능에 안좋은 영향을 미치는건 아닌건가
그리고 레벨업을 추가할거면 레벨업에 따라, 뭔가 추가되는 무언가가 있어야 재미가 있을수잇는데
일단,
[ ]퇴비, 뼛가루 뿌리는 로직
[ ]레벨업 함에따라, 음, 더 다양한 작물 심을수있도록, (그러면 현재 뭘 심고, 수확할수잇는지도 알야겟는데
[ ]스스로 일반땅을 경작지로 만드는거<또 탐색부분이 나오는데
[ ]거래 시스템 활성화해서, 농산물 관련 가격 더 싸게 팔고, 비싸게 사드리는것도 할수도 ,
[ ok ]
상자에 담는부분부터 하면 되겟다
- 상자 위치 인식: 농부가 아이템을 보관할 '창고(상자)'가 어디 있는지 찾는 인공지능이 필요합니다.
- 아이템 보관(Deposit): 가방이 가득 찼거나 수확이 끝났을 때, 상자로 이동해서 가방 안의 작물을 상자로 옮겨 담는 로직이 필요합니다.
- 아이템 보급(Withdraw): 만약 가방에 씨앗이 떨어졌다면, 상자에서 씨앗만 골라 꺼내오는 로직이 필요합니다.
- 상자 열기 애니메이션: 상자와 상호작용할 때 상자가 실제로 열리거나 농부가 손을 흔드는 등의 시각적 효과가 추가되어야 자연스럽습니다.
[ ok ]주위 농부랑 씨앗 나누어주기 ㄴㄴ
상자 위치 '캐싱(Caching)' (검색 비용 줄이기)
농부가 상자를 찾을 때마다 주변 수십 칸을 뒤지는 건 성능에 아주 좋지 않습니다.
- 로직: 처음 생성될 때나 집으로 돌아왔을 때 상자의 위치를 딱 한 번 기억(저장)해둡니다.
- 효과: 상자에 갈 일이 생기면 머릿속에 저장된 좌표로 즉시 이동합니다. 상자를 새로 찾는 계산이 사라집니다.
[ ok ]
FarmerHarvestGoal의 성능 문제 (가장 심각)
MoveToBlockGoal을 상속받은 FarmerHarvestGoal의 isValidTarget 메서드 안에 중첩 루프가 있습니다.
- 문제: MoveToBlockGoal은 주변의 수백 개 블록을 매번 전수조사합니다. 그런데 그 조사 과정(isValidTarget) 안에 또 isHarvestableNearby라는 7x2x7(98개 블록) 루프가 들어있습니다.
- 결과: 농부가 한 번 주변을 살필 때마다 수만 번의 연산이 발생합니다. 농부가 여러 명이면 서버가 즉시 멈춥니다.
- 해결: isHarvestableNearby 체크를 삭제하거나, 아주 단순한 조건으로 변경해야 합니다.
[ ok ]
대충 농부옷만 좀 일반 주민이랑 차별되게 하면 될것같은데

오 일단, 씨앗 던져주면, 그거 감지해서, 농사시작하네
내가 씨앗이 없나?"를 매 틱(0.05초)마다 확인하는 게 아니라, 특정 사건이 터졌을 때만 상태를 바꿉니다.
좀비가 오면 처음부터 다시 시작하나요? (우선순위의 원리)
마인크래프트의 AI는 GoalSelector라는 시스템을 사용합니다. 각 행동(Goal)에 번호(우선순위)를 매겨두면, 매 순간 가장 중요한 일을 알아서 판단합니다.
- 번호가 낮은 것(0순위, 1순위)이 가장 중요합니다.
- 예시: 0: PanicGoal (도망), 1: HarvestGoal (수확), 2: GoToChestGoal (상자 가기)
- 농부가 상자로 가다가 좀비를 만나면, 마인크래프트 엔진이 자동으로 "상자 가기"를 중단하고 "도망"을 실행합니다. 좀비가 사라지면 다시 현재 상황에서 할 수 있는 가장 높은 순위의 행동을 선택합니다.
- 즉, "절차적"으로 짤 필요가 없고, 각 행동이 실행될 "조건"만 잘 주면 됩니다.
- 도망(Panic): 내 주변에 괴물이 있는가? (최우선)
- 보관(Deposit): 내 가방이 꽉 찼는가? -> 기억된 상자로 이동.
- 수확/심기(Work):
- 눈앞에 다 자란 작물이 있는가? -> 수확.
- 빈 땅이 있고 내 가방에 씨앗이 있는가? -> 심기.
- 보급(Withdraw):
- 가방에 씨앗이 없고 + 상자 확인 도장이 없는가? -> 기억된 상자로 이동.
- 휴식(Idle): 위 사항이 모두 해당 없으면? -> 집(상자 근처)에서 대기하거나 친구랑 씨앗 나누기.
1. 씨앗 나누기 로직 (절반 공유)
단순히 한 개를 주는 것보다 "전체 개수의 절반"을 주는 로직은 농부들 사이의 자원 균형을 맞추는 데 아주 좋습니다.
- 판단 기준:
- 농부 A(씨앗 0개)가 주변 5~10칸 이내의 농부 B를 스캔합니다.
- 농부 B가 가진 씨앗이 일정 개수(예: 2개 이상) 이상인지 확인합니다.
- 나누기 실행:
- 농부 B의 씨앗 개수를 체크합니다 (예: 10개).
- 계산: 10 / 2 = 5.
- 농부 B의 가방에서 씨앗 5개를 뺍니다.
- 농부 B가 농부 A의 방향을 쳐다보며 씨앗 5개 묶음을 아이템 형태로 바닥에 던집니다(ItemEntity).
- 결과:
- 농부 A는 이미 구현된 pickUpItem 기능 덕분에 바닥에 떨어진 5개의 씨앗을 자동으로 줍습니다.
- 두 농부는 이제 각각 5개씩 씨앗을 가진 상태가 되어 공평하게 일을 시작합니다.
2. 집안의 상자 위치 기억하기 (NBT 구조물 대응)
NBT 파일(구조물)로 집이 생성될 때, 상자의 위치는 매번 달라집니다. 하지만 "집이 스폰되는 순간 딱 한 번만 제대로 찾으면" 그 이후로는 절대 좌표를 기억할 수 있습니다.
[방법] '최초 탐색 및 고정' 방식
구조물로 집과 농부가 생성된 직후에 농부가 자신의 집(HomePos)을 기준으로 주변을 한 번만 수색하는 방식입니다.
- HomePos 기준 검색:
- 농부가 처음 스폰될 때 기억하는 homePos(집 위치)는 이미 코드에 있습니다.
- 스폰 직후(또는 첫날 아침), homePos로부터 반경 5~10칸 이내에 있는 Chest(상자) 블록을 검색합니다.
- 좌표 잠금(Locking):
- 상자를 발견하면 그 **절대 좌표(X, Y, Z)**를 농부의 메모리(chestPos)에 저장합니다.
- 이 좌표는 농부의 NBT 데이터에 함께 저장되므로, 서버를 껐다 켜도 농부는 "내 상자는 저기야"라고 계속 기억하게 됩니다.
- 상자가 없을 경우 (예외 처리):
- 만약 집 안에 상자가 없다면, 농부는 상자 없음 상태가 되어 상자 관련 AI를 아예 작동시키지 않습니다. (성능 최적화)
- 장점:
- NBT 구조물 파일 자체에 농부와 상자의 상대적 거리가 이미 정해져 있으므로, 농부가 태어나자마자 주변 10칸만 뒤지면 무조건 상자를 찾을 수 있습니다.
- 한 번 찾은 뒤에는 매번 상자를 찾기 위해 계산(Scan)할 필요 없이 저장된 좌표로 즉시 달려갑니다.
집의 크기가 가변적일 수 있다는 점을 고려하면, 5~10칸이라는 고정된 숫자는 확실히 한계가 있습니다. NBT 구조물(집)이 스폰될 때 그 집의 실제 크기(영역)를 먼저 파악하고, 그 안에서 상자를 찾는 방식이 훨씬 스마트합니다.
1. "내 집의 영역(Bounding Box)" 파악하기
NBT 구조물로 집이 생성될 때, 그 집은 보통 직육면체 공간(예: 가로 15, 세로 10, 세로 15)을 차지합니다. 농부가 스폰된 직후에 다음 로직을 실행합니다.
- 영역 설정: 농부가 스폰된 homePos를 중심으로, 해당 서버에서 허용하는 최대 집 크기(예: 32x32x32)를 검색 범위로 잡습니다.
- 구조물 블록 감지 (선택 사항): 농부가 주변을 훑으며 '공기'가 아닌 '집의 구성 요소(목재, 돌, 벽돌 등)'가 어디까지 퍼져 있는지 확인하여 실제 집의 경계선을 머릿속으로 그립니다.
2. 영역 내 상자 스캔 (최초 1회)
집의 영역이 파악되었다면, 이제 그 영역 내부 전체를 뒤져서 상자를 찾습니다.
- 우선순위 부여: 만약 영역 안에 상자가 여러 개 있다면?
- homePos(스폰 지점)에서 가장 가까운 상자.
- 또는, 내부에 씨앗이나 농작물이 이미 들어있는 상자.
- 좌표 고정: 찾은 상자의 위치를 TargetChestPos로 저장합니다. 이제부터 농부에게 "집에 가서 상자 열어"라는 명령은 곧 "저장된 TargetChestPos로 가라"는 뜻이 됩니다.
3. 집이 확장될 경우를 대비한 '재스캔' 로직
나중에 플레이어나 시스템이 집을 더 크게 확장하거나 상자 위치를 바꿀 수도 있습니다. 이를 위해 **'업데이트 트리거'**를 만듭니다.
- 정기 점검: 게임 시간으로 며칠에 한 번씩, 혹은 농부가 상자에 갔는데 상자가 파괴되어 없을 경우에만 다시 1번 로직(영역 스캔)을 실행합니다.
- 효과: 평소에는 저장된 좌표로만 다녀서 성능을 아끼고, 상황이 변했을 때만 똑똑하게 다시 상자를 찾습니다.
맞습니다! 사용자님 말씀대로 "받는 쪽이 씨앗이 0개일 때만" 이라는 조건이 확실하게 붙어 있다면, 이론적으로 두 농부가 씨앗을 테니스 공 치듯 무한히 주고받는 '무한 루프(Ping-Pong)' 문제는 거의 발생하지 않습니다.
하지만 컴퓨터 로직과 애니메이션 사이의 시차 때문에 발생할 수 있는 '다른 형태의 버그'가 있는데, 이를 방지하기 위해 아주 짧은 쿨타임이라도 있는 것이 안전합니다. 그 이유를 쉽게 설명해 드릴게요.
1. 아이템이 날아가는 시간 (가장 큰 이유)
농부 B가 씨앗 5개를 던졌다고 가정해 봅시다.
- 틱 1: 농부 B가 씨앗 5개를 제거하고 던졌습니다. (B는 5개, A는 아직 0개)
- 틱 2: 씨앗 아이템 엔티티가 공중을 날아가고 있습니다. (B는 5개, A는 여전히 0개)
- 틱 3: AI는 아주 빠르게 작동합니다. 농부 B는 다시 주변을 봅니다. "어? 저 친구(A)가 아직 씨앗이 0개네?"
- 틱 4: 농부 B가 남은 5개 중 또 절반을 뺍니다. (B는 2개, A는 아직도 0개)
즉, A가 아이템을 실제로 주워서 인벤토리에 숫자가 올라가기 전까지는 AI 눈에 A는 계속 "씨앗 0개인 가난한 친구"로 보입니다. 이 짧은 찰나에 농부 B가 자기 씨앗을 몽땅 다 던져버릴 수 있습니다.
2. "구걸"의 중복 방지
농부 A의 입장에서 씨앗이 0개가 되었을 때, 주변에 농부 B, C, D가 있다면 어떨까요?
- 0개인 상태에서 한꺼번에 B, C, D 모두에게 씨앗을 달라고 요청 신호를 보낼 수 있습니다.
- 그러면 B, C, D가 동시에 씨앗 보따리를 던져서 농부 A가 순식간에 씨앗 부자가 되고, 나머지 농부들은 텅텅 비어버리는 상황이 생길 수 있습니다.
3. 성능(Optimization) 측면
주변에 농부가 있는지, 그 농부의 인벤토리에 씨앗이 몇 개인지 계속 확인하는 작업은 서버 컴퓨터에 부담을 줍니다.
- "한 번 확인했으면 결과가 어떻든 5초는 쉬어라" 라는 식의 아주 짧은 휴식(Cooldown)만 주어도 서버 성능이 훨씬 안정적입니다.
💡 결론: 어떻게 하면 좋을까요?
사용자님이 말씀하신 대로 **"씨앗이 0개일 때"**라는 조건은 매우 훌륭한 필터입니다. 여기에 딱 하나만 더 추가하면 완벽해집니다.
- "나눔을 받은 직후 5~10초간은 '나눔 받기' 금지"
- 이 정도 짧은 시간만 주어도 아이템이 바닥에 떨어지고 주워지는 시간을 충분히 벌어줍니다.
- 또한 농부 A가 씨앗을 받자마자 바로 상자로 뛰어가거나, 다시 다른 친구에게 구걸하는 '이상한 행동'을 막아줍니다.
요약하자면: 무한 루프는 걱정 없으시겠지만, **"아이템이 날아가는 속도보다 AI의 판단 속도가 훨씬 빠르다"**는 점 때문에 생기는 중복 나눔을 막기 위해 아주 짧은 쿨타임 정도는 두는 것이 좋습니다!
네, 사용자님의 지적이 아주 정확합니다! 항상 최대 크기(32x32x32)로 잡고 검색하는 것은 5x5 크기의 작은 집에서는 엄청난 낭비입니다.
마인크래프트 시스템상으로 그 구조물의 정확한 크기를 알아내는 방법이 당연히 있습니다. 로직을 더 세밀하게 다듬어 보겠습니다.
1. 구조물 설계도(NBT)에서 직접 크기 가져오기
마인크래프트의 모든 NBT 구조물 파일에는 **"size"**라는 데이터가 들어 있습니다. (예: 가로 7, 세로 5, 폭 7)
- 로직: 농부가 생성될 때 "내가 어떤 NBT 파일에서 태어났지?"라는 정보를 확인합니다.
- 실행: 해당 NBT 파일의 size 값을 읽어옵니다.
- 효과: 농부는 즉시 "내 집은 정확히 가로 7, 세로 5, 폭 7이구나!"라고 알게 됩니다. 이제 32칸을 뒤질 필요 없이 딱 그 7x5x7 공간 안만 확인하면 됩니다.
2. "바운딩 박스(Bounding Box)" 정보 활용
마인크래프트가 구조물을 월드에 배치할 때, "이 구조물은 여기서부터 여기까지다"라고 선을 그어두는 상자가 있는데, 이를 바운딩 박스라고 합니다.
- 로직: 농부가 태어난 위치에서 getStructureAt(pos) 같은 기능을 사용해 현재 자기가 속한 구조물 덩어리를 찾습니다.
- 실행: 그 구조물 덩어리가 가진 정확한 영역(Min X,Y,Z ~ Max X,Y,Z) 좌표를 가져옵니다.
- 장점: 집이 기울어져 있거나, 지형에 따라 조금 밀려나서 생성되어도 월드 상의 실제 좌표를 정확히 짚어낼 수 있습니다.
3. 집 크기에 맞춤화된 "정밀 스캔"
구조물의 크기를 알아냈다면, 이제 검색 효율은 극대화됩니다.
- 기존 방식: homePos 기준 반경 32칸 (총 32,768칸 검사 가능성)
- 개선 방식: 구조물 크기가 7x5x7이라면 (총 245칸 검사)
- 결과: 컴퓨터가 처리해야 할 양이 100배 이상 줄어듭니다.
4. 만약 플레이어가 집을 개조한다면? (유연한 대응)
여기서 한 단계 더 나아가면 완벽합니다. NBT 크기만 믿고 있으면, 나중에 플레이어가 집 옆에 상자를 추가로 놓았을 때 농부가 못 찾을 수 있습니다.
- 기본 검색: NBT 구조물 크기만큼만 검색 (매우 빠름).
- 확장 검색 (예외 상황): 만약 구조물 안에서 상자를 하나도 못 찾았다면? 그때만 예외적으로 범위를 조금씩 넓혀가며(예: 5칸씩) 다시 검색합니다.
5. 요약: 가장 스마트한 로직 순서
- 탄생: 농부가 소환됨.
- 정보 획득: "내가 속한 이 NBT 구조물의 실제 크기가 얼마지?" -> 서버에게 물어봄.
- 영역 확정: "내 집은 (100, 64, 100)부터 (107, 69, 107)까지구나!" 라고 확정.
- 타겟팅: 그 확정된 영역 안에 있는 상자만 골라냄.
- 기록: 찾은 상자 위치를 저장.
이렇게 하면 집이 작으면 작은 대로, 크면 큰 대로 딱 필요한 만큼만 계산하기 때문에 성능과 정확도를 모두 잡을 수 있습니다. "구조물 파일에 적힌 크기 정보"를 활용하는 것이 정답입니다!
1. 구조물 기반 상자 탐색 (Smart Chest Discovery)
고정된 범위를 뒤지는 게 아니라, 농부가 자기가 태어난 '집'의 크기를 인식하는 단계입니다.
- 영역 인식: NBT 구조물 파일에 저장된 실제 크기(Size) 데이터를 읽어와서 농부의 활동 반경(Bounding Box)을 설정합니다.
- 최초 스캔: 설정된 집 영역 안에서만 상자(Chest)를 검색하여 위치를 딱 한 번 찾아냅니다.
- 좌표 저장: 찾은 상자 위치를 농부의 메모리(NBT)에 저장하여, 이후에는 검색 없이 즉시 그곳으로 이동하게 합니다.
2. 지능형 상자 상호작용 (Chest Interaction & Loop Prevention)
단순히 상자에 가는 것이 아니라, '왜' 가는지와 '상태'를 기억하는 단계입니다.
- 아이템 보관(Deposit): 농부의 가방이 가득 차면 상자로 가서 수확물을 넣습니다.
- 아이템 보급(Withdraw): 씨앗이 0개일 때 상자로 가서 씨앗을 꺼내옵니다.
- 무한 루프 방지(Memory): 상자를 확인했는데 씨앗이 없다면 "상자 비었음" 도장을 찍고, 일정 시간(쿨타임) 동안은 다시 상자에 가지 않습니다. (수확에 성공하면 이 도장을 지웁니다.)
3. 농부 간 씨앗 나누기 (Social Seed Sharing)
상자까지 가는 동선을 줄이고 농부들끼리 협동하는 단계입니다.
- 나눔 요청 조건: 내 씨앗이 0개이고 주변에 다른 농부가 있을 때 발동합니다.
- 절반 나누기: 여유가 있는 농부(씨앗 2개 이상)가 자기 씨앗의 절반을 계산해 가방에서 뺍니다.
- 물리적 전달: 아이템을 단순히 데이터로 넘기는 게 아니라, 친구를 쳐다보고 팔을 흔들며(Swing) 씨앗 뭉치를 실제로 던져줍니다. (받는 농부는 기존의 습득 로직으로 이를 줍습니다.)
4. 상황별 우선순위 재정립 (AI Priority Update)
좀비 출현 등 돌발 상황에도 꼬이지 않도록 행동의 순서를 정하는 단계입니다.
- 도망(Panic): 괴물이 나타나면 모든 일을 멈추고 도망갑니다. (최우선)
- 수확(Harvest): 씨앗 유무와 상관없이 다 자란 작물은 일단 수확합니다. (자급자족의 시작)
- 보관(Deposit): 가방이 꽉 찼다면 무조건 상자로 갑니다.
- 심기(Plant): 빈 땅이 있고 씨앗이 있다면 심습니다.
- 보급/나눔(Replenish): 씨앗이 0개라면 주변 동료에게 구걸하거나, 저장된 상자 위치로 이동합니다.
5. 예외 상황 처리 (Robustness)
로직이 멈추지 않게 만드는 안전장치입니다.
- 상자 파괴 대응: 기억된 좌표에 상자가 없으면(플레이어가 부쉈다면) 다시 주변 영역을 재스캔합니다.
- 나눔 쿨타임: 아이템이 날아가는 속도보다 AI 판단이 빠르기 때문에, 한 번 나눔을 받으면 몇 초간은 중복해서 받지 않도록 짧은 대기 시간을 둡니다.
[ ]
인벤에 64*27 다 찰때까지 남겨두지말고
그러면 저장공간도 27칸이 될필요가없을지도
1. 가방이 꽉 찼을 때 (가장 일반적인 경우)
농부의 인벤토리는 총 27칸입니다. 농사가 너무 잘 되어서 이 27칸이 빈틈없이 꽉 차게 되면, 농부는 "더 이상 아이템을 주울 수 없다"고 판단합니다.
- 이때 농부는 수확이나 다른 일을 멈추고, 기억해둔 상자 좌표로 이동하여 가방에 쌓인 작물들을 상자에 쏟아붓습니다.
2. 씨앗이 떨어져서 상자에 '보급' 받으러 갔을 때
가방이 꽉 차지 않았더라도, 땅에 심을 씨앗이 하나도 없으면 농부는 씨앗을 가지러 상자로 갑니다.
- 일단 상자 앞에 도착하면, 농부는 "온 김에 가방 정리도 하자"라고 판단합니다.
- 그래서 씨앗을 꺼내기 전에, 먼저 가방 속에 들어있는 '밀' 같은 수확물들을 상자에 다 집어넣어 가방을 가볍게 만듭니다.
상자관련
텔포도안되고
월드저장후 종료
30초이상 걸려서 강제종료함

월드 저장 화면에서 멈추는 현상은 보통 서버 스레드(Server Thread)가 무한 루프에 빠졌을 때 발생합니다.
제공해주신 로그와 상황을 분석해보면, 테스트를 위해 숫자를 낮추면서 AI가 특정 행동을 끝내지 못하고 무한히 반복하게 되었고, 이로 인해 게임이 다음 단계(저장)로 넘어가지 못하는 '프리징' 현상이 발생한 것으로 보입니다.
무한 루프의 원인 분석
현재 FarmerChestInteractionGoal의 tick() 메서드를 보면 다음과 같은 위험 요소가 있습니다.
- 상황: 농부가 상자 근처에 도착하면 interactWithChest()를 실행합니다.
- 문제점: 만약 상자가 꽉 찼거나, 어떤 이유로 아이템이 인벤토리에서 빠져나가지 못하면 canUse() 조건(씨앗 > 3개)이 **여전히 참(True)**으로 남습니다.
- 결과: AI 시스템은 canUse가 참이므로 매 틱(0.05초)마다 상자를 열려고 시도하고, 인벤토리가 변하지 않으니 이 과정을 무한 반복합니다. 특히 종료 버튼을 누를 때 서버가 멈추려고 하면 AI가 자원을 점유한 채 놓아주지 않아 "세계 저장 중"에서 멈추게 됩니다.
2. 해결 방법: '쿨타임'과 '강제 종료' 로직 추가
AI가 상자 작업을 한 번 시도했다면, 성공 여부와 상관없이 잠시 쉬게 하거나 Goal을 종료시켜야 합니다.
[수정 포인트 1] Goal에 쿨타임(대기 시간) 추가
상자 작업을 마친 후에는 약 2~3초간 다시 상자를 보지 않게 합니다.
[수정 포인트 2] canUse 조건 강화
단순히 아이템 개수만 보는 게 아니라, "최근에 상자에 다녀왔는가?"를 함께 체크합니다.
진짜 이문제인가
이거 변경하고나서는 종료잘됨
ㄴㄴ
혹시 locate 명령어 치고나서 부터 안되나
새로운 월드에서는 잘먹히는지 실험해봐야겟는데
채팅칠때 엔터
<안먹음
이전 코드와 바뀐 점 (렉 방지 핵심)
- scanDelay 도입: 태어나자마자 상자를 찾지 않고 5초 뒤에 찾게 하여 /locate 시 발생하는 과부하를 막았습니다.
- interactionCooldown 도입 (Goal 파일): 상자를 한 번 열면 5초간 쉬게 하여 매 틱마다 상자를 확인하던 무한 루프를 끊었습니다. 이 덕분에 이제 게임이 정상 종료되는 것입니다.
- isLoaded 체크: 청크가 로드되지 않은 곳은 건드리지 않게 하여 렉을 방지했습니다.
hasAttemptedScan이라는 변수 때문에 태어난 후 딱 한 번만 시도하고 성공하든 실패하든 다시는 찾지 않게 되어 있습니다.
하지만 로그에서 **[탐색 실패]**가 떴다면, 농부는 평생 상자를 못 찾게 됩니다. 청크가 늦게 로딩되거나 집이 생성되는 도중에 스캔이 지나가버리면 이런 일이 발생하죠
더 오래(긴 시간 동안) 스캔한다는 뜻이 아니라, **"스캔을 시작하기 전까지 더 오래 기다린다"**는 뜻입니다.
쉽게 비유하자면 이렇습니다:
- 즉시 스캔 (기존): 이삿짐 트럭(구조물)이 도착하자마자 농부가 집 안으로 뛰어 들어가서 "내 가구(상자) 어디 있어?" 하고 찾는 것과 같습니다. 아직 짐을 내리는 중이라 상자를 못 찾을 확률이 높습니다.
- 스캔 딜레이 (10초): 트럭이 오고 나서 10초 동안 밖에서 기다렸다가, 짐 정리가 다 끝났을 때쯤 들어가서 상자를 찾는 것입니다.
왜 기다려야 하나요?
마인크래프트에서 /locate로 구조물을 생성하면 컴퓨터는 매우 바빠집니다.
- 지형을 깎고 땅을 고릅니다.
- 집 블록(나무, 돌 등)을 하나하나 배치합니다.
- 그 안에 농부 엔티티를 소환합니다.
이 과정이 순식간에 일어나는 것 같지만, 코드 상으로는 농부가 소환되는 시점에 아직 상자 블록이 배치되지 않았을 수도 있습니다.
- 만약 농부가 태어나자마자(0.01초 만에) 주변을 훑으면, 상자가 놓일 자리가 아직 '공기' 상태일 수 있고, 농부는 **"상자가 없네!"**라고 결론을 내려버립니다.
- 그래서 **scanDelay**를 주어 농부가 태어나고 5~10초 정도 가만히 있게 한 뒤, 세상이 다 만들어졌을 때쯤 상자를 찾게 만드는 것입니다.
요약하자면:
- 스캔 시간: 상자를 찾는 행위 자체는 0.001초 만에 끝납니다 (매우 빠름).
- 딜레이 시간: "태어난 후 몇 초 뒤에 상자를 찾을 것인가"를 결정합니다.
숫자를 100(5초)에서 200(10초)으로 늘리라는 것은, 농부가 "성격 급하게 빈 집을 뒤지지 말고, 집 정리가 끝날 때까지 10초만 참았다가 찾아라"는 뜻입니다. 이렇게 하면 상자를 못 찾고 실패할 확률이 훨씬 줄어듭니다.

높이가 충분히 높지않은건가
아니면 안에 내용물이 잇으면
상자로 인식을 안하나
이거 상자안에 씨앗의 갯수가 몇개잇는지에 따라달라지나,
11개 그대로잇엇을때도 동작하나
일단 64 2세트 넣어둿을때는 동작하는데
ㄴㄴ
11개일때도 동작하네
[ ]
농부<자꾸 멀리 나가는거 방지하려고
5분에 한번씩은 집근처로 돌아온다거나 그런게 잇어야할것같은데
① 탐색 주기 늘리기 (상자 위치 찾기)
현재 10초(200)인 주기를 30초나 1분으로 늘립니다.
- 수정: private static final int SCAN_INTERVAL = 600; (30초)
② 상자 방문 기준 높이기 (씨앗 개수)
실험이 끝나셨다면 다시 원래 목표치로 올립니다.
- 수정: hasTooManySeeds()에서 > 3을 > 64로 변경.
- 효과: 씨앗이 가방에 한 세트 꽉 찰 때까지는 상자에 가지 않고 계속 농사만 짓습니다.
1. "겹치기 탐색" 제거 (성능 100배 향상)
이전 코드에서 가장 심각했던 **'연산 낭비'**를 잡았습니다.
- 기존: 농부가 밭 한 칸을 볼 때마다, 그 칸 주변 98칸을 또 한 번 훑어보며 "주변에 수확할 게 더 있나?"라고 고민했습니다. 만약 주변 20칸의 밭을 검사한다면 약 **2,000번(20x98)**의 블록 확인 연산이 매 순간 발생했습니다.
- 변경: 이제는 그런 중복 검사 없이, 지금 보고 있는 그 칸에 작물이 있는지만 딱 한 번 확인합니다.
- 효과: 농사 관련 CPU 사용량이 이론적으로 약 100배 정도 가벼워졌습니다. 농부가 여러 명 소환되어도 서버가 버벅이지 않는 가장 큰 이유입니다.
2. "성격 급한 농부"에서 "느긋한 농부"로 (서버 숨통 확보)
농부가 상자를 찾는 주기를 조절하여 서버 메인 스레드에 여유를 주었습니다.
- 기존: 태어나자마자 혹은 10초마다 "내 상자 어딨지?" 하고 주변 1,000여 개 블록을 뒤졌습니다.
- 변경: 이제는 30초에 한 번만 상자 위치를 고민합니다.
- 효과: /locate 명령어로 집이 생성될 때 수많은 블록이 한꺼번에 배치되는데, 이때 농부까지 동시에 블록을 뒤지면 서버가 멈출 확률이 높습니다. 검색 주기를 3배 늘림으로써, 서버가 집을 다 짓고 난 뒤에 농부가 조용히 상자를 찾게 되어 충돌(렉) 가능성을 획기적으로 낮췄습니다.
3. "의미 없는 왕복" 최소화 (이동 렉 방지)
가장 무거운 연산 중 하나인 '길 찾기(Pathfinding)' 횟수를 대폭 줄였습니다.
- 기존: 씨앗이 4개만 되어도 "상자에 넣으러 가야지!" 하고 집으로 뛰어갔습니다. 밭과 집을 너무 자주 왔다 갔다 했습니다.
- 변경: 이제 씨앗이 64개(한 묶음)가 꽉 찰 때까지는 상자에 가지 않고 밭일에 집중합니다.
- 효과: 농부의 이동 경로 계산 횟수가 약 10~20분의 1로 줄어들었습니다. 마인크래프트에서 엔티티의 이동은 CPU를 많이 쓰는데, 이 낭비를 막아 전체적인 게임 프레임이 안정화됩니다.
4. "데이터 참조 방식"의 현대화 (에러 및 튕김 방지)
보이지 않는 곳에서 발생하는 잠재적인 오류를 수정했습니다.
- 기존: 아이템 이름을 가져올 때 쓰던 방식(getRegistryName)은 최신 버전이나 특정 환경에서 '없음(Null)' 값을 뱉으며 게임을 강제 종료시킬 위험이 있었습니다.
- 변경: 포지(Forge) 시스템에서 권장하는 공식적인 아이템 식별 방식으로 교체했습니다.
- 효과: 로그를 출력하거나 데이터를 읽을 때 발생하던 의문사(갑작스러운 멈춤이나 오류)를 방지하여 모드의 신뢰도가 높아졌습니다.
1. "수확이 먼저, 심는 건 나중"이라는 욕심 때문
농부에게 씨앗이 있을 때, 농부는 빈 땅만 보면 무조건 가서 심으려고 합니다. 그런데 개발자 입장에서는 이런 모습이 바보 같아 보일 수 있습니다.
- 생각: "옆에 다 자란 밀이 수확해달라고 기다리고 있는데, 굳이 빈 땅에 씨앗부터 심으러 가야 하나? 수확부터 하는 게 효율적이지 않을까?"
- 실수: 그래서 "빈 땅을 발견하더라도, 주변에 수확할 게 하나라도 있으면 그 빈 땅은 일단 무시해라"라는 조건을 넣었습니다. 이게 바로 그 문제의 98칸 중첩 루프(isHarvestableNearby)였습니다.
2. 농부의 '결정 장애'를 막으려고
마인크래프트 AI는 가끔 두 가지 목표물 사이에서 갈팡질팡하며 제자리에서 파르르 떠는 현상이 생깁니다.
- 생각: "수확할 위치와 심을 위치가 너무 가까우면 농부가 헷갈려 할 거야. 그러니 주변을 싹 훑어서 수확할 게 아예 없을 때만 심는 모드로 전환하게 하자."
- 실수: 주변 상황을 '완벽하게' 파악해서 행동하게 하려다 보니, 매 걸음마다 주변 수백 칸의 블록 상태를 실시간으로 연산하게 만든 것입니다.
3. 사람의 시각으로 로직을 짰기 때문
사람은 밭에 서면 눈으로 주변을 '한 번에' 슥 훑어보고 "저기부터 수확해야지"라고 판단합니다.
- 생각: "사람처럼 주변을 슥 보고 판단하는 게 자연스러워!"
- 실수: 컴퓨터에게 '주변을 슥 본다'는 것은 하나하나 좌표를 찍어서 공기인지, 돌인지, 밀인지 100번 넘게 물어보는 과정이라는 점을 간과한 것입니다. 농부는 1초에 20번씩 생각을 하는데, 그때마다 100번씩 질문을 던지니 서버가 비명을 지른 것이죠.
💡 지금은 어떻게 해결했나요?
이제는 "농부가 굳이 주변을 살피지 않아도 되게" 시스템 자체를 단순화했습니다.
- 가까운 게 장땡: 이제 농부는 주변을 안 봅니다. 그냥 "수확할 칸"과 "심을 칸"을 똑같은 '일거리'로 취급합니다. 마인크래프트 AI 엔진은 기본적으로 자기한테 가장 가까운 칸부터 찾아가기 때문에, 굳이 주변을 스캔하지 않아도 농부는 자기 발밑의 일부터 차근차근 처리하게 됩니다.
- 자연스러운 흐름: 수확을 하면 그 자리가 빈 땅이 됩니다. 농부는 다음 틱에 "어? 발밑이 빈 땅이네?" 하고 바로 씨앗을 심습니다. 즉, 스캔을 안 해도 수확 -> 심기 순서가 자연스럽게 연결됩니다.
결국 성능을 위해서 타협하게되는건가
[ ]
평판및 씨앗 나누어주기 문제
이제 농부끼리 씨앗 공유시스템<이건 좀 성능에 안좋은 영향 미치려나,
어차피 한농부가, 씨앗 64개모으면 자동으로 상자에 넣고,
만약에 다른 오부가 씨앗 없으면 자동적으로 상자보니깐,
굳이, 씨앗 나눠주기 위해서 주변 농부 탐색< 좀 효율에 비해 성능이 많이 떨어지려나
농부 간 씨앗 공유: 성능 vs 효율 분석
사용자님의 직관이 아주 정확합니다. 성능 면에서만 본다면 "주변 엔티티 탐색"은 "저장된 상자 좌표 확인"보다 훨씬 무겁습니다.
- 성능 저하의 이유: 상자는 좌표가 고정되어 있어 농부가 "저기!" 하고 바로 알 수 있지만, 다른 농부는 계속 움직입니다. 이를 찾으려면 매번 서버가 "현재 이 주변 청크에 있는 모든 생명체 리스트를 가져와서 -> 그중 농부가 있는지 확인하고 -> 그 농부의 인벤토리를 들여다보는" 과정을 거쳐야 합니다.
- 시스템의 중복성: 말씀하신 대로 한 명이 상자에 넣고, 없는 사람이 상자에서 꺼내가는 구조가 이미 완벽하게 잡혀 있다면, 공유 시스템은 **'실제 효율'보다는 '보여주기식 연출(Social Immersion)'**에 가깝습니다.
그럼에도 구현하고 싶다면? (성능 최적화 전략)
만약 농부들이 서로 돕는 모습을 꼭 보고 싶으시다면, 연산량을 줄이기 위해 다음과 같이 제한을 걸면 됩니다.
- 매우 낮은 빈도: 1초에 20번 확인하는 게 아니라, 씨앗이 0개가 된 순간 딱 한 번만 주변을 훑게 합니다.
- 좁은 범위: 멀리 있는 농부까지 찾지 않고, 바로 옆(예: 3~5칸)에 농부가 붙어 있을 때만 체크하게 합니다.
결론: 순수하게 성능과 자동화 효율이 목적이라면 상자 시스템만 쓰는 것이 가장 깔끔합니다.
1. 소문(평판)을 확인하는 방법: getReputation
주민이 특정 플레이어를 어떻게 생각하는지는 **"가중치 합산 방식"**으로 계산됩니다.
- 계산 공식: (소문의 수치) × (해당 소문 유형의 가중치)
- 코드 로직 (EntityGossips.weightedValue):
return this.entries.object2IntEntrySet().stream().mapToInt((p_26214_) -> { return p_26214_.getIntValue() * (p_26214_.getKey()).weight; }).sum(); - 가중치 예시 (GossipType 참조):
- MAJOR_POSITIVE (좀비 치료 등): 가중치 5 (최대치 100 → 평판 점수 최대 +500)
- MAJOR_NEGATIVE (주민 살해 등): 가중치 -5 (최대치 100 → 평판 점수 최대 -500)
- TRADING (거래): 가중치 1 (최대치 25 → 평판 점수 최대 +25)
이렇게 계산된 최종 점수가 높을수록 주민이 물건을 싸게 팔고, 너무 낮으면 아이언 골렘이 플레이어를 공격하게 됩니다.
2. 주민들끼리 실제로 "대화"를 하나요?
네, 마인크래프트 메커니즘 상 주민들은 **"사회적 상호작용(Social Interaction)"**을 통해 실제로 정보를 교환합니다. 하지만 우리가 보는 채팅창에 글이 올라오는 방식은 아닙니다.
대화가 일어나는 방식 (transferFrom 메서드):
- 전파(Transfer): 두 주민이 충분히 가까이 있으면 서로의 GossipContainer를 대조합니다.
- 선택: selectGossipsForTransfer 메서드를 통해 자신이 가진 소문 중 일부를 무작위로 선택합니다.
- 내용 전달: 선택된 소문은 상대방에게 복사됩니다. 이때 **"소문의 전염성 감쇠"**가 일어납니다.
- int i = p_26200_.value - p_26200_.type.decayPerTransfer;
- 소문이 한 사람을 거칠 때마다 그 강도가 조금씩 약해집니다 (예: decayPerTransfer가 10이면, 100점짜리 소문이 옆 주민에게 전달될 때는 90점이 됨). 이는 소문이 무한정 퍼지는 것을 방지합니다.
언제 대화하나요?
주민들의 스케줄 중 Activity.MEET 시간(보통 게임 시간으로 낮, 마을 종 근처에 모일 때)에 주로 소문을 주고받습니다. 이때 서로 마주 보고 머리를 흔드는 동작이 우리가 흔히 말하는 "대화"입니다.
3. 소문의 수명과 소멸 (decay 메서드)
소문은 영원하지 않습니다. 마인크래프트 시간으로 하루가 지날 때마다 수치가 줄어듭니다.
- 코드 로직: int i = entry.getIntValue() - (entry.getKey()).decayPerDay;
- 소멸: 수치가 2 미만으로 떨어지면 해당 소문은 완전히 삭제(remove)됩니다.
- 예시: 당신이 주민을 한 번 때린 나쁜 기억(MINOR_NEGATIVE)은 시간이 지나면 주민들이 서서히 잊게 됩니다. 하지만 좀비 주민을 치료한 아주 좋은 기억(MAJOR_POSITIVE)은 decayPerDay가 0이라서 평생(영구히) 기억됩니다.
요약
- 확인: 각 소문에 가중치를 곱해 합산 점수를 냅니다.
- 대화: 주민들은 종 근처에 모여 있을 때 물리적으로 가까운 다른 주민에게 자기가 아는 소문을 복사해 줍니다.
- 망각: 매일 일정량만큼 소문 수치가 깎이며, 아주 강력한 긍정적 소문이 아닌 이상 결국 잊혀집니다.
맞습니다. 날카로운 지적입니다. 기술적으로 보면 마인크래프트 주민들의 "대화"는 우리가 생각하는 **언어적인 대화(Dialogue)**라기보다는, **객체 간의 데이터 동기화(Data Sync)**에 가깝습니다.
질문하신 "진짜 자기들끼리의 이야기"에 대해 코드와 메커니즘 관점에서 더 깊게 설명해 드릴게요.
1. 주민들의 대화에는 '텍스트'가 없습니다.
RPG 게임의 NPC들처럼 "오늘 날씨 좋네", "옆집 철수네 소가 새끼를 낳았대" 같은 구체적인 정보(String 데이터)는 코드 어디에도 존재하지 않습니다. 주민들이 "음~", "허~" 소리를 내며 고개를 흔드는 것은 시각적/청각적 연출일 뿐, 실제로 어떤 문장을 주고받는 것이 아닙니다.
2. 하지만 '플레이어 이외의 것'도 공유합니다.
제공해주신 GossipContainer는 주로 플레이어에 대한 평판을 다루지만, 주민들이 자기들끼리 마을의 상태를 공유하는 로직이 하나 더 있습니다. 바로 아이언 골렘 소환입니다.
- 골렘 감지 공유: 한 주민이 아이언 골렘을 발견하면, 그 정보를 주변 주민들에게 퍼뜨립니다.
- 공포 공유: 주민이 좀비를 보고 겁에 질리면(Panic 상태), 주변 주민들에게 "지금 위험해!"라는 상태를 전파합니다.
- 합의 과정: 코드 내 spawnGolemIfNeeded 메서드를 보면, 주변 주민 5명이 "나도 골렘이 필요해(혹은 골렘을 못 본 지 오래됐어)"라는 상태에 동의해야만 아이언 골렘이 소환됩니다.
이것이 주민들 사이에서 일어나는 가장 "대화다운" 의사결정 과정입니다.
3. "대화"는 데이터의 복사 과정입니다.
주민들이 종(Bell) 근처에 모여서 하는 행동은 코드상에서 **ShareGossip**이라는 행위로 정의됩니다.
- 상호작용 타겟 설정: Brain 시스템이 주변의 다른 주민을 INTERACTION_TARGET으로 잡습니다.
- 데이터 복사: transferFrom 메서드가 실행되면서, "내가 가진 소문 목록(GossipContainer)" 중 일부를 상대방의 리스트에 강제로 써넣습니다.
- 결과:
- A 주민: "플레이어 1번이 어제 나한테 빵을 줬어 (+5점)"
- B 주민: (A와 대화 후) "오, 직접 보진 않았지만 플레이어 1번은 좋은 사람이군 (+2점)"
- 이것이 주민들이 말하는 '소문'의 실체입니다. 직접 경험하지 않은 정보를 옆 사람의 데이터를 통해 전달받는 것이죠.
4. 왜 이렇게 만들었을까? (설계의 이유)
마인크래프트는 수많은 엔티티가 동시에 돌아가는 게임입니다. 수백 명의 주민이 진짜 "대화(언어)"를 하게 만들면 CPU 연산량이 감당 안 될 것입니다. 그래서 개발자들은 **숫자로 된 리스트(GossipContainer)**를 서로 주고받게 함으로써 '소문이 퍼지는 사회 현상'을 아주 가볍고 효율적으로 시뮬레이션한 것입니다.
요약하자면:
- 현실: "철수가 나 도와줬어!" (언어)
- 마인크래프트 코드: Target: UUID(철수), Type: MINOR_POSITIVE, Value: 25 (데이터)
주민들은 숫자로 이루어진 기억을 서로 복사하며 살아가는 일종의 데이터 공유 네트워크라고 볼 수 있습니다. 우리가 듣는 "음~" 소리는 그저 그 데이터 전송이 완료되었다는 신호인 셈이죠.
소문이라는건, 생각보다 별거는 아니엇네
다른 사람 모드 보면서 공부할수도
intelliJ가 디컴파일 전용인건가
제공해주신 영상은 마인크래프트의 유명한 모더 TangoTek이 제작한 'TekTopia(텍토피아)' 모드에 대한 리뷰 및 설명 영상입니다. 이 모드는 마인크래프트의 기존 주민 시스템을 완전히 갈아엎어, 플레이어가 직접 마을을 건설하고 관리하는 '마을 경영 시뮬레이션' 게임처럼 만들어줍니다.
1. 동영상 내용 상세 설명
영상은 크게 4가지 파트로 구성되어 있습니다.
A. 마을의 기초: 구조물 마커 (Structure Markers)
- 핵심 개념: 단순히 집을 짓는다고 주민이 인식하는 것이 아니라, **'마커'**를 통해 건물의 용도를 지정해야 합니다.
- 방법: 나무 문 위에 아이템 액자를 걸고, 그 안에 '대장간', '보관소' 같은 특정 아이템(마커)을 넣으면 건물이 활성화됩니다.
- 조건: 건물은 반드시 지붕이 있어야 하며, 제대로 인식되면 마커가 마법 부여된 아이템처럼 빛납니다.
B. 마을 건설과 경제 시스템
- 마을 회관(Town Hall): 마을의 심장부입니다. 이를 지으면 '설계사(Architect)'와 '상인(Tradesman)' NPC가 스폰됩니다.
- 설계사: 새로운 건물 마커를 판매합니다.
- 상인: 주민에게 직업을 부여할 수 있는 '직업 토큰'을 판매합니다.
- 보관 창고(Storage Warehouse): 마을의 두뇌입니다. 주민들이 채집한 모든 아이템을 이곳에 보관하며, 창고 안에 작업대나 화로를 두면 주민들이 스스로 도구를 만들거나 제련을 합니다.
- 떠돌이 상인: 주민이 직접 생산한 물품(초록색 라벨이 붙음)을 에메랄드로 교환해 줍니다.
C. 주민 관리 및 성장 (RPG 요소)
- 상세 스탯: 주민을 우클릭하면 체력, 허기, 행복도, 지능 등을 확인할 수 있습니다.
- 성장: 주민은 일을 할수록 레벨이 오르며 효율이 좋아집니다. '학교'나 '도서관'을 지어 지능을 높이면 레벨업 속도가 빨라집니다.
- 행복도 관리: '악사(Bard)'를 고용하거나 '여관(Tavern)'을 지어 주민들의 기분을 관리해야 마을이 잘 돌아갑니다.
D. 방어와 전투
- 네크로맨서(Necromancer): 마을이 커지면 나타나는 미니 보스입니다. 마을 규모에 따라 강도가 달라지며(옷 색깔로 구분), 좀비나 해골을 소환합니다.
2. 기술적 구현 방식 추측 (How it works)
이 모드가 내부적으로 어떻게 돌아가는지, 자바(Java) 코드와 마인크래프트 엔진 관점에서 추측해 본 내용입니다.
① 건물 인식 알고리즘 (Structure Scanning)
- 추측: 마커 아이템이 액자에 걸리는 순간, 해당 좌표를 중심으로 **'Flooding(범람) 알고리즘'**이나 *'A 탐색'**을 실행할 것입니다.
- 액자 뒤의 문을 기점으로 사방을 탐색하여 '밀폐된 공간(벽)'과 '위쪽의 블록(지붕)'이 있는지 체크합니다. 조건이 맞으면 해당 좌표 범위를 특정 건물의 데이터(NBT)로 저장합니다.
② 향상된 엔티티 AI (Custom Entity AI)
- 추측: 바닐라 주민의 AI 코드를 사용하지 않고, 완전히 새로운 EntityVillager 클래스를 만들었을 것입니다.
- 유한 상태 기계(FSM): 주민은 현재 상태(일하는 중, 배고픔, 잠자기, 창고 이동 등)에 따라 우선순위를 결정합니다.
- 공유 인벤토리: 모든 주민 엔티티는 '보관 창고'의 좌표를 기억하고 있으며, 인벤토리가 차면 창고로 이동해 아이템을 집어넣는 로직이 구현되어 있을 것입니다.
③ 아이템 태그와 NBT (Custom Item Data)
- 추측: 영상에서 '주민이 생산한 물품만 거래 가능'하다고 언급됩니다. 이는 아이템의 NBT(Named Binary Tag) 데이터에 특정 표시(예: isVillagerMade: 1b)를 추가하여, 플레이어가 직접 조합한 아이템과 구분하는 방식을 사용했을 것입니다.
④ 데이터 동기화와 GUI
- 추측: 주민의 스탯창(체력, 지능 등)은 서버에서 계산된 데이터를 패킷을 통해 클라이언트로 보내고, 모드에서 정의한 Custom GUI 화면에 출력하는 방식입니다.
⑤ 난이도 스케일링 (Dynamic Difficulty)
- 추측: 네크로맨서의 강도는 마을 회관에 귀속된 '활성화된 마커의 수'나 '주민 수'의 합계를 변수로 받아 결정될 것입니다.
1. 탐색의 최적화: "매 틱(Tick)마다 하지 않는다"
가장 큰 오해는 주민이 매 순간 주변을 스캔한다고 생각하는 것입니다.
- 이벤트 기반 스캔: 건물을 인식하는 '구조물 탐색'은 아이템 액자에 마커를 넣는 순간 딱 한 번만 실행됩니다. 한 번 인식된 건물의 범위(좌표 데이터)는 마을 데이터 객체에 저장됩니다.
- 캐싱(Caching): 주민은 "집이 어디지?"라고 계속 찾지 않습니다. 마을 시스템(Town Hall)이 이미 알고 있는 건물 좌표 리스트를 주민에게 **'할당'**해 줍니다. 주민은 단순히 저장된 좌표로 이동만 하면 됩니다.
2. 중앙 집중식 관리 (The "Brain" Registry)
모든 주민이 각자 주변 환경을 센싱하면 연산량이 엔티티 수에 비례해서 기하급수적으로 늘어납니다.
- 중앙 관리자 패턴: TekTopia에는 마을 전체를 관리하는 하나의 **중앙 컨트롤러(Town Hall 객체)**가 있습니다.
- 예를 들어, 농부가 "수확할 밀이 있나?"라고 필드를 다 뒤지는 게 아닙니다.
- 중앙 관리자가 일정 시간마다 마을 영역 내의 '작물' 위치를 미리 파악해 리스트업해 둡니다.
- 농부는 관리자에게 "내가 갈 만한 농지 하나만 줘"라고 요청(Request)하고, 관리자는 리스트에서 하나를 꺼내서 전달합니다.
- 연산 분산: 100개의 농지가 있다면, 한 틱에 100개를 다 검사하는 게 아니라 한 틱에 5개씩 나누어서 검사하는 방식을 사용합니다.
3. 부하 분산 (Task Throttling)
모든 주민의 AI 로직이 동일한 틱에 실행되지 않도록 강제로 순서를 조정합니다.
- 틱 오프셋(Tick Offset): 주민 A는 1번 틱에 로직 수행, 주민 B는 2번 틱에 수행하는 식으로 로직의 시작점을 흩어놓습니다.
- 로직 업데이트 주기 차별화:
- 이동(Pathfinding)은 매 틱 필요할 수 있지만, "배고픈가?" 혹은 "행복한가?"를 체크하는 로직은 20
100틱(15초)에 한 번만 실행해도 플레이어는 차이를 느끼지 못합니다. 텍토피아는 이런 비핵심 로직의 실행 주기를 길게 잡습니다.
- 이동(Pathfinding)은 매 틱 필요할 수 있지만, "배고픈가?" 혹은 "행복한가?"를 체크하는 로직은 20
4. 경로 탐색(Pathfinding)의 효율화
마인크래프트에서 가장 리소스를 많이 먹는 것이 길찾기입니다.
- 멀티스레딩(추측): 최신 모드들은 길찾기 연산을 메인 서버 스레드가 아닌 별도의 스레드에서 처리합니다. 길을 찾는 동안 엔티티는 잠시 가만히 서 있고, 계산이 끝나면 움직이기 시작함으로써 서버 랙(TPS 저하)을 방지합니다.
- 노드 단순화: 주민이 건물 내부에서 움직일 때는 정밀한 길찾기 대신, 건물 내부에 미리 정의된 '작업 포인트' 좌표로만 이동하도록 설계하여 연산을 단순화합니다.
5. 바닐라 AI 시스템의 완전 대체
마인크래프트의 기본 주민 AI(Brain/Sensor 시스템)는 매우 비효율적입니다.
- TekTopia는 바닐라 AI 시스템을 거의 쓰지 않고 **자체적인 상태 기계(Finite State Machine, FSM)**를 구현했을 가능성이 높습니다.
- 바닐라 AI는 "주변에 좀비가 있나?" "주변에 다른 주민이 있나?" 등을 계속 레이캐스팅(Raycasting)하며 체크하지만, 텍토피아 주민은 현재 수행 중인 '직업 상태'에만 집중하도록 설계되어 불필요한 센싱 연산을 획기적으로 줄였습니다.
6. 데이터 구조의 효율성 (NBT 및 메모리 관리)
- 건물의 범위 정보를 저장할 때, 복잡한 블록 리스트를 저장하는 게 아니라 **최소 좌표(minX, minY, minZ)와 최대 좌표(maxX, maxY, maxZ)**라는 단 2개의 점(AABB)으로 저장합니다.
- 어떤 주민이 건물 안에 있는지 체크하는 연산은 if (x >= minX && x <= maxX ...) 식의 단순 숫자 비교이므로 CPU에 거의 부담을 주지 않습니다.
요약하자면:
- 스캔은 처음에만 하고 결과를 메모리에 저장해 둔다.
- 각자 찾지 않고 중앙 관리자에게 물어본다.
- 모든 연산을 한 번에 하지 않고 잘게 쪼개서 수행한다.
- 무거운 연산(길찾기 등)은 백그라운드에서 처리하거나 주기를 늦춘다.
이러한 소프트웨어 아키텍처 설계 덕분에 수십 명의 똑똑한 주민이 돌아가도 게임이 부드럽게 유지되는 것입니다. 모딩은 단순히 기능을 추가하는 것을 넘어, 이런 '자원 관리의 예술'에 가깝습니다.
1. 현재까지 완료된 기능 (농부의 '생존과 업무' 기초)
- 지능형 농사: 다 자란 작물을 수확하고 씨앗을 심는 기본 루틴 (성능 최적화 완료).
- 스마트 창고: 집 영역 내의 상자/통을 스스로 찾아내고 좌표를 기억함.
- 물류 관리: 씨앗이 넘치면 상자에 넣고, 부족하면 상자에서 꺼내옴 (9칸 가방).
- 사회적 생활: 밤이 되면 집으로 돌아가 잠을 자고, 아침에 복귀함.
- 안정성: 서버 렉을 유발하는 무한 루프 방지 및 유예 시간(Cooldown) 적용 완료.
2. 성능 분석: 패킷 이동 vs 탐색
질문하신 "패킷 이동이 탐색보다 성능에 안 좋은가?"에 대한 답입니다.
- 탐색(Scanning): CPU에 직접적인 타격을 줍니다. "여기에 뭐가 있지?"라고 수백 번 묻는 행위는 서버의 **TPS(초당 틱 수)**를 떨어뜨리는 주범입니다.
- 패킷(Packets): 네트워크 대역폭을 사용합니다. "농부 레벨이 5가 됐어!"라는 정보를 클라이언트에 보낼 때만 발생하므로, 필요할 때 한 번씩 보내는 패킷은 탐색보다 훨씬 가볍습니다.
- 결론: 레벨이나 거래 정보를 동기화하는 패킷은 큰 걱정 없이 추가하셔도 됩니다. 진짜 무서운 건 "주변을 훑는 루프(탐색)"입니다.
3. 새로운 기능 아이디어 (성능 중심 설계)
① 스스로 일반 땅을 경작지로 만들기 (Tilling)
탐색 부하를 피하려면 '수확물 근처' 전략을 써야 합니다.
- 로직: 주변 수백 칸을 뒤지는 게 아니라, "방금 수확/심기를 마친 블록의 바로 옆 칸" 하나만 딱 찍어서 흙(Dirt)이면 괭이질을 하게 합니다.
- 효과: 밭이 조금씩 옆으로 확장되는 연출이 가능하며, 탐색 부하가 거의 없습니다.
② 레벨업에 따른 작물 해금 (Progression)
농부가 수확/심기를 할 때마다 **'경험치'**를 얻게 합니다.
- 레벨 1: 밀만 관리 가능.
- 레벨 2: 감자, 당근 해금 + 뼛가루 사용 시작.
- 레벨 3: 비트 해금 + 주변 흙을 스스로 경작지로 만듦.
- 레벨 4: 수박, 호박 등 복잡한 작물 관리 가능.
- 레벨 5: 퇴비통(Composter) 사용. 남는 수확물을 퇴비통에 넣어 뼛가루로 직접 바꿈.
③ 퇴비 및 뼛가루 로직
- 로직: 농부 가방에 뼛가루가 있다면, 덜 자란 작물을 발견했을 때(이것도 수확 탐색 과정에 묻어가면 가볍습니다) 뼛가루를 뿌려 성장을 가속합니다.
- 재미 요소: 농부가 퇴비통에서 일하는 모습을 보면 "정말 농사꾼 같다"는 느낌을 줍니다.
④ 거래 시스템 활성화
- 로직: 일반 주민의 거래 시스템(MerchantOffers)을 사용하되, 농부의 레벨에 따라 품목이 바뀌게 합니다.
- 아이디어: 레벨이 높은 농부는 "특수 비료"나 "풍성한 씨앗 주머니" 같은 모드 전용 아이템을 팔 수도 있습니다.
4. 추천하는 다음 단계: "성장하는 농부"
지금 바로 거래나 패킷을 복잡하게 넣기보다는, **[레벨업 + 뼛가루 사용]**을 먼저 해보시는 걸 추천합니다.
- 경험치 쌓기: 수확/심기 성공 시마다 내부 변수 xp 상승.
- 뼛가루 보급: 상자에서 씨앗만 가져오는 게 아니라, **뼛가루(Bone Meal)**도 있으면 가져오게 함.
- 성장 촉진: 심을 게 없고 수확할 것도 없을 때, 자라고 있는 작물에 뼛가루 뿌리기.<이거는 좀 복잡해보이는데 [ ]
- 비율 기반 바(Fill Bar): 단순히 텍스트만 띄우는 게 아니라, 현재 경험치 / 현재 레벨 비율을 계산해 노란색 바가 차오르도록 했습니다.
- 실시간 갱신: FarmerHarvestGoal에서 수확/심기 시 sendToTrackingPlayers를 호출하면(이전 코드에 포함됨), 플레이어 화면에서 바가 즉시 늘어납니다.
- 가독성: 검은색 배경 바(fill 메서드 사용)를 먼저 그려서 밝은 곳에서도 글자와 바가 잘 보이게 처리했습니다.
- 효율: TRACKING_ENTITY 배포 방식을 사용하여, 그 농부를 실제로 보고 있는 플레이어들에게만 패킷을 보냅니다. (서버 부하 최소화)

farmer이라는 이름과
농부옷도 입혀주고 싶은데
[ ]
특이한, 주민마다의 이름도 해볼수도 <이건 완전히 랜덤보다는
이미 주어진 배열에서 임의로 뽑아쓰는게 낫겟지 ?
- 언어 관련 (영어/한글):
- 마인크래프트의 폰트 렌더러는 유니코드를 지원합니다. 따라서 영어(Farmer)와 한글(농부) 모두 문제없이 화면에 띄울 수 있습니다.
- 심지어 설정 파일이나 코드에서 한글로 "농부"라고 적어두면 게임 화면에서도 예쁜 한글로 보입니다.
바이옴별 농부 의상 (지능형 옷 입기)
마인크래프트 주민은 원래 **태어난 장소(바이옴)**에 따라 옷의 색깔과 형태가 바뀝니다. 우리 커스텀 농부도 이 시스템을 그대로 따라가게 할 수 있습니다.
- 바이옴 감지:
- 농부가 처음 스폰될 때, 자신이 서 있는 땅의 환경(평원, 사막, 눈 지대, 정글 등)을 체크합니다.
- 텍스처 자동 선택:
- 기존 아처(Archer)는 무조건 한 가지 옷만 입었지만, 농부 렌더러는 **"상태 체크"**를 한 번 더 거칩니다.
- 사막이라면? ▷ 밝은색 사막 주민 옷 + 농부 밀짚모자
- 눈 지대이라면? ▷ 두꺼운 털이 달린 겨울 주민 옷 + 농부 밀짚모자
- 정글이라면? ▷ 나뭇잎 장식이 있는 정글 주민 옷 + 농부 밀짚모자
- 결과: 이렇게 하면 같은 '커스텀 농부' 엔티티라도 사막 마을에 있는 농부와 평원 마을에 있는 농부가 서로 다른 옷을 입고 있게 됩니다. 훨씬 더 '바닐라 마인크래프트'스러운 고퀄리티 연출이 가능해집니다.
뭐 어차피 현재는 평원 지역에서만 스폰되도록 햇긴햇지만
[ ]이름뜨는거, lang에따라 다르게 뜨게할수도잇나
일단 한국어를 기본으로 하자
다른 특성들도 영어로 추가하려면 좀 복잡할듯

오 ㅋ
가끔, 스폰될때
집은 나오는데, 농부는 스폰안되는문제
기다리면 나오려나
메커니즘이 어케 되지
[ ok ]
상자에서 다 가져가지말고, 반큼만 가져가도록

'모딩 > 마인크래프트 모드 개발 일지' 카테고리의 다른 글
| 마크모딩) 선제 타격 ai/ 투사체 물리 판정/ 섹션 탐색 최적화 / 인터페이스 상속 구조 정리 (0) | 2025.12.25 |
|---|---|
| 마크모딩) 사용자정의 법사 만들기(3d 엔티티로) (0) | 2025.12.24 |
| 마크모딩) 스스로 발전하는 마을주민 만들기 #2 (1) | 2025.12.23 |
| 마크모딩) 스스로 발전하는 마을주민 만들기 #1 (1) | 2025.12.22 |
| 마크모딩) 부모 클래스 추상화 / NBT 데이터 영구 저장 / 주민 빵 (1) | 2025.12.22 |