add: allow installing OptiFine 1.14.4 and Forge in same game version
This commit is contained in:
@@ -198,4 +198,8 @@ public final class LibraryAnalyzer implements Iterable<LibraryAnalyzer.LibraryMa
|
||||
return libraryVersion;
|
||||
}
|
||||
}
|
||||
|
||||
public static final String VANILLA_MAIN = "net.minecraft.client.main.Main";
|
||||
public static final String LAUNCH_WRAPPER_MAIN = "net.minecraft.launchwrapper.Launch";
|
||||
public static final String MOD_LAUNCHER_MAIN = "cpw.mods.modlauncher.Launcher";
|
||||
}
|
||||
|
||||
@@ -24,18 +24,22 @@ import org.jackhuang.hmcl.game.Library;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.game.VersionLibraryBuilder;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.Logging;
|
||||
import org.jackhuang.hmcl.util.SimpleMultimap;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.versioning.VersionNumber;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.jackhuang.hmcl.download.LibraryAnalyzer.LibraryType.*;
|
||||
import static org.jackhuang.hmcl.download.LibraryAnalyzer.LibraryType.FORGE;
|
||||
import static org.jackhuang.hmcl.download.LibraryAnalyzer.LibraryType.LITELOADER;
|
||||
import static org.jackhuang.hmcl.download.LibraryAnalyzer.LibraryType.OPTIFINE;
|
||||
|
||||
public class MaintainTask extends Task<Version> {
|
||||
private final GameRepository repository;
|
||||
@@ -60,13 +64,15 @@ public class MaintainTask extends Task<Version> {
|
||||
|
||||
String mainClass = version.resolve(null).getMainClass();
|
||||
|
||||
if (mainClass != null && mainClass.contains("launchwrapper")) {
|
||||
return maintainOptiFineLibrary(repository, maintainGameWithLaunchWrapper(unique(version), true));
|
||||
if (mainClass != null && mainClass.equals(LibraryAnalyzer.LAUNCH_WRAPPER_MAIN)) {
|
||||
return maintainOptiFineLibrary(repository, maintainGameWithLaunchWrapper(unique(version), true), false);
|
||||
} else if (mainClass != null && mainClass.equals(LibraryAnalyzer.MOD_LAUNCHER_MAIN)) {
|
||||
// Forge 1.13 and OptiFine
|
||||
return maintainOptiFineLibrary(repository, maintainGameWithModLauncher(repository, unique(version)), true);
|
||||
} else {
|
||||
// Vanilla Minecraft does not need maintain
|
||||
// Forge 1.13 support not implemented, not compatible with OptiFine currently.
|
||||
// Fabric does not need maintain, nothing compatible with fabric now.
|
||||
return maintainOptiFineLibrary(repository, unique(version));
|
||||
return maintainOptiFineLibrary(repository, unique(version), false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,7 +122,34 @@ public class MaintainTask extends Task<Version> {
|
||||
return mainClass == null ? ret : ret.setMainClass(mainClass);
|
||||
}
|
||||
|
||||
private static Version maintainOptiFineLibrary(GameRepository repository, Version version) {
|
||||
private static Version maintainGameWithModLauncher(GameRepository repository, Version version) {
|
||||
LibraryAnalyzer libraryAnalyzer = LibraryAnalyzer.analyze(version);
|
||||
VersionLibraryBuilder builder = new VersionLibraryBuilder(version);
|
||||
|
||||
if (!libraryAnalyzer.has(FORGE)) return version;
|
||||
|
||||
if (libraryAnalyzer.has(OPTIFINE)) {
|
||||
Library hmclTransformerDiscoveryService = new Library(new Artifact("org.jackhuang.hmcl", "transformer-discovery-service", "1.0"));
|
||||
Optional<Library> optiFine = version.getLibraries().stream().filter(library -> library.is("optifine", "OptiFine")).findAny();
|
||||
boolean libraryExisting = version.getLibraries().stream().anyMatch(library -> library.is("org.jackhuang.hmcl", "transformer-discovery-service"));
|
||||
optiFine.ifPresent(library -> {
|
||||
builder.addJvmArgument("-Dhmcl.transformer.candidates=${libraries_directory}/" + library.getPath());
|
||||
if (!libraryExisting) builder.addLibrary(hmclTransformerDiscoveryService);
|
||||
Path libraryPath = repository.getLibraryFile(version, hmclTransformerDiscoveryService).toPath();
|
||||
try {
|
||||
Files.createDirectories(libraryPath.getParent());
|
||||
Files.copy(MaintainTask.class.getResourceAsStream("/assets/game/HMCLTransformerDiscoveryService-1.0.jar"),
|
||||
libraryPath, StandardCopyOption.REPLACE_EXISTING);
|
||||
} catch (IOException e) {
|
||||
Logging.LOG.log(Level.WARNING, "Unable to unpack HMCLTransformerDiscoveryService", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static Version maintainOptiFineLibrary(GameRepository repository, Version version, boolean remove) {
|
||||
LibraryAnalyzer libraryAnalyzer = LibraryAnalyzer.analyze(version);
|
||||
List<Library> libraries = new ArrayList<>(version.getLibraries());
|
||||
|
||||
@@ -135,7 +168,7 @@ public class MaintainTask extends Task<Version> {
|
||||
// Although we have altered priority of OptiFine higher than Forge,
|
||||
// there still exists a situation that Forge is installed without patch.
|
||||
// Here we manually alter the position of OptiFine library in classpath.
|
||||
libraries.add(newLibrary);
|
||||
if (!remove) libraries.add(newLibrary);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jackhuang.hmcl.download.forge;
|
||||
|
||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||
import org.jackhuang.hmcl.download.DependencyManager;
|
||||
import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
||||
import org.jackhuang.hmcl.download.VersionMismatchException;
|
||||
import org.jackhuang.hmcl.download.optifine.OptiFineInstallTask;
|
||||
import org.jackhuang.hmcl.game.GameVersion;
|
||||
@@ -104,7 +105,7 @@ public final class ForgeInstallTask extends Task<Version> {
|
||||
String originalMainClass = version.resolve(dependencyManager.getGameRepository()).getMainClass();
|
||||
if (VersionNumber.VERSION_COMPARATOR.compare("1.13", remote.getGameVersion()) <= 0) {
|
||||
// Forge 1.13 is not compatible with any other libraries.
|
||||
if (!"net.minecraft.client.main.Main".equals(originalMainClass) && !"cpw.mods.modlauncher.Launcher".equals(originalMainClass))
|
||||
if (!LibraryAnalyzer.VANILLA_MAIN.equals(originalMainClass) && !LibraryAnalyzer.MOD_LAUNCHER_MAIN.equals(originalMainClass) && !LibraryAnalyzer.LAUNCH_WRAPPER_MAIN.equals(originalMainClass))
|
||||
throw new OptiFineInstallTask.UnsupportedOptiFineInstallationException();
|
||||
} else {
|
||||
// Forge 1.12 and older versions is compatible with vanilla and launchwrapper.
|
||||
|
||||
@@ -69,7 +69,7 @@ public final class LiteLoaderInstallTask extends Task<Version> {
|
||||
remote.getSelfVersion(),
|
||||
60000,
|
||||
new Arguments().addGameArguments("--tweakClass", "com.mumfrey.liteloader.launch.LiteLoaderTweaker"),
|
||||
"net.minecraft.launchwrapper.Launch",
|
||||
LibraryAnalyzer.LAUNCH_WRAPPER_MAIN,
|
||||
Lang.merge(remote.getLibraries(), Collections.singleton(library)))
|
||||
.setLogging(Collections.emptyMap()) // Mods may log in malformed format, causing XML parser to crash. So we suppress using official log4j configuration
|
||||
);
|
||||
|
||||
@@ -121,7 +121,7 @@ public final class OptiFineInstallTask extends Task<Version> {
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
String originalMainClass = version.resolve(dependencyManager.getGameRepository()).getMainClass();
|
||||
if (!"net.minecraft.client.main.Main".equals(originalMainClass) && !"net.minecraft.launchwrapper.Launch".equals(originalMainClass))
|
||||
if (!LibraryAnalyzer.VANILLA_MAIN.equals(originalMainClass) && !LibraryAnalyzer.LAUNCH_WRAPPER_MAIN.equals(originalMainClass) && !LibraryAnalyzer.MOD_LAUNCHER_MAIN.equals(originalMainClass))
|
||||
throw new OptiFineInstallTask.UnsupportedOptiFineInstallationException();
|
||||
|
||||
List<Library> libraries = new LinkedList<>();
|
||||
@@ -183,9 +183,9 @@ public final class OptiFineInstallTask extends Task<Version> {
|
||||
setResult(new Version(
|
||||
LibraryAnalyzer.LibraryType.OPTIFINE.getPatchId(),
|
||||
remote.getSelfVersion(),
|
||||
90000,
|
||||
10000,
|
||||
new Arguments().addGameArguments("--tweakClass", "optifine.OptiFineTweaker"),
|
||||
"net.minecraft.launchwrapper.Launch",
|
||||
LibraryAnalyzer.LAUNCH_WRAPPER_MAIN,
|
||||
libraries
|
||||
));
|
||||
|
||||
|
||||
@@ -96,12 +96,17 @@ public class DefaultGameRepository implements GameRepository {
|
||||
return versions.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getLibrariesDirectory(Version version) {
|
||||
return new File(getBaseDirectory(), "libraries");
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getLibraryFile(Version version, Library lib) {
|
||||
if ("local".equals(lib.getHint()) && lib.getFileName() != null)
|
||||
return new File(getVersionRoot(version.getId()), "libraries/" + lib.getFileName());
|
||||
else
|
||||
return new File(getBaseDirectory(), "libraries/" + lib.getPath());
|
||||
return new File(getLibrariesDirectory(version), lib.getPath());
|
||||
}
|
||||
|
||||
public Path getArtifactFile(Version version, Artifact artifact) {
|
||||
|
||||
@@ -99,6 +99,8 @@ public interface GameRepository extends VersionProvider {
|
||||
*/
|
||||
File getRunDirectory(String id);
|
||||
|
||||
File getLibrariesDirectory(Version version);
|
||||
|
||||
/**
|
||||
* Get the library file in disk.
|
||||
* This method allows versions and libraries that are not loaded by this game repository.
|
||||
|
||||
@@ -20,8 +20,7 @@ package org.jackhuang.hmcl.game;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.platform.CommandBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -31,12 +30,17 @@ public final class VersionLibraryBuilder {
|
||||
private final Version version;
|
||||
private final List<String> mcArgs;
|
||||
private final List<Argument> game;
|
||||
private final List<Argument> jvm;
|
||||
private final List<Library> libraries;
|
||||
private final boolean useMcArgs;
|
||||
private boolean jvmChanged = false;
|
||||
|
||||
public VersionLibraryBuilder(Version version) {
|
||||
this.version = version;
|
||||
this.libraries = new ArrayList<>(version.getLibraries());
|
||||
this.mcArgs = version.getMinecraftArguments().map(StringUtils::tokenize).map(ArrayList::new).orElse(null);
|
||||
this.game = version.getArguments().map(Arguments::getGame).map(ArrayList::new).orElseGet(ArrayList::new);
|
||||
this.jvm = new ArrayList<>(version.getArguments().map(Arguments::getJvm).orElse(Arguments.DEFAULT_JVM_ARGUMENTS));
|
||||
this.useMcArgs = mcArgs != null;
|
||||
}
|
||||
|
||||
@@ -47,7 +51,10 @@ public final class VersionLibraryBuilder {
|
||||
// so we regenerate the minecraftArgument without escaping.
|
||||
ret = ret.setMinecraftArguments(new CommandBuilder().addAllWithoutParsing(mcArgs).toString());
|
||||
}
|
||||
return ret.setArguments(ret.getArguments().map(args -> args.withGame(game)).orElse(new Arguments(game, null)));
|
||||
return ret.setArguments(ret.getArguments()
|
||||
.map(args -> args.withGame(game))
|
||||
.map(args -> jvmChanged ? args.withJvm(jvm) : args).orElse(new Arguments(game, jvmChanged ? jvm : null)))
|
||||
.setLibraries(libraries);
|
||||
}
|
||||
|
||||
public void removeTweakClass(String target) {
|
||||
@@ -138,8 +145,18 @@ public final class VersionLibraryBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
public void addArgument(String... args) {
|
||||
public void addGameArgument(String... args) {
|
||||
for (String arg : args)
|
||||
game.add(new StringArgument(arg));
|
||||
}
|
||||
|
||||
public void addJvmArgument(String... args) {
|
||||
jvmChanged = true;
|
||||
for (String arg : args)
|
||||
jvm.add(new StringArgument(arg));
|
||||
}
|
||||
|
||||
public void addLibrary(Library library) {
|
||||
libraries.add(library);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,6 +153,7 @@ public class DefaultLauncher extends Launcher {
|
||||
configuration.put("${natives_directory}", nativeFolder.getAbsolutePath());
|
||||
configuration.put("${game_assets}", gameAssets.getAbsolutePath());
|
||||
configuration.put("${assets_root}", gameAssets.getAbsolutePath());
|
||||
configuration.put("${libraries_directory}", repository.getLibrariesDirectory(version).getAbsolutePath());
|
||||
|
||||
res.addAll(Arguments.parseArguments(version.getArguments().map(Arguments::getJvm).orElseGet(this::getDefaultJVMArguments), configuration));
|
||||
if (authInfo.getArguments() != null && authInfo.getArguments().getJvm() != null && !authInfo.getArguments().getJvm().isEmpty())
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user