From b32d3304b0c1dc5c2b2fb6eb9a0bc96654d3414f Mon Sep 17 00:00:00 2001 From: Glavo Date: Sat, 11 Oct 2025 20:45:27 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=AF=BB=E5=8F=96=20META-INF?= =?UTF-8?q?/jarjar/metadata.json=20(#4652)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hmcl/mod/modinfo/ForgeNewModMetadata.java | 79 ++++++++++++++++--- 1 file changed, 66 insertions(+), 13 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/modinfo/ForgeNewModMetadata.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/modinfo/ForgeNewModMetadata.java index 6da608558..9fb52c380 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/modinfo/ForgeNewModMetadata.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/modinfo/ForgeNewModMetadata.java @@ -6,11 +6,15 @@ import org.jackhuang.hmcl.mod.LocalModFile; import org.jackhuang.hmcl.mod.ModLoaderType; import org.jackhuang.hmcl.mod.ModManager; 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 java.io.IOException; import java.io.InputStream; import java.nio.file.*; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.jar.Attributes; @@ -186,28 +190,55 @@ public final class ForgeNewModMetadata { manifest = new Manifest(input); } - String embeddedDependenciesMod = manifest.getMainAttributes().getValue("Embedded-Dependencies-Mod"); - if (embeddedDependenciesMod == null) - throw new IOException("Embedded-Dependencies-Mod attribute is missing"); + List embeddedModFiles = List.of(); - Path embeddedModFile = fs.getPath(embeddedDependenciesMod); - if (!Files.isRegularFile(embeddedModFile)) { - LOG.warning("Missing embedded-dependencies-mod: " + embeddedModFile); - throw new IOException(); + String embeddedDependenciesMod = manifest.getMainAttributes().getValue("Embedded-Dependencies-Mod"); + if (embeddedDependenciesMod != null) { + Path embeddedModFile = fs.getPath(embeddedDependenciesMod); + 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"); try { - Files.copy(embeddedModFile, tempFile, StandardCopyOption.REPLACE_EXISTING); - try (FileSystem embeddedFs = CompressingUtils.createReadOnlyZipFileSystem(tempFile)) { - return fromFile(modManager, modFile, embeddedFs, modLoaderType); + for (Path embeddedModFile : embeddedModFiles) { + Files.copy(embeddedModFile, tempFile, StandardCopyOption.REPLACE_EXISTING); + 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 { Files.deleteIfExists(tempFile); } + + throw new 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 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"); + } + } + }