1- import org.gradle.api.GradleException
21import org.gradle.api.tasks.testing.Test
3- import top.ellan.mahjong.build.CraftEngineBundleGenerator
4- import top.ellan.mahjong.build.MahjongCodegen
5- import top.ellan.mahjong.build.NativeBuildSupport
6- import java.io.File
2+ import top.ellan.mahjong.build.MahjongTaskRegistration
73
84plugins {
95 java
@@ -19,12 +15,10 @@ group = "top.ellan"
1915version = " 1.3.0-SNAPSHOT"
2016
2117val minimumPaperDevBundleVersion = " 1.20.1-R0.1-SNAPSHOT"
22- val latestPaperDevBundleVersion = " 26.2-rc-2.build.9-alpha"
23- val supportedPaperApiVersion = " 1.20"
2418val paperDevBundleVersion = providers.gradleProperty(" mahjongPaperDevBundle" )
2519 .orElse(minimumPaperDevBundleVersion)
2620 .get()
27- // Keep plugin descriptors pinned to the lowest supported Paper API so one jar can load on newer Paper versions.
21+ val supportedPaperApiVersion = " 1.20 "
2822val paperApiVersion = supportedPaperApiVersion
2923val javaTargetVersion = providers.gradleProperty(" mahjongJavaTarget" )
3024 .map(String ::toInt)
@@ -41,7 +35,6 @@ val mysqlVersion = "9.7.0"
4135val h2Version = " 2.4.240"
4236val hikariVersion = " 7.1.0"
4337val caffeineVersion = " 3.2.0"
44- // Keep explicit Adventure APIs on the Paper 1.20.1 line so the jar stays runtime-compatible with older servers.
4538val adventureVersion = " 4.14.0"
4639val junitVersion = " 6.1.0"
4740val testcontainersVersion = " 1.21.4"
@@ -55,146 +48,13 @@ repositories {
5548 maven(" https://jitpack.io" )
5649}
5750
58- val generateMessageIndex = tasks.register(" generateMessageIndex" ) {
59- val inputDir = layout.projectDirectory.dir(" src/main/resources" ).asFile
60- val outputFile = generatedResourcesDir.map { it.file(" i18n/_index.json" ) }.get().asFile
61- inputs.dir(inputDir)
62- outputs.file(outputFile)
63- doLast {
64- MahjongCodegen .writeMessageIndex(inputDir, outputFile, " zh-CN" )
65- }
66- }
67-
68- val generateLocalizedConfigs = tasks.register(" generateLocalizedConfigs" ) {
69- val templateFile = layout.projectDirectory.file(" src/main/config-template/config.template.yml" ).asFile
70- val translations = linkedMapOf(
71- " config.yml" to layout.projectDirectory.file(" src/main/config-template/config_comments_en.properties" ).asFile,
72- " config_zh_CN.yml" to layout.projectDirectory.file(" src/main/config-template/config_comments_zh_CN.properties" ).asFile,
73- " config_zh_TW.yml" to layout.projectDirectory.file(" src/main/config-template/config_comments_zh_TW.properties" ).asFile
74- )
75- val outputDir = generatedResourcesDir.get().asFile
76-
77- inputs.file(templateFile)
78- translations.values.forEach { inputs.file(it) }
79- outputs.files(translations.keys.map { outputDir.resolve(it) })
80-
81- doLast {
82- outputDir.mkdirs()
83- val template = templateFile.readText(Charsets .UTF_8 )
84- translations.forEach { (targetFileName, translationFile) ->
85- val rendered = MahjongCodegen .renderTemplateWithTokens(template, MahjongCodegen .loadUtf8Properties(translationFile))
86- outputDir.resolve(targetFileName).writeText(rendered, Charsets .UTF_8 )
87- }
88- }
89- }
90-
91- val verifyMahjongTileResources = tasks.register(" verifyMahjongTileResources" ) {
92- val enumSource = layout.projectDirectory.file(" src/main/java/top/ellan/mahjong/model/MahjongTile.java" ).asFile
93- val itemsDir = layout.projectDirectory.dir(" resourcepack/assets/mahjongcraft/items/mahjong_tile" ).asFile
94- val modelsDir = layout.projectDirectory.dir(" resourcepack/assets/mahjongcraft/models/item/mahjong_tile" ).asFile
95- val texturesDir = layout.projectDirectory.dir(" resourcepack/assets/mahjongcraft/textures/item/mahjong_tile" ).asFile
96- val outputFile = generatedResourcesDir.map { it.file(" resourcepack/mahjong_tile_index.json" ) }.get().asFile
97- inputs.file(enumSource)
98- inputs.dir(itemsDir)
99- inputs.dir(modelsDir)
100- inputs.dir(texturesDir)
101- outputs.file(outputFile)
102- doLast {
103- MahjongCodegen .writeMahjongTileResourceIndex(enumSource, itemsDir, modelsDir, texturesDir, outputFile)
104- }
105- }
106-
107- val generateCraftEngineBundle = tasks.register(" generateCraftEngineBundle" ) {
108- val enumSource = layout.projectDirectory.file(" src/main/java/top/ellan/mahjong/model/MahjongTile.java" ).asFile
109- val resourcepackDir = layout.projectDirectory.dir(" resourcepack" ).asFile
110- val attributionFile = layout.projectDirectory.file(" resourcepack/ATTRIBUTION.md" ).asFile
111- val outputDir = generatedResourcesDir.get().asFile
112- inputs.file(enumSource)
113- inputs.dir(resourcepackDir)
114- inputs.file(attributionFile)
115- outputs.dir(outputDir.resolve(" craftengine" ))
116- doLast {
117- CraftEngineBundleGenerator .writeCraftEngineBundle(enumSource, resourcepackDir, attributionFile, outputDir, project.version.toString())
118- }
119- }
120-
121- val gbNativeSourceDir = layout.projectDirectory.dir(" native/gbmahjong" )
122- val gbNativeBuildDir = layout.buildDirectory.dir(" native/gbmahjong" )
123- val gbNativeCmakeExecutable = NativeBuildSupport .findExecutable(" cmake" )
124- val gbNativeGxxExecutable = NativeBuildSupport .findExecutable(" g++" )
125- val gbNativeNinjaExecutable = NativeBuildSupport .findExecutable(" ninja" )
126- val gbNativeToolchainAvailable = gbNativeCmakeExecutable != null && gbNativeGxxExecutable != null
127- val gbNativeWindowsRuntimeDir = gbNativeGxxExecutable?.let { File (it).parentFile }
128- val gbNativeCurrentOsName = System .getProperty(" os.name" , " " )
129- val gbNativeCurrentArch = System .getProperty(" os.arch" , " " )
130- val gbNativePlatformKey = NativeBuildSupport .nativePlatformKey(gbNativeCurrentOsName, gbNativeCurrentArch)
131- val gbNativeLibraryFileName = NativeBuildSupport .nativeLibraryFileName(gbNativeCurrentOsName)
132-
133- val configureGbMahjongNative = tasks.register<Exec >(" configureGbMahjongNative" ) {
134- group = " build"
135- description = " Configure the JNI GB Mahjong native project with CMake."
136- onlyIf { gbNativeToolchainAvailable }
137- val sourceDir = gbNativeSourceDir.asFile
138- val buildDir = gbNativeBuildDir.get().asFile
139- inputs.dir(sourceDir)
140- outputs.dir(buildDir)
141- doFirst {
142- buildDir.mkdirs()
143- }
144- val command = mutableListOf (
145- gbNativeCmakeExecutable ? : " cmake" ,
146- " -S" , sourceDir.absolutePath,
147- " -B" , buildDir.absolutePath
148- )
149- if (gbNativeNinjaExecutable != null ) {
150- command + = listOf (" -G" , " Ninja" , " -DCMAKE_MAKE_PROGRAM=${gbNativeNinjaExecutable} " )
151- }
152- if (gbNativeGxxExecutable != null ) {
153- command + = listOf (" -DCMAKE_CXX_COMPILER=${gbNativeGxxExecutable} " )
154- }
155- commandLine(command)
156- }
157-
158- val buildGbMahjongNative = tasks.register<Exec >(" buildGbMahjongNative" ) {
159- group = " build"
160- description = " Build the JNI GB Mahjong native project with CMake."
161- dependsOn(configureGbMahjongNative)
162- onlyIf { gbNativeToolchainAvailable }
163- val buildDir = gbNativeBuildDir.get().asFile
164- inputs.dir(gbNativeSourceDir)
165- outputs.dir(buildDir)
166- commandLine(
167- gbNativeCmakeExecutable ? : " cmake" ,
168- " --build" , buildDir.absolutePath,
169- " --config" , " Release"
170- )
171- }
172-
173- val packageGbMahjongNative = tasks.register(" packageGbMahjongNative" ) {
174- group = " build"
175- description = " Copy built GB Mahjong native runtime files into generated resources."
176- dependsOn(buildGbMahjongNative)
177- onlyIf { gbNativeToolchainAvailable }
178- val buildDir = gbNativeBuildDir.get().asFile
179- val outputDir = generatedNativeResourcesDir.get().asFile.resolve(" native/$gbNativePlatformKey " )
180- inputs.dir(buildDir)
181- outputs.dir(outputDir)
182- doLast {
183- outputDir.mkdirs()
184- val library = buildDir.resolve(gbNativeLibraryFileName)
185- if (! library.isFile) {
186- throw GradleException (" Expected GB Mahjong native library at ${library.absolutePath} " )
187- }
188- library.copyTo(outputDir.resolve(library.name), overwrite = true )
189-
190- if (gbNativePlatformKey == " windows-x86_64" ) {
191- val winPthread = gbNativeWindowsRuntimeDir?.resolve(" libwinpthread-1.dll" )
192- if (winPthread?.isFile == true ) {
193- winPthread.copyTo(outputDir.resolve(winPthread.name), overwrite = true )
194- }
195- }
196- }
197- }
51+ // Codegen + native build tasks are registered via buildSrc convention helpers.
52+ val codegenTasks = MahjongTaskRegistration .registerCodegenTasks(
53+ project, generatedResourcesDir, project.version.toString()
54+ )
55+ val nativeTasks = MahjongTaskRegistration .registerNativeTasks(
56+ project, generatedNativeResourcesDir
57+ )
19858
19959dependencies {
20060 paperweight.paperDevBundle(paperDevBundleVersion)
@@ -217,9 +77,6 @@ dependencies {
21777 testImplementation(" org.testcontainers:testcontainers:$testcontainersVersion " )
21878 testImplementation(" org.testcontainers:junit-jupiter:$testcontainersVersion " )
21979 testImplementation(" org.testcontainers:mariadb:$testcontainersVersion " )
220- // Tests follow whichever Adventure version the active paperDevBundle ships with so that
221- // paper-api's compiled-against interfaces (e.g. ComponentDecoder added in Adventure 4.16) resolve
222- // at runtime. Production code is still constrained to the older surface via the compileOnly BOM above.
22380 testImplementation(" net.kyori:adventure-api" )
22481 testImplementation(" net.kyori:adventure-text-minimessage" )
22582 testImplementation(" net.kyori:adventure-text-serializer-plain" )
@@ -256,7 +113,7 @@ tasks {
256113 }
257114
258115 processResources {
259- dependsOn(generateMessageIndex, generateLocalizedConfigs, verifyMahjongTileResources, generateCraftEngineBundle, packageGbMahjongNative )
116+ dependsOn(codegenTasks + nativeTasks )
260117 filteringCharset = Charsets .UTF_8 .name()
261118 inputs.property(" pluginVersion" , project.version.toString())
262119 inputs.property(" paperApiVersion" , paperApiVersion)
@@ -322,16 +179,14 @@ tasks {
322179
323180 check {
324181 dependsOn(jacocoTestReport)
325- dependsOn(verifyMahjongTileResources)
326- dependsOn(generateCraftEngineBundle)
182+ dependsOn(" verifyMahjongTileResources" )
183+ dependsOn(" generateCraftEngineBundle" )
327184 dependsOn(" spotlessCheck" )
328185 dependsOn(" detekt" )
329186 }
330187}
331188
332189spotless {
333- // Ratchet: only enforce formatting on files that changed relative to the
334- // dev branch, so existing code is not reformatted in one giant commit.
335190 ratchetFrom(" origin/dev" )
336191 kotlin {
337192 target(" src/main/kotlin/**/*.kt" , " src/test/kotlin/**/*.kt" , " buildSrc/**/*.kt" )
@@ -343,17 +198,13 @@ spotless {
343198 }
344199 java {
345200 target(" src/main/java/**/*.java" , " src/test/java/**/*.java" )
346- // Remove trailing whitespace and ensure files end with a newline.
347201 trimTrailingWhitespace()
348202 endWithNewline()
349203 }
350204}
351205
352206detekt {
353- // Permissive baseline: existing code has many style issues. New code is
354- // enforced via spotless; detekt focuses on code-smell rules going forward.
355207 buildUponDefaultConfig = true
356208 config.setFrom(files(" $rootDir /config/detekt.yml" ))
357- // Don't fail the build on existing violations; only fail on new severe issues.
358209 ignoreFailures = true
359210}
0 commit comments