diff --git a/build.gradle b/build.gradle index 154bf6b..6b08ef9 100644 --- a/build.gradle +++ b/build.gradle @@ -8,6 +8,8 @@ allprojects { group = project.mod_group version = project.mod_version + // 기본 JDK toolchain 은 Java 25 (26.x Loom 빌드 요구). subproject 가 필요하면 + // 자체 release 21 등으로 다운그레이드. java { toolchain.languageVersion = JavaLanguageVersion.of(25) } @@ -24,7 +26,51 @@ allprojects { } } -// MC 26.1.2 배포물은 Fabric jar 단일 빌드. buildAll = fabric remapJar 결과물. -tasks.register('buildAll') { - dependsOn ':fabric:remapJar' +// ───── 단일 배포 jar 컨테이너 ──────────────────────────────────────────────── +// 한 jar 가 어떤 환경에서도 동작하도록: +// * outer = NeoForge 1.21.6 모드 본체 (NeoForge 만 fabric.mod.json 을 무시) +// + 메타로 fabric.mod.json (entrypoint 없는 컨테이너) +// * META-INF/jars/ = Fabric 용 nested jar 둘 (1.21.6 / 26.1.2) +// Fabric Loader 가 depends.minecraft 로 자동 매칭. NeoForge 는 무시. +// +// 결과: chat_answer-.jar 한 개를 Fabric 1.21.6 / Fabric 26.1.2 / NeoForge +// 1.21.6 어디에 넣어도 적절한 코드 경로가 활성화된다. + +tasks.register('containerJar', Jar) { + dependsOn ':fabric-1216:remapJar', + ':fabric-2612:remapJar', + ':neoforge-1216:jar' + + archiveBaseName = project.mod_id + archiveVersion = project.mod_version + archiveClassifier = '' + destinationDirectory = file('build/libs') + + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + + // 1. NeoForge 모드 본체 (classes + META-INF/neoforge.mods.toml + icon.png) 을 통째로. + // MANIFEST.MF 는 새 jar 가 자체적으로 생성하니 제외. + from(zipTree(project(':neoforge-1216').tasks.named('jar').flatMap { it.archiveFile })) { + exclude 'META-INF/MANIFEST.MF' + } + + // 2. Fabric 컨테이너 메타데이터 (entrypoint 없이 그냥 "외피") 와 아이콘. + // fabric.mod.json 의 ${version} 만 치환. + filteringCharset = 'UTF-8' + from("${rootDir}/container-resources") { + filesMatching("fabric.mod.json") { + expand("version": project.mod_version) + } + } + + // 3. Fabric nested jars (Fabric Loader 가 META-INF/jars/ 를 스캔해서 + // depends.minecraft 매칭되는 jar 만 활성화). + into('META-INF/jars') { + from project(':fabric-1216').tasks.named('remapJar').flatMap { it.archiveFile } + from project(':fabric-2612').tasks.named('remapJar').flatMap { it.archiveFile } + } +} + +tasks.register('buildAll') { + dependsOn 'containerJar' } diff --git a/fabric/src/main/resources/assets/chat_answer/icon.png b/container-resources/assets/chat_answer/icon.png similarity index 100% rename from fabric/src/main/resources/assets/chat_answer/icon.png rename to container-resources/assets/chat_answer/icon.png diff --git a/container-resources/fabric.mod.json b/container-resources/fabric.mod.json new file mode 100644 index 0000000..0d846d5 --- /dev/null +++ b/container-resources/fabric.mod.json @@ -0,0 +1,15 @@ +{ + "schemaVersion": 1, + "id": "chat_answer", + "version": "${version}", + "name": "채팅정답", + "description": "음악퀴즈(mq) 데이터팩이 정답 입력을 받는 상태(init=5)에서 채팅을 가로채 mq:answer/submit 함수로 전달합니다. 단일 jar 에 1.21.6 (Fabric/NeoForge) + 26.1.2 (Fabric) 빌드가 모두 들어있어 어느 환경에서도 그대로 동작합니다.", + "authors": [ "tkrmagid" ], + "license": "MIT", + "icon": "assets/chat_answer/icon.png", + "environment": "*", + "depends": { + "fabricloader": ">=0.16.0", + "java": ">=21" + } +} diff --git a/fabric-1216/build.gradle b/fabric-1216/build.gradle new file mode 100644 index 0000000..2fa4547 --- /dev/null +++ b/fabric-1216/build.gradle @@ -0,0 +1,53 @@ +plugins { + id 'fabric-loom' version '1.16-SNAPSHOT' +} + +base.archivesName = "${project.mod_id}-fabric-1216" + +// 1.21.6 은 Java 21 런타임. release 21 로 컴파일. +java { + toolchain.languageVersion = JavaLanguageVersion.of(25) +} +tasks.withType(JavaCompile).configureEach { + options.release = 21 +} + +// common/ 디렉토리의 로더 비종속 소스 포함. Mojang 매핑으로 컴파일됨. +sourceSets { + main { + java { + srcDirs += "${rootDir}/common/src/main/java" + } + } +} + +dependencies { + minecraft "com.mojang:minecraft:${project.mc_1216}" + mappings loom.officialMojangMappings() + modImplementation "net.fabricmc:fabric-loader:${project.fabric_loader_1216}" + modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_1216}" +} + +loom { + serverOnlyMinecraftJar() +} + +processResources { + inputs.property "version", project.version + inputs.property "mod_id", project.mod_id + + filteringCharset = 'UTF-8' + + filesMatching("fabric.mod.json") { + expand( + "version": project.version, + "mod_id": project.mod_id + ) + } +} + +jar { + from(rootProject.file("LICENSE")) { + rename { "${it}_${project.mod_id}_fabric_1216" } + } +} diff --git a/fabric/src/main/java/kr/tkrmagid/chatanswer/fabric/ChatAnswerFabric.java b/fabric-1216/src/main/java/kr/tkrmagid/chatanswer/fabric/ChatAnswerFabric.java similarity index 100% rename from fabric/src/main/java/kr/tkrmagid/chatanswer/fabric/ChatAnswerFabric.java rename to fabric-1216/src/main/java/kr/tkrmagid/chatanswer/fabric/ChatAnswerFabric.java diff --git a/fabric-1216/src/main/resources/assets/chat_answer/icon.png b/fabric-1216/src/main/resources/assets/chat_answer/icon.png new file mode 100644 index 0000000..080209f Binary files /dev/null and b/fabric-1216/src/main/resources/assets/chat_answer/icon.png differ diff --git a/fabric-1216/src/main/resources/fabric.mod.json b/fabric-1216/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..330af2f --- /dev/null +++ b/fabric-1216/src/main/resources/fabric.mod.json @@ -0,0 +1,20 @@ +{ + "schemaVersion": 1, + "id": "chat_answer_fabric", + "version": "${version}", + "name": "채팅정답 (Fabric impl)", + "description": "음악퀴즈(mq) 데이터팩이 정답 입력을 받는 상태(init=5)에서 채팅을 가로채 mq:answer/submit 함수로 전달합니다. (MC 1.21.6 변형)", + "authors": [ "tkrmagid" ], + "license": "MIT", + "icon": "assets/chat_answer/icon.png", + "environment": "*", + "entrypoints": { + "main": [ "kr.tkrmagid.chatanswer.fabric.ChatAnswerFabric" ] + }, + "depends": { + "fabricloader": ">=0.16.0", + "minecraft": ">=1.21.6 <1.22", + "java": ">=21", + "fabric-api": "*" + } +} diff --git a/fabric-2612/build.gradle b/fabric-2612/build.gradle new file mode 100644 index 0000000..ed8e3a6 --- /dev/null +++ b/fabric-2612/build.gradle @@ -0,0 +1,42 @@ +plugins { + id 'fabric-loom' version '1.16-SNAPSHOT' +} + +base.archivesName = "${project.mod_id}-fabric-2612" + +// common/ 디렉토리의 로더 비종속 소스 포함. +sourceSets { + main { + java { + srcDirs += "${rootDir}/common/src/main/java" + } + } +} + +dependencies { + // MC 26.x: server jar 가 unobfuscated. intermediary 0.0.0 = identity mapping. + minecraft "com.mojang:minecraft:${project.mc_2612}" + mappings "net.fabricmc:intermediary:0.0.0:v2" + implementation "net.fabricmc:fabric-loader:${project.fabric_loader_2612}" + implementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_2612}" +} + +processResources { + inputs.property "version", project.version + inputs.property "mod_id", project.mod_id + + filteringCharset = 'UTF-8' + + filesMatching("fabric.mod.json") { + expand( + "version": project.version, + "mod_id": project.mod_id + ) + } +} + +jar { + from(rootProject.file("LICENSE")) { + rename { "${it}_${project.mod_id}_fabric_2612" } + } +} diff --git a/fabric-2612/src/main/java/kr/tkrmagid/chatanswer/fabric/ChatAnswerFabric.java b/fabric-2612/src/main/java/kr/tkrmagid/chatanswer/fabric/ChatAnswerFabric.java new file mode 100644 index 0000000..587f5b4 --- /dev/null +++ b/fabric-2612/src/main/java/kr/tkrmagid/chatanswer/fabric/ChatAnswerFabric.java @@ -0,0 +1,18 @@ +package kr.tkrmagid.chatanswer.fabric; + +import kr.tkrmagid.chatanswer.core.ChatAnswerCore; +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.message.v1.ServerMessageEvents; +import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; + +public final class ChatAnswerFabric implements ModInitializer { + @Override + public void onInitialize() { + ServerMessageEvents.ALLOW_CHAT_MESSAGE.register((message, sender, params) -> + ChatAnswerCore.handleChat(sender, message.signedContent()) + ); + ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> + ChatAnswerCore.onPlayerJoin(handler.player) + ); + } +} diff --git a/fabric-2612/src/main/resources/assets/chat_answer/icon.png b/fabric-2612/src/main/resources/assets/chat_answer/icon.png new file mode 100644 index 0000000..080209f Binary files /dev/null and b/fabric-2612/src/main/resources/assets/chat_answer/icon.png differ diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric-2612/src/main/resources/fabric.mod.json similarity index 80% rename from fabric/src/main/resources/fabric.mod.json rename to fabric-2612/src/main/resources/fabric.mod.json index 435456a..bde180c 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric-2612/src/main/resources/fabric.mod.json @@ -1,9 +1,9 @@ { "schemaVersion": 1, - "id": "${mod_id}", + "id": "chat_answer_fabric", "version": "${version}", - "name": "채팅정답", - "description": "음악퀴즈(mq) 데이터팩이 정답 입력을 받는 상태(init=5)에서 채팅을 가로채 mq:answer/submit 함수로 전달합니다.", + "name": "채팅정답 (Fabric impl)", + "description": "음악퀴즈(mq) 데이터팩이 정답 입력을 받는 상태(init=5)에서 채팅을 가로채 mq:answer/submit 함수로 전달합니다. (MC 26.1.2 변형)", "authors": [ "tkrmagid" ], "license": "MIT", "icon": "assets/chat_answer/icon.png", diff --git a/fabric/build.gradle b/fabric/build.gradle deleted file mode 100644 index 6fe61ff..0000000 --- a/fabric/build.gradle +++ /dev/null @@ -1,70 +0,0 @@ -plugins { - id 'fabric-loom' version '1.16-SNAPSHOT' - id 'com.gradleup.shadow' version '9.4.1' -} - -base.archivesName = "${project.mod_id}-fabric" - -// common/ 디렉토리의 로더 비종속 소스를 fabric 컴파일에 포함 (Mojang 매핑으로 컴파일) -sourceSets { - main { - java { - srcDirs += "${rootDir}/common/src/main/java" - } - } -} - -dependencies { - // MC 26.x: server jar 가 unobfuscated. intermediary 0.0.0 = identity mapping. - minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:intermediary:0.0.0:v2" - implementation "net.fabricmc:fabric-loader:${project.loader_version}" - implementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" -} - -processResources { - inputs.property "version", project.version - inputs.property "mod_id", project.mod_id - inputs.property "mod_name", project.mod_name - - filteringCharset = 'UTF-8' - - filesMatching("fabric.mod.json") { - expand( - "version": project.version, - "mod_id": project.mod_id, - "mod_name": project.mod_name - ) - } -} - -jar { - from(rootProject.file("LICENSE")) { - rename { "${it}_${project.mod_id}" } - } -} - -// ───── relocation for single-jar merge ───────────────────────────────────── -// Fabric 의 common 코드는 intermediary 매핑으로 컴파일되고, NeoForge 의 common -// 코드는 Mojang 매핑으로 컴파일된다. 둘은 바이트코드가 달라서 같은 클래스 경로에 -// 공존 불가. Shadow 의 relocate 로 Fabric 쪽 common 클래스만 별도 패키지로 옮겨서 -// merged jar 안에서 충돌하지 않게 한다. -// -// 진행 순서: loom 의 remapJar 결과 → shadowJar 가 받아서 패키지 재배치 → -// rootProject 의 mergedJar 가 이걸 사용. - -// Shadow 가 자동으로 만든 shadowJar 는 main sourceSet + 런타임 classpath 를 전부 -// 포함해서 100MB+ 가 되어버린다. 우리한테 필요한 건 "remapJar 결과물에 relocate 만 -// 적용한 작은 jar" 이므로, 별도 ShadowJar 태스크를 새로 만들어서 입력을 명시적으로 -// remapJar 의 zipTree 만 지정한다. -tasks.register('relocatedJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { - dependsOn 'remapJar' - archiveClassifier = 'relocated' - from zipTree(tasks.named('remapJar').flatMap { it.archiveFile }) - relocate 'kr.tkrmagid.chatanswer.core', 'kr.tkrmagid.chatanswer.fabric.core' - mergeServiceFiles() -} - -tasks.named('build') { - dependsOn 'relocatedJar' -} diff --git a/gradle.properties b/gradle.properties index c98824e..d4567d0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,20 +1,26 @@ org.gradle.jvmargs=-Xmx3G org.gradle.parallel=true -# ───── target Minecraft / loader versions ─────────────────────────────────── -# MC 26.1.2 = 사용자 환경. 1.21.6 과는 intermediary 매핑이 달라서 동일 jar 로 양쪽 -# 지원 불가 → 26.1.2 전용 빌드. -minecraft_version=26.1.2 - -# Fabric -loader_version=0.19.2 -fabric_version=0.148.2+26.1.2 - -# NeoForge -neoforge_version=26.1.2.36-beta - # ───── mod metadata ───────────────────────────────────────────────────────── mod_id=chat_answer -mod_version=1.2.1 +mod_version=1.3.0 mod_group=kr.tkrmagid.chatanswer mod_name=채팅정답 + +# ───── per-target MC / loader versions ────────────────────────────────────── +# 한 jar 로 1.21.6 (Fabric/NeoForge) + 26.1.2 (Fabric) 전부 커버하기 위해 +# 각 타겟마다 별도 subproject 가 자기 버전으로 빌드되고, 결과물을 outer +# container jar 가 묶는다 (Fabric 은 META-INF/jars/ JiJ, NeoForge 는 outer 본체). + +# Fabric MC 1.21.6 +mc_1216=1.21.6 +fabric_api_1216=0.128.2+1.21.6 +fabric_loader_1216=0.16.10 + +# Fabric MC 26.1.2 (26.x 서버 jar 는 unobfuscated. intermediary 0.0.0 = identity) +mc_2612=26.1.2 +fabric_api_2612=0.148.2+26.1.2 +fabric_loader_2612=0.19.2 + +# NeoForge MC 1.21.6 (26.x 는 NeoForge moddev plugin 이 아직 인식 못 함) +neoforge_1216=21.6.20-beta diff --git a/neoforge-1216/build.gradle b/neoforge-1216/build.gradle new file mode 100644 index 0000000..1d6efdb --- /dev/null +++ b/neoforge-1216/build.gradle @@ -0,0 +1,49 @@ +plugins { + id 'net.neoforged.moddev' version '2.0.97' +} + +base.archivesName = "${project.mod_id}-neoforge-1216" + +// NeoForge 1.21.6 은 Java 21. release 21 로 컴파일. +java { + toolchain.languageVersion = JavaLanguageVersion.of(25) +} +tasks.withType(JavaCompile).configureEach { + options.release = 21 +} + +sourceSets { + main { + java { + srcDirs += "${rootDir}/common/src/main/java" + } + } +} + +neoForge { + version = project.neoforge_1216 +} + +processResources { + inputs.property "version", project.version + inputs.property "mod_id", project.mod_id + inputs.property "minecraft_version", project.mc_1216 + inputs.property "neoforge_version", project.neoforge_1216 + + filteringCharset = 'UTF-8' + + filesMatching("META-INF/neoforge.mods.toml") { + expand( + "version": project.version, + "mod_id": project.mod_id, + "minecraft_version": project.mc_1216, + "neoforge_version": project.neoforge_1216 + ) + } +} + +jar { + from(rootProject.file("LICENSE")) { + rename { "${it}_${project.mod_id}_neoforge_1216" } + } +} diff --git a/neoforge/src/main/java/kr/tkrmagid/chatanswer/neoforge/ChatAnswerNeoForge.java b/neoforge-1216/src/main/java/kr/tkrmagid/chatanswer/neoforge/ChatAnswerNeoForge.java similarity index 100% rename from neoforge/src/main/java/kr/tkrmagid/chatanswer/neoforge/ChatAnswerNeoForge.java rename to neoforge-1216/src/main/java/kr/tkrmagid/chatanswer/neoforge/ChatAnswerNeoForge.java diff --git a/neoforge/src/main/resources/META-INF/neoforge.mods.toml b/neoforge-1216/src/main/resources/META-INF/neoforge.mods.toml similarity index 76% rename from neoforge/src/main/resources/META-INF/neoforge.mods.toml rename to neoforge-1216/src/main/resources/META-INF/neoforge.mods.toml index 8191595..5d7db34 100644 --- a/neoforge/src/main/resources/META-INF/neoforge.mods.toml +++ b/neoforge-1216/src/main/resources/META-INF/neoforge.mods.toml @@ -1,15 +1,14 @@ modLoader = "javafml" loaderVersion = "[1,)" license = "MIT" -issueTrackerURL = "https://git.tkrmagid.kr/tkrmagid/mc_chat_answer_mod/issues" [[mods]] modId = "${mod_id}" version = "${version}" -displayName = "${mod_name}" +displayName = "채팅정답" authors = "tkrmagid" description = '''음악퀴즈(mq) 데이터팩이 정답 입력을 받는 상태(init=5)에서 채팅을 가로채 mq:answer/submit 함수로 전달합니다.''' -displayURL = "https://git.tkrmagid.kr/tkrmagid/mc_chat_answer_mod" +logoFile = "icon.png" [[dependencies.${mod_id}]] modId = "neoforge" diff --git a/neoforge-1216/src/main/resources/icon.png b/neoforge-1216/src/main/resources/icon.png new file mode 100644 index 0000000..080209f Binary files /dev/null and b/neoforge-1216/src/main/resources/icon.png differ diff --git a/neoforge/build.gradle b/neoforge/build.gradle deleted file mode 100644 index 1e12ceb..0000000 --- a/neoforge/build.gradle +++ /dev/null @@ -1,41 +0,0 @@ -plugins { - id 'net.neoforged.moddev' version '2.0.97' -} - -base.archivesName = "${project.mod_id}-neoforge" - -sourceSets { - main { - java { - srcDirs += "${rootDir}/common/src/main/java" - } - } -} - -neoForge { - version = project.neoforge_version -} - -processResources { - inputs.property "version", project.version - inputs.property "mod_id", project.mod_id - inputs.property "mod_name", project.mod_name - inputs.property "minecraft_version", project.minecraft_version - inputs.property "neoforge_version", project.neoforge_version - - filesMatching("META-INF/neoforge.mods.toml") { - expand( - "version": project.version, - "mod_id": project.mod_id, - "mod_name": project.mod_name, - "minecraft_version": project.minecraft_version, - "neoforge_version": project.neoforge_version - ) - } -} - -jar { - from(rootProject.file("LICENSE")) { - rename { "${it}_${project.mod_id}" } - } -} diff --git a/settings.gradle b/settings.gradle index c1b2c30..119f93f 100644 --- a/settings.gradle +++ b/settings.gradle @@ -8,5 +8,9 @@ pluginManagement { } rootProject.name = 'chat_answer' -// NeoForge moddev plugin 이 MC 26.1.2 를 파싱하지 못함(1.21.5 로 fallback) → 26.x 정식 지원 전까지 제외. -include 'fabric' + +// 세 개의 target-specific subproject. 각각 자기 MC/로더 버전으로 컴파일/리맵. +// rootProject 의 containerJar 가 셋의 산출물을 하나로 묶어 단일 jar 배포물 생성. +include 'fabric-1216' +include 'fabric-2612' +include 'neoforge-1216'