1+ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
12import java.io.FileOutputStream
23import java.io.IOException
34import java.util.jar.JarEntry
45import java.util.jar.JarFile
56import java.util.jar.JarOutputStream
67
7- plugins{
8+ plugins {
89 id(" eternalcode.java" )
910 id(" com.gradleup.shadow" )
1011 id(" xyz.jpenilla.run-paper" ) version " 3.0.2"
1112}
1213
13- tasks.create( " shadowAll " ) {
14- group = " shadow "
14+ tasks.register< ShadowJar >( " shadowChatFormatter " ) {
15+ this . group = " build "
1516
16- val projects = listOf (
17+ val targetProjects = listOf (
1718 project(" :chatformatter-core" ),
1819 project(" :chatformatter-paper-plugin" )
1920 )
2021
21- for (project in projects ) {
22- dependsOn(project .name + " :shadowJar" )
22+ for (targetProject in targetProjects ) {
23+ this . dependsOn(" ${targetProject .name} :shadowJar" )
2324 }
2425
25- doLast {
26- merge(" ChatFormatter v${project.version} .jar" , projects)
26+ this .doLast {
27+ this @register.mergeJars(
28+ " ChatFormatter v${project.version} .jar" ,
29+ targetProjects
30+ )
2731 }
2832}
2933
30- fun merge (archiveFileName : String , projects : List <Project >) {
31- val outputFile = File (project.layout.buildDirectory.asFile.get(), " libs/${archiveFileName} " )
32- val outputDir = outputFile.parentFile ? : throw RuntimeException (" Could not get output directory" )
34+ fun ShadowJar.mergeJars (archiveFileName : String , projects : List <Project >) {
35+ val outputFile = File (
36+ this .project.layout.buildDirectory.asFile.get(),
37+ " libs/$archiveFileName "
38+ )
39+ val outputDir = outputFile.parentFile
40+ ? : throw IllegalStateException (" Kurwa, nie mogę znaleźć katalogu wyjściowego" )
3341
3442 if (! outputDir.exists() && ! outputDir.mkdirs()) {
35- throw RuntimeException ( " Could not create output directory " )
43+ throw IllegalStateException ( " Nie udało się stworzyć katalogu: ${outputDir.absolutePath} " )
3644 }
3745
38- if (outputFile.exists()) {
39- outputFile.delete( )
46+ if (outputFile.exists() && ! outputFile.delete() ) {
47+ throw IllegalStateException ( " Nie można usunąć istniejącego pliku: ${ outputFile.absolutePath} " )
4048 }
4149
4250 if (! outputFile.createNewFile()) {
43- throw RuntimeException ( " Could not find output file to merge " )
51+ throw IllegalStateException ( " Nie można utworzyć pliku wyjściowego: ${outputFile.absolutePath} " )
4452 }
4553
54+ mergeShadowJarsIntoOutput(outputFile, projects)
55+ }
56+
57+ private fun mergeShadowJarsIntoOutput (
58+ outputFile : File ,
59+ projects : List <Project >
60+ ) {
4661 JarOutputStream (FileOutputStream (outputFile)).use { outputJar ->
47- for (project in projects) {
48- val shadowJar = project.tasks.shadowJar.get()
49-
50- for (file in shadowJar.outputs.files.files) {
51- JarFile (file).use { jarFile ->
52- for (entry in jarFile.entries() ) {
53- if (entry.isDirectory) {
54- continue
55- }
56-
57- val bytes = jarFile.getInputStream(entry).readBytes()
58- val newEntry = JarEntry (entry.name)
59-
60- newEntry.setTime( System .currentTimeMillis())
61- newEntry.setSize(bytes.size.toLong())
62-
63- try {
64- outputJar.putNextEntry(newEntry)
65- outputJar.write(bytes)
66- outputJar.closeEntry()
67- }
68- catch (exception : IOException ) {
69- if (exception.message?.contains( " duplicate entry: " ) == true ) {
70- continue
71- }
72-
73- exception.printStackTrace()
74- }
75- }
62+ val processedEntries = mutableSetOf< String >()
63+
64+ for (targetProject in projects) {
65+ val shadowJarTask = targetProject.tasks.named( " shadowJar " , ShadowJar :: class .java).get()
66+
67+ for (jarFile in shadowJarTask.outputs.files.files ) {
68+ processJarFile(jarFile, outputJar, processedEntries)
69+ }
70+ }
71+ }
72+ }
73+
74+ private fun processJarFile (
75+ jarFile : File ,
76+ outputJar : JarOutputStream ,
77+ processedEntries : MutableSet < String >
78+ ) {
79+ JarFile (jarFile).use { sourceJar ->
80+ for (entry in sourceJar.entries()) {
81+ if (entry.isDirectory || processedEntries.contains(entry.name)) {
82+ continue
83+ }
84+
85+ try {
86+ copyJarEntry(sourceJar, entry, outputJar)
87+ processedEntries.add(entry.name)
88+ } catch (exception : IOException ) {
89+ if (exception.message?.contains( " duplicate entry: " ) != true ) {
90+ throw exception
7691 }
7792 }
7893 }
7994 }
95+ }
8096
97+ private fun copyJarEntry (
98+ sourceJar : JarFile ,
99+ entry : JarEntry ,
100+ outputJar : JarOutputStream
101+ ) {
102+ val entryBytes = sourceJar.getInputStream(entry).use { it.readBytes() }
103+ val newEntry = JarEntry (entry.name).apply {
104+ this .time = System .currentTimeMillis()
105+ this .size = entryBytes.size.toLong()
106+ }
107+
108+ outputJar.putNextEntry(newEntry)
109+ outputJar.write(entryBytes)
110+ outputJar.closeEntry()
81111}
82112
83113runPaper {
84- disablePluginJarDetection()
114+ this . disablePluginJarDetection()
85115}
86116
87117tasks.runServer {
88- minecraftVersion(" 1.21.9" )
89- dependsOn(" shadowAll" )
90- pluginJars = files(" /build/libs/ChatFormatter v${project.version} .jar" )
91- // We need to start the server with Java 21, but jar is built with Java 17
92- javaLauncher.set(javaToolchains.launcherFor {
93- languageVersion.set(JavaLanguageVersion .of(21 ))
94- })
95- downloadPlugins.modrinth(" luckperms" , " v5.5.0-bukkit" )
96- downloadPlugins.modrinth(" VaultUnlocked" , " 2.16.0" )
97- }
118+ minecraftVersion(" 1.21.10" )
119+ dependsOn(" shadowChatFormatter" )
120+ pluginJars.from(layout.buildDirectory.file(" libs/ChatFormatter v${project.version} .jar" ))
121+
122+ javaLauncher.set(
123+ javaToolchains.launcherFor {
124+ this .languageVersion.set(JavaLanguageVersion .of(21 ))
125+ }
126+ )
127+
128+ downloadPlugins {
129+ this .modrinth(" luckperms" , " v5.5.0-bukkit" )
130+ this .modrinth(" VaultUnlocked" , " 2.16.0" )
131+ }
132+ }
0 commit comments