Skip to content

Commit 7d7dbb9

Browse files
authored
重构 MultiMC 整合包兼容功能 (HMCL-dev#3547)
Fix HMCL-dev#3540 Fix HMCL-dev#3706
1 parent 88a7243 commit 7d7dbb9

18 files changed

Lines changed: 760 additions & 207 deletions

HMCL/src/main/java/org/jackhuang/hmcl/ui/InstallerItem.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,13 @@ public InstallerItemGroup(String gameVersion, Style style) {
281281

282282
for (InstallerItem item : all) {
283283
if (!item.resolvedStateProperty.isBound()) {
284-
item.resolvedStateProperty.bind(item.versionProperty);
284+
item.resolvedStateProperty.bind(Bindings.createObjectBinding(() -> {
285+
InstalledState itemVersion = item.versionProperty.get();
286+
if (itemVersion != null) {
287+
return itemVersion;
288+
}
289+
return InstallableState.INSTANCE;
290+
}, item.versionProperty));
285291
}
286292
}
287293

@@ -385,7 +391,10 @@ private static final class InstallerItemSkin extends SkinBase<InstallerItem> {
385391
if (control.id.equals(MINECRAFT.getPatchId())) {
386392
removeButton.setVisible(false);
387393
} else {
388-
removeButton.visibleProperty().bind(Bindings.createBooleanBinding(() -> control.resolvedStateProperty.get() instanceof InstalledState, control.resolvedStateProperty));
394+
removeButton.visibleProperty().bind(Bindings.createBooleanBinding(() -> {
395+
State state = control.resolvedStateProperty.get();
396+
return state instanceof InstalledState && !((InstalledState) state).external;
397+
}, control.resolvedStateProperty));
389398
}
390399
removeButton.managedProperty().bind(removeButton.visibleProperty());
391400
removeButton.setOnAction(e -> {

HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricInstallTask.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ private Version getPatch(FabricInfo fabricInfo, String gameVersion, String loade
124124
libraries.add(new Library(Artifact.fromDescriptor(fabricInfo.intermediary.maven), "https://maven.fabricmc.net/", null));
125125
libraries.add(new Library(Artifact.fromDescriptor(fabricInfo.loader.maven), "https://maven.fabricmc.net/", null));
126126

127-
return new Version(LibraryAnalyzer.LibraryType.FABRIC.getPatchId(), loaderVersion, 30000, arguments, mainClass, libraries);
127+
return new Version(LibraryAnalyzer.LibraryType.FABRIC.getPatchId(), loaderVersion, Version.PRIORITY_LOADER, arguments, mainClass, libraries);
128128
}
129129

130130
public static class FabricInfo {

HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeNewInstallTask.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ public void execute() throws Exception {
410410
dependencyManager.checkLibraryCompletionAsync(forgeVersion, true)));
411411

412412
setResult(forgeVersion
413-
.setPriority(30000)
413+
.setPriority(Version.PRIORITY_LOADER)
414414
.setId(LibraryAnalyzer.LibraryType.FORGE.getPatchId())
415415
.setVersion(selfVersion));
416416
}

HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeOldInstallTask.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public void execute() throws Exception {
8282
}
8383

8484
setResult(installProfile.getVersionInfo()
85-
.setPriority(30000)
85+
.setPriority(Version.PRIORITY_LOADER)
8686
.setId(LibraryAnalyzer.LibraryType.FORGE.getPatchId())
8787
.setVersion(selfVersion));
8888
dependencies.add(dependencyManager.checkLibraryCompletionAsync(installProfile.getVersionInfo(), true));

HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameInstallTask.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public boolean isRelyingOnDependencies() {
6565
@Override
6666
public void execute() throws Exception {
6767
Version patch = JsonUtils.fromNonNullJson(downloadTask.getResult(), Version.class)
68-
.setId(MINECRAFT.getPatchId()).setVersion(remote.getGameVersion()).setJar(null).setPriority(0);
68+
.setId(MINECRAFT.getPatchId()).setVersion(remote.getGameVersion()).setJar(null).setPriority(Version.PRIORITY_MC);
6969
setResult(patch);
7070

7171
Version version = new Version(this.version.getId()).addPatch(patch);

HMCLCore/src/main/java/org/jackhuang/hmcl/download/neoforge/NeoForgeOldInstallTask.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ public void execute() throws Exception {
406406
dependencyManager.checkLibraryCompletionAsync(neoForgeVersion, true)));
407407

408408
setResult(neoForgeVersion
409-
.setPriority(30000)
409+
.setPriority(Version.PRIORITY_LOADER)
410410
.setId(LibraryAnalyzer.LibraryType.NEO_FORGE.getPatchId())
411411
.setVersion(selfVersion));
412412
}

HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltInstallTask.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ private Version getPatch(QuiltInfo quiltInfo, String gameVersion, String loaderV
120120
libraries.add(new Library(Artifact.fromDescriptor(quiltInfo.intermediary.maven), getMavenRepositoryByGroup(quiltInfo.intermediary.maven), null));
121121
libraries.add(new Library(Artifact.fromDescriptor(quiltInfo.loader.maven), getMavenRepositoryByGroup(quiltInfo.loader.maven), null));
122122

123-
return new Version(LibraryAnalyzer.LibraryType.QUILT.getPatchId(), loaderVersion, 30000, arguments, mainClass, libraries);
123+
return new Version(LibraryAnalyzer.LibraryType.QUILT.getPatchId(), loaderVersion, Version.PRIORITY_LOADER, arguments, mainClass, libraries);
124124
}
125125

126126
private static String getMavenRepositoryByGroup(String maven) {

HMCLCore/src/main/java/org/jackhuang/hmcl/game/Arguments.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,12 @@ public Arguments addJVMArguments(String... jvmArguments) {
7979
}
8080

8181
public Arguments addJVMArguments(List<String> jvmArguments) {
82-
List<Argument> list = jvmArguments.stream().map(StringArgument::new).collect(Collectors.toList());
83-
return new Arguments(getGame(), Lang.merge(getJvm(), list));
82+
return addJVMArgumentsDirect(jvmArguments.stream().map(StringArgument::new).collect(Collectors.toList()));
83+
}
84+
85+
// TODO: How to distinguish addJVMArgumentsDirect from addJVMArguments? Naming is hard :)
86+
public Arguments addJVMArgumentsDirect(List<Argument> jvmArguments) {
87+
return new Arguments(getGame(), Lang.merge(getJvm(), jvmArguments));
8488
}
8589

8690
public static Arguments merge(Arguments a, Arguments b) {

HMCLCore/src/main/java/org/jackhuang/hmcl/game/DefaultGameRepository.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,15 @@ public File getLibrariesDirectory(Version version) {
9595

9696
@Override
9797
public File getLibraryFile(Version version, Library lib) {
98-
if ("local".equals(lib.getHint()) && lib.getFileName() != null)
99-
return new File(getVersionRoot(version.getId()), "libraries/" + lib.getFileName());
100-
else
101-
return new File(getLibrariesDirectory(version), lib.getPath());
98+
if ("local".equals(lib.getHint())) {
99+
if (lib.getFileName() != null) {
100+
return new File(getVersionRoot(version.getId()), "libraries/" + lib.getFileName());
101+
}
102+
103+
return new File(getVersionRoot(version.getId()), "libraries/" + lib.getArtifact().getFileName());
104+
}
105+
106+
return new File(getLibrariesDirectory(version), lib.getPath());
102107
}
103108

104109
public Path getArtifactFile(Version version, Artifact artifact) {

HMCLCore/src/main/java/org/jackhuang/hmcl/game/Library.java

Lines changed: 89 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,19 @@
1717
*/
1818
package org.jackhuang.hmcl.game;
1919

20-
import com.google.gson.*;
20+
import com.google.gson.JsonParseException;
2121
import com.google.gson.annotations.SerializedName;
2222
import org.jackhuang.hmcl.util.Constants;
2323
import org.jackhuang.hmcl.util.Immutable;
24+
import org.jackhuang.hmcl.util.Lang;
2425
import org.jackhuang.hmcl.util.ToStringBuilder;
2526
import org.jackhuang.hmcl.util.gson.TolerableValidationException;
2627
import org.jackhuang.hmcl.util.gson.Validation;
2728
import org.jackhuang.hmcl.util.platform.Architecture;
2829
import org.jackhuang.hmcl.util.platform.OperatingSystem;
2930
import org.jetbrains.annotations.Nullable;
3031

31-
import java.util.List;
32-
import java.util.Map;
33-
import java.util.Objects;
34-
import java.util.Optional;
32+
import java.util.*;
3533

3634
/**
3735
* A class that describes a Minecraft dependency.
@@ -40,6 +38,40 @@
4038
*/
4139
@Immutable
4240
public class Library implements Comparable<Library>, Validation {
41+
/**
42+
* <p>A possible native descriptors can be: [variant-]os[-key]</p>
43+
*
44+
* <p>
45+
* Variant can be empty string, 'native', or 'natives'.
46+
* Key can be empty string, system arch, or system arch bit count.
47+
* </p>
48+
*/
49+
private static final String[] POSSIBLE_NATIVE_DESCRIPTORS;
50+
51+
static {
52+
String[] keys = {
53+
"",
54+
Architecture.SYSTEM_ARCH.name().toLowerCase(Locale.ROOT),
55+
Architecture.SYSTEM_ARCH.getBits().getBit()
56+
}, variants = {"", "native", "natives"};
57+
58+
POSSIBLE_NATIVE_DESCRIPTORS = new String[keys.length * variants.length];
59+
StringBuilder builder = new StringBuilder();
60+
for (int i = 0; i < keys.length; i++) {
61+
for (int j = 0; j < variants.length; j++) {
62+
if (!variants[j].isEmpty()) {
63+
builder.append(variants[j]).append('-');
64+
}
65+
builder.append(OperatingSystem.CURRENT_OS.getMojangName());
66+
if (!keys[i].isEmpty()) {
67+
builder.append('-').append(keys[i]);
68+
}
69+
70+
POSSIBLE_NATIVE_DESCRIPTORS[i * variants.length + j] = builder.toString();
71+
builder.setLength(0);
72+
}
73+
}
74+
}
4375

4476
@SerializedName("name")
4577
private final Artifact artifact;
@@ -93,13 +125,27 @@ public String getVersion() {
93125
}
94126

95127
public String getClassifier() {
96-
if (artifact.getClassifier() == null)
97-
if (natives != null && natives.containsKey(OperatingSystem.CURRENT_OS.getMojangName()))
98-
return natives.get(OperatingSystem.CURRENT_OS.getMojangName()).replace("${arch}", Architecture.SYSTEM_ARCH.getBits().getBit());
99-
else
100-
return null;
101-
else
128+
if (artifact.getClassifier() == null) {
129+
if (natives != null) {
130+
for (String nativeDescriptor : POSSIBLE_NATIVE_DESCRIPTORS) {
131+
String nd = natives.get(nativeDescriptor);
132+
if (nd != null) {
133+
return nd.replace("${arch}", Architecture.SYSTEM_ARCH.getBits().getBit());
134+
}
135+
}
136+
} else if (downloads != null && downloads.getClassifiers() != null) {
137+
for (String nativeDescriptor : POSSIBLE_NATIVE_DESCRIPTORS) {
138+
LibraryDownloadInfo info = downloads.getClassifiers().get(nativeDescriptor);
139+
if (info != null) {
140+
return nativeDescriptor;
141+
}
142+
}
143+
}
144+
145+
return null;
146+
} else {
102147
return artifact.getClassifier();
148+
}
103149
}
104150

105151
public ExtractRules getExtract() {
@@ -111,10 +157,17 @@ public boolean appliesToCurrentEnvironment() {
111157
}
112158

113159
public boolean isNative() {
114-
return natives != null && appliesToCurrentEnvironment();
160+
if (!appliesToCurrentEnvironment()) {
161+
return false;
162+
}
163+
if (natives != null) {
164+
return true;
165+
}
166+
167+
return downloads != null && downloads.getClassifiers().keySet().stream().anyMatch(s -> s.startsWith("native"));
115168
}
116169

117-
protected LibraryDownloadInfo getRawDownloadInfo() {
170+
public LibraryDownloadInfo getRawDownloadInfo() {
118171
if (downloads != null) {
119172
if (isNative())
120173
return downloads.getClassifiers().get(getClassifier());
@@ -125,6 +178,10 @@ protected LibraryDownloadInfo getRawDownloadInfo() {
125178
}
126179
}
127180

181+
public Artifact getArtifact() {
182+
return artifact;
183+
}
184+
128185
public String getPath() {
129186
LibraryDownloadInfo temp = getRawDownloadInfo();
130187
if (temp != null && temp.getPath() != null)
@@ -137,12 +194,28 @@ public LibraryDownloadInfo getDownload() {
137194
LibraryDownloadInfo temp = getRawDownloadInfo();
138195
String path = getPath();
139196
return new LibraryDownloadInfo(path,
140-
Optional.ofNullable(temp).map(LibraryDownloadInfo::getUrl).orElse(Optional.ofNullable(url).orElse(Constants.DEFAULT_LIBRARY_URL) + path),
197+
computePath(temp, path),
141198
temp != null ? temp.getSha1() : null,
142199
temp != null ? temp.getSize() : 0
143200
);
144201
}
145202

203+
private String computePath(LibraryDownloadInfo raw, String path) {
204+
if (raw != null) {
205+
String url = raw.getUrl();
206+
if (url != null) {
207+
return url;
208+
}
209+
}
210+
211+
String repo = Lang.requireNonNullElse(url, Constants.DEFAULT_LIBRARY_URL);
212+
if (!repo.endsWith("/")) {
213+
repo += '/';
214+
}
215+
216+
return repo + path;
217+
}
218+
146219
public boolean hasDownloadURL() {
147220
LibraryDownloadInfo temp = getRawDownloadInfo();
148221
if (temp != null) return temp.getUrl() != null;
@@ -159,6 +232,7 @@ public List<CompatibilityRule> getRules() {
159232

160233
/**
161234
* Hint for how to locate the library file.
235+
*
162236
* @return null for default, "local" for location in version/&lt;version&gt;/libraries/filename
163237
*/
164238
@Nullable
@@ -168,6 +242,7 @@ public String getHint() {
168242

169243
/**
170244
* Available when hint is "local"
245+
*
171246
* @return the filename of the local library in version/&lt;version&gt;/libraries/$filename
172247
*/
173248
@Nullable

0 commit comments

Comments
 (0)