为非 x86 平台提供开箱即用的启动支持 (#1610)
* Replace native libraries on non-x86 platforms * Add support for Linux ARM * Relax the constraint 'JavaVersionConstraint.VANILLA_X86' * Fix several hints * Add OpenGL software renderer option * Add support for OpenGL software renderer on windows * Add __GLX_VENDOR_LIBRARY_NAME on Linux * Catch GLFW error 65543 * Allow users to disable auto completion of native libraries * fix NPE when violated mandatory constraint * Add support for Minecraft 1.13 * Add support for Minecraft 1.6~1.12 * Add base support for linux-loongarch64 * Improve warnings on Loongson platform * Add linux launcher script * fix typo * Add support for loongarch64 (old world)
This commit is contained in:
@@ -106,7 +106,8 @@ public class BMCLAPIDownloadProvider implements DownloadProvider {
|
||||
.replace("http://dl.liteloader.com/versions", apiRoot + "/maven")
|
||||
.replace("https://meta.fabricmc.net", apiRoot + "/fabric-meta")
|
||||
.replace("https://maven.fabricmc.net", apiRoot + "/maven")
|
||||
.replace("https://authlib-injector.yushi.moe", apiRoot + "/mirrors/authlib-injector");
|
||||
.replace("https://authlib-injector.yushi.moe", apiRoot + "/mirrors/authlib-injector")
|
||||
.replace("https://repo1.maven.org/maven2", "https://maven.aliyun.com/repository/central");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -44,7 +44,7 @@ public final class CrashReportAnalyzer {
|
||||
|
||||
// Maybe software rendering? Suggest user for using a graphics card.
|
||||
OPENGL_NOT_SUPPORTED(Pattern.compile("The driver does not appear to support OpenGL")),
|
||||
GRAPHICS_DRIVER(Pattern.compile("(Pixel format not accelerated|Couldn't set pixel format|net\\.minecraftforge\\.fml.client\\.SplashProgress|org\\.lwjgl\\.LWJGLException|EXCEPTION_ACCESS_VIOLATION(.|\\n|\\r)+# C {2}\\[(ig|atio|nvoglv))")),
|
||||
GRAPHICS_DRIVER(Pattern.compile("(Pixel format not accelerated|GLX: Failed to create context: GLXBadFBConfig|Couldn't set pixel format|net\\.minecraftforge\\.fml.client\\.SplashProgress|org\\.lwjgl\\.LWJGLException|EXCEPTION_ACCESS_VIOLATION(.|\\n|\\r)+# C {2}\\[(ig|atio|nvoglv))")),
|
||||
// Out of memory
|
||||
OUT_OF_MEMORY(Pattern.compile("(java\\.lang\\.OutOfMemoryError|The system is out of physical RAM or swap space)")),
|
||||
// Memory exceeded
|
||||
|
||||
@@ -116,7 +116,7 @@ public enum JavaVersionConstraint {
|
||||
}
|
||||
},
|
||||
// Minecraft currently does not provide official support for architectures other than x86 and x86-64.
|
||||
VANILLA_X86(JavaVersionConstraint.RULE_MANDATORY, versionRange(JavaVersionConstraint.MIN, JavaVersionConstraint.MAX), versionRange(JavaVersionConstraint.MIN, JavaVersionConstraint.MAX)) {
|
||||
VANILLA_X86(JavaVersionConstraint.RULE_SUGGESTED, versionRange(JavaVersionConstraint.MIN, JavaVersionConstraint.MAX), versionRange(JavaVersionConstraint.MIN, JavaVersionConstraint.MAX)) {
|
||||
@Override
|
||||
protected boolean appliesToVersionImpl(VersionNumber gameVersionNumber, @Nullable Version version,
|
||||
@Nullable JavaVersion javaVersion) {
|
||||
@@ -237,12 +237,15 @@ public enum JavaVersionConstraint {
|
||||
public static JavaVersion findSuitableJavaVersion(VersionNumber gameVersion, Version version) throws InterruptedException {
|
||||
VersionRanges range = findSuitableJavaVersionRange(gameVersion, version);
|
||||
|
||||
boolean skipCheckArchitecture = Architecture.CURRENT_ARCH.isX86()
|
||||
|| (OperatingSystem.CURRENT_OS == OperatingSystem.OSX && gameVersion.compareTo(VersionNumber.asVersion("1.19")) >= 0)
|
||||
|| OperatingSystem.CURRENT_OS == OperatingSystem.LINUX;
|
||||
|
||||
JavaVersion mandatory = null;
|
||||
JavaVersion suggested = null;
|
||||
for (JavaVersion javaVersion : JavaVersion.getJavas()) {
|
||||
// select the latest x86 java that this version accepts.
|
||||
if (!javaVersion.getArchitecture().isX86()
|
||||
&& (OperatingSystem.CURRENT_OS != OperatingSystem.OSX || gameVersion.compareTo(VersionNumber.asVersion("1.19")) < 0))
|
||||
if (!skipCheckArchitecture && !javaVersion.getArchitecture().isX86())
|
||||
continue;
|
||||
|
||||
VersionNumber javaVersionNumber = javaVersion.getVersionNumber();
|
||||
|
||||
@@ -58,6 +58,7 @@ public class LaunchOptions implements Serializable {
|
||||
private NativesDirectoryType nativesDirType;
|
||||
private String nativesDir;
|
||||
private ProcessPriority processPriority = ProcessPriority.NORMAL;
|
||||
private boolean useSoftwareRenderer;
|
||||
private boolean useNativeGLFW;
|
||||
private boolean useNativeOpenAL;
|
||||
private boolean daemon;
|
||||
@@ -242,6 +243,10 @@ public class LaunchOptions implements Serializable {
|
||||
return processPriority;
|
||||
}
|
||||
|
||||
public boolean isUseSoftwareRenderer() {
|
||||
return useSoftwareRenderer;
|
||||
}
|
||||
|
||||
public boolean isUseNativeGLFW() {
|
||||
return useNativeGLFW;
|
||||
}
|
||||
@@ -421,6 +426,10 @@ public class LaunchOptions implements Serializable {
|
||||
return options.nativesDir;
|
||||
}
|
||||
|
||||
public boolean isUseSoftwareRenderer() {
|
||||
return options.useSoftwareRenderer;
|
||||
}
|
||||
|
||||
public boolean isUseNativeGLFW() {
|
||||
return options.useNativeGLFW;
|
||||
}
|
||||
@@ -561,6 +570,11 @@ public class LaunchOptions implements Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setUseSoftwareRenderer(boolean useSoftwareRenderer) {
|
||||
options.useSoftwareRenderer = useSoftwareRenderer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setUseNativeGLFW(boolean useNativeGLFW) {
|
||||
options.useNativeGLFW = useNativeGLFW;
|
||||
return this;
|
||||
|
||||
@@ -481,6 +481,11 @@ public class DefaultLauncher extends Launcher {
|
||||
env.put("INST_MC_DIR", repository.getRunDirectory(version.getId()).getAbsolutePath());
|
||||
env.put("INST_JAVA", options.getJava().getBinary().toString());
|
||||
|
||||
if (options.isUseSoftwareRenderer() && OperatingSystem.CURRENT_OS == OperatingSystem.LINUX) {
|
||||
env.put("LIBGL_ALWAYS_SOFTWARE", "1");
|
||||
env.put("__GLX_VENDOR_LIBRARY_NAME", "mesa");
|
||||
}
|
||||
|
||||
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(version);
|
||||
if (analyzer.has(LibraryAnalyzer.LibraryType.FORGE)) {
|
||||
env.put("INST_FORGE", "1");
|
||||
|
||||
@@ -26,9 +26,7 @@ import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.platform.ManagedProcess;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -60,21 +58,37 @@ final class ExitWaiter implements Runnable {
|
||||
for (Thread thread : joins)
|
||||
thread.join();
|
||||
|
||||
List<String> errorLines = process.getLines().stream()
|
||||
.filter(Log4jLevel::guessLogLineError).collect(Collectors.toList());
|
||||
ProcessListener.ExitType exitType;
|
||||
ProcessListener.ExitType exitType = null;
|
||||
for (String line : process.getLines()) {
|
||||
Log4jLevel level = Log4jLevel.guessLevel(line);
|
||||
if (Log4jLevel.isError(level)) {
|
||||
// LaunchWrapper will catch the exception logged and will exit normally.
|
||||
if (exitCode != 0 && StringUtils.containsOne(line,
|
||||
"Could not create the Java Virtual Machine.",
|
||||
"Error occurred during initialization of VM",
|
||||
"A fatal exception has occurred. Program will exit.")) {
|
||||
EventBus.EVENT_BUS.fireEvent(new JVMLaunchFailedEvent(this, process));
|
||||
exitType = ProcessListener.ExitType.JVM_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
// LaunchWrapper will catch the exception logged and will exit normally.
|
||||
if (exitCode != 0 && StringUtils.containsOne(errorLines,
|
||||
"Could not create the Java Virtual Machine.",
|
||||
"Error occurred during initialization of VM",
|
||||
"A fatal exception has occurred. Program will exit.")) {
|
||||
EventBus.EVENT_BUS.fireEvent(new JVMLaunchFailedEvent(this, process));
|
||||
exitType = ProcessListener.ExitType.JVM_ERROR;
|
||||
} else if (exitCode != 0 || StringUtils.containsOne(errorLines, "Unable to launch")) {
|
||||
EventBus.EVENT_BUS.fireEvent(new ProcessExitedAbnormallyEvent(this, process));
|
||||
exitType = ProcessListener.ExitType.APPLICATION_ERROR;
|
||||
} else
|
||||
if (exitCode != 0 || StringUtils.containsOne(line, "Unable to launch")) {
|
||||
EventBus.EVENT_BUS.fireEvent(new ProcessExitedAbnormallyEvent(this, process));
|
||||
exitType = ProcessListener.ExitType.APPLICATION_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (level == Log4jLevel.WARN) {
|
||||
if (StringUtils.containsOne(line, "Failed to create window")) {
|
||||
EventBus.EVENT_BUS.fireEvent(new ProcessExitedAbnormallyEvent(this, process));
|
||||
exitType = ProcessListener.ExitType.APPLICATION_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (exitType == null)
|
||||
exitType = ProcessListener.ExitType.NORMAL;
|
||||
|
||||
EventBus.EVENT_BUS.fireEvent(new ProcessStoppedEvent(this, process));
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.util.platform;
|
||||
|
||||
import org.jackhuang.hmcl.util.versioning.VersionNumber;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Locale;
|
||||
@@ -46,6 +48,7 @@ public enum Architecture {
|
||||
S390X(BIT_64, "S390x"),
|
||||
RISCV(BIT_64, "RISC-V"),
|
||||
LOONGARCH32(BIT_32, "LoongArch32"),
|
||||
LOONGARCH64_OW(BIT_64, "LoongArch64 (old world)"),
|
||||
LOONGARCH64(BIT_64, "LoongArch64"),
|
||||
UNKNOWN(Bits.UNKNOWN, "Unknown");
|
||||
|
||||
@@ -172,8 +175,11 @@ public enum Architecture {
|
||||
return S390X;
|
||||
case "loongarch32":
|
||||
return LOONGARCH32;
|
||||
case "loongarch64":
|
||||
case "loongarch64": {
|
||||
if (VersionNumber.VERSION_COMPARATOR.compare(System.getProperty("os.version"), "5.19") < 0)
|
||||
return LOONGARCH64_OW;
|
||||
return LOONGARCH64;
|
||||
}
|
||||
default:
|
||||
if (value.startsWith("armv7")) {
|
||||
return ARM32;
|
||||
|
||||
@@ -14,6 +14,21 @@ public final class Platform {
|
||||
public static final Platform CURRENT_PLATFORM = Platform.getPlatform(OperatingSystem.CURRENT_OS, Architecture.CURRENT_ARCH);
|
||||
public static final Platform SYSTEM_PLATFORM = Platform.getPlatform(OperatingSystem.CURRENT_OS, Architecture.SYSTEM_ARCH);
|
||||
|
||||
public static boolean isCompatibleWithX86Java() {
|
||||
if (Architecture.CURRENT_ARCH.isX86())
|
||||
return true;
|
||||
|
||||
// Rosetta 2 is available for Mac computers with Apple silicon
|
||||
if (CURRENT_PLATFORM == OSX_ARM64)
|
||||
return true;
|
||||
|
||||
// Windows on ARM introduced translation support for x86-64 after 10.0.21277.
|
||||
if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS && OperatingSystem.SYSTEM_BUILD_NUMBER >= 21277)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private final OperatingSystem os;
|
||||
private final Architecture arch;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user