Fix #4647: 修复总是将同时兼容 Forge 和 NeoForge 的模组识别为 Forge 模组的问题 (#4648)

This commit is contained in:
Glavo
2025-10-10 21:35:11 +08:00
committed by GitHub
parent 8a166266d8
commit 7dad43570e
2 changed files with 54 additions and 48 deletions

View File

@@ -41,21 +41,22 @@ public final class ModManager {
LocalModFile fromFile(ModManager modManager, Path modFile, FileSystem fs) throws IOException, JsonParseException; LocalModFile fromFile(ModManager modManager, Path modFile, FileSystem fs) throws IOException, JsonParseException;
} }
private static final Map<String, List<Pair<ModMetadataReader, Set<ModLoaderType>>>> READERS; private static final Map<String, List<Pair<ModMetadataReader, ModLoaderType>>> READERS;
static { static {
var map = new HashMap<String, List<Pair<ModMetadataReader, Set<ModLoaderType>>>>(); var map = new HashMap<String, List<Pair<ModMetadataReader, ModLoaderType>>>();
var zipReaders = List.<Pair<ModMetadataReader, Set<ModLoaderType>>>of( var zipReaders = List.<Pair<ModMetadataReader, ModLoaderType>>of(
pair(ForgeNewModMetadata::fromFile, EnumSet.of(ModLoaderType.FORGE, ModLoaderType.NEO_FORGED)), pair(ForgeNewModMetadata::fromForgeFile, ModLoaderType.FORGE),
pair(ForgeOldModMetadata::fromFile, EnumSet.of(ModLoaderType.FORGE)), pair(ForgeNewModMetadata::fromNeoForgeFile, ModLoaderType.NEO_FORGED),
pair(FabricModMetadata::fromFile, EnumSet.of(ModLoaderType.FABRIC)), pair(ForgeOldModMetadata::fromFile, ModLoaderType.FORGE),
pair(QuiltModMetadata::fromFile, EnumSet.of(ModLoaderType.QUILT)), pair(FabricModMetadata::fromFile, ModLoaderType.FABRIC),
pair(PackMcMeta::fromFile, EnumSet.of(ModLoaderType.PACK)) pair(QuiltModMetadata::fromFile, ModLoaderType.QUILT),
pair(PackMcMeta::fromFile, ModLoaderType.PACK)
); );
map.put("zip", zipReaders); map.put("zip", zipReaders);
map.put("jar", zipReaders); map.put("jar", zipReaders);
map.put("litemod", List.of(pair(LiteModMetadata::fromFile, EnumSet.of(ModLoaderType.LITE_LOADER)))); map.put("litemod", List.of(pair(LiteModMetadata::fromFile, ModLoaderType.LITE_LOADER)));
READERS = map; READERS = map;
} }
@@ -102,7 +103,7 @@ public final class ModManager {
String fileName = StringUtils.removeSuffix(FileUtils.getName(file), DISABLED_EXTENSION, OLD_EXTENSION); String fileName = StringUtils.removeSuffix(FileUtils.getName(file), DISABLED_EXTENSION, OLD_EXTENSION);
String extension = fileName.substring(fileName.lastIndexOf(".") + 1); String extension = fileName.substring(fileName.lastIndexOf(".") + 1);
List<Pair<ModMetadataReader, Set<ModLoaderType>>> readersMap = READERS.get(extension); List<Pair<ModMetadataReader, ModLoaderType>> readersMap = READERS.get(extension);
if (readersMap == null) { if (readersMap == null) {
// Is not a mod file. // Is not a mod file.
return; return;
@@ -113,16 +114,8 @@ public final class ModManager {
var supportedReaders = new ArrayList<ModMetadataReader>(); var supportedReaders = new ArrayList<ModMetadataReader>();
var unsupportedReaders = new ArrayList<ModMetadataReader>(); var unsupportedReaders = new ArrayList<ModMetadataReader>();
for (Pair<ModMetadataReader, Set<ModLoaderType>> reader : readersMap) { for (Pair<ModMetadataReader, ModLoaderType> reader : readersMap) {
boolean supported = false; if (modLoaderTypes.contains(reader.getValue())) {
for (ModLoaderType type : reader.getValue()) {
if (modLoaderTypes.contains(type)) {
supported = true;
break;
}
}
if (supported) {
supportedReaders.add(reader.getKey()); supportedReaders.add(reader.getKey());
} else { } else {
unsupportedReaders.add(reader.getKey()); unsupportedReaders.add(reader.getKey());

View File

@@ -110,23 +110,33 @@ public final class ForgeNewModMetadata {
} }
} }
private static final int ACC_FORGE = 0x01; public static LocalModFile fromForgeFile(ModManager modManager, Path modFile, FileSystem fs) throws IOException {
return fromFile(modManager, modFile, fs, ModLoaderType.FORGE);
}
private static final int ACC_NEO_FORGED = 0x02; public static LocalModFile fromNeoForgeFile(ModManager modManager, Path modFile, FileSystem fs) throws IOException {
return fromFile(modManager, modFile, fs, ModLoaderType.NEO_FORGED);
}
private static LocalModFile fromFile(ModManager modManager, Path modFile, FileSystem fs, ModLoaderType modLoaderType) throws IOException {
if (modLoaderType != ModLoaderType.FORGE && modLoaderType != ModLoaderType.NEO_FORGED) {
throw new IOException("Invalid mod loader: " + modLoaderType);
}
if (modLoaderType == ModLoaderType.NEO_FORGED) {
try {
return fromFile0("META-INF/neoforge.mods.toml", modLoaderType, modManager, modFile, fs);
} catch (Exception ignored) {
}
}
public static LocalModFile fromFile(ModManager modManager, Path modFile, FileSystem fs) throws IOException, JsonParseException {
try { try {
return fromFile0("META-INF/mods.toml", ACC_FORGE | ACC_NEO_FORGED, ModLoaderType.FORGE, modManager, modFile, fs); return fromFile0("META-INF/mods.toml", modLoaderType, modManager, modFile, fs);
} catch (Exception ignored) { } catch (Exception ignored) {
} }
try { try {
return fromFile0("META-INF/neoforge.mods.toml", ACC_NEO_FORGED, ModLoaderType.NEO_FORGED, modManager, modFile, fs); return fromEmbeddedMod(modManager, modFile, fs, modLoaderType);
} catch (Exception ignored) {
}
try {
return fromEmbeddedMod(modManager, modFile, fs);
} catch (Exception ignored) { } catch (Exception ignored) {
} }
@@ -134,8 +144,8 @@ public final class ForgeNewModMetadata {
} }
private static LocalModFile fromFile0( private static LocalModFile fromFile0(
String tomlPath, int loaderACC, String tomlPath,
ModLoaderType defaultLoader, ModLoaderType modLoaderType,
ModManager modManager, ModManager modManager,
Path modFile, Path modFile,
FileSystem fs) throws IOException, JsonParseException { FileSystem fs) throws IOException, JsonParseException {
@@ -158,7 +168,7 @@ public final class ForgeNewModMetadata {
} }
} }
ModLoaderType type = analyzeLoader(toml, mod.getModId(), loaderACC, defaultLoader); ModLoaderType type = analyzeLoader(toml, mod.getModId(), modLoaderType);
return new LocalModFile(modManager, modManager.getLocalMod(mod.getModId(), type), modFile, mod.getDisplayName(), new LocalModFile.Description(mod.getDescription()), return new LocalModFile(modManager, modManager.getLocalMod(mod.getModId(), type), modFile, mod.getDisplayName(), new LocalModFile.Description(mod.getDescription()),
mod.getAuthors(), jarVersion == null ? mod.getVersion() : mod.getVersion().replace("${file.jarVersion}", jarVersion), "", mod.getAuthors(), jarVersion == null ? mod.getVersion() : mod.getVersion().replace("${file.jarVersion}", jarVersion), "",
@@ -166,7 +176,7 @@ public final class ForgeNewModMetadata {
metadata.getLogoFile()); metadata.getLogoFile());
} }
private static LocalModFile fromEmbeddedMod(ModManager modManager, Path modFile, FileSystem fs) throws IOException { private static LocalModFile fromEmbeddedMod(ModManager modManager, Path modFile, FileSystem fs, ModLoaderType modLoaderType) throws IOException {
Path manifestFile = fs.getPath("META-INF/MANIFEST.MF"); Path manifestFile = fs.getPath("META-INF/MANIFEST.MF");
if (!Files.isRegularFile(manifestFile)) if (!Files.isRegularFile(manifestFile))
throw new IOException("Missing MANIFEST.MF in file " + manifestFile); throw new IOException("Missing MANIFEST.MF in file " + manifestFile);
@@ -190,7 +200,7 @@ public final class ForgeNewModMetadata {
try { try {
Files.copy(embeddedModFile, tempFile, StandardCopyOption.REPLACE_EXISTING); Files.copy(embeddedModFile, tempFile, StandardCopyOption.REPLACE_EXISTING);
try (FileSystem embeddedFs = CompressingUtils.createReadOnlyZipFileSystem(tempFile)) { try (FileSystem embeddedFs = CompressingUtils.createReadOnlyZipFileSystem(tempFile)) {
return fromFile(modManager, modFile, embeddedFs); return fromFile(modManager, modFile, embeddedFs, modLoaderType);
} }
} catch (IOException e) { } catch (IOException e) {
LOG.warning("Failed to read embedded-dependencies-mod: " + embeddedModFile, e); LOG.warning("Failed to read embedded-dependencies-mod: " + embeddedModFile, e);
@@ -200,33 +210,36 @@ public final class ForgeNewModMetadata {
} }
} }
private static ModLoaderType analyzeLoader(Toml toml, String modID, int loaderACC, ModLoaderType defaultLoader) throws IOException { private static ModLoaderType analyzeLoader(Toml toml, String modID, ModLoaderType loader) throws IOException {
List<HashMap<String, Object>> dependencies = toml.getList("dependencies." + modID); List<HashMap<String, Object>> dependencies = toml.getList("dependencies." + modID);
if (dependencies == null) { if (dependencies == null) {
dependencies = toml.getList("dependencies"); // ??? I have no idea why some of the Forge mods use [[dependencies]] dependencies = toml.getList("dependencies"); // ??? I have no idea why some of the Forge mods use [[dependencies]]
if (dependencies == null) { if (dependencies == null) {
return defaultLoader; return loader;
} }
} }
ModLoaderType result = null;
loop:
for (HashMap<String, Object> dependency : dependencies) { for (HashMap<String, Object> dependency : dependencies) {
switch ((String) dependency.get("modId")) { switch ((String) dependency.get("modId")) {
case "forge": case "forge":
return checkLoaderACC(loaderACC, ACC_FORGE, ModLoaderType.FORGE); result = ModLoaderType.FORGE;
break loop;
case "neoforge": case "neoforge":
return checkLoaderACC(loaderACC, ACC_NEO_FORGED, ModLoaderType.NEO_FORGED); result = ModLoaderType.NEO_FORGED;
break loop;
} }
} }
// ??? I have no idea why some of the Forge mods doesn't provide this key. if (result == loader)
return defaultLoader; return result;
} else if (result != null)
throw new IOException("Loader mismatch");
private static ModLoaderType checkLoaderACC(int current, int target, ModLoaderType res) throws IOException { else {
if ((target & current) != 0) { LOG.warning("Cannot determine the mod loader for mod " + modID + ", expected " + loader);
return res; return loader;
} else {
throw new IOException("Mismatched loader.");
} }
} }
} }