DirectoryModCandidateFinder

基本信息

属性 值
类 com.mitchej123.jarjar.fml.common.discovery.finder.DirectoryModCandidateFinder
接口 ModCandidateFinder
来源 Fabric DirectoryModCandidateFinder (Apache 2.0 / LGPL v3)
输出 <mc>/mods/ 内所有合法 .jar 候选

DirectoryModCandidateFinder 是 ClasspathModCandidateFinder 之外的第二个 finder,扫描 mods 目录,支持 Forge 1.7.10 引入的 versioned 子目录与 ModListHelper.additionalMods 额外路径。

构造函数

public DirectoryModCandidateFinder(Path path, File[] additionalMods, boolean requiresRemap) {
    this.pathToSearch = LoaderUtil.normalizePath(path);
    this.additionalMods = FileListHelper.sortFileList(additionalMods);
    this.requiresRemap = requiresRemap;
}

public DirectoryModCandidateFinder(Path path, boolean requiresRemap) {
    this(path, new File[0], requiresRemap);
}
  • path 经 LoaderUtil.normalizePath → path.toRealPath() 归一化
  • additionalMods 经 FileListHelper.sortFileList 排序

findCandidates 流程

public void findCandidates(ModCandidateConsumer out) {
    LOGGER.info("Searching for mods in {}", pathToSearch);
    if (!Files.exists(pathToSearch)) {
        try { Files.createDirectory(pathToSearch); return; }
        catch (IOException e) { throw new RuntimeException("Could not create directory " + pathToSearch, e); }
    }
    if (!Files.isDirectory(pathToSearch)) {
        throw new RuntimeException(pathToSearch + " is not a directory!");
    }

    final List<Path> paths = new ArrayList<>();
    paths.add(pathToSearch);

    final Path versionSpecificModsDir = pathToSearch.resolve(FMLInjectionData.mccversion);
    if (versionSpecificModsDir.toFile().isDirectory()) {
        FMLLog.info("Also searching %s for mods", versionSpecificModsDir);
        paths.add(versionSpecificModsDir);
    }

    try {
        for (Path path : paths) {
            Files.walkFileTree(path, EnumSet.of(FileVisitOption.FOLLOW_LINKS), 1, new SimpleFileVisitor<>() {
                @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
                    if (isValidFile(file)) out.accept(file, requiresRemap);
                    return FileVisitResult.CONTINUE;
                }
            });
        }
        for (File additionalMod : additionalMods) {
            final Path additionalModPath = LoaderUtil.normalizePath(additionalMod.toPath());
            if (isValidFile(additionalModPath)) {
                out.accept(LoaderUtil.normalizePath(additionalMod.toPath()), requiresRemap);
            }
        }
    } catch (IOException e) {
        throw new RuntimeException("Exception while searching for mods in '" + pathToSearch + "'!", e);
    }
}

深度

Files.walkFileTree(..., maxDepth=1, ...) —— 不递归子目录。mod 目录要求 jar 平铺。

isValidFile

static boolean isValidFile(Path path) {
    if (!Files.isRegularFile(path)) return false;
    try { if (Files.isHidden(path)) return false; }
    catch (IOException e) { return false; }
    final String fileName = path.getFileName().toString();
    return fileName.endsWith(".jar") && !fileName.startsWith(".") && !getDisabledFiles().contains(fileName);
}

三重过滤:

  • 必须是 regular file
  • 不能是 hidden
  • 必须以 .jar 结尾,不以 . 开头,不在 disabled 集合内

getDisabledFiles

private static Set<String> disabledFiles;

@SuppressWarnings("unchecked")
public static Set<String> getDisabledFiles() {
    if (disabledFiles == null) {
        disabledFiles = (Set<String>)Launch.blackboard.get(CoreModManagerV2.DISABLED_FILES);
    }
    return disabledFiles;
}

懒加载从 Launch.blackboard["jarjar.disabledFiles"] 读取。CoreModManagerV2.loadTweakersAndCoreMods 写入。

versioned 子目录

FMLInjectionData.mccversion(如 1.7.10)作为子目录名,Forge 1.7.10 后期引入的版本专用 mods 目录机制。JarJar 完整支持。

相关条目