diff --git a/HMCL/build.gradle b/HMCL/build.gradle deleted file mode 100644 index 7ffa6f66d..000000000 --- a/HMCL/build.gradle +++ /dev/null @@ -1,242 +0,0 @@ -buildscript { - repositories { - gradlePluginPortal() - maven { url 'https://jitpack.io' } - } - dependencies { - classpath 'org.tukaani:xz:1.8' - classpath 'org.glavo:pack200:0.3.0' - } -} - -plugins { - id 'application' - id 'com.github.johnrengelman.shadow' version '7.0.0' -} - -import java.nio.file.FileSystems -import java.security.KeyFactory -import java.security.MessageDigest -import java.security.Signature -import java.security.spec.PKCS8EncodedKeySpec -import java.util.jar.JarFile -import java.util.jar.JarOutputStream -import java.util.zip.GZIPOutputStream -import java.util.zip.ZipFile -import java.nio.file.Files - -import org.tukaani.xz.LZMA2Options -import org.tukaani.xz.XZOutputStream -import org.glavo.pack200.Pack200 - -def dev = null -def shortcommit = System.getenv("GITHUB_SHA")?.toLowerCase()?.substring(0, 7) ?: null -if (shortcommit != null && !shortcommit.isEmpty()) dev = "dev-" + shortcommit -def buildnumber = System.getenv("BUILD_NUMBER") ?: dev ?: "SNAPSHOT" -if (System.getenv("BUILD_NUMBER") != null && System.getenv("BUILD_NUMBER_OFFSET") != null) - buildnumber = (Integer.parseInt(System.getenv("BUILD_NUMBER")) - Integer.parseInt(System.getenv("BUILD_NUMBER_OFFSET"))).toString() -def versionroot = System.getenv("VERSION_ROOT") ?: "3.5" -def microsoftAuthId = System.getenv("MICROSOFT_AUTH_ID") ?: "" -def microsoftAuthSecret = System.getenv("MICROSOFT_AUTH_SECRET") ?: "" -def versionType = System.getenv("VERSION_TYPE") ?: "nightly" -version = versionroot + '.' + buildnumber - -mainClassName = 'org.jackhuang.hmcl.Main' - -dependencies { - implementation project(":HMCLCore") - implementation 'libs:JFoenix' - - implementation group: 'de.javawi.jstun', name: 'jstun', version: '0.7.4' -} - -def digest(String algorithm, byte[] bytes) { - return MessageDigest.getInstance(algorithm).digest(bytes) -} - -def createChecksum(File file) { - def algorithms = [ - ["MD5", "md5"], - ["SHA-1", "sha1"], - ["SHA-256", "sha256"], - ["SHA-512", "sha512"] - ] - - for (algorithm in algorithms) { - new File(file.parentFile, file.name + "." + algorithm[1]).text = digest(algorithm[0], file.bytes).encodeHex().toString() + "\n" - } -} - -def attachSignature(File jar) { - def keyLocation = System.getenv("HMCL_SIGNATURE_KEY"); - if (keyLocation == null) - return - def privatekey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(new File(keyLocation).bytes)) - - def signer = Signature.getInstance("SHA512withRSA") - signer.initSign(privatekey) - new ZipFile(jar).withCloseable { zip -> - zip.stream() - .sorted(Comparator.comparing { it.name }) - .filter { it.name != "META-INF/hmcl_signature" } - .forEach { - signer.update(digest("SHA-512", it.name.getBytes("UTF-8"))) - signer.update(digest("SHA-512", zip.getInputStream(it).bytes)) - } - } - def signature = signer.sign() - - FileSystems.newFileSystem(URI.create("jar:" + jar.toURI()), [:]).withCloseable { zipfs -> - Files.newOutputStream(zipfs.getPath("META-INF/hmcl_signature")).withCloseable { it << signature } - } -} - -ext.packer = Pack200.newPacker() -packer.properties()["pack.effort"] = "9" -ext.unpacker = Pack200.newUnpacker() - -// Pack200 does not guarantee that unpacked .class file is bit-wise same as the .class file before packing -// because of shrinking. So we should pack .class files and unpack it to make sure that after unpacking -// .class files remain the same. -def repack(File file) { - def packed = new ByteArrayOutputStream() - new JarFile(file).withCloseable { packer.pack(it, packed) } - new JarOutputStream(file.newOutputStream()).withCloseable { unpacker.unpack(new ByteArrayInputStream(packed.toByteArray()), it) } -} - -sourceSets { - java11 { - java { - srcDirs = ['src/main/java11'] - } - } -} - -compileJava11Java { - if(JavaVersion.current() < JavaVersion.VERSION_11) { - javaCompiler = javaToolchains.compilerFor { - languageVersion = JavaLanguageVersion.of(11) - } - } - options.compilerArgs.add('--add-exports=java.base/jdk.internal.loader=ALL-UNNAMED') - sourceCompatibility = 11 - targetCompatibility = 11 -} - -jar { - enabled = false - dependsOn shadowJar -} - -shadowJar { - classifier = null - - - minimize { - exclude(dependency('com.google.code.gson:.*:.*')) - exclude(dependency('com.github.steveice10:.*:.*')) - exclude(dependency('libs:JFoenix:.*')) - } - - manifest { - attributes 'Created-By': 'Copyright(c) 2013-2021 huangyuhui.', - 'Main-Class': mainClassName, - 'Multi-Release': 'true', - 'Implementation-Version': project.version, - 'Microsoft-Auth-Id': microsoftAuthId, - 'Microsoft-Auth-Secret': microsoftAuthSecret, - 'Build-Channel': versionType, - 'Class-Path': 'pack200.jar', - 'Add-Opens': [ - 'java.base/java.lang', - 'java.base/java.lang.reflect', - 'javafx.graphics/javafx.css', - 'javafx.base/com.sun.javafx.runtime', - 'javafx.controls/com.sun.javafx.scene.control.behavior', - 'javafx.controls/javafx.scene.control.skin', - 'javafx.controls/com.sun.javafx.scene.control', - 'javafx.base/com.sun.javafx.binding', - 'javafx.base/com.sun.javafx.event', - 'javafx.graphics/com.sun.javafx.stage' - ].join(" "), - 'Add-Exports': [ - 'java.base/jdk.internal.loader', - 'javafx.controls/com.sun.javafx.scene.control.behavior', - 'javafx.controls/javafx.scene.control.skin', - 'javafx.controls/com.sun.javafx.scene.control', - 'javafx.base/com.sun.javafx.binding', - 'javafx.graphics/com.sun.javafx.stage', - 'javafx.base/com.sun.javafx.event' - ].join(" ") - } - - doLast { - repack(jar.archivePath) // see repack() - attachSignature(jar.archivePath) - createChecksum(jar.archivePath) - } -} - -def createExecutable(String suffix, String header) { - def output = new File(jar.archivePath.parentFile, jar.archivePath.name[0..-4] + suffix) - output.bytes = new File(project.projectDir, header).bytes - output << jar.archivePath.bytes - createChecksum(output) -} - -processResources { - ext.convertToBSS = { String resource -> - // exclude resource - doFirst { - def cssFile = new File(this.projectDir, "src/main/resources/" + resource) - def bssFile = new File(this.projectDir, "build/compiled-resources/" + resource[0..-4] + "bss") - bssFile.parentFile.mkdirs() - javaexec { - classpath = sourceSets.main.compileClasspath - mainClass = "com.sun.javafx.css.parser.Css2Bin" - args = [cssFile, bssFile] - } - } - } - from "build/compiled-resources" - - convertToBSS "assets/css/root.css" - convertToBSS "assets/css/blue.css" - - into('META-INF/versions/11') { - from sourceSets.java11.output - } - dependsOn java11Classes -} - -task makePack(dependsOn: jar) { - ext.outputPath = new File(jar.archivePath.parentFile, jar.archivePath.name[0..-4] + "pack") - doLast { - outputPath.newOutputStream().withCloseable { out -> - new JarFile(jar.archivePath).withCloseable { jarFile -> packer.pack(jarFile, out) } - } - createChecksum(outputPath) - } -} - -task makePackXz(dependsOn: makePack) doLast { - def packXz = new File(makePack.outputPath.parentFile, makePack.outputPath.name + ".xz") - // Our CI server does not have enough memory space to compress file at highest level. - new XZOutputStream(packXz.newOutputStream(), new LZMA2Options(5)).withCloseable { it << makePack.outputPath.bytes } - createChecksum(packXz) -} - -task makePackGz(dependsOn: makePack) doLast { - def packGz = new File(makePack.outputPath.parentFile, makePack.outputPath.name + ".gz") - new GZIPOutputStream(packGz.newOutputStream()).withCloseable { it << makePack.outputPath.bytes } - createChecksum(packGz) -} - - -task makeExecutables(dependsOn: jar) doLast { - createExecutable("exe", "src/main/resources/assets/HMCLauncher.exe") -} - -build.dependsOn makePackXz -build.dependsOn makePackGz -build.dependsOn makeExecutables diff --git a/HMCL/build.gradle.kts b/HMCL/build.gradle.kts new file mode 100644 index 000000000..373a94876 --- /dev/null +++ b/HMCL/build.gradle.kts @@ -0,0 +1,273 @@ +import java.nio.file.FileSystems +import java.nio.file.Files +import java.security.KeyFactory +import java.security.MessageDigest +import java.security.Signature +import java.security.spec.PKCS8EncodedKeySpec +import java.util.jar.JarFile +import java.util.jar.JarOutputStream +import java.util.zip.ZipFile +import java.util.zip.GZIPOutputStream +import java.io.ByteArrayOutputStream +import java.io.ByteArrayInputStream +import java.net.URI + +import org.glavo.pack200.Pack200 +import org.tukaani.xz.LZMA2Options +import org.tukaani.xz.XZOutputStream + +buildscript { + repositories { + gradlePluginPortal() + maven(url = "https://jitpack.io") + } + dependencies { + classpath("org.tukaani:xz:1.8") + classpath("org.glavo:pack200:0.3.0") + } +} + +plugins { + application + id("com.github.johnrengelman.shadow") version "7.0.0" +} + +val buildNumber = System.getenv("BUILD_NUMBER")?.toInt().let { number -> + val offset = System.getenv("BUILD_NUMBER_OFFSET")?.toInt() ?: 0 + if (number != null) { + (number - offset).toString() + } else { + val shortCommit = System.getenv("GITHUB_SHA")?.toLowerCase()?.substring(0, 7) + if (!shortCommit.isNullOrEmpty()) "dev-$shortCommit" else "SNAPSHOT" + } +} +val versionRoot = System.getenv("VERSION_ROOT") ?: "3.5" +val microsoftAuthId = System.getenv("MICROSOFT_AUTH_ID") ?: "" +val microsoftAuthSecret = System.getenv("MICROSOFT_AUTH_SECRET") ?: "" +val versionType = System.getenv("VERSION_TYPE") ?: "nightly" + +version = "$versionRoot.$buildNumber" + +application { + mainClass.set("org.jackhuang.hmcl.Main") +} + +dependencies { + implementation(project(":HMCLCore")) + implementation("libs:JFoenix") + + implementation("de.javawi.jstun:jstun:0.7.4") +} + +fun digest(algorithm: String, bytes: ByteArray) = MessageDigest.getInstance(algorithm).digest(bytes) + +fun createChecksum(file: File) { + val algorithms = linkedMapOf( + "MD5" to "md5", + "SHA-1" to "sha1", + "SHA-256" to "sha256", + "SHA-512" to "sha512" + ) + + algorithms.forEach { (algorithm, ext) -> + File(file.parentFile, "${file.name}.$ext").writeText( + digest(algorithm, file.readBytes()).joinToString(separator = "", postfix = "\n") { "%02x".format(it) } + ) + } +} + +fun attachSignature(jar: File) { + val keyLocation = System.getenv("HMCL_SIGNATURE_KEY") ?: return + val privatekey = KeyFactory.getInstance("RSA").generatePrivate(PKCS8EncodedKeySpec(File(keyLocation).readBytes())) + val signer = Signature.getInstance("SHA512withRSA") + signer.initSign(privatekey) + ZipFile(jar).use { zip -> + zip.stream() + .sorted(Comparator.comparing { it.name }) + .filter { it.name != "META-INF/hmcl_signature" } + .forEach { + signer.update(digest("SHA-512", it.name.toByteArray())) + signer.update(digest("SHA-512", zip.getInputStream(it).readBytes())) + } + } + val signature = signer.sign() + FileSystems.newFileSystem(URI.create("jar:" + jar.toURI()), emptyMap()).use { zipfs -> + Files.newOutputStream(zipfs.getPath("META-INF/hmcl_signature")).use { it.write(signature) } + } +} + +val packer = Pack200.newPacker().apply { + properties()["pack.effort"] = "9" +} + +val unpacker = Pack200.newUnpacker() + +// Pack200 does not guarantee that unpacked .class file is bit-wise same as the .class file before packing +// because of shrinking. So we should pack .class files and unpack it to make sure that after unpacking +// .class files remain the same. +fun repack(file: File) { + val packed = ByteArrayOutputStream() + JarFile(file).use { packer.pack(it, packed) } + JarOutputStream(file.outputStream()).use { unpacker.unpack(ByteArrayInputStream(packed.toByteArray()), it) } +} + +val java11 = sourceSets.create("java11") { + java { + srcDir("src/main/java11") + } +} + +tasks.getByName(java11.compileJavaTaskName) { + if (JavaVersion.current() < JavaVersion.VERSION_11) { + javaCompiler.set(javaToolchains.compilerFor { + languageVersion.set(JavaLanguageVersion.of(11)) + }) + } + options.compilerArgs.add("--add-exports=java.base/jdk.internal.loader=ALL-UNNAMED") + sourceCompatibility = "11" + targetCompatibility = "11" +} + +tasks.jar { + enabled = false + dependsOn(tasks["shadowJar"]) +} + +val jarPath = tasks.jar.get().archiveFile.get().asFile + +tasks.getByName("shadowJar") { + archiveClassifier.set(null as String?) + + minimize { + exclude(dependency("com.google.code.gson:.*:.*")) + exclude(dependency("com.github.steveice10:.*:.*")) + exclude(dependency("libs:JFoenix:.*")) + } + + manifest { + attributes( + "Created-By" to "Copyright(c) 2013-2021 huangyuhui.", + "Main-Class" to application.mainClass.get(), + "Multi-Release" to "true", + "Implementation-Version" to project.version, + "Microsoft-Auth-Id" to microsoftAuthId, + "Microsoft-Auth-Secret" to microsoftAuthSecret, + "Build-Channel" to versionType, + "Class-Path" to "pack200.jar", + "Add-Opens" to listOf( + "java.base/java.lang", + "java.base/java.lang.reflect", + "javafx.graphics/javafx.css", + "javafx.base/com.sun.javafx.runtime", + "javafx.controls/com.sun.javafx.scene.control.behavior", + "javafx.controls/javafx.scene.control.skin", + "javafx.controls/com.sun.javafx.scene.control", + "javafx.base/com.sun.javafx.binding", + "javafx.base/com.sun.javafx.event", + "javafx.graphics/com.sun.javafx.stage" + ).joinToString(" "), + "Add-Exports" to listOf( + "java.base/jdk.internal.loader", + "javafx.controls/com.sun.javafx.scene.control.behavior", + "javafx.controls/javafx.scene.control.skin", + "javafx.controls/com.sun.javafx.scene.control", + "javafx.base/com.sun.javafx.binding", + "javafx.graphics/com.sun.javafx.stage", + "javafx.base/com.sun.javafx.event" + ).joinToString(" ") + ) + } + + doLast { + repack(jarPath) // see repack() + attachSignature(jarPath) + createChecksum(jarPath) + } +} + + + +fun createExecutable(suffix: String, header: String) { + val output = File(jarPath.parentFile, jarPath.nameWithoutExtension + '.' + suffix) + + output.outputStream().use { + it.write(File(project.projectDir, header).readBytes()) + it.write(jarPath.readBytes()) + } + + createChecksum(output) +} + +tasks.processResources { + fun convertToBSS(resource: String) { + doFirst { + val cssFile = File(projectDir, "src/main/resources/$resource") + val bssFile = File(projectDir, "build/compiled-resources/${resource.substring(0, resource.length - 4)}.bss") + bssFile.parentFile.mkdirs() + javaexec { + classpath = sourceSets["main"].compileClasspath + mainClass.set("com.sun.javafx.css.parser.Css2Bin") + args(cssFile, bssFile) + } + } + } + + from("build/compiled-resources") + + convertToBSS("assets/css/root.css") + convertToBSS("assets/css/blue.css") + + into("META-INF/versions/11") { + from(sourceSets["java11"].output) + } + dependsOn(tasks["java11Classes"]) +} + +val packFile = File(jarPath.parentFile, jarPath.nameWithoutExtension + ".pack") + +val makePack = tasks.create("makePack") { + dependsOn(tasks.jar) + + doLast { + packFile.outputStream().use { out -> + JarFile(jarPath).use { jarFile -> packer.pack(jarFile, out) } + } + createChecksum(packFile) + } +} + +val makePackXz = tasks.create("makePackXz") { + dependsOn(makePack) + + val packXz = File(packFile.parentFile, packFile.name + ".xz") + + doLast { + // Our CI server does not have enough memory space to compress file at highest level. + XZOutputStream(packXz.outputStream(), LZMA2Options(5)) + .use { it.write(packFile.readBytes()) } + createChecksum(packXz) + } +} + +val makePackGz = tasks.create("makePackGz") { + dependsOn(makePack) + + val packGz = File(packFile.parentFile, packFile.name + ".gz") + + doLast { + GZIPOutputStream(packGz.outputStream()).use { it.write(packFile.readBytes()) } + createChecksum(packGz) + } +} + +val makeExecutables = tasks.create("makeExecutables") { + dependsOn(makePack) + + doLast { + createExecutable("exe", "src/main/resources/assets/HMCLauncher.exe") + } +} + +tasks.build { + dependsOn(makePackXz, makePackGz, makeExecutables) +} \ No newline at end of file diff --git a/HMCLCore/build.gradle b/HMCLCore/build.gradle deleted file mode 100644 index 1e2360c70..000000000 --- a/HMCLCore/build.gradle +++ /dev/null @@ -1,27 +0,0 @@ -plugins { - id 'java-library' -} - -dependencies { - api group: 'com.google.code.gson', name: 'gson', version: '2.8.1' - api group: 'com.moandjiezana.toml', name: 'toml4j', version: '0.7.2' - api group: 'org.tukaani', name: 'xz', version: '1.8' - api(group: 'org.hildan.fxgson', name: 'fx-gson', version: '3.1.0') { - exclude group: 'org.jetbrains', module: 'annotations' - } - api group: 'org.jenkins-ci', name: 'constant-pool-scanner', version: '1.2' - api group: 'com.github.steveice10', name: 'opennbt', version: '1.1' - api group: 'com.nqzero', name: 'permit-reflect', version: '0.3' - api group: 'org.nanohttpd', name: 'nanohttpd', version: '2.3.1' - api group: 'org.apache.commons', name: 'commons-compress', version: '1.21' - api group: 'org.apache.commons', name: 'commons-lang3', version: '3.12.0' - compileOnlyApi group: 'org.jetbrains', name: 'annotations', version: '16.0.3' -} - -tasks.processResources { - dependsOn ':log4j-patch:jar' - - into('assets/game') { - from project(':log4j-patch').file("build/libs") - } -} diff --git a/HMCLCore/build.gradle.kts b/HMCLCore/build.gradle.kts new file mode 100644 index 000000000..d4071f8f4 --- /dev/null +++ b/HMCLCore/build.gradle.kts @@ -0,0 +1,27 @@ +plugins { + `java-library` +} + +dependencies { + api("com.google.code.gson:gson:2.8.1") + api("com.moandjiezana.toml:toml4j:0.7.2") + api("org.tukaani:xz:1.8") + api("org.hildan.fxgson:fx-gson:3.1.0") { + exclude(group = "org.jetbrains", module = "annotations") + } + api("org.jenkins-ci:constant-pool-scanner:1.2") + api("com.github.steveice10:opennbt:1.1") + api("com.nqzero:permit-reflect:0.3") + api("org.nanohttpd:nanohttpd:2.3.1") + api("org.apache.commons:commons-compress:1.21") + api("org.apache.commons:commons-lang3:3.12.0") + compileOnlyApi("org.jetbrains:annotations:16.0.3") +} + +tasks.processResources { + dependsOn(":log4j-patch:jar") + + into("assets/game") { + from(project(":log4j-patch").file("build/libs")) + } +} diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 71b121204..000000000 --- a/build.gradle +++ /dev/null @@ -1,221 +0,0 @@ -buildscript { - repositories { - mavenCentral() - maven { url 'https://plugins.gradle.org/m2/' } - } - dependencies { - classpath group: 'com.google.code.gson', name: 'gson', version: '2.8.1' - } -} - -plugins { - id 'checkstyle' -} - -group 'org.jackhuang' -version '3.0' - -subprojects { - apply plugin: 'java' - apply plugin: 'idea' - apply plugin: 'maven-publish' - apply plugin: 'checkstyle' - - repositories { - flatDir name: 'libs', dirs: rootProject.file('lib') - - mavenCentral() - - maven { url 'https://jitpack.io' } - } - - checkstyle { - sourceSets = [] - } - - tasks.withType(Checkstyle) { - exclude 'de/javawi/jstun' - } - - sourceCompatibility = 1.8 - compileJava.options.encoding = "UTF-8" - compileTestJava.options.encoding = "UTF-8" - - dependencies { - testImplementation group: 'junit', name: 'junit', version: '4.12' - } - - publishing { - publications { - maven(MavenPublication) { - from components.java - } - } - repositories { - mavenLocal() - } - } -} - -defaultTasks 'clean', 'build' - -var jfxModules = ['base', 'graphics', 'controls', 'fxml', 'media', 'web'] -var jfxArches = ['linux', 'linux-arm32-monocle', 'linux-aarch64', 'mac', 'mac-aarch64', 'win', 'win-x86'] -var jfxVersion = "17" -var jfxRepos = ['https://repo1.maven.org/maven2', 'https://maven.aliyun.com/repository/central'] -var jfxDependenciesFile = file('HMCL/src/main/resources/assets/openjfx-dependencies.json') -var jfxUnsupported = [ - 'linux-arm32-monocle': ['media', 'web'] -] - -var jfxInClasspath = false - -try { - Class.forName("javafx.application.Application", false, this.getClass().getClassLoader()) - jfxInClasspath = true -} catch (Throwable ignored) { -} - -if (!jfxInClasspath && JavaVersion.current() >= JavaVersion.VERSION_11) { - String os = null - String arch = null - - String osName = System.getProperty("os.name").toLowerCase(Locale.US) - if (osName.contains("win")) - os = 'win' - else if (osName.contains("mac")) - os = 'mac' - else if (osName.contains("solaris") || osName.contains("linux") || osName.contains("unix") || osName.contains("sunos")) - os = 'linux' - else - os = null - - String archName = System.getProperty("os.arch").toLowerCase(Locale.US) - switch (archName) { - case "x86_64": - case "x86-64": - case "amd64": - arch = '' - break - case "x86": - case "x86_32": - case "x86-32": - case "i386": - case "i486": - case "i586": - case "i686": - case "i86pc": - arch = '-x86' - break - case "aarch64": - arch = '-aarch64'; - break - } - String platform = "$os$arch" - - if (os != null && arch != null && jfxArches.contains(platform)) { - var jfxDependencies = jfxModules.collect { module -> "org.openjfx:javafx-$module:$jfxVersion:$platform" } - - subprojects { - repositories { - mavenCentral() - } - dependencies { - jfxDependencies.forEach { - compileOnly it - } - } - } - } -} - -import com.google.gson.* - -task 'generateOpenJFXDependencies' { - doLast { - var jfxDependencies = new JsonArray() - - jfxModules.forEach { module -> - JsonObject m = new JsonObject() - m.addProperty("module", "javafx.$module") - m.addProperty("groupId", "org.openjfx") - m.addProperty("artifactId", "javafx-$module") - m.addProperty("version", jfxVersion) - - var sha1 = new JsonObject() - jfxArches.forEach { arch -> - if (jfxUnsupported.getOrDefault(arch, []).contains(module)) { - return - } - - sha1.addProperty( - arch, - new URL("${jfxRepos.head()}/org/openjfx/javafx-$module/$jfxVersion/javafx-$module-$jfxVersion-${arch}.jar.sha1").getText("UTF-8") - ) - } - m.add("sha1", sha1) - - jfxDependencies.add(m) - } - - jfxDependenciesFile.text = new GsonBuilder().setPrettyPrinting().create().toJson(jfxDependencies) - } -} - -// Ensure that the mirror repository caches files -task 'preTouchOpenJFXDependencies' { - doLast { - jfxRepos.tail().forEach { repo -> - jfxModules.forEach { module -> - jfxArches.forEach { arch -> - if (jfxUnsupported.getOrDefault(arch, []).contains(module)) { - return - } - var jarUrl = "$repo/org/openjfx/javafx-$module/$jfxVersion/javafx-$module-$jfxVersion-${arch}.jar" - - [jarUrl, jarUrl + ".sha1"].forEach { url -> - try { - new URL(url).getBytes() - System.out.println(url) - } catch (Throwable ignored) { - ignored.printStackTrace() - } - } - } - } - } - } -} - -task 'checkTranslations' { - group 'verification' - doLast { - var en = new Properties() - var zh = new Properties() - var zh_CN = new Properties() - - file("HMCL/src/main/resources/assets/lang/I18N.properties").withInputStream { en.load(it) } - file("HMCL/src/main/resources/assets/lang/I18N_zh.properties").withInputStream { zh.load(it) } - file("HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties").withInputStream { zh_CN.load(it) } - - boolean success = true - - zh_CN.forEach { k, v -> - if (!en.containsKey(k)) { - project.logger.log(LogLevel.WARN, "I18N.properties missing key '$k'") - success = false - } - } - - zh_CN.forEach { k, v -> - if (!zh.containsKey(k)) { - project.logger.log(LogLevel.WARN, "I18N_zh.properties missing key '$k'") - success = false - } - } - - if (!success) { - throw new GradleException("Part of the translation is missing") - } - } -} \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 000000000..0161ac284 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,200 @@ +buildscript { + repositories { + mavenCentral() + maven(url = "https://plugins.gradle.org/m2/") + } + + dependencies { + classpath("com.google.code.gson:gson:2.8.1") + } +} + +plugins { + id("checkstyle") +} + +group = "org.jackhuang" +version = "3.0" + +subprojects { + apply { + plugin("java") + plugin("idea") + plugin("maven-publish") + plugin("checkstyle") + } + + repositories { + flatDir { + name = "libs" + dirs = setOf(rootProject.file("lib")) + } + mavenCentral() + maven(url = "https://jitpack.io") + } + + tasks.withType { + sourceCompatibility = "1.8" + targetCompatibility = "1.8" + + options.encoding = "UTF-8" + } + + configure { + sourceSets = setOf() + } + + tasks.withType { + exclude("de/javawi/jstun") + } + + dependencies { + "testImplementation"("junit:junit:4.12") + } + + configure { + publications { + create("maven") { + from(components["java"]) + } + } + repositories { + mavenLocal() + } + } +} + +tasks.create("checkTranslations") { + doLast { + val hmclLangDir = file("HMCL/src/main/resources/assets/lang") + + val en = java.util.Properties().apply { + hmclLangDir.resolve("I18N.properties").bufferedReader().use { load(it) } + } + + val zh = java.util.Properties().apply { + hmclLangDir.resolve("I18N_zh.properties").bufferedReader().use { load(it) } + } + + val zh_CN = java.util.Properties().apply { + hmclLangDir.resolve("I18N_zh_CN.properties").bufferedReader().use { load(it) } + } + + var success = true + + zh_CN.forEach { + if (!en.containsKey(it.key)) { + project.logger.warn("I18N.properties missing key '${it.key}'") + success = false + } + } + + zh_CN.forEach { + if (!zh.containsKey(it.key)) { + project.logger.warn("I18N_zh.properties missing key '${it.key}'") + success = false + } + } + + if (!success) { + throw GradleException("Part of the translation is missing") + } + } +} + +defaultTasks("clean", "build") + +val jfxModules = listOf("base", "graphics", "controls", "fxml", "media", "web") +val jfxClassifier = listOf( + "linux", "linux-arm32-monocle", "linux-aarch64", + "mac", "mac-aarch64", + "win", "win-x86" +) +val jfxVersion = "17" +val jfxMirrorRepos = listOf("https://maven.aliyun.com/repository/central") +val jfxDependenciesFile = rootProject.file("HMCL/src/main/resources/assets/openjfx-dependencies.json") +val jfxUnsupported = mapOf( + "linux-arm32-monocle" to listOf("media", "web") +) + +fun isSupported(module: String, classifier: String) = when (classifier) { + "linux-arm32-monocle" -> module != "media" && module != "web" + else -> true +} + +val jfxInClasspath = + try { + Class.forName("javafx.application.Application", false, this.javaClass.classLoader) + true + } catch (ignored: Throwable) { + false + } + +if (!jfxInClasspath && JavaVersion.current() >= JavaVersion.VERSION_11) { + val os = System.getProperty("os.name").toLowerCase().let { osName -> + when { + osName.contains("win") -> "win" + osName.contains("mac") -> "mac" + osName.contains("linux") || osName.contains("unix") -> "linux" + else -> null + } + } + + val classifier = if (os == null) null else when (System.getProperty("os.arch").toLowerCase()) { + "x86_64", "x86-64", "amd64", "ia32e", "em64t", "x64" -> os + "x86", "x86_32", "x86-32", "i386", "i486", "i586", "i686", "i86pc", "ia32", "x32" -> "$os-x86" + "arm64", "aarch64", "armv8", "armv9" -> "$os-aarch64" + else -> null + } + + if (classifier != null && classifier in jfxClassifier) { + rootProject.subprojects { + for (module in jfxModules) { + dependencies.add("compileOnly", "org.openjfx:javafx-$module:$jfxVersion:$classifier") + } + } + } +} + +rootProject.tasks.create("generateOpenJFXDependencies") { + doLast { + val jfxDependencies = jfxModules.map { module -> + linkedMapOf( + "module" to "javafx.$module", + "groupId" to "org.openjfx", + "artifactId" to "javafx-$module", + "version" to jfxVersion, + "sha1" to jfxClassifier.filter { classifier -> isSupported(module, classifier) } + .associateWith { classifier -> + java.net.URL("https://repo1.maven.org/maven2/org/openjfx/javafx-$module/$jfxVersion/javafx-$module-$jfxVersion-$classifier.jar.sha1") + .readText() + } + ) + } + + jfxDependenciesFile.writeText( + com.google.gson.GsonBuilder().setPrettyPrinting().create().toJson(jfxDependencies) + ) + } +} + +// Ensure that the mirror repository caches files +rootProject.tasks.create("preTouchOpenJFXDependencies") { + doLast { + for (repo in jfxMirrorRepos) { + for (module in jfxModules) { + for (classifier in jfxClassifier) { + if (isSupported(module, classifier)) { + val jarUrl = + java.net.URL("$repo/org/openjfx/javafx-$module/$jfxVersion/javafx-$module-$jfxVersion-$classifier.jar") + try { + jarUrl.readBytes() + } catch (e: Throwable) { + logger.warn("An exception occurred while pre touching $jarUrl", e) + } + } + } + } + } + } +} \ No newline at end of file diff --git a/minecraft/libraries/HMCLTransformerDiscoveryService/build.gradle b/minecraft/libraries/HMCLTransformerDiscoveryService/build.gradle deleted file mode 100644 index 413299664..000000000 --- a/minecraft/libraries/HMCLTransformerDiscoveryService/build.gradle +++ /dev/null @@ -1,17 +0,0 @@ -version '1.0' - -dependencies { - compileOnly project.files("lib/modlauncher-4.1.0.jar") -} - -compileJava { - sourceCompatibility = 8 - targetCompatibility = 8 -} - -jar { - manifest { - attributes 'Created-By': 'Copyright(c) 2013-2020 huangyuhui.', - 'Implementation-Version': project.version - } -} diff --git a/minecraft/libraries/HMCLTransformerDiscoveryService/build.gradle.kts b/minecraft/libraries/HMCLTransformerDiscoveryService/build.gradle.kts new file mode 100644 index 000000000..35450a139 --- /dev/null +++ b/minecraft/libraries/HMCLTransformerDiscoveryService/build.gradle.kts @@ -0,0 +1,19 @@ +version = "1.0" + +dependencies { + compileOnly(project.files("lib/modlauncher-4.1.0.jar")) +} + +tasks.compileJava { + sourceCompatibility = "1.8" + targetCompatibility = "1.8" +} + +tasks.jar { + manifest { + attributes( + "Created-By" to "Copyright(c) 2013-2020 huangyuhui.", + "Implementation-Version" to project.version + ) + } +} diff --git a/minecraft/libraries/log4j-patch/build.gradle b/minecraft/libraries/log4j-patch/build.gradle deleted file mode 100644 index 655c85bc7..000000000 --- a/minecraft/libraries/log4j-patch/build.gradle +++ /dev/null @@ -1,52 +0,0 @@ -version '1.0' - -sourceSets.create("agent") { - java { - srcDir 'src/main/agent' - } -} - -dependencies { - compileOnly group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.0-beta9' -} - -tasks.withType(JavaCompile) { - sourceCompatibility = 8 - targetCompatibility = 8 - - doLast { - FileTree tree = fileTree('build/classes/java') - tree.include '**/*.class' - tree.each { - RandomAccessFile rf = new RandomAccessFile(it, "rw") - rf.seek(7) // major version - rf.write(50) // java 6 - rf.close() - } - } -} - -task agentJar(type: Jar) { - dependsOn(tasks.compileJava) - - baseName = 'log4j-patch-agent' - - manifest { - attributes 'Premain-Class': 'org.glavo.log4j.patch.agent.Log4jAgent' - } - - from(sourceSets.agent.output) - from(sourceSets.main.output) { - includeEmptyDirs = false - - eachFile { - it.path = "org/glavo/log4j/patch/agent/${it.name}.bin" - } - } -} - -tasks.jar { - enabled = false - dependsOn agentJar -} - diff --git a/minecraft/libraries/log4j-patch/build.gradle.kts b/minecraft/libraries/log4j-patch/build.gradle.kts new file mode 100644 index 000000000..174f37403 --- /dev/null +++ b/minecraft/libraries/log4j-patch/build.gradle.kts @@ -0,0 +1,53 @@ +import java.io.RandomAccessFile + +version = "1.0" + +sourceSets.create("agent") { + java { + srcDir("src/main/agent") + } +} + +dependencies { + compileOnly("org.apache.logging.log4j:log4j-core:2.0-beta9") +} + +tasks.withType { + sourceCompatibility = "1.8" + targetCompatibility = "1.8" + + doLast { + val tree = fileTree(destinationDirectory) + tree.include("**/*.class") + tree.exclude("module-info.class") + tree.forEach { + RandomAccessFile(it, "rw").use { rf -> + rf.seek(7) // major version + rf.write(50) // java 6 + rf.close() + } + } + } +} + +val agentJar = tasks.create("agentJar") { + dependsOn(tasks.compileJava) + + archiveBaseName.set("log4j-patch-agent") + + manifest { + attributes("Premain-Class" to "org.glavo.log4j.patch.agent.Log4jAgent") + } + + from(sourceSets["agent"].output) + from(sourceSets["main"].output) { + includeEmptyDirs = false + eachFile { path = "org/glavo/log4j/patch/agent/$name.bin" } + } + +} + +tasks.jar { + enabled = false + dependsOn(agentJar) +} diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index b7aabf891..000000000 --- a/settings.gradle +++ /dev/null @@ -1,8 +0,0 @@ -rootProject.name = 'HMCL3' -include ':HMCL' -include ':HMCLCore' -include ':HMCLTransformerDiscoveryService' -include ':log4j-patch' - -project(':HMCLTransformerDiscoveryService').projectDir = file('minecraft/libraries/HMCLTransformerDiscoveryService') -project(':log4j-patch').projectDir = file('minecraft/libraries/log4j-patch') diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 000000000..9f6ef327e --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,13 @@ +rootProject.name = "HMCL3" +include( + "HMCL", + "HMCLCore", + "HMCLTransformerDiscoveryService", + "log4j-patch" +) + +val minecraftLibraries = listOf("log4j-patch", "HMCLTransformerDiscoveryService") + +for (library in minecraftLibraries) { + project(":$library").projectDir = file("minecraft/libraries/$library") +}