이전 v1.3.2: onPlayerJoin 에서 storage chat_answer:status active=1b 를 set.
하지만 통합 서버 (integrated singleplayer) 에서 데이터팩의 mq:load 가
player join 이후에 도는 케이스가 있어 모드가 써놓은 1b 를 데이터팩이
0b 로 덮어쓰는 race 가 있었고, repeat/players 의 첫 tick 체크 시점에
이미 0b 라서 알림 메세지가 안 떴음.
v1.3.3: storage flag 자체를 폐기. onPlayerJoin 에서
execute as <uuid> at @s run function mq:players/mod_active_notice
를 호출. 데이터팩이 메세지 텍스트를 정의하고, 모드는 "지금 들어온 이
플레이어에게 보여라" 만 트리거한다. 데이터팩 자체가 없으면 함수가 없어
suppressed source 의 command 실패로 silent → 안전.
데이터팩(music_quiz) 도 동일 커밋으로 함수 추가 및 flag 제거됨.
증상: chat_answer:status active 가 0b 그대로 → 데이터팩 login 메시지 안 뜸.
mq:load 는 정상 작동(0b 초기화 됨)인데 모드의 onPlayerJoin 이 1b 로 안 씀.
추가 로그:
- ChatAnswerFabric.onInitialize: 진입/완료, event register 예외시 ERROR
- ChatAnswerCore.onPlayerJoin: 진입 (player 이름 포함), 성공 시 INFO,
실패 catch 를 LOG.debug → LOG.warn 으로 승격해 latest.log 에 보이게.
이 로그를 보고 다음 중 어디서 깨지는지 좁힐 수 있음:
- "Fabric entrypoint onInitialize starting" 안 보임 → nested jar 미로드
- "onInitialize starting" 보이고 "registered" 안 보임 → fabric-api ABI mismatch
- "onPlayerJoin fired" 안 보임 → JOIN 이벤트 미발화
- "active=1b set" 안 보이고 "failed" 만 보임 → command 실행 실패
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.3.0 의 nested fabric jar 가 실제로 로드되지 않던 버그 수정.
Fabric Loader 는 META-INF/jars/ 디렉토리를 자동 스캔하지 않고, 부모 jar 의
fabric.mod.json 에 "jars" 배열로 명시된 파일만 처리한다. v1.3.0 에선 jars
배열이 비어 있어서 outer chat_answer 컨테이너만 로드되고 (entrypoint 없으니
no-op), 실제 채팅 hook 을 담은 nested fabric jar 는 그대로 무시됐다.
수정:
- container-resources/fabric.mod.json: "jars" 배열에 두 nested 경로 명시
- root build.gradle: containerJar 의 nested jar 파일명을 버전 suffix 없는
고정 이름 (chat_answer-fabric-1216.jar / -2612.jar) 으로 변경. outer
fabric.mod.json 의 jars 항목과 일치해야 Fabric Loader 가 찾는다.
증상: 음악퀴즈 데이터팩 맵 접속 시 "모드 활성화" 메시지 안 뜸
(ServerPlayConnectionEvents.JOIN 이 실행 안 되어 storage chat_answer:status
active 가 0b 로 유지).
원인: 위와 같이 nested jar 가 로드 안 됨.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
이전엔 1.21.6 (v1.1.1) 와 26.1.2 (v1.2.1) 가 분리된 jar 였음. 사용자 입장에서
버전별로 다른 파일을 받아야 했고 합친 의미가 없어서, 한 jar 가 어느 환경에든
들어갈 수 있도록 컨테이너 구조로 재작업.
구조:
- outer chat_answer-1.3.0.jar
├── fabric.mod.json (entrypoint 없는 컨테이너 메타. MC dep 없음.)
├── META-INF/neoforge.mods.toml (NeoForge 1.21.6 모드 본체 메타)
├── kr/.../neoforge/ (NeoForge 1.21.6 entry + core, Mojang 매핑)
├── kr/.../core/ (NeoForge 가 쓰는 공유 core 사본)
└── META-INF/jars/ (Fabric Loader 가 자동 스캔)
├── chat_answer-fabric-1216-1.3.0.jar (MC ">=1.21.6 <1.22")
└── chat_answer-fabric-2612-1.3.0.jar (MC ">=26.1.2")
로더별 동작:
- Fabric 1.21.6 → outer 는 no-op 컨테이너, 1216 nested 가 활성 (intermediary class_NNNN 리매핑됨)
- Fabric 26.1.2 → outer 는 no-op 컨테이너, 2612 nested 가 활성 (intermediary 0.0.0 identity)
- NeoForge 1.21.6 → outer 의 NeoForge entry 가 동작. Fabric 메타와 nested jars 는 NeoForge 가 무시.
핵심 트레이드오프:
- 1.21.6 fabric subproject 는 modImplementation 필수 (intermediary 매핑 리맵 필요)
- 26.1.2 fabric subproject 는 implementation 으로 충분 (서버 jar unobfuscated → identity 매핑)
- 26.1.2 NeoForge 는 moddev plugin 이 아직 26.x 를 파싱 못 함 → 1.21.6 만 지원
- 두 nested fabric jar 는 mod id 동일 (chat_answer_fabric) — depends.minecraft 가 상호 배타라
한 환경에서 둘이 동시 candidate 가 되지 않으므로 충돌 없음.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Embed music quiz icon at assets/chat_answer/icon.png; reference from
fabric.mod.json so ModMenu shows it.
- Remove contact.homepage (private Gitea — owner-only).
User reported NoClassDefFoundError: net/minecraft/class_7471 on MC 26.1.2.
Root cause: v1.1.1 was built for 1.21.6 intermediary, which uses
class_NNNN obfuscated names. MC 26.x ships an unobfuscated server jar
with Mojang names directly, so intermediary lookups for class_7471
(=PlayerChatMessage in 1.21.6) fail at runtime.
Build retargeted to 26.1.2:
- minecraft 26.1.2 / loader 0.19.2 / fabric-api 0.148.2+26.1.2
- Loom 1.16-SNAPSHOT, Shadow 9.4.1 (Java 25 bytecode support)
- Gradle 9.5.1, JDK 25 toolchain
- Drop officialMojangMappings(); use intermediary:0.0.0 identity
(Mojang stopped publishing proguard mappings for 26.x).
- Adapt code: ServerPlayer.getServer() removed in 26.1.2 → use
player.level().getServer() (ServerPlayer.level() returns ServerLevel).
- NeoForge dropped from this build — moddev plugin can't parse 26.1.2
yet, falls back to 1.21.5.
- 1.2.0 = Fabric only; 1.21.6 users stay on 1.1.1.
fabric.mod.json 의 environment 가 "server" 라 client 설치에선 Fabric Loader
가 모드를 건너뛰어 ModMenu 에 안 나타나는 문제. "*" 로 바꿔서 client (싱글
플레이 integrated server 포함) + dedicated server 양쪽에서 로드되게 함.
NeoForge 쪽도 side = "BOTH" 로 변경. 실제 로직은 변함없이 server 측 채팅
이벤트만 hook 하므로 client 단독에서는 no-op.
ChatAnswerCore.onPlayerJoin 이 storage chat_answer:status active=1b 를 set.
Fabric 측은 ServerPlayConnectionEvents.JOIN, NeoForge 측은 PlayerLoggedInEvent
에서 호출. 데이터팩이 mq:load 단계에서 0b 로 clear 해 두므로, 모드가 빠진
환경에선 이 hook 이 일어나지 않아 0b 가 유지되고, 모드가 있으면 첫 로그인
직후 1b 로 갱신되어 데이터팩이 활성 상태를 분기할 수 있다.
common 디렉토리에 로더 비종속 ChatAnswerCore 를 두고, fabric/ 과 neoforge/
서브프로젝트가 각자 진입점만 갖도록 분리. 두 결과물을 하나의 jar 로 묶기 위해
Fabric 측 common 클래스를 Shadow 의 relocate 로 kr.tkrmagid.chatanswer.fabric.core
패키지로 옮긴다 (Fabric 은 intermediary, NeoForge 는 Mojang 매핑이라 같은 클래스
경로에 그대로 두면 충돌). 루트의 mergedJar 태스크가 :fabric:relocatedJar 와
:neoforge:jar 를 합쳐서 build/libs/chat_answer-<version>-all.jar 생성.
산출물: 9.9KB 통합 jar 가 Fabric / NeoForge 양쪽에서 작동.
Hooks ServerMessageEvents.ALLOW_CHAT_MESSAGE to intercept chat while the
music_quiz datapack is in answer-accepting state (init=5 on objective
'main'). Intercepted messages are forwarded to mq:answer/submit with the
player's UUID context and the chat broadcast is suppressed so the answer
stays hidden from other players. Outside that state chat passes through
normally.
Target: Minecraft 1.21.6+, Java 21, Fabric Loader 0.16+, Fabric API.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>