mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-09-23 19:23:12 -04:00
Feature: MacOS Support.
This commit is contained in:
parent
a4d6580793
commit
4618a51934
@ -138,16 +138,21 @@ public final class TerracottaManager {
|
||||
ReadOnlyDoubleWrapper progress = new ReadOnlyDoubleWrapper(0);
|
||||
TerracottaState.Preparing preparing = new TerracottaState.Preparing(progress.getReadOnlyProperty());
|
||||
|
||||
Objects.requireNonNull(TerracottaMetadata.PROVIDER).install(progress).thenRunAsync(() -> {
|
||||
TerracottaState.Launching launching = new TerracottaState.Launching();
|
||||
if (compareAndSet(preparing, launching)) {
|
||||
launch(launching);
|
||||
}
|
||||
}).whenComplete(exception -> {
|
||||
compareAndSet(preparing, TerracottaState.Fatal.INSTANCE);
|
||||
}).start();
|
||||
try {
|
||||
Objects.requireNonNull(TerracottaMetadata.PROVIDER).install(progress).thenRunAsync(() -> {
|
||||
TerracottaState.Launching launching = new TerracottaState.Launching();
|
||||
if (compareAndSet(preparing, launching)) {
|
||||
launch(launching);
|
||||
}
|
||||
}).whenComplete(exception -> {
|
||||
compareAndSet(preparing, TerracottaState.Fatal.INSTANCE);
|
||||
}).start();
|
||||
|
||||
return setState(preparing);
|
||||
return setState(preparing);
|
||||
} catch (Exception e) {
|
||||
setState(TerracottaState.Fatal.INSTANCE);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void launch(TerracottaState.Launching state) {
|
||||
|
@ -1,9 +1,11 @@
|
||||
package org.jackhuang.hmcl.ui.terracotta.core;
|
||||
|
||||
import org.jackhuang.hmcl.ui.terracotta.core.provider.ExecutableProvider;
|
||||
import org.jackhuang.hmcl.ui.terracotta.core.provider.GeneralProvider;
|
||||
import org.jackhuang.hmcl.ui.terracotta.core.provider.ITerracottaProvider;
|
||||
import org.jackhuang.hmcl.ui.terracotta.core.provider.MacOSProvider;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
public final class TerracottaMetadata {
|
||||
private TerracottaMetadata() {
|
||||
@ -11,15 +13,28 @@ public final class TerracottaMetadata {
|
||||
|
||||
public static final String VERSION = "0.3.8-rc.1";
|
||||
|
||||
public static final URI WINDOWS_X86_64 = URI.create(String.format("https://github.com/burningtnt/Terracotta/releases/download/V%1$s/terracotta-%1$s-windows-x86_64.exe", VERSION));
|
||||
public static final URI WINDOWS_ARM64 = URI.create(String.format("https://github.com/burningtnt/Terracotta/releases/download/V%1$s/terracotta-%1$s-windows-arm64.exe", VERSION));
|
||||
public static final URI LINUX_X86_64 = URI.create(String.format("https://github.com/burningtnt/Terracotta/releases/download/V%1$s/terracotta-%1$s-linux-x86_64", VERSION));
|
||||
public static final URI LINUX_ARM64 = URI.create(String.format("https://github.com/burningtnt/Terracotta/releases/download/V%1$s/terracotta-%1$s-linux-arm64", VERSION));
|
||||
public static final List<URI> WINDOWS_X86_64 = create(String.format("https://github.com/burningtnt/Terracotta/releases/download/V%1$s/terracotta-%1$s-windows-x86_64.exe", VERSION));
|
||||
public static final List<URI> WINDOWS_ARM64 = create(String.format("https://github.com/burningtnt/Terracotta/releases/download/V%1$s/terracotta-%1$s-windows-arm64.exe", VERSION));
|
||||
|
||||
public static final List<URI> LINUX_X86_64 = create(String.format("https://github.com/burningtnt/Terracotta/releases/download/V%1$s/terracotta-%1$s-linux-x86_64", VERSION));
|
||||
public static final List<URI> LINUX_ARM64 = create(String.format("https://github.com/burningtnt/Terracotta/releases/download/V%1$s/terracotta-%1$s-linux-arm64", VERSION));
|
||||
|
||||
public static final List<URI> MACOS_INSTALLER_X86_64 = create(String.format("https://github.com/burningtnt/Terracotta/releases/download/V%1$s/terracotta-%1$s-macos-x86_64.pkg", VERSION));
|
||||
public static final List<URI> MACOS_INSTALLER_ARM64 = create(String.format("https://github.com/burningtnt/Terracotta/releases/download/V%1$s/terracotta-%1$s-macos-arm64.pkg", VERSION));
|
||||
public static final List<URI> MACOS_BIN_X86_64 = create(String.format("https://github.com/burningtnt/Terracotta/releases/download/V%1$s/terracotta-%1$s-macos-x86_64", VERSION));
|
||||
public static final List<URI> MACOS_BIN_ARM64 = create(String.format("https://github.com/burningtnt/Terracotta/releases/download/V%1$s/terracotta-%1$s-macos-arm64", VERSION));
|
||||
|
||||
private static List<URI> create(String s) {
|
||||
return List.of(URI.create("https://ghfast.top/" + s), URI.create("https://cdn.crashmc.com/" + s), URI.create(s));
|
||||
}
|
||||
|
||||
public static final ITerracottaProvider PROVIDER = locateProvider();
|
||||
|
||||
private static ITerracottaProvider locateProvider() {
|
||||
if (ExecutableProvider.TARGET != null) {
|
||||
return new ExecutableProvider();
|
||||
if (GeneralProvider.TARGET != null) {
|
||||
return new GeneralProvider();
|
||||
} else if (MacOSProvider.INSTALLER != null) {
|
||||
return new MacOSProvider();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -11,22 +11,23 @@ import org.jackhuang.hmcl.util.platform.Platform;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.attribute.PosixFilePermission;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public final class ExecutableProvider implements ITerracottaProvider {
|
||||
public static final URI TARGET = Map.of(
|
||||
public final class GeneralProvider implements ITerracottaProvider {
|
||||
public static final List<URI> TARGET = Map.of(
|
||||
Platform.WINDOWS_X86_64, TerracottaMetadata.WINDOWS_X86_64,
|
||||
Platform.WINDOWS_ARM64, TerracottaMetadata.WINDOWS_ARM64,
|
||||
Platform.LINUX_X86_64, TerracottaMetadata.LINUX_X86_64,
|
||||
Platform.LINUX_ARM64, TerracottaMetadata.LINUX_ARM64
|
||||
).get(Platform.SYSTEM_PLATFORM);
|
||||
|
||||
private static final Path PATH = Metadata.DEPENDENCIES_DIRECTORY.resolve(String.format(
|
||||
"terracota/%s/%s", TerracottaMetadata.VERSION, Path.of(TARGET.getPath()).getFileName()
|
||||
)).toAbsolutePath();
|
||||
private static final Path PATH = TARGET != null ? Metadata.DEPENDENCIES_DIRECTORY.resolve(String.format(
|
||||
"terracota/%s/%s", TerracottaMetadata.VERSION, Path.of(TARGET.get(0).getPath()).getFileName()
|
||||
)).toAbsolutePath() : null;
|
||||
|
||||
@Override
|
||||
public boolean exist() {
|
||||
@ -35,8 +36,12 @@ public final class ExecutableProvider implements ITerracottaProvider {
|
||||
|
||||
@Override
|
||||
public Task<?> install(DoubleProperty progress) {
|
||||
Task<?> task = new FileDownloadTask(TARGET, PATH);
|
||||
Path tmp = PATH.resolveSibling(PATH.getFileName() + ".tmp");
|
||||
|
||||
Task<?> task = new FileDownloadTask(TARGET, tmp);
|
||||
progress.bind(task.progressProperty());
|
||||
task = task.thenRunAsync(() -> Files.move(tmp, PATH, StandardCopyOption.REPLACE_EXISTING));
|
||||
|
||||
if (OperatingSystem.CURRENT_OS.isLinuxOrBSD()) {
|
||||
task = task.thenRunAsync(() -> Files.setPosixFilePermissions(PATH, Set.of(
|
||||
PosixFilePermission.OWNER_READ,
|
@ -3,13 +3,14 @@ package org.jackhuang.hmcl.ui.terracotta.core.provider;
|
||||
import javafx.beans.property.DoubleProperty;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
public interface ITerracottaProvider {
|
||||
boolean exist();
|
||||
|
||||
Task<?> install(DoubleProperty progress);
|
||||
Task<?> install(DoubleProperty progress) throws IOException;
|
||||
|
||||
List<String> launch(Path path);
|
||||
}
|
||||
|
@ -0,0 +1,93 @@
|
||||
package org.jackhuang.hmcl.ui.terracotta.core.provider;
|
||||
|
||||
import javafx.beans.property.DoubleProperty;
|
||||
import org.jackhuang.hmcl.Metadata;
|
||||
import org.jackhuang.hmcl.task.FileDownloadTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.ui.terracotta.core.TerracottaMetadata;
|
||||
import org.jackhuang.hmcl.util.platform.Architecture;
|
||||
import org.jackhuang.hmcl.util.platform.ManagedProcess;
|
||||
import org.jackhuang.hmcl.util.platform.SystemUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.attribute.PosixFilePermission;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
|
||||
public final class MacOSProvider implements ITerracottaProvider {
|
||||
public static final List<URI> INSTALLER, BINARY;
|
||||
|
||||
static {
|
||||
if (Architecture.SYSTEM_ARCH == Architecture.X86_64) {
|
||||
INSTALLER = TerracottaMetadata.MACOS_INSTALLER_X86_64;
|
||||
BINARY = TerracottaMetadata.MACOS_BIN_X86_64;
|
||||
} else if (Architecture.SYSTEM_ARCH == Architecture.ARM64) {
|
||||
INSTALLER = TerracottaMetadata.MACOS_INSTALLER_ARM64;
|
||||
BINARY = TerracottaMetadata.MACOS_BIN_ARM64;
|
||||
} else {
|
||||
INSTALLER = null;
|
||||
BINARY = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Path PATH = BINARY != null ? Metadata.DEPENDENCIES_DIRECTORY.resolve(String.format(
|
||||
"terracota/%s/%s", TerracottaMetadata.VERSION, Path.of(BINARY.get(0).getPath()).getFileName()
|
||||
)).toAbsolutePath() : null;
|
||||
|
||||
@Override
|
||||
public boolean exist() {
|
||||
return Files.exists(Path.of("/Applications/terracotta.app")) && Files.exists(PATH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task<?> install(DoubleProperty progress) throws IOException {
|
||||
Path installer = Files.createTempFile("hmcl-terracotta-installer-", ".pkg").toAbsolutePath();
|
||||
Task<?> installerTask = new FileDownloadTask(INSTALLER, installer);
|
||||
|
||||
Path binary = PATH.resolveSibling(PATH.getFileName() + ".tmp");
|
||||
Task<?> binaryTask = new FileDownloadTask(BINARY, binary);
|
||||
|
||||
progress.bind(installerTask.progressProperty().add(binaryTask.progressProperty()).multiply(0.3));
|
||||
|
||||
installerTask = installerTask.thenComposeAsync(() -> {
|
||||
ManagedProcess process = new ManagedProcess(new ProcessBuilder(
|
||||
"osascript",
|
||||
"-e",
|
||||
String.format(
|
||||
"do shell script \"%s\" with prompt \"%s\" with administrator privileges",
|
||||
String.format("installer -pkg %s -target /Applications", installer),
|
||||
i18n("terracotta.sudo_installing")
|
||||
)
|
||||
));
|
||||
process.pumpInputStream(SystemUtils::onLogLine);
|
||||
process.pumpErrorStream(SystemUtils::onLogLine);
|
||||
|
||||
return Task.fromCompletableFuture(process.getProcess().onExit());
|
||||
});
|
||||
binaryTask = binaryTask.thenRunAsync(() -> {
|
||||
Files.move(binary, PATH, StandardCopyOption.REPLACE_EXISTING);
|
||||
Files.setPosixFilePermissions(PATH, Set.of(
|
||||
PosixFilePermission.OWNER_READ,
|
||||
PosixFilePermission.OWNER_WRITE,
|
||||
PosixFilePermission.OWNER_EXECUTE,
|
||||
PosixFilePermission.GROUP_READ,
|
||||
PosixFilePermission.GROUP_EXECUTE,
|
||||
PosixFilePermission.OTHERS_READ,
|
||||
PosixFilePermission.OTHERS_EXECUTE
|
||||
));
|
||||
});
|
||||
|
||||
return Task.allOf(installerTask, binaryTask);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> launch(Path path) {
|
||||
return List.of(PATH.toString(), "--hmcl", path.toString());
|
||||
}
|
||||
}
|
@ -1195,6 +1195,7 @@ terracotta=多人联机
|
||||
terracotta.status=状态
|
||||
terracotta.back=退出
|
||||
terracotta.network_warning=多人联机基于 p2p,最终联机体验和您的网络情况有较大关系。
|
||||
terracotta.sudo_installing=HMCL 需要验证您的密码才能安装多人联机核心。
|
||||
terracotta.status.uninitialized=未下载多人联机核心
|
||||
terracotta.status.uninitialized.title=下载多人联机核心(约 8MB)
|
||||
terracotta.status.uninitialized.desc=您承诺,多人联机全过程中,您将严格遵守您所在国家或地区的全部法律法规
|
||||
@ -1227,7 +1228,7 @@ terracotta.status.exception.desc.ping_host_rst=房间连接断开:房间已关
|
||||
terracotta.status.exception.desc.guest_et_crash=加入房间失败:EasyTier 已崩溃,请向开发者反馈该问题
|
||||
terracotta.status.exception.desc.host_et_crash=创建房间失败:EasyTier 已崩溃,请向开发者反馈该问题
|
||||
terracotta.status.exception.desc.ping_server_rst=房间已关闭:您已退出游戏存档,房间已自动关闭
|
||||
terracotta.status.fatal=严重错误,您的设备可能无法正常使用多人联机功能
|
||||
terracotta.status.fatal=严重错误,您的设备无法正常使用多人联机功能
|
||||
|
||||
unofficial.hint=你正在使用非官方构建的 HMCL。我们无法保证其安全性,请注意甄别。
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user