feat: Add progress gui for downloading JavaFX

This commit is contained in:
huanghongxun
2021-03-07 13:15:44 +08:00
parent 63bd707741
commit d22dae9834
12 changed files with 240 additions and 142 deletions

View File

@@ -25,6 +25,7 @@ import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.task.AsyncTaskExecutor;
import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.upgrade.UpdateChecker;
import org.jackhuang.hmcl.upgrade.UpdateHandler;
import org.jackhuang.hmcl.util.CrashReporter;
import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.StringUtils;
@@ -84,6 +85,10 @@ public final class Launcher extends Application {
}
public static void main(String[] args) {
if (UpdateHandler.processArguments(args)) {
return;
}
Thread.setDefaultUncaughtExceptionHandler(CRASH_REPORTER);
AsyncTaskExecutor.setUncaughtExceptionHandler(new CrashReporter(false));

View File

@@ -17,7 +17,6 @@
*/
package org.jackhuang.hmcl;
import org.jackhuang.hmcl.upgrade.UpdateHandler;
import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.SelfDependencyPatcher;
@@ -26,6 +25,8 @@ import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -36,6 +37,7 @@ import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.function.Consumer;
import java.util.logging.Level;
import static org.jackhuang.hmcl.util.Lang.thread;
@@ -59,13 +61,15 @@ public final class Main {
Logging.start(Metadata.HMCL_DIRECTORY.resolve("logs"));
checkJavaFX();
if (UpdateHandler.processArguments(args)) {
return;
checkJavaFX(classLoader -> {
try {
Class<?> c = Class.forName("org.jackhuang.hmcl.Launcher", true, classLoader);
Method method = c.getDeclaredMethod("main");
method.invoke(null, (Object) args);
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
throw new InternalError(e);
}
Launcher.main(args);
});
}
private static void checkDirectoryPath() {
@@ -77,8 +81,16 @@ public final class Main {
}
}
private static void checkJavaFX() {
SelfDependencyPatcher.patch();
private static void checkJavaFX(Consumer<ClassLoader> runnable) {
try {
SelfDependencyPatcher.runInJavaFxEnvironment(runnable);
} catch (SelfDependencyPatcher.PatchException e) {
LOG.log(Level.SEVERE, "unable to patch JVM", e);
showErrorAndExit(i18n("fatal.javafx.missing"));
} catch (SelfDependencyPatcher.IncompatibleVersionException e) {
LOG.log(Level.SEVERE, "unable to patch JVM", e);
showErrorAndExit(i18n("fatal.javafx.incompatible"));
}
}
private static void checkDSTRootCAX3() {

View File

@@ -340,7 +340,7 @@ public final class LauncherHelper {
}
// LaunchWrapper 1.12 will crash because of assuming the system class loader is an instance of URLClassLoader.
if (!flag && java.getParsedVersion() >= JavaVersion.JAVA_9_AND_LATER
if (!flag && java.getParsedVersion() >= JavaVersion.JAVA_9
&& version.getMainClass().equals(LibraryAnalyzer.LAUNCH_WRAPPER_MAIN)
&& version.getLibraries().stream()
.filter(library -> "launchwrapper".equals(library.getArtifactId()))

View File

@@ -1,8 +1,11 @@
package org.jackhuang.hmcl.util;
import com.nqzero.permit.Permit;
import org.jackhuang.hmcl.util.io.ChecksumMismatchException;
import org.jackhuang.hmcl.util.io.NetworkUtils;
import org.jackhuang.hmcl.util.platform.OperatingSystem;
import javax.swing.*;
import java.awt.*;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
@@ -12,15 +15,18 @@ import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.List;
import java.util.*;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.regex.Matcher;
import static java.lang.Class.forName;
import static javax.swing.JOptionPane.ERROR_MESSAGE;
import static javax.swing.JOptionPane.showMessageDialog;
import static org.jackhuang.hmcl.Metadata.HMCL_DIRECTORY;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
import static org.jackhuang.hmcl.util.platform.JavaVersion.CURRENT_JAVA;
/**
* Utility for patching self when missing dependencies.
@@ -83,32 +89,39 @@ public class SelfDependencyPatcher {
/**
* Patch in any missing dependencies, if any.
*/
public static void patch() {
if (getVmVersion() > 8) {
Permit.godMode();
Permit.unLog();
public static void runInJavaFxEnvironment(Consumer<ClassLoader> runnable) throws PatchException, IncompatibleVersionException {
if (CURRENT_JAVA.getParsedVersion() > 8) {
patchReflectionFilters();
}
// Do nothing if JavaFX is detected
try {
try {
forName("javafx.application.Platform", false, ClassLoader.getSystemClassLoader());
return;
} catch(Exception ignored) {
forName("javafx.application.Application");
runnable.accept(SelfDependencyPatcher.class.getClassLoader());
} catch (Exception ignored) {
}
} catch(UnsupportedClassVersionError error) {
} catch (UnsupportedClassVersionError error) {
// Loading the JavaFX class was unsupported.
// We are probably on 8 and its on 11
showIncompatibleVersion();
return;
throw new IncompatibleVersionException();
}
// So the problem with Java 8 is that some distributions DO NOT BUNDLE JAVAFX
// Why is this a problem? OpenJFX does not come in public bundles prior to Java 11
// So you're out of luck unless you change your JDK or update Java.
if (getVmVersion() < 11) {
showIncompatibleVersion();
return;
if (CURRENT_JAVA.getParsedVersion() < 11) {
throw new IncompatibleVersionException();
}
// We can only self-patch JavaFX on x86 platform.
// For ARM support, user's manual patch is required.
switch (System.getProperty("os.arch")) {
case "amd64":
case "x86":
break;
default:
throw new IncompatibleVersionException();
}
// Otherwise we're free to download in Java 11+
LOG.info("Missing JavaFX dependencies, attempting to patch in missing classes");
// Check if dependencies need to be downloaded
@@ -116,9 +129,8 @@ public class SelfDependencyPatcher {
LOG.info(" - No local cache, downloading dependencies...");
try {
fetchDependencies();
} catch(IOException ex) {
logError(ex, "Failed to download dependencies!");
System.exit(-1);
} catch (Exception ex) {
throw new PatchException("Failed to download dependencies", ex);
}
} else {
LOG.info(" - Local cache found!");
@@ -126,17 +138,35 @@ public class SelfDependencyPatcher {
// Add the dependencies
try {
loadFromCache();
} catch(IOException ex) {
logError(ex, ex.getMessage());
System.exit(-1);
} catch(ReflectiveOperationException ex) {
logError(ex, "Failed to add dependencies to classpath!");
System.exit(-1);
} catch (IOException ex) {
throw new PatchException("Failed to load JavaFX cache", ex);
} catch (ReflectiveOperationException ex) {
throw new PatchException("Failed to add dependencies to classpath!", ex);
}
LOG.info(" - Done!");
}
// /**
// * Inject them into the current classpath.
// *
// * @throws IOException When the locally cached dependency urls cannot be resolved.
// * @throws ReflectiveOperationException When the call to add these urls to the system classpath failed.
// */
// private static void loadFromCache(Consumer<ClassLoader> runnable) throws IOException, ReflectiveOperationException {
// LOG.info(" - Loading dependencies...");
// // Get Jar URLs
// List<URL> jarUrls = new ArrayList<>();
// Files.walk(DEPENDENCIES_DIR_PATH).forEach(path -> {
// try {
// jarUrls.add(path.toUri().toURL());
// } catch (MalformedURLException ex) {
// LOG.log(Level.WARNING, "Failed to convert '" + path.toFile().getAbsolutePath() + "' to URL", ex);
// }
// });
// ClassLoader classLoader = new URLClassLoader(jarUrls.toArray(new URL[0]), SelfDependencyPatcher.class.getClassLoader());
// runnable.accept(classLoader);
// }
/**
* Inject them into the current classpath.
*
@@ -153,7 +183,7 @@ public class SelfDependencyPatcher {
try {
jarUrls.add(path.toUri().toURL());
} catch(MalformedURLException ex) {
logError(ex, "Failed to convert '%s' to URL", path.toFile().getAbsolutePath());
LOG.log(Level.WARNING, "Failed to convert '" + path.toFile().getAbsolutePath() + "' to URL", ex);
}
});
// Fetch UCP of application's ClassLoader
@@ -162,7 +192,7 @@ public class SelfDependencyPatcher {
Object appClassLoader = clsClassLoaders.getDeclaredMethod("appClassLoader").invoke(null);
Class<?> ucpOwner = appClassLoader.getClass();
// Field removed in 16, but still exists in parent class "BuiltinClassLoader"
if (getVmVersion() >= 16)
if (CURRENT_JAVA.getParsedVersion() >= 16)
ucpOwner = ucpOwner.getSuperclass();
Field fieldUCP = ucpOwner.getDeclaredField("ucp");
fieldUCP.setAccessible(true);
@@ -175,42 +205,47 @@ public class SelfDependencyPatcher {
addURL.invoke(ucp, url);
}
/**
* Display a message detailing why self-patching cannot continue.
*/
private static void showIncompatibleVersion() {
String message = "Application cannot self-patch below Java 11 on this JVM. " +
"Please run using JDK 11 or higher or use a JDK that bundles JavaFX.\n" +
" - Your JDK does not bundle JavaFX\n" +
" - Downloadable JFX bundles only come with 11 support or higher.";
showMessageDialog(null, message, "Error: Cannot self-patch", ERROR_MESSAGE);
// LOG and exit
LOG.severe(message);
System.exit(-1);
}
/**
* Download dependencies.
*
* @throws IOException
* When the files cannot be fetched or saved.
* @throws IOException When the files cannot be fetched or saved.
*/
private static void fetchDependencies() throws IOException {
private static void fetchDependencies() throws Exception {
// Get dir to store dependencies in
Path dependenciesDir = DEPENDENCIES_DIR_PATH;
if (!Files.isDirectory(dependenciesDir)) {
Files.createDirectories(dependenciesDir);
}
ProgressFrame dialog = new ProgressFrame(i18n("download.javafx"));
ForkJoinTask<Void> task = ForkJoinPool.commonPool().submit(() -> {
// Download each dependency
List<String> dependencies = getLatestDependencies();
for(String dependencyPattern : dependencies) {
String dependencyUrlPath = String.format(dependencyPattern, getMvnName());
for (int i = 0; i < dependencies.size(); i++) {
String dependencyUrlPath = dependencies.get(i);
URL depURL = new URL(dependencyUrlPath);
Path dependencyFilePath = DEPENDENCIES_DIR_PATH.resolve(getFileName(dependencyUrlPath));
int finalI = i;
SwingUtilities.invokeLater(() -> {
dialog.setStatus(dependencyUrlPath);
dialog.setProgress(finalI, dependencies.size());
});
String expectedHash = NetworkUtils.doGet(NetworkUtils.toURL(dependencyUrlPath + ".sha1"));
Files.copy(depURL.openStream(), dependencyFilePath, StandardCopyOption.REPLACE_EXISTING);
String actualHash = Hex.encodeHex(DigestUtils.digest("SHA-1", dependencyFilePath));
if (!expectedHash.equalsIgnoreCase(actualHash)) {
throw new ChecksumMismatchException("SHA-1", expectedHash, actualHash);
}
}
return null;
});
dialog.setVisible(true);
task.get();
}
/**
* @return {@code true} when the dependencies directory has files in it.
*/
@@ -222,9 +257,7 @@ public class SelfDependencyPatcher {
}
/**
* @param url
* Full url path.
*
* @param url Full url path.
* @return Name of file at url.
*/
private static String getFileName(String url) {
@@ -232,23 +265,22 @@ public class SelfDependencyPatcher {
}
/**
* @param component
* Name of the component.
*
* @param component Name of the component.
* @return Formed URL for the component.
*/
private static String jfxUrl(String component, String version) {
// Add platform specific identifier to the end.
// https://repo1.maven.org/maven2/org/openjfx/javafx-%s/%s/javafx-%s-%s
return String.format("https://maven.aliyun.com/repository/central/org/openjfx/javafx-%s/%s/javafx-%s-%s",
component, version, component, version) + "-%s.jar";
// https://repo1.maven.org/maven2/org/openjfx/javafx-%s/%s/javafx-%s-%s-%s.jar
return String.format("https://maven.aliyun.com/repository/central/org/openjfx/javafx-%s/%s/javafx-%s-%s-%s.jar",
component, version, component, version, getMvnName());
// return String.format("https://bmclapi.bangbang93.com/maven/org/openjfx/javafx-%s/%s/javafx-%s-%s-%s.jar",
// component, version, component, version, getMvnName());
}
/**
* @return Latest JavaFX supported version for.
*/
private static int getLatestSupportedJfxVersion() {
int version = getVmVersion();
int version = CURRENT_JAVA.getParsedVersion();
while (version >= 11) {
List<String> dependencies = JFX_DEPENDENCIES.get(version);
if (dependencies != null)
@@ -269,40 +301,14 @@ public class SelfDependencyPatcher {
throw new AssertionError("Failed to get latest JFX artifact urls");
}
private static void logError(Throwable t, String msg, Object... args) {
LOG.log(Level.SEVERE, t, () -> compile(msg, args));
}
/**
* Compiles message with "{}" arg patterns.
*
* @param msg
* Message pattern.
* @param args
* Values to pass.
*
* @return Compiled message with inlined arg values.
*/
private static String compile(String msg, Object[] args) {
int c = 0;
while(msg.contains("{}")) {
// Failsafe, shouldn't occur if logging is written correctly
if (c == args.length)
return msg;
// Replace arg in pattern
Object arg = args[c];
String argStr = arg == null ? "null" : arg.toString();
msg = msg.replaceFirst("\\{}", Matcher.quoteReplacement(argStr));
c++;
}
return msg;
}
private static String getMvnName() {
switch (OperatingSystem.CURRENT_OS) {
case LINUX: return "linux";
case OSX: return "mac";
default: return "win";
case LINUX:
return "linux";
case OSX:
return "mac";
default:
return "win";
}
}
@@ -321,12 +327,12 @@ public class SelfDependencyPatcher {
Field[] fields;
try {
Method m = Class.class.getDeclaredMethod("getDeclaredFieldsImpl");
m.setAccessible(true);
ReflectionHelper.setAccessible(m);
fields = (Field[]) m.invoke(klass);
} catch (NoSuchMethodException | InvocationTargetException ex) {
try {
Method m = Class.class.getDeclaredMethod("getDeclaredFields0", Boolean.TYPE);
m.setAccessible(true);
ReflectionHelper.setAccessible(m);
fields = (Field[]) m.invoke(klass, false);
} catch (InvocationTargetException | NoSuchMethodException ex1) {
ex.addSuppressed(ex1);
@@ -337,7 +343,7 @@ public class SelfDependencyPatcher {
for (Field field : fields) {
String name = field.getName();
if ("fieldFilterMap".equals(name) || "methodFilterMap".equals(name)) {
field.setAccessible(true);
ReflectionHelper.setAccessible(field);
field.set(null, new HashMap<>(0));
if (++c == 2) {
return;
@@ -346,33 +352,80 @@ public class SelfDependencyPatcher {
}
throw new RuntimeException("One of field patches did not apply properly. " +
"Expected to patch two fields, but patched: " + c);
} catch (IllegalAccessException ex) {
} catch (IllegalAccessException | InvocationTargetException ex) {
throw new RuntimeException("Unable to patch reflection filters", ex);
}
}
private static int vmVersion = -1;
/**
* @return running VM version.
*/
public static int getVmVersion() {
if (vmVersion < 0) {
// Check for class version, ez
String property = System.getProperty("java.class.version", "");
if (!property.isEmpty())
return vmVersion = (int) (Float.parseFloat(property) - 44);
// Odd, not found. Try the spec version
LOG.warning("Using fallback vm-version fetch, no value for 'java.class.version'");
property = System.getProperty("java.vm.specification.version", "");
if (property.contains("."))
return vmVersion = (int) Float.parseFloat(property.substring(property.indexOf('.') + 1));
else if (!property.isEmpty())
return vmVersion = Integer.parseInt(property);
// Very odd
LOG.warning("Fallback vm-version fetch failed, defaulting to 8");
return 8;
public static class PatchException extends Exception {
PatchException(String message, Throwable cause) {
super(message, cause);
}
}
public static class IncompatibleVersionException extends Exception {
}
public static class ProgressFrame extends JDialog {
private int totalTasks = 0;
private int finishedTasks = 0;
private final JProgressBar progressBar;
private final JLabel progressText;
public ProgressFrame(String title) {
super();
JPanel panel = new JPanel();
setResizable(false);
setTitle(title);
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
setBounds(100, 100, 600, 150);
setContentPane(panel);
setLocationRelativeTo(null);
GridBagLayout gridBagLayout = new GridBagLayout();
gridBagLayout.columnWidths = new int[]{600, 0};
gridBagLayout.rowHeights = new int[]{0, 0, 0, 200};
gridBagLayout.columnWeights = new double[]{1.0, Double.MIN_VALUE};
gridBagLayout.rowWeights = new double[]{0.0, 0.0, 0.0, 1.0};
panel.setLayout(gridBagLayout);
progressText = new JLabel("");
GridBagConstraints gbc_lblProgressText = new GridBagConstraints();
gbc_lblProgressText.insets = new Insets(10, 0, 5, 0);
gbc_lblProgressText.gridx = 0;
gbc_lblProgressText.gridy = 0;
panel.add(progressText, gbc_lblProgressText);
progressBar = new JProgressBar();
GridBagConstraints gbc_progressBar = new GridBagConstraints();
gbc_progressBar.insets = new Insets(0, 25, 5, 25);
gbc_progressBar.fill = GridBagConstraints.HORIZONTAL;
gbc_progressBar.gridx = 0;
gbc_progressBar.gridy = 1;
panel.add(progressBar, gbc_progressBar);
JButton btnCancel = new JButton(i18n("button.cancel"));
btnCancel.addActionListener(e -> {
System.exit(-1);
});
GridBagConstraints gbc_btnCancel = new GridBagConstraints();
gbc_btnCancel.insets = new Insets(0, 25, 5, 25);
gbc_btnCancel.fill = GridBagConstraints.HORIZONTAL;
gbc_btnCancel.gridx = 0;
gbc_btnCancel.gridy = 2;
panel.add(btnCancel, gbc_btnCancel);
}
public void setStatus(String status) {
progressText.setText(status);
}
public void setProgress(int current, int total) {
progressBar.setValue(current);
progressBar.setMaximum(total);
}
return vmVersion;
}
}

View File

@@ -113,7 +113,8 @@ extension.mod=Mod file
extension.png=Image file
extension.sh=Bash shell
fatal.missing_javafx=JavaFX is missing.\nIf you are using Java 11 or later, please downgrade to Java 8 or 10.\nIf you are using OpenJDK, please ensure OpenJFX is included.
fatal.javafx.incompatible=Application cannot patch JavaFX on current Java environment below 11.\nPlease run this app using JDK 11 or higher or a JDK with JavaFX bundled.
fatal.javafx.missing=JavaFX is missing.\nIf you are using Java 11 or later, please downgrade to Java 8 or 10.\nIf you are using OpenJDK, please ensure OpenJFX is included.
fatal.missing_dst_root_ca_x3=The DST Root CA X3 certificate is missing on the current Java platform.\nYou can still use Hello Minecraft! Launcher, but it will be unable to connect to some sites (such as sites that use certificates issued by Let's Encrypt), which may cause the launcher not to function properly.\nPlease upgrade your Java Runtime to 8u101 or later to resolve the problem.
fatal.config_loading_failure=The configuration is not accessible.\nPlease ensure Hello Minecraft! Launcher has read and write access to "%s" and the files in it.
fatal.migration_requires_manual_reboot=The update is complete. Please reopen Hello Minecraft! Launcher.

View File

@@ -113,7 +113,8 @@ extension.mod=模組檔案
extension.png=圖片檔案
extension.sh=Bash 指令碼
fatal.missing_javafx=找不到 JavaFX。\n如果您使用的是 Java 11 或更高版本,請降級到 Java 8 或 10。\n如果您使用的是 OpenJDK請確保其包含 OpenJFX
fatal.javafx.incompatible=缺少 JavaFX 運行環境。\nHMCL 無法在低於 Java 11 且缺少 JavaFX 的 Java 環境上自行補全 JavaFX 運行環境。\n請更換如 Oracle Java 8 等包含 JavaFX 的 Java 運行環境,或者更新到 Java 11 或更高版本
fatal.javafx.missing=找不到 JavaFX。\n如果您使用的是 Java 11 或更高版本,請降級到 Java 8 或 10。\n如果您使用的是 OpenJDK請確保其包含 OpenJFX。
fatal.missing_dst_root_ca_x3=目前的 Java 平台缺少 DST Root CA X3 憑證。\n您依然可以使用 Hello Minecraft! Launcher但會無法連線到部分網站 (如使用 Lets Encrypt 憑證的站台),這可能會使 Hello Minecraft! Launcher 無法正常運作。\n請將您的 Java 升級到 8u101 以上來解決此問題。
fatal.config_loading_failure=Hello Minecraft! Launcher 無法載入設定檔案。\n請確保 Hello Minecraft! Launcher 對 "%s" 目錄及該目錄下的檔案擁有讀寫權限。
fatal.migration_requires_manual_reboot=Hello Minecraft! Launcher 即將升級完成,請重新開啟 Hello Minecraft! Launcher。

View File

@@ -113,7 +113,8 @@ extension.mod=模组文件
extension.png=图片文件
extension.sh=Bash 脚本
fatal.missing_javafx=JavaFX 缺失。\n如果您使用的是 Java 11 或更高版本,请降级到 Java 8 或 10。\n如果您使用的是 OpenJDK请确保其包含 OpenJFX
fatal.javafx.incompatible=缺少 JavaFX 运行环境。\nHMCL 无法在低于 Java 11 且缺少 JavaFX 的 Java 环境上自行补全 JavaFX 运行环境。\n请更换如 Oracle Java 8 等包含 JavaFX 的 Java 运行环境,或者更新到 Java 11 或更高版本
fatal.javafx.missing=缺少 JavaFX 运行环境。\n如果您使用的是 Java 11 或更高版本,请降级到 Oracle Java 8 或 10或者安装 Bell-Soft Liberica Full JRE。\n如果您使用的是其他 OpenJDK请确保其包含 OpenJFX。
fatal.missing_dst_root_ca_x3=当前 Java 平台缺少 DST Root CA X3 证书。\n您依然可以使用 Hello Minecraft! Launcher但将无法连接到部分站点如使用 Lets Encrypt 证书的站点),这可能会使 HMCL 无法正常工作。\n请将您的 Java 升级到 8u101 以上以解决此问题。
fatal.config_loading_failure=Hello Minecraft! Launcher 无法加载配置文件。\n请确保 Hello Minecraft! Launcher 对 "%s" 目录及该目录下的文件拥有读写权限。
fatal.migration_requires_manual_reboot=Hello Minecraft! Launcher 即将完成升级,请重新打开 Hello Minecraft! Launcher。

View File

@@ -231,7 +231,7 @@ public class DefaultLauncher extends Launcher {
}
private final Map<String, Supplier<Boolean>> forbiddens = mapOf(
pair("-Xincgc", () -> options.getJava().getParsedVersion() >= JavaVersion.JAVA_9_AND_LATER)
pair("-Xincgc", () -> options.getJava().getParsedVersion() >= JavaVersion.JAVA_9)
);
protected Map<String, Supplier<Boolean>> getForbiddens() {

View File

@@ -66,7 +66,7 @@ public abstract class TaskExecutor {
return cancelled.get();
}
public int getRunningTasks() {
public int getTaskCount() {
return totTask.get();
}

View File

@@ -17,6 +17,9 @@
*/
package org.jackhuang.hmcl.util;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.function.Predicate;
/**
@@ -24,6 +27,19 @@ import java.util.function.Predicate;
* @author huangyuhui
*/
public final class ReflectionHelper {
private static Method accessible0;
static {
try {
accessible0 = AccessibleObject.class.getDeclaredMethod("setAccessible0", boolean.class);
accessible0.setAccessible(true);
} catch (Throwable ex) {
}
}
public static void setAccessible(AccessibleObject obj) throws InvocationTargetException, IllegalAccessException {
accessible0.invoke(obj, true);
}
/**
* Get caller, this method is caller sensitive.

View File

@@ -80,6 +80,7 @@ public final class JavaVersion {
/**
* The major version of Java installation.
*
* @see org.jackhuang.hmcl.util.platform.JavaVersion#JAVA_9
* @see org.jackhuang.hmcl.util.platform.JavaVersion#JAVA_8
* @see org.jackhuang.hmcl.util.platform.JavaVersion#JAVA_7
* @see org.jackhuang.hmcl.util.platform.JavaVersion#UNKNOWN
@@ -92,15 +93,15 @@ public final class JavaVersion {
private static final Pattern VERSION = Pattern.compile("^(?<version>[0-9]+)");
public static final int UNKNOWN = -1;
public static final int JAVA_7 = 70;
public static final int JAVA_8 = 80;
public static final int JAVA_9_AND_LATER = 90;
public static final int JAVA_7 = 7;
public static final int JAVA_8 = 8;
public static final int JAVA_9 = 9;
private static int parseVersion(String version) {
Matcher matcher = VERSION.matcher(version);
if (matcher.find()) {
int head = Lang.parseInt(matcher.group(), -1);
if (head > 1) return JAVA_9_AND_LATER;
if (head > 1) return head;
}
if (version.contains("1.8"))
return JAVA_8;

View File

@@ -33,6 +33,14 @@ subprojects {
compile group: 'com.nqzero', name: 'permit-reflect', version: '0.3'
compileOnly group: 'org.jetbrains', name: 'annotations', version: '16.0.3'
// compileOnly group: 'org.openjfx', name: 'javafx-base', version: '15', classifier: 'win'
// compileOnly group: 'org.openjfx', name: 'javafx-controls', version: '15', classifier: 'win'
// compileOnly group: 'org.openjfx', name: 'javafx-fxml', version: '15', classifier: 'win'
// compileOnly group: 'org.openjfx', name: 'javafx-graphics', version: '15', classifier: 'win'
// compileOnly group: 'org.openjfx', name: 'javafx-media', version: '15', classifier: 'win'
// compileOnly group: 'org.openjfx', name: 'javafx-swing', version: '15', classifier: 'win'
// compileOnly group: 'org.openjfx', name: 'javafx-web', version: '15', classifier: 'win'
testCompile group: 'junit', name: 'junit', version: '4.12'
}