为非 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:
Glavo
2022-08-21 19:00:05 +08:00
committed by GitHub
parent c8652012c5
commit b80c787b60
25 changed files with 1570 additions and 104 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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();

View File

@@ -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;

View File

@@ -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");

View File

@@ -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));

View File

@@ -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;

View File

@@ -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;