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 完整支持。
相关条目
- ModCandidateFinder 接口 - 实现接口
- ClasspathModCandidateFinder - 兄弟 finder
- 并行 mod 发现 - 主调度方
- 重复 mod 去重 - 写入 disabledFiles blackboard
- LoaderUtil 路径缓存 - normalizePath 提供