1. 프로젝트 정체성
이 프로젝트는 기존 Stime Mod와 별개의 신규 프로젝트다.
- 프로젝트명:
Stime Seasonal War - Minecraft:
26.3 - 플랫폼: Fabric 서버사이드 모드
- 메인 패키지:
dev.stime.seasonal - Mod ID:
stime-seasonal-war
기존 Stime Mod의 길드/경제/Stock/상점/영토 구매/동맹/용병/NPC 시스템은 가져오지 않는다.
기존 프로젝트는 유지하고, 이 프로젝트 디렉터리 안에서만 작업한다.
2. 기술 스택
- Minecraft 26.3
- Fabric Loader 0.19.5
- Fabric API 0.162.0+26.3
- Loom 1.18.2
- Gradle 9.7.1
- Java 25
- Mojang unobfuscated names 사용
- Yarn mappings 미사용
서버사이드 전용이다.
클라이언트에 별도 Fabric 모드를 요구하지 않으며, Geyser/Floodgate 환경의 Bedrock 유저도 고려한 구조다.
사용하면 안 되는 것:
- 클라이언트 전용 모드 의존
- 커스텀 패킷
- 커스텀 클라이언트 화면
- Keybind
- Client Rendering
플레이어 식별은 서버에서 보이는 UUID를 기준으로 한다.
3. 작업 전 필독 문서
가장 먼저 읽을 문서:
docs/PROJECT_REFERENCE.md
세부 작업에 따라 아래 문서를 참고한다.
게임 규칙 / 코어 / 전쟁
docs/GAMEPLAY_REFERENCE.md
데이터 / JSON / 저장 / Rollback
docs/DATA_AND_PERSISTENCE.md
명령어 / 권한 / 관리자 GUI
docs/COMMANDS_AND_GUI_REFERENCE.md
Fabric Hook / Entity / Mixin / Runtime 문제
docs/SERVER_RUNTIME_AND_DEBUGGING.md
테스트 / 검증
docs/VERIFICATION_MATRIX.md
기존 전체 코드 리뷰
docs/CONSOLIDATED_REVIEW_2026-10-12.md
여기에는 기존 리뷰 Finding F01 ~ F60과 수정/유지/검증 결과가 기록돼 있다.
이미 해결된 Finding을 다시 수정하기 전에 반드시 확인한다.
4. 문서와 실제 구현의 관계
문서는 현재 구현 상태와 알려진 제한사항을 기록한다.
하지만 문서에 적힌 현재 구현상의 제한을 임의로 새로운 게임 규칙으로 해석하면 안 된다.
코드 수정 전에는:
- 관련 문서 확인
- 실제 해당 Source Method 확인
- 기존 Review Finding 확인
- 수정
- 테스트
- 대응 문서 업데이트
순서로 진행하는 것을 기본으로 한다.
5. 코어 기본 규칙
코어 강화 단계는 정확히 Lv.0 ~ Lv.3이다.
- Lv.0: 800 HP
- Lv.1: 1200 HP
- Lv.2: 1600 HP
- Lv.3: 2000 HP
강화 비용은 다음 단계로 올라갈 때마다 실제 다이아를 소모한다.
- Lv.0 → Lv.1: 다이아 64개
- Lv.1 → Lv.2: 다이아 128개
- Lv.2 → Lv.3: 다이아 192개
즉 14단계가 아니라 **03단계**다.
6. 코어의 권위 데이터
코어와 국가의 실제 권위 데이터는 JSON이다.
주요 데이터:
- Core HP
- Core 위치
- Core 강화 레벨
- 국가 멤버
- 국가 상태
- 시즌/전쟁 상태
바닐라 엔티티 자체의 상태를 권위 데이터로 취급하지 않는다.
특히 바닐라 Iron Golem의:
- 실제 Vanilla Health
- 엔티티 존재 여부
만으로 국가 멸망을 판정하면 안 된다.
7. 코어 파괴 판정
WAR 중 최초의 정상적인 치명타 1회만 전쟁 종료를 발생시킨다.
단순히 코어 엔티티가:
- 사라짐
- 제거됨
- 언로드됨
- 로딩되지 않음
같은 상황만으로 국가가 멸망하면 안 된다.
Core Entity 제거와 정상적인 HP 0 파괴는 반드시 구분한다.
8. Core 생성 / 복구 주의사항
새 Core UUID는 반드시 엔티티를 월드에 추가하기 전에 저장해야 한다.
순서상 중요한 부분:
Core UUID 저장
→
addFreshEntity
Fabric의 Entity Load Callback이 동기식이기 때문에 순서를 바꾸면 복구 로직에서 문제가 생길 수 있다.
또한 Core가 없다고 판단하기 전에 해당 청크의 저장된 Entity NBT 로딩을 기다려야 한다.
사용되는 흐름:
waitForEntities(chunk, 0)
이 과정 없이 바로 "코어 없음"으로 판단하면 중복 코어가 생성될 수 있다.
9. 국가 인원 밸런스
밸런스 계산에는 ACTIVE 국가만 포함한다.
플레이어가 자발적으로 국가를 선택했을 때 예상 결과가:
최대 국가 인원 - 최소 국가 인원 >= 2
가 되면 가입을 거부한다.
즉 정상적으로 허용되는 최대 인원 차이는 1명이다.
멸망한 국가는 계산에서 제외한다.
10. 안전구역
안전구역은 청크 전체 높이가 아니다.
정확히 다음 요소로 구성된다.
- Dimension
- Chunk X
- Chunk Z
- minY
- maxY
그리고 minY / maxY는 둘 다 포함된다.
즉 해당 1×1 청크에서도 지정된 Y 범위만 안전구역이다.
이 규칙은 OneChunk Survival처럼 안전청크 전체를 무적 창고/시설로 사용하는 것을 방지하기 위한 의도된 설계다.
11. PREPARATION의 영토 제한
일반 안전구역 판정은 Y 범위를 사용하지만, PREPARATION 상태의 적국 영토 출입 제한은 다르다.
PREPARATION에서는:
- 적국 Territory의 X/Z 영역 전체를 검사
- Y는 무시
즉 지하로 파서 적국 영토에 들어가는 식의 우회가 불가능해야 한다.
12. 코어와 안전구역 겹침
코어의 3×3×3 본체 영역은 ACTIVE 국가의 안전구역과 겹치면 안 된다.
예외 설정:
allowCoreInSafeZone
이 활성화된 경우만 허용한다.
테스트에서도 안전청크 바로 옆 청크 등에 코어를 배치하는 이유가 이것이다.
13. 관리자 명령어 / GUI
명령어와 GUI는 반드시 같은 Service Layer를 사용한다.
예를 들어 GUI에서 코어 강화 버튼을 눌러도 GUI 내부에서 강화 로직을 직접 구현하지 않는다.
GUI:
Core upgrade 클릭
→
공통 Service 호출
명령어도 같은 Service 호출.
그래야 Java / Bedrock / 명령어 / GUI 사이에서 게임 규칙이 달라지지 않는다.
14. 오래 열린 GUI 처리
GUI는 열었을 당시 상태가 최신이라는 보장이 없다.
따라서 실제 실행 직전에 다시 확인해야 한다.
예:
- 아직도 해당 국가 리더인지
- 아직 같은 국가인지
- 현재 코어 강화 단계가 맞는지
- 현재 게임 상태에서 가능한 행동인지
Stale Confirmation을 그대로 실행하면 안 된다.
15. Rollback 주의사항
SeasonEngine.transaction rollback은 가장 바깥쪽 SeasonData 객체는 유지한다.
하지만 내부의:
- Nation
- CoreData
- 기타 Nested Value
는 교체될 수 있다.
따라서 Transaction 실패 이후 기존에 보관하고 있던 Nation/CoreData 참조를 그대로 사용하면 안 된다.
실패 후에는 항상 최신 객체를 다시 조회한다.
16. 서로 다른 저장 영역
다음은 서로 다른 저장 영역이다.
- Mod JSON State
- Vanilla Player Inventory
- Vanilla Ban List
따라서 이 세 가지가 하나의 완전한 Crash-Atomic Transaction으로 저장된다고 주장하면 안 된다.
예를 들어 플레이어 추방 과정에서:
- Mod 데이터 변경
- Ban 처리
등은 서로 다른 저장 시스템이다.
테스트와 문서에서도 이 차이를 유지한다.
17. Geyser 검증 범위
Unit Test나 Fabric GameTest가 통과했다고 해서 실제 Bedrock Client 검증까지 끝났다고 주장하면 안 된다.
구분:
- Unit Test 성공
- GameTest 성공
- Source Inspection
- 실제 Java Client 테스트
- 실제 Bedrock + Geyser 테스트
각각 다른 수준의 Evidence다.
Bedrock 실제 플레이 검증을 하지 않았다면 "Geyser에서 확실히 검증 완료"라고 표현하면 안 된다.
18. Safe Zone Automation 보호
안전구역 보호에는 플레이어뿐 아니라 자동화 영향도 포함된다.
주요 대상:
- Hopper
- Dispenser
- Piston
- Fluid
- Fire
- Falling Block
- Chest Pairing
판정 원칙은:
효과가 시작된 보호 Volume과 효과가 도착하는 Volume을 비교한다.
다만 같은 안전구역 안에서 정상적으로 동작하는 자동화까지 막으면 안 된다.
따라서 모든 보호 테스트에는 정상적인 unprotected control 또는 허용되는 동일 구역 동작 사례가 있어야 한다.
19. Piston Mixin 주의
Piston 보호 로직은 moveBlocks의 HEAD에 Inject하면 안 된다.
Vanilla가 PistonStructureResolver를 생성하는 지점에서 판정해야 한다.
Retracting Piston에서는 자기 Piston Head 때문에 더 이른 Resolve가 발생할 수 있어서, moveBlocks HEAD 방식은 보호 로직이 조용히 우회될 수 있다.
이 부분은 이미 리뷰에서 확인된 중요한 Runtime 조건이다.
20. Entity 위치 판정
Living Entity와 Non-Living Entity의 안전구역 판정 방식이 다르다.
Living Entity
정확한 발 위치를 사용한다.
특히 Y값을 floor해서 사용하지 않는다.
Non-Living Entity
Block Position 기준으로 판정한다.
Living Entity의 Y를 임의로 정수화하면 안전구역 경계에서 판정 오류가 생길 수 있다.
21. 연속 피격 테스트 주의
Minecraft의 반복 피격 쿨다운은:
LivingEntity.damageCooldownTime
을 사용한다.
setInvulnerableTime(0)만 호출한다고 해서 독립적인 다음 타격이 정상적으로 테스트되는 것은 아니다.
연속 독립 타격 테스트에서는 해당 Damage Cooldown 상태까지 초기화해야 한다.
22. 현재 의도적으로 유지하는 게임 규칙
사용자가 명시적으로 변경하기 전까지 다음은 의도된 규칙이다.
- 국가 추방 시 영구 Ban
- 국가 가입 인원 밸런스 엄격 적용
- 리더는 자동 선거가 아니라 관리자 지정
- WAR 중 로그인 시 자기 국가 안전구역에서 시작
- 안전구역은 얕은 Y 범위
- 일반 국가 영토는 약탈 가능
- 환경 데미지도 Core에 적용 가능
- 정상적으로 적용된 Core Hit마다 동기식 Save 1회 수행
이 항목을 "성능상 이상하다" 또는 "보통 다른 서버와 다르다"는 이유만으로 임의 수정하지 않는다.
23. 현재 모드 범위가 아닌 것
이 프로젝트에서 구현하지 않는다.
- Nether 차단
- End 차단
- TNT 조합법 제한
- TNT Minecart 조합법 제한
- 자동 Farm 감지
- World Reset
- Season 자동 초기화
- Vault Gameplay
이 기능들은 다른 시스템이 담당하거나 추후 별도 구현 대상이다.
24. Git 작업 주의
실제 Git Top-Level이 프로젝트 폴더가 아니라 다음 상위 경로로 잡힐 수 있다.
C:/Users/hhajj
이 상위 경로에는 이 프로젝트와 무관한 파일이 포함될 수 있다.
따라서 Git 명령 전에 반드시 Scope를 확인한다.
특히 상위 경로에서 다음을 함부로 실행하지 않는다.
git statusgit add .- 전체 Commit
- 전체 Reset/Clean
- 기타 광범위 Git 작업
Sibling인 Stime Mod나 사용자 홈 파일을 이 프로젝트 일부로 취급하면 안 된다.
25. 테스트 명령어
PowerShell + 프로젝트에 포함된 Gradle Wrapper 기준.
Unit Test:
.\gradlew.bat test --console=plain
Server GameTest:
.\gradlew.bat runGameTest --console=plain
전체 Build:
.\gradlew.bat build --console=plain --warning-mode all
build는 check를 통해 설정된 Server GameTest도 실행한다.
26. GameTest 환경
기본 GameTest 월드는 다음 아래에 격리된다.
build/gametest-runs/<UUID>
Test Preparation에서 다음 설정이 사용될 수 있다.
online-mode=false- Flat Test World
spawn-protection=0
이 설정은 테스트 전용이다.
실제 배포 서버 설정으로 해석하면 안 된다.
Restart Test용 재사용 월드와 Marker도 Production World와 혼동하면 안 된다.
27. 테스트 / 빌드 보고 원칙
문서만 수정한 경우 무조건 전체 Minecraft Server Build를 돌릴 필요는 없다.
대신:
- 링크
- 예시
- Source Claim
- 문서간 일관성
을 검증한다.
코드를 수정한 경우에는:
- 영향받은 관련 테스트
- 필요한 GameTest
- 최종 전체 Build
를 수행한 뒤 성공 여부를 보고한다.
그리고 보고할 때 반드시 구분한다.
- 이번에 실제 실행한 테스트
- 과거 Archive Evidence
- Source Inspection
- 아직 실제 배포에서 검증하지 않은 내용
28. 개발자용 핵심 한 줄
Stime Seasonal War는 Minecraft 26.3 Fabric 기반의 독립적인 서버사이드 시즌제 국가 전쟁 모드이며, JSON 데이터를 권위 상태로 사용하는 국가/코어/전쟁/안전구역 시스템이 이미 구현된 상태다. 현재 작업의 핵심은 기존 Gameplay Contract와 Persistence/Runtime/Test Contract를 깨지 않으면서 유지보수하고 확장하는 것이다.
그리고 작업 시작할 때는 무조건:
docs/PROJECT_REFERENCE.md 먼저 읽기 → 변경 영역별 Reference 확인 → 실제 Source 확인 → 기존 F01~F60 Review 확인
순서로 보면 됨.