diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/InstallerController.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/InstallerController.java index 666266287..de0082e72 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/InstallerController.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/InstallerController.java @@ -21,6 +21,7 @@ import javafx.fxml.FXML; import javafx.scene.control.ScrollPane; import javafx.scene.layout.VBox; +import org.jackhuang.hmcl.download.LibraryAnalyzer; import org.jackhuang.hmcl.download.MaintainTask; import org.jackhuang.hmcl.download.game.VersionJsonSaveTask; import org.jackhuang.hmcl.game.GameVersion; @@ -35,6 +36,7 @@ import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import java.util.LinkedList; import java.util.Optional; import java.util.function.Consumer; +import java.util.function.Function; public class InstallerController { private Profile profile; @@ -43,9 +45,6 @@ public class InstallerController { @FXML private ScrollPane scrollPane; @FXML private VBox contentPane; - private String forge; - private String liteLoader; - private String optiFine; @FXML private void initialize() { @@ -58,32 +57,22 @@ public class InstallerController { this.version = profile.getRepository().getResolvedVersion(versionId); contentPane.getChildren().clear(); - forge = liteLoader = optiFine = null; - for (Library library : version.getLibraries()) { - Consumer removeAction = x -> { - LinkedList newList = new LinkedList<>(version.getLibraries()); - newList.remove(library); - new MaintainTask(version.setLibraries(newList)) - .then(variables -> new VersionJsonSaveTask(profile.getRepository(), variables.get(MaintainTask.ID))) - .with(profile.getRepository().refreshVersionsAsync()) - .with(Task.of(Schedulers.javafx(), () -> loadVersion(this.profile, this.versionId))) - .start(); - }; + LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(version); - if (library.getGroupId().equalsIgnoreCase("net.minecraftforge") && library.getArtifactId().equalsIgnoreCase("forge")) { - contentPane.getChildren().add(new InstallerItem("Forge", library.getVersion(), removeAction)); - forge = library.getVersion(); - } - if (library.getGroupId().equalsIgnoreCase("com.mumfrey") && library.getArtifactId().equalsIgnoreCase("liteloader")) { - contentPane.getChildren().add(new InstallerItem("LiteLoader", library.getVersion(), removeAction)); - liteLoader = library.getVersion(); - } - if (library.getGroupId().equalsIgnoreCase("net.optifine") && library.getArtifactId().equalsIgnoreCase("optifine")) { - contentPane.getChildren().add(new InstallerItem("OptiFine", library.getVersion(), removeAction)); - optiFine = library.getVersion(); - } - } + Function> removeAction = library -> x -> { + LinkedList newList = new LinkedList<>(version.getLibraries()); + newList.remove(library); + new MaintainTask(version.setLibraries(newList)) + .then(variables -> new VersionJsonSaveTask(profile.getRepository(), variables.get(MaintainTask.ID))) + .with(profile.getRepository().refreshVersionsAsync()) + .with(Task.of(Schedulers.javafx(), () -> loadVersion(this.profile, this.versionId))) + .start(); + }; + + analyzer.getForge().ifPresent(library -> contentPane.getChildren().add(new InstallerItem("Forge", library.getVersion(), removeAction.apply(library)))); + analyzer.getLiteLoader().ifPresent(library -> contentPane.getChildren().add(new InstallerItem("LiteLoader", library.getVersion(), removeAction.apply(library)))); + analyzer.getOptiFine().ifPresent(library -> contentPane.getChildren().add(new InstallerItem("OptiFine", library.getVersion(), removeAction.apply(library)))); } @FXML @@ -93,6 +82,6 @@ public class InstallerController { if (!gameVersion.isPresent()) Controllers.dialog(i18n("version.cannot_read")); else - Controllers.getDecorator().startWizard(new InstallerWizardProvider(profile, gameVersion.get(), version, forge, liteLoader, optiFine)); + Controllers.getDecorator().startWizard(new InstallerWizardProvider(profile, gameVersion.get(), version)); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/MainPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/MainPage.java index 1acbd7a67..508e7cbe1 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/MainPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/MainPage.java @@ -30,6 +30,7 @@ import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; import javafx.stage.FileChooser; +import org.jackhuang.hmcl.download.LibraryAnalyzer; import org.jackhuang.hmcl.event.EventBus; import org.jackhuang.hmcl.event.ProfileChangedEvent; import org.jackhuang.hmcl.event.RefreshedVersionsEvent; @@ -119,17 +120,10 @@ public final class MainPage extends StackPane implements DecoratorPage { item.setGameVersion(game); StringBuilder libraries = new StringBuilder(); - for (Library library : version.getLibraries()) { - if (library.getGroupId().equalsIgnoreCase("net.minecraftforge") && library.getArtifactId().equalsIgnoreCase("forge")) { - libraries.append(i18n("install.installer.forge")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)forge", ""))).append("\n"); - } - if (library.getGroupId().equalsIgnoreCase("com.mumfrey") && library.getArtifactId().equalsIgnoreCase("liteloader")) { - libraries.append(i18n("install.installer.liteloader")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)liteloader", ""))).append("\n"); - } - if (library.getGroupId().equalsIgnoreCase("net.optifine") && library.getArtifactId().equalsIgnoreCase("optifine")) { - libraries.append(i18n("install.installer.optifine")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)optifine", ""))).append("\n"); - } - } + LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(version); + analyzer.getForge().ifPresent(library -> libraries.append(i18n("install.installer.forge")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)forge", ""))).append("\n")); + analyzer.getLiteLoader().ifPresent(library -> libraries.append(i18n("install.installer.liteloader")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)liteloader", ""))).append("\n")); + analyzer.getOptiFine().ifPresent(library -> libraries.append(i18n("install.installer.optifine")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)optifine", ""))).append("\n")); item.setLibraries(libraries.toString()); }); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallerWizardProvider.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallerWizardProvider.java index 5c4d16538..b5d08c8c5 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallerWizardProvider.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallerWizardProvider.java @@ -21,7 +21,9 @@ import javafx.scene.Node; import org.jackhuang.hmcl.download.BMCLAPIDownloadProvider; import org.jackhuang.hmcl.download.DownloadProvider; +import org.jackhuang.hmcl.download.LibraryAnalyzer; import org.jackhuang.hmcl.download.RemoteVersion; +import org.jackhuang.hmcl.game.Library; import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.task.Task; @@ -40,16 +42,14 @@ public final class InstallerWizardProvider implements WizardProvider { private final String optiFine; public InstallerWizardProvider(Profile profile, String gameVersion, Version version) { - this(profile, gameVersion, version, null, null, null); - } - - public InstallerWizardProvider(Profile profile, String gameVersion, Version version, String forge, String liteLoader, String optiFine) { this.profile = profile; this.gameVersion = gameVersion; this.version = version; - this.forge = forge; - this.liteLoader = liteLoader; - this.optiFine = optiFine; + + LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(version); + forge = analyzer.getForge().map(Library::getVersion).orElse(null); + liteLoader = analyzer.getLiteLoader().map(Library::getVersion).orElse(null); + optiFine = analyzer.getOptiFine().map(Library::getVersion).orElse(null); } public Profile getProfile() { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/LibraryAnalyzer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/LibraryAnalyzer.java new file mode 100644 index 000000000..265a114e0 --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/LibraryAnalyzer.java @@ -0,0 +1,78 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * 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 {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.download; + +import org.jackhuang.hmcl.game.Library; +import org.jackhuang.hmcl.game.Version; + +import java.util.Optional; + +public final class LibraryAnalyzer { + private final Library forge; + private final Library liteLoader; + private final Library optiFine; + + public LibraryAnalyzer(Library forge, Library liteLoader, Library optiFine) { + this.forge = forge; + this.liteLoader = liteLoader; + this.optiFine = optiFine; + } + + public Optional getForge() { + return Optional.ofNullable(forge); + } + + public boolean hasForge() { + return forge != null; + } + + public Optional getLiteLoader() { + return Optional.ofNullable(liteLoader); + } + + public boolean hasLiteLoader() { + return liteLoader != null; + } + + public Optional getOptiFine() { + return Optional.ofNullable(optiFine); + } + + public boolean hasOptiFine() { + return optiFine != null; + } + + public static LibraryAnalyzer analyze(Version version) { + Library forge = null, liteLoader = null, optiFine = null; + + for (Library library : version.getLibraries()) { + String groupId = library.getGroupId(); + String artifactId = library.getArtifactId(); + if (groupId.equalsIgnoreCase("net.minecraftforge") && artifactId.equalsIgnoreCase("forge")) + forge = library; + + if (groupId.equalsIgnoreCase("com.mumfrey") && artifactId.equalsIgnoreCase("liteloader")) + liteLoader = library; + + if ((groupId.equalsIgnoreCase("optifine") || groupId.equalsIgnoreCase("net.optifine")) && artifactId.equalsIgnoreCase("optifine")) + optiFine = library; + } + + return new LibraryAnalyzer(forge, liteLoader, optiFine); + } +} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/MaintainTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/MaintainTask.java index 0663ca5f8..ea4df2f5e 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/MaintainTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/MaintainTask.java @@ -17,14 +17,12 @@ */ package org.jackhuang.hmcl.download; -import org.jackhuang.hmcl.game.Library; -import org.jackhuang.hmcl.game.Version; +import org.jackhuang.hmcl.game.*; import org.jackhuang.hmcl.task.TaskResult; import org.jackhuang.hmcl.util.CommandBuilder; import org.jackhuang.hmcl.util.StringUtils; -import java.util.ArrayList; -import java.util.List; +import java.util.*; public class MaintainTask extends TaskResult { @@ -46,57 +44,41 @@ public class MaintainTask extends TaskResult { } public static Version maintain(Version version) { - Library forge = null, liteLoader = null, optiFine = null; - List args = new ArrayList<>(StringUtils.tokenize(version.getMinecraftArguments().orElse(""))); + LibraryAnalyzer libraryAnalyzer = LibraryAnalyzer.analyze(version); + List mcArgs = version.getMinecraftArguments().map(StringUtils::tokenize).map(ArrayList::new).orElse(null); + List game = version.getArguments().map(Arguments::getGame).map(ArrayList::new).orElseGet(ArrayList::new); + boolean useMcArgs = mcArgs != null; - for (Library library : version.getLibraries()) { - if (library.getGroupId().equalsIgnoreCase("net.minecraftforge") && library.getArtifactId().equalsIgnoreCase("forge")) - forge = library; - - if (library.getGroupId().equalsIgnoreCase("com.mumfrey") && library.getArtifactId().equalsIgnoreCase("liteloader")) - liteLoader = library; - - if (library.getGroupId().equalsIgnoreCase("net.optifine") && library.getArtifactId().equalsIgnoreCase("optifine")) - optiFine = library; - - } - - if (forge == null) { - removeTweakClass(args, "forge"); + if (!libraryAnalyzer.hasForge()) { + removeTweakClass(useMcArgs, mcArgs, game, "forge"); } // Installing Forge will override the Minecraft arguments in json, so LiteLoader and OptiFine Tweaker are being re-added. - if (liteLoader == null) { - removeTweakClass(args, "liteloader"); + removeTweakClass(useMcArgs, mcArgs, game, "liteloader"); + if (libraryAnalyzer.hasLiteLoader()) { + addArgument(useMcArgs, mcArgs, game, "--tweakClass", "com.mumfrey.liteloader.launch.LiteLoaderTweaker"); + } + + removeTweakClass(useMcArgs, mcArgs, game, "optifine"); + if (libraryAnalyzer.hasOptiFine()) { + if (!libraryAnalyzer.hasLiteLoader() && !libraryAnalyzer.hasForge()) { + addArgument(useMcArgs, mcArgs, game, "--tweakClass", "optifine.OptiFineTweaker"); + } else { + // If forge or LiteLoader installed, OptiFine Forge Tweaker is needed. + addArgument(useMcArgs, mcArgs, game, "--tweakClass", "optifine.OptiFineForgeTweaker"); + } + } + + Version result; + if (useMcArgs) { + // Since $ will be escaped in linux, and our maintain of minecraftArgument will not cause escaping, + // so we regenerate the minecraftArgument without escaping. + result = version.setMinecraftArguments(new CommandBuilder().addAllWithoutParsing(mcArgs).toString()); } else { - if (!StringUtils.containsOne(args, "LiteLoaderTweaker")) { - args.add("--tweakClass"); - args.add("com.mumfrey.liteloader.launch.LiteLoaderTweaker"); - } + result = version.setArguments(version.getArguments().map(args -> args.withGame(game)).orElse(new Arguments(game, Collections.emptyList()))); } - - if (optiFine == null) { - removeTweakClass(args, "optifine"); - } - - if (liteLoader == null && forge == null && optiFine != null) { - if (!StringUtils.containsOne(args, "optifine.OptiFineTweaker")) { - args.add("--tweakClass"); - args.add("optifine.OptiFineTweaker"); - } - } - - if ((liteLoader != null || forge != null) && optiFine != null) { - // If forge or LiteLoader installed, OptiFine Forge Tweaker is needed. - removeTweakClass(args, "optifine"); - args.add("--tweakClass"); - args.add("optifine.OptiFineForgeTweaker"); - } - - // Since $ will be escaped in linux, and our maintain of minecraftArgument will not cause escaping, - // so we regenerate the minecraftArgument without escaping. - return version.setMinecraftArguments(new CommandBuilder().addAllWithoutParsing(args).toString()); + return result; } @Override @@ -104,17 +86,43 @@ public class MaintainTask extends TaskResult { return id; } - private static void removeTweakClass(List args, String target) { - for (int i = 0; i < args.size(); ++i) { - if (args.get(i).toLowerCase().contains(target)) { - if (i > 0 && args.get(i - 1).equals("--tweakClass")) { - args.remove(i - 1); - args.remove(i - 1); - i -= 2; + private static void removeTweakClass(boolean useMcArgs, List mcArgs, List game, String target) { + if (useMcArgs) { + for (int i = 0; i + 1 < mcArgs.size(); ++i) { + String arg0Str = mcArgs.get(i); + String arg1Str = mcArgs.get(i + 1); + if (arg0Str.equals("--tweakClass") && arg1Str.toLowerCase().contains(target)) { + mcArgs.remove(i); + mcArgs.remove(i); + --i; + } + } + } else { + for (int i = 0; i + 1 < game.size(); ++i) { + Argument arg0 = game.get(i); + Argument arg1 = game.get(i + 1); + if (arg0 instanceof StringArgument && arg1 instanceof StringArgument) { + // We need to preserve the tokens + String arg0Str = arg0.toString(); + String arg1Str = arg1.toString(); + if (arg0Str.equals("--tweakClass") && arg1Str.toLowerCase().contains(target)) { + game.remove(i); + game.remove(i); + --i; + } } } } } + private static void addArgument(boolean useMcArgs, List mcArgs, List game, String... args) { + if (useMcArgs) { + mcArgs.addAll(Arrays.asList(args)); + } else { + for (String arg : args) + game.add(new StringArgument(arg)); + } + } + public static final String ID = "version"; } 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 04d33e845..e3c4da317 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 @@ -69,12 +69,12 @@ public final class OptiFineInstallTask extends TaskResult { @Override public void execute() { - String remoteVersion = remote.getGameVersion() + "-" + remote.getSelfVersion(); + String remoteVersion = remote.getGameVersion() + "_" + remote.getSelfVersion(); Library library = new Library( - "net.optifine", "optifine", remoteVersion, null, null, + "optifine", "OptiFine", remoteVersion, null, null, new LibrariesDownloadInfo(new LibraryDownloadInfo( - "net/optifine/optifine/" + remoteVersion + "/optifine-" + remoteVersion + ".jar", + "optifine/OptiFine/" + remoteVersion + "/OptiFine-" + remoteVersion + ".jar", remote.getUrl())) ); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Arguments.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Arguments.java index 68b4addc5..e59ae9fa7 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Arguments.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Arguments.java @@ -50,10 +50,18 @@ public final class Arguments { return game == null ? Collections.emptyList() : Collections.unmodifiableList(game); } + public Arguments withGame(List game) { + return new Arguments(game, jvm); + } + public List getJvm() { return jvm == null ? Collections.emptyList() : Collections.unmodifiableList(jvm); } + public Arguments withJvm(List jvm) { + return new Arguments(game, jvm); + } + public Arguments addGameArguments(String... gameArguments) { return addGameArguments(Arrays.asList(gameArguments)); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/StringArgument.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/StringArgument.java index acfd86e10..f57d24524 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/StringArgument.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/StringArgument.java @@ -54,4 +54,8 @@ public final class StringArgument implements Argument { return Collections.singletonList(res); } + @Override + public String toString() { + return argument; + } }