Skip to content

Commit d60a923

Browse files
Glavo3gf8jv4dv
andauthored
使用 Java 11 构建 HMCL (#4078)
Co-authored-by: 3gf8jv4dv <3gf8jv4dv@gmail.com>
1 parent f9dd7a1 commit d60a923

35 files changed

+408
-470
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ minecraft-exported-crash-info*
1818
/build/
1919
/HMCL/build/
2020
/HMCLCore/build/
21+
/HMCLBoot/build/
2122
/HMCLTransformerDiscoveryService/build/
2223
/minecraft/libraries/HMCLTransformerDiscoveryService/build/
2324
/buildSrc/build/

HMCL/build.gradle.kts

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ version = "$versionRoot.$buildNumber"
3939

4040
dependencies {
4141
implementation(project(":HMCLCore"))
42+
implementation(project(":HMCLBoot"))
4243
implementation("libs:JFoenix")
4344
implementation(libs.twelvemonkeys.imageio.webp)
4445
implementation(libs.java.info)
@@ -89,16 +90,13 @@ fun attachSignature(jar: File) {
8990
}
9091
}
9192

92-
val java11 = sourceSets.create("java11") {
93-
java {
94-
srcDir("src/main/java11")
95-
}
93+
tasks.withType<JavaCompile> {
94+
sourceCompatibility = "11"
95+
targetCompatibility = "11"
9696
}
9797

98-
tasks.getByName<JavaCompile>(java11.compileJavaTaskName) {
98+
tasks.compileJava {
9999
options.compilerArgs.add("--add-exports=java.base/jdk.internal.loader=ALL-UNNAMED")
100-
sourceCompatibility = "11"
101-
targetCompatibility = "11"
102100
}
103101

104102
tasks.jar {
@@ -126,6 +124,7 @@ tasks.shadowJar {
126124
exclude(dependency("com.google.code.gson:.*:.*"))
127125
exclude(dependency("net.java.dev.jna:jna:.*"))
128126
exclude(dependency("libs:JFoenix:.*"))
127+
exclude(project(":HMCLBoot"))
129128
}
130129

131130
manifest {
@@ -174,13 +173,6 @@ tasks.shadowJar {
174173
}
175174
}
176175

177-
tasks.processResources {
178-
into("META-INF/versions/11") {
179-
from(sourceSets["java11"].output)
180-
}
181-
dependsOn(tasks["java11Classes"])
182-
}
183-
184176
val makeExecutables by tasks.registering {
185177
val extensions = listOf("exe", "sh")
186178

HMCL/src/main/java/org/jackhuang/hmcl/Main.java renamed to HMCL/src/main/java/org/jackhuang/hmcl/EntryPoint.java

Lines changed: 16 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -17,41 +17,25 @@
1717
*/
1818
package org.jackhuang.hmcl;
1919

20-
import javafx.application.Platform;
21-
import javafx.scene.control.Alert;
2220
import org.jackhuang.hmcl.util.FileSaver;
2321
import org.jackhuang.hmcl.ui.AwtUtils;
2422
import org.jackhuang.hmcl.util.ModuleHelper;
2523
import org.jackhuang.hmcl.util.SelfDependencyPatcher;
26-
import org.jackhuang.hmcl.ui.SwingUtils;
24+
import org.jackhuang.hmcl.util.SwingUtils;
2725
import org.jackhuang.hmcl.java.JavaRuntime;
2826
import org.jackhuang.hmcl.util.platform.OperatingSystem;
2927

30-
import javax.net.ssl.HttpsURLConnection;
31-
import javax.net.ssl.SSLContext;
32-
import javax.net.ssl.TrustManagerFactory;
33-
import java.io.File;
3428
import java.io.IOException;
35-
import java.io.InputStream;
3629
import java.lang.reflect.Method;
3730
import java.nio.file.Files;
38-
import java.nio.file.Path;
39-
import java.nio.file.Paths;
40-
import java.security.KeyManagementException;
41-
import java.security.KeyStore;
42-
import java.security.KeyStoreException;
43-
import java.security.NoSuchAlgorithmException;
44-
import java.security.cert.CertificateException;
45-
import java.util.Collections;
4631
import java.util.concurrent.CancellationException;
4732

48-
import static org.jackhuang.hmcl.util.Lang.thread;
4933
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
5034
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
5135

52-
public final class Main {
36+
public final class EntryPoint {
5337

54-
private Main() {
38+
private EntryPoint() {
5539
}
5640

5741
public static void main(String[] args) {
@@ -64,10 +48,6 @@ public static void main(String[] args) {
6448

6549
checkDirectoryPath();
6650

67-
if (JavaRuntime.CURRENT_VERSION < 9)
68-
// This environment check will take ~300ms
69-
thread(Main::fixLetsEncrypt, "CA Certificate Check", true);
70-
7151
if (OperatingSystem.CURRENT_OS == OperatingSystem.MACOS)
7252
initIcon();
7353

@@ -97,6 +77,8 @@ private static void createHMCLDirectories() {
9777
}
9878
}
9979
} catch (IOException e) {
80+
// Logger has not been started yet, so print directly to System.err
81+
System.err.println("Failed to create HMCL directory: " + Metadata.HMCL_CURRENT_DIRECTORY);
10082
e.printStackTrace(System.err);
10183
showErrorAndExit(i18n("fatal.create_hmcl_current_directory_failure", Metadata.HMCL_CURRENT_DIRECTORY));
10284
}
@@ -112,27 +94,28 @@ private static void createHMCLDirectories() {
11294
}
11395

11496
private static void initIcon() {
115-
java.awt.Image image = java.awt.Toolkit.getDefaultToolkit().getImage(Main.class.getResource("/assets/img/icon-mac.png"));
97+
java.awt.Image image = java.awt.Toolkit.getDefaultToolkit().getImage(EntryPoint.class.getResource("/assets/img/icon-mac.png"));
11698
AwtUtils.setAppleIcon(image);
11799
}
118100

119101
private static void checkDirectoryPath() {
120-
String currentDirectory = new File("").getAbsolutePath();
121-
if (currentDirectory.contains("!")) {
102+
String currentDir = System.getProperty("user.dir", "");
103+
if (currentDir.contains("!")) {
104+
LOG.error("The current working path contains an exclamation mark: " + currentDir);
122105
// No Chinese translation because both Swing and JavaFX cannot render Chinese character properly when exclamation mark exists in the path.
123106
showErrorAndExit("Exclamation mark(!) is not allowed in the path where HMCL is in.\n"
124-
+ "The path is " + currentDirectory);
107+
+ "The path is " + currentDir);
125108
}
126109
}
127110

128111
private static void checkJavaFX() {
129112
try {
130113
SelfDependencyPatcher.patch();
131114
} catch (SelfDependencyPatcher.PatchException e) {
132-
LOG.error("unable to patch JVM", e);
115+
LOG.error("Unable to patch JVM", e);
133116
showErrorAndExit(i18n("fatal.javafx.missing"));
134117
} catch (SelfDependencyPatcher.IncompatibleVersionException e) {
135-
LOG.error("unable to patch JVM", e);
118+
LOG.error("Unable to patch JVM", e);
136119
showErrorAndExit(i18n("fatal.javafx.incompatible"));
137120
} catch (CancellationException e) {
138121
LOG.error("User cancels downloading JavaFX", e);
@@ -149,7 +132,7 @@ private static void verifyJavaFX() {
149132
Class.forName("javafx.stage.Stage"); // javafx.graphics
150133
Class.forName("javafx.scene.control.Skin"); // javafx.controls
151134
} catch (Exception e) {
152-
e.printStackTrace(System.err);
135+
LOG.warning("JavaFX is incomplete or not found", e);
153136
showErrorAndExit(i18n("fatal.javafx.incomplete"));
154137
}
155138
}
@@ -159,7 +142,7 @@ private static void addEnableNativeAccess() {
159142
try {
160143
ModuleHelper.addEnableNativeAccess(Class.forName("javafx.stage.Stage")); // javafx.graphics
161144
} catch (ClassNotFoundException e) {
162-
e.printStackTrace(System.err);
145+
LOG.error("Failed to add enable native access for JavaFX", e);
163146
showErrorAndExit(i18n("fatal.javafx.incomplete"));
164147
}
165148
}
@@ -174,78 +157,16 @@ private static void enableUnsafeMemoryAccess() {
174157
trySetMemoryAccessWarned.setAccessible(true);
175158
trySetMemoryAccessWarned.invoke(null);
176159
} catch (Throwable e) {
177-
e.printStackTrace(System.err);
160+
LOG.warning("Failed to enable unsafe memory access", e);
178161
}
179162
}
180163
}
181164

182165
/**
183166
* Indicates that a fatal error has occurred, and that the application cannot start.
184167
*/
185-
static void showErrorAndExit(String message) {
186-
System.err.println(message);
187-
System.err.println("A fatal error has occurred, forcibly exiting.");
188-
189-
try {
190-
if (Platform.isFxApplicationThread()) {
191-
new Alert(Alert.AlertType.ERROR, message).showAndWait();
192-
exit(1);
193-
}
194-
} catch (Throwable ignored) {
195-
}
196-
168+
private static void showErrorAndExit(String message) {
197169
SwingUtils.showErrorDialog(message);
198170
exit(1);
199171
}
200-
201-
/**
202-
* Indicates that potential issues have been detected, and that the application may not function properly (but it can still run).
203-
*/
204-
static void showWarningAndContinue(String message) {
205-
System.err.println(message);
206-
System.err.println("Potential issues have been detected.");
207-
208-
try {
209-
if (Platform.isFxApplicationThread()) {
210-
new Alert(Alert.AlertType.WARNING, message).showAndWait();
211-
return;
212-
}
213-
} catch (Throwable ignored) {
214-
}
215-
216-
SwingUtils.showWarningDialog(message);
217-
}
218-
219-
private static void fixLetsEncrypt() {
220-
try {
221-
KeyStore defaultKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
222-
Path ksPath = Paths.get(System.getProperty("java.home"), "lib", "security", "cacerts");
223-
224-
try (InputStream ksStream = Files.newInputStream(ksPath)) {
225-
defaultKeyStore.load(ksStream, "changeit".toCharArray());
226-
}
227-
228-
KeyStore letsEncryptKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
229-
try (InputStream letsEncryptFile = Main.class.getResourceAsStream("/assets/lekeystore.jks")) {
230-
letsEncryptKeyStore.load(letsEncryptFile, "supersecretpassword".toCharArray());
231-
}
232-
233-
KeyStore merged = KeyStore.getInstance(KeyStore.getDefaultType());
234-
merged.load(null, new char[0]);
235-
for (String alias : Collections.list(letsEncryptKeyStore.aliases()))
236-
merged.setCertificateEntry(alias, letsEncryptKeyStore.getCertificate(alias));
237-
for (String alias : Collections.list(defaultKeyStore.aliases()))
238-
merged.setCertificateEntry(alias, defaultKeyStore.getCertificate(alias));
239-
240-
TrustManagerFactory instance = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
241-
instance.init(merged);
242-
SSLContext tls = SSLContext.getInstance("TLS");
243-
tls.init(null, instance.getTrustManagers(), null);
244-
HttpsURLConnection.setDefaultSSLSocketFactory(tls.getSocketFactory());
245-
LOG.info("Added Lets Encrypt root certificates as additional trust");
246-
} catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException |
247-
KeyManagementException e) {
248-
LOG.error("Failed to load lets encrypt certificate. Expect problems", e);
249-
}
250-
}
251172
}

HMCL/src/main/java/org/jackhuang/hmcl/Launcher.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,14 @@ public void start(Stage primaryStage) {
8181
try {
8282
try {
8383
ConfigHolder.init();
84-
} catch (SambaException ignored) {
85-
Main.showWarningAndContinue(i18n("fatal.samba"));
84+
} catch (SambaException e) {
85+
showAlert(AlertType.WARNING, i18n("fatal.samba"));
8686
} catch (IOException e) {
8787
LOG.error("Failed to load config", e);
8888
checkConfigInTempDir();
8989
checkConfigOwner();
90-
Main.showErrorAndExit(i18n("fatal.config_loading_failure", ConfigHolder.configLocation().getParent()));
90+
showAlert(AlertType.ERROR, i18n("fatal.config_loading_failure", ConfigHolder.configLocation().getParent()));
91+
EntryPoint.exit(1);
9192
}
9293

9394
// https://lapcatsoftware.com/articles/app-translocation.html
@@ -106,7 +107,7 @@ public void start(Stage primaryStage) {
106107
}
107108

108109
if (Metadata.HMCL_CURRENT_DIRECTORY.toString().indexOf('=') >= 0) {
109-
Main.showWarningAndContinue(i18n("fatal.illegal_char"));
110+
showAlert(AlertType.WARNING, i18n("fatal.illegal_char"));
110111
}
111112

112113
// runLater to ensure ConfigHolder.init() finished initialization
@@ -169,7 +170,7 @@ private static boolean isConfigInTempDir() {
169170
private static void checkConfigInTempDir() {
170171
if (ConfigHolder.isNewlyCreated() && isConfigInTempDir()
171172
&& showAlert(AlertType.WARNING, i18n("fatal.config_in_temp_dir"), ButtonType.YES, ButtonType.NO) == ButtonType.NO) {
172-
Main.exit(0);
173+
EntryPoint.exit(0);
173174
}
174175
}
175176

@@ -209,7 +210,7 @@ private static void checkConfigOwner() {
209210
Clipboard.getSystemClipboard()
210211
.setContent(Collections.singletonMap(DataFormat.PLAIN_TEXT, command));
211212
}
212-
Main.exit(1);
213+
EntryPoint.exit(1);
213214
}
214215

215216
@Override

HMCL/src/main/java/org/jackhuang/hmcl/Metadata.java

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,10 @@
1919

2020
import org.jackhuang.hmcl.util.StringUtils;
2121
import org.jackhuang.hmcl.util.io.JarUtils;
22-
import org.jackhuang.hmcl.util.platform.Architecture;
2322
import org.jackhuang.hmcl.util.platform.OperatingSystem;
24-
import org.jetbrains.annotations.Nullable;
2523

2624
import java.nio.file.Path;
2725
import java.nio.file.Paths;
28-
import java.util.EnumSet;
2926

3027
/**
3128
* Stores metadata about this application.
@@ -38,9 +35,6 @@ private Metadata() {
3835
public static final String FULL_NAME = "Hello Minecraft! Launcher";
3936
public static final String VERSION = System.getProperty("hmcl.version.override", JarUtils.getManifestAttribute("Implementation-Version", "@develop@"));
4037

41-
public static final int MINIMUM_REQUIRED_JAVA_VERSION = 8;
42-
public static final int MINIMUM_SUPPORTED_JAVA_VERSION = 11;
43-
4438
public static final String TITLE = NAME + " " + VERSION;
4539
public static final String FULL_TITLE = FULL_NAME + " v" + VERSION;
4640

@@ -100,31 +94,4 @@ public static boolean isNightly() {
10094
return !isStable() && !isDev();
10195
}
10296

103-
public static @Nullable String getSuggestedJavaDownloadLink() {
104-
if (OperatingSystem.CURRENT_OS == OperatingSystem.LINUX && Architecture.SYSTEM_ARCH == Architecture.LOONGARCH64_OW)
105-
return "https://www.loongnix.cn/zh/api/java/downloads-jdk21/index.html";
106-
else {
107-
EnumSet<Architecture> supportedArchitectures;
108-
if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS)
109-
supportedArchitectures = EnumSet.of(Architecture.X86_64, Architecture.X86, Architecture.ARM64);
110-
else if (OperatingSystem.CURRENT_OS == OperatingSystem.LINUX)
111-
supportedArchitectures = EnumSet.of(
112-
Architecture.X86_64, Architecture.X86,
113-
Architecture.ARM64, Architecture.ARM32,
114-
Architecture.RISCV64, Architecture.LOONGARCH64
115-
);
116-
else if (OperatingSystem.CURRENT_OS == OperatingSystem.MACOS)
117-
supportedArchitectures = EnumSet.of(Architecture.X86_64, Architecture.ARM64);
118-
else
119-
supportedArchitectures = EnumSet.noneOf(Architecture.class);
120-
121-
if (supportedArchitectures.contains(Architecture.SYSTEM_ARCH))
122-
return String.format("https://docs.hmcl.net/downloads/%s/%s.html",
123-
OperatingSystem.CURRENT_OS.getCheckedName(),
124-
Architecture.SYSTEM_ARCH.getCheckedName()
125-
);
126-
else
127-
return null;
128-
}
129-
}
13097
}

HMCL/src/main/java/org/jackhuang/hmcl/setting/ConfigHolder.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ public static void init() throws IOException {
101101
if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS
102102
&& configLocation.getFileSystem() == FileSystems.getDefault()
103103
&& configLocation.toFile().canWrite()) {
104+
LOG.warning("Config at " + configLocation + " is not writable, but it seems to be a Samba share or OpenJDK bug");
104105
// There are some serious problems with the implementation of Samba or OpenJDK
105106
throw new SambaException();
106107
} else {

0 commit comments

Comments
 (0)