diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index 71e0ea3..8a9babb 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -5,21 +5,22 @@ jobs: build-app: strategy: matrix: - os: [macos-latest, ubuntu-20.04, windows-latest] + os: [macos-latest, ubuntu-latest, windows-latest] name: Package runs-on: ${{ matrix.os }} steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v5 with: submodules: true - name: Setup Java - uses: actions/setup-java@v1 + uses: actions/setup-java@v5 with: - java-version: 18 + distribution: oracle + java-version: '26.0.2' - run: ./gradlew --no-daemon clean test jpackage - name: Upload - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: ProjectSWG-${{matrix.os}} path: build/installer diff --git a/README.md b/README.md index 7c865b5..e24baba 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # ProjectSWG Launcher ## Quick Start +* Install JDK 26.0.2 and set `JAVA_HOME` to its installation directory. * Clone the repo * Pull submodules, build, and run ```bash @@ -8,3 +9,12 @@ git submodule update --init --recursive ./gradlew jlink ./build/image/bin/projectswg ``` + +Compile without running tests: +```bash +./gradlew clean classes +``` + +The wrapper uses Gradle 9.7.1. Java and Kotlin both target JVM 26; JavaFX remains at 18.0.2 for compatibility with the existing UI libraries. + +The retired TornadoFX snapshot is preserved in `libs/`; see `libs/README.md` for provenance and its checksum. Build updates also touch the `pswgcommon` and `forwarder` submodules. diff --git a/build.gradle.kts b/build.gradle.kts index 3cdcbe3..9159c32 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,15 +1,18 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + plugins { application java idea - kotlin("jvm") version "1.7.10" - id("org.beryx.jlink") version "2.25.0" - id("de.undercouch.download") version "5.0.5" + kotlin("jvm") version "2.4.10" + id("org.beryx.jlink") version "4.1.1" + id("de.undercouch.download") version "5.7.0" } -val javaVersion = "18.0.2" -val javaMajorVersion = "18" -val kotlinTargetJdk = "18" +val javaVersion = JavaVersion.current() +val javafxVersion = JavaVersion.current() +val kotlinTargetJdk = JvmTarget.JVM_26 +val junit5Version = "5.12.2" val osName: String = System.getProperty("os.name") val platform: String = when { @@ -20,14 +23,15 @@ val platform: String = when { } println("Configuration:") println(" Java Version: $javaVersion") -println(" Java Major Version: $javaMajorVersion") +println(" JavaFX Version: $javafxVersion") println(" Kotlin Target: $kotlinTargetJdk") println(" Platform: $platform") subprojects { ext { set("javaVersion", javaVersion) - set("javaMajorVersion", javaMajorVersion) + set("javafxVersion", javafxVersion) + set("junit5Version", junit5Version) set("kotlinTargetJdk", kotlinTargetJdk) } } @@ -43,7 +47,6 @@ application { repositories { maven("https://dev.joshlarson.me/maven2") - maven("https://oss.sonatype.org/content/repositories/snapshots") mavenCentral() } @@ -52,8 +55,8 @@ sourceSets { dependencies { val jfxOptions = object { val group = "org.openjfx" - val version = javaVersion - val fxModules = arrayListOf("javafx-base", "javafx-graphics", "javafx-controls") + val version = javafxVersion + val fxModules = arrayListOf("javafx-base", "javafx-graphics", "javafx-controls", "javafx-fxml", "javafx-media", "javafx-swing", "javafx-web") } jfxOptions.run { fxModules.forEach { @@ -61,37 +64,38 @@ sourceSets { } } - implementation(group="org.jetbrains", name="annotations", version="20.1.0") + implementation("org.jetbrains:annotations:20.1.0") implementation(project(":pswgcommon")) implementation(project(":forwarder")) implementation("javax.json:javax.json-api:1.1.4") - implementation(group="me.joshlarson", name="fast-json", version="3.0.2") - implementation(group="me.joshlarson", name="jlcommon-fx", version="17.0.1") { - exclude(group="org.openjfx") - } - implementation(group="no.tornado", name="tornadofx", version="2.0.0-SNAPSHOT") { - exclude(group="org.jetbrains.kotlin") + implementation("me.joshlarson:fast-json:3.0.2") + implementation("me.joshlarson:jlcommon-fx:17.0.1") { exclude(group="org.openjfx") } + implementation(project(":tornadofx")) implementation(kotlin("stdlib")) implementation(kotlin("reflect")) - implementation(group="de.jensd", name="fontawesomefx-fontawesome", version="4.7.0-9.1.2") - implementation(group="com.rometools", name="rome", version="1.15.0") { + implementation("de.jensd:fontawesomefx-fontawesome:4.7.0-9.1.2") + implementation("com.rometools:rome:1.15.0") { exclude(group="org.slf4j") } - implementation(group="org.apache.commons", name="commons-text", version="1.9") + implementation("org.apache.commons:commons-text:1.9") implementation("org.slf4j:slf4j-nop:1.7.36") + + testImplementation("org.junit.jupiter:junit-jupiter-api:$junit5Version") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:$junit5Version") + testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.12.2") + testImplementation("org.junit.jupiter:junit-jupiter-params:$junit5Version") } } test { dependencies { - testImplementation(group="junit", name="junit", version="4.12") + testImplementation("junit:junit:4.12") } } } idea { - targetVersion = javaVersion module { inheritOutputDirs = true } @@ -99,22 +103,21 @@ idea { java { modularity.inferModulePath.set(true) + toolchain.languageVersion.set(JavaLanguageVersion.of(javaVersion.majorVersion)) } -task("downloadJmods", de.undercouch.gradle.tasks.download.Download::class) { - val zipPath = buildDir.absolutePath + "/jmods.zip" - val unzipPath = buildDir.absolutePath + "/jmods" - val baseUrl = "https://download2.gluonhq.com/openjfx/$javaVersion/" +val downloadJmods = tasks.register("downloadJmods", de.undercouch.gradle.tasks.download.Download::class) { + val zipPath = layout.buildDirectory.file("jmods.zip").get().asFile + val unzipPath = layout.buildDirectory.dir("jmods").get().asFile + val baseUrl = "https://download2.gluonhq.com/openjfx/$javafxVersion/" val platformUrl = when(platform) { - "mac" -> "openjfx-${javaVersion}_osx-x64_bin-jmods.zip" - "win" -> "openjfx-${javaVersion}_windows-x64_bin-jmods.zip" - else -> "openjfx-${javaVersion}_linux-x64_bin-jmods.zip" + "mac" -> "openjfx-${javafxVersion}_osx-x64_bin-jmods.zip" + "win" -> "openjfx-${javafxVersion}_windows-x64_bin-jmods.zip" + else -> "openjfx-${javafxVersion}_linux-x64_bin-jmods.zip" } src(baseUrl + platformUrl) dest(zipPath) overwrite(false) - tasks.getByName("prepareMergedJarsDir").dependsOn(this) - tasks.getByName("prepareMergedJarsDir").mustRunAfter(this) doLast { copy { @@ -124,12 +127,17 @@ task("downloadJmods", de.undercouch.gradle.tasks.download.Download::class) { } } +tasks.named("prepareMergedJarsDir") { + dependsOn(downloadJmods) + mustRunAfter(downloadJmods) +} + jlink { - addOptions("--strip-debug", "--compress", "2", "--no-header-files", "--no-man-pages", "--ignore-signing-information") + addOptions("--strip-debug", "--compress", "zip-6", "--no-header-files", "--no-man-pages", "--ignore-signing-information") forceMerge("kotlin-stdlib") jlink { - addExtraModulePath("${buildDir.absolutePath}/jmods/javafx-jmods-${javaVersion}") + addExtraModulePath(layout.buildDirectory.dir("jmods/javafx-jmods-${javafxVersion}").get().asFile.absolutePath) } launcher { @@ -142,7 +150,7 @@ jlink { imageName = "ProjectSWG" installerName = "ProjectSWG" - installerOutputDir = File("${buildDir.absolutePath}/installer") + setInstallerOutputDir(layout.buildDirectory.dir("installer").get().asFile) installerType = when(platform) { "linux" -> "deb" @@ -163,8 +171,14 @@ jlink { } tasks.withType().configureEach { - kotlinOptions { - jvmTarget = kotlinTargetJdk + compilerOptions { + jvmTarget.set(kotlinTargetJdk) } - destinationDirectory.set(File(destinationDirectory.get().asFile.path.replace("kotlin", "java"))) +} + +// Make Kotlin classes visible while javac compiles the JPMS module descriptor. +tasks.named("compileJava") { + options.compilerArgumentProviders.add(CommandLineArgumentProvider { + listOf("--patch-module", "com.projectswg.launcher=${sourceSets.main.get().output.asPath}") + }) } diff --git a/forwarder b/forwarder index fa2ec61..e5a0e1d 160000 --- a/forwarder +++ b/forwarder @@ -1 +1 @@ -Subproject commit fa2ec6174384d73dae84efd431741888451a26da +Subproject commit e5a0e1deb7efc67f419f47fc391c048141e50bfe diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index ccebba7..eddabd2 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index bdc9a83..ad7845b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,9 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-bin.zip networkTimeout=10000 +retries=0 +retryBackOffMs=500 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 79a61d4..249efbb 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,10 +15,12 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # -# Gradle start up script for POSIX generated by Gradle. +# gradlew start up script for POSIX generated by Gradle. # # Important for running: # @@ -27,7 +29,7 @@ # bash, then to run this script, type that shell name before the whole # command line, like: # -# ksh Gradle +# ksh gradlew # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -83,10 +85,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -114,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -133,10 +132,13 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. @@ -144,7 +146,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +154,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -169,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -197,16 +198,19 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 6689b85..8508ef6 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,16 +13,18 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem -@rem Gradle startup script for Windows +@rem gradlew startup script for Windows @rem @rem ########################################################################## -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @@ -43,13 +45,13 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% @@ -57,36 +59,24 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +@rem Execute gradlew +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/pswgcommon b/pswgcommon index 8574112..9ab4234 160000 --- a/pswgcommon +++ b/pswgcommon @@ -1 +1 @@ -Subproject commit 85741121960837b048dfe97b180aaf293bdd325b +Subproject commit 9ab4234e94be480f3b48f539a1f0dd6f5bd408a4 diff --git a/settings.gradle.kts b/settings.gradle.kts index 0d88d72..fab98c6 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,2 +1,3 @@ rootProject.name = "launcher" include("pswgcommon", "forwarder", "tornadofx") +project(":tornadofx").projectDir = file("external/tornadofx2") diff --git a/src/main/java/com/projectswg/launcher/resources/pipeline/UpdateServerUpdater.kt b/src/main/java/com/projectswg/launcher/resources/pipeline/UpdateServerUpdater.kt index afd8700..fbb1689 100644 --- a/src/main/java/com/projectswg/launcher/resources/pipeline/UpdateServerUpdater.kt +++ b/src/main/java/com/projectswg/launcher/resources/pipeline/UpdateServerUpdater.kt @@ -104,7 +104,7 @@ object UpdateServerUpdater { * Stage 2: Scan each file and only keep the ones that need to be downloaded. */ private fun filterValidFiles(info: UpdateServerDownloaderInfo) { - val files: MutableList = Objects.requireNonNull?>(info.files, "File list was not read correctly") + val files: MutableList = info.files ?: throw NullPointerException("File list was not read correctly") Log.d("%d known files. Scanning...", files.size) val total = files.size Platform.runLater { info.server.status = UpdateServerStatus.SCANNING } diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 3f92bd0..f84ce83 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -9,7 +9,6 @@ open module com.projectswg.launcher { requires com.projectswg.common; requires com.projectswg.forwarder; - requires jdk.crypto.ec; requires java.prefs; requires java.net.http; requires java.xml;