支持读取 META-INF/jarjar/metadata.json (#4652)

This commit is contained in:
Glavo
2025-10-11 20:45:27 +08:00
committed by GitHub
parent 60375c9632
commit b32d3304b0

View File

@@ -6,11 +6,15 @@ import org.jackhuang.hmcl.mod.LocalModFile;
import org.jackhuang.hmcl.mod.ModLoaderType; import org.jackhuang.hmcl.mod.ModLoaderType;
import org.jackhuang.hmcl.mod.ModManager; import org.jackhuang.hmcl.mod.ModManager;
import org.jackhuang.hmcl.util.Immutable; import org.jackhuang.hmcl.util.Immutable;
import org.jackhuang.hmcl.util.gson.JsonSerializable;
import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.gson.Validation;
import org.jackhuang.hmcl.util.io.CompressingUtils; import org.jackhuang.hmcl.util.io.CompressingUtils;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.file.*; import java.nio.file.*;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.jar.Attributes; import java.util.jar.Attributes;
@@ -186,28 +190,55 @@ public final class ForgeNewModMetadata {
manifest = new Manifest(input); manifest = new Manifest(input);
} }
String embeddedDependenciesMod = manifest.getMainAttributes().getValue("Embedded-Dependencies-Mod"); List<Path> embeddedModFiles = List.of();
if (embeddedDependenciesMod == null)
throw new IOException("Embedded-Dependencies-Mod attribute is missing");
Path embeddedModFile = fs.getPath(embeddedDependenciesMod); String embeddedDependenciesMod = manifest.getMainAttributes().getValue("Embedded-Dependencies-Mod");
if (!Files.isRegularFile(embeddedModFile)) { if (embeddedDependenciesMod != null) {
LOG.warning("Missing embedded-dependencies-mod: " + embeddedModFile); Path embeddedModFile = fs.getPath(embeddedDependenciesMod);
throw new IOException(); if (!Files.isRegularFile(embeddedModFile)) {
LOG.warning("Missing embedded-dependencies-mod: " + embeddedModFile);
throw new IOException();
}
embeddedModFiles = List.of(embeddedModFile);
} else {
Path jarInJarMetadata = fs.getPath("META-INF/jarjar/metadata.json");
if (Files.isRegularFile(jarInJarMetadata)) {
JarInJarMetadata metadata = JsonUtils.fromJsonFile(jarInJarMetadata, JarInJarMetadata.class);
if (metadata == null)
throw new IOException("Invalid metadata file: " + jarInJarMetadata);
metadata.validate();
embeddedModFiles = new ArrayList<>();
for (EmbeddedJarMetadata jar : metadata.jars) {
Path path = fs.getPath(jar.path);
if (Files.isRegularFile(path)) {
embeddedModFiles.add(path);
} else {
LOG.warning("Missing embedded-dependencies-mod: " + path);
}
}
}
}
if (embeddedModFiles.isEmpty()) {
throw new IOException("Missing embedded mods");
} }
Path tempFile = Files.createTempFile("hmcl-", ".zip"); Path tempFile = Files.createTempFile("hmcl-", ".zip");
try { try {
Files.copy(embeddedModFile, tempFile, StandardCopyOption.REPLACE_EXISTING); for (Path embeddedModFile : embeddedModFiles) {
try (FileSystem embeddedFs = CompressingUtils.createReadOnlyZipFileSystem(tempFile)) { Files.copy(embeddedModFile, tempFile, StandardCopyOption.REPLACE_EXISTING);
return fromFile(modManager, modFile, embeddedFs, modLoaderType); try (FileSystem embeddedFs = CompressingUtils.createReadOnlyZipFileSystem(tempFile)) {
return fromFile(modManager, modFile, embeddedFs, modLoaderType);
} catch (Exception ignored) {
}
} }
} catch (IOException e) {
LOG.warning("Failed to read embedded-dependencies-mod: " + embeddedModFile, e);
throw e;
} finally { } finally {
Files.deleteIfExists(tempFile); Files.deleteIfExists(tempFile);
} }
throw new IOException();
} }
private static ModLoaderType analyzeLoader(Toml toml, String modID, ModLoaderType loader) throws IOException { private static ModLoaderType analyzeLoader(Toml toml, String modID, ModLoaderType loader) throws IOException {
@@ -242,4 +273,26 @@ public final class ForgeNewModMetadata {
} }
} }
@JsonSerializable
private record JarInJarMetadata(List<EmbeddedJarMetadata> jars) implements Validation {
@Override
public void validate() throws JsonParseException {
Validation.requireNonNull(jars, "jars");
for (EmbeddedJarMetadata jar : jars) {
jar.validate();
}
}
}
@JsonSerializable
private record EmbeddedJarMetadata(
String path,
boolean isObfuscated
) implements Validation {
@Override
public void validate() throws JsonParseException {
Validation.requireNonNull(path, "path");
}
}
} }