mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-08-03 19:36:53 -04:00
解析 MultiMC 整合包中未声明但在依赖链上的组件 (#4003)
This commit is contained in:
parent
fa8b3a952b
commit
d624086594
@ -45,6 +45,7 @@ import java.util.Arrays;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -96,7 +97,10 @@ public final class MultiMCInstancePatch {
|
|||||||
@SerializedName("jarMods")
|
@SerializedName("jarMods")
|
||||||
private final List<Library> jarMods;
|
private final List<Library> jarMods;
|
||||||
|
|
||||||
public MultiMCInstancePatch(int formatVersion, String id, String version, AssetIndexInfo assetIndex, String minecraftArguments, List<String> jvmArgs, String mainClass, int[] javaMajors, Library mainJar, List<String> traits, List<String> tweakers, List<Library> libraries0, List<Library> libraries1, List<Library> mavenFiles, List<Library> jarMods) {
|
@SerializedName("requires")
|
||||||
|
private final List<MultiMCManifest.MultiMCManifestCachedRequires> requires;
|
||||||
|
|
||||||
|
public MultiMCInstancePatch(int formatVersion, String id, String version, AssetIndexInfo assetIndex, String minecraftArguments, List<String> jvmArgs, String mainClass, int[] javaMajors, Library mainJar, List<String> traits, List<String> tweakers, List<Library> libraries0, List<Library> libraries1, List<Library> mavenFiles, List<Library> jarMods, List<MultiMCManifest.MultiMCManifestCachedRequires> requires) {
|
||||||
this.formatVersion = formatVersion;
|
this.formatVersion = formatVersion;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
@ -112,6 +116,7 @@ public final class MultiMCInstancePatch {
|
|||||||
this.libraries1 = libraries1;
|
this.libraries1 = libraries1;
|
||||||
this.mavenFiles = mavenFiles;
|
this.mavenFiles = mavenFiles;
|
||||||
this.jarMods = jarMods;
|
this.jarMods = jarMods;
|
||||||
|
this.requires = requires;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getFormatVersion() {
|
public int getFormatVersion() {
|
||||||
@ -177,6 +182,10 @@ public final class MultiMCInstancePatch {
|
|||||||
return nonNullOrEmpty(jarMods);
|
return nonNullOrEmpty(jarMods);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<MultiMCManifest.MultiMCManifestCachedRequires> getRequires() {
|
||||||
|
return nonNullOrEmpty(requires);
|
||||||
|
}
|
||||||
|
|
||||||
private static <T> List<T> nonNullOrEmpty(List<T> value) {
|
private static <T> List<T> nonNullOrEmpty(List<T> value) {
|
||||||
return value != null && !value.isEmpty() ? value : Collections.emptyList();
|
return value != null && !value.isEmpty() ? value : Collections.emptyList();
|
||||||
}
|
}
|
||||||
@ -257,6 +266,8 @@ public final class MultiMCInstancePatch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (MultiMCInstancePatch patch : patches) {
|
for (MultiMCInstancePatch patch : patches) {
|
||||||
|
Objects.requireNonNull(patch, "patch");
|
||||||
|
|
||||||
if (patch.getFormatVersion() != 1) {
|
if (patch.getFormatVersion() != 1) {
|
||||||
throw new UnsupportedOperationException(
|
throw new UnsupportedOperationException(
|
||||||
String.format("Unsupported JSON-Patch[%s] format version: %d", patch.getID(), patch.getFormatVersion())
|
String.format("Unsupported JSON-Patch[%s] format version: %d", patch.getID(), patch.getFormatVersion())
|
||||||
|
@ -86,7 +86,7 @@ public final class MultiMCManifest {
|
|||||||
return equalsVersion;
|
return equalsVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUid() {
|
public String getID() {
|
||||||
return uid;
|
return uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,16 +44,26 @@ import java.nio.file.FileSystem;
|
|||||||
import java.nio.file.Files;
|
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.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>A task transforming MultiMC Modpack Scheme to Official Launcher Scheme.
|
* <p>A task transforming MultiMC Modpack Scheme to Official Launcher Scheme.
|
||||||
* The transforming process contains 7 stage:
|
* The transforming process contains 7 stage:
|
||||||
* General Setup, Load Components, Resolve Json-Patch, Build Artifact,
|
* <ul>
|
||||||
* Copy Embedded Files, Assemble Game, Download Game and Apply JAR mods.
|
* <li>General Setup</li>
|
||||||
|
* <li>Load Components</li>
|
||||||
|
* <li>Resolve Json-Patch</li>
|
||||||
|
* <li>Build Artifact</li>
|
||||||
|
* <li>Copy Embedded Files</li>
|
||||||
|
* <li>Assemble Game</li>
|
||||||
|
* <li>Download Game</li>
|
||||||
|
* <li>Apply JAR mods</li>
|
||||||
|
* </ul>
|
||||||
* See codes below for detailed implementation.
|
* See codes below for detailed implementation.
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
@ -64,7 +74,6 @@ public final class MultiMCModpackInstallTask extends Task<MultiMCInstancePatch.R
|
|||||||
private final MultiMCInstanceConfiguration manifest;
|
private final MultiMCInstanceConfiguration manifest;
|
||||||
private final String name;
|
private final String name;
|
||||||
private final DefaultGameRepository repository;
|
private final DefaultGameRepository repository;
|
||||||
private final List<Task<MultiMCInstancePatch>> patches = new ArrayList<>();
|
|
||||||
private final List<Task<?>> dependents = new ArrayList<>();
|
private final List<Task<?>> dependents = new ArrayList<>();
|
||||||
private final List<Task<?>> dependencies = new ArrayList<>();
|
private final List<Task<?>> dependencies = new ArrayList<>();
|
||||||
private final DefaultDependencyManager dependencyManager;
|
private final DefaultDependencyManager dependencyManager;
|
||||||
@ -125,29 +134,74 @@ public final class MultiMCModpackInstallTask extends Task<MultiMCInstancePatch.R
|
|||||||
try (FileSystem fs = openModpack()) {
|
try (FileSystem fs = openModpack()) {
|
||||||
Path root = getRootPath(fs);
|
Path root = getRootPath(fs);
|
||||||
|
|
||||||
|
List<Task<MultiMCInstancePatch>> patches = new ArrayList<>();
|
||||||
for (MultiMCManifest.MultiMCManifestComponent component : Objects.requireNonNull(
|
for (MultiMCManifest.MultiMCManifestComponent component : Objects.requireNonNull(
|
||||||
Objects.requireNonNull(manifest.getMmcPack(), "mmc-pack.json").getComponents(), "components"
|
Objects.requireNonNull(manifest.getMmcPack(), "mmc-pack.json").getComponents(), "components"
|
||||||
)) {
|
)) {
|
||||||
String componentID = Objects.requireNonNull(component.getUid(), "Component ID");
|
String componentID = Objects.requireNonNull(component.getUid(), "Component ID");
|
||||||
Path patchPath = root.resolve(String.format("patches/%s.json", componentID));
|
Path patchPath = root.resolve(String.format("patches/%s.json", componentID));
|
||||||
|
|
||||||
Task<String> task;
|
|
||||||
if (Files.exists(patchPath)) {
|
if (Files.exists(patchPath)) {
|
||||||
if (!Files.isRegularFile(patchPath)) {
|
if (!Files.isRegularFile(patchPath)) {
|
||||||
throw new IllegalArgumentException("Json-Patch isn't a file: " + componentID);
|
throw new IllegalArgumentException("Json-Patch isn't a file: " + componentID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Task.completed has unclear compatibility issue.
|
MultiMCInstancePatch patch = MultiMCInstancePatch.read(componentID, FileUtils.readText(patchPath, StandardCharsets.UTF_8));
|
||||||
String text = FileUtils.readText(patchPath, StandardCharsets.UTF_8);
|
patches.add(Task.supplyAsync(() -> patch)); // TODO: Task.completed has unclear compatibility issue.
|
||||||
task = Task.supplyAsync(() -> text);
|
|
||||||
} else {
|
} else {
|
||||||
task = new GetTask(MultiMCComponents.getMetaURL(componentID, component.getVersion()));
|
patches.add(
|
||||||
|
new GetTask(MultiMCComponents.getMetaURL(componentID, component.getVersion()))
|
||||||
|
.thenApplyAsync(s -> MultiMCInstancePatch.read(componentID, s))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dependents.add(new MMCInstancePatchesAssembleTask(patches));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class MMCInstancePatchesAssembleTask extends Task<List<MultiMCInstancePatch>> {
|
||||||
|
private final List<Task<MultiMCInstancePatch>> patches;
|
||||||
|
|
||||||
|
public MMCInstancePatchesAssembleTask(List<Task<MultiMCInstancePatch>> patches) {
|
||||||
|
this.patches = patches;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<? extends Task<?>> getDependents() {
|
||||||
|
return patches;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() throws Exception {
|
||||||
|
Map<String, MultiMCInstancePatch> existed = new HashMap<>();
|
||||||
|
for (Task<MultiMCInstancePatch> patch : patches) {
|
||||||
|
MultiMCInstancePatch result = patch.getResult();
|
||||||
|
|
||||||
|
existed.put(result.getID(), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
checking:
|
||||||
|
while (true) {
|
||||||
|
for (MultiMCInstancePatch patch : existed.values()) {
|
||||||
|
for (MultiMCManifest.MultiMCManifestCachedRequires require : patch.getRequires()) {
|
||||||
|
String componentID = require.getID();
|
||||||
|
if (!existed.containsKey(componentID)) {
|
||||||
|
Task<MultiMCInstancePatch> task = new GetTask(MultiMCComponents.getMetaURL(
|
||||||
|
componentID, Lang.requireNonNullElse(require.getEqualsVersion(), require.getSuggests())
|
||||||
|
)).thenApplyAsync(s -> MultiMCInstancePatch.read(componentID, s));
|
||||||
|
task.run();
|
||||||
|
|
||||||
|
MultiMCInstancePatch result = Objects.requireNonNull(task.getResult());
|
||||||
|
existed.put(result.getID(), result);
|
||||||
|
continue checking;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Task<MultiMCInstancePatch> task2 = task.thenApplyAsync(s -> MultiMCInstancePatch.read(componentID, s));
|
break;
|
||||||
patches.add(task2);
|
|
||||||
dependents.add(task2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setResult(new ArrayList<>(existed.values()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,10 +214,15 @@ public final class MultiMCModpackInstallTask extends Task<MultiMCInstancePatch.R
|
|||||||
@Override
|
@Override
|
||||||
public void execute() throws Exception {
|
public void execute() throws Exception {
|
||||||
// Stage #3: Build Json-Patch artifact.
|
// Stage #3: Build Json-Patch artifact.
|
||||||
MultiMCInstancePatch.ResolvedInstance artifact = MultiMCInstancePatch.resolveArtifact(patches.stream()
|
MultiMCInstancePatch.ResolvedInstance artifact = null;
|
||||||
.map(value -> Objects.requireNonNull(value.getResult(), "MultiMCInstancePatch"))
|
for (int i = dependents.size() - 1; i >= 0; i--) {
|
||||||
.collect(Collectors.toList()), name
|
Task<?> task = dependents.get(i);
|
||||||
);
|
if (task instanceof MMCInstancePatchesAssembleTask) {
|
||||||
|
artifact = MultiMCInstancePatch.resolveArtifact(((MMCInstancePatchesAssembleTask) task).getResult(), name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Objects.requireNonNull(artifact, "artifact");
|
||||||
|
|
||||||
// Stage #4: Copy embedded files.
|
// Stage #4: Copy embedded files.
|
||||||
try (FileSystem fs = openModpack()) {
|
try (FileSystem fs = openModpack()) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user