优化对于 IntelliJ IDEA 的支持 (#4270)

This commit is contained in:
Glavo
2025-08-20 20:33:03 +08:00
committed by GitHub
parent 0e12c1a132
commit af56096162
7 changed files with 115 additions and 70 deletions

View File

@@ -108,6 +108,50 @@ tasks.compileJava {
options.compilerArgs.add("--add-exports=java.base/jdk.internal.loader=ALL-UNNAMED")
}
val hmclProperties = buildList {
add("hmcl.version" to project.version.toString())
System.getenv("GITHUB_SHA")?.let {
add("hmcl.version.hash" to it)
}
add("hmcl.version.type" to versionType)
add("hmcl.microsoft.auth.id" to microsoftAuthId)
add("hmcl.microsoft.auth.secret" to microsoftAuthSecret)
add("hmcl.curseforge.apikey" to curseForgeApiKey)
add("hmcl.authlib-injector.version" to libs.authlib.injector.get().version!!)
}
val hmclPropertiesFile = layout.buildDirectory.file("hmcl.properties")
val createPropertiesFile by tasks.registering {
outputs.file(hmclPropertiesFile)
hmclProperties.forEach { (k, v) -> inputs.property(k, v) }
doLast {
val targetFile = hmclPropertiesFile.get().asFile
targetFile.parentFile.mkdir()
targetFile.bufferedWriter().use {
for ((k, v) in hmclProperties) {
it.write("$k=$v\n")
}
}
}
}
val addOpens = listOf(
"java.base/java.lang",
"java.base/java.lang.reflect",
"java.base/jdk.internal.loader",
"javafx.base/com.sun.javafx.binding",
"javafx.base/com.sun.javafx.event",
"javafx.base/com.sun.javafx.runtime",
"javafx.graphics/javafx.css",
"javafx.graphics/com.sun.javafx.stage",
"javafx.graphics/com.sun.prism",
"javafx.controls/com.sun.javafx.scene.control",
"javafx.controls/com.sun.javafx.scene.control.behavior",
"javafx.controls/javafx.scene.control.skin",
"jdk.attach/sun.tools.attach",
)
tasks.jar {
enabled = false
dependsOn(tasks["shadowJar"])
@@ -116,6 +160,8 @@ tasks.jar {
val jarPath = tasks.jar.get().archiveFile.get().asFile
tasks.shadowJar {
dependsOn(createPropertiesFile)
archiveClassifier.set(null as String?)
exclude("**/package-info.class")
@@ -136,43 +182,14 @@ tasks.shadowJar {
exclude(project(":HMCLBoot"))
}
into("assets/") {
from(embedResources)
}
manifest {
attributes(
"Created-By" to "Copyright(c) 2013-2025 huangyuhui.",
"Main-Class" to "org.jackhuang.hmcl.Main",
"Multi-Release" to "true",
"Implementation-Version" to project.version,
"Microsoft-Auth-Id" to microsoftAuthId,
"Microsoft-Auth-Secret" to microsoftAuthSecret,
"CurseForge-Api-Key" to curseForgeApiKey,
"Authlib-Injector-Version" to libs.authlib.injector.get().version!!,
"Build-Channel" to versionType,
"Add-Opens" to listOf(
"java.base/java.lang",
"java.base/java.lang.reflect",
"java.base/jdk.internal.loader",
"javafx.base/com.sun.javafx.binding",
"javafx.base/com.sun.javafx.event",
"javafx.base/com.sun.javafx.runtime",
"javafx.graphics/javafx.css",
"javafx.graphics/com.sun.javafx.stage",
"javafx.graphics/com.sun.prism",
"javafx.controls/com.sun.javafx.scene.control",
"javafx.controls/com.sun.javafx.scene.control.behavior",
"javafx.controls/javafx.scene.control.skin",
"jdk.attach/sun.tools.attach",
).joinToString(" "),
"Enable-Native-Access" to "ALL-UNNAMED"
)
System.getenv("GITHUB_SHA")?.also {
attributes("GitHub-SHA" to it)
}
}
manifest.attributes(
"Created-By" to "Copyright(c) 2013-2025 huangyuhui.",
"Implementation-Version" to project.version.toString(),
"Main-Class" to "org.jackhuang.hmcl.Main",
"Multi-Release" to "true",
"Add-Opens" to addOpens.joinToString(" "),
"Enable-Native-Access" to "ALL-UNNAMED"
)
if (launcherExe != null) {
into("assets") {
@@ -186,6 +203,15 @@ tasks.shadowJar {
}
}
tasks.processResources {
dependsOn(createPropertiesFile)
into("assets/") {
from(hmclPropertiesFile)
from(embedResources)
}
}
val makeExecutables by tasks.registering {
val extensions = listOf("exe", "sh")
@@ -268,6 +294,16 @@ fun parseToolOptions(options: String?): MutableList<String> {
return result
}
// For IntelliJ IDEA
tasks.withType<JavaExec> {
if (name != "run") {
jvmArgs(addOpens.map { "--add-opens=$it=ALL-UNNAMED" })
if (javaVersion >= JavaVersion.VERSION_24) {
jvmArgs("--enable-native-access=ALL-UNNAMED")
}
}
}
tasks.register<JavaExec>("run") {
dependsOn(tasks.jar)

View File

@@ -33,7 +33,7 @@ public final class Metadata {
public static final String NAME = "HMCL";
public static final String FULL_NAME = "Hello Minecraft! Launcher";
public static final String VERSION = System.getProperty("hmcl.version.override", JarUtils.getManifestAttribute("Implementation-Version", "@develop@"));
public static final String VERSION = System.getProperty("hmcl.version.override", JarUtils.getAttribute("hmcl.version", "@develop@"));
public static final String TITLE = NAME + " " + VERSION;
public static final String FULL_TITLE = FULL_NAME + " v" + VERSION;
@@ -49,8 +49,8 @@ public final class Metadata {
public static final String EULA_URL = DOCS_URL + "/eula/hmcl.html";
public static final String GROUPS_URL = "https://www.bilibili.com/opus/905435541874409529";
public static final String BUILD_CHANNEL = JarUtils.getManifestAttribute("Build-Channel", "nightly");
public static final String GITHUB_SHA = JarUtils.getManifestAttribute("GitHub-SHA", null);
public static final String BUILD_CHANNEL = JarUtils.getAttribute("hmcl.version.type", "nightly");
public static final String GITHUB_SHA = JarUtils.getAttribute("hmcl.version.hash", null);
public static final Path CURRENT_DIRECTORY = Paths.get(System.getProperty("user.dir")).toAbsolutePath().normalize();
public static final Path MINECRAFT_DIRECTORY = OperatingSystem.getWorkingDirectory("minecraft");

View File

@@ -158,13 +158,13 @@ public final class OAuthServer extends NanoHTTPD implements OAuth.Session {
@Override
public String getClientId() {
return System.getProperty("hmcl.microsoft.auth.id",
JarUtils.getManifestAttribute("Microsoft-Auth-Id", ""));
JarUtils.getAttribute("hmcl.microsoft.auth.id", ""));
}
@Override
public String getClientSecret() {
return System.getProperty("hmcl.microsoft.auth.secret",
JarUtils.getManifestAttribute("Microsoft-Auth-Secret", ""));
JarUtils.getAttribute("hmcl.microsoft.auth.secret", ""));
}
@Override

View File

@@ -363,9 +363,9 @@ public final class Accounts {
return new SimpleAuthlibInjectorArtifactProvider(Paths.get(authlibinjectorLocation));
}
String authlibInjectorVersion = JarUtils.getManifestAttribute("Authlib-Injector-Version", null);
String authlibInjectorVersion = JarUtils.getAttribute("hmcl.authlib-injector.version", null);
if (authlibInjectorVersion == null)
throw new AssertionError("Missing Authlib-Injector-Version");
throw new AssertionError("Missing hmcl.authlib-injector.version");
String authlibInjectorFileName = "authlib-injector-" + authlibInjectorVersion + ".jar";
return new AuthlibInjectorExtractor(Accounts.class.getResource("/assets/" + authlibInjectorFileName),

View File

@@ -46,7 +46,6 @@ import org.jackhuang.hmcl.Metadata;
import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.io.ChecksumMismatchException;
import org.jackhuang.hmcl.util.io.IOUtils;
import org.jackhuang.hmcl.util.io.JarUtils;
import org.jackhuang.hmcl.java.JavaRuntime;
import org.jackhuang.hmcl.util.platform.Platform;
@@ -63,6 +62,7 @@ import java.util.List;
import java.util.*;
import java.util.concurrent.CancellationException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.jar.Manifest;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.stream.Collectors.toSet;
@@ -261,9 +261,15 @@ public final class SelfDependencyPatcher {
.map(DependencyDescriptor::localPath)
.toArray(Path[]::new);
String[] addOpens = JarUtils.getManifestAttribute("Add-Opens", "").split(" ");
String addOpens = null;
try (InputStream input = SelfDependencyPatcher.class.getResourceAsStream("/META-INF/MANIFEST.MF")) {
if (input != null)
addOpens = new Manifest(input).getMainAttributes().getValue("Add-Opens");
} catch (IOException e) {
LOG.warning("Failed to read MANIFEST.MF file", e);
}
JavaFXPatcher.patch(modules, jars, addOpens);
JavaFXPatcher.patch(modules, jars, addOpens != null ? addOpens.split(" ") : new String[0]);
}
/**

View File

@@ -45,7 +45,7 @@ import static org.jackhuang.hmcl.util.gson.JsonUtils.listTypeOf;
public final class CurseForgeRemoteModRepository implements RemoteModRepository {
private static final String PREFIX = "https://api.curseforge.com";
private static final String apiKey = System.getProperty("hmcl.curseforge.apikey", JarUtils.getManifestAttribute("CurseForge-Api-Key", ""));
private static final String apiKey = System.getProperty("hmcl.curseforge.apikey", JarUtils.getAttribute("hmcl.curseforge.apikey", ""));
private static final int WORD_PERFECT_MATCH_WEIGHT = 5;

View File

@@ -20,47 +20,51 @@ package org.jackhuang.hmcl.util.io;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystemNotFoundException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.CodeSource;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.Properties;
public final class JarUtils {
private JarUtils() {
}
private static final Path THIS_JAR;
private static final Manifest manifest;
private static final Properties properties = new Properties();
static {
CodeSource cs = JarUtils.class.getProtectionDomain().getCodeSource();
Class<?> entryPointClass = null;
CodeSource cs = null;
try {
entryPointClass = Class.forName("org.jackhuang.hmcl.EntryPoint");
cs = entryPointClass.getProtectionDomain().getCodeSource();
} catch (ClassNotFoundException ignored) {
}
if (cs == null) {
THIS_JAR = null;
manifest = new Manifest();
} else {
Path path;
try {
path = Paths.get(cs.getLocation().toURI()).toAbsolutePath();
path = Path.of(cs.getLocation().toURI()).toAbsolutePath();
} catch (FileSystemNotFoundException | IllegalArgumentException | URISyntaxException e) {
path = null;
}
if (path == null || !Files.isRegularFile(path)) {
THIS_JAR = null;
manifest = new Manifest();
} else {
THIS_JAR = path;
Manifest mn;
try (JarFile file = new JarFile(path.toFile())) {
mn = file.getManifest();
} catch (IOException e) {
mn = new Manifest();
THIS_JAR = path != null && Files.isRegularFile(path) ? path : null;
}
if (entryPointClass != null) {
InputStream input = entryPointClass.getResourceAsStream("/assets/hmcl.properties");
if (input != null) {
try (var reader = new InputStreamReader(input, StandardCharsets.UTF_8)) {
properties.load(reader);
} catch (IOException ignored) {
}
manifest = mn;
}
}
}
@@ -70,8 +74,7 @@ public final class JarUtils {
return THIS_JAR;
}
public static String getManifestAttribute(String name, String defaultValue) {
String value = manifest.getMainAttributes().getValue(name);
return value != null ? value : defaultValue;
public static String getAttribute(String name, String defaultValue) {
return properties.getProperty(name, defaultValue);
}
}