mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-09-14 06:17:47 -04:00
修复自动安装在 1.20.4 的严重问题 (#3023)
* Fix: OptiFine and Forge has compatible problem on 1.20.4 . Fix: Forge changes it's main class on 1.20.4 .
* Fix: HMCL cannot display the analyed versions installed by external launchers.
* Refuse to configure installable widgets when it's from external process.
* Add javadoc about LibraryStatus
* Adapt to the new change of Forge: b8270cd9ff
* Re-arrange entries.
* Fix.
This commit is contained in:
parent
b43c8ceae5
commit
6b78f56298
@ -270,10 +270,12 @@ public class InstallerItem extends Control {
|
|||||||
return i18n("install.installer.incompatible", i18n("install.installer." + incompatibleWith));
|
return i18n("install.installer.incompatible", i18n("install.installer." + incompatibleWith));
|
||||||
} else if (version == null) {
|
} else if (version == null) {
|
||||||
return i18n("install.installer.not_installed");
|
return i18n("install.installer.not_installed");
|
||||||
} else {
|
} else if (control.id.equals(MINECRAFT.getPatchId()) || control.removable.get() || control.upgradable.get()) {
|
||||||
return i18n("install.installer.version", version);
|
return i18n("install.installer.version", version);
|
||||||
|
} else {
|
||||||
|
return i18n("install.installer.external_version", version);
|
||||||
}
|
}
|
||||||
}, control.incompatibleLibraryName, control.incompatibleWithGame, control.libraryVersion));
|
}, control.incompatibleLibraryName, control.incompatibleWithGame, control.libraryVersion, control.installable, control.removable, control.upgradable));
|
||||||
BorderPane.setMargin(statusLabel, new Insets(0, 0, 0, 8));
|
BorderPane.setMargin(statusLabel, new Insets(0, 0, 0, 8));
|
||||||
BorderPane.setAlignment(statusLabel, Pos.CENTER_LEFT);
|
BorderPane.setAlignment(statusLabel, Pos.CENTER_LEFT);
|
||||||
|
|
||||||
@ -297,8 +299,9 @@ public class InstallerItem extends Control {
|
|||||||
control.upgradable));
|
control.upgradable));
|
||||||
arrowButton.getStyleClass().add("toggle-icon4");
|
arrowButton.getStyleClass().add("toggle-icon4");
|
||||||
arrowButton.visibleProperty().bind(Bindings.createBooleanBinding(
|
arrowButton.visibleProperty().bind(Bindings.createBooleanBinding(
|
||||||
() -> control.installable.get() && control.incompatibleLibraryName.get() == null,
|
() -> control.installable.get() && control.libraryVersion.get() == null && control.incompatibleLibraryName.get() == null,
|
||||||
control.installable, control.incompatibleLibraryName));
|
control.installable, control.libraryVersion, control.incompatibleLibraryName
|
||||||
|
));
|
||||||
arrowButton.managedProperty().bind(arrowButton.visibleProperty());
|
arrowButton.managedProperty().bind(arrowButton.visibleProperty());
|
||||||
arrowButton.onMouseClickedProperty().bind(control.action);
|
arrowButton.onMouseClickedProperty().bind(control.action);
|
||||||
buttonsContainer.getChildren().add(arrowButton);
|
buttonsContainer.getChildren().add(arrowButton);
|
||||||
|
@ -30,7 +30,6 @@ import org.jackhuang.hmcl.task.TaskExecutor;
|
|||||||
import org.jackhuang.hmcl.task.TaskListener;
|
import org.jackhuang.hmcl.task.TaskListener;
|
||||||
import org.jackhuang.hmcl.ui.*;
|
import org.jackhuang.hmcl.ui.*;
|
||||||
import org.jackhuang.hmcl.ui.download.UpdateInstallerWizardProvider;
|
import org.jackhuang.hmcl.ui.download.UpdateInstallerWizardProvider;
|
||||||
import org.jackhuang.hmcl.util.Lang;
|
|
||||||
import org.jackhuang.hmcl.util.TaskCancellationAction;
|
import org.jackhuang.hmcl.util.TaskCancellationAction;
|
||||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||||
|
|
||||||
@ -90,13 +89,15 @@ public class InstallerListPage extends ListPageBase<InstallerItem> implements Ve
|
|||||||
for (InstallerItem installerItem : group.getLibraries()) {
|
for (InstallerItem installerItem : group.getLibraries()) {
|
||||||
String libraryId = installerItem.getLibraryId();
|
String libraryId = installerItem.getLibraryId();
|
||||||
String libraryVersion = analyzer.getVersion(libraryId).orElse(null);
|
String libraryVersion = analyzer.getVersion(libraryId).orElse(null);
|
||||||
|
boolean libraryConfigurable = libraryVersion != null && analyzer.getLibraryStatus(libraryId) == LibraryAnalyzer.LibraryMark.LibraryStatus.CLEAR;
|
||||||
|
|
||||||
installerItem.libraryVersion.set(libraryVersion);
|
installerItem.libraryVersion.set(libraryVersion);
|
||||||
installerItem.upgradable.set(libraryVersion != null);
|
installerItem.upgradable.set(libraryConfigurable);
|
||||||
installerItem.installable.set(true);
|
installerItem.installable.set(true);
|
||||||
installerItem.action.set(e -> {
|
installerItem.action.set(e -> {
|
||||||
Controllers.getDecorator().startWizard(new UpdateInstallerWizardProvider(profile, gameVersion, version, libraryId, libraryVersion));
|
Controllers.getDecorator().startWizard(new UpdateInstallerWizardProvider(profile, gameVersion, version, libraryId, libraryVersion));
|
||||||
});
|
});
|
||||||
boolean removable = !LibraryAnalyzer.LibraryType.MINECRAFT.getPatchId().equals(libraryId) && libraryVersion != null;
|
boolean removable = !LibraryAnalyzer.LibraryType.MINECRAFT.getPatchId().equals(libraryId) && libraryConfigurable;
|
||||||
installerItem.removable.set(removable);
|
installerItem.removable.set(removable);
|
||||||
if (removable) {
|
if (removable) {
|
||||||
Runnable action = removeAction.apply(libraryId);
|
Runnable action = removeAction.apply(libraryId);
|
||||||
@ -119,17 +120,10 @@ public class InstallerListPage extends ListPageBase<InstallerItem> implements Ve
|
|||||||
InstallerItem installerItem = new InstallerItem(libraryId);
|
InstallerItem installerItem = new InstallerItem(libraryId);
|
||||||
installerItem.libraryVersion.set(libraryVersion);
|
installerItem.libraryVersion.set(libraryVersion);
|
||||||
installerItem.installable.set(false);
|
installerItem.installable.set(false);
|
||||||
installerItem.upgradable.bind(installerItem.installable);
|
installerItem.upgradable.set(false);
|
||||||
installerItem.removable.set(true);
|
installerItem.removable.set(true);
|
||||||
installerItem.removeAction.set(e -> action.run());
|
installerItem.removeAction.set(e -> action.run());
|
||||||
|
|
||||||
if (libraryVersion != null && Lang.test(() -> profile.getDependency().getVersionList(libraryId))) {
|
|
||||||
installerItem.installable.set(true);
|
|
||||||
installerItem.action.set(e -> {
|
|
||||||
Controllers.getDecorator().startWizard(new UpdateInstallerWizardProvider(profile, gameVersion, version, libraryId, libraryVersion));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
itemsProperty().add(installerItem);
|
itemsProperty().add(installerItem);
|
||||||
}
|
}
|
||||||
}, Platform::runLater);
|
}, Platform::runLater);
|
||||||
@ -175,7 +169,8 @@ public class InstallerListPage extends ListPageBase<InstallerItem> implements Ve
|
|||||||
@Override
|
@Override
|
||||||
protected List<Node> initializeToolbar(InstallerListPage skinnable) {
|
protected List<Node> initializeToolbar(InstallerListPage skinnable) {
|
||||||
return Collections.singletonList(
|
return Collections.singletonList(
|
||||||
createToolbarButton2(i18n("install.installer.install_offline"), SVG.PLUS, skinnable::installOffline));
|
createToolbarButton2(i18n("install.installer.install_offline"), SVG.PLUS, skinnable::installOffline)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -637,6 +637,7 @@ install.installer.optifine=OptiFine
|
|||||||
install.installer.quilt=Quilt
|
install.installer.quilt=Quilt
|
||||||
install.installer.quilt-api=QSL/QFAPI
|
install.installer.quilt-api=QSL/QFAPI
|
||||||
install.installer.version=%s
|
install.installer.version=%s
|
||||||
|
install.installer.external_version=%s Installed by external process, which cannot be configured
|
||||||
install.modpack=Install a Modpack
|
install.modpack=Install a Modpack
|
||||||
install.new_game=Add a New Instance
|
install.new_game=Add a New Instance
|
||||||
install.new_game.already_exists=This instance already exists. Please use another name.
|
install.new_game.already_exists=This instance already exists. Please use another name.
|
||||||
|
@ -521,6 +521,7 @@ install.installer.optifine=OptiFine
|
|||||||
install.installer.quilt=Quilt
|
install.installer.quilt=Quilt
|
||||||
install.installer.quilt-api=QSL/QFAPI
|
install.installer.quilt-api=QSL/QFAPI
|
||||||
install.installer.version=%s
|
install.installer.version=%s
|
||||||
|
install.installer.external_version=%s 由外部安裝的版本,無法解除安裝或更換
|
||||||
install.modpack=安裝模組包
|
install.modpack=安裝模組包
|
||||||
install.new_game=安裝新遊戲版本
|
install.new_game=安裝新遊戲版本
|
||||||
install.new_game.already_exists=此版本已經存在,請重新命名
|
install.new_game.already_exists=此版本已經存在,請重新命名
|
||||||
|
@ -520,6 +520,7 @@ install.installer.optifine=OptiFine
|
|||||||
install.installer.quilt=Quilt
|
install.installer.quilt=Quilt
|
||||||
install.installer.quilt-api=QSL/QFAPI
|
install.installer.quilt-api=QSL/QFAPI
|
||||||
install.installer.version=%s
|
install.installer.version=%s
|
||||||
|
install.installer.external_version=%s 由外部安装的版本,无法卸载或更换
|
||||||
install.modpack=安装整合包
|
install.modpack=安装整合包
|
||||||
install.new_game=安装新游戏版本
|
install.new_game=安装新游戏版本
|
||||||
install.new_game.already_exists=此版本已经存在,请换一个名字
|
install.new_game.already_exists=此版本已经存在,请换一个名字
|
||||||
|
@ -19,7 +19,10 @@ package org.jackhuang.hmcl.download;
|
|||||||
|
|
||||||
import org.jackhuang.hmcl.game.*;
|
import org.jackhuang.hmcl.game.*;
|
||||||
import org.jackhuang.hmcl.mod.ModLoaderType;
|
import org.jackhuang.hmcl.mod.ModLoaderType;
|
||||||
|
import org.jackhuang.hmcl.util.Lang;
|
||||||
import org.jackhuang.hmcl.util.Pair;
|
import org.jackhuang.hmcl.util.Pair;
|
||||||
|
import org.jackhuang.hmcl.util.versioning.VersionNumber;
|
||||||
|
import org.jackhuang.hmcl.util.versioning.VersionRange;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
@ -51,6 +54,15 @@ public final class LibraryAnalyzer implements Iterable<LibraryAnalyzer.LibraryMa
|
|||||||
return Optional.ofNullable(libraries.get(type.getPatchId())).map(Pair::getKey);
|
return Optional.ofNullable(libraries.get(type.getPatchId())).map(Pair::getKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a library is provided in $.patches, it's structure is so clear that we can do any operation.
|
||||||
|
* Otherwise, we must guess how are these libraries mixed.
|
||||||
|
* Maybe a guessing implementation will be provided in the future. But by now, we simply set it to JUST_EXISTED.
|
||||||
|
*/
|
||||||
|
public LibraryMark.LibraryStatus getLibraryStatus(String type) {
|
||||||
|
return version.hasPatch(type) ? LibraryMark.LibraryStatus.CLEAR : LibraryMark.LibraryStatus.JUST_EXISTED;
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public Iterator<LibraryMark> iterator() {
|
public Iterator<LibraryMark> iterator() {
|
||||||
@ -65,7 +77,7 @@ public final class LibraryAnalyzer implements Iterable<LibraryAnalyzer.LibraryMa
|
|||||||
@Override
|
@Override
|
||||||
public LibraryMark next() {
|
public LibraryMark next() {
|
||||||
Map.Entry<String, Pair<Library, String>> entry = impl.next();
|
Map.Entry<String, Pair<Library, String>> entry = impl.next();
|
||||||
return new LibraryMark(entry.getKey(), entry.getValue().getValue());
|
return new LibraryMark(entry.getKey(), entry.getValue().getValue(), getLibraryStatus(entry.getKey()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -85,13 +97,9 @@ public final class LibraryAnalyzer implements Iterable<LibraryAnalyzer.LibraryMa
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasModLauncher() {
|
public boolean hasModLauncher() {
|
||||||
final String modLauncher = "cpw.mods.modlauncher.Launcher";
|
return LibraryAnalyzer.MOD_LAUNCHER_MAIN.equals(version.getMainClass()) || version.getPatches().stream().anyMatch(
|
||||||
return modLauncher.equals(version.getMainClass()) || version.getPatches().stream().anyMatch(patch -> modLauncher.equals(patch.getMainClass()));
|
patch -> LibraryAnalyzer.MOD_LAUNCHER_MAIN.equals(patch.getMainClass())
|
||||||
}
|
);
|
||||||
|
|
||||||
public boolean hasBootstrapLauncher() {
|
|
||||||
final String bootstrapLauncher = "cpw.mods.bootstraplauncher.BootstrapLauncher";
|
|
||||||
return bootstrapLauncher.equals(version.getMainClass()) || version.getPatches().stream().anyMatch(patch -> bootstrapLauncher.equals(patch.getMainClass()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Version removingMatchedLibrary(Version version, String libraryId) {
|
private Version removingMatchedLibrary(Version version, String libraryId) {
|
||||||
@ -184,7 +192,7 @@ public final class LibraryAnalyzer implements Iterable<LibraryAnalyzer.LibraryMa
|
|||||||
private final Pattern FORGE_VERSION_MATCHER = Pattern.compile("^([0-9.]+)-(?<forge>[0-9.]+)(-([0-9.]+))?$");
|
private final Pattern FORGE_VERSION_MATCHER = Pattern.compile("^([0-9.]+)-(?<forge>[0-9.]+)(-([0-9.]+))?$");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String patchVersion(Version gameVersion, String libraryVersion) {
|
protected String patchVersion(Version gameVersion, String libraryVersion) {
|
||||||
Matcher matcher = FORGE_VERSION_MATCHER.matcher(libraryVersion);
|
Matcher matcher = FORGE_VERSION_MATCHER.matcher(libraryVersion);
|
||||||
if (matcher.find()) {
|
if (matcher.find()) {
|
||||||
return matcher.group("forge");
|
return matcher.group("forge");
|
||||||
@ -193,7 +201,7 @@ public final class LibraryAnalyzer implements Iterable<LibraryAnalyzer.LibraryMa
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matchLibrary(Library library, List<Library> libraries) {
|
protected boolean matchLibrary(Library library, List<Library> libraries) {
|
||||||
for (Library l : libraries) {
|
for (Library l : libraries) {
|
||||||
if (NEO_FORGE.matchLibrary(l, libraries)) {
|
if (NEO_FORGE.matchLibrary(l, libraries)) {
|
||||||
return false;
|
return false;
|
||||||
@ -206,7 +214,7 @@ public final class LibraryAnalyzer implements Iterable<LibraryAnalyzer.LibraryMa
|
|||||||
private final Pattern NEO_FORGE_VERSION_MATCHER = Pattern.compile("^([0-9.]+)-(?<forge>[0-9.]+)(-([0-9.]+))?$");
|
private final Pattern NEO_FORGE_VERSION_MATCHER = Pattern.compile("^([0-9.]+)-(?<forge>[0-9.]+)(-([0-9.]+))?$");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String patchVersion(Version gameVersion, String libraryVersion) {
|
protected String patchVersion(Version gameVersion, String libraryVersion) {
|
||||||
Matcher matcher = NEO_FORGE_VERSION_MATCHER.matcher(libraryVersion);
|
Matcher matcher = NEO_FORGE_VERSION_MATCHER.matcher(libraryVersion);
|
||||||
if (matcher.find()) {
|
if (matcher.find()) {
|
||||||
return matcher.group("forge");
|
return matcher.group("forge");
|
||||||
@ -289,22 +297,37 @@ public final class LibraryAnalyzer implements Iterable<LibraryAnalyzer.LibraryMa
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean matchLibrary(Library library, List<Library> libraries) {
|
protected boolean matchLibrary(Library library, List<Library> libraries) {
|
||||||
return group.matcher(library.getGroupId()).matches() && artifact.matcher(library.getArtifactId()).matches();
|
return group.matcher(library.getGroupId()).matches() && artifact.matcher(library.getArtifactId()).matches();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String patchVersion(Version gameVersion, String libraryVersion) {
|
protected String patchVersion(Version gameVersion, String libraryVersion) {
|
||||||
return libraryVersion;
|
return libraryVersion;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class LibraryMark {
|
public final static class LibraryMark {
|
||||||
|
/**
|
||||||
|
* If a library is provided in $.patches, it's structure is so clear that we can do any operation.
|
||||||
|
* Otherwise, we must guess how are these libraries mixed.
|
||||||
|
* Maybe a guessing implementation will be provided in the future. But by now, we simply set it to JUST_EXISTED.
|
||||||
|
*/
|
||||||
|
public enum LibraryStatus {
|
||||||
|
CLEAR, UNSURE, JUST_EXISTED
|
||||||
|
}
|
||||||
|
|
||||||
private final String libraryId;
|
private final String libraryId;
|
||||||
private final String libraryVersion;
|
private final String libraryVersion;
|
||||||
|
/**
|
||||||
|
* If this version is installed by HMCL, instead of external process,
|
||||||
|
* which means $.patches contains this library, structureClear is true.
|
||||||
|
*/
|
||||||
|
private final LibraryStatus status;
|
||||||
|
|
||||||
public LibraryMark(@NotNull String libraryId, @Nullable String libraryVersion) {
|
private LibraryMark(@NotNull String libraryId, @Nullable String libraryVersion, LibraryStatus status) {
|
||||||
this.libraryId = libraryId;
|
this.libraryId = libraryId;
|
||||||
this.libraryVersion = libraryVersion;
|
this.libraryVersion = libraryVersion;
|
||||||
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@ -316,12 +339,27 @@ public final class LibraryAnalyzer implements Iterable<LibraryAnalyzer.LibraryMa
|
|||||||
public String getLibraryVersion() {
|
public String getLibraryVersion() {
|
||||||
return libraryVersion;
|
return libraryVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LibraryStatus getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String VANILLA_MAIN = "net.minecraft.client.main.Main";
|
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 LAUNCH_WRAPPER_MAIN = "net.minecraft.launchwrapper.Launch";
|
||||||
public static final String MOD_LAUNCHER_MAIN = "cpw.mods.modlauncher.Launcher";
|
public static final String MOD_LAUNCHER_MAIN = "cpw.mods.modlauncher.Launcher";
|
||||||
public static final String BOOTSTRAP_LAUNCHER_MAIN = "cpw.mods.bootstraplauncher.BootstrapLauncher";
|
public static final String BOOTSTRAP_LAUNCHER_MAIN = "cpw.mods.bootstraplauncher.BootstrapLauncher";
|
||||||
|
public static final String FORGE_BOOTSTRAP_MAIN = "net.minecraftforge.bootstrap.ForgeBootstrap";
|
||||||
|
|
||||||
|
public static final Set<String> FORGE_OPTIFINE_MAIN = new HashSet<>(Lang.immutableListOf(
|
||||||
|
LibraryAnalyzer.VANILLA_MAIN,
|
||||||
|
LibraryAnalyzer.LAUNCH_WRAPPER_MAIN,
|
||||||
|
LibraryAnalyzer.MOD_LAUNCHER_MAIN,
|
||||||
|
LibraryAnalyzer.BOOTSTRAP_LAUNCHER_MAIN,
|
||||||
|
LibraryAnalyzer.FORGE_BOOTSTRAP_MAIN
|
||||||
|
));
|
||||||
|
|
||||||
|
public static final VersionRange<VersionNumber> FORGE_OPTIFINE_BROKEN_RANGE = VersionNumber.between("48.0.0", "49.0.50");
|
||||||
|
|
||||||
public static final String[] FORGE_TWEAKERS = new String[]{
|
public static final String[] FORGE_TWEAKERS = new String[]{
|
||||||
"net.minecraftforge.legacy._1_5_2.LibraryFixerTweaker", // 1.5.2
|
"net.minecraftforge.legacy._1_5_2.LibraryFixerTweaker", // 1.5.2
|
||||||
|
@ -76,7 +76,9 @@ public class MaintainTask extends Task<Version> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<Library> libraries = version.getLibraries();
|
List<Library> libraries = version.getLibraries();
|
||||||
if (libraries.size() > 0) {
|
if (!libraries.isEmpty()) {
|
||||||
|
// HMCL once use log4j-patch to prevent virus. But now, we only modify log4j2.xml.
|
||||||
|
// Therefore, we remove this library.
|
||||||
Library library = libraries.get(0);
|
Library library = libraries.get(0);
|
||||||
if ("org.glavo".equals(library.getGroupId())
|
if ("org.glavo".equals(library.getGroupId())
|
||||||
&& ("log4j-patch".equals(library.getArtifactId()) || "log4j-patch-beta9".equals(library.getArtifactId()))
|
&& ("log4j-patch".equals(library.getArtifactId()) || "log4j-patch-beta9".equals(library.getArtifactId()))
|
||||||
@ -161,8 +163,8 @@ public class MaintainTask extends Task<Version> {
|
|||||||
Path libraryPath = repository.getLibraryFile(version, hmclTransformerDiscoveryService).toPath();
|
Path libraryPath = repository.getLibraryFile(version, hmclTransformerDiscoveryService).toPath();
|
||||||
try (InputStream input = MaintainTask.class.getResourceAsStream("/assets/game/HMCLTransformerDiscoveryService-1.0.jar")) {
|
try (InputStream input = MaintainTask.class.getResourceAsStream("/assets/game/HMCLTransformerDiscoveryService-1.0.jar")) {
|
||||||
Files.createDirectories(libraryPath.getParent());
|
Files.createDirectories(libraryPath.getParent());
|
||||||
Files.copy(input, libraryPath, StandardCopyOption.REPLACE_EXISTING);
|
Files.copy(Objects.requireNonNull(input, "Bundled HMCLTransformerDiscoveryService is missing."), libraryPath, StandardCopyOption.REPLACE_EXISTING);
|
||||||
} catch (IOException e) {
|
} catch (IOException | NullPointerException e) {
|
||||||
LOG.warning("Unable to unpack HMCLTransformerDiscoveryService", e);
|
LOG.warning("Unable to unpack HMCLTransformerDiscoveryService", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -282,13 +284,6 @@ public class MaintainTask extends Task<Version> {
|
|||||||
return version.setLibraries(libraries.stream().filter(Objects::nonNull).collect(Collectors.toList()));
|
return version.setLibraries(libraries.stream().filter(Objects::nonNull).collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isPurePatched(Version version) {
|
|
||||||
if (!version.isResolvedPreservingPatches())
|
|
||||||
throw new IllegalArgumentException("isPurePatched requires a version resolved preserving patches");
|
|
||||||
|
|
||||||
return version.hasPatch("game");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Version unique(Version version) {
|
public static Version unique(Version version) {
|
||||||
List<Library> libraries = new ArrayList<>();
|
List<Library> libraries = new ArrayList<>();
|
||||||
|
|
||||||
|
@ -102,18 +102,10 @@ public final class ForgeInstallTask extends Task<Version> {
|
|||||||
String originalMainClass = version.resolve(dependencyManager.getGameRepository()).getMainClass();
|
String originalMainClass = version.resolve(dependencyManager.getGameRepository()).getMainClass();
|
||||||
if (GameVersionNumber.compare("1.13", remote.getGameVersion()) <= 0) {
|
if (GameVersionNumber.compare("1.13", remote.getGameVersion()) <= 0) {
|
||||||
// Forge 1.13 is not compatible with fabric.
|
// Forge 1.13 is not compatible with fabric.
|
||||||
if (!LibraryAnalyzer.VANILLA_MAIN.equals(originalMainClass)
|
if (!LibraryAnalyzer.FORGE_OPTIFINE_MAIN.contains(originalMainClass))
|
||||||
&& !LibraryAnalyzer.MOD_LAUNCHER_MAIN.equals(originalMainClass)
|
|
||||||
&& !LibraryAnalyzer.LAUNCH_WRAPPER_MAIN.equals(originalMainClass)
|
|
||||||
&& !LibraryAnalyzer.BOOTSTRAP_LAUNCHER_MAIN.equals(originalMainClass))
|
|
||||||
throw new UnsupportedInstallationException(UNSUPPORTED_LAUNCH_WRAPPER);
|
throw new UnsupportedInstallationException(UNSUPPORTED_LAUNCH_WRAPPER);
|
||||||
} else {
|
|
||||||
// Forge 1.12 and older versions is compatible with vanilla and launchwrapper.
|
|
||||||
// if (!"net.minecraft.client.main.Main".equals(originalMainClass) && !"net.minecraft.launchwrapper.Launch".equals(originalMainClass))
|
|
||||||
// throw new OptiFineInstallTask.UnsupportedOptiFineInstallationException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (detectForgeInstallerType(dependencyManager, version, installer))
|
if (detectForgeInstallerType(dependencyManager, version, installer))
|
||||||
dependency = new ForgeNewInstallTask(dependencyManager, version, remote.getSelfVersion(), installer);
|
dependency = new ForgeNewInstallTask(dependencyManager, version, remote.getSelfVersion(), installer);
|
||||||
else
|
else
|
||||||
|
@ -18,15 +18,21 @@
|
|||||||
package org.jackhuang.hmcl.download.game;
|
package org.jackhuang.hmcl.download.game;
|
||||||
|
|
||||||
import org.jackhuang.hmcl.download.AbstractDependencyManager;
|
import org.jackhuang.hmcl.download.AbstractDependencyManager;
|
||||||
|
import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
||||||
import org.jackhuang.hmcl.game.GameRepository;
|
import org.jackhuang.hmcl.game.GameRepository;
|
||||||
import org.jackhuang.hmcl.game.Library;
|
import org.jackhuang.hmcl.game.Library;
|
||||||
import org.jackhuang.hmcl.game.Version;
|
import org.jackhuang.hmcl.game.Version;
|
||||||
import org.jackhuang.hmcl.task.FileDownloadTask;
|
import org.jackhuang.hmcl.task.FileDownloadTask;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
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.FileUtils;
|
||||||
|
import org.jackhuang.hmcl.util.versioning.GameVersionNumber;
|
||||||
|
import org.jackhuang.hmcl.util.versioning.VersionNumber;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.FileSystem;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -81,20 +87,23 @@ public final class GameLibrariesTask extends Task<Void> {
|
|||||||
File file = gameRepository.getLibraryFile(version, library);
|
File file = gameRepository.getLibraryFile(version, library);
|
||||||
Path jar = file.toPath();
|
Path jar = file.toPath();
|
||||||
if (!file.isFile()) return true;
|
if (!file.isFile()) return true;
|
||||||
|
|
||||||
|
if (!integrityCheck) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
if (integrityCheck && !library.getDownload().validateChecksum(jar, true)) return true;
|
if (!library.getDownload().validateChecksum(jar, true)) {
|
||||||
if (integrityCheck &&
|
return true;
|
||||||
library.getChecksums() != null && !library.getChecksums().isEmpty() &&
|
}
|
||||||
!LibraryDownloadTask.checksumValid(file, library.getChecksums())) return true;
|
if (library.getChecksums() != null && !library.getChecksums().isEmpty() && !LibraryDownloadTask.checksumValid(file, library.getChecksums())) {
|
||||||
if (integrityCheck) {
|
return true;
|
||||||
String ext = FileUtils.getExtension(file);
|
}
|
||||||
if (ext.equals("jar")) {
|
if (FileUtils.getExtension(file).equals("jar")) {
|
||||||
try {
|
try {
|
||||||
FileDownloadTask.ZIP_INTEGRITY_CHECK_HANDLER.checkIntegrity(jar, jar);
|
FileDownloadTask.ZIP_INTEGRITY_CHECK_HANDLER.checkIntegrity(jar, jar);
|
||||||
} catch (IOException ignored) {
|
} catch (IOException ignored) {
|
||||||
// the Jar file is malformed, so re-download it.
|
// the Jar file is malformed, so re-download it.
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -105,16 +114,32 @@ public final class GameLibrariesTask extends Task<Void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() throws IOException {
|
||||||
libraries.stream().filter(Library::appliesToCurrentEnvironment).forEach(library -> {
|
GameRepository gameRepository = dependencyManager.getGameRepository();
|
||||||
File file = dependencyManager.getGameRepository().getLibraryFile(version, library);
|
for (Library library : libraries) {
|
||||||
if (shouldDownloadLibrary(dependencyManager.getGameRepository(), version, library, integrityCheck)) {
|
if (!library.appliesToCurrentEnvironment()) {
|
||||||
if (library.hasDownloadURL() || !"optifine".equals(library.getGroupId()))
|
continue;
|
||||||
dependencies.add(new LibraryDownloadTask(dependencyManager, file, library));
|
}
|
||||||
|
|
||||||
|
File file = gameRepository.getLibraryFile(version, library);
|
||||||
|
if ("optifine".equals(library.getGroupId()) && file.exists() && GameVersionNumber.asGameVersion(gameRepository.getGameVersion(version)).compareTo("1.20.4") == 0) {
|
||||||
|
String forgeVersion = LibraryAnalyzer.analyze(version, "1.20.4")
|
||||||
|
.getVersion(LibraryAnalyzer.LibraryType.FORGE)
|
||||||
|
.orElse(null);
|
||||||
|
if (forgeVersion != null && LibraryAnalyzer.FORGE_OPTIFINE_BROKEN_RANGE.contains(VersionNumber.asVersion(forgeVersion))) {
|
||||||
|
try (FileSystem fs2 = CompressingUtils.createWritableZipFileSystem(file.toPath())) {
|
||||||
|
Files.deleteIfExists(fs2.getPath("/META-INF/mods.toml"));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new IOException("Cannot fix optifine", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (shouldDownloadLibrary(gameRepository, version, library, integrityCheck) && library.hasDownloadURL()) {
|
||||||
|
dependencies.add(new LibraryDownloadTask(dependencyManager, file, library));
|
||||||
} else {
|
} else {
|
||||||
dependencyManager.getCacheRepository().tryCacheLibrary(library, file.toPath());
|
dependencyManager.getCacheRepository().tryCacheLibrary(library, file.toPath());
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -125,20 +125,23 @@ public final class OptiFineInstallTask extends Task<Version> {
|
|||||||
@Override
|
@Override
|
||||||
public void execute() throws Exception {
|
public void execute() throws Exception {
|
||||||
String originalMainClass = version.resolve(dependencyManager.getGameRepository()).getMainClass();
|
String originalMainClass = version.resolve(dependencyManager.getGameRepository()).getMainClass();
|
||||||
if (!LibraryAnalyzer.VANILLA_MAIN.equals(originalMainClass) &&
|
if (!LibraryAnalyzer.FORGE_OPTIFINE_MAIN.contains(originalMainClass))
|
||||||
!LibraryAnalyzer.LAUNCH_WRAPPER_MAIN.equals(originalMainClass) &&
|
|
||||||
!LibraryAnalyzer.MOD_LAUNCHER_MAIN.equals(originalMainClass) &&
|
|
||||||
!LibraryAnalyzer.BOOTSTRAP_LAUNCHER_MAIN.equals(originalMainClass))
|
|
||||||
throw new UnsupportedInstallationException(UnsupportedInstallationException.UNSUPPORTED_LAUNCH_WRAPPER);
|
throw new UnsupportedInstallationException(UnsupportedInstallationException.UNSUPPORTED_LAUNCH_WRAPPER);
|
||||||
|
|
||||||
List<Library> libraries = new ArrayList<>(4);
|
List<Library> libraries = new ArrayList<>(4);
|
||||||
libraries.add(optiFineLibrary);
|
libraries.add(optiFineLibrary);
|
||||||
|
|
||||||
FileUtils.copyFile(dest, gameRepository.getLibraryFile(version, optiFineInstallerLibrary).toPath());
|
Path optiFineInstallerLibraryPath = gameRepository.getLibraryFile(version, optiFineInstallerLibrary).toPath();
|
||||||
|
FileUtils.copyFile(dest, optiFineInstallerLibraryPath);
|
||||||
|
|
||||||
|
try (FileSystem fs2 = CompressingUtils.createWritableZipFileSystem(optiFineInstallerLibraryPath)) {
|
||||||
|
Files.deleteIfExists(fs2.getPath("/META-INF/mods.toml"));
|
||||||
|
}
|
||||||
|
|
||||||
// Install launch wrapper modified by OptiFine
|
// Install launch wrapper modified by OptiFine
|
||||||
boolean hasLaunchWrapper = false;
|
boolean hasLaunchWrapper = false;
|
||||||
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(dest)) {
|
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(dest)) {
|
||||||
|
Path optiFineLibraryPath = gameRepository.getLibraryFile(version, optiFineLibrary).toPath();
|
||||||
if (Files.exists(fs.getPath("optifine/Patcher.class"))) {
|
if (Files.exists(fs.getPath("optifine/Patcher.class"))) {
|
||||||
String[] command = {
|
String[] command = {
|
||||||
JavaVersion.fromCurrentEnvironment().getBinary().toString(),
|
JavaVersion.fromCurrentEnvironment().getBinary().toString(),
|
||||||
@ -147,13 +150,17 @@ public final class OptiFineInstallTask extends Task<Version> {
|
|||||||
"optifine.Patcher",
|
"optifine.Patcher",
|
||||||
gameRepository.getVersionJar(version).getAbsolutePath(),
|
gameRepository.getVersionJar(version).getAbsolutePath(),
|
||||||
dest.toString(),
|
dest.toString(),
|
||||||
gameRepository.getLibraryFile(version, optiFineLibrary).toString()
|
optiFineLibraryPath.toString()
|
||||||
};
|
};
|
||||||
int exitCode = SystemUtils.callExternalProcess(command);
|
int exitCode = SystemUtils.callExternalProcess(command);
|
||||||
if (exitCode != 0)
|
if (exitCode != 0)
|
||||||
throw new IOException("OptiFine patcher failed, command: " + new CommandBuilder().addAll(Arrays.asList(command)));
|
throw new IOException("OptiFine patcher failed, command: " + new CommandBuilder().addAll(Arrays.asList(command)));
|
||||||
} else {
|
} else {
|
||||||
FileUtils.copyFile(dest, gameRepository.getLibraryFile(version, optiFineLibrary).toPath());
|
FileUtils.copyFile(dest, optiFineLibraryPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
try (FileSystem fs2 = CompressingUtils.createWritableZipFileSystem(optiFineLibraryPath)) {
|
||||||
|
Files.deleteIfExists(fs2.getPath("/META-INF/mods.toml"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Path launchWrapper2 = fs.getPath("launchwrapper-2.0.jar");
|
Path launchWrapper2 = fs.getPath("launchwrapper-2.0.jar");
|
||||||
|
@ -295,7 +295,10 @@ public class Version implements Comparable<Version>, Validation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (patches != null && !patches.isEmpty()) {
|
if (patches == null) {
|
||||||
|
// This is a version from external launcher.
|
||||||
|
thisVersion = thisVersion.merge(this, true);
|
||||||
|
} else if (!patches.isEmpty()) {
|
||||||
// Assume patches themselves do not have patches recursively.
|
// Assume patches themselves do not have patches recursively.
|
||||||
List<Version> sortedPatches = patches.stream()
|
List<Version> sortedPatches = patches.stream()
|
||||||
.sorted(Comparator.comparing(Version::getPriority))
|
.sorted(Comparator.comparing(Version::getPriority))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user