From c5919f27197669cd297e3a9565809f03ae3c2960 Mon Sep 17 00:00:00 2001 From: huanghongxun Date: Mon, 19 Aug 2019 00:18:34 +0800 Subject: [PATCH] Fix OptiFine installation --- .../download/forge/ForgeNewInstallTask.java | 11 +--- .../optifine/OptiFineInstallTask.java | 59 ++++++++++++------- .../java/org/jackhuang/hmcl/util/Lang.java | 10 ++++ .../hmcl/util/platform/SystemUtils.java | 42 +++++++++++++ 4 files changed, 93 insertions(+), 29 deletions(-) create mode 100644 HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/SystemUtils.java diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeNewInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeNewInstallTask.java index ff4659f46..c88d6ae9f 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeNewInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeNewInstallTask.java @@ -35,11 +35,10 @@ import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.platform.CommandBuilder; import org.jackhuang.hmcl.util.platform.JavaVersion; import org.jackhuang.hmcl.util.platform.OperatingSystem; +import org.jackhuang.hmcl.util.platform.SystemUtils; -import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.InputStream; -import java.io.InputStreamReader; import java.nio.file.FileSystem; import java.nio.file.Files; import java.nio.file.Path; @@ -241,13 +240,7 @@ public class ForgeNewInstallTask extends Task { command.addAll(args); LOG.info("Executing external processor " + processor.getJar().toString() + ", command line: " + new CommandBuilder().addAll(command).toString()); - Process process = new ProcessBuilder(command).start(); - try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { - for (String line; (line = reader.readLine()) != null;) { - System.out.println(line); - } - } - int exitCode = process.waitFor(); + int exitCode = SystemUtils.callExternalProcess(command); if (exitCode != 0) throw new IllegalStateException("Game processor exited abnormally"); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.java index 763bc4e43..342eadd2c 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.java @@ -21,6 +21,7 @@ import org.jackhuang.hmcl.download.DefaultDependencyManager; import org.jackhuang.hmcl.download.LibraryAnalyzer; import org.jackhuang.hmcl.download.VersionMismatchException; import org.jackhuang.hmcl.game.Arguments; +import org.jackhuang.hmcl.game.DefaultGameRepository; import org.jackhuang.hmcl.game.GameVersion; import org.jackhuang.hmcl.game.LibrariesDownloadInfo; import org.jackhuang.hmcl.game.Library; @@ -31,6 +32,8 @@ import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.util.io.CompressingUtils; import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.NetworkUtils; +import org.jackhuang.hmcl.util.platform.JavaVersion; +import org.jackhuang.hmcl.util.platform.SystemUtils; import org.jenkinsci.constant_pool_scanner.ConstantPool; import org.jenkinsci.constant_pool_scanner.ConstantPoolScanner; import org.jenkinsci.constant_pool_scanner.ConstantType; @@ -42,7 +45,6 @@ import java.nio.file.FileSystem; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.LinkedList; import java.util.List; @@ -57,15 +59,17 @@ import static org.jackhuang.hmcl.util.Lang.getOrDefault; */ public final class OptiFineInstallTask extends Task { + private final DefaultGameRepository gameRepository; private final DefaultDependencyManager dependencyManager; private final Version version; private final OptiFineRemoteVersion remote; private final Path installer; private final List> dependents = new LinkedList<>(); private final List> dependencies = new LinkedList<>(); - private final File dest; + private Path dest; private final Library optiFineLibrary; + private final Library optiFineInstallerLibrary; public OptiFineInstallTask(DefaultDependencyManager dependencyManager, Version version, OptiFineRemoteVersion remoteVersion) { this(dependencyManager, version, remoteVersion, null); @@ -73,20 +77,21 @@ public final class OptiFineInstallTask extends Task { public OptiFineInstallTask(DefaultDependencyManager dependencyManager, Version version, OptiFineRemoteVersion remoteVersion, Path installer) { this.dependencyManager = dependencyManager; + this.gameRepository = dependencyManager.getGameRepository(); this.version = version; this.remote = remoteVersion; this.installer = installer; String mavenVersion = remote.getGameVersion() + "_" + remote.getSelfVersion(); - optiFineLibrary = new Library( - "optifine", "OptiFine", mavenVersion, null, null, + optiFineLibrary = new Library("optifine", "OptiFine", mavenVersion); + + optiFineInstallerLibrary = new Library( + "optifine", "OptiFine", mavenVersion, "installer", null, new LibrariesDownloadInfo(new LibraryDownloadInfo( - "optifine/OptiFine/" + mavenVersion + "/OptiFine-" + mavenVersion + ".jar", + "optifine/OptiFine/" + mavenVersion + "/OptiFine-" + mavenVersion + "-installer.jar", remote.getUrl())) ); - - dest = dependencyManager.getGameRepository().getLibraryFile(version, optiFineLibrary); } @Override @@ -96,18 +101,14 @@ public final class OptiFineInstallTask extends Task { @Override public void preExecute() throws Exception { - if (!Arrays.asList("net.minecraft.client.main.Main", - "net.minecraft.launchwrapper.Launch") - .contains(version.resolve(dependencyManager.getGameRepository()).getMainClass())) - throw new UnsupportedOptiFineInstallationException(); - + dest = Files.createTempFile("optifine-installer", ".jar"); if (installer == null) { - dependents.add(new FileDownloadTask(NetworkUtils.toURL(remote.getUrl()), dest) + dependents.add(new FileDownloadTask(NetworkUtils.toURL(remote.getUrl()), dest.toFile()) .setCacheRepository(dependencyManager.getCacheRepository()) .setCaching(true)); } else { - FileUtils.copyFile(installer, dest.toPath()); + FileUtils.copyFile(installer, dest); } } @@ -127,13 +128,31 @@ public final class OptiFineInstallTask extends Task { } @Override - public void execute() throws IOException { + public void execute() throws Exception { List libraries = new LinkedList<>(); libraries.add(optiFineLibrary); + FileUtils.copyFile(dest, gameRepository.getLibraryFile(version, optiFineInstallerLibrary).toPath()); + // Install launch wrapper modified by OptiFine boolean hasLaunchWrapper = false; - try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(dest.toPath())) { + try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(dest)) { + if (Files.exists(fs.getPath("optifine/Patcher.class"))) { + int exitCode = SystemUtils.callExternalProcess( + JavaVersion.fromCurrentEnvironment().getBinary().toString(), + "-cp", + dest.toString(), + "optifine.Patcher", + gameRepository.getVersionJar(version).getAbsolutePath(), + dest.toString(), + gameRepository.getLibraryFile(version, optiFineLibrary).toString() + ); + if (exitCode != 0) + throw new IllegalStateException("OptiFine patcher failed"); + } else { + FileUtils.copyFile(dest, gameRepository.getLibraryFile(version, optiFineLibrary).toPath()); + } + Path launchWrapperVersionText = fs.getPath("launchwrapper-of.txt"); if (Files.exists(launchWrapperVersionText)) { String launchWrapperVersion = FileUtils.readText(launchWrapperVersionText).trim(); @@ -142,24 +161,24 @@ public final class OptiFineInstallTask extends Task { Library launchWrapper = new Library("optifine", "launchwrapper-of", launchWrapperVersion); if (Files.exists(launchWrapperJar)) { - File launchWrapperFile = dependencyManager.getGameRepository().getLibraryFile(version, launchWrapper); + File launchWrapperFile = gameRepository.getLibraryFile(version, launchWrapper); FileUtils.makeDirectory(launchWrapperFile.getAbsoluteFile().getParentFile()); FileUtils.copyFile(launchWrapperJar, launchWrapperFile.toPath()); hasLaunchWrapper = true; - libraries.add(0, launchWrapper); + libraries.add(launchWrapper); } } } if (!hasLaunchWrapper) { - libraries.add(0, new Library("net.minecraft", "launchwrapper", "1.12")); + libraries.add(new Library("net.minecraft", "launchwrapper", "1.12")); } setResult(new Version( LibraryAnalyzer.LibraryType.OPTIFINE.getPatchId(), remote.getSelfVersion(), - 90000, + 10000, new Arguments().addGameArguments("--tweakClass", "optifine.OptiFineTweaker"), "net.minecraft.launchwrapper.Launch", libraries diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Lang.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Lang.java index 9b449f1b9..29b5bfe34 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Lang.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Lang.java @@ -17,6 +17,7 @@ */ package org.jackhuang.hmcl.util; +import org.jackhuang.hmcl.util.function.ExceptionalRunnable; import org.jackhuang.hmcl.util.function.ExceptionalSupplier; import java.util.*; @@ -57,6 +58,15 @@ public final class Lang { return Collections.unmodifiableList(Arrays.asList(elements)); } + public static boolean test(ExceptionalRunnable r) { + try { + r.run(); + return true; + } catch (Exception e) { + return false; + } + } + public static boolean test(ExceptionalSupplier r) { try { return r.get(); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/SystemUtils.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/SystemUtils.java new file mode 100644 index 000000000..0f2cb84aa --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/SystemUtils.java @@ -0,0 +1,42 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2019 huangyuhui and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.jackhuang.hmcl.util.platform; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Arrays; +import java.util.List; + +public final class SystemUtils { + private SystemUtils() {} + + public static int callExternalProcess(String... command) throws IOException, InterruptedException { + return callExternalProcess(Arrays.asList(command)); + } + + public static int callExternalProcess(List command) throws IOException, InterruptedException { + Process process = new ProcessBuilder(command).start(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { + for (String line; (line = reader.readLine()) != null;) { + System.out.println(line); + } + } + return process.waitFor(); + } +}